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