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 	{ 0 }
59 };
60 AuthMethod *am = authmethod;	/* default is p9 */
61 
62 char *p9authproto = "p9any";
63 
64 int setam(char*);
65 
66 void
exits(char * s)67 exits(char *s)
68 {
69 	print("\ngoodbye\n");
70 	for(;;) osyield();
71 }
72 
73 void
usage(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
mountfactotum(void)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
cpumain(int argc,char ** argv)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 = "auth";
120 	system = getenv("cpu");
121 	if(system == nil)
122 		system = "cpu";
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
fatal(int syserr,char * fmt,...)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*
rexcall(int * fd,char * host,char * service)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
writestr(int fd,char * str,char * thing,int ignore)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
readstr(int fd,char * str,int len)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
readln(char * buf,int n)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
netkeyauth(int fd)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
netkeysrvauth(int fd,char * user)353 netkeysrvauth(int fd, char *user)
354 {
355 	return -1;
356 }
357 
358 static void
mksecret(char * t,uchar * f)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
p9auth(int fd)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
authdial(char * net,char * dom)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
getastickets(Ticketreq * tr,char * trbuf,char * tbuf)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
mkserverticket(Ticketreq * tr,char * authkey,char * tbuf)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
gettickets(Ticketreq * tr,char * key,char * trbuf,char * tbuf)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*
promptforkey(char * params)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
sendkey(Attr * attr)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
askuser(char * params)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*
p9anyfactotum(int fd,int afd)543 p9anyfactotum(int fd, int afd)
544 {
545 	return auth_proxy(fd, askuser, "proto=p9any role=client %s", keyspec);
546 }
547 
548 AuthInfo*
p9any(int fd)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 	werrstr("");
564 
565 	if(readstr(fd, buf, sizeof buf) < 0)
566 		fatal(1, "cannot read p9any negotiation");
567 	bbuf = buf;
568 	v2 = 0;
569 	if(strncmp(buf, "v.2 ", 4) == 0){
570 		v2 = 1;
571 		bbuf += 4;
572 	}
573 	if((p = strchr(bbuf, ' ')))
574 		*p = 0;
575 	p = bbuf;
576 	if((dom = strchr(p, '@')) == nil)
577 		fatal(1, "bad p9any domain");
578 	*dom++ = 0;
579 	if(strcmp(p, "p9sk1") != 0)
580 		fatal(1, "server did not offer p9sk1");
581 
582 	sprint(buf2, "%s %s", p, dom);
583 	if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
584 		fatal(1, "cannot write user/domain choice in p9any");
585 	if(v2){
586 		if(readstr(fd, buf, sizeof buf) < 0)
587 			fatal(1, "cannot read OK in p9any: got %d %s", n, buf);
588 		if(memcmp(buf, "OK\0", 3) != 0)
589 			fatal(1, "did not get OK in p9any");
590 	}
591 	for(i=0; i<CHALLEN; i++)
592 		cchal[i] = fastrand();
593 	if(write(fd, cchal, 8) != 8)
594 		fatal(1, "cannot write p9sk1 challenge");
595 
596 	if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN)
597 		fatal(1, "cannot read ticket request in p9sk1");
598 
599 
600 	convM2TR(trbuf, &tr);
601 	u = user;
602 	pass = findkey(&u, tr.authdom);
603 	if(pass == nil)
604 	again:
605 		pass = getkey(u, tr.authdom);
606 	if(pass == nil)
607 		fatal(1, "no password");
608 
609 	passtokey(authkey, pass);
610 	memset(pass, 0, strlen(pass));
611 
612 	tr.type = AuthTreq;
613 	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u);
614 	strecpy(tr.uid, tr.uid+sizeof tr.uid, u);
615 	convTR2M(&tr, trbuf);
616 
617 	if(gettickets(&tr, authkey, trbuf, tbuf) < 0)
618 		fatal(1, "cannot get auth tickets in p9sk1");
619 
620 	convM2T(tbuf, &t, authkey);
621 	if(t.num != AuthTc){
622 		print("?password mismatch with auth server\n");
623 		goto again;
624 	}
625 	memmove(tbuf, tbuf+TICKETLEN, TICKETLEN);
626 
627 	auth.num = AuthAc;
628 	memmove(auth.chal, tr.chal, CHALLEN);
629 	auth.id = 0;
630 	convA2M(&auth, tbuf+TICKETLEN, t.key);
631 
632 	if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
633 		fatal(1, "cannot send ticket and authenticator back in p9sk1");
634 
635 	if((n=readn(fd, tbuf, AUTHENTLEN)) != AUTHENTLEN ||
636 			memcmp(tbuf, "cpu:", 4) == 0){
637 		if(n <= 4)
638 			fatal(1, "cannot read authenticator in p9sk1");
639 
640 		/*
641 		 * didn't send back authenticator:
642 		 * sent back fatal error message.
643 		 */
644 		memmove(buf, tbuf, n);
645 		i = readn(fd, buf+n, sizeof buf-n-1);
646 		if(i > 0)
647 			n += i;
648 		buf[n] = 0;
649 		werrstr("");
650 		fatal(0, "server says: %s", buf);
651 	}
652 
653 	convM2A(tbuf, &auth, t.key);
654 	if(auth.num != AuthAs
655 	|| memcmp(auth.chal, cchal, CHALLEN) != 0
656 	|| auth.id != 0){
657 		print("?you and auth server agree about password.\n");
658 		print("?server is confused.\n");
659 		fatal(0, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0);
660 	}
661 	//print("i am %s there.\n", t.suid);
662 	ai = mallocz(sizeof(AuthInfo), 1);
663 	ai->secret = mallocz(8, 1);
664 	des56to64((uchar*)t.key, ai->secret);
665 	ai->nsecret = 8;
666 	ai->suid = strdup(t.suid);
667 	ai->cuid = strdup(t.cuid);
668 	memset(authkey, 0, sizeof authkey);
669 	return ai;
670 }
671 
672 /*
673 static int
674 noauth(int fd)
675 {
676 	ealgs = nil;
677 	return fd;
678 }
679 
680 static int
681 srvnoauth(int fd, char *user)
682 {
683 	strecpy(user, user+MaxStr, getuser());
684 	ealgs = nil;
685 	return fd;
686 }
687 */
688 
689 void
loghex(uchar * p,int n)690 loghex(uchar *p, int n)
691 {
692 	char buf[100];
693 	int i;
694 
695 	for(i = 0; i < n; i++)
696 		sprint(buf+2*i, "%2.2ux", p[i]);
697 //	syslog(0, "cpu", buf);
698 }
699 
700 static int
srvp9auth(int fd,char * user)701 srvp9auth(int fd, char *user)
702 {
703 	return -1;
704 }
705 
706 /*
707  *  set authentication mechanism
708  */
709 int
setam(char * name)710 setam(char *name)
711 {
712 	for(am = authmethod; am->name != nil; am++)
713 		if(strcmp(am->name, name) == 0)
714 			return 0;
715 	am = authmethod;
716 	return -1;
717 }
718 
719 /*
720  *  set authentication mechanism and encryption/hash algs
721  *
722 int
723 setamalg(char *s)
724 {
725 	ealgs = strchr(s, ' ');
726 	if(ealgs != nil)
727 		*ealgs++ = 0;
728 	return setam(s);
729 }
730 
731 */
732