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);