ref: d0c87bada6e1d3822a414a48c6ee75da68361a19
parent: badbf50b0cc21c0faaae6daddf086f76bc871086
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat May 2 12:53:52 EDT 2020
ip/cifsd: implement primitive per-share unix id mapping for wstat()
--- a/sys/src/cmd/ip/cifsd/dat.h
+++ b/sys/src/cmd/ip/cifsd/dat.h
@@ -6,7 +6,10 @@
typedef struct File File;
typedef struct Find Find;
typedef struct Tree Tree;
+typedef struct Idmap Idmap;
+#pragma incomplete Idmap
+
struct Rop
{
int (*strpack)(uchar *, uchar *, uchar *, void *);
@@ -96,6 +99,9 @@
vlong freesize;
int sectorsize;
int blocksize;
+
+ Idmap *users;
+ Idmap *groups;
};
struct Tree
--- a/sys/src/cmd/ip/cifsd/fns.h
+++ b/sys/src/cmd/ip/cifsd/fns.h
@@ -83,3 +83,9 @@
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);
--- /dev/null
+++ b/sys/src/cmd/ip/cifsd/idmap.c
@@ -1,0 +1,175 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#include <bio.h>
+
+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);
+}
--- a/sys/src/cmd/ip/cifsd/mkfile
+++ b/sys/src/cmd/ip/cifsd/mkfile
@@ -6,6 +6,7 @@
HFILES=dat.h fns.h
OFILES=\
+ idmap.$O \
pack.$O \
util.$O \
error.$O \
--- a/sys/src/cmd/ip/cifsd/share.c
+++ b/sys/src/cmd/ip/cifsd/share.c
@@ -114,6 +114,8 @@
s->allocsize = 0;
s->freesize = s->blocksize;
+ unixidmap(s);
+
s->next = shares;
shares = s;
--- a/sys/src/cmd/ip/cifsd/smb.c
+++ b/sys/src/cmd/ip/cifsd/smb.c
@@ -1020,16 +1020,6 @@
}
static int
-unixuid(char *)
-{
- return 99999;
-}
-static int
-unixgid(char *)
-{
- return 99999;
-}
-static int
unixtype(Dir *d)
{
return (d->qid.type & QTDIR) != 0;
@@ -1081,7 +1071,7 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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;