1 /*
2 * Factotum RPC
3 *
4 * Must be paired write/read cycles on /mnt/factotum/rpc.
5 * The format of a request is verb, single space, data.
6 * Data format is verb-dependent; in particular, it can be binary.
7 * The format of a response is the same. The write only sets up
8 * the RPC. The read tries to execute it. If the /mnt/factotum/key
9 * file is open, we ask for new keys using that instead of returning
10 * an error in the RPC. This means the read blocks.
11 * Textual arguments are parsed with tokenize, so rc-style quoting
12 * rules apply.
13 *
14 * Only authentication protocol messages go here. Configuration
15 * is still via ctl (below).
16 *
17 * Return values are:
18 * error message - an error happened.
19 * ok [data] - success, possible data is request dependent.
20 * needkey proto domain user - request aborted, get me this key and try again
21 * badkey proto domain user - request aborted, this key might be bad
22 * done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
23 * Request RPCs are:
24 * start attrs - initializes protocol for authentication, can fail.
25 * returns "ok read" or "ok write" on success.
26 * read - execute protocol read
27 * write - execute protocol write
28 * authinfo - if the protocol is finished, return the AI if any
29 * attr - return protocol information
30 */
31
32 #include "dat.h"
33
34 Req *rpcwait;
35
36 typedef struct Verb Verb;
37 struct Verb {
38 char *verb;
39 int iverb;
40 };
41
42 enum {
43 Vunknown = -1,
44 Vauthinfo = 0,
45 Vread,
46 Vstart,
47 Vwrite,
48 Vattr,
49 };
50
51 Verb rpctab[] = {
52 "authinfo", Vauthinfo,
53 "read", Vread,
54 "start", Vstart,
55 "write", Vwrite,
56 "attr", Vattr,
57 };
58
59 static int
classify(char * s,Verb * verbtab,int nverbtab)60 classify(char *s, Verb *verbtab, int nverbtab)
61 {
62 int i;
63
64 for(i=0; i<nverbtab; i++)
65 if(strcmp(s, verbtab[i].verb) == 0)
66 return verbtab[i].iverb;
67 return Vunknown;
68 }
69
70 void
rpcwrite(Req * r)71 rpcwrite(Req *r)
72 {
73 Fsstate *fss;
74
75 if(r->ifcall.count >= Maxrpc){
76 respond(r, Etoolarge);
77 return;
78 }
79 fss = r->fid->aux;
80 if(fss->pending){
81 respond(r, "rpc already pending; read to clear");
82 return;
83 }
84 memmove(fss->rpc.buf, r->ifcall.data, r->ifcall.count);
85 fss->rpc.buf[r->ifcall.count] = '\0';
86 fss->rpc.verb = fss->rpc.buf;
87 if(fss->rpc.arg = strchr(fss->rpc.buf, ' ')){
88 *fss->rpc.arg++ = '\0';
89 fss->rpc.narg = r->ifcall.count - (fss->rpc.arg - fss->rpc.buf);
90 }else{
91 fss->rpc.arg = "";
92 fss->rpc.narg = 0;
93 }
94 fss->rpc.iverb = classify(fss->rpc.verb, rpctab, nelem(rpctab));
95 r->ofcall.count = r->ifcall.count;
96 fss->pending = 1;
97 respond(r, nil);
98 }
99
100 static void
retstring(Req * r,Fsstate * fss,char * s)101 retstring(Req *r, Fsstate *fss, char *s)
102 {
103 int n;
104
105 n = strlen(s);
106 if(n > r->ifcall.count)
107 n = r->ifcall.count;
108 memmove(r->ofcall.data, s, n);
109 r->ofcall.count = n;
110 fss->pending = 0;
111 respond(r, nil);
112 return;
113 }
114
115 static void
retrpc(Req * r,int ret,Fsstate * fss)116 retrpc(Req *r, int ret, Fsstate *fss)
117 {
118 switch(ret){
119 default:
120 snprint(fss->rpc.buf, Maxrpc, "internal error %d", ret);
121 retstring(r, fss, fss->rpc.buf);
122 return;
123 case RpcErrstr:
124 snprint(fss->rpc.buf, Maxrpc, "error %r");
125 retstring(r, fss, fss->rpc.buf);
126 return;
127 case RpcFailure:
128 snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
129 retstring(r, fss, fss->rpc.buf);
130 return;
131 case RpcNeedkey:
132 if(needkeyqueue(r, fss) < 0){
133 snprint(fss->rpc.buf, Maxrpc, "needkey %s", fss->keyinfo);
134 retstring(r, fss, fss->rpc.buf);
135 }
136 return;
137 case RpcOk:
138 retstring(r, fss, "ok");
139 return;
140 case RpcToosmall:
141 snprint(fss->rpc.buf, Maxrpc, "toosmall %d", fss->rpc.nwant);
142 retstring(r, fss, fss->rpc.buf);
143 return;
144 case RpcPhase:
145 snprint(fss->rpc.buf, Maxrpc, "phase %r");
146 retstring(r, fss, fss->rpc.buf);
147 return;
148 case RpcConfirm:
149 confirmqueue(r, fss);
150 return;
151 }
152 }
153
154 int
rdwrcheck(Req * r,Fsstate * fss)155 rdwrcheck(Req *r, Fsstate *fss)
156 {
157 if(fss->ps == nil){
158 retstring(r, fss, "error no current protocol");
159 return -1;
160 }
161 if(fss->phase == Notstarted){
162 retstring(r, fss, "protocol not started");
163 return -1;
164 }
165 if(fss->phase == Broken){
166 snprint(fss->rpc.buf, Maxrpc, "error %s", fss->err);
167 retstring(r, fss, fss->rpc.buf);
168 return -1;
169 }
170 if(fss->phase == Established){
171 if(fss->haveai)
172 retstring(r, fss, "done haveai");
173 else
174 retstring(r, fss, "done");
175 return -1;
176 }
177 return 0;
178 }
179
180 static void
logret(char * pre,Fsstate * fss,int ret)181 logret(char *pre, Fsstate *fss, int ret)
182 {
183 switch(ret){
184 default:
185 flog("%s: code %d", pre, ret);
186 break;
187 case RpcErrstr:
188 flog("%s: error %r", pre);
189 break;
190 case RpcFailure:
191 flog("%s: failure %s", pre, fss->err);
192 break;
193 case RpcNeedkey:
194 flog("%s: needkey %s", pre, fss->keyinfo);
195 break;
196 case RpcOk:
197 flog("%s: ok", pre);
198 break;
199 case RpcToosmall:
200 flog("%s: toosmall %d", pre, fss->rpc.nwant);
201 break;
202 case RpcPhase:
203 flog("%s: phase: %r", pre);
204 break;
205 case RpcConfirm:
206 flog("%s: waiting for confirm", pre);
207 break;
208 }
209 }
210
211 void
rpcrdwrlog(Fsstate * fss,char * rdwr,uint n,int ophase,int ret)212 rpcrdwrlog(Fsstate *fss, char *rdwr, uint n, int ophase, int ret)
213 {
214 char buf0[40], buf1[40], pre[300];
215
216 if(!debug)
217 return;
218 snprint(pre, sizeof pre, "%d: %s %ud in phase %s yields phase %s",
219 fss->seqnum, rdwr, n, phasename(fss, ophase, buf0), phasename(fss, fss->phase, buf1));
220 logret(pre, fss, ret);
221 }
222
223 void
rpcstartlog(Attr * attr,Fsstate * fss,int ret)224 rpcstartlog(Attr *attr, Fsstate *fss, int ret)
225 {
226 char pre[300], tmp[40];
227
228 if(!debug)
229 return;
230 snprint(pre, sizeof pre, "%d: start %A yields phase %s", fss->seqnum,
231 attr, phasename(fss, fss->phase, tmp));
232 logret(pre, fss, ret);
233 }
234
235 int seqnum;
236
237 void
rpcread(Req * r)238 rpcread(Req *r)
239 {
240 Attr *attr;
241 char *p;
242 int ophase, ret;
243 uchar *e;
244 uint count;
245 Fsstate *fss;
246 Proto *proto;
247
248 if(r->ifcall.count < 64){
249 respond(r, "rpc read too small");
250 return;
251 }
252 fss = r->fid->aux;
253 if(!fss->pending){
254 respond(r, "no rpc pending");
255 return;
256 }
257 switch(fss->rpc.iverb){
258 default:
259 case Vunknown:
260 retstring(r, fss, "error unknown verb");
261 break;
262
263 case Vstart:
264 if(fss->phase != Notstarted){
265 flog("%d: implicit close due to second start; old attr '%A'", fss->seqnum, fss->attr);
266 if(fss->proto && fss->ps)
267 (*fss->proto->close)(fss);
268 fss->ps = nil;
269 fss->proto = nil;
270 _freeattr(fss->attr);
271 fss->attr = nil;
272 fss->phase = Notstarted;
273 }
274 attr = _parseattr(fss->rpc.arg);
275 if((p = _strfindattr(attr, "proto")) == nil){
276 retstring(r, fss, "error did not specify proto");
277 _freeattr(attr);
278 break;
279 }
280 if((proto = findproto(p)) == nil){
281 snprint(fss->rpc.buf, Maxrpc, "error unknown protocol %q", p);
282 retstring(r, fss, fss->rpc.buf);
283 _freeattr(attr);
284 break;
285 }
286 fss->attr = attr;
287 fss->proto = proto;
288 fss->seqnum = ++seqnum;
289 ret = (*proto->init)(proto, fss);
290 rpcstartlog(attr, fss, ret);
291 if(ret != RpcOk){
292 _freeattr(fss->attr);
293 fss->attr = nil;
294 fss->phase = Notstarted;
295 }
296 retrpc(r, ret, fss);
297 break;
298
299 case Vread:
300 if(fss->rpc.arg && fss->rpc.arg[0]){
301 retstring(r, fss, "error read needs no parameters");
302 break;
303 }
304 if(rdwrcheck(r, fss) < 0)
305 break;
306 count = r->ifcall.count - 3;
307 ophase = fss->phase;
308 ret = fss->proto->read(fss, (uchar*)r->ofcall.data+3, &count);
309 rpcrdwrlog(fss, "read", count, ophase, ret);
310 if(ret == RpcOk){
311 memmove(r->ofcall.data, "ok ", 3);
312 if(count == 0)
313 r->ofcall.count = 2;
314 else
315 r->ofcall.count = 3+count;
316 fss->pending = 0;
317 respond(r, nil);
318 }else
319 retrpc(r, ret, fss);
320 break;
321
322 case Vwrite:
323 if(rdwrcheck(r, fss) < 0)
324 break;
325 ophase = fss->phase;
326 ret = fss->proto->write(fss, fss->rpc.arg, fss->rpc.narg);
327 rpcrdwrlog(fss, "write", fss->rpc.narg, ophase, ret);
328 retrpc(r, ret, fss);
329 break;
330
331 case Vauthinfo:
332 if(fss->phase != Established){
333 retstring(r, fss, "error authentication unfinished");
334 break;
335 }
336 if(!fss->haveai){
337 retstring(r, fss, "error no authinfo available");
338 break;
339 }
340 memmove(r->ofcall.data, "ok ", 3);
341 fss->ai.cap = mkcap(r->fid->uid, fss->ai.suid);
342 e = convAI2M(&fss->ai, (uchar*)r->ofcall.data+3, r->ifcall.count-3);
343 free(fss->ai.cap);
344 fss->ai.cap = nil;
345 if(e == nil){
346 retstring(r, fss, "error read too small");
347 break;
348 }
349 r->ofcall.count = e - (uchar*)r->ofcall.data;
350 fss->pending = 0;
351 respond(r, nil);
352 break;
353
354 case Vattr:
355 snprint(fss->rpc.buf, Maxrpc, "ok %A", fss->attr);
356 retstring(r, fss, fss->rpc.buf);
357 break;
358 }
359 }
360
361 enum {
362 Vdelkey,
363 Vaddkey,
364 Vdebug,
365 };
366
367 Verb ctltab[] = {
368 "delkey", Vdelkey,
369 "key", Vaddkey,
370 "debug", Vdebug,
371 };
372
373 /*
374 * key attr=val... - add a key
375 * the attr=val pairs are protocol-specific.
376 * for example, both of these are valid:
377 * key p9sk1 gre cs.bell-labs.com mysecret
378 * key p9sk1 gre cs.bell-labs.com 11223344556677 fmt=des7hex
379 * delkey ... - delete a key
380 * if given, the attr=val pairs are used to narrow the search
381 * [maybe should require a password?]
382 */
383
384 int
ctlwrite(char * a,int atzero)385 ctlwrite(char *a, int atzero)
386 {
387 char *p;
388 int i, nmatch, ret;
389 Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos;
390 Key *k;
391 Proto *proto;
392
393 if(a[0] == '#' || a[0] == '\0')
394 return 0;
395
396 /*
397 * it would be nice to emit a warning of some sort here.
398 * we ignore all but the first line of the write. this helps
399 * both with things like "echo delkey >/mnt/factotum/ctl"
400 * and writes that (incorrectly) contain multiple key lines.
401 */
402 if(p = strchr(a, '\n')){
403 if(p[1] != '\0'){
404 werrstr("multiline write not allowed");
405 return -1;
406 }
407 *p = '\0';
408 }
409
410 if((p = strchr(a, ' ')) == nil)
411 p = "";
412 else
413 *p++ = '\0';
414 switch(classify(a, ctltab, nelem(ctltab))){
415 default:
416 case Vunknown:
417 werrstr("unknown verb");
418 return -1;
419 case Vdebug:
420 debug ^= 1;
421 return 0;
422 case Vdelkey:
423 nmatch = 0;
424 attr = _parseattr(p);
425 for(pa=attr; pa; pa=pa->next){
426 if(pa->type != AttrQuery && pa->name[0]=='!'){
427 werrstr("only !private? patterns are allowed for private fields");
428 _freeattr(attr);
429 return -1;
430 }
431 }
432 for(i=0; i<ring->nkey; ){
433 if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){
434 nmatch++;
435 closekey(ring->key[i]);
436 ring->nkey--;
437 memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0]));
438 }else
439 i++;
440 }
441 _freeattr(attr);
442 if(nmatch == 0){
443 werrstr("found no keys to delete");
444 return -1;
445 }
446 return 0;
447 case Vaddkey:
448 attr = _parseattr(p);
449 /* separate out proto= attributes */
450 lprotos = &protos;
451 for(l=&attr; (*l); ){
452 if(strcmp((*l)->name, "proto") == 0){
453 *lprotos = *l;
454 lprotos = &(*l)->next;
455 *l = (*l)->next;
456 }else
457 l = &(*l)->next;
458 }
459 *lprotos = nil;
460 if(protos == nil){
461 werrstr("key without protos");
462 _freeattr(attr);
463 return -1;
464 }
465
466 /* separate out private attributes */
467 lpriv = &priv;
468 for(l=&attr; (*l); ){
469 if((*l)->name[0] == '!'){
470 *lpriv = *l;
471 lpriv = &(*l)->next;
472 *l = (*l)->next;
473 }else
474 l = &(*l)->next;
475 }
476 *lpriv = nil;
477
478 /* add keys */
479 ret = 0;
480 for(pa=protos; pa; pa=pa->next){
481 if((proto = findproto(pa->val)) == nil){
482 werrstr("unknown proto %s", pa->val);
483 ret = -1;
484 continue;
485 }
486 if(proto->addkey == nil){
487 werrstr("proto %s doesn't take keys", proto->name);
488 ret = -1;
489 continue;
490 }
491 k = emalloc(sizeof(Key));
492 k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr));
493 k->privattr = _copyattr(priv);
494 k->ref = 1;
495 k->proto = proto;
496 if(proto->addkey(k, atzero) < 0){
497 ret = -1;
498 closekey(k);
499 continue;
500 }
501 closekey(k);
502 }
503 _freeattr(attr);
504 _freeattr(priv);
505 _freeattr(protos);
506 return ret;
507 }
508 }
509