cpu.c 22 KB

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