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
 * p9any - protocol negotiator.
3
 *
4
 * Protocol:
5
 *	Server->Client: list of proto@domain, tokenize separated, nul terminated
6
 *	Client->Server: proto domain, tokenize separated (not proto@domain), nul terminated
7
 *
8
 * Server protocol:
9
 * 	read list of protocols.
10
 *	write null-terminated 
11
 */
12
 
13
#include "dat.h"
14
 
15
static Proto *negotiable[] = {
16
	&p9sk1,
17
};
18
 
19
struct State
20
{
21
	Fsstate subfss;
22
	State *substate;	/* be very careful; this is not one of our States */
23
	Proto *subproto;
24
	int keyasked;
25
	String *subdom;
26
	int version;
27
};
28
 
29
enum
30
{
31
	CNeedProtos,
32
	CHaveProto,
33
	CNeedOK,
34
	CRelay,
35
 
36
	SHaveProtos,
37
	SNeedProto,
38
	SHaveOK,
39
	SRelay,
40
 
41
	Maxphase,
42
};
43
 
44
static char *phasenames[Maxphase] =
45
{
46
[CNeedProtos]	"CNeedProtos",
47
[CHaveProto]	"CHaveProto",
48
[CNeedOK]	"CNeedOK",
49
[CRelay]	"CRelay",
50
[SHaveProtos]	"SHaveProtos",
51
[SNeedProto]	"SNeedProto",
52
[SHaveOK]	"SHaveOK",
53
[SRelay]	"SRelay",
54
};
55
 
56
static int
57
p9anyinit(Proto*, Fsstate *fss)
58
{
59
	int iscli;
60
	State *s;
61
 
62
	if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
63
		return failure(fss, nil);
64
 
65
	s = emalloc(sizeof *s);
66
	fss = fss;
67
	fss->phasename = phasenames;
68
	fss->maxphase = Maxphase;
69
	if(iscli)
70
		fss->phase = CNeedProtos;
71
	else
72
		fss->phase = SHaveProtos;
73
	s->version = 1;
74
	fss->ps = s;
75
	return RpcOk;
76
}
77
 
78
static void
79
p9anyclose(Fsstate *fss)
80
{
81
	State *s;
82
 
83
	s = fss->ps;
84
	if(s->subproto && s->subfss.ps && s->subproto->close)
85
		(*s->subproto->close)(&s->subfss);
86
	s->subproto = nil;
87
	s->substate = nil;
88
	s_free(s->subdom);
89
	s->subdom = nil;
90
	s->keyasked = 0;
91
	memset(&s->subfss, 0, sizeof s->subfss);
92
	free(s);
93
}
94
 
95
static void
96
setupfss(Fsstate *fss, State *s, Key *k)
97
{
98
	fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name);
99
	fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom"));
100
	s->subfss.attr = fss->attr;
101
	s->subfss.phase = Notstarted;
102
	s->subfss.sysuser = fss->sysuser;
103
	s->subfss.seqnum = fss->seqnum;
104
	s->subfss.conf = fss->conf;
105
	s->subfss.nconf = fss->nconf;
106
}
107
 
108
static int
109
passret(Fsstate *fss, State *s, int ret)
110
{
111
	switch(ret){
112
	default:
113
		return ret;
114
	case RpcFailure:
115
		if(s->subfss.phase == Broken)
116
			fss->phase = Broken;
117
		memmove(fss->err, s->subfss.err, sizeof fss->err);
118
		return ret;
119
	case RpcNeedkey:
120
		memmove(fss->keyinfo, s->subfss.keyinfo, sizeof fss->keyinfo);
121
		return ret;
122
	case RpcOk:
123
		if(s->subfss.haveai){
124
			fss->haveai = 1;
125
			fss->ai = s->subfss.ai;
126
			s->subfss.haveai = 0;
127
		}
128
		if(s->subfss.phase == Established)
129
			fss->phase = Established;
130
		return ret;
131
	case RpcToosmall:
132
		fss->rpc.nwant = s->subfss.rpc.nwant;
133
		return ret;
134
	case RpcConfirm:
135
		fss->conf = s->subfss.conf;
136
		fss->nconf = s->subfss.nconf;
137
		return ret;
138
	}
139
}
140
 
141
static int
142
p9anyread(Fsstate *fss, void *a, uint *n)
143
{
144
	int i, m, ophase, ret;
145
	Attr *anew;
146
	Key *k;
147
	Keyinfo ki;
148
	String *negstr;
149
	State *s;
150
 
151
	s = fss->ps;
152
	switch(fss->phase){
153
	default:
154
		return phaseerror(fss, "read");
155
 
156
	case SHaveProtos:
157
		m = 0;
158
		negstr = s_new();
159
		mkkeyinfo(&ki, fss, nil);
160
		ki.attr = nil;
161
		ki.noconf = 1;
162
		ki.user = nil;
163
		for(i=0; i<nelem(negotiable); i++){
164
			anew = setattr(_copyattr(fss->attr), "proto=%q dom?", negotiable[i]->name);
165
			ki.attr = anew;
166
			for(ki.skip=0; findkey(&k, &ki, nil)==RpcOk; ki.skip++){
167
				if(m++)
168
					s_append(negstr, " ");
169
				s_append(negstr, negotiable[i]->name);
170
				s_append(negstr, "@");
171
				s_append(negstr, _strfindattr(k->attr, "dom"));
172
				closekey(k);
173
			}
174
			_freeattr(anew);
175
		}
176
		if(m == 0){
177
			s_free(negstr);
178
			return failure(fss, Enegotiation);
179
		}
180
		i = s_len(negstr)+1;
181
		if(*n < i){
182
			s_free(negstr);
183
			return toosmall(fss, i);
184
		}
185
		*n = i;
186
		memmove(a, s_to_c(negstr), i+1);
187
		fss->phase = SNeedProto;
188
		s_free(negstr);
189
		return RpcOk;
190
 
191
	case CHaveProto:
192
		i = strlen(s->subproto->name)+1+s_len(s->subdom)+1;
193
		if(*n < i)
194
			return toosmall(fss, i);
195
		*n = i;
196
		strcpy(a, s->subproto->name);
197
		strcat(a, " ");
198
		strcat(a, s_to_c(s->subdom));
199
		if(s->version == 1)
200
			fss->phase = CRelay;
201
		else
202
			fss->phase = CNeedOK;
203
		return RpcOk;
204
 
205
	case SHaveOK:
206
		i = 3;
207
		if(*n < i)
208
			return toosmall(fss, i);
209
		*n = i;
210
		strcpy(a, "OK");
211
		fss->phase = SRelay;
212
		return RpcOk;
213
 
214
	case CRelay:
215
	case SRelay:
216
		ophase = s->subfss.phase;
217
		ret = (*s->subproto->read)(&s->subfss, a, n);
218
		rpcrdwrlog(&s->subfss, "read", *n, ophase, ret);
219
		return passret(fss, s, ret);
220
	}
221
}
222
 
223
static char*
224
getdom(char *p)
225
{
226
	p = strchr(p, '@');
227
	if(p == nil)
228
		return "";
229
	return p+1;
230
}
231
 
232
static Proto*
233
findneg(char *name)
234
{
235
	int i, len;
236
	char *p;
237
 
238
	if(p = strchr(name, '@'))
239
		len = p-name;
240
	else
241
		len = strlen(name);
242
 
243
	for(i=0; i<nelem(negotiable); i++)
244
		if(strncmp(negotiable[i]->name, name, len) == 0 && negotiable[i]->name[len] == 0)
245
			return negotiable[i];
246
	return nil;
247
}
248
 
249
static int
250
p9anywrite(Fsstate *fss, void *va, uint n)
251
{
252
	char *a, *dom, *user, *token[20];
253
	int asking, i, m, ophase, ret;
254
	Attr *anew, *anewsf, *attr;
255
	Key *k;
256
	Keyinfo ki;
257
	Proto *p;
258
	State *s;
259
 
260
	s = fss->ps;
261
	a = va;
262
	switch(fss->phase){
263
	default:
264
		return phaseerror(fss, "write");
265
 
266
	case CNeedProtos:
267
		if(n==0 || a[n-1] != '\0')
268
			return toosmall(fss, 2048);
269
		a = estrdup(a);
270
		m = tokenize(a, token, nelem(token));
271
		if(m > 0 && strncmp(token[0], "v.", 2) == 0){
272
			s->version = atoi(token[0]+2);
273
			if(s->version != 2){
274
				free(a);
275
				return failure(fss, "unknown version of p9any");
276
			}
277
		}
278
 
279
		/*
280
		 * look for a key
281
		 */
282
		anew = _delattr(_delattr(_copyattr(fss->attr), "proto"), "role");
283
		anewsf = _delattr(_copyattr(anew), "user");
284
		user = _strfindattr(anew, "user");
285
		k = nil;
286
		p = nil;
287
		dom = nil;
288
		for(i=(s->version==1?0:1); i<m; i++){
289
			p = findneg(token[i]);
290
			if(p == nil)
291
				continue;
292
			dom = getdom(token[i]);
293
			ret = RpcFailure;
294
			mkkeyinfo(&ki, fss, nil);
295
			if(user==nil || strcmp(user, fss->sysuser)==0){
296
				ki.attr = anewsf;
297
				ki.user = nil;
298
				ret = findkey(&k, &ki, "proto=%q dom=%q role=speakfor %s",
299
						p->name, dom, p->keyprompt);
300
			}
301
			if(ret == RpcFailure){
302
				ki.attr = anew;
303
				ki.user = fss->sysuser;
304
				ret = findkey(&k, &ki,
305
					"proto=%q dom=%q role=client %s",
306
					p->name, dom, p->keyprompt);
307
			}
308
			if(ret == RpcConfirm){
309
				free(a);
310
				return ret;
311
			}
312
			if(ret == RpcOk)
313
				break;
314
		}
315
		_freeattr(anewsf);
316
 
317
		/*
318
		 * no acceptable key, go through the proto@domains one at a time.
319
		 */
320
		asking = 0;
321
		if(k == nil){
322
			while(!asking && s->keyasked < m){
323
				p = findneg(token[s->keyasked]);
324
				if(p == nil){
325
					s->keyasked++;
326
					continue;
327
				}
328
				dom = getdom(token[s->keyasked]);
329
				mkkeyinfo(&ki, fss, nil);
330
				ki.attr = anew;
331
				ret = findkey(&k, &ki,
332
					"proto=%q dom=%q role=client %s",
333
					p->name, dom, p->keyprompt);
334
				s->keyasked++;
335
				if(ret == RpcNeedkey){
336
					asking = 1;
337
					break;
338
				}
339
			}
340
		}
341
		if(k == nil){
342
			free(a);
343
			_freeattr(anew);
344
			if(asking)
345
				return RpcNeedkey;
346
			else if(s->keyasked)
347
				return failure(fss, nil);
348
			else
349
				return failure(fss, Enegotiation);
350
		}
351
		s->subdom = s_copy(dom);
352
		s->subproto = p;
353
		free(a);
354
		_freeattr(anew);
355
		setupfss(fss, s, k);
356
		closekey(k);
357
		ret = (*s->subproto->init)(p, &s->subfss);
358
		rpcstartlog(s->subfss.attr, &s->subfss, ret);
359
		if(ret == RpcOk)
360
			fss->phase = CHaveProto;
361
		return passret(fss, s, ret);
362
 
363
	case SNeedProto:
364
		if(n==0 || a[n-1] != '\0')
365
			return toosmall(fss, n+1);
366
		a = estrdup(a);
367
		m = tokenize(a, token, nelem(token));
368
		if(m != 2){
369
			free(a);
370
			return failure(fss, Ebadarg);
371
		}
372
		p = findneg(token[0]);
373
		if(p == nil){
374
			free(a);
375
			return failure(fss, Enegotiation);
376
		}
377
		attr = _delattr(_copyattr(fss->attr), "proto");
378
		mkkeyinfo(&ki, fss, nil);
379
		ki.attr = attr;
380
		ki.user = nil;
381
		ret = findkey(&k, &ki, "proto=%q dom=%q role=server", token[0], token[1]);
382
		free(a);
383
		_freeattr(attr);
384
		if(ret == RpcConfirm)
385
			return ret;
386
		if(ret != RpcOk)
387
			return failure(fss, Enegotiation);
388
		s->subproto = p;
389
		setupfss(fss, s, k);
390
		closekey(k);
391
		ret = (*s->subproto->init)(p, &s->subfss);
392
		if(ret == RpcOk){
393
			if(s->version == 1)
394
				fss->phase = SRelay;
395
			else
396
				fss->phase = SHaveOK;
397
		}
398
		return passret(fss, s, ret);
399
 
400
	case CNeedOK:
401
		if(n < 3)
402
			return toosmall(fss, 3);
403
		if(strcmp("OK", a) != 0)
404
			return failure(fss, "server gave up");
405
		fss->phase = CRelay;
406
		return RpcOk;
407
 
408
	case CRelay:
409
	case SRelay:
410
		ophase = s->subfss.phase;
411
		ret = (*s->subproto->write)(&s->subfss, va, n);
412
		rpcrdwrlog(&s->subfss, "write", n, ophase, ret);
413
		return passret(fss, s, ret);
414
	}
415
}
416
 
417
Proto p9any = 
418
{
419
.name=	"p9any",
420
.init=		p9anyinit,
421
.write=	p9anywrite,
422
.read=	p9anyread,
423
.close=	p9anyclose,
424
};