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_posix/sys/src/cmd/unix/drawterm/cpu-bl.c – Rev 2

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
 * cpu.c - Make a connection to a cpu server
3
 *
4
 *	   Invoked by listen as 'cpu -R | -N service net netdir'
5
 *	    	   by users  as 'cpu [-h system] [-c cmd args ...]'
6
 */
7
 
8
#include <u.h>
9
#include <libc.h>
10
#include <auth.h>
11
#include <fcall.h>
12
#include <authsrv.h>
13
#include <libsec.h>
14
#include "args.h"
15
#include "drawterm.h"
16
 
17
#define Maxfdata 8192
18
#define MaxStr 128
19
 
20
static void	fatal(int, char*, ...);
21
static void	usage(void);
22
static void	writestr(int, char*, char*, int);
23
static int	readstr(int, char*, int);
24
static char	*rexcall(int*, char*, char*);
25
static char *keyspec = "";
26
static AuthInfo *p9any(int);
27
 
28
#define system csystem
29
static char	*system;
30
static int	cflag;
31
extern int	dbg;
32
extern char*	base;	// fs base for devroot
33
 
34
static char	*srvname = "ncpu";
35
static char	*ealgs = "rc4_256 sha1";
36
 
37
/* message size for exportfs; may be larger so we can do big graphics in CPU window */
38
static int	msgsize = Maxfdata+IOHDRSZ;
39
 
40
/* authentication mechanisms */
41
static int	netkeyauth(int);
42
static int	netkeysrvauth(int, char*);
43
static int	p9auth(int);
44
static int	srvp9auth(int, char*);
45
 
46
char *authserver;
47
 
48
typedef struct AuthMethod AuthMethod;
49
struct AuthMethod {
50
	char	*name;			/* name of method */
51
	int	(*cf)(int);		/* client side authentication */
52
	int	(*sf)(int, char*);	/* server side authentication */
53
} authmethod[] =
54
{
55
	{ "p9",		p9auth,		srvp9auth,},
56
	{ "netkey",	netkeyauth,	netkeysrvauth,},
57
//	{ "none",	noauth,		srvnoauth,},
58
	{ nil,	nil}
59
};
60
AuthMethod *am = authmethod;	/* default is p9 */
61
 
62
char *p9authproto = "p9any";
63
 
64
int setam(char*);
65
 
66
void
67
exits(char *s)
68
{
69
	print("\ngoodbye\n");
70
	for(;;) osyield();
71
}
72
 
73
void
74
usage(void)
75
{
76
	fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");
77
	exits("usage");
78
}
79
int fdd;
80
 
81
int
82
mountfactotum(void)
83
{
84
	int fd;
85
 
86
	if((fd = dialfactotum()) < 0)
87
		return -1;
88
	if(sysmount(fd, -1, "/mnt/factotum", MREPL, "") < 0){
89
		fprint(2, "mount factotum: %r\n");
90
		return -1;
91
	}
92
	if((fd = open("/mnt/factotum/ctl", OREAD)) < 0){
93
		fprint(2, "open /mnt/factotum/ctl: %r\n");
94
		return -1;
95
	}
96
	close(fd);
97
	return 0;
98
}
99
 
100
void
101
cpumain(int argc, char **argv)
102
{
103
	char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *err, *secstoreserver, *p, *s;
104
	int fd, ms, data;
105
 
106
	/* see if we should use a larger message size */
107
	fd = open("/dev/draw", OREAD);
108
	if(fd > 0){
109
		ms = iounit(fd);
110
		if(msgsize < ms+IOHDRSZ)
111
			msgsize = ms+IOHDRSZ;
112
		close(fd);
113
	}
114
 
115
	user = getenv("USER");
116
	secstoreserver = nil;
117
	authserver = getenv("auth");
118
	if(authserver == nil)
119
		authserver = "p9auth.cs.bell-labs.com";
120
	system = getenv("cpu");
121
	if(system == nil)
122
		system = "plan9.bell-labs.com";
123
	ARGBEGIN{
124
	case 'a':
125
		authserver = EARGF(usage());
126
		break;
127
	case 'c':
128
		system = EARGF(usage());
129
		break;
130
	case 'd':
131
		dbg++;
132
		break;
133
	case 'e':
134
		ealgs = EARGF(usage());
135
		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
136
			ealgs = nil;
137
		break;
138
	case 'C':
139
		cflag++;
140
		cmd[0] = '!';
141
		cmd[1] = '\0';
142
		while((p = ARGF()) != nil) {
143
			strcat(cmd, " ");
144
			strcat(cmd, p);
145
		}
146
		break;
147
	case 'k':
148
		keyspec = EARGF(usage());
149
		break;
150
	case 'r':
151
		base = EARGF(usage());
152
		break;
153
	case 's':
154
		secstoreserver = EARGF(usage());
155
		break;
156
	case 'u':
157
		user = EARGF(usage());
158
		break;
159
	default:
160
		usage();
161
	}ARGEND;
162
 
163
	if(argc != 0)
164
		usage();
165
 
166
	if(user == nil)
167
		user = readcons("user", nil, 0);
168
 
169
	if(mountfactotum() < 0){
170
		if(secstoreserver == nil)
171
			secstoreserver = authserver;
172
	        if(havesecstore(secstoreserver, user)){
173
	                s = secstorefetch(secstoreserver, user, nil);
174
	                if(s){
175
	                        if(strlen(s) >= sizeof secstorebuf)
176
	                                sysfatal("secstore data too big");
177
	                        strcpy(secstorebuf, s);
178
	                }
179
	        }
180
	}
181
 
182
	if((err = rexcall(&data, system, srvname)))
183
		fatal(1, "%s: %s", err, system);
184
 
185
	/* Tell the remote side the command to execute and where our working directory is */
186
	if(cflag)
187
		writestr(data, cmd, "command", 0);
188
	if(getcwd(dat, sizeof(dat)) == 0)
189
		writestr(data, "NO", "dir", 0);
190
	else
191
		writestr(data, dat, "dir", 0);
192
 
193
	/* 
194
	 *  Wait for the other end to execute and start our file service
195
	 *  of /mnt/term
196
	 */
197
	if(readstr(data, buf, sizeof(buf)) < 0)
198
		fatal(1, "waiting for FS: %r");
199
	if(strncmp("FS", buf, 2) != 0) {
200
		print("remote cpu: %s", buf);
201
		exits(buf);
202
	}
203
 
204
	if(readstr(data, buf, sizeof buf) < 0)
205
		fatal(1, "waiting for remote export: %r");
206
	if(strcmp(buf, "/") != 0){
207
		print("remote cpu: %s" , buf);
208
		exits(buf);
209
	}
210
	write(data, "OK", 2);
211
 
212
	/* Begin serving the gnot namespace */
213
	exportfs(data, msgsize);
214
	fatal(1, "starting exportfs");
215
}
216
 
217
void
218
fatal(int syserr, char *fmt, ...)
219
{
220
	Fmt f;
221
	char *str;
222
	va_list arg;
223
 
224
	fmtstrinit(&f);
225
	fmtprint(&f, "cpu: ");
226
	va_start(arg, fmt);
227
	fmtvprint(&f, fmt, arg);
228
	va_end(arg);
229
	if(syserr)
230
		fmtprint(&f, ": %r");
231
	fmtprint(&f, "\n");
232
	str = fmtstrflush(&f);
233
	write(2, str, strlen(str));
234
	exits(str);
235
}
236
 
237
char *negstr = "negotiating authentication method";
238
 
239
char bug[256];
240
 
241
char*
242
rexcall(int *fd, char *host, char *service)
243
{
244
	char *na;
245
	char dir[MaxStr];
246
	char err[ERRMAX];
247
	char msg[MaxStr];
248
	int n;
249
 
250
	na = netmkaddr(host, "tcp", "17010");
251
	if((*fd = dial(na, 0, dir, 0)) < 0)
252
		return "can't dial";
253
 
254
	/* negotiate authentication mechanism */
255
	if(ealgs != nil)
256
		snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
257
	else
258
		snprint(msg, sizeof(msg), "%s", am->name);
259
	writestr(*fd, msg, negstr, 0);
260
	n = readstr(*fd, err, sizeof err);
261
	if(n < 0)
262
		return negstr;
263
	if(*err){
264
		werrstr(err);
265
		return negstr;
266
	}
267
 
268
	/* authenticate */
269
	*fd = (*am->cf)(*fd);
270
	if(*fd < 0)
271
		return "can't authenticate";
272
	return 0;
273
}
274
 
275
void
276
writestr(int fd, char *str, char *thing, int ignore)
277
{
278
	int l, n;
279
 
280
	l = strlen(str);
281
	n = write(fd, str, l+1);
282
	if(!ignore && n < 0)
283
		fatal(1, "writing network: %s", thing);
284
}
285
 
286
int
287
readstr(int fd, char *str, int len)
288
{
289
	int n;
290
 
291
	while(len) {
292
		n = read(fd, str, 1);
293
		if(n < 0) 
294
			return -1;
295
		if(*str == '\0')
296
			return 0;
297
		str++;
298
		len--;
299
	}
300
	return -1;
301
}
302
 
303
static int
304
readln(char *buf, int n)
305
{
306
	int i;
307
	char *p;
308
 
309
	n--;	/* room for \0 */
310
	p = buf;
311
	for(i=0; i<n; i++){
312
		if(read(0, p, 1) != 1)
313
			break;
314
		if(*p == '\n' || *p == '\r')
315
			break;
316
		p++;
317
	}
318
	*p = '\0';
319
	return p-buf;
320
}
321
 
322
/*
323
 *  user level challenge/response
324
 */
325
static int
326
netkeyauth(int fd)
327
{
328
	char chall[32];
329
	char resp[32];
330
 
331
	strecpy(chall, chall+sizeof chall, getuser());
332
	print("user[%s]: ", chall);
333
	if(readln(resp, sizeof(resp)) < 0)
334
		return -1;
335
	if(*resp != 0)
336
		strcpy(chall, resp);
337
	writestr(fd, chall, "challenge/response", 1);
338
 
339
	for(;;){
340
		if(readstr(fd, chall, sizeof chall) < 0)
341
			break;
342
		if(*chall == 0)
343
			return fd;
344
		print("challenge: %s\nresponse: ", chall);
345
		if(readln(resp, sizeof(resp)) < 0)
346
			break;
347
		writestr(fd, resp, "challenge/response", 1);
348
	}
349
	return -1;
350
}
351
 
352
static int
353
netkeysrvauth(int fd, char *user)
354
{
355
	return -1;
356
}
357
 
358
static void
359
mksecret(char *t, uchar *f)
360
{
361
	sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
362
		f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
363
}
364
 
365
/*
366
 *  plan9 authentication followed by rc4 encryption
367
 */
368
static int
369
p9auth(int fd)
370
{
371
	uchar key[16];
372
	uchar digest[SHA1dlen];
373
	char fromclientsecret[21];
374
	char fromserversecret[21];
375
	int i;
376
	AuthInfo *ai;
377
 
378
	ai = p9any(fd);
379
	if(ai == nil)
380
		return -1;
381
	memmove(key+4, ai->secret, ai->nsecret);
382
	if(ealgs == nil)
383
		return fd;
384
 
385
	/* exchange random numbers */
386
	for(i = 0; i < 4; i++)
387
		key[i] = fastrand();
388
	if(write(fd, key, 4) != 4)
389
		return -1;
390
	if(readn(fd, key+12, 4) != 4)
391
		return -1;
392
 
393
	/* scramble into two secrets */
394
	sha1(key, sizeof(key), digest, nil);
395
	mksecret(fromclientsecret, digest);
396
	mksecret(fromserversecret, digest+10);
397
 
398
	/* set up encryption */
399
	i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
400
	if(i < 0)
401
		werrstr("can't establish ssl connection: %r");
402
	return i;
403
}
404
 
405
int
406
authdial(char *net, char *dom)
407
{
408
	int fd;
409
	fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0);
410
	//print("authdial %d\n", fd);
411
	return fd;
412
}
413
 
414
static int
415
getastickets(Ticketreq *tr, char *trbuf, char *tbuf)
416
{
417
	int asfd, rv;
418
	char *dom;
419
 
420
	dom = tr->authdom;
421
	asfd = authdial(nil, dom);
422
	if(asfd < 0)
423
		return -1;
424
	rv = _asgetticket(asfd, trbuf, tbuf);
425
	close(asfd);
426
	return rv;
427
}
428
 
429
static int
430
mkserverticket(Ticketreq *tr, char *authkey, char *tbuf)
431
{
432
	int i;
433
	Ticket t;
434
 
435
	if(strcmp(tr->authid, tr->hostid) != 0)
436
		return -1;
437
	memset(&t, 0, sizeof(t));
438
	memmove(t.chal, tr->chal, CHALLEN);
439
	strcpy(t.cuid, tr->uid);
440
	strcpy(t.suid, tr->uid);
441
	for(i=0; i<DESKEYLEN; i++)
442
		t.key[i] = fastrand();
443
	t.num = AuthTc;
444
	convT2M(&t, tbuf, authkey);
445
	t.num = AuthTs;
446
	convT2M(&t, tbuf+TICKETLEN, authkey);
447
	return 0;
448
}
449
 
450
static int
451
gettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf)
452
{
453
	if(getastickets(tr, trbuf, tbuf) >= 0)
454
		return 0;
455
	return mkserverticket(tr, key, tbuf);
456
}
457
 
458
/*
459
 *  prompt user for a key.  don't care about memory leaks, runs standalone
460
 */
461
static Attr*
462
promptforkey(char *params)
463
{
464
	char *v;
465
	int fd;
466
	Attr *a, *attr;
467
	char *def;
468
 
469
	fd = open("/dev/cons", ORDWR);
470
	if(fd < 0)
471
		sysfatal("opening /dev/cons: %r");
472
 
473
	attr = _parseattr(params);
474
	fprint(fd, "\n!Adding key:");
475
	for(a=attr; a; a=a->next)
476
		if(a->type != AttrQuery && a->name[0] != '!')
477
			fprint(fd, " %q=%q", a->name, a->val);
478
	fprint(fd, "\n");
479
 
480
	for(a=attr; a; a=a->next){
481
		v = a->name;
482
		if(a->type != AttrQuery || v[0]=='!')
483
			continue;
484
		def = nil;
485
		if(strcmp(v, "user") == 0)
486
			def = getuser();
487
		a->val = readcons(v, def, 0);
488
		if(a->val == nil)
489
			sysfatal("user terminated key input");
490
		a->type = AttrNameval;
491
	}
492
	for(a=attr; a; a=a->next){
493
		v = a->name;
494
		if(a->type != AttrQuery || v[0]!='!')
495
			continue;
496
		def = nil;
497
		if(strcmp(v+1, "user") == 0)
498
			def = getuser();
499
		a->val = readcons(v+1, def, 1);
500
		if(a->val == nil)
501
			sysfatal("user terminated key input");
502
		a->type = AttrNameval;
503
	}
504
	fprint(fd, "!\n");
505
	close(fd);
506
	return attr;
507
}
508
 
509
/*
510
 *  send a key to the mounted factotum
511
 */
512
static int
513
sendkey(Attr *attr)
514
{
515
	int fd, rv;
516
	char buf[1024];
517
 
518
	fd = open("/mnt/factotum/ctl", ORDWR);
519
	if(fd < 0)
520
		sysfatal("opening /mnt/factotum/ctl: %r");
521
	rv = fprint(fd, "key %A\n", attr);
522
	read(fd, buf, sizeof buf);
523
	close(fd);
524
	return rv;
525
}
526
 
527
int
528
askuser(char *params)
529
{
530
	Attr *attr;
531
 
532
	fmtinstall('A', _attrfmt);
533
 
534
	attr = promptforkey(params);
535
	if(attr == nil)
536
		sysfatal("no key supplied");
537
	if(sendkey(attr) < 0)
538
		sysfatal("sending key to factotum: %r");
539
	return 0;
540
}
541
 
542
AuthInfo*
543
p9anyfactotum(int fd, int afd)
544
{
545
	return auth_proxy(fd, askuser, "proto=p9any role=client %s", keyspec);
546
}
547
 
548
AuthInfo*
549
p9any(int fd)
550
{
551
	char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u;
552
	char *pass;
553
	char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN];
554
	char authkey[DESKEYLEN];
555
	Authenticator auth;
556
	int afd, i, n, v2;
557
	Ticketreq tr;
558
	Ticket t;
559
	AuthInfo *ai;
560
 
561
	if((afd = open("/mnt/factotum/ctl", ORDWR)) >= 0)
562
		return p9anyfactotum(fd, afd);
563
 
564
	if(readstr(fd, buf, sizeof buf) < 0)
565
		fatal(1, "cannot read p9any negotiation");
566
	bbuf = buf;
567
	v2 = 0;
568
	if(strncmp(buf, "v.2 ", 4) == 0){
569
		v2 = 1;
570
		bbuf += 4;
571
	}
572
	if((p = strchr(bbuf, ' ')))
573
		*p = 0;
574
	p = bbuf;
575
	if((dom = strchr(p, '@')) == nil)
576
		fatal(1, "bad p9any domain");
577
	*dom++ = 0;
578
	if(strcmp(p, "p9sk1") != 0)
579
		fatal(1, "server did not offer p9sk1");
580
 
581
	sprint(buf2, "%s %s", p, dom);
582
	if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
583
		fatal(1, "cannot write user/domain choice in p9any");
584
	if(v2){
585
		if(readstr(fd, buf, sizeof buf) != 3)
586
			fatal(1, "cannot read OK in p9any");
587
		if(memcmp(buf, "OK\0", 3) != 0)
588
			fatal(1, "did not get OK in p9any");
589
	}
590
	for(i=0; i<CHALLEN; i++)
591
		cchal[i] = fastrand();
592
	if(write(fd, cchal, 8) != 8)
593
		fatal(1, "cannot write p9sk1 challenge");
594
 
595
	if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN)
596
		fatal(1, "cannot read ticket request in p9sk1");
597
 
598
 
599
	convM2TR(trbuf, &tr);
600
	u = user;
601
	pass = findkey(&u, tr.authdom);
602
	if(pass == nil)
603
	again:
604
		pass = getkey(u, tr.authdom);
605
	if(pass == nil)
606
		fatal(1, "no password");
607
 
608
	passtokey(authkey, pass);
609
	memset(pass, 0, strlen(pass));
610
 
611
	tr.type = AuthTreq;
612
	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u);
613
	strecpy(tr.uid, tr.uid+sizeof tr.uid, u);
614
	convTR2M(&tr, trbuf);
615
 
616
	if(gettickets(&tr, authkey, trbuf, tbuf) < 0)
617
		fatal(1, "cannot get auth tickets in p9sk1");
618
 
619
	convM2T(tbuf, &t, authkey);
620
	if(t.num != AuthTc){
621
		print("?password mismatch with auth server\n");
622
		goto again;
623
	}
624
	memmove(tbuf, tbuf+TICKETLEN, TICKETLEN);
625
 
626
	auth.num = AuthAc;
627
	memmove(auth.chal, tr.chal, CHALLEN);
628
	auth.id = 0;
629
	convA2M(&auth, tbuf+TICKETLEN, t.key);
630
 
631
	if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
632
		fatal(1, "cannot send ticket and authenticator back in p9sk1");
633
 
634
	if((n=readn(fd, tbuf, AUTHENTLEN)) != AUTHENTLEN ||
635
			memcmp(tbuf, "cpu:", 4) == 0){
636
		if(n <= 4)
637
			fatal(1, "cannot read authenticator in p9sk1");
638
 
639
		/*
640
		 * didn't send back authenticator:
641
		 * sent back fatal error message.
642
		 */
643
		memmove(buf, tbuf, n);
644
		i = readn(fd, buf+n, sizeof buf-n-1);
645
		if(i > 0)
646
			n += i;
647
		buf[n] = 0;
648
		werrstr("");
649
		fatal(0, "server says: %s", buf);
650
	}
651
 
652
	convM2A(tbuf, &auth, t.key);
653
	if(auth.num != AuthAs
654
	|| memcmp(auth.chal, cchal, CHALLEN) != 0
655
	|| auth.id != 0){
656
		print("?you and auth server agree about password.\n");
657
		print("?server is confused.\n");
658
		fatal(0, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0);
659
	}
660
	//print("i am %s there.\n", t.suid);
661
	ai = mallocz(sizeof(AuthInfo), 1);
662
	ai->secret = mallocz(8, 1);
663
	des56to64((uchar*)t.key, ai->secret);
664
	ai->nsecret = 8;
665
	ai->suid = strdup(t.suid);
666
	ai->cuid = strdup(t.cuid);
667
	memset(authkey, 0, sizeof authkey);
668
	return ai;
669
}
670
 
671
/*
672
static int
673
noauth(int fd)
674
{
675
	ealgs = nil;
676
	return fd;
677
}
678
 
679
static int
680
srvnoauth(int fd, char *user)
681
{
682
	strecpy(user, user+MaxStr, getuser());
683
	ealgs = nil;
684
	return fd;
685
}
686
*/
687
 
688
void
689
loghex(uchar *p, int n)
690
{
691
	char buf[100];
692
	int i;
693
 
694
	for(i = 0; i < n; i++)
695
		sprint(buf+2*i, "%2.2ux", p[i]);
696
//	syslog(0, "cpu", buf);
697
}
698
 
699
static int
700
srvp9auth(int fd, char *user)
701
{
702
	return -1;
703
}
704
 
705
/*
706
 *  set authentication mechanism
707
 */
708
int
709
setam(char *name)
710
{
711
	for(am = authmethod; am->name != nil; am++)
712
		if(strcmp(am->name, name) == 0)
713
			return 0;
714
	am = authmethod;
715
	return -1;
716
}
717
 
718
/*
719
 *  set authentication mechanism and encryption/hash algs
720
 *
721
int
722
setamalg(char *s)
723
{
724
	ealgs = strchr(s, ' ');
725
	if(ealgs != nil)
726
		*ealgs++ = 0;
727
	return setam(s);
728
}
729
 
730
*/