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