ref: bc36c6b77688a51db606c14b6d9f84b529e043d9
parent: 12a0ed55204affb277def2a73c1769bd76105ed4
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu Nov 12 07:23:35 EST 2020
better permission logic; add -l hide option to hide links; implement remove
--- a/common.h
+++ b/common.h
@@ -8,6 +8,7 @@
struct Opts {
int cachewb;
+ int linkmode;
};
struct Part {
@@ -26,6 +27,10 @@
Groups groups;
int f;
uchar blkbuf[];
+};
+
+enum {
+ Lhide = 1,
};
Part *openpart(char *dev, Opts *opts);
--- a/ext4srv.c
+++ b/ext4srv.c
@@ -28,19 +28,29 @@
Root = 0,
};
-static Opts opts = {
- .cachewb = 0,
-};
+static Opts opts;
static char *
-linkresolve(Aux *a, char *s)
+linkresolve(Aux *a, char *s, char **value)
{
- char *q;
- char buf[4096+1];
+ char *q, buf[4096+1];
ulong sz;
- if(ext4_readlink(s, buf, sizeof(buf)-1, &sz) == 0){
+ if(ext4_readlink(s, buf, sizeof(buf), &sz) == 0){
+ if(sz == sizeof(buf)){
+ werrstr("readlink: %s: path too long", s);
+ free(s);
+ return nil;
+ }
+ if(opts.linkmode == Lhide){
+ werrstr("linkresolve: %s: links are hidden", s);
+ free(s);
+ return nil;
+ }
+
buf[sz] = 0;
+ if(value != nil)
+ *value = strdup(buf);
cleanname(buf);
if(buf[0] == '/'){
free(s);
@@ -53,6 +63,8 @@
cleanname(s);
free(q);
}
+ }else if(value != nil){
+ *value = nil;
}
return s;
@@ -61,7 +73,7 @@
static char *
fullpath(Aux *a)
{
- return linkresolve(a, smprint("%M/%s", a->p, a->path));
+ return linkresolve(a, smprint("%M/%s", a->p, a->path), nil);
}
static int
@@ -68,10 +80,10 @@
haveperm(Aux *a, int p)
{
struct ext4_inode inode;
- u32int ino;
+ u32int ino, id;
+ int m, fm, r;
Group *g;
char *s;
- int m, fm, r;
switch(p & 3){
case OREAD:
@@ -90,10 +102,12 @@
return 0;
}
- s = fullpath(a);
+ if((s = fullpath(a)) == nil)
+ return -1;
if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0){
- fprint(2, "inode: %s: %s\n", s, errno2s(r));
- return 0;
+ werrstr("%s: %s", s, errno2s(r));
+ free(s);
+ return -1;
}
free(s);
@@ -105,7 +119,8 @@
return 1;
/* owner */
- if(a->uid == Root || ((g = findgroupid(&a->p->groups, ext4_inode_get_uid(&inode))) != nil && g->id == a->uid)){
+ id = ext4_inode_get_uid(&inode);
+ if(a->uid == Root || ((g = findgroupid(&a->p->groups, id)) != nil && ingroup(g, a->uid))){
m |= (fm >> 6) & 7;
if((p & m) == p)
return 1;
@@ -112,7 +127,8 @@
}
/* group */
- if(a->uid == Root || ((g = findgroupid(&a->p->groups, ext4_inode_get_gid(&inode))) != nil && g->id == a->uid)){
+ id = ext4_inode_get_gid(&inode);
+ if(a->uid == Root || ((g = findgroupid(&a->p->groups, id)) != nil && ingroup(g, a->uid))){
m |= (fm >> 3) & 7;
if((p & m) == p)
return 1;
@@ -124,8 +140,8 @@
static void
rattach(Req *r)
{
+ char err[ERRMAX];
Aux *a;
- static char err[ERRMAX];
if((a = calloc(1, sizeof(*a))) == nil)
respond(r, "memory");
@@ -254,7 +270,8 @@
dirfill(Dir *dir, Aux *a, char *path)
{
struct ext4_inode inode;
- u32int t, ino;
+ u32int t, ino, id;
+ char tmp[16];
char *s, *q;
Group *g;
int r;
@@ -269,9 +286,13 @@
path = "/";
s = smprint("%M%s%s/%s", a->p, *a->path ? "/" : "", a->path, path);
}
- s = linkresolve(a, s);
- if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0)
- fprint(2, "inode: %s: %s\n", s, errno2s(r));
+ if((s = linkresolve(a, s, nil)) == nil)
+ return -1;
+ if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0){
+ werrstr("%s: %s", s, errno2s(r));
+ free(s);
+ return -1;
+ }
dir->mode = ext4_inode_get_mode(a->p->sb, &inode);
dir->qid.path = a->p->qidmask.path | ino;
@@ -293,11 +314,12 @@
dir->atime = ext4_inode_get_access_time(&inode);
dir->mtime = ext4_inode_get_modif_time(&inode);
- 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);
+ sprint(tmp, "%ud", id = ext4_inode_get_uid(&inode));
+ dir->uid = estrdup9p((g = findgroupid(&a->p->groups, id)) != nil ? g->name : tmp);
+ sprint(tmp, "%ud", id = ext4_inode_get_gid(&inode));
+ dir->gid = estrdup9p((g = findgroupid(&a->p->groups, id)) != nil ? g->name : tmp);
+
free(s);
return 0;
@@ -312,12 +334,16 @@
a = aux;
if(n == 0)
ext4_dir_entry_rewind(a->dir);
- do{
- if((e = ext4_dir_entry_next(a->dir)) == nil)
- return -1;
- }while(strcmp((char*)e->name, ".") == 0 || strcmp((char*)e->name, "..") == 0);
- return dirfill(dir, a, (char*)e->name);
+ for(;;){
+ do{
+ if((e = ext4_dir_entry_next(a->dir)) == nil)
+ return -1;
+ }while(strcmp((char*)e->name, ".") == 0 || strcmp((char*)e->name, "..") == 0);
+
+ if(dirfill(dir, a, (char*)e->name) == 0)
+ return 0;
+ }
}
static void
@@ -373,7 +399,52 @@
static void
rremove(Req *r)
{
- respond(r, "nope");
+ struct ext4_inode inode;
+ const ext4_direntry *e;
+ u32int ino, t, empty;
+ char *s, *err;
+ ext4_dir dir;
+ Group *g;
+ int res;
+ Aux *a;
+
+ a = r->fid->aux;
+ err = nil;
+
+ /* do not resolve links here as most likely it's JUST the link we want to remove */
+ if((s = smprint("%M/%s", a->p, a->path)) == nil){
+ err = "memory";
+ goto end;
+ }
+ if((res = ext4_raw_inode_fill(s, &ino, &inode)) != 0){
+ext4error:
+ err = errno2s(res);
+ goto end;
+ }
+
+ if(a->uid == Root || ((g = findgroupid(&a->p->groups, ext4_inode_get_uid(&inode))) != nil && g->id == a->uid)){
+ t = ext4_inode_type(a->p->sb, &inode);
+ if((t & EXT4_INODE_MODE_DIRECTORY) != 0 && ext4_dir_open(&dir, s) == 0){
+ do{
+ e = ext4_dir_entry_next(&dir);
+ empty = e == nil;
+ if(empty)
+ break;
+ }while(strcmp((char*)e->name, ".") == 0 || strcmp((char*)e->name, "..") == 0);
+ ext4_dir_close(&dir);
+ if(!empty)
+ err = "directory not empty";
+ else if((res = ext4_dir_rm(s)) != 0)
+ goto ext4error;
+ }else if((res = ext4_fremove(s)) != 0)
+ goto ext4error;
+ }else{
+ err = "permission denied";
+ }
+
+end:
+ free(s);
+ respond(r, err);
}
static void
@@ -380,11 +451,15 @@
rstat(Req *r)
{
Aux *a;
+ char err[ERRMAX];
a = r->fid->aux;
- dirfill(&r->d, a, nil);
-
- respond(r, nil);
+ if(dirfill(&r->d, a, nil) != 0){
+ rerrstr(err, sizeof(err));
+ respond(r, err);
+ }else{
+ respond(r, nil);
+ }
}
static void
@@ -396,22 +471,43 @@
static char *
rwalk1(Fid *fid, char *name, Qid *qid)
{
- Aux *a;
- char *s, *q;
- u32int ino, t;
+ static char errbuf[ERRMAX];
struct ext4_inode inode;
+ u32int ino, t;
+ Aux *a, dir;
+ char *s, *q;
int r;
a = fid->aux;
- s = smprint("%M/%s", a->p, a->path);
- s = linkresolve(a, s);
+ /* try walking to the real file first */
+ if((s = fullpath(a)) == nil){
+ /* else try link itself. might want to just remove it anyway */
+ if((s = smprint("%M/%s", a->p, a->path)) == nil){
+ r = ENOMEM;
+ goto error;
+ }
+ }
+ if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0)
+ goto error;
+ t = ext4_inode_type(a->p->sb, &inode);
+ if((t & EXT4_INODE_MODE_DIRECTORY) == 0){
+ free(s);
+ return "not a directory";
+ }
+ dir = *a;
+ dir.path = s;
+ if(!haveperm(&dir, OEXEC)){
+ free(s);
+ return "permission denied";
+ }
q = s;
s = smprint("%s/%s", q, name);
cleanname(s);
free(q);
- s = linkresolve(a, s);
+ if((s = linkresolve(a, s, nil)) == nil)
+ goto error;
if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0)
goto error;
qid->type = 0;
@@ -536,10 +632,20 @@
static void
usage(void)
{
- fprint(2, "usage: %s [-C] [-s srvname]\n", argv0);
+ fprint(2, "usage: %s [-C] [-l hide] [-s srvname]\n", argv0);
threadexitsall("usage");
}
+static int
+linkmode(char *m)
+{
+ if(strcmp(m, "hide") == 0)
+ return Lhide;
+
+ usage();
+ return -1;
+}
+
void
threadmain(int argc, char **argv)
{
@@ -553,8 +659,12 @@
case 'C':
opts.cachewb = 1;
break;
+ case 'l':
+ opts.linkmode = linkmode(EARGF(usage()));
+ break;
case 's':
srv = EARGF(usage());
+ break;
}ARGEND
if(argc != 0)
--- a/group.c
+++ b/group.c
@@ -5,9 +5,9 @@
int
loadgroups(Groups *gs, char *raw)
{
- Group *g;
- char *m, **memb, *s, *e, *a[5], *ide;
- int line, n;
+ Group *g, *memb;
+ char *m, *s, *e, *a[5], *ide;
+ int line, n, k;
vlong id;
memset(gs, 0, sizeof(*gs));
@@ -38,7 +38,7 @@
goto error;
g->memb = memb;
memb += g->nmemb++;
- *memb = m;
+ memb->name = m;
if((m = strchr(m, ',')) == nil)
break;
}
@@ -51,6 +51,12 @@
break;
}
+ g = gs->g;
+ for(n = 0; n < gs->ng; n++, g++){
+ for(k = 0; k < g->nmemb; k++)
+ findgroup(gs, g->memb[k].name, &g->memb[k].id);
+ }
+
return 0;
error:
werrstr("togroups: %r");
@@ -104,4 +110,20 @@
}
return nil;
+}
+
+int
+ingroup(Group *g, u32int id)
+{
+ int i;
+
+ if(g->id == id)
+ return 1;
+
+ for(i = 0, g = g->memb; i < g->nmemb; i++, g++){
+ if(g->id == id)
+ return 1;
+ }
+
+ return 0;
}
--- a/group.h
+++ b/group.h
@@ -4,7 +4,7 @@
struct Group {
u32int id;
char *name;
- char **memb;
+ Group *memb;
int nmemb;
};
@@ -18,3 +18,4 @@
void freegroups(Groups *gs);
Group *findgroup(Groups *gs, char *name, u32int *id);
Group *findgroupid(Groups *gs, u32int id);
+int ingroup(Group *g, u32int id);