shithub: ext4srv

Download patch

ref: 12a0ed55204affb277def2a73c1769bd76105ed4
parent: 46f57aba13e43e6ec3c84d6123c6bc59546e4b7d
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sat Nov 7 13:31:12 EST 2020

better permission checking and simple file writing

--- a/ext4srv.c
+++ b/ext4srv.c
@@ -12,6 +12,7 @@
 
 struct Aux {
 	Part *p;
+	u32int uid;
 	char *path;
 	union {
 		ext4_file *file;
@@ -23,6 +24,8 @@
 enum {
 	Adir,
 	Afile,
+
+	Root = 0,
 };
 
 static Opts opts = {
@@ -29,6 +32,95 @@
 	.cachewb = 0,
 };
 
+static char *
+linkresolve(Aux *a, char *s)
+{
+	char *q;
+	char buf[4096+1];
+	ulong sz;
+
+	if(ext4_readlink(s, buf, sizeof(buf)-1, &sz) == 0){
+		buf[sz] = 0;
+		cleanname(buf);
+		if(buf[0] == '/'){
+			free(s);
+			s = smprint("%M%s", a->p, buf);
+		}else{
+			q = strrchr(s, '/');
+			*q = 0;
+			q = s;
+			s = smprint("%s/%s", q, buf);
+			cleanname(s);
+			free(q);
+		}
+	}
+
+	return s;
+}
+
+static char *
+fullpath(Aux *a)
+{
+	return linkresolve(a, smprint("%M/%s", a->p, a->path));
+}
+
+static int
+haveperm(Aux *a, int p)
+{
+	struct ext4_inode inode;
+	u32int ino;
+	Group *g;
+	char *s;
+	int m, fm, r;
+
+	switch(p & 3){
+	case OREAD:
+		p = AREAD;	
+		break;
+	case OWRITE:
+		p = AWRITE;
+		break;
+	case ORDWR:
+		p = AREAD|AWRITE;
+		break;
+	case OEXEC:
+		p = AEXEC;	
+		break;
+	default:
+		return 0;
+	}
+
+	s = fullpath(a);
+	if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0){
+		fprint(2, "inode: %s: %s\n", s, errno2s(r));
+		return 0;
+	}
+	free(s);
+
+	fm = ext4_inode_get_mode(a->p->sb, &inode);
+
+	/* other */
+	m = fm & 7;
+	if((p & m) == p)
+		return 1;
+
+	/* owner */
+	if(a->uid == Root || ((g = findgroupid(&a->p->groups, ext4_inode_get_uid(&inode))) != nil && g->id == a->uid)){
+		m |= (fm >> 6) & 7;
+		if((p & m) == p)
+			return 1;
+	}
+
+	/* group */
+	if(a->uid == Root || ((g = findgroupid(&a->p->groups, ext4_inode_get_gid(&inode))) != nil && g->id == a->uid)){
+		m |= (fm >> 3) & 7;
+		if((p & m) == p)
+			return 1;
+	}
+
+	return 0;
+}
+
 static void
 rattach(Req *r)
 {
@@ -42,6 +134,9 @@
 		rerrstr(err, sizeof(err));
 		respond(r, err);
 	}else{
+		if(findgroup(&a->p->groups, r->ifcall.uname, &a->uid) == nil)
+			a->uid = Root; /* FIXME need external mapping */
+
 		incref(a->p);
 		a->type = Adir;
 		a->path = strdup("");
@@ -52,6 +147,34 @@
 	}
 }
 
+static u32int
+toext4mode(u32int mode, u32int perm, int creat)
+{
+	u32int e;
+
+	e = 0;
+	mode &= ~OCEXEC;
+
+	if(mode & OTRUNC){
+		mode &= ~OTRUNC;
+		e |= O_TRUNC;
+	}
+	if(mode == OWRITE)
+		e |= O_WRONLY;
+	else if(mode == ORDWR)
+		e |= O_RDWR;
+
+	if(creat)
+		e |= O_CREAT;
+
+	if(perm & DMEXCL)
+		e |= O_EXCL;
+	if(perm & DMAPPEND)
+		e |= O_APPEND;
+
+	return e;
+}
+
 static void
 ropen(Req *r)
 {
@@ -62,7 +185,7 @@
 	a = r->fid->aux;
 	switch(a->type){
 	case Adir:
-		if(r->ifcall.mode != OREAD){
+		if(r->ifcall.mode != OREAD || !haveperm(a, r->ifcall.mode)){
 			respond(r, "permission denied");
 			return;
 		}
@@ -88,7 +211,7 @@
 		break;
 
 	case Afile:
-		if(r->ifcall.mode != OREAD){
+		if(!haveperm(a, r->ifcall.mode)){
 			respond(r, "permission denied");
 			return;
 		}
@@ -103,7 +226,7 @@
 			a->file = nil;
 			goto Nomem;
 		}
-		res = ext4_fopen2(a->file, path, O_RDONLY);
+		res = ext4_fopen2(a->file, path, toext4mode(r->ifcall.mode, 0, 0));
 		free(path);
 		if(res != 0){
 			free(a->file);
@@ -127,40 +250,14 @@
 	respond(r, "nope");
 }
 
-static char *
-linkresolve(Aux *a, char *s)
-{
-	char *q;
-	char buf[4096+1];
-	ulong sz;
-
-	if(ext4_readlink(s, buf, sizeof(buf)-1, &sz) == 0){
-		buf[sz] = 0;
-		cleanname(buf);
-		if(buf[0] == '/'){
-			free(s);
-			s = smprint("%M%s", a->p, buf);
-		}else{
-			q = strrchr(s, '/');
-			*q = 0;
-			q = s;
-			s = smprint("%s/%s", q, buf);
-			cleanname(s);
-			free(q);
-		}
-	}
-
-	return s;
-}
-
 static int
 dirfill(Dir *dir, Aux *a, char *path)
 {
 	struct ext4_inode inode;
-	Group *g;
+	u32int t, ino;
 	char *s, *q;
-	int r, i;
-	u32int uid, gid, t, ino;
+	Group *g;
+	int r;
 
 	memset(dir, 0, sizeof(*dir));
 
@@ -196,14 +293,10 @@
 	dir->atime = ext4_inode_get_access_time(&inode);
 	dir->mtime = ext4_inode_get_modif_time(&inode);
 
-	uid = ext4_inode_get_uid(&inode);
-	gid = ext4_inode_get_gid(&inode);
-	for(i = 0, g = a->p->groups.g; i < a->p->groups.ng && (dir->uid == nil || dir->gid == nil); i++, g++){
-		if(g->id == uid)
-			dir->uid = estrdup9p(g->name);
-		if(g->id == gid)
-			dir->gid = estrdup9p(g->name);
-	}
+	if((g = findgroupid(&a->p->groups, ext4_inode_get_uid(&inode))) != nil)
+		dir->uid = estrdup9p(g->name);
+	if((g = findgroupid(&a->p->groups, ext4_inode_get_gid(&inode))) != nil)
+		dir->gid = estrdup9p(g->name);
 
 	free(s);
 
@@ -255,7 +348,26 @@
 static void
 rwrite(Req *r)
 {
-	respond(r, "nope");
+	Aux *a;
+	ulong n;
+	int res;
+
+	a = r->fid->aux;
+	if(a->type == Adir){
+		respond(r, "can't write to dir");
+		return;
+	}else if(a->type == Afile){
+		ext4_fseek(a->file, r->ifcall.offset, SEEK_SET);
+		if((res = ext4_fwrite(a->file, r->ifcall.data, r->ifcall.count, &n)) != 0)
+			respond(r, errno2s(res));
+		else{
+			r->ofcall.count = n;
+			respond(r, nil);
+		}
+		return;
+	}
+
+	respond(r, "eh?");
 }
 
 static void
--- a/group.c
+++ b/group.c
@@ -69,3 +69,39 @@
 	free(gs->g);
 	free(gs->raw);
 }
+
+Group *
+findgroup(Groups *gs, char *name, u32int *id)
+{
+	int i;
+	Group *g;
+
+	g = gs->g;
+	for(i = 0; i < gs->ng; i++, g++){
+		if(strcmp(g->name, name) == 0){
+			if(id != nil)
+				*id = g->id;
+			return g;
+		}
+	}
+
+	if(id != nil)
+		*id = ~0;
+
+	return nil;
+}
+
+Group *
+findgroupid(Groups *gs, u32int id)
+{
+	int i;
+	Group *g;
+
+	g = gs->g;
+	for(i = 0; i < gs->ng; i++, g++){
+		if(g->id == id)
+			return g;
+	}
+
+	return nil;
+}
--- a/group.h
+++ b/group.h
@@ -16,3 +16,5 @@
 
 int loadgroups(Groups *gs, char *raw);
 void freegroups(Groups *gs);
+Group *findgroup(Groups *gs, char *name, u32int *id);
+Group *findgroupid(Groups *gs, u32int id);