|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <auth.h> | 
|  | #include <fcall.h> | 
|  | #include <thread.h> | 
|  |  | 
|  | int post9p(int, char*); | 
|  | int debug; | 
|  | char *aname = ""; | 
|  | char *keypattern = ""; | 
|  | int fd; | 
|  | int msize; | 
|  | int doauth; | 
|  | u32int afid = NOFID; | 
|  | extern char *post9parg;	/* clumsy hack */ | 
|  | void xauth(void); | 
|  | AuthInfo* xauth_proxy(AuthGetkey *getkey, char *fmt, ...); | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: srv [-a] [-A aname] [-k keypattern] addr [srvname]\n"); | 
|  | threadexitsall("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | threadmain(int argc, char **argv) | 
|  | { | 
|  | 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 'n': | 
|  | doauth = -1; | 
|  | break; | 
|  | case 'k': | 
|  | keypattern = EARGF(usage()); | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | }ARGEND | 
|  |  | 
|  | if(argc != 1 && argc != 2) | 
|  | usage(); | 
|  |  | 
|  | addr = netmkaddr(argv[0], "tcp", "9fs"); | 
|  | if((fd = dial(addr, nil, nil, nil)) < 0) | 
|  | sysfatal("dial %s: %r", addr); | 
|  |  | 
|  | if(doauth > 0) | 
|  | xauth(); | 
|  |  | 
|  | if(argc == 2) | 
|  | service = argv[1]; | 
|  | else | 
|  | service = argv[0]; | 
|  |  | 
|  | rfork(RFNOTEG); | 
|  | if(post9p(fd, service) < 0) | 
|  | sysfatal("post9p: %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) == nil) | 
|  | 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 | 
|  | post9p(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 > 0) | 
|  | execlp("9pserve", "9pserve", "-u", | 
|  | "-M", | 
|  | smprint("%d", msize), | 
|  | "-A", | 
|  | aname, | 
|  | smprint("%d", afid), | 
|  | s, (char*)0); | 
|  | else | 
|  | execlp("9pserve", "9pserve", | 
|  | doauth < 0 ? "-nu" : "-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; | 
|  | } | 
|  |  |