sshfs: look up uid/gid from /etc/^(passwd group)
This commit is contained in:
parent
562fd5b134
commit
11954a19a6
1 changed files with 131 additions and 15 deletions
|
@ -15,7 +15,8 @@ enum {
|
||||||
MAXWRITE = 32768,
|
MAXWRITE = 32768,
|
||||||
MAXATTRIB = 64,
|
MAXATTRIB = 64,
|
||||||
VERSION = 3,
|
VERSION = 3,
|
||||||
MAXREQID = 32
|
MAXREQID = 32,
|
||||||
|
HASH = 64
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -84,6 +85,7 @@ char *errors[] = {
|
||||||
|
|
||||||
typedef struct SFid SFid;
|
typedef struct SFid SFid;
|
||||||
typedef struct SReq SReq;
|
typedef struct SReq SReq;
|
||||||
|
typedef struct IDEnt IDEnt;
|
||||||
|
|
||||||
struct SFid {
|
struct SFid {
|
||||||
RWLock;
|
RWLock;
|
||||||
|
@ -103,6 +105,13 @@ struct SReq {
|
||||||
SReq *next;
|
SReq *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IDEnt {
|
||||||
|
char *name;
|
||||||
|
int id;
|
||||||
|
IDEnt *next;
|
||||||
|
};
|
||||||
|
IDEnt *uidtab[HASH], *gidtab[HASH];
|
||||||
|
|
||||||
int rdfd, wrfd;
|
int rdfd, wrfd;
|
||||||
SReq *sreqrd[MAXREQID];
|
SReq *sreqrd[MAXREQID];
|
||||||
QLock sreqidlock;
|
QLock sreqidlock;
|
||||||
|
@ -154,6 +163,34 @@ fxpfmt(Fmt *f)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
idlookup(IDEnt **tab, int id)
|
||||||
|
{
|
||||||
|
IDEnt *p;
|
||||||
|
|
||||||
|
for(p = tab[(ulong)id % HASH]; p != nil; p = p->next)
|
||||||
|
if(p->id == id)
|
||||||
|
return strdup(p->name);
|
||||||
|
return smprint("%d", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
namelookup(IDEnt **tab, char *name)
|
||||||
|
{
|
||||||
|
IDEnt *p;
|
||||||
|
int i;
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
for(i = 0; i < HASH; i++)
|
||||||
|
for(p = tab[i]; p != nil; p = p->next)
|
||||||
|
if(strcmp(p->name, name) == 0)
|
||||||
|
return p->id;
|
||||||
|
i = strtol(name, &q, 10);
|
||||||
|
if(*q == 0) return i;
|
||||||
|
werrstr("unknown %s '%s'", tab == uidtab ? "user" : "group", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vpack(uchar *p, int n, char *fmt, va_list a)
|
vpack(uchar *p, int n, char *fmt, va_list a)
|
||||||
{
|
{
|
||||||
|
@ -471,8 +508,8 @@ attrib2dir(uchar *p0, uchar *ep, Dir *d)
|
||||||
}
|
}
|
||||||
if((flags & SSH_FILEXFER_ATTR_UIDGID) != 0){
|
if((flags & SSH_FILEXFER_ATTR_UIDGID) != 0){
|
||||||
rc = unpack(p, ep - p, "uu", &uid, &gid); if(rc < 0) return -1; p += rc;
|
rc = unpack(p, ep - p, "uu", &uid, &gid); if(rc < 0) return -1; p += rc;
|
||||||
d->uid = smprint("%d", uid);
|
d->uid = idlookup(uidtab, uid);
|
||||||
d->gid = smprint("%d", gid);
|
d->gid = idlookup(gidtab, gid);
|
||||||
}else{
|
}else{
|
||||||
d->uid = strdup("sshfs");
|
d->uid = strdup("sshfs");
|
||||||
d->gid = strdup("sshfs");
|
d->gid = strdup("sshfs");
|
||||||
|
@ -502,7 +539,6 @@ dir2attrib(Dir *d, uchar **rp)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
uchar *r, *p, *e;
|
uchar *r, *p, *e;
|
||||||
char *pp;
|
|
||||||
u32int fl;
|
u32int fl;
|
||||||
int uid, gid;
|
int uid, gid;
|
||||||
|
|
||||||
|
@ -518,19 +554,15 @@ dir2attrib(Dir *d, uchar **rp)
|
||||||
if(d->uid != nil && *d->uid != 0 || d->gid != nil && *d->gid != 0){
|
if(d->uid != nil && *d->uid != 0 || d->gid != nil && *d->gid != 0){
|
||||||
/* FIXME: sending -1 for "don't change" works with openssh, but violates the spec */
|
/* FIXME: sending -1 for "don't change" works with openssh, but violates the spec */
|
||||||
if(d->uid != nil && *d->uid != 0){
|
if(d->uid != nil && *d->uid != 0){
|
||||||
uid = strtol(d->uid, &pp, 10);
|
uid = namelookup(uidtab, d->uid);
|
||||||
if(*pp != 0){
|
if(uid == -1)
|
||||||
werrstr("uid not a number");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
}else
|
}else
|
||||||
uid = -1;
|
uid = -1;
|
||||||
if(d->gid != nil && *d->gid != 0){
|
if(d->gid != nil && *d->gid != 0){
|
||||||
gid = strtol(d->gid, &pp, 10);
|
gid = namelookup(gidtab, d->gid);
|
||||||
if(*pp != 0){
|
if(gid == -1)
|
||||||
werrstr("gid not a number");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
}else
|
}else
|
||||||
gid = -1;
|
gid = -1;
|
||||||
fl |= SSH_FILEXFER_ATTR_UIDGID;
|
fl |= SSH_FILEXFER_ATTR_UIDGID;
|
||||||
|
@ -1113,6 +1145,79 @@ Srv sshfssrv = {
|
||||||
.end sshfsend
|
.end sshfsend
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char *
|
||||||
|
readfile(char *fn)
|
||||||
|
{
|
||||||
|
char *hand, *dat;
|
||||||
|
int handn, datn;
|
||||||
|
u32int code;
|
||||||
|
char *p;
|
||||||
|
int off;
|
||||||
|
|
||||||
|
if(fn == nil) return nil;
|
||||||
|
sendpkt("busuu", SSH_FXP_OPEN, 0, fn, strlen(fn), SSH_FXF_READ, 0);
|
||||||
|
if(recvpkt() != SSH_FXP_HANDLE) return nil;
|
||||||
|
if(unpack(rxpkt, rxlen, "_____s", &dat, &handn) < 0) return nil;
|
||||||
|
hand = emalloc9p(handn);
|
||||||
|
memcpy(hand, dat, handn);
|
||||||
|
off = 0;
|
||||||
|
p = nil;
|
||||||
|
for(;;){
|
||||||
|
sendpkt("busvu", SSH_FXP_READ, 0, hand, handn, (uvlong)off, MAXWRITE);
|
||||||
|
switch(recvpkt()){
|
||||||
|
case SSH_FXP_STATUS:
|
||||||
|
if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto err;
|
||||||
|
print("%d\n", code);
|
||||||
|
if(code == SSH_FX_EOF) goto out;
|
||||||
|
default:
|
||||||
|
goto err;
|
||||||
|
case SSH_FXP_DATA:
|
||||||
|
if(unpack(rxpkt, rxlen, "_____s", &dat, &datn) < 0) goto err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = erealloc9p(p, off + datn + 1);
|
||||||
|
memcpy(p + off, dat, datn);
|
||||||
|
off += datn;
|
||||||
|
p[off] = 0;
|
||||||
|
}
|
||||||
|
err:
|
||||||
|
p = nil;
|
||||||
|
out:
|
||||||
|
sendpkt("bus", SSH_FXP_CLOSE, 0, hand, handn);
|
||||||
|
free(hand);
|
||||||
|
recvpkt();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
passwdparse(IDEnt **tab, char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *n;
|
||||||
|
int id;
|
||||||
|
IDEnt *e, **b;
|
||||||
|
|
||||||
|
p = s;
|
||||||
|
for(;;){
|
||||||
|
n = p;
|
||||||
|
p = strpbrk(p, ":\n"); if(p == nil) break; if(*p != ':'){ p++; continue; }
|
||||||
|
*p = 0;
|
||||||
|
p = strpbrk(p+1, ":\n");
|
||||||
|
p = strpbrk(p, ":\n"); if(p == nil) break; if(*p != ':'){ p++; continue; }
|
||||||
|
id = strtol(p+1, &p, 10);
|
||||||
|
p = strchr(p, '\n');
|
||||||
|
if(p == nil) break;
|
||||||
|
p++;
|
||||||
|
e = emalloc9p(sizeof(IDEnt));
|
||||||
|
e->name = strdup(n);
|
||||||
|
e->id = id;
|
||||||
|
b = &tab[((ulong)e->id) % HASH];
|
||||||
|
e->next = *b;
|
||||||
|
*b = e;
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
int sshargc;
|
int sshargc;
|
||||||
char **sshargv;
|
char **sshargv;
|
||||||
|
@ -1137,9 +1242,10 @@ startssh(void *)
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
fprint(2, "usage: %s [-abdR] [-s service] [-m mtpt] [-- ssh options] host\n", argv0);
|
static char *common = "[-abdRUG] [-s service] [-m mtpt] [-u uidfile] [-g gidfile]";
|
||||||
fprint(2, " %s [-abdR] [-s service] [-m mtpt] -c cmdline\n", argv0);
|
fprint(2, "usage: %s %s [-- ssh-options] host\n", argv0, common);
|
||||||
fprint(2, " %s [-abdR] [-s service] [-m mtpt] -p\n", argv0);
|
fprint(2, " %s %s -c cmdline\n", argv0, common);
|
||||||
|
fprint(2, " %s %s -p\n", argv0, common);
|
||||||
exits("usage");
|
exits("usage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1150,10 +1256,13 @@ threadmain(int argc, char **argv)
|
||||||
static int pflag, cflag;
|
static int pflag, cflag;
|
||||||
static char *svc, *mtpt;
|
static char *svc, *mtpt;
|
||||||
static int mflag;
|
static int mflag;
|
||||||
|
static char *uidfile, *gidfile;
|
||||||
|
|
||||||
fmtinstall(L'Σ', fxpfmt);
|
fmtinstall(L'Σ', fxpfmt);
|
||||||
|
|
||||||
mtpt = "/n/ssh";
|
mtpt = "/n/ssh";
|
||||||
|
uidfile = "/etc/passwd";
|
||||||
|
gidfile = "/etc/group";
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
case 'R': readonly++; break;
|
case 'R': readonly++; break;
|
||||||
case 'd': debug++; chatty9p++; break;
|
case 'd': debug++; chatty9p++; break;
|
||||||
|
@ -1163,6 +1272,10 @@ threadmain(int argc, char **argv)
|
||||||
case 'a': mflag |= MAFTER; break;
|
case 'a': mflag |= MAFTER; break;
|
||||||
case 'b': mflag |= MBEFORE; break;
|
case 'b': mflag |= MBEFORE; break;
|
||||||
case 'm': mtpt = EARGF(usage()); break;
|
case 'm': mtpt = EARGF(usage()); break;
|
||||||
|
case 'u': uidfile = EARGF(usage()); break;
|
||||||
|
case 'U': uidfile = nil; break;
|
||||||
|
case 'g': gidfile = EARGF(usage()); break;
|
||||||
|
case 'G': gidfile = nil; break;
|
||||||
default: usage();
|
default: usage();
|
||||||
}ARGEND;
|
}ARGEND;
|
||||||
|
|
||||||
|
@ -1198,6 +1311,9 @@ threadmain(int argc, char **argv)
|
||||||
if(recvpkt() != SSH_FXP_VERSION || unpack(rxpkt, rxlen, "_u", &x) < 0) sysfatal("received garbage");
|
if(recvpkt() != SSH_FXP_VERSION || unpack(rxpkt, rxlen, "_u", &x) < 0) sysfatal("received garbage");
|
||||||
if(x != VERSION) sysfatal("server replied with incompatible version %d", x);
|
if(x != VERSION) sysfatal("server replied with incompatible version %d", x);
|
||||||
|
|
||||||
|
passwdparse(uidtab, readfile(uidfile));
|
||||||
|
passwdparse(gidtab, readfile(gidfile));
|
||||||
|
|
||||||
procrfork(sendproc, 0, mainstacksize, RFNOTEG);
|
procrfork(sendproc, 0, mainstacksize, RFNOTEG);
|
||||||
procrfork(recvproc, 0, mainstacksize, RFNOTEG);
|
procrfork(recvproc, 0, mainstacksize, RFNOTEG);
|
||||||
threadpostmountsrv(&sshfssrv, svc, mtpt, MCREATE | mflag);
|
threadpostmountsrv(&sshfssrv, svc, mtpt, MCREATE | mflag);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue