Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
}