drawterm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. #include "lib9.h"
  2. #include "auth.h"
  3. #include "libsec/libsec.h"
  4. char *cpuaddr = "plan9cpu";
  5. char *authaddr = "plan9auth";
  6. char *ealgs = "rc4_256 sha1";
  7. static char *pbmsg = "AS protocol botch";
  8. static char *ccmsg = "can't connect to AS";
  9. int debug = 0;
  10. int mousequeue = 1;
  11. int depth;
  12. static void fdwritestr(int, char*, char*, int);
  13. static int fdreadstr(int, char*, int);
  14. static void noteproc(char *pid);
  15. static void getpasswd(char *p, int len);
  16. static void userpasswd(char *key, int islocal);
  17. static int outin(char *prompt, char *def, int len);
  18. static char *checkkey(char *name, char *key);
  19. static int writefile(char *name, char *buf, int len);
  20. static int authtcp(void);
  21. static int sendmsg(int fd, char *msg);
  22. extern void procinit(void);
  23. extern char *hostlookup(char*);
  24. extern char *base;
  25. void usage(void);
  26. int nncpu(void);
  27. int setam(char*);
  28. int
  29. main(int argc, char *argv[])
  30. {
  31. char buf[128];
  32. int fd;
  33. /*
  34. * Needed by various parts of the code.
  35. * This is a huge bug.
  36. */
  37. assert(sizeof(char)==1);
  38. assert(sizeof(short)==2);
  39. assert(sizeof(ushort)==2);
  40. assert(sizeof(int)==4);
  41. assert(sizeof(uint)==4);
  42. assert(sizeof(long)==4);
  43. assert(sizeof(ulong)==4);
  44. assert(sizeof(vlong)==8);
  45. assert(sizeof(uvlong)==8);
  46. threadinit();
  47. procinit();
  48. ARGBEGIN {
  49. case 'a':
  50. authaddr = ARGF();
  51. break;
  52. case 'c':
  53. cpuaddr = ARGF();
  54. break;
  55. case 'd':
  56. depth = atoi(ARGF());
  57. break;
  58. case 'e':
  59. ealgs = ARGF();
  60. if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
  61. ealgs = nil;
  62. break;
  63. case 'n':
  64. setam("netkey");
  65. break;
  66. case 'm':
  67. mousequeue = !mousequeue;
  68. break;
  69. case 'r':
  70. base = ARGF();
  71. break;
  72. case 'o':
  73. /* from the outside */
  74. /*
  75. cpuaddr = "achille.cs.bell-labs.com";
  76. authaddr = "achille.cs.bell-labs.com";
  77. */
  78. break;
  79. case '@':
  80. /* from Comcast @Home */
  81. /*
  82. cpuaddr = "10.252.0.122";
  83. authaddr = "10.252.0.122";
  84. */
  85. break;
  86. default:
  87. usage();
  88. } ARGEND;
  89. if(argc != 0)
  90. usage();
  91. if(bind("#i", "/dev", MBEFORE) < 0)
  92. iprint("bind failed: %r\n");
  93. if(bind("#m", "/dev", MBEFORE) < 0)
  94. iprint("bind failed: %r\n");
  95. if(bind("#I", "/net", MBEFORE) < 0)
  96. iprint("bind failed: %r\n");
  97. authaddr = hostlookup(authaddr);
  98. cpuaddr = hostlookup(cpuaddr);
  99. fd = nncpu(); /* fd = cpu(); */
  100. /* Tell the remote side the command to execute and where our working directory is */
  101. fdwritestr(fd, "NO", "dir", 0);
  102. /*
  103. * old cpu protocol
  104. *
  105. if(fdreadstr(fd, buf, sizeof(buf)) < 0)
  106. fatal("bad pid");
  107. noteproc(buf);
  108. *
  109. */
  110. /* Wait for the other end to execute and start our file service
  111. * of /mnt/term */
  112. if(fdreadstr(fd, buf, sizeof(buf)) < 0)
  113. fatal("waiting for FS");
  114. if(strncmp("FS", buf, 2) != 0)
  115. fatal("remote cpu: %s", buf);
  116. if(fdreadstr(fd, buf, sizeof(buf)) < 0)
  117. fatal("waiting for root");
  118. if(write(fd, "OK", 2) < 2)
  119. fatal("ack root");
  120. export(fd);
  121. return 0;
  122. }
  123. int
  124. cpu(void)
  125. {
  126. int fd;
  127. char na[256];
  128. userpasswd(na, 0);
  129. netmkaddr(na, cpuaddr, "tcp", "17005");
  130. if((fd = dial(na, 0, 0, 0)) < 0) {
  131. fatal("can't dial %s: %r", na);
  132. }
  133. if(auth(fd, 0) < 0)
  134. fatal("can't authenticate: %r");
  135. return fd;
  136. }
  137. /* authentication mechanisms */
  138. static int netkeyauth(int, uchar*);
  139. typedef struct AuthMethod AuthMethod;
  140. struct AuthMethod {
  141. char *name; /* name of method */
  142. int (*cf)(int, uchar*); /* client side authentication */
  143. } authmethod[] =
  144. {
  145. { "p9", auth},
  146. { "netkey", netkeyauth},
  147. { nil, nil}
  148. };
  149. AuthMethod *am = authmethod; /* default is p9 */
  150. int
  151. setam(char *name)
  152. {
  153. for(am = authmethod; am->name != nil; am++)
  154. if(strcmp(am->name, name) == 0)
  155. return 0;
  156. am = authmethod;
  157. return -1;
  158. }
  159. static void
  160. mksecret(char *t, uchar *f)
  161. {
  162. sprint(t, "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
  163. f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
  164. }
  165. char *negstr = "negotiating authentication method";
  166. int
  167. nncpu(void)
  168. {
  169. char na[128];
  170. char err[ERRLEN];
  171. uchar key[16];
  172. uchar digest[SHA1dlen];
  173. char fromclientsecret[21];
  174. char fromserversecret[21];
  175. int fd, n, i;
  176. netmkaddr(na, cpuaddr, "tcp", "17013");
  177. if((fd = dial(na, 0, 0, 0)) < 0) {
  178. fatal("can't dial %s: %r", na);
  179. }
  180. if(am->cf == auth)
  181. userpasswd(key+4, 0);
  182. /* negotiate authentication mechanism */
  183. if(ealgs != nil)
  184. snprint(na, sizeof(na), "%s %s", am->name, ealgs);
  185. else
  186. snprint(na, sizeof(na), "%s", am->name);
  187. fdwritestr(fd, na, negstr, 0);
  188. n = fdreadstr(fd, err, ERRLEN);
  189. if(n < 0)
  190. fatal(negstr);
  191. if(*err)
  192. fatal("%s: %s", negstr, err);
  193. /* authenticate */
  194. if((*am->cf)(fd, key+4) < 0)
  195. fatal("cannot authenticate with %s", am->name);
  196. if(ealgs == nil)
  197. return fd;
  198. /* ssl handshake */
  199. for(i = 0; i < 4; i++)
  200. key[i] = nrand(256);
  201. if(write(fd, key, 4) != 4 || readn(fd, key+12, 4) != 4)
  202. fatal("cannot exchange random numbers for ssl: %r");
  203. /* scramble into two secrets */
  204. sha1(key, sizeof(key), digest, nil);
  205. mksecret(fromclientsecret, digest);
  206. mksecret(fromserversecret, digest+10);
  207. /* set up encryption */
  208. fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
  209. if(fd < 0)
  210. fatal("cannot establish ssl connection: %r");
  211. return fd;
  212. }
  213. static int
  214. readln(char *buf, int n)
  215. {
  216. char *p = buf;
  217. n--;
  218. while(n > 0){
  219. if(read(0, p, 1) != 1)
  220. break;
  221. if(*p == '\n' || *p == '\r'){
  222. *p = 0;
  223. return p-buf;
  224. }
  225. p++;
  226. }
  227. *p = 0;
  228. return p-buf;
  229. }
  230. static int
  231. netkeyauth(int fd, uchar *secret)
  232. {
  233. char chall[NAMELEN];
  234. char resp[NAMELEN];
  235. USED(secret);
  236. strcpy(chall, getuser());
  237. print("user[%s]: ", chall);
  238. if(readln(resp, sizeof(resp)) < 0)
  239. return -1;
  240. if(*resp != 0)
  241. strcpy(chall, resp);
  242. fdwritestr(fd, chall, "challenge/response", 1);
  243. for(;;){
  244. if(fdreadstr(fd, chall, sizeof chall) < 0)
  245. break;
  246. if(*chall == 0)
  247. return 0;
  248. print("challenge: %s\nresponse: ", chall);
  249. if(readln(resp, sizeof(resp)) < 0)
  250. break;
  251. fdwritestr(fd, resp, "challenge/response", 1);
  252. }
  253. return -1;
  254. }
  255. void
  256. usage(void)
  257. {
  258. iprint("usage: %s [-o@] [-n] [-m] [-c cpusrv] [-a authsrv] [-e 'crypt hash'] [-r root]\n", argv0);
  259. exits(0);
  260. }
  261. void
  262. fdwritestr(int fd, char *str, char *thing, int ignore)
  263. {
  264. int l, n;
  265. l = strlen(str);
  266. n = write(fd, str, l+1);
  267. if(!ignore && n < 0)
  268. fatal("writing network: %s", thing);
  269. }
  270. int
  271. fdreadstr(int fd, char *str, int len)
  272. {
  273. int n;
  274. while(len) {
  275. n = read(fd, str, 1);
  276. if(n < 0)
  277. return -1;
  278. if(*str == '\0')
  279. return 0;
  280. str++;
  281. len--;
  282. }
  283. return -1;
  284. }
  285. void
  286. noteproc(char *pid)
  287. {
  288. char cmd[NAMELEN];
  289. int fd;
  290. char na[256];
  291. netmkaddr(na, cpuaddr, "tcp", "17006");
  292. if((fd = dial(na, 0, 0, 0)) < 0)
  293. fatal("can't dial");
  294. if(auth(fd, 0) < 0)
  295. fatal("can't authenticate");
  296. sprint(cmd, "%s", pid);
  297. fdwritestr(fd, cmd, "notepid", 0);
  298. return;
  299. /*
  300. notify(catcher);
  301. for(;;) {
  302. n = wait(&w);
  303. if(n < 0) {
  304. writestr(notechan, notebuf, "catcher", 1);
  305. errstr(syserr);
  306. if(strcmp(syserr, "interrupted") != 0){
  307. iprint("cpu: wait: %s\n", syserr);
  308. exits("waiterr");
  309. }
  310. }
  311. if(n == notepid)
  312. break;
  313. }
  314. exits(w.msg);
  315. */
  316. }
  317. static char password[NAMELEN];
  318. char username[NAMELEN];
  319. char *homsg = "can't set user name or key; please reboot";
  320. /*
  321. * get/set user name and password. verify password with auth server.
  322. */
  323. void
  324. userpasswd(char *hostkey, int islocal)
  325. {
  326. int fd;
  327. char *msg;
  328. if(*username == 0 || strcmp(username, "none") == 0){
  329. strcpy(username, "none");
  330. outin("user", username, sizeof(username));
  331. }
  332. if(!atlocalconsole()){
  333. print("not at local console; won't ask for password\n");
  334. p9sleep(10000);
  335. exits(0);
  336. }
  337. fd = -1;
  338. while(strcmp(username, "none") != 0){
  339. getpasswd(password, sizeof password);
  340. passtokey(hostkey, password);
  341. memset(password, 0, sizeof(password));
  342. fd = -1;
  343. if(islocal)
  344. break;
  345. msg = checkkey(username, hostkey);
  346. if(msg == 0)
  347. break;
  348. print("?%s\n", msg);
  349. outin("user", username, sizeof(username));
  350. }
  351. if(fd > 0)
  352. close(fd);
  353. /* set host's key */
  354. if(writefile("#c/key", hostkey, DESKEYLEN) < 0)
  355. fatal(homsg);
  356. /* set host's owner (and uid of current process) */
  357. if(writefile("#c/hostowner", username, strlen(username)) < 0)
  358. fatal(homsg);
  359. close(fd);
  360. }
  361. static char*
  362. fromauth(char *trbuf, char *tbuf)
  363. {
  364. int afd;
  365. char t;
  366. char *msg;
  367. static char error[2*ERRLEN];
  368. afd = authtcp();
  369. if(afd < 0) {
  370. sprint(error, "%s: %r", ccmsg);
  371. return error;
  372. }
  373. if(write(afd, trbuf, TICKREQLEN) < 0 || read(afd, &t, 1) != 1){
  374. close(afd);
  375. sprint(error, "%s: %r", pbmsg);
  376. return error;
  377. }
  378. switch(t){
  379. case AuthOK:
  380. msg = 0;
  381. if(readn(afd, tbuf, 2*TICKETLEN) < 0) {
  382. sprint(error, "%s: %r", pbmsg);
  383. msg = error;
  384. }
  385. break;
  386. case AuthErr:
  387. if(readn(afd, error, ERRLEN) < 0) {
  388. sprint(error, "%s: %r", pbmsg);
  389. msg = error;
  390. }
  391. else {
  392. error[ERRLEN-1] = 0;
  393. msg = error;
  394. }
  395. break;
  396. default:
  397. msg = pbmsg;
  398. break;
  399. }
  400. close(afd);
  401. return msg;
  402. }
  403. char*
  404. checkkey(char *name, char *key)
  405. {
  406. char *msg;
  407. Ticketreq tr;
  408. Ticket t;
  409. char trbuf[TICKREQLEN];
  410. char tbuf[2*TICKETLEN];
  411. memset(&tr, 0, sizeof tr);
  412. tr.type = AuthTreq;
  413. strcpy(tr.authid, name);
  414. strcpy(tr.hostid, name);
  415. strcpy(tr.uid, name);
  416. convTR2M(&tr, trbuf);
  417. msg = fromauth(trbuf, tbuf);
  418. if(msg == ccmsg){
  419. iprint("boot: can't contact auth server, passwd unchecked\n");
  420. return 0;
  421. }
  422. if(msg)
  423. return msg;
  424. convM2T(tbuf, &t, key);
  425. if(t.num == AuthTc && strcmp(name, t.cuid)==0)
  426. return 0;
  427. return "no match";
  428. }
  429. void
  430. getpasswd(char *p, int len)
  431. {
  432. char c;
  433. int i, n, fd;
  434. fd = open("#c/consctl", OWRITE);
  435. if(fd < 0)
  436. fatal("can't open consctl; please reboot");
  437. write(fd, "rawon", 5);
  438. Prompt:
  439. print("password: ");
  440. n = 0;
  441. for(;;){
  442. do{
  443. i = read(0, &c, 1);
  444. if(i < 0)
  445. fatal("can't read cons; please reboot");
  446. }while(i == 0);
  447. switch(c){
  448. case '\n':
  449. p[n] = '\0';
  450. close(fd);
  451. print("\n");
  452. return;
  453. case '\b':
  454. if(n > 0)
  455. n--;
  456. break;
  457. case 'u' - 'a' + 1: /* cntrl-u */
  458. print("\n");
  459. goto Prompt;
  460. default:
  461. if(n < len - 1)
  462. p[n++] = c;
  463. break;
  464. }
  465. }
  466. }
  467. int
  468. authtcp(void)
  469. {
  470. char na[256];
  471. netmkaddr(na, authaddr, "tcp", "567");
  472. return dial(na, 0, 0, 0);
  473. }
  474. int
  475. plumb(char *dir, char *dest, int *efd, char *here)
  476. {
  477. char buf[128];
  478. char name[128];
  479. int n;
  480. sprint(name, "%s/clone", dir);
  481. efd[0] = open(name, ORDWR);
  482. if(efd[0] < 0)
  483. return -1;
  484. n = read(efd[0], buf, sizeof(buf)-1);
  485. if(n < 0){
  486. close(efd[0]);
  487. return -1;
  488. }
  489. buf[n] = 0;
  490. sprint(name, "%s/%s/data", dir, buf);
  491. if(here){
  492. sprint(buf, "announce %s", here);
  493. if(sendmsg(efd[0], buf) < 0){
  494. close(efd[0]);
  495. return -1;
  496. }
  497. }
  498. sprint(buf, "connect %s", dest);
  499. if(sendmsg(efd[0], buf) < 0){
  500. close(efd[0]);
  501. return -1;
  502. }
  503. efd[1] = open(name, ORDWR);
  504. if(efd[1] < 0){
  505. close(efd[0]);
  506. return -1;
  507. }
  508. return efd[1];
  509. }
  510. int
  511. sendmsg(int fd, char *msg)
  512. {
  513. int n;
  514. n = strlen(msg);
  515. if(write(fd, msg, n) != n)
  516. return -1;
  517. return 0;
  518. }
  519. void
  520. warning(char *s)
  521. {
  522. char buf[ERRLEN];
  523. errstr(buf);
  524. iprint("boot: %s: %s\n", s, buf);
  525. }
  526. int
  527. readfile(char *name, char *buf, int len)
  528. {
  529. int f, n;
  530. buf[0] = 0;
  531. f = open(name, OREAD);
  532. if(f < 0)
  533. return -1;
  534. n = read(f, buf, len-1);
  535. if(n >= 0)
  536. buf[n] = 0;
  537. close(f);
  538. return 0;
  539. }
  540. int
  541. writefile(char *name, char *buf, int len)
  542. {
  543. int f, n;
  544. f = open(name, OWRITE);
  545. if(f < 0)
  546. return -1;
  547. n = write(f, buf, len);
  548. close(f);
  549. return (n != len) ? -1 : 0;
  550. }
  551. void
  552. srvcreate(char *name, int fd)
  553. {
  554. char *srvname;
  555. int f;
  556. char buf[2*NAMELEN];
  557. srvname = strrchr(name, '/');
  558. if(srvname)
  559. srvname++;
  560. else
  561. srvname = name;
  562. sprint(buf, "#s/%s", srvname);
  563. f = create(buf, 1, 0666);
  564. if(f < 0)
  565. fatal(buf);
  566. sprint(buf, "%d", fd);
  567. if(write(f, buf, strlen(buf)) != (int)strlen(buf))
  568. fatal("write");
  569. close(f);
  570. }
  571. int
  572. outin(char *prompt, char *def, int len)
  573. {
  574. int n;
  575. char buf[256];
  576. print("%s[%s]: ", prompt, *def ? def : "no default");
  577. n = read(0, buf, len);
  578. if(n <= 0)
  579. return -1;
  580. if(n != 1){
  581. buf[n-1] = 0;
  582. strcpy(def, buf);
  583. }
  584. return n;
  585. }
  586. /*
  587. * get second word of the terminal environment variable. If it
  588. * ends in "boot", get rid of that part.
  589. */
  590. void
  591. getconffile(char *conffile, char *terminal)
  592. {
  593. char *p, *q;
  594. char *s;
  595. int n;
  596. s = conffile;
  597. *conffile = 0;
  598. p = terminal;
  599. if((p = strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0)
  600. return;
  601. p++;
  602. for(q = p; *q && *q != ' '; q++)
  603. ;
  604. while(p < q)
  605. *conffile++ = *p++;
  606. *conffile = 0;
  607. /* dump a trailing boot */
  608. n = strlen(s);
  609. if(n > 4 && strcmp(s + n - 4, "boot") == 0)
  610. *(s+n-4) = 0;
  611. }
  612. /*
  613. * Case insensitive strcmp
  614. */
  615. int
  616. cistrncmp(char *a, char *b, int n)
  617. {
  618. unsigned ac, bc;
  619. while(n > 0){
  620. ac = *a++;
  621. bc = *b++;
  622. n--;
  623. if(ac >= 'A' && ac <= 'Z')
  624. ac = 'a' + (ac - 'A');
  625. if(bc >= 'A' && bc <= 'Z')
  626. bc = 'a' + (bc - 'A');
  627. ac -= bc;
  628. if(ac)
  629. return ac;
  630. if(bc == 0)
  631. break;
  632. }
  633. return 0;
  634. }