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 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 = "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 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 */ 731