From d0c87bada6e1d3822a414a48c6ee75da68361a19 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 2 May 2020 16:53:52 +0200 Subject: [PATCH] ip/cifsd: implement primitive per-share unix id mapping for wstat() --- sys/src/cmd/ip/cifsd/dat.h | 6 ++ sys/src/cmd/ip/cifsd/fns.h | 6 ++ sys/src/cmd/ip/cifsd/idmap.c | 175 +++++++++++++++++++++++++++++++++++ sys/src/cmd/ip/cifsd/mkfile | 1 + sys/src/cmd/ip/cifsd/share.c | 2 + sys/src/cmd/ip/cifsd/smb.c | 38 ++++---- 6 files changed, 208 insertions(+), 20 deletions(-) create mode 100644 sys/src/cmd/ip/cifsd/idmap.c diff --git a/sys/src/cmd/ip/cifsd/dat.h b/sys/src/cmd/ip/cifsd/dat.h index 94235cf48..15f53d319 100644 --- a/sys/src/cmd/ip/cifsd/dat.h +++ b/sys/src/cmd/ip/cifsd/dat.h @@ -6,6 +6,9 @@ typedef struct Share Share; typedef struct File File; typedef struct Find Find; typedef struct Tree Tree; +typedef struct Idmap Idmap; + +#pragma incomplete Idmap struct Rop { @@ -96,6 +99,9 @@ struct Share vlong freesize; int sectorsize; int blocksize; + + Idmap *users; + Idmap *groups; }; struct Tree diff --git a/sys/src/cmd/ip/cifsd/fns.h b/sys/src/cmd/ip/cifsd/fns.h index 2bf1ae4b9..71f96be5b 100644 --- a/sys/src/cmd/ip/cifsd/fns.h +++ b/sys/src/cmd/ip/cifsd/fns.h @@ -83,3 +83,9 @@ void putfind(Find *f); int xdirread(char **path, int (*namecmp)(char *, char *), Dir **d); Dir *xdirstat(char **path, int (*namecmp)(char *, char *)); void xdirflush(char *path, int (*namecmp)(char *, char *)); + +/* idmap */ +void unixidmap(Share *share); +char* unixname(Share *share, int id, int group); +int unixuid(Share *share, char *name); +int unixgid(Share *share, char *name); diff --git a/sys/src/cmd/ip/cifsd/idmap.c b/sys/src/cmd/ip/cifsd/idmap.c new file mode 100644 index 000000000..178d99b19 --- /dev/null +++ b/sys/src/cmd/ip/cifsd/idmap.c @@ -0,0 +1,175 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +#include + +enum { + NHASH = 251, +}; + +typedef struct Ident Ident; +struct Ident +{ + Ident *nextid; + Ident *nextname; + int id; + char name[]; +}; + +struct Idmap +{ + Ident *tab[NHASH]; +}; + +static Ident** +nametab(Idmap *map, char *name) +{ + return &map->tab[(uint)namehash(name) % NHASH]; +} +static Ident** +idtab(Idmap *map, int id) +{ + return &map->tab[(uint)id % NHASH]; +} + +static int +name2id(Idmap *map, char *name) +{ + Ident *e; + + for(e = *nametab(map, name); e != nil; e = e->nextid){ + if(strcmp(e->name, name) == 0) + return e->id; + } + return -1; +} + +static char* +id2name(Idmap *map, int id) +{ + Ident *e; + + for(e = *idtab(map, id); e != nil; e = e->nextname){ + if(e->id == id) + return e->name; + } + return nil; +} + +static void +idmap(Idmap *map, char *name, int id) +{ + Ident *e, **h; + int n; + + n = strlen(name)+1; + e = malloc(sizeof(Ident)+n); + if(e == nil) + return; + + e->id = id; + h = idtab(map, e->id); + e->nextid = *h; + *h = e; + + memmove(e->name, name, n); + h = nametab(map, e->name); + e->nextname = *h; + *h = e; +} + +static Idmap* +readidmap(char *file, int style) +{ + Biobuf *b; + Idmap *m; + char *l, *name; + int id; + + if((b = Bopen(file, OREAD)) == nil) + return nil; + + if((m = mallocz(sizeof(*m), 1)) == nil) + goto Out; + + while((l = Brdline(b, '\n')) != nil){ + l[Blinelen(b)-1] = 0; + switch(style){ + case '9': + id = 9000000 + strtol(l, &l, 10); + if(*l != ':') + continue; + name = ++l; + l = strchr(l, ':'); + if(l == 0) + continue; + *l = 0; + break; + default: + name = l; + l = strchr(l, ':'); + if(l == 0) + continue; + *l++ = 0; + /* skip password */ + l = strchr(l, ':'); + if(l == 0) + continue; + id = strtol(l+1, 0, 10); + break; + } + idmap(m, name, id); + } +Out: + Bterm(b); + + return m; +} + +void +unixidmap(Share *share) +{ + static Idmap emptymap; + char *file; + + if(share->stype != STYPE_DISKTREE) + goto Out; + + file = smprint("%s/etc/passwd", share->root); + share->users = readidmap(file, 'u'); + free(file); + file = smprint("%s/etc/group", share->root); + share->groups = readidmap(file, 'u'); + free(file); + if(share->users != nil && share->groups != nil) + return; + + file = smprint("%s/adm/users", share->root); + share->users = share->groups = readidmap(file, '9'); + free(file); + if(share->users != nil && share->groups != nil) + return; + +Out: + share->users = share->groups = &emptymap; +} + +char* +unixname(Share *share, int id, int group) +{ + return id2name(group? share->groups: share->users, id); +} + +int +unixuid(Share *share, char *name) +{ + return name2id(share->users, name); +} + +int +unixgid(Share *share, char *name) +{ + return name2id(share->groups, name); +} diff --git a/sys/src/cmd/ip/cifsd/mkfile b/sys/src/cmd/ip/cifsd/mkfile index da0ec1e50..142b657f0 100644 --- a/sys/src/cmd/ip/cifsd/mkfile +++ b/sys/src/cmd/ip/cifsd/mkfile @@ -6,6 +6,7 @@ TARG=cifsd HFILES=dat.h fns.h OFILES=\ + idmap.$O \ pack.$O \ util.$O \ error.$O \ diff --git a/sys/src/cmd/ip/cifsd/share.c b/sys/src/cmd/ip/cifsd/share.c index e14014085..b74ae0a8b 100644 --- a/sys/src/cmd/ip/cifsd/share.c +++ b/sys/src/cmd/ip/cifsd/share.c @@ -114,6 +114,8 @@ mapshare(char *path) s->allocsize = 0; s->freesize = s->blocksize; + unixidmap(s); + s->next = shares; shares = s; diff --git a/sys/src/cmd/ip/cifsd/smb.c b/sys/src/cmd/ip/cifsd/smb.c index 08278e609..b7cd2cc15 100644 --- a/sys/src/cmd/ip/cifsd/smb.c +++ b/sys/src/cmd/ip/cifsd/smb.c @@ -1019,16 +1019,6 @@ smbqueryinformationdisk(Req *r, uchar *h, uchar *p, uchar *e) r->respond(r, 0); } -static int -unixuid(char *) -{ - return 99999; -} -static int -unixgid(char *) -{ - return 99999; -} static int unixtype(Dir *d) { @@ -1081,7 +1071,7 @@ fpackdir(Req *r, Dir *d, Tree *t, int i, int level, uchar *b, uchar *p, uchar *e 0, i, dlen, alen, mtime, atime, mtime, - (vlong)unixuid(d->uid), (vlong)unixgid(d->gid), unixtype(d), + (vlong)unixuid(share, d->uid), (vlong)unixgid(share, d->gid), unixtype(d), 0LL, 0LL, /* MAJ/MIN */ (vlong)d->qid.path, (vlong)d->mode & 0777, @@ -1147,7 +1137,7 @@ qpackdir(Req *, Dir *d, Tree *t, File *f, int level, uchar *b, uchar *p, uchar * return pack(b, p, e, "vvvvvvvlvvvvv", dlen, alen, mtime, atime, mtime, - (vlong)unixuid(d->uid), (vlong)unixgid(d->gid), unixtype(d), + (vlong)unixuid(share, d->uid), (vlong)unixgid(share, d->gid), unixtype(d), 0LL, 0LL, /* MAJ/MIN */ (vlong)d->qid.path, (vlong)d->mode & 0777, @@ -1229,10 +1219,10 @@ out: } static int -setfilepathinformation(Req *r, Dir *d, File *f, char *path, int level, uchar *b, uchar *p, uchar *e) +setfilepathinformation(Req *r, Dir *d, Tree *t, File *f, char *path, int level, uchar *b, uchar *p, uchar *e) { int attr, adt, atm, mdt, mtm, delete; - vlong len, ctime, atime, mtime, mode; + vlong len, ctime, atime, mtime, mode, uid, gid; Dir nd; nulldir(&nd); @@ -1283,8 +1273,8 @@ setfilepathinformation(Req *r, Dir *d, File *f, char *path, int level, uchar *b, break; case 0x0200: /* SMB_SET_FILE_UNIX_BASIC */ - if(!unpack(b, p, e, "v________vvv____________________________________________v________", - &len, &ctime, &atime, &mtime, &mode)) + if(!unpack(b, p, e, "v________vvvvv____________________________v________", + &len, &ctime, &atime, &mtime, &uid, &gid, &mode)) goto unsup; if(len != -1LL) nd.length = len; @@ -1294,6 +1284,14 @@ setfilepathinformation(Req *r, Dir *d, File *f, char *path, int level, uchar *b, nd.mtime = fromfiletime(mtime); else if(ctime && ctime != -1LL) nd.mtime = fromfiletime(ctime); + if(uid != -1LL){ + if((nd.uid = unixname(t->share, (int)uid, 0)) == nil) + return STATUS_SMB_BAD_UID; + } + if(gid != -1LL){ + if((nd.gid = unixname(t->share, (int)gid, 1)) == nil) + return STATUS_SMB_BAD_UID; + } if(mode != -1LL) nd.mode = (d->mode & ~0777) | (mode & 0777); break; @@ -1305,8 +1303,8 @@ setfilepathinformation(Req *r, Dir *d, File *f, char *path, int level, uchar *b, return STATUS_NOT_SUPPORTED; } if(debug) - fprint(2, "wstat\nmode %lo\natime %ld\nmtime %ld\nlength %llux\n", - nd.mode, nd.atime, nd.mtime, nd.length); + fprint(2, "wstat\nmode %lo\natime %ld\nmtime %ld\nlength %llux\nuid %s\ngid %s\n", + nd.mode, nd.atime, nd.mtime, nd.length, nd.uid, nd.gid); if(((f && f->fd >= 0) ? dirfwstat(f->fd, &nd) : dirwstat(path, &nd)) < 0) return smbmkerror(); xdirflush(path, r->namecmp); @@ -1334,7 +1332,7 @@ trans2setpathinformation(Trans *t) t->respond(t, smbmkerror()); goto out; } - if(err = setfilepathinformation(t->r, d, nil, path, level, t->in.data.b, t->in.data.p, t->in.data.e)){ + if(err = setfilepathinformation(t->r, d, tree, nil, path, level, t->in.data.b, t->in.data.p, t->in.data.e)){ errout: t->respond(t, err); goto out; @@ -1367,7 +1365,7 @@ trans2setfileinformation(Trans *t) t->respond(t, smbmkerror()); goto out; } - if(err = setfilepathinformation(t->r, d, f, f->path, level, t->in.data.b, t->in.data.p, t->in.data.e)){ + if(err = setfilepathinformation(t->r, d, tree, f, f->path, level, t->in.data.b, t->in.data.p, t->in.data.e)){ errout: t->respond(t, err); goto out;