123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * Factotum RPC
- *
- * Must be paired write/read cycles on /mnt/factotum/rpc.
- * The format of a request is verb, single space, data.
- * Data format is verb-dependent; in particular, it can be binary.
- * The format of a response is the same. The write only sets up
- * the RPC. The read tries to execute it. If the /mnt/factotum/key
- * file is open, we ask for new keys using that instead of returning
- * an error in the RPC. This means the read blocks.
- * Textual arguments are parsed with tokenize, so rc-style quoting
- * rules apply.
- *
- * Only authentication protocol messages go here. Configuration
- * is still via ctl (below).
- *
- * Return values are:
- * error message - an error happened.
- * ok [data] - success, possible data is request dependent.
- * needkey proto domain user - request aborted, get me this key and try again
- * badkey proto domain user - request aborted, this key might be bad
- * done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
- * Request RPCs are:
- * start attrs - initializes protocol for authentication, can fail.
- * returns "ok read" or "ok write" on success.
- * read - execute protocol read
- * write - execute protocol write
- * authinfo - if the protocol is finished, return the AI if any
- * attr - return protocol information
- */
- #include "dat.h"
- Req *rpcwait;
- typedef struct Verb Verb;
- struct Verb {
- char *verb;
- int iverb;
- };
- enum {
- Vunknown = -1,
- Vauthinfo = 0,
- Vread,
- Vstart,
- Vwrite,
- Vattr,
- };
- Verb rpctab[] = {
- "authinfo", Vauthinfo,
- "read", Vread,
- "start", Vstart,
- "write", Vwrite,
- "attr", Vattr,
- };
- static int
- classify(char *s, Verb *verbtab, int nverbtab)
- {
- int i;
- for(i=0; i<nverbtab; i++)
- if(strcmp(s, verbtab[i].verb) == 0)
- return verbtab[i].iverb;
- return Vunknown;
- }
- void
- rpcwrite(Req *r)
- {
- Fsstate *fss;
- if(r->ifcall.count >= Maxrpc){
- respond(r, Etoolarge);
- return;
- }
- fss = r->fid->aux;
- if(fss->pending){
- respond(r, "rpc already pending; read to clear");
- return;
- }
- memmove(fss->rpc.buf, r->ifcall.data, r->ifcall.count);
- fss->rpc.buf[r->ifcall.count] = '\0';
- fss->rpc.verb = fss->rpc.buf;
- if(fss->rpc.arg = strchr(fss->rpc.buf, ' ')){
- *fss->rpc.arg++ = '\0';
- fss->rpc.narg = r->ifcall.count - (fss->rpc.arg - fss->rpc.buf);
- }else{
- fss->rpc.arg = "";
- fss->rpc.narg = 0;
- }
- fss->rpc.iverb = classify(fss->rpc.verb, rpctab, nelem(rpctab));
- r->ofcall.count = r->ifcall.count;
- fss->pending = 1;
- respond(r, nil);
- }
- static void
- retstring(Req *r, Fsstate *fss, char *s)
- {
- int n;
- n = strlen(s);
- if(n > r->ifcall.count)
- n = r->ifcall.count;
- memmove(r->ofcall.data, s, n);
- r->ofcall.count = n;
- fss->pending = 0;
- respond(r, nil);
- return;
- }
- static void
- retrpc(Req *r, int ret, Fsstate *fss)
- {
- switch(ret){
- default:
- snprint(fss->rpc.buf, Maxrpc, "internal error %d", ret);
- retstring(r, fss, fss->rpc.buf);
- return;
- case RpcErrstr:
- snprint(fss->rpc.buf, Maxrpc, "error %r");
- retstring(r, fss, fss->rpc.buf);
- return;
- case RpcFailure:
- snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
- retstring(r, fss, fss->rpc.buf);
- return;
- case RpcNeedkey:
- if(needkeyqueue(r, fss) < 0){
- snprint(fss->rpc.buf, Maxrpc, "needkey %s", fss->keyinfo);
- retstring(r, fss, fss->rpc.buf);
- }
- return;
- case RpcOk:
- retstring(r, fss, "ok");
- return;
- case RpcToosmall:
- snprint(fss->rpc.buf, Maxrpc, "toosmall %d", fss->rpc.nwant);
- retstring(r, fss, fss->rpc.buf);
- return;
- case RpcPhase:
- snprint(fss->rpc.buf, Maxrpc, "phase %r");
- retstring(r, fss, fss->rpc.buf);
- return;
- case RpcConfirm:
- confirmqueue(r, fss);
- return;
- }
- }
- int
- rdwrcheck(Req *r, Fsstate *fss)
- {
- if(fss->ps == nil){
- retstring(r, fss, "error no current protocol");
- return -1;
- }
- if(fss->phase == Notstarted){
- retstring(r, fss, "protocol not started");
- return -1;
- }
- if(fss->phase == Broken){
- snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
- retstring(r, fss, fss->rpc.buf);
- return -1;
- }
- if(fss->phase == Established){
- if(fss->haveai)
- retstring(r, fss, "done haveai");
- else
- retstring(r, fss, "done");
- return -1;
- }
- return 0;
- }
- static void
- logret(char *pre, Fsstate *fss, int ret)
- {
- switch(ret){
- default:
- flog("%s: code %d", pre, ret);
- break;
- case RpcErrstr:
- flog("%s: error %r", pre);
- break;
- case RpcFailure:
- flog("%s: failure %s", pre, fss->err);
- break;
- case RpcNeedkey:
- flog("%s: needkey %s", pre, fss->keyinfo);
- break;
- case RpcOk:
- flog("%s: ok", pre);
- break;
- case RpcToosmall:
- flog("%s: toosmall %d", pre, fss->rpc.nwant);
- break;
- case RpcPhase:
- flog("%s: phase: %r", pre);
- break;
- case RpcConfirm:
- flog("%s: waiting for confirm", pre);
- break;
- }
- }
- void
- rpcrdwrlog(Fsstate *fss, char *rdwr, uint n, int ophase, int ret)
- {
- char buf0[40], buf1[40], pre[300];
- if(!debug)
- return;
- snprint(pre, sizeof pre, "%d: %s %ud in phase %s yields phase %s",
- fss->seqnum, rdwr, n, phasename(fss, ophase, buf0), phasename(fss, fss->phase, buf1));
- logret(pre, fss, ret);
- }
- void
- rpcstartlog(Attr *attr, Fsstate *fss, int ret)
- {
- char pre[300], tmp[40];
- if(!debug)
- return;
- snprint(pre, sizeof pre, "%d: start %A yields phase %s", fss->seqnum,
- attr, phasename(fss, fss->phase, tmp));
- logret(pre, fss, ret);
- }
- int seqnum;
- void
- rpcread(Req *r)
- {
- Attr *attr;
- char *p;
- int ophase, ret;
- uint8_t *e;
- uint count;
- Fsstate *fss;
- Proto *proto;
- if(r->ifcall.count < 64){
- respond(r, "rpc read too small");
- return;
- }
- fss = r->fid->aux;
- if(!fss->pending){
- respond(r, "no rpc pending");
- return;
- }
- switch(fss->rpc.iverb){
- default:
- case Vunknown:
- retstring(r, fss, "error unknown verb");
- break;
- case Vstart:
- if(fss->phase != Notstarted){
- flog("%d: implicit close due to second start; old attr '%A'", fss->seqnum, fss->attr);
- if(fss->proto && fss->ps)
- (*fss->proto->close)(fss);
- fss->ps = nil;
- fss->proto = nil;
- _freeattr(fss->attr);
- fss->attr = nil;
- fss->phase = Notstarted;
- }
- attr = _parseattr(fss->rpc.arg);
- if((p = _strfindattr(attr, "proto")) == nil){
- retstring(r, fss, "error did not specify proto");
- _freeattr(attr);
- break;
- }
- if((proto = findproto(p)) == nil){
- snprint(fss->rpc.buf, Maxrpc, "error unknown protocol %q", p);
- retstring(r, fss, fss->rpc.buf);
- _freeattr(attr);
- break;
- }
- fss->attr = attr;
- fss->proto = proto;
- fss->seqnum = ++seqnum;
- ret = (*proto->init)(proto, fss);
- rpcstartlog(attr, fss, ret);
- if(ret != RpcOk){
- _freeattr(fss->attr);
- fss->attr = nil;
- fss->phase = Notstarted;
- }
- retrpc(r, ret, fss);
- break;
- case Vread:
- if(fss->rpc.arg && fss->rpc.arg[0]){
- retstring(r, fss, "error read needs no parameters");
- break;
- }
- if(rdwrcheck(r, fss) < 0)
- break;
- count = r->ifcall.count - 3;
- ophase = fss->phase;
- ret = fss->proto->read(fss, (uint8_t*)r->ofcall.data+3,
- &count);
- rpcrdwrlog(fss, "read", count, ophase, ret);
- if(ret == RpcOk){
- memmove(r->ofcall.data, "ok ", 3);
- if(count == 0)
- r->ofcall.count = 2;
- else
- r->ofcall.count = 3+count;
- fss->pending = 0;
- respond(r, nil);
- }else
- retrpc(r, ret, fss);
- break;
- case Vwrite:
- if(rdwrcheck(r, fss) < 0)
- break;
- ophase = fss->phase;
- ret = fss->proto->write(fss, fss->rpc.arg, fss->rpc.narg);
- rpcrdwrlog(fss, "write", fss->rpc.narg, ophase, ret);
- retrpc(r, ret, fss);
- break;
- case Vauthinfo:
- if(fss->phase != Established){
- retstring(r, fss, "error authentication unfinished");
- break;
- }
- if(!fss->haveai){
- retstring(r, fss, "error no authinfo available");
- break;
- }
- memmove(r->ofcall.data, "ok ", 3);
- fss->ai.cap = mkcap(r->fid->uid, fss->ai.suid);
- e = convAI2M(&fss->ai, (uint8_t*)r->ofcall.data+3,
- r->ifcall.count-3);
- free(fss->ai.cap);
- fss->ai.cap = nil;
- if(e == nil){
- retstring(r, fss, "error read too small");
- break;
- }
- r->ofcall.count = e - (uint8_t*)r->ofcall.data;
- fss->pending = 0;
- respond(r, nil);
- break;
- case Vattr:
- snprint(fss->rpc.buf, Maxrpc, "ok %A", fss->attr);
- retstring(r, fss, fss->rpc.buf);
- break;
- }
- }
- enum {
- Vdelkey,
- Vaddkey,
- Vdebug,
- };
- Verb ctltab[] = {
- "delkey", Vdelkey,
- "key", Vaddkey,
- "debug", Vdebug,
- };
- /*
- * key attr=val... - add a key
- * the attr=val pairs are protocol-specific.
- * for example, both of these are valid:
- * key p9sk1 gre cs.bell-labs.com mysecret
- * key p9sk1 gre cs.bell-labs.com 11223344556677 fmt=des7hex
- * delkey ... - delete a key
- * if given, the attr=val pairs are used to narrow the search
- * [maybe should require a password?]
- */
- int
- ctlwrite(char *a, int atzero)
- {
- char *p;
- int i, nmatch, ret;
- Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos;
- Key *k;
- Proto *proto;
- if(a[0] == '#' || a[0] == '\0')
- return 0;
- /*
- * it would be nice to emit a warning of some sort here.
- * we ignore all but the first line of the write. this helps
- * both with things like "echo delkey >/mnt/factotum/ctl"
- * and writes that (incorrectly) contain multiple key lines.
- */
- if(p = strchr(a, '\n')){
- if(p[1] != '\0'){
- werrstr("multiline write not allowed");
- return -1;
- }
- *p = '\0';
- }
- if((p = strchr(a, ' ')) == nil)
- p = "";
- else
- *p++ = '\0';
- switch(classify(a, ctltab, nelem(ctltab))){
- default:
- case Vunknown:
- werrstr("unknown verb");
- return -1;
- case Vdebug:
- debug ^= 1;
- return 0;
- case Vdelkey:
- nmatch = 0;
- attr = _parseattr(p);
- for(pa=attr; pa; pa=pa->next){
- if(pa->type != AttrQuery && pa->name[0]=='!'){
- werrstr("only !private? patterns are allowed for private fields");
- _freeattr(attr);
- return -1;
- }
- }
- for(i=0; i<ring->nkey; ){
- if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){
- nmatch++;
- closekey(ring->key[i]);
- ring->nkey--;
- memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0]));
- }else
- i++;
- }
- _freeattr(attr);
- if(nmatch == 0){
- werrstr("found no keys to delete");
- return -1;
- }
- return 0;
- case Vaddkey:
- attr = _parseattr(p);
- /* separate out proto= attributes */
- lprotos = &protos;
- for(l=&attr; (*l); ){
- if(strcmp((*l)->name, "proto") == 0){
- *lprotos = *l;
- lprotos = &(*l)->next;
- *l = (*l)->next;
- }else
- l = &(*l)->next;
- }
- *lprotos = nil;
- if(protos == nil){
- werrstr("key without protos");
- _freeattr(attr);
- return -1;
- }
- /* separate out private attributes */
- lpriv = &priv;
- for(l=&attr; (*l); ){
- if((*l)->name[0] == '!'){
- *lpriv = *l;
- lpriv = &(*l)->next;
- *l = (*l)->next;
- }else
- l = &(*l)->next;
- }
- *lpriv = nil;
- /* add keys */
- ret = 0;
- for(pa=protos; pa; pa=pa->next){
- if((proto = findproto(pa->val)) == nil){
- werrstr("unknown proto %s", pa->val);
- ret = -1;
- continue;
- }
- if(proto->addkey == nil){
- werrstr("proto %s doesn't take keys", proto->name);
- ret = -1;
- continue;
- }
- k = emalloc(sizeof(Key));
- k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr));
- k->privattr = _copyattr(priv);
- k->ref = 1;
- k->proto = proto;
- if(proto->addkey(k, atzero) < 0){
- ret = -1;
- closekey(k);
- continue;
- }
- closekey(k);
- }
- _freeattr(attr);
- _freeattr(priv);
- _freeattr(protos);
- return ret;
- }
- }
|