ip/cifsd: implement primitive per-share unix id mapping for wstat()

front
cinap_lenrek 2020-05-02 16:53:52 +02:00
parent badbf50b0c
commit d0c87bada6
6 changed files with 208 additions and 20 deletions

View File

@ -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

View File

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

View File

@ -0,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);
}

View File

@ -6,6 +6,7 @@ TARG=cifsd
HFILES=dat.h fns.h
OFILES=\
idmap.$O \
pack.$O \
util.$O \
error.$O \

View File

@ -114,6 +114,8 @@ mapshare(char *path)
s->allocsize = 0;
s->freesize = s->blocksize;
unixidmap(s);
s->next = shares;
shares = s;

View File

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