|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <fcall.h> | 
|  | #include <auth.h> | 
|  | #include <9pclient.h> | 
|  | #include "authlocal.h" | 
|  |  | 
|  | enum { | 
|  | ARgiveup = 100 | 
|  | }; | 
|  |  | 
|  | static uchar* | 
|  | gstring(uchar *p, uchar *ep, char **s) | 
|  | { | 
|  | uint n; | 
|  |  | 
|  | if(p == nil) | 
|  | return nil; | 
|  | if(p+BIT16SZ > ep) | 
|  | return nil; | 
|  | n = GBIT16(p); | 
|  | p += BIT16SZ; | 
|  | if(p+n > ep) | 
|  | return nil; | 
|  | *s = malloc(n+1); | 
|  | memmove((*s), p, n); | 
|  | (*s)[n] = '\0'; | 
|  | p += n; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | static uchar* | 
|  | gcarray(uchar *p, uchar *ep, uchar **s, int *np) | 
|  | { | 
|  | uint n; | 
|  |  | 
|  | if(p == nil) | 
|  | return nil; | 
|  | if(p+BIT16SZ > ep) | 
|  | return nil; | 
|  | n = GBIT16(p); | 
|  | p += BIT16SZ; | 
|  | if(p+n > ep) | 
|  | return nil; | 
|  | *s = malloc(n); | 
|  | if(*s == nil) | 
|  | return nil; | 
|  | memmove((*s), p, n); | 
|  | *np = n; | 
|  | p += n; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | void | 
|  | auth_freeAI(AuthInfo *ai) | 
|  | { | 
|  | if(ai == nil) | 
|  | return; | 
|  | free(ai->cuid); | 
|  | free(ai->suid); | 
|  | free(ai->cap); | 
|  | free(ai->secret); | 
|  | free(ai); | 
|  | } | 
|  |  | 
|  | static uchar* | 
|  | convM2AI(uchar *p, int n, AuthInfo **aip) | 
|  | { | 
|  | uchar *e = p+n; | 
|  | AuthInfo *ai; | 
|  |  | 
|  | ai = mallocz(sizeof(*ai), 1); | 
|  | if(ai == nil) | 
|  | return nil; | 
|  |  | 
|  | p = gstring(p, e, &ai->cuid); | 
|  | p = gstring(p, e, &ai->suid); | 
|  | p = gstring(p, e, &ai->cap); | 
|  | p = gcarray(p, e, &ai->secret, &ai->nsecret); | 
|  | if(p == nil) | 
|  | auth_freeAI(ai); | 
|  | else | 
|  | *aip = ai; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | AuthInfo* | 
|  | auth_getinfo(AuthRpc *rpc) | 
|  | { | 
|  | AuthInfo *a; | 
|  |  | 
|  | if(auth_rpc(rpc, "authinfo", nil, 0) != ARok) | 
|  | return nil; | 
|  | a = nil; | 
|  | if(convM2AI((uchar*)rpc->arg, rpc->narg, &a) == nil){ | 
|  | werrstr("bad auth info from factotum"); | 
|  | return nil; | 
|  | } | 
|  | return a; | 
|  | } | 
|  |  | 
|  | 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* | 
|  | fauth_proxy(int fd, 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(write(fd, rpc->arg, rpc->narg) != rpc->narg){ | 
|  | werrstr("auth_proxy write fd: %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 = read(fd, 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* | 
|  | auth_proxy(int fd, 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 = fauth_proxy(fd, rpc, getkey, p); | 
|  | free(p); | 
|  | auth_freerpc(rpc); | 
|  | return ai; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  this just proxies what the factotum tells it to. | 
|  | */ | 
|  | AuthInfo* | 
|  | fsfauth_proxy(CFid *fid, 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(fswrite(fid, 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 = fsread(fid, 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* | 
|  | fsauth_proxy(CFid *fid, 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 = fsfauth_proxy(fid, rpc, getkey, p); | 
|  | free(p); | 
|  | auth_freerpc(rpc); | 
|  | return ai; | 
|  | } | 
|  |  |