commit 5c84c448b82c7bfdfeaae533783aa09317656e86 from: rsc date: Mon Mar 21 17:24:21 2005 UTC add srv -a option commit - b8c9f31785f3243a52432023d4d555d490963769 commit + 5c84c448b82c7bfdfeaae533783aa09317656e86 blob - 510c16e8230b88807c9a3dd990c40356fefbddc8 blob + 38f122f8b65d551a0c57caa2f73165e9fcaef153 --- man/man4/9pserve.4 +++ man/man4/9pserve.4 @@ -4,8 +4,17 @@ .SH SYNOPSIS .B 9pserve [ -.B -v +.B -lv ] +[ +.B -A +.I aname +.I afid +] +[ +.B -M +.I msize +] .I addr .SH DESCRIPTION On Plan 9, when a user-level file server mounts itself into a name space @@ -39,6 +48,33 @@ and clunks any outstanding fids belonging to the clien is typically not invoked directly; use .IR post9pservice (3) instead. +.PP +The options are: +.TP +.B -l +logging; write a debugging log to +.IB addr .log \fR. +.TP +.B -v +verbose; more verbose when repeated +.TP +.B -A +rewrite all attach messages to use +.I aname +and +.IR afid ; +used to implement +.IR srv (4)'s +.B -a +option +.TP +.B -M +do not initialize the connection with a +.B Tversion +message; +instead assume 9P2000 and a maximum message size of +.IR msize +.PD .SH "SEE ALSO .IR intro (4), .IR intro (9p) blob - 2017ce40be2999156c0ee930ae0401b086b033de blob + a74f43f1675c05e5fd6a0f56053989274521f7c6 --- man/man4/srv.4 +++ man/man4/srv.4 @@ -3,6 +3,13 @@ srv, 9fs \- start network file esrvice .SH SYNOPSIS .B srv +[ +.B -a +] +[ +.B -k +.I keypattern +] .I address [ .I srvname @@ -22,6 +29,23 @@ as .IR address ). .PP The +.B -a +option causes +.I srv +to post a pre-authenticated connection to the file system +.I aname +(by default, the empty string; +see +.IR attach (9p)). +.I Srv +authenticates over the 9P connection to establish a valid auth fid. +.IR Keypattern , +if specified, is used to select the key used for authentication. +Client attach requests are rewritten to use the specified +.I aname +and auth fid. +.PP +The .I 9fs command executes the .I srv blob - a6cb11f7da7a7ba72573a885a6a9875ac0d31148 blob + a1f6851c860d9293757acd919d6656d7f5b01d58 --- src/cmd/9pserve.c +++ src/cmd/9pserve.c @@ -69,6 +69,7 @@ struct Conn Queue *inq; }; +char *xaname; char *addr; int afd; char adir[40]; @@ -78,6 +79,9 @@ Queue *inq; int verbose = 0; int logging = 0; int msize = 8192; +int xafid = NOFID; +int attached; +int versioned; void *gethash(Hash**, uint); int puthash(Hash**, uint, void*); @@ -104,6 +108,7 @@ void listenthread(void*); void outputthread(void*); void inputthread(void*); void rewritehdr(Fcall*, uchar*); +void repack(Fcall*, uchar**); int tlisten(char*, char*); int taccept(int, char*); int iolisten(Ioproc*, char*, char*); @@ -113,11 +118,12 @@ int iosendfd(Ioproc*, int, int); void mainproc(void*); int ignorepipe(void*, char*); int timefmt(Fmt*); +void dorootstat(void); void usage(void) { - fprint(2, "usage: 9pserve [-lv] address\n"); + fprint(2, "usage: 9pserve [-lv] [-A aname afid] [-M msize] address\n"); fprint(2, "\treads/writes 9P messages on stdin/stdout\n"); threadexitsall("usage"); } @@ -131,21 +137,37 @@ threadmain(int argc, char **argv) int fd; x = getenv("verbose9pserve"); - if(x) + if(x){ verbose = atoi(x); + fprint(2, "verbose9pserve %s => %d\n", x, verbose); + } ARGBEGIN{ default: usage(); + case 'A': + attached = 1; + xaname = EARGF(usage()); + xafid = atoi(EARGF(usage())); + break; + case 'M': + versioned = 1; + msize = atoi(EARGF(usage())); + break; case 'v': verbose++; break; case 'u': - isunix = 1; + isunix++; break; case 'l': logging++; break; }ARGEND + + if(attached && !versioned){ + fprint(2, "-A must be used with -M\n"); + usage(); + } if(argc != 1) usage(); @@ -187,24 +209,30 @@ mainproc(void *v) outq = qalloc(); inq = qalloc(); - f.type = Tversion; - f.version = "9P2000"; - f.msize = msize; - f.tag = NOTAG; - n = convS2M(&f, vbuf, sizeof vbuf); - if(verbose > 1) fprint(2, "%T * <- %F\n", &f); - nn = write(1, vbuf, n); - if(n != nn) - sysfatal("error writing Tversion: %r\n"); - n = read9pmsg(0, vbuf, sizeof vbuf); - if(convM2S(vbuf, n, &f) != n) - sysfatal("convM2S failure"); - if(f.msize < msize) - msize = f.msize; - if(verbose > 1) fprint(2, "%T * -> %F\n", &f); + if(!versioned){ + f.type = Tversion; + f.version = "9P2000"; + f.msize = msize; + f.tag = NOTAG; + n = convS2M(&f, vbuf, sizeof vbuf); + if(verbose > 1) fprint(2, "%T * <- %F\n", &f); + nn = write(1, vbuf, n); + if(n != nn) + sysfatal("error writing Tversion: %r\n"); + n = read9pmsg(0, vbuf, sizeof vbuf); + if(convM2S(vbuf, n, &f) != n) + sysfatal("convM2S failure"); + if(f.msize < msize) + msize = f.msize; + if(verbose > 1) fprint(2, "%T * -> %F\n", &f); + } threadcreate(inputthread, nil, STACK); threadcreate(outputthread, nil, STACK); + +// if(rootfid) +// dorootstat(); + threadcreate(listenthread, nil, STACK); threadexits(0); } @@ -283,6 +311,16 @@ err(Msg *m, char *ename) send9pmsg(m); } +char* +estrdup(char *s) +{ + char *t; + + t = emalloc(strlen(s)+1); + strcpy(t, s); + return t; +} + void connthread(void *arg) { @@ -349,6 +387,18 @@ connthread(void *arg) continue; } m->fid->ref++; + if(attached && m->afid==nil){ + if(m->tx.aname[0] && strcmp(xaname, m->tx.aname) != 0){ + err(m, "invalid attach name"); + continue; + } + m->tx.afid = xafid; + m->tx.aname = xaname; + m->tx.uname = estrdup(m->tx.uname); + repack(&m->tx, &m->tpkt); + free(m->tx.uname); + m->tx.uname = "XXX"; + } break; case Twalk: if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ @@ -369,6 +419,10 @@ connthread(void *arg) } break; case Tauth: + if(attached){ + err(m, "authentication not required"); + continue; + } m->afid = fidnew(m->tx.afid); if(puthash(c->fid, m->tx.afid, m->afid) < 0){ err(m, "duplicate fid"); @@ -707,7 +761,8 @@ connoutthread(void *arg) fidput(m->fid); break; case Twalk: - if(err && m->tx.fid != m->tx.newfid && m->newfid) + if(err || m->rx.nwqid < m->tx.nwname) + if(m->tx.fid != m->tx.newfid && m->newfid) if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0) fidput(m->newfid); break; @@ -851,6 +906,10 @@ fidnew(int cfid) if(freefid == nil){ fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0])); + if(nfidtab == xafid){ + fidtab[nfidtab++] = nil; + fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0])); + } fidtab[nfidtab] = emalloc(sizeof(Fid)); freefid = fidtab[nfidtab]; freefid->fid = nfidtab++; @@ -1163,6 +1222,23 @@ restring(uchar *pkt, int pn, char *s) n = strlen(s); memmove(s+1, s, n); PBIT16((uchar*)s-1, n); +} + +void +repack(Fcall *f, uchar **ppkt) +{ + uint n, nn; + uchar *pkt; + + pkt = *ppkt; + n = GBIT32(pkt); + nn = sizeS2M(f); + if(nn > n){ + free(pkt); + pkt = emalloc(nn); + *ppkt = pkt; + } + convS2M(f, pkt, nn); } void blob - 95dfef88c632338b1795ff735d73bf36cd67134a blob + 01c05e642487bf54e00b4405e34e37ed00de5673 --- src/cmd/srv.c +++ src/cmd/srv.c @@ -4,20 +4,46 @@ #include #include +int debug; +char *aname = ""; +char *keypattern = ""; +int fd; +int msize; +int doauth; +int afid = NOFID; +extern char *post9parg; /* clumsy hack */ +void xauth(void); +AuthInfo* xauth_proxy(AuthGetkey *getkey, char *fmt, ...); + void usage(void) { - fprint(2, "usage: srv addr [srvname]\n"); + fprint(2, "usage: srv [-a] [-A aname] [-k keypattern] addr [srvname]\n"); threadexitsall("usage"); } void threadmain(int argc, char **argv) { - int fd; char *addr, *service; + + fmtinstall('F', fcallfmt); + fmtinstall('M', dirmodefmt); ARGBEGIN{ + case 'D': + debug = 1; + break; + case 'A': + /* BUG: should be able to repeat this and establish multiple afids */ + aname = EARGF(usage()); + break; + case 'a': + doauth = 1; + break; + case 'k': + keypattern = EARGF(usage()); + break; default: usage(); }ARGEND @@ -28,14 +54,298 @@ threadmain(int argc, char **argv) addr = netmkaddr(argv[0], "tcp", "9fs"); if((fd = dial(addr, nil, nil, nil)) < 0) sysfatal("dial %s: %r", addr); - + + if(doauth) + xauth(); + if(argc == 2) service = argv[1]; else service = argv[0]; - + if(post9pservice(fd, service) < 0) sysfatal("post9pservice: %r"); threadexitsall(0); } + +void +do9p(Fcall *tx, Fcall *rx) +{ + static uchar buf[9000]; + static char ebuf[200]; + int n; + + n = convS2M(tx, buf, sizeof buf); + if(n == BIT16SZ){ + werrstr("convS2M failed"); + goto err; + } + if(debug) + fprint(2, "<- %F\n", tx); + if(write(fd, buf, n) != n) + goto err; + if((n = read9pmsg(fd, buf, sizeof buf)) < 0) + goto err; + if(n == 0){ + werrstr("unexpected eof"); + goto err; + } + if(convM2S(buf, n, rx) != n){ + werrstr("convM2S failed"); + goto err; + } + if(debug) + fprint(2, "-> %F\n", rx); + if(rx->type != Rerror && rx->type != tx->type+1){ + werrstr("unexpected type"); + goto err; + } + if(rx->tag != tx->tag){ + werrstr("unexpected tag"); + goto err; + } + return; + +err: + rerrstr(ebuf, sizeof ebuf); + rx->ename = ebuf; + rx->type = Rerror; + return; +} + +void +xauth(void) +{ + Fcall tx, rx; + + afid = 0; + tx.type = Tversion; + tx.tag = NOTAG; + tx.version = "9P2000"; + tx.msize = 8192; + do9p(&tx, &rx); + if(rx.type == Rerror) + sysfatal("Tversion: %s", rx.ename); + msize = rx.msize; + + tx.type = Tauth; + tx.tag = 1; + tx.afid = afid; + tx.uname = getuser(); + tx.aname = aname; + do9p(&tx, &rx); + if(rx.type == Rerror){ + fprint(2, "rx: %s\n", rx.ename); + afid = NOFID; + return; + } + + if(xauth_proxy(auth_getkey, "proto=p9any role=client %s", keypattern) < 0) + sysfatal("authproxy: %r"); +} + +int +xread(void *buf, int n) +{ + Fcall tx, rx; + + tx.type = Tread; + tx.tag = 1; + tx.fid = 0; /* afid above */ + tx.count = n; + tx.offset = 0; + do9p(&tx, &rx); + if(rx.type == Rerror){ + werrstr("%s", rx.ename); + return -1; + } + + if(rx.count > n){ + werrstr("too much data returned"); + return -1; + } + memmove(buf, rx.data, rx.count); + return rx.count; +} + +int +xwrite(void *buf, int n) +{ + Fcall tx, rx; + + tx.type = Twrite; + tx.tag = 1; + tx.fid = 0; /* afid above */ + tx.data = buf; + tx.count = n; + tx.offset = 0; + do9p(&tx, &rx); + if(rx.type == Rerror){ + werrstr("%s", rx.ename); + return -1; + } + return n; +} + + +/* + * changed to add -A below + */ +#undef _exits +int +post9pservice(int fd, char *name) +{ + int i; + char *ns, *s; + Waitmsg *w; + + if((ns = getns()) == nil) + return -1; + + s = smprint("unix!%s/%s", ns, name); + free(ns); + if(s == nil) + return -1; + switch(fork()){ + case -1: + return -1; + case 0: + dup(fd, 0); + dup(fd, 1); + for(i=3; i<20; i++) + close(i); + if(doauth) + execlp("9pserve", "9pserve", "-u", + "-M", + smprint("%d", msize), + "-A", + aname, + smprint("%d", afid), + s, (char*)0); + else + execlp("9pserve", "9pserve", "-u", s, (char*)0); + fprint(2, "exec 9pserve: %r\n"); + _exits("exec"); + default: + w = wait(); + if(w == nil) + return -1; + close(fd); + free(s); + if(w->msg && w->msg[0]){ + free(w); + werrstr("9pserve failed"); + return -1; + } + free(w); + return 0; + } +} + +enum { ARgiveup = 100 }; +static int +dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey) +{ + int ret; + + for(;;){ + if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey) + return ret; + if(getkey == nil) + return ARgiveup; /* don't know how */ + if((*getkey)(rpc->arg) < 0) + return ARgiveup; /* user punted */ + } +} + + +/* + * this just proxies what the factotum tells it to. + */ +AuthInfo* +xfauth_proxy(AuthRpc *rpc, AuthGetkey *getkey, char *params) +{ + char *buf; + int m, n, ret; + AuthInfo *a; + char oerr[ERRMAX]; + + rerrstr(oerr, sizeof oerr); + werrstr("UNKNOWN AUTH ERROR"); + + if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok){ + werrstr("fauth_proxy start: %r"); + return nil; + } + + buf = malloc(AuthRpcMax); + if(buf == nil) + return nil; + for(;;){ + switch(dorpc(rpc, "read", nil, 0, getkey)){ + case ARdone: + free(buf); + a = auth_getinfo(rpc); + errstr(oerr, sizeof oerr); /* no error, restore whatever was there */ + return a; + case ARok: + if(xwrite(rpc->arg, rpc->narg) != rpc->narg){ + werrstr("auth_proxy write fid: %r"); + goto Error; + } + break; + case ARphase: + n = 0; + memset(buf, 0, AuthRpcMax); + while((ret = dorpc(rpc, "write", buf, n, getkey)) == ARtoosmall){ + if(atoi(rpc->arg) > AuthRpcMax) + break; + m = xread(buf+n, atoi(rpc->arg)-n); + if(m <= 0){ + if(m == 0) + werrstr("auth_proxy short read: %s", buf); + goto Error; + } + n += m; + } + if(ret != ARok){ + werrstr("auth_proxy rpc write: %s: %r", buf); + goto Error; + } + break; + default: + werrstr("auth_proxy rpc: %r"); + goto Error; + } + } +Error: + free(buf); + return nil; +} + +AuthInfo* +xauth_proxy(AuthGetkey *getkey, char *fmt, ...) +{ + char *p; + va_list arg; + AuthInfo *ai; + AuthRpc *rpc; + + quotefmtinstall(); /* just in case */ + va_start(arg, fmt); + p = vsmprint(fmt, arg); + va_end(arg); + + rpc = auth_allocrpc(); + if(rpc == nil){ + free(p); + return nil; + } + + ai = xfauth_proxy(rpc, getkey, p); + free(p); + auth_freerpc(rpc); + return ai; +} +