Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/unix/u9fs/authp9any.c – Rev 67

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
3
 * Nigel Roles (nigel@9fs.org) 2003
4
 */
5
 
6
#include <plan9.h>
7
#include <fcall.h>
8
#include <u9fs.h>
9
#include <stdlib.h>	/* for random stuff */
10
 
11
typedef struct	Ticket		Ticket;
12
typedef struct	Ticketreq	Ticketreq;
13
typedef struct	Authenticator	Authenticator;
14
 
15
enum
16
{
17
	DOMLEN=		48,		/* length of an authentication domain name */
18
	CHALLEN=	8		/* length of a challenge */
19
};
20
 
21
enum {
22
	HaveProtos,
23
	NeedProto,
24
	NeedChal,
25
	HaveTreq,
26
	NeedTicket,
27
	HaveAuth,
28
	Established,
29
};
30
 
31
/* encryption numberings (anti-replay) */
32
enum
33
{
34
	AuthTreq=1,	/* ticket request */
35
	AuthChal=2,	/* challenge box request */
36
	AuthPass=3,	/* change password */
37
	AuthOK=4,	/* fixed length reply follows */
38
	AuthErr=5,	/* error follows */
39
	AuthMod=6,	/* modify user */
40
	AuthApop=7,	/* apop authentication for pop3 */
41
	AuthOKvar=9,	/* variable length reply follows */
42
	AuthChap=10,	/* chap authentication for ppp */
43
	AuthMSchap=11,	/* MS chap authentication for ppp */
44
	AuthCram=12,	/* CRAM verification for IMAP (RFC2195 & rfc2104) */
45
	AuthHttp=13,	/* http domain login */
46
	AuthVNC=14,	/* http domain login */
47
 
48
 
49
	AuthTs=64,	/* ticket encrypted with server's key */
50
	AuthTc,		/* ticket encrypted with client's key */
51
	AuthAs,		/* server generated authenticator */
52
	AuthAc,		/* client generated authenticator */
53
	AuthTp,		/* ticket encrypted with client's key for password change */
54
	AuthHr		/* http reply */
55
};
56
 
57
struct Ticketreq
58
{
59
	char	type;
60
	char	authid[NAMELEN];	/* server's encryption id */
61
	char	authdom[DOMLEN];	/* server's authentication domain */
62
	char	chal[CHALLEN];		/* challenge from server */
63
	char	hostid[NAMELEN];	/* host's encryption id */
64
	char	uid[NAMELEN];		/* uid of requesting user on host */
65
};
66
#define	TICKREQLEN	(3*NAMELEN+CHALLEN+DOMLEN+1)
67
 
68
struct Ticket
69
{
70
	char	num;			/* replay protection */
71
	char	chal[CHALLEN];		/* server challenge */
72
	char	cuid[NAMELEN];		/* uid on client */
73
	char	suid[NAMELEN];		/* uid on server */
74
	char	key[DESKEYLEN];		/* nonce DES key */
75
};
76
#define	TICKETLEN	(CHALLEN+2*NAMELEN+DESKEYLEN+1)
77
 
78
struct Authenticator
79
{
80
	char	num;			/* replay protection */
81
	char	chal[CHALLEN];
82
	ulong	id;			/* authenticator id, ++'d with each auth */
83
};
84
#define	AUTHENTLEN	(CHALLEN+4+1)
85
 
86
extern int chatty9p;
87
 
88
static	int	convT2M(Ticket*, char*, char*);
89
static	void	convM2T(char*, Ticket*, char*);
90
static	void	convM2Tnoenc(char*, Ticket*);
91
static	int	convA2M(Authenticator*, char*, char*);
92
static	void	convM2A(char*, Authenticator*, char*);
93
static	int	convTR2M(Ticketreq*, char*);
94
static	void	convM2TR(char*, Ticketreq*);
95
static	int	passtokey(char*, char*);
96
 
97
/*
98
 * destructively encrypt the buffer, which
99
 * must be at least 8 characters long.
100
 */
101
static int
102
encrypt9p(void *key, void *vbuf, int n)
103
{
104
	char ekey[128], *buf;
105
	int i, r;
106
 
107
	if(n < 8)
108
		return 0;
109
	key_setup(key, ekey);
110
	buf = vbuf;
111
	n--;
112
	r = n % 7;
113
	n /= 7;
114
	for(i = 0; i < n; i++){
115
		block_cipher(ekey, buf, 0);
116
		buf += 7;
117
	}
118
	if(r)
119
		block_cipher(ekey, buf - 7 + r, 0);
120
	return 1;
121
}
122
 
123
/*
124
 * destructively decrypt the buffer, which
125
 * must be at least 8 characters long.
126
 */
127
static int
128
decrypt9p(void *key, void *vbuf, int n)
129
{
130
	char ekey[128], *buf;
131
	int i, r;
132
 
133
	if(n < 8)
134
		return 0;
135
	key_setup(key, ekey);
136
	buf = vbuf;
137
	n--;
138
	r = n % 7;
139
	n /= 7;
140
	buf += n * 7;
141
	if(r)
142
		block_cipher(ekey, buf - 7 + r, 1);
143
	for(i = 0; i < n; i++){
144
		buf -= 7;
145
		block_cipher(ekey, buf, 1);
146
	}
147
	return 1;
148
}
149
 
150
#define	CHAR(x)		*p++ = f->x
151
#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
152
#define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
153
#define	LONG(x)		VLONG(f->x)
154
#define	STRING(x,n)	memmove(p, f->x, n); p += n
155
 
156
static int
157
convTR2M(Ticketreq *f, char *ap)
158
{
159
	int n;
160
	uchar *p;
161
 
162
	p = (uchar*)ap;
163
	CHAR(type);
164
	STRING(authid, NAMELEN);
165
	STRING(authdom, DOMLEN);
166
	STRING(chal, CHALLEN);
167
	STRING(hostid, NAMELEN);
168
	STRING(uid, NAMELEN);
169
	n = p - (uchar*)ap;
170
	return n;
171
}
172
 
173
static int
174
convT2M(Ticket *f, char *ap, char *key)
175
{
176
	int n;
177
	uchar *p;
178
 
179
	p = (uchar*)ap;
180
	CHAR(num);
181
	STRING(chal, CHALLEN);
182
	STRING(cuid, NAMELEN);
183
	STRING(suid, NAMELEN);
184
	STRING(key, DESKEYLEN);
185
	n = p - (uchar*)ap;
186
	if(key)
187
		encrypt9p(key, ap, n);
188
	return n;
189
}
190
 
191
int
192
convA2M(Authenticator *f, char *ap, char *key)
193
{
194
	int n;
195
	uchar *p;
196
 
197
	p = (uchar*)ap;
198
	CHAR(num);
199
	STRING(chal, CHALLEN);
200
	LONG(id);
201
	n = p - (uchar*)ap;
202
	if(key)
203
		encrypt9p(key, ap, n);
204
	return n;
205
}
206
 
207
#undef CHAR
208
#undef SHORT
209
#undef VLONG
210
#undef LONG
211
#undef STRING
212
 
213
#define	CHAR(x)		f->x = *p++
214
#define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
215
#define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
216
#define	LONG(x)		VLONG(f->x)
217
#define	STRING(x,n)	memmove(f->x, p, n); p += n
218
 
219
void
220
convM2A(char *ap, Authenticator *f, char *key)
221
{
222
	uchar *p;
223
 
224
	if(key)
225
		decrypt9p(key, ap, AUTHENTLEN);
226
	p = (uchar*)ap;
227
	CHAR(num);
228
	STRING(chal, CHALLEN);
229
	LONG(id);
230
	USED(p);
231
}
232
 
233
void
234
convM2T(char *ap, Ticket *f, char *key)
235
{
236
	uchar *p;
237
 
238
	if(key)
239
		decrypt9p(key, ap, TICKETLEN);
240
	p = (uchar*)ap;
241
	CHAR(num);
242
	STRING(chal, CHALLEN);
243
	STRING(cuid, NAMELEN);
244
	f->cuid[NAMELEN-1] = 0;
245
	STRING(suid, NAMELEN);
246
	f->suid[NAMELEN-1] = 0;
247
	STRING(key, DESKEYLEN);
248
	USED(p);
249
}
250
 
251
#undef CHAR
252
#undef SHORT
253
#undef LONG
254
#undef VLONG
255
#undef STRING
256
 
257
static int
258
passtokey(char *key, char *p)
259
{
260
	uchar buf[NAMELEN], *t;
261
	int i, n;
262
 
263
	n = strlen(p);
264
	if(n >= NAMELEN)
265
		n = NAMELEN-1;
266
	memset(buf, ' ', 8);
267
	t = buf;
268
	strncpy((char*)t, p, n);
269
	t[n] = 0;
270
	memset(key, 0, DESKEYLEN);
271
	for(;;){
272
		for(i = 0; i < DESKEYLEN; i++)
273
			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
274
		if(n <= 8)
275
			return 1;
276
		n -= 8;
277
		t += 8;
278
		if(n < 8){
279
			t -= 8 - n;
280
			n = 8;
281
		}
282
		encrypt9p(key, t, 8);
283
	}
284
	return 1;	/* not reached */
285
}
286
 
287
static char authkey[DESKEYLEN];
288
static char *authid;
289
static char *authdom;
290
static char *haveprotosmsg;
291
static char *needprotomsg;
292
 
293
static void
294
p9anyinit(void)
295
{
296
	int n, fd;
297
	char abuf[200];
298
	char *af, *f[4];
299
 
300
	af = autharg;
301
	if(af == nil)
302
		af = "/etc/u9fs.key";
303
 
304
	if((fd = open(af, OREAD)) < 0)
305
		sysfatal("can't open key file '%s'", af);
306
 
307
	if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
308
		sysfatal("can't read key file '%s'", af);
309
	if (n > 0 && abuf[n - 1] == '\n')
310
		n--;
311
	abuf[n] = '\0';
312
 
313
	if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
314
		sysfatal("key file '%s' not exactly 3 lines", af);
315
 
316
	passtokey(authkey, f[0]);
317
	authid = strdup(f[1]);
318
	authdom = strdup(f[2]);
319
	haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
320
	sprint(haveprotosmsg, "p9sk1@%s", authdom);
321
	needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
322
	sprint(needprotomsg, "p9sk1 %s", authdom);
323
}
324
 
325
typedef struct AuthSession {
326
	int state;
327
	char *uname;
328
	char *aname;
329
	char cchal[CHALLEN];
330
	Ticketreq tr;
331
	Ticket t;
332
} AuthSession;
333
 
334
static char*
335
p9anyauth(Fcall *rx, Fcall *tx)
336
{
337
	AuthSession *sp;
338
	Fid *f;
339
	char *ep;
340
 
341
	sp = malloc(sizeof(AuthSession));
342
	f = newauthfid(rx->afid, sp, &ep);
343
	if (f == nil) {
344
		free(sp);
345
		return ep;
346
	}
347
	if (chatty9p)
348
		fprint(2, "p9anyauth: afid %d\n", rx->afid);
349
	sp->state = HaveProtos;
350
	sp->uname = strdup(rx->uname);
351
	sp->aname = strdup(rx->aname);
352
	tx->aqid.type = QTAUTH;
353
	tx->aqid.path = 1;
354
	tx->aqid.vers = 0;
355
	return nil;
356
}
357
 
358
static char *
359
p9anyattach(Fcall *rx, Fcall *tx)
360
{
361
	AuthSession *sp;
362
	Fid *f;
363
	char *ep;
364
 
365
	f = oldauthfid(rx->afid, (void **)&sp, &ep);
366
	if (f == nil)
367
		return ep;
368
	if (chatty9p)
369
		fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
370
	if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
371
		&& strcmp(rx->aname, sp->aname) == 0)
372
		return nil;
373
	return "authentication failed";
374
}
375
 
376
static int
377
readstr(Fcall *rx, Fcall *tx, char *s, int len)
378
{
379
	if (rx->offset >= len)
380
		return 0;
381
	tx->count = len - rx->offset;
382
	if (tx->count > rx->count)
383
		tx->count = rx->count;
384
	memcpy(tx->data, s + rx->offset, tx->count);
385
	return tx->count;
386
}
387
 
388
static char *
389
p9anyread(Fcall *rx, Fcall *tx)
390
{
391
	AuthSession *sp;
392
	char *ep;
393
 
394
	Fid *f;
395
	f = oldauthfid(rx->afid, (void **)&sp, &ep);
396
	if (f == nil)
397
		return ep;
398
	if (chatty9p)
399
		fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
400
	switch (sp->state) {
401
	case HaveProtos:
402
		readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
403
		if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
404
			sp->state = NeedProto;
405
		return nil;
406
	case HaveTreq:
407
		if (rx->count != TICKREQLEN)
408
			goto botch;
409
		convTR2M(&sp->tr, tx->data);
410
		tx->count = TICKREQLEN;
411
		sp->state = NeedTicket;
412
		return nil;
413
	case HaveAuth: {
414
		Authenticator a;
415
		if (rx->count != AUTHENTLEN)
416
			goto botch;
417
		a.num = AuthAs;
418
		memmove(a.chal, sp->cchal, CHALLEN);
419
		a.id = 0;
420
		convA2M(&a, (char*)tx->data, sp->t.key);
421
		memset(sp->t.key, 0, sizeof(sp->t.key));
422
		tx->count = rx->count;
423
		sp->state = Established;
424
		return nil;
425
	}
426
	default:
427
	botch:
428
		return "protocol botch";
429
	}
430
}
431
 
432
static char *
433
p9anywrite(Fcall *rx, Fcall *tx)
434
{
435
	AuthSession *sp;
436
	char *ep;
437
 
438
	Fid *f;
439
 
440
	f = oldauthfid(rx->afid, (void **)&sp, &ep);
441
	if (f == nil)
442
		return ep;
443
	if (chatty9p)
444
		fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
445
	switch (sp->state) {
446
	case NeedProto:
447
		if (rx->count != strlen(needprotomsg) + 1)
448
			return "protocol response wrong length";
449
		if (memcmp(rx->data, needprotomsg, rx->count) != 0)
450
			return "unacceptable protocol";
451
		sp->state = NeedChal;
452
		tx->count = rx->count;
453
		return nil;
454
	case NeedChal:
455
		if (rx->count != CHALLEN)
456
			goto botch;
457
		memmove(sp->cchal, rx->data, CHALLEN);
458
		sp->tr.type = AuthTreq;
459
		safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
460
		safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
461
		randombytes((uchar *)sp->tr.chal, CHALLEN);
462
		safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
463
		safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
464
		tx->count = rx->count;
465
		sp->state = HaveTreq;
466
		return nil;
467
	case NeedTicket: {
468
		Authenticator a;
469
 
470
		if (rx->count != TICKETLEN + AUTHENTLEN) {
471
			fprint(2, "bad length in attach");
472
			goto botch;
473
		}
474
		convM2T((char*)rx->data, &sp->t, authkey);
475
		if (sp->t.num != AuthTs) {
476
			fprint(2, "bad AuthTs in attach\n");
477
			goto botch;
478
		}
479
		if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
480
			fprint(2, "bad challenge in attach\n");
481
			goto botch;
482
		}
483
		convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
484
		if (a.num != AuthAc) {
485
			fprint(2, "bad AuthAs in attach\n");
486
			goto botch;
487
		}
488
		if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
489
			fprint(2, "bad challenge in attach 2\n");
490
			goto botch;
491
		}
492
		sp->state = HaveAuth;
493
		tx->count = rx->count;
494
		return nil;
495
	}
496
	default:
497
	botch:
498
		return "protocol botch";
499
	}
500
}
501
 
502
static void
503
safefree(char *p)
504
{
505
	if (p) {
506
		memset(p, 0, strlen(p));
507
		free(p);
508
	}
509
}
510
 
511
static char *
512
p9anyclunk(Fcall *rx, Fcall *tx)
513
{
514
	Fid *f;
515
	AuthSession *sp;
516
	char *ep;
517
 
518
	f = oldauthfid(rx->afid, (void **)&sp, &ep);
519
	if (f == nil)
520
		return ep;
521
	if (chatty9p)
522
		fprint(2, "p9anyclunk: afid %d\n", rx->fid);
523
	safefree(sp->uname);
524
	safefree(sp->aname);
67 7u83 525
	memset(sp, 0, sizeof(AuthSession));
2 - 526
	free(sp);
527
	return nil;
528
}
529
 
530
Auth authp9any = {
531
	"p9any",
532
	p9anyauth,
533
	p9anyattach,
534
	p9anyinit,
535
	p9anyread,
536
	p9anywrite,
537
	p9anyclunk,
538
};