19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * Factotum RPC
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier * Must be paired write/read cycles on /mnt/factotum/rpc.
59a747e4fSDavid du Colombier * The format of a request is verb, single space, data.
69a747e4fSDavid du Colombier * Data format is verb-dependent; in particular, it can be binary.
79a747e4fSDavid du Colombier * The format of a response is the same. The write only sets up
89a747e4fSDavid du Colombier * the RPC. The read tries to execute it. If the /mnt/factotum/key
99a747e4fSDavid du Colombier * file is open, we ask for new keys using that instead of returning
109a747e4fSDavid du Colombier * an error in the RPC. This means the read blocks.
119a747e4fSDavid du Colombier * Textual arguments are parsed with tokenize, so rc-style quoting
129a747e4fSDavid du Colombier * rules apply.
139a747e4fSDavid du Colombier *
149a747e4fSDavid du Colombier * Only authentication protocol messages go here. Configuration
159a747e4fSDavid du Colombier * is still via ctl (below).
169a747e4fSDavid du Colombier *
179a747e4fSDavid du Colombier * Return values are:
189a747e4fSDavid du Colombier * error message - an error happened.
199a747e4fSDavid du Colombier * ok [data] - success, possible data is request dependent.
209a747e4fSDavid du Colombier * needkey proto domain user - request aborted, get me this key and try again
219a747e4fSDavid du Colombier * badkey proto domain user - request aborted, this key might be bad
229a747e4fSDavid du Colombier * done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
239a747e4fSDavid du Colombier * Request RPCs are:
249a747e4fSDavid du Colombier * start attrs - initializes protocol for authentication, can fail.
259a747e4fSDavid du Colombier * returns "ok read" or "ok write" on success.
269a747e4fSDavid du Colombier * read - execute protocol read
279a747e4fSDavid du Colombier * write - execute protocol write
289a747e4fSDavid du Colombier * authinfo - if the protocol is finished, return the AI if any
299a747e4fSDavid du Colombier * attr - return protocol information
309a747e4fSDavid du Colombier */
319a747e4fSDavid du Colombier
329a747e4fSDavid du Colombier #include "dat.h"
339a747e4fSDavid du Colombier
349a747e4fSDavid du Colombier Req *rpcwait;
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier typedef struct Verb Verb;
379a747e4fSDavid du Colombier struct Verb {
389a747e4fSDavid du Colombier char *verb;
399a747e4fSDavid du Colombier int iverb;
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier
429a747e4fSDavid du Colombier enum {
439a747e4fSDavid du Colombier Vunknown = -1,
449a747e4fSDavid du Colombier Vauthinfo = 0,
459a747e4fSDavid du Colombier Vread,
469a747e4fSDavid du Colombier Vstart,
479a747e4fSDavid du Colombier Vwrite,
489a747e4fSDavid du Colombier Vattr,
499a747e4fSDavid du Colombier };
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier Verb rpctab[] = {
529a747e4fSDavid du Colombier "authinfo", Vauthinfo,
539a747e4fSDavid du Colombier "read", Vread,
549a747e4fSDavid du Colombier "start", Vstart,
559a747e4fSDavid du Colombier "write", Vwrite,
569a747e4fSDavid du Colombier "attr", Vattr,
579a747e4fSDavid du Colombier };
589a747e4fSDavid du Colombier
599a747e4fSDavid du Colombier static int
classify(char * s,Verb * verbtab,int nverbtab)609a747e4fSDavid du Colombier classify(char *s, Verb *verbtab, int nverbtab)
619a747e4fSDavid du Colombier {
629a747e4fSDavid du Colombier int i;
639a747e4fSDavid du Colombier
649a747e4fSDavid du Colombier for(i=0; i<nverbtab; i++)
659a747e4fSDavid du Colombier if(strcmp(s, verbtab[i].verb) == 0)
669a747e4fSDavid du Colombier return verbtab[i].iverb;
679a747e4fSDavid du Colombier return Vunknown;
689a747e4fSDavid du Colombier }
699a747e4fSDavid du Colombier
709a747e4fSDavid du Colombier void
rpcwrite(Req * r)719a747e4fSDavid du Colombier rpcwrite(Req *r)
729a747e4fSDavid du Colombier {
739a747e4fSDavid du Colombier Fsstate *fss;
749a747e4fSDavid du Colombier
759a747e4fSDavid du Colombier if(r->ifcall.count >= Maxrpc){
769a747e4fSDavid du Colombier respond(r, Etoolarge);
779a747e4fSDavid du Colombier return;
789a747e4fSDavid du Colombier }
799a747e4fSDavid du Colombier fss = r->fid->aux;
809a747e4fSDavid du Colombier if(fss->pending){
819a747e4fSDavid du Colombier respond(r, "rpc already pending; read to clear");
829a747e4fSDavid du Colombier return;
839a747e4fSDavid du Colombier }
849a747e4fSDavid du Colombier memmove(fss->rpc.buf, r->ifcall.data, r->ifcall.count);
859a747e4fSDavid du Colombier fss->rpc.buf[r->ifcall.count] = '\0';
869a747e4fSDavid du Colombier fss->rpc.verb = fss->rpc.buf;
879a747e4fSDavid du Colombier if(fss->rpc.arg = strchr(fss->rpc.buf, ' ')){
889a747e4fSDavid du Colombier *fss->rpc.arg++ = '\0';
899a747e4fSDavid du Colombier fss->rpc.narg = r->ifcall.count - (fss->rpc.arg - fss->rpc.buf);
909a747e4fSDavid du Colombier }else{
919a747e4fSDavid du Colombier fss->rpc.arg = "";
929a747e4fSDavid du Colombier fss->rpc.narg = 0;
939a747e4fSDavid du Colombier }
949a747e4fSDavid du Colombier fss->rpc.iverb = classify(fss->rpc.verb, rpctab, nelem(rpctab));
959a747e4fSDavid du Colombier r->ofcall.count = r->ifcall.count;
969a747e4fSDavid du Colombier fss->pending = 1;
979a747e4fSDavid du Colombier respond(r, nil);
989a747e4fSDavid du Colombier }
999a747e4fSDavid du Colombier
1009a747e4fSDavid du Colombier static void
retstring(Req * r,Fsstate * fss,char * s)1019a747e4fSDavid du Colombier retstring(Req *r, Fsstate *fss, char *s)
1029a747e4fSDavid du Colombier {
1039a747e4fSDavid du Colombier int n;
1049a747e4fSDavid du Colombier
1059a747e4fSDavid du Colombier n = strlen(s);
1069a747e4fSDavid du Colombier if(n > r->ifcall.count)
1079a747e4fSDavid du Colombier n = r->ifcall.count;
1089a747e4fSDavid du Colombier memmove(r->ofcall.data, s, n);
1099a747e4fSDavid du Colombier r->ofcall.count = n;
1109a747e4fSDavid du Colombier fss->pending = 0;
1119a747e4fSDavid du Colombier respond(r, nil);
1129a747e4fSDavid du Colombier return;
1139a747e4fSDavid du Colombier }
1149a747e4fSDavid du Colombier
1159a747e4fSDavid du Colombier static void
retrpc(Req * r,int ret,Fsstate * fss)1169a747e4fSDavid du Colombier retrpc(Req *r, int ret, Fsstate *fss)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier switch(ret){
1199a747e4fSDavid du Colombier default:
1209a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "internal error %d", ret);
1219a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1229a747e4fSDavid du Colombier return;
1239a747e4fSDavid du Colombier case RpcErrstr:
1249a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "error %r");
1259a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1269a747e4fSDavid du Colombier return;
1279a747e4fSDavid du Colombier case RpcFailure:
1289a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
1299a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1309a747e4fSDavid du Colombier return;
1319a747e4fSDavid du Colombier case RpcNeedkey:
1329a747e4fSDavid du Colombier if(needkeyqueue(r, fss) < 0){
1339a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "needkey %s", fss->keyinfo);
1349a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier return;
1379a747e4fSDavid du Colombier case RpcOk:
1389a747e4fSDavid du Colombier retstring(r, fss, "ok");
1399a747e4fSDavid du Colombier return;
1409a747e4fSDavid du Colombier case RpcToosmall:
1419a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "toosmall %d", fss->rpc.nwant);
1429a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1439a747e4fSDavid du Colombier return;
1449a747e4fSDavid du Colombier case RpcPhase:
1459a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "phase %r");
1469a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1479a747e4fSDavid du Colombier return;
1489a747e4fSDavid du Colombier case RpcConfirm:
1499a747e4fSDavid du Colombier confirmqueue(r, fss);
1509a747e4fSDavid du Colombier return;
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier
1549a747e4fSDavid du Colombier int
rdwrcheck(Req * r,Fsstate * fss)1559a747e4fSDavid du Colombier rdwrcheck(Req *r, Fsstate *fss)
1569a747e4fSDavid du Colombier {
1579a747e4fSDavid du Colombier if(fss->ps == nil){
1589a747e4fSDavid du Colombier retstring(r, fss, "error no current protocol");
1599a747e4fSDavid du Colombier return -1;
1609a747e4fSDavid du Colombier }
1619a747e4fSDavid du Colombier if(fss->phase == Notstarted){
1629a747e4fSDavid du Colombier retstring(r, fss, "protocol not started");
1639a747e4fSDavid du Colombier return -1;
1649a747e4fSDavid du Colombier }
1659a747e4fSDavid du Colombier if(fss->phase == Broken){
1669a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
1679a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
1689a747e4fSDavid du Colombier return -1;
1699a747e4fSDavid du Colombier }
1709a747e4fSDavid du Colombier if(fss->phase == Established){
1719a747e4fSDavid du Colombier if(fss->haveai)
1729a747e4fSDavid du Colombier retstring(r, fss, "done haveai");
1739a747e4fSDavid du Colombier else
1749a747e4fSDavid du Colombier retstring(r, fss, "done");
1759a747e4fSDavid du Colombier return -1;
1769a747e4fSDavid du Colombier }
1779a747e4fSDavid du Colombier return 0;
1789a747e4fSDavid du Colombier }
1799a747e4fSDavid du Colombier
1809a747e4fSDavid du Colombier static void
logret(char * pre,Fsstate * fss,int ret)1819a747e4fSDavid du Colombier logret(char *pre, Fsstate *fss, int ret)
1829a747e4fSDavid du Colombier {
1839a747e4fSDavid du Colombier switch(ret){
1849a747e4fSDavid du Colombier default:
1859a747e4fSDavid du Colombier flog("%s: code %d", pre, ret);
1869a747e4fSDavid du Colombier break;
1879a747e4fSDavid du Colombier case RpcErrstr:
1889a747e4fSDavid du Colombier flog("%s: error %r", pre);
1899a747e4fSDavid du Colombier break;
1909a747e4fSDavid du Colombier case RpcFailure:
1919a747e4fSDavid du Colombier flog("%s: failure %s", pre, fss->err);
1929a747e4fSDavid du Colombier break;
1939a747e4fSDavid du Colombier case RpcNeedkey:
1949a747e4fSDavid du Colombier flog("%s: needkey %s", pre, fss->keyinfo);
1959a747e4fSDavid du Colombier break;
1969a747e4fSDavid du Colombier case RpcOk:
1979a747e4fSDavid du Colombier flog("%s: ok", pre);
1989a747e4fSDavid du Colombier break;
1999a747e4fSDavid du Colombier case RpcToosmall:
2009a747e4fSDavid du Colombier flog("%s: toosmall %d", pre, fss->rpc.nwant);
2019a747e4fSDavid du Colombier break;
2029a747e4fSDavid du Colombier case RpcPhase:
2039a747e4fSDavid du Colombier flog("%s: phase: %r", pre);
2049a747e4fSDavid du Colombier break;
2059a747e4fSDavid du Colombier case RpcConfirm:
2069a747e4fSDavid du Colombier flog("%s: waiting for confirm", pre);
2079a747e4fSDavid du Colombier break;
2089a747e4fSDavid du Colombier }
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier
2119a747e4fSDavid du Colombier void
rpcrdwrlog(Fsstate * fss,char * rdwr,uint n,int ophase,int ret)2129a747e4fSDavid du Colombier rpcrdwrlog(Fsstate *fss, char *rdwr, uint n, int ophase, int ret)
2139a747e4fSDavid du Colombier {
2149a747e4fSDavid du Colombier char buf0[40], buf1[40], pre[300];
2159a747e4fSDavid du Colombier
2169a747e4fSDavid du Colombier if(!debug)
2179a747e4fSDavid du Colombier return;
2189a747e4fSDavid du Colombier snprint(pre, sizeof pre, "%d: %s %ud in phase %s yields phase %s",
2199a747e4fSDavid du Colombier fss->seqnum, rdwr, n, phasename(fss, ophase, buf0), phasename(fss, fss->phase, buf1));
2209a747e4fSDavid du Colombier logret(pre, fss, ret);
2219a747e4fSDavid du Colombier }
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier void
rpcstartlog(Attr * attr,Fsstate * fss,int ret)2249a747e4fSDavid du Colombier rpcstartlog(Attr *attr, Fsstate *fss, int ret)
2259a747e4fSDavid du Colombier {
2269a747e4fSDavid du Colombier char pre[300], tmp[40];
2279a747e4fSDavid du Colombier
2289a747e4fSDavid du Colombier if(!debug)
2299a747e4fSDavid du Colombier return;
2309a747e4fSDavid du Colombier snprint(pre, sizeof pre, "%d: start %A yields phase %s", fss->seqnum,
2319a747e4fSDavid du Colombier attr, phasename(fss, fss->phase, tmp));
2329a747e4fSDavid du Colombier logret(pre, fss, ret);
2339a747e4fSDavid du Colombier }
2349a747e4fSDavid du Colombier
2359a747e4fSDavid du Colombier int seqnum;
2369a747e4fSDavid du Colombier
2379a747e4fSDavid du Colombier void
rpcread(Req * r)2389a747e4fSDavid du Colombier rpcread(Req *r)
2399a747e4fSDavid du Colombier {
2409a747e4fSDavid du Colombier Attr *attr;
2419a747e4fSDavid du Colombier char *p;
2429a747e4fSDavid du Colombier int ophase, ret;
2439a747e4fSDavid du Colombier uchar *e;
2449a747e4fSDavid du Colombier uint count;
2459a747e4fSDavid du Colombier Fsstate *fss;
2469a747e4fSDavid du Colombier Proto *proto;
2479a747e4fSDavid du Colombier
2489a747e4fSDavid du Colombier if(r->ifcall.count < 64){
2499a747e4fSDavid du Colombier respond(r, "rpc read too small");
2509a747e4fSDavid du Colombier return;
2519a747e4fSDavid du Colombier }
2529a747e4fSDavid du Colombier fss = r->fid->aux;
2539a747e4fSDavid du Colombier if(!fss->pending){
2549a747e4fSDavid du Colombier respond(r, "no rpc pending");
2559a747e4fSDavid du Colombier return;
2569a747e4fSDavid du Colombier }
2579a747e4fSDavid du Colombier switch(fss->rpc.iverb){
2589a747e4fSDavid du Colombier default:
2599a747e4fSDavid du Colombier case Vunknown:
2609a747e4fSDavid du Colombier retstring(r, fss, "error unknown verb");
2619a747e4fSDavid du Colombier break;
2629a747e4fSDavid du Colombier
2639a747e4fSDavid du Colombier case Vstart:
264d9306527SDavid du Colombier if(fss->phase != Notstarted){
265d9306527SDavid du Colombier flog("%d: implicit close due to second start; old attr '%A'", fss->seqnum, fss->attr);
266d9306527SDavid du Colombier if(fss->proto && fss->ps)
267d9306527SDavid du Colombier (*fss->proto->close)(fss);
268d9306527SDavid du Colombier fss->ps = nil;
269d9306527SDavid du Colombier fss->proto = nil;
270d9306527SDavid du Colombier _freeattr(fss->attr);
271d9306527SDavid du Colombier fss->attr = nil;
272d9306527SDavid du Colombier fss->phase = Notstarted;
273d9306527SDavid du Colombier }
2749a747e4fSDavid du Colombier attr = _parseattr(fss->rpc.arg);
2752ebbfa15SDavid du Colombier if((p = _strfindattr(attr, "proto")) == nil){
2769a747e4fSDavid du Colombier retstring(r, fss, "error did not specify proto");
277d9306527SDavid du Colombier _freeattr(attr);
2789a747e4fSDavid du Colombier break;
2799a747e4fSDavid du Colombier }
2809a747e4fSDavid du Colombier if((proto = findproto(p)) == nil){
2819a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "error unknown protocol %q", p);
2829a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
283d9306527SDavid du Colombier _freeattr(attr);
2849a747e4fSDavid du Colombier break;
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier fss->attr = attr;
2879a747e4fSDavid du Colombier fss->proto = proto;
2889a747e4fSDavid du Colombier fss->seqnum = ++seqnum;
2899a747e4fSDavid du Colombier ret = (*proto->init)(proto, fss);
2909a747e4fSDavid du Colombier rpcstartlog(attr, fss, ret);
2919a747e4fSDavid du Colombier if(ret != RpcOk){
2929a747e4fSDavid du Colombier _freeattr(fss->attr);
2939a747e4fSDavid du Colombier fss->attr = nil;
2949a747e4fSDavid du Colombier fss->phase = Notstarted;
2959a747e4fSDavid du Colombier }
2969a747e4fSDavid du Colombier retrpc(r, ret, fss);
2979a747e4fSDavid du Colombier break;
2989a747e4fSDavid du Colombier
2999a747e4fSDavid du Colombier case Vread:
3009a747e4fSDavid du Colombier if(fss->rpc.arg && fss->rpc.arg[0]){
3019a747e4fSDavid du Colombier retstring(r, fss, "error read needs no parameters");
3029a747e4fSDavid du Colombier break;
3039a747e4fSDavid du Colombier }
3049a747e4fSDavid du Colombier if(rdwrcheck(r, fss) < 0)
3059a747e4fSDavid du Colombier break;
3069a747e4fSDavid du Colombier count = r->ifcall.count - 3;
3079a747e4fSDavid du Colombier ophase = fss->phase;
3089a747e4fSDavid du Colombier ret = fss->proto->read(fss, (uchar*)r->ofcall.data+3, &count);
3099a747e4fSDavid du Colombier rpcrdwrlog(fss, "read", count, ophase, ret);
3109a747e4fSDavid du Colombier if(ret == RpcOk){
3119a747e4fSDavid du Colombier memmove(r->ofcall.data, "ok ", 3);
3129a747e4fSDavid du Colombier if(count == 0)
3139a747e4fSDavid du Colombier r->ofcall.count = 2;
3149a747e4fSDavid du Colombier else
3159a747e4fSDavid du Colombier r->ofcall.count = 3+count;
3169a747e4fSDavid du Colombier fss->pending = 0;
3179a747e4fSDavid du Colombier respond(r, nil);
3189a747e4fSDavid du Colombier }else
3199a747e4fSDavid du Colombier retrpc(r, ret, fss);
3209a747e4fSDavid du Colombier break;
3219a747e4fSDavid du Colombier
3229a747e4fSDavid du Colombier case Vwrite:
3239a747e4fSDavid du Colombier if(rdwrcheck(r, fss) < 0)
3249a747e4fSDavid du Colombier break;
3259a747e4fSDavid du Colombier ophase = fss->phase;
3269a747e4fSDavid du Colombier ret = fss->proto->write(fss, fss->rpc.arg, fss->rpc.narg);
3279a747e4fSDavid du Colombier rpcrdwrlog(fss, "write", fss->rpc.narg, ophase, ret);
3289a747e4fSDavid du Colombier retrpc(r, ret, fss);
3299a747e4fSDavid du Colombier break;
3309a747e4fSDavid du Colombier
3319a747e4fSDavid du Colombier case Vauthinfo:
3329a747e4fSDavid du Colombier if(fss->phase != Established){
3339a747e4fSDavid du Colombier retstring(r, fss, "error authentication unfinished");
3349a747e4fSDavid du Colombier break;
3359a747e4fSDavid du Colombier }
3369a747e4fSDavid du Colombier if(!fss->haveai){
3379a747e4fSDavid du Colombier retstring(r, fss, "error no authinfo available");
3389a747e4fSDavid du Colombier break;
3399a747e4fSDavid du Colombier }
3409a747e4fSDavid du Colombier memmove(r->ofcall.data, "ok ", 3);
341d9306527SDavid du Colombier fss->ai.cap = mkcap(r->fid->uid, fss->ai.suid);
3429a747e4fSDavid du Colombier e = convAI2M(&fss->ai, (uchar*)r->ofcall.data+3, r->ifcall.count-3);
3439a747e4fSDavid du Colombier free(fss->ai.cap);
3449a747e4fSDavid du Colombier fss->ai.cap = nil;
3459a747e4fSDavid du Colombier if(e == nil){
3469a747e4fSDavid du Colombier retstring(r, fss, "error read too small");
3479a747e4fSDavid du Colombier break;
3489a747e4fSDavid du Colombier }
3499a747e4fSDavid du Colombier r->ofcall.count = e - (uchar*)r->ofcall.data;
3509a747e4fSDavid du Colombier fss->pending = 0;
3519a747e4fSDavid du Colombier respond(r, nil);
3529a747e4fSDavid du Colombier break;
3539a747e4fSDavid du Colombier
3549a747e4fSDavid du Colombier case Vattr:
3559a747e4fSDavid du Colombier snprint(fss->rpc.buf, Maxrpc, "ok %A", fss->attr);
3569a747e4fSDavid du Colombier retstring(r, fss, fss->rpc.buf);
3579a747e4fSDavid du Colombier break;
3589a747e4fSDavid du Colombier }
3599a747e4fSDavid du Colombier }
3609a747e4fSDavid du Colombier
3619a747e4fSDavid du Colombier enum {
3629a747e4fSDavid du Colombier Vdelkey,
3639a747e4fSDavid du Colombier Vaddkey,
3649a747e4fSDavid du Colombier Vdebug,
3659a747e4fSDavid du Colombier };
3669a747e4fSDavid du Colombier
3679a747e4fSDavid du Colombier Verb ctltab[] = {
3689a747e4fSDavid du Colombier "delkey", Vdelkey,
3699a747e4fSDavid du Colombier "key", Vaddkey,
3709a747e4fSDavid du Colombier "debug", Vdebug,
3719a747e4fSDavid du Colombier };
3729a747e4fSDavid du Colombier
3739a747e4fSDavid du Colombier /*
3749a747e4fSDavid du Colombier * key attr=val... - add a key
3759a747e4fSDavid du Colombier * the attr=val pairs are protocol-specific.
3769a747e4fSDavid du Colombier * for example, both of these are valid:
3779a747e4fSDavid du Colombier * key p9sk1 gre cs.bell-labs.com mysecret
3789a747e4fSDavid du Colombier * key p9sk1 gre cs.bell-labs.com 11223344556677 fmt=des7hex
3799a747e4fSDavid du Colombier * delkey ... - delete a key
3809a747e4fSDavid du Colombier * if given, the attr=val pairs are used to narrow the search
3819a747e4fSDavid du Colombier * [maybe should require a password?]
3829a747e4fSDavid du Colombier */
3839a747e4fSDavid du Colombier
3849a747e4fSDavid du Colombier int
ctlwrite(char * a,int atzero)385*70b8e010SDavid du Colombier ctlwrite(char *a, int atzero)
3869a747e4fSDavid du Colombier {
3879a747e4fSDavid du Colombier char *p;
3889a747e4fSDavid du Colombier int i, nmatch, ret;
3899a747e4fSDavid du Colombier Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos;
3909a747e4fSDavid du Colombier Key *k;
3919a747e4fSDavid du Colombier Proto *proto;
3929a747e4fSDavid du Colombier
3939a747e4fSDavid du Colombier if(a[0] == '#' || a[0] == '\0')
3949a747e4fSDavid du Colombier return 0;
3959a747e4fSDavid du Colombier
396d9306527SDavid du Colombier /*
397d9306527SDavid du Colombier * it would be nice to emit a warning of some sort here.
398d9306527SDavid du Colombier * we ignore all but the first line of the write. this helps
399d9306527SDavid du Colombier * both with things like "echo delkey >/mnt/factotum/ctl"
400d9306527SDavid du Colombier * and writes that (incorrectly) contain multiple key lines.
401d9306527SDavid du Colombier */
402d9306527SDavid du Colombier if(p = strchr(a, '\n')){
403d9306527SDavid du Colombier if(p[1] != '\0'){
404d9306527SDavid du Colombier werrstr("multiline write not allowed");
405d9306527SDavid du Colombier return -1;
406d9306527SDavid du Colombier }
407d9306527SDavid du Colombier *p = '\0';
408d9306527SDavid du Colombier }
409d9306527SDavid du Colombier
4109a747e4fSDavid du Colombier if((p = strchr(a, ' ')) == nil)
4119a747e4fSDavid du Colombier p = "";
4129a747e4fSDavid du Colombier else
4139a747e4fSDavid du Colombier *p++ = '\0';
4149a747e4fSDavid du Colombier switch(classify(a, ctltab, nelem(ctltab))){
4159a747e4fSDavid du Colombier default:
4169a747e4fSDavid du Colombier case Vunknown:
4179a747e4fSDavid du Colombier werrstr("unknown verb");
4189a747e4fSDavid du Colombier return -1;
4199a747e4fSDavid du Colombier case Vdebug:
4209a747e4fSDavid du Colombier debug ^= 1;
4219a747e4fSDavid du Colombier return 0;
4229a747e4fSDavid du Colombier case Vdelkey:
4239a747e4fSDavid du Colombier nmatch = 0;
4249a747e4fSDavid du Colombier attr = _parseattr(p);
425d9306527SDavid du Colombier for(pa=attr; pa; pa=pa->next){
4262ebbfa15SDavid du Colombier if(pa->type != AttrQuery && pa->name[0]=='!'){
427d9306527SDavid du Colombier werrstr("only !private? patterns are allowed for private fields");
428d9306527SDavid du Colombier _freeattr(attr);
429d9306527SDavid du Colombier return -1;
430d9306527SDavid du Colombier }
431d9306527SDavid du Colombier }
4329a747e4fSDavid du Colombier for(i=0; i<ring->nkey; ){
433d9306527SDavid du Colombier if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){
4349a747e4fSDavid du Colombier nmatch++;
4359a747e4fSDavid du Colombier closekey(ring->key[i]);
4369a747e4fSDavid du Colombier ring->nkey--;
4379a747e4fSDavid du Colombier memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0]));
4389a747e4fSDavid du Colombier }else
4399a747e4fSDavid du Colombier i++;
4409a747e4fSDavid du Colombier }
4419a747e4fSDavid du Colombier _freeattr(attr);
4429a747e4fSDavid du Colombier if(nmatch == 0){
4439a747e4fSDavid du Colombier werrstr("found no keys to delete");
4449a747e4fSDavid du Colombier return -1;
4459a747e4fSDavid du Colombier }
4469a747e4fSDavid du Colombier return 0;
4479a747e4fSDavid du Colombier case Vaddkey:
4489a747e4fSDavid du Colombier attr = _parseattr(p);
4499a747e4fSDavid du Colombier /* separate out proto= attributes */
4509a747e4fSDavid du Colombier lprotos = &protos;
4519a747e4fSDavid du Colombier for(l=&attr; (*l); ){
4522ebbfa15SDavid du Colombier if(strcmp((*l)->name, "proto") == 0){
4539a747e4fSDavid du Colombier *lprotos = *l;
4549a747e4fSDavid du Colombier lprotos = &(*l)->next;
4559a747e4fSDavid du Colombier *l = (*l)->next;
4569a747e4fSDavid du Colombier }else
4579a747e4fSDavid du Colombier l = &(*l)->next;
4589a747e4fSDavid du Colombier }
4599a747e4fSDavid du Colombier *lprotos = nil;
4609a747e4fSDavid du Colombier if(protos == nil){
4619a747e4fSDavid du Colombier werrstr("key without protos");
4629a747e4fSDavid du Colombier _freeattr(attr);
4639a747e4fSDavid du Colombier return -1;
4649a747e4fSDavid du Colombier }
4659a747e4fSDavid du Colombier
4669a747e4fSDavid du Colombier /* separate out private attributes */
4679a747e4fSDavid du Colombier lpriv = &priv;
4689a747e4fSDavid du Colombier for(l=&attr; (*l); ){
4692ebbfa15SDavid du Colombier if((*l)->name[0] == '!'){
4709a747e4fSDavid du Colombier *lpriv = *l;
4719a747e4fSDavid du Colombier lpriv = &(*l)->next;
4729a747e4fSDavid du Colombier *l = (*l)->next;
4739a747e4fSDavid du Colombier }else
4749a747e4fSDavid du Colombier l = &(*l)->next;
4759a747e4fSDavid du Colombier }
4769a747e4fSDavid du Colombier *lpriv = nil;
4779a747e4fSDavid du Colombier
4789a747e4fSDavid du Colombier /* add keys */
4799a747e4fSDavid du Colombier ret = 0;
4809a747e4fSDavid du Colombier for(pa=protos; pa; pa=pa->next){
4812ebbfa15SDavid du Colombier if((proto = findproto(pa->val)) == nil){
4822ebbfa15SDavid du Colombier werrstr("unknown proto %s", pa->val);
4839a747e4fSDavid du Colombier ret = -1;
4849a747e4fSDavid du Colombier continue;
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier if(proto->addkey == nil){
4879a747e4fSDavid du Colombier werrstr("proto %s doesn't take keys", proto->name);
4889a747e4fSDavid du Colombier ret = -1;
4899a747e4fSDavid du Colombier continue;
4909a747e4fSDavid du Colombier }
4919a747e4fSDavid du Colombier k = emalloc(sizeof(Key));
4929a747e4fSDavid du Colombier k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr));
4939a747e4fSDavid du Colombier k->privattr = _copyattr(priv);
4949a747e4fSDavid du Colombier k->ref = 1;
495d9306527SDavid du Colombier k->proto = proto;
496*70b8e010SDavid du Colombier if(proto->addkey(k, atzero) < 0){
4979a747e4fSDavid du Colombier ret = -1;
4989a747e4fSDavid du Colombier closekey(k);
4999a747e4fSDavid du Colombier continue;
5009a747e4fSDavid du Colombier }
5019a747e4fSDavid du Colombier closekey(k);
5029a747e4fSDavid du Colombier }
5039a747e4fSDavid du Colombier _freeattr(attr);
5049a747e4fSDavid du Colombier _freeattr(priv);
5059a747e4fSDavid du Colombier _freeattr(protos);
5069a747e4fSDavid du Colombier return ret;
5079a747e4fSDavid du Colombier }
5089a747e4fSDavid du Colombier }
509