shithub: riscv

Download patch

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;