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 <bio.h> 11 #include <auth.h> 12 #include <fcall.h> 13 #include <libsec.h> 14 15 #define Maxfdata 8192 16 #define MaxStr 128 17 18 void remoteside(int); 19 void fatal(int, char*, ...); 20 void lclnoteproc(int); 21 void rmtnoteproc(void); 22 void catcher(void*, char*); 23 void usage(void); 24 void writestr(int, char*, char*, int); 25 int readstr(int, char*, int); 26 char *rexcall(int*, char*, char*); 27 int setamalg(char*); 28 char *keyspec = ""; 29 30 int notechan; 31 int exportpid; 32 char *system; 33 int cflag; 34 int dbg; 35 char *user; 36 char *patternfile; 37 38 char *srvname = "ncpu"; 39 char *exportfs = "/bin/exportfs"; 40 char *ealgs = "rc4_256 sha1"; 41 42 /* message size for exportfs; may be larger so we can do big graphics in CPU window */ 43 int msgsize = Maxfdata+IOHDRSZ; 44 45 /* authentication mechanisms */ 46 static int netkeyauth(int); 47 static int netkeysrvauth(int, char*); 48 static int p9auth(int); 49 static int srvp9auth(int, char*); 50 static int noauth(int); 51 static int srvnoauth(int, char*); 52 53 typedef struct AuthMethod AuthMethod; 54 struct AuthMethod { 55 char *name; /* name of method */ 56 int (*cf)(int); /* client side authentication */ 57 int (*sf)(int, char*); /* server side authentication */ 58 } authmethod[] = 59 { 60 { "p9", p9auth, srvp9auth,}, 61 { "netkey", netkeyauth, netkeysrvauth,}, 62 // { "none", noauth, srvnoauth,}, 63 { nil, nil} 64 }; 65 AuthMethod *am = authmethod; /* default is p9 */ 66 67 char *p9authproto = "p9any"; 68 69 int setam(char*); 70 71 void 72 usage(void) 73 { 74 fprint(2, "usage: cpu [-h system] [-u user] [-a authmethod] " 75 "[-e 'crypt hash'] [-k keypattern] [-P patternfile] " 76 "[-c cmd arg ...]\n"); 77 exits("usage"); 78 } 79 80 void 81 main(int argc, char **argv) 82 { 83 char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err; 84 int ac, fd, ms, data; 85 char *av[10]; 86 87 /* see if we should use a larger message size */ 88 fd = open("/dev/draw", OREAD); 89 if(fd > 0){ 90 ms = iounit(fd); 91 if(msgsize < ms+IOHDRSZ) 92 msgsize = ms+IOHDRSZ; 93 close(fd); 94 } 95 96 user = getuser(); 97 if(user == nil) 98 fatal(1, "can't read user name"); 99 ARGBEGIN{ 100 case 'a': 101 p = EARGF(usage()); 102 if(setam(p) < 0) 103 fatal(0, "unknown auth method %s", p); 104 break; 105 case 'e': 106 ealgs = EARGF(usage()); 107 if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) 108 ealgs = nil; 109 break; 110 case 'd': 111 dbg++; 112 break; 113 case 'f': 114 /* ignored but accepted for compatibility */ 115 break; 116 case 'O': 117 p9authproto = "p9sk2"; 118 remoteside(1); /* From listen */ 119 break; 120 case 'R': /* From listen */ 121 remoteside(0); 122 break; 123 case 'h': 124 system = EARGF(usage()); 125 break; 126 case 'c': 127 cflag++; 128 cmd[0] = '!'; 129 cmd[1] = '\0'; 130 while(p = ARGF()) { 131 strcat(cmd, " "); 132 strcat(cmd, p); 133 } 134 break; 135 case 'k': 136 keyspec = smprint("%s %s", keyspec, EARGF(usage())); 137 break; 138 case 'P': 139 patternfile = EARGF(usage()); 140 break; 141 case 'u': 142 user = EARGF(usage()); 143 keyspec = smprint("%s user=%s", keyspec, user); 144 break; 145 default: 146 usage(); 147 }ARGEND; 148 149 150 if(argc != 0) 151 usage(); 152 153 if(system == nil) { 154 p = getenv("cpu"); 155 if(p == 0) 156 fatal(0, "set $cpu"); 157 system = p; 158 } 159 160 if(err = rexcall(&data, system, srvname)) 161 fatal(1, "%s: %s", err, system); 162 163 /* Tell the remote side the command to execute and where our working directory is */ 164 if(cflag) 165 writestr(data, cmd, "command", 0); 166 if(getwd(dat, sizeof(dat)) == 0) 167 writestr(data, "NO", "dir", 0); 168 else 169 writestr(data, dat, "dir", 0); 170 171 /* start up a process to pass along notes */ 172 lclnoteproc(data); 173 174 /* 175 * Wait for the other end to execute and start our file service 176 * of /mnt/term 177 */ 178 if(readstr(data, buf, sizeof(buf)) < 0) 179 fatal(1, "waiting for FS: %r"); 180 if(strncmp("FS", buf, 2) != 0) { 181 print("remote cpu: %s", buf); 182 exits(buf); 183 } 184 185 /* Begin serving the gnot namespace */ 186 close(0); 187 dup(data, 0); 188 close(data); 189 190 sprint(buf, "%d", msgsize); 191 ac = 0; 192 av[ac++] = exportfs; 193 av[ac++] = "-m"; 194 av[ac++] = buf; 195 if(dbg) 196 av[ac++] = "-d"; 197 if(patternfile != nil){ 198 av[ac++] = "-P"; 199 av[ac++] = patternfile; 200 } 201 av[ac] = nil; 202 exec(exportfs, av); 203 fatal(1, "starting exportfs"); 204 } 205 206 void 207 fatal(int syserr, char *fmt, ...) 208 { 209 Fmt f; 210 char *str; 211 va_list arg; 212 213 fmtstrinit(&f); 214 fmtprint(&f, "cpu: "); 215 va_start(arg, fmt); 216 fmtvprint(&f, fmt, arg); 217 va_end(arg); 218 if(syserr) 219 fmtprint(&f, ": %r"); 220 str = fmtstrflush(&f); 221 222 fprint(2, "%s\n", str); 223 syslog(0, "cpu", str); 224 exits(str); 225 } 226 227 char *negstr = "negotiating authentication method"; 228 229 char bug[256]; 230 231 int 232 old9p(int fd) 233 { 234 int p[2]; 235 236 if(pipe(p) < 0) 237 fatal(1, "pipe"); 238 239 switch(rfork(RFPROC|RFFDG|RFNAMEG)) { 240 case -1: 241 fatal(1, "rfork srvold9p"); 242 case 0: 243 if(fd != 1){ 244 dup(fd, 1); 245 close(fd); 246 } 247 if(p[0] != 0){ 248 dup(p[0], 0); 249 close(p[0]); 250 } 251 close(p[1]); 252 if(0){ 253 fd = open("/sys/log/cpu", OWRITE); 254 if(fd != 2){ 255 dup(fd, 2); 256 close(fd); 257 } 258 execl("/bin/srvold9p", "srvold9p", "-ds", nil); 259 } else 260 execl("/bin/srvold9p", "srvold9p", "-s", nil); 261 fatal(1, "exec srvold9p"); 262 default: 263 close(fd); 264 close(p[0]); 265 } 266 return p[1]; 267 } 268 269 /* Invoked with stdin, stdout and stderr connected to the network connection */ 270 void 271 remoteside(int old) 272 { 273 char user[MaxStr], home[MaxStr], buf[MaxStr], xdir[MaxStr], cmd[MaxStr]; 274 int i, n, fd, badchdir, gotcmd; 275 276 rfork(RFENVG); 277 putenv("service", "cpu"); 278 fd = 0; 279 280 /* negotiate authentication mechanism */ 281 n = readstr(fd, cmd, sizeof(cmd)); 282 if(n < 0) 283 fatal(1, "authenticating"); 284 if(setamalg(cmd) < 0){ 285 writestr(fd, "unsupported auth method", nil, 0); 286 fatal(1, "bad auth method %s", cmd); 287 } else 288 writestr(fd, "", "", 1); 289 290 fd = (*am->sf)(fd, user); 291 if(fd < 0) 292 fatal(1, "srvauth"); 293 294 /* Set environment values for the user */ 295 putenv("user", user); 296 sprint(home, "/usr/%s", user); 297 putenv("home", home); 298 299 /* Now collect invoking cpu's current directory or possibly a command */ 300 gotcmd = 0; 301 if(readstr(fd, xdir, sizeof(xdir)) < 0) 302 fatal(1, "dir/cmd"); 303 if(xdir[0] == '!') { 304 strcpy(cmd, &xdir[1]); 305 gotcmd = 1; 306 if(readstr(fd, xdir, sizeof(xdir)) < 0) 307 fatal(1, "dir"); 308 } 309 310 /* Establish the new process at the current working directory of the 311 * gnot */ 312 badchdir = 0; 313 if(strcmp(xdir, "NO") == 0) 314 chdir(home); 315 else if(chdir(xdir) < 0) { 316 badchdir = 1; 317 chdir(home); 318 } 319 320 /* Start the gnot serving its namespace */ 321 writestr(fd, "FS", "FS", 0); 322 writestr(fd, "/", "exportfs dir", 0); 323 324 n = read(fd, buf, sizeof(buf)); 325 if(n != 2 || buf[0] != 'O' || buf[1] != 'K') 326 exits("remote tree"); 327 328 if(old) 329 fd = old9p(fd); 330 331 /* make sure buffers are big by doing fversion explicitly; pick a huge number; other side will trim */ 332 strcpy(buf, VERSION9P); 333 if(fversion(fd, 64*1024, buf, sizeof buf) < 0) 334 exits("fversion failed"); 335 if(mount(fd, -1, "/mnt/term", MCREATE|MREPL, "") < 0) 336 exits("mount failed"); 337 338 close(fd); 339 340 /* the remote noteproc uses the mount so it must follow it */ 341 rmtnoteproc(); 342 343 for(i = 0; i < 3; i++) 344 close(i); 345 346 if(open("/mnt/term/dev/cons", OREAD) != 0) 347 exits("open stdin"); 348 if(open("/mnt/term/dev/cons", OWRITE) != 1) 349 exits("open stdout"); 350 dup(1, 2); 351 352 if(badchdir) 353 print("cpu: failed to chdir to '%s'\n", xdir); 354 355 if(gotcmd) 356 execl("/bin/rc", "rc", "-lc", cmd, nil); 357 else 358 execl("/bin/rc", "rc", "-li", nil); 359 fatal(1, "exec shell"); 360 } 361 362 char* 363 rexcall(int *fd, char *host, char *service) 364 { 365 char *na; 366 char dir[MaxStr]; 367 char err[ERRMAX]; 368 char msg[MaxStr]; 369 int n; 370 371 na = netmkaddr(host, 0, service); 372 if((*fd = dial(na, 0, dir, 0)) < 0) 373 return "can't dial"; 374 375 /* negotiate authentication mechanism */ 376 if(ealgs != nil) 377 snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); 378 else 379 snprint(msg, sizeof(msg), "%s", am->name); 380 writestr(*fd, msg, negstr, 0); 381 n = readstr(*fd, err, sizeof err); 382 if(n < 0) 383 return negstr; 384 if(*err){ 385 werrstr(err); 386 return negstr; 387 } 388 389 /* authenticate */ 390 *fd = (*am->cf)(*fd); 391 if(*fd < 0) 392 return "can't authenticate"; 393 return 0; 394 } 395 396 void 397 writestr(int fd, char *str, char *thing, int ignore) 398 { 399 int l, n; 400 401 l = strlen(str); 402 n = write(fd, str, l+1); 403 if(!ignore && n < 0) 404 fatal(1, "writing network: %s", thing); 405 } 406 407 int 408 readstr(int fd, char *str, int len) 409 { 410 int n; 411 412 while(len) { 413 n = read(fd, str, 1); 414 if(n < 0) 415 return -1; 416 if(*str == '\0') 417 return 0; 418 str++; 419 len--; 420 } 421 return -1; 422 } 423 424 static int 425 readln(char *buf, int n) 426 { 427 int i; 428 char *p; 429 430 n--; /* room for \0 */ 431 p = buf; 432 for(i=0; i<n; i++){ 433 if(read(0, p, 1) != 1) 434 break; 435 if(*p == '\n' || *p == '\r') 436 break; 437 p++; 438 } 439 *p = '\0'; 440 return p-buf; 441 } 442 443 /* 444 * user level challenge/response 445 */ 446 static int 447 netkeyauth(int fd) 448 { 449 char chall[32]; 450 char resp[32]; 451 452 strecpy(chall, chall+sizeof chall, getuser()); 453 print("user[%s]: ", chall); 454 if(readln(resp, sizeof(resp)) < 0) 455 return -1; 456 if(*resp != 0) 457 strcpy(chall, resp); 458 writestr(fd, chall, "challenge/response", 1); 459 460 for(;;){ 461 if(readstr(fd, chall, sizeof chall) < 0) 462 break; 463 if(*chall == 0) 464 return fd; 465 print("challenge: %s\nresponse: ", chall); 466 if(readln(resp, sizeof(resp)) < 0) 467 break; 468 writestr(fd, resp, "challenge/response", 1); 469 } 470 return -1; 471 } 472 473 static int 474 netkeysrvauth(int fd, char *user) 475 { 476 char response[32]; 477 Chalstate *ch; 478 int tries; 479 AuthInfo *ai; 480 481 if(readstr(fd, user, 32) < 0) 482 return -1; 483 484 ai = nil; 485 ch = nil; 486 for(tries = 0; tries < 10; tries++){ 487 if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil) 488 return -1; 489 writestr(fd, ch->chal, "challenge", 1); 490 if(readstr(fd, response, sizeof response) < 0) 491 return -1; 492 ch->resp = response; 493 ch->nresp = strlen(response); 494 if((ai = auth_response(ch)) != nil) 495 break; 496 } 497 auth_freechal(ch); 498 if(ai == nil) 499 return -1; 500 writestr(fd, "", "challenge", 1); 501 if(auth_chuid(ai, 0) < 0) 502 fatal(1, "newns"); 503 auth_freeAI(ai); 504 return fd; 505 } 506 507 static void 508 mksecret(char *t, uchar *f) 509 { 510 sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", 511 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); 512 } 513 514 /* 515 * plan9 authentication followed by rc4 encryption 516 */ 517 static int 518 p9auth(int fd) 519 { 520 uchar key[16]; 521 uchar digest[SHA1dlen]; 522 char fromclientsecret[21]; 523 char fromserversecret[21]; 524 int i; 525 AuthInfo *ai; 526 527 ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", p9authproto, keyspec); 528 if(ai == nil) 529 return -1; 530 memmove(key+4, ai->secret, ai->nsecret); 531 if(ealgs == nil) 532 return fd; 533 534 /* exchange random numbers */ 535 srand(truerand()); 536 for(i = 0; i < 4; i++) 537 key[i] = rand(); 538 if(write(fd, key, 4) != 4) 539 return -1; 540 if(readn(fd, key+12, 4) != 4) 541 return -1; 542 543 /* scramble into two secrets */ 544 sha1(key, sizeof(key), digest, nil); 545 mksecret(fromclientsecret, digest); 546 mksecret(fromserversecret, digest+10); 547 548 /* set up encryption */ 549 i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); 550 if(i < 0) 551 werrstr("can't establish ssl connection: %r"); 552 return i; 553 } 554 555 static int 556 noauth(int fd) 557 { 558 ealgs = nil; 559 return fd; 560 } 561 562 static int 563 srvnoauth(int fd, char *user) 564 { 565 strecpy(user, user+MaxStr, getuser()); 566 ealgs = nil; 567 newns(user, nil); 568 return fd; 569 } 570 571 void 572 loghex(uchar *p, int n) 573 { 574 char buf[100]; 575 int i; 576 577 for(i = 0; i < n; i++) 578 sprint(buf+2*i, "%2.2ux", p[i]); 579 syslog(0, "cpu", buf); 580 } 581 582 static int 583 srvp9auth(int fd, char *user) 584 { 585 uchar key[16]; 586 uchar digest[SHA1dlen]; 587 char fromclientsecret[21]; 588 char fromserversecret[21]; 589 int i; 590 AuthInfo *ai; 591 592 ai = auth_proxy(0, nil, "proto=%q role=server %s", p9authproto, keyspec); 593 if(ai == nil) 594 return -1; 595 if(auth_chuid(ai, nil) < 0) 596 return -1; 597 strecpy(user, user+MaxStr, ai->cuid); 598 memmove(key+4, ai->secret, ai->nsecret); 599 600 if(ealgs == nil) 601 return fd; 602 603 /* exchange random numbers */ 604 srand(truerand()); 605 for(i = 0; i < 4; i++) 606 key[i+12] = rand(); 607 if(readn(fd, key, 4) != 4) 608 return -1; 609 if(write(fd, key+12, 4) != 4) 610 return -1; 611 612 /* scramble into two secrets */ 613 sha1(key, sizeof(key), digest, nil); 614 mksecret(fromclientsecret, digest); 615 mksecret(fromserversecret, digest+10); 616 617 /* set up encryption */ 618 i = pushssl(fd, ealgs, fromserversecret, fromclientsecret, nil); 619 if(i < 0) 620 werrstr("can't establish ssl connection: %r"); 621 return i; 622 } 623 624 /* 625 * set authentication mechanism 626 */ 627 int 628 setam(char *name) 629 { 630 for(am = authmethod; am->name != nil; am++) 631 if(strcmp(am->name, name) == 0) 632 return 0; 633 am = authmethod; 634 return -1; 635 } 636 637 /* 638 * set authentication mechanism and encryption/hash algs 639 */ 640 int 641 setamalg(char *s) 642 { 643 ealgs = strchr(s, ' '); 644 if(ealgs != nil) 645 *ealgs++ = 0; 646 return setam(s); 647 } 648 649 char *rmtnotefile = "/mnt/term/dev/cpunote"; 650 651 /* 652 * loop reading /mnt/term/dev/note looking for notes. 653 * The child returns to start the shell. 654 */ 655 void 656 rmtnoteproc(void) 657 { 658 int n, fd, pid, notepid; 659 char buf[256]; 660 661 /* new proc returns to start shell */ 662 pid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFMEM); 663 switch(pid){ 664 case -1: 665 syslog(0, "cpu", "cpu -R: can't start noteproc: %r"); 666 return; 667 case 0: 668 return; 669 } 670 671 /* new proc reads notes from other side and posts them to shell */ 672 switch(notepid = rfork(RFPROC|RFFDG|RFMEM)){ 673 case -1: 674 syslog(0, "cpu", "cpu -R: can't start wait proc: %r"); 675 _exits(0); 676 case 0: 677 fd = open(rmtnotefile, OREAD); 678 if(fd < 0){ 679 syslog(0, "cpu", "cpu -R: can't open %s", rmtnotefile); 680 _exits(0); 681 } 682 683 for(;;){ 684 n = read(fd, buf, sizeof(buf)-1); 685 if(n <= 0){ 686 postnote(PNGROUP, pid, "hangup"); 687 _exits(0); 688 } 689 buf[n] = 0; 690 postnote(PNGROUP, pid, buf); 691 } 692 } 693 694 /* original proc waits for shell proc to die and kills note proc */ 695 for(;;){ 696 n = waitpid(); 697 if(n < 0 || n == pid) 698 break; 699 } 700 postnote(PNPROC, notepid, "kill"); 701 _exits(0); 702 } 703 704 enum 705 { 706 Qdir, 707 Qcpunote, 708 709 Nfid = 32, 710 }; 711 712 struct { 713 char *name; 714 Qid qid; 715 ulong perm; 716 } fstab[] = 717 { 718 [Qdir] { ".", {Qdir, 0, QTDIR}, DMDIR|0555 }, 719 [Qcpunote] { "cpunote", {Qcpunote, 0}, 0444 }, 720 }; 721 722 typedef struct Note Note; 723 struct Note 724 { 725 Note *next; 726 char msg[ERRMAX]; 727 }; 728 729 typedef struct Request Request; 730 struct Request 731 { 732 Request *next; 733 Fcall f; 734 }; 735 736 typedef struct Fid Fid; 737 struct Fid 738 { 739 int fid; 740 int file; 741 int omode; 742 }; 743 Fid fids[Nfid]; 744 745 struct { 746 Lock; 747 Note *nfirst, *nlast; 748 Request *rfirst, *rlast; 749 } nfs; 750 751 int 752 fsreply(int fd, Fcall *f) 753 { 754 uchar buf[IOHDRSZ+Maxfdata]; 755 int n; 756 757 if(dbg) 758 fprint(2, "notefs: <-%F\n", f); 759 n = convS2M(f, buf, sizeof buf); 760 if(n > 0){ 761 if(write(fd, buf, n) != n){ 762 close(fd); 763 return -1; 764 } 765 } 766 return 0; 767 } 768 769 /* match a note read request with a note, reply to the request */ 770 int 771 kick(int fd) 772 { 773 Request *rp; 774 Note *np; 775 int rv; 776 777 for(;;){ 778 lock(&nfs); 779 rp = nfs.rfirst; 780 np = nfs.nfirst; 781 if(rp == nil || np == nil){ 782 unlock(&nfs); 783 break; 784 } 785 nfs.rfirst = rp->next; 786 nfs.nfirst = np->next; 787 unlock(&nfs); 788 789 rp->f.type = Rread; 790 rp->f.count = strlen(np->msg); 791 rp->f.data = np->msg; 792 rv = fsreply(fd, &rp->f); 793 free(rp); 794 free(np); 795 if(rv < 0) 796 return -1; 797 } 798 return 0; 799 } 800 801 void 802 flushreq(int tag) 803 { 804 Request **l, *rp; 805 806 lock(&nfs); 807 for(l = &nfs.rfirst; *l != nil; l = &(*l)->next){ 808 rp = *l; 809 if(rp->f.tag == tag){ 810 *l = rp->next; 811 unlock(&nfs); 812 free(rp); 813 return; 814 } 815 } 816 unlock(&nfs); 817 } 818 819 Fid* 820 getfid(int fid) 821 { 822 int i, freefid; 823 824 freefid = -1; 825 for(i = 0; i < Nfid; i++){ 826 if(freefid < 0 && fids[i].file < 0) 827 freefid = i; 828 if(fids[i].fid == fid) 829 return &fids[i]; 830 } 831 if(freefid >= 0){ 832 fids[freefid].fid = fid; 833 return &fids[freefid]; 834 } 835 return nil; 836 } 837 838 int 839 fsstat(int fd, Fid *fid, Fcall *f) 840 { 841 Dir d; 842 uchar statbuf[256]; 843 844 memset(&d, 0, sizeof(d)); 845 d.name = fstab[fid->file].name; 846 d.uid = user; 847 d.gid = user; 848 d.muid = user; 849 d.qid = fstab[fid->file].qid; 850 d.mode = fstab[fid->file].perm; 851 d.atime = d.mtime = time(0); 852 f->stat = statbuf; 853 f->nstat = convD2M(&d, statbuf, sizeof statbuf); 854 return fsreply(fd, f); 855 } 856 857 int 858 fsread(int fd, Fid *fid, Fcall *f) 859 { 860 Dir d; 861 uchar buf[256]; 862 Request *rp; 863 864 switch(fid->file){ 865 default: 866 return -1; 867 case Qdir: 868 if(f->offset == 0 && f->count >0){ 869 memset(&d, 0, sizeof(d)); 870 d.name = fstab[Qcpunote].name; 871 d.uid = user; 872 d.gid = user; 873 d.muid = user; 874 d.qid = fstab[Qcpunote].qid; 875 d.mode = fstab[Qcpunote].perm; 876 d.atime = d.mtime = time(0); 877 f->count = convD2M(&d, buf, sizeof buf); 878 f->data = (char*)buf; 879 } else 880 f->count = 0; 881 return fsreply(fd, f); 882 case Qcpunote: 883 rp = mallocz(sizeof(*rp), 1); 884 if(rp == nil) 885 return -1; 886 rp->f = *f; 887 lock(&nfs); 888 if(nfs.rfirst == nil) 889 nfs.rfirst = rp; 890 else 891 nfs.rlast->next = rp; 892 nfs.rlast = rp; 893 unlock(&nfs); 894 return kick(fd);; 895 } 896 } 897 898 char Eperm[] = "permission denied"; 899 char Enofile[] = "out of files"; 900 char Enotdir[] = "not a directory"; 901 902 void 903 notefs(int fd) 904 { 905 uchar buf[IOHDRSZ+Maxfdata]; 906 int i, n, ncpunote; 907 Fcall f; 908 Qid wqid[MAXWELEM]; 909 Fid *fid, *nfid; 910 int doreply; 911 912 rfork(RFNOTEG); 913 fmtinstall('F', fcallfmt); 914 915 for(n = 0; n < Nfid; n++){ 916 fids[n].file = -1; 917 fids[n].omode = -1; 918 } 919 920 ncpunote = 0; 921 for(;;){ 922 n = read9pmsg(fd, buf, sizeof(buf)); 923 if(n <= 0){ 924 if(dbg) 925 fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n); 926 break; 927 } 928 if(convM2S(buf, n, &f) <= BIT16SZ) 929 break; 930 if(dbg) 931 fprint(2, "notefs: ->%F\n", &f); 932 doreply = 1; 933 fid = getfid(f.fid); 934 if(fid == nil){ 935 nofids: 936 f.type = Rerror; 937 f.ename = Enofile; 938 fsreply(fd, &f); 939 continue; 940 } 941 switch(f.type++){ 942 default: 943 f.type = Rerror; 944 f.ename = "unknown type"; 945 break; 946 case Tflush: 947 flushreq(f.oldtag); 948 break; 949 case Tversion: 950 if(f.msize > IOHDRSZ+Maxfdata) 951 f.msize = IOHDRSZ+Maxfdata; 952 break; 953 case Tauth: 954 f.type = Rerror; 955 f.ename = "authentication not required"; 956 break; 957 case Tattach: 958 f.qid = fstab[Qdir].qid; 959 fid->file = Qdir; 960 break; 961 case Twalk: 962 nfid = nil; 963 if(f.newfid != f.fid){ 964 nfid = getfid(f.newfid); 965 if(nfid == nil) 966 goto nofids; 967 nfid->file = fid->file; 968 fid = nfid; 969 } 970 for(i=0; i<f.nwname && i<MAXWELEM; i++){ 971 if(fid->file != Qdir){ 972 f.type = Rerror; 973 f.ename = Enotdir; 974 break; 975 } 976 if(strcmp(f.wname[i], "..") == 0){ 977 wqid[i] = fstab[Qdir].qid; 978 continue; 979 } 980 if(strcmp(f.wname[i], "cpunote") != 0){ 981 if(i == 0){ 982 f.type = Rerror; 983 f.ename = "file does not exist"; 984 } 985 break; 986 } 987 fid->file = Qcpunote; 988 wqid[i] = fstab[Qcpunote].qid; 989 } 990 if(nfid != nil && (f.type == Rerror || i < f.nwname)) 991 nfid ->file = -1; 992 if(f.type != Rerror){ 993 f.nwqid = i; 994 for(i=0; i<f.nwqid; i++) 995 f.wqid[i] = wqid[i]; 996 } 997 break; 998 case Topen: 999 if(f.mode != OREAD){ 1000 f.type = Rerror; 1001 f.ename = Eperm; 1002 break; 1003 } 1004 fid->omode = f.mode; 1005 if(fid->file == Qcpunote) 1006 ncpunote++; 1007 f.qid = fstab[fid->file].qid; 1008 f.iounit = 0; 1009 break; 1010 case Tread: 1011 if(fsread(fd, fid, &f) < 0) 1012 goto err; 1013 doreply = 0; 1014 break; 1015 case Tclunk: 1016 if(fid->omode != -1 && fid->file == Qcpunote){ 1017 ncpunote--; 1018 if(ncpunote == 0) /* remote side is done */ 1019 goto err; 1020 } 1021 fid->file = -1; 1022 fid->omode = -1; 1023 break; 1024 case Tstat: 1025 if(fsstat(fd, fid, &f) < 0) 1026 goto err; 1027 doreply = 0; 1028 break; 1029 case Tcreate: 1030 case Twrite: 1031 case Tremove: 1032 case Twstat: 1033 f.type = Rerror; 1034 f.ename = Eperm; 1035 break; 1036 } 1037 if(doreply) 1038 if(fsreply(fd, &f) < 0) 1039 break; 1040 } 1041 err: 1042 if(dbg) 1043 fprint(2, "notefs exiting: %r\n"); 1044 werrstr("success"); 1045 postnote(PNGROUP, exportpid, "kill"); 1046 if(dbg) 1047 fprint(2, "postnote PNGROUP %d: %r\n", exportpid); 1048 close(fd); 1049 } 1050 1051 char notebuf[ERRMAX]; 1052 1053 void 1054 catcher(void*, char *text) 1055 { 1056 int n; 1057 1058 n = strlen(text); 1059 if(n >= sizeof(notebuf)) 1060 n = sizeof(notebuf)-1; 1061 memmove(notebuf, text, n); 1062 notebuf[n] = '\0'; 1063 noted(NCONT); 1064 } 1065 1066 /* 1067 * mount in /dev a note file for the remote side to read. 1068 */ 1069 void 1070 lclnoteproc(int netfd) 1071 { 1072 Waitmsg *w; 1073 Note *np; 1074 int pfd[2]; 1075 int pid; 1076 1077 if(pipe(pfd) < 0){ 1078 fprint(2, "cpu: can't start note proc: pipe: %r\n"); 1079 return; 1080 } 1081 1082 /* new proc mounts and returns to start exportfs */ 1083 switch(pid = rfork(RFPROC|RFNAMEG|RFFDG|RFMEM)){ 1084 default: 1085 exportpid = pid; 1086 break; 1087 case -1: 1088 fprint(2, "cpu: can't start note proc: rfork: %r\n"); 1089 return; 1090 case 0: 1091 close(pfd[0]); 1092 if(mount(pfd[1], -1, "/dev", MBEFORE, "") < 0) 1093 fprint(2, "cpu: can't mount note proc: %r\n"); 1094 close(pfd[1]); 1095 return; 1096 } 1097 1098 close(netfd); 1099 close(pfd[1]); 1100 1101 /* new proc listens for note file system rpc's */ 1102 switch(rfork(RFPROC|RFNAMEG|RFMEM)){ 1103 case -1: 1104 fprint(2, "cpu: can't start note proc: rfork1: %r\n"); 1105 _exits(0); 1106 case 0: 1107 notefs(pfd[0]); 1108 _exits(0); 1109 } 1110 1111 /* original proc waits for notes */ 1112 notify(catcher); 1113 w = nil; 1114 for(;;) { 1115 *notebuf = 0; 1116 free(w); 1117 w = wait(); 1118 if(w == nil) { 1119 if(*notebuf == 0) 1120 break; 1121 np = mallocz(sizeof(Note), 1); 1122 if(np != nil){ 1123 strcpy(np->msg, notebuf); 1124 lock(&nfs); 1125 if(nfs.nfirst == nil) 1126 nfs.nfirst = np; 1127 else 1128 nfs.nlast->next = np; 1129 nfs.nlast = np; 1130 unlock(&nfs); 1131 kick(pfd[0]); 1132 } 1133 unlock(&nfs); 1134 } else if(w->pid == exportpid) 1135 break; 1136 } 1137 1138 if(w == nil) 1139 exits(nil); 1140 exits(0); 1141 /* exits(w->msg); */ 1142 } 1143