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