cpu-bl.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * cpu.c - Make a connection to a cpu server
  11. *
  12. * Invoked by listen as 'cpu -R | -N service net netdir'
  13. * by users as 'cpu [-h system] [-c cmd args ...]'
  14. */
  15. #include <u.h>
  16. #include <libc.h>
  17. #include <auth.h>
  18. #include <fcall.h>
  19. #include <authsrv.h>
  20. #include <libsec.h>
  21. #include "args.h"
  22. #include "drawterm.h"
  23. #define Maxfdata 8192
  24. #define MaxStr 128
  25. static void fatal(int, char*, ...);
  26. static void usage(void);
  27. static void writestr(int, char*, char*, int);
  28. static int readstr(int, char*, int);
  29. static char *rexcall(int*, char*, char*);
  30. static char *keyspec = "";
  31. static AuthInfo *p9any(int);
  32. #define system csystem
  33. static char *system;
  34. static int cflag;
  35. extern int dbg;
  36. extern char* base; // fs base for devroot
  37. static char *srvname = "ncpu";
  38. static char *ealgs = "rc4_256 sha1";
  39. /* message size for exportfs; may be larger so we can do big graphics in CPU window */
  40. static int msgsize = Maxfdata+IOHDRSZ;
  41. /* authentication mechanisms */
  42. static int netkeyauth(int);
  43. static int netkeysrvauth(int, char*);
  44. static int p9auth(int);
  45. static int srvp9auth(int, char*);
  46. char *authserver;
  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. char *p9authproto = "p9any";
  61. int setam(char*);
  62. void
  63. exits(char *s)
  64. {
  65. print("\ngoodbye\n");
  66. for(;;) osyield();
  67. }
  68. void
  69. usage(void)
  70. {
  71. fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");
  72. exits("usage");
  73. }
  74. int fdd;
  75. int
  76. mountfactotum(void)
  77. {
  78. int fd;
  79. if((fd = dialfactotum()) < 0)
  80. return -1;
  81. if(sysmount(fd, -1, "/mnt/factotum", MREPL, "") < 0){
  82. fprint(2, "mount factotum: %r\n");
  83. return -1;
  84. }
  85. if((fd = open("/mnt/factotum/ctl", OREAD)) < 0){
  86. fprint(2, "open /mnt/factotum/ctl: %r\n");
  87. return -1;
  88. }
  89. close(fd);
  90. return 0;
  91. }
  92. void
  93. cpumain(int argc, char **argv)
  94. {
  95. char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *err, *secstoreserver, *p, *s;
  96. int fd, ms, data;
  97. /* see if we should use a larger message size */
  98. fd = open("/dev/draw", OREAD);
  99. if(fd > 0){
  100. ms = iounit(fd);
  101. if(msgsize < ms+IOHDRSZ)
  102. msgsize = ms+IOHDRSZ;
  103. close(fd);
  104. }
  105. user = getenv("USER");
  106. secstoreserver = nil;
  107. authserver = getenv("auth");
  108. if(authserver == nil)
  109. authserver = "p9auth.cs.bell-labs.com";
  110. system = getenv("cpu");
  111. if(system == nil)
  112. system = "plan9.bell-labs.com";
  113. ARGBEGIN{
  114. case 'a':
  115. authserver = EARGF(usage());
  116. break;
  117. case 'c':
  118. system = EARGF(usage());
  119. break;
  120. case 'd':
  121. dbg++;
  122. break;
  123. case 'e':
  124. ealgs = EARGF(usage());
  125. if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
  126. ealgs = nil;
  127. break;
  128. case 'C':
  129. cflag++;
  130. cmd[0] = '!';
  131. cmd[1] = '\0';
  132. while((p = ARGF()) != nil) {
  133. strcat(cmd, " ");
  134. strcat(cmd, p);
  135. }
  136. break;
  137. case 'k':
  138. keyspec = EARGF(usage());
  139. break;
  140. case 'r':
  141. base = EARGF(usage());
  142. break;
  143. case 's':
  144. secstoreserver = EARGF(usage());
  145. break;
  146. case 'u':
  147. user = EARGF(usage());
  148. break;
  149. default:
  150. usage();
  151. }ARGEND;
  152. if(argc != 0)
  153. usage();
  154. if(user == nil)
  155. user = readcons("user", nil, 0);
  156. if(mountfactotum() < 0){
  157. if(secstoreserver == nil)
  158. secstoreserver = authserver;
  159. if(havesecstore(secstoreserver, user)){
  160. s = secstorefetch(secstoreserver, user, nil);
  161. if(s){
  162. if(strlen(s) >= sizeof secstorebuf)
  163. sysfatal("secstore data too big");
  164. strcpy(secstorebuf, s);
  165. }
  166. }
  167. }
  168. if((err = rexcall(&data, system, srvname)))
  169. fatal(1, "%s: %s", err, system);
  170. /* Tell the remote side the command to execute and where our working directory is */
  171. if(cflag)
  172. writestr(data, cmd, "command", 0);
  173. if(getcwd(dat, sizeof(dat)) == 0)
  174. writestr(data, "NO", "dir", 0);
  175. else
  176. writestr(data, dat, "dir", 0);
  177. /*
  178. * Wait for the other end to execute and start our file service
  179. * of /mnt/term
  180. */
  181. if(readstr(data, buf, sizeof(buf)) < 0)
  182. fatal(1, "waiting for FS: %r");
  183. if(strncmp("FS", buf, 2) != 0) {
  184. print("remote cpu: %s", buf);
  185. exits(buf);
  186. }
  187. if(readstr(data, buf, sizeof buf) < 0)
  188. fatal(1, "waiting for remote export: %r");
  189. if(strcmp(buf, "/") != 0){
  190. print("remote cpu: %s" , buf);
  191. exits(buf);
  192. }
  193. write(data, "OK", 2);
  194. /* Begin serving the gnot namespace */
  195. exportfs(data, msgsize);
  196. fatal(1, "starting exportfs");
  197. }
  198. void
  199. fatal(int syserr, char *fmt, ...)
  200. {
  201. Fmt f;
  202. char *str;
  203. va_list arg;
  204. fmtstrinit(&f);
  205. fmtprint(&f, "cpu: ");
  206. va_start(arg, fmt);
  207. fmtvprint(&f, fmt, arg);
  208. va_end(arg);
  209. if(syserr)
  210. fmtprint(&f, ": %r");
  211. fmtprint(&f, "\n");
  212. str = fmtstrflush(&f);
  213. write(2, str, strlen(str));
  214. exits(str);
  215. }
  216. char *negstr = "negotiating authentication method";
  217. char bug[256];
  218. char*
  219. rexcall(int *fd, char *host, char *service)
  220. {
  221. char *na;
  222. char dir[MaxStr];
  223. char err[ERRMAX];
  224. char msg[MaxStr];
  225. int n;
  226. na = netmkaddr(host, "tcp", "17010");
  227. if((*fd = dial(na, 0, dir, 0)) < 0)
  228. return "can't dial";
  229. /* negotiate authentication mechanism */
  230. if(ealgs != nil)
  231. snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
  232. else
  233. snprint(msg, sizeof(msg), "%s", am->name);
  234. writestr(*fd, msg, negstr, 0);
  235. n = readstr(*fd, err, sizeof err);
  236. if(n < 0)
  237. return negstr;
  238. if(*err){
  239. werrstr(err);
  240. return negstr;
  241. }
  242. /* authenticate */
  243. *fd = (*am->cf)(*fd);
  244. if(*fd < 0)
  245. return "can't authenticate";
  246. return 0;
  247. }
  248. void
  249. writestr(int fd, char *str, char *thing, int ignore)
  250. {
  251. int l, n;
  252. l = strlen(str);
  253. n = write(fd, str, l+1);
  254. if(!ignore && n < 0)
  255. fatal(1, "writing network: %s", thing);
  256. }
  257. int
  258. readstr(int fd, char *str, int len)
  259. {
  260. int n;
  261. while(len) {
  262. n = read(fd, str, 1);
  263. if(n < 0)
  264. return -1;
  265. if(*str == '\0')
  266. return 0;
  267. str++;
  268. len--;
  269. }
  270. return -1;
  271. }
  272. static int
  273. readln(char *buf, int n)
  274. {
  275. int i;
  276. char *p;
  277. n--; /* room for \0 */
  278. p = buf;
  279. for(i=0; i<n; i++){
  280. if(read(0, p, 1) != 1)
  281. break;
  282. if(*p == '\n' || *p == '\r')
  283. break;
  284. p++;
  285. }
  286. *p = '\0';
  287. return p-buf;
  288. }
  289. /*
  290. * user level challenge/response
  291. */
  292. static int
  293. netkeyauth(int fd)
  294. {
  295. char chall[32];
  296. char resp[32];
  297. strecpy(chall, chall+sizeof chall, getuser());
  298. print("user[%s]: ", chall);
  299. if(readln(resp, sizeof(resp)) < 0)
  300. return -1;
  301. if(*resp != 0)
  302. strcpy(chall, resp);
  303. writestr(fd, chall, "challenge/response", 1);
  304. for(;;){
  305. if(readstr(fd, chall, sizeof chall) < 0)
  306. break;
  307. if(*chall == 0)
  308. return fd;
  309. print("challenge: %s\nresponse: ", chall);
  310. if(readln(resp, sizeof(resp)) < 0)
  311. break;
  312. writestr(fd, resp, "challenge/response", 1);
  313. }
  314. return -1;
  315. }
  316. static int
  317. netkeysrvauth(int fd, char *user)
  318. {
  319. return -1;
  320. }
  321. static void
  322. mksecret(char *t, uint8_t *f)
  323. {
  324. sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
  325. f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
  326. }
  327. /*
  328. * plan9 authentication followed by rc4 encryption
  329. */
  330. static int
  331. p9auth(int fd)
  332. {
  333. uint8_t key[16];
  334. uint8_t digest[SHA1dlen];
  335. char fromclientsecret[21];
  336. char fromserversecret[21];
  337. int i;
  338. AuthInfo *ai;
  339. ai = p9any(fd);
  340. if(ai == nil)
  341. return -1;
  342. memmove(key+4, ai->secret, ai->nsecret);
  343. if(ealgs == nil)
  344. return fd;
  345. /* exchange random numbers */
  346. for(i = 0; i < 4; i++)
  347. key[i] = fastrand();
  348. if(write(fd, key, 4) != 4)
  349. return -1;
  350. if(readn(fd, key+12, 4) != 4)
  351. return -1;
  352. /* scramble into two secrets */
  353. sha1(key, sizeof(key), digest, nil);
  354. mksecret(fromclientsecret, digest);
  355. mksecret(fromserversecret, digest+10);
  356. /* set up encryption */
  357. i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
  358. if(i < 0)
  359. werrstr("can't establish ssl connection: %r");
  360. return i;
  361. }
  362. int
  363. authdial(char *net, char *dom)
  364. {
  365. int fd;
  366. fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0);
  367. //print("authdial %d\n", fd);
  368. return fd;
  369. }
  370. static int
  371. getastickets(Ticketreq *tr, char *trbuf, char *tbuf)
  372. {
  373. int asfd, rv;
  374. char *dom;
  375. dom = tr->authdom;
  376. asfd = authdial(nil, dom);
  377. if(asfd < 0)
  378. return -1;
  379. rv = _asgetticket(asfd, trbuf, tbuf);
  380. close(asfd);
  381. return rv;
  382. }
  383. static int
  384. mkserverticket(Ticketreq *tr, char *authkey, char *tbuf)
  385. {
  386. int i;
  387. Ticket t;
  388. if(strcmp(tr->authid, tr->hostid) != 0)
  389. return -1;
  390. memset(&t, 0, sizeof(t));
  391. memmove(t.chal, tr->chal, CHALLEN);
  392. strcpy(t.cuid, tr->uid);
  393. strcpy(t.suid, tr->uid);
  394. for(i=0; i<DESKEYLEN; i++)
  395. t.key[i] = fastrand();
  396. t.num = AuthTc;
  397. convT2M(&t, tbuf, authkey);
  398. t.num = AuthTs;
  399. convT2M(&t, tbuf+TICKETLEN, authkey);
  400. return 0;
  401. }
  402. static int
  403. gettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf)
  404. {
  405. if(getastickets(tr, trbuf, tbuf) >= 0)
  406. return 0;
  407. return mkserverticket(tr, key, tbuf);
  408. }
  409. /*
  410. * prompt user for a key. don't care about memory leaks, runs standalone
  411. */
  412. static Attr*
  413. promptforkey(char *params)
  414. {
  415. char *v;
  416. int fd;
  417. Attr *a, *attr;
  418. char *def;
  419. fd = open("/dev/cons", ORDWR);
  420. if(fd < 0)
  421. sysfatal("opening /dev/cons: %r");
  422. attr = _parseattr(params);
  423. fprint(fd, "\n!Adding key:");
  424. for(a=attr; a; a=a->next)
  425. if(a->type != AttrQuery && a->name[0] != '!')
  426. fprint(fd, " %q=%q", a->name, a->val);
  427. fprint(fd, "\n");
  428. for(a=attr; a; a=a->next){
  429. v = a->name;
  430. if(a->type != AttrQuery || v[0]=='!')
  431. continue;
  432. def = nil;
  433. if(strcmp(v, "user") == 0)
  434. def = getuser();
  435. a->val = readcons(v, def, 0);
  436. if(a->val == nil)
  437. sysfatal("user terminated key input");
  438. a->type = AttrNameval;
  439. }
  440. for(a=attr; a; a=a->next){
  441. v = a->name;
  442. if(a->type != AttrQuery || v[0]!='!')
  443. continue;
  444. def = nil;
  445. if(strcmp(v+1, "user") == 0)
  446. def = getuser();
  447. a->val = readcons(v+1, def, 1);
  448. if(a->val == nil)
  449. sysfatal("user terminated key input");
  450. a->type = AttrNameval;
  451. }
  452. fprint(fd, "!\n");
  453. close(fd);
  454. return attr;
  455. }
  456. /*
  457. * send a key to the mounted factotum
  458. */
  459. static int
  460. sendkey(Attr *attr)
  461. {
  462. int fd, rv;
  463. char buf[1024];
  464. fd = open("/mnt/factotum/ctl", ORDWR);
  465. if(fd < 0)
  466. sysfatal("opening /mnt/factotum/ctl: %r");
  467. rv = fprint(fd, "key %A\n", attr);
  468. read(fd, buf, sizeof buf);
  469. close(fd);
  470. return rv;
  471. }
  472. int
  473. askuser(char *params)
  474. {
  475. Attr *attr;
  476. fmtinstall('A', _attrfmt);
  477. attr = promptforkey(params);
  478. if(attr == nil)
  479. sysfatal("no key supplied");
  480. if(sendkey(attr) < 0)
  481. sysfatal("sending key to factotum: %r");
  482. return 0;
  483. }
  484. AuthInfo*
  485. p9anyfactotum(int fd, int afd)
  486. {
  487. return auth_proxy(fd, askuser, "proto=p9any role=client %s", keyspec);
  488. }
  489. AuthInfo*
  490. p9any(int fd)
  491. {
  492. char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u;
  493. char *pass;
  494. char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN];
  495. char authkey[DESKEYLEN];
  496. Authenticator auth;
  497. int afd, i, n, v2;
  498. Ticketreq tr;
  499. Ticket t;
  500. AuthInfo *ai;
  501. if((afd = open("/mnt/factotum/ctl", ORDWR)) >= 0)
  502. return p9anyfactotum(fd, afd);
  503. if(readstr(fd, buf, sizeof buf) < 0)
  504. fatal(1, "cannot read p9any negotiation");
  505. bbuf = buf;
  506. v2 = 0;
  507. if(strncmp(buf, "v.2 ", 4) == 0){
  508. v2 = 1;
  509. bbuf += 4;
  510. }
  511. if((p = strchr(bbuf, ' ')))
  512. *p = 0;
  513. p = bbuf;
  514. if((dom = strchr(p, '@')) == nil)
  515. fatal(1, "bad p9any domain");
  516. *dom++ = 0;
  517. if(strcmp(p, "p9sk1") != 0)
  518. fatal(1, "server did not offer p9sk1");
  519. sprint(buf2, "%s %s", p, dom);
  520. if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
  521. fatal(1, "cannot write user/domain choice in p9any");
  522. if(v2){
  523. if(readstr(fd, buf, sizeof buf) != 3)
  524. fatal(1, "cannot read OK in p9any");
  525. if(memcmp(buf, "OK\0", 3) != 0)
  526. fatal(1, "did not get OK in p9any");
  527. }
  528. for(i=0; i<CHALLEN; i++)
  529. cchal[i] = fastrand();
  530. if(write(fd, cchal, 8) != 8)
  531. fatal(1, "cannot write p9sk1 challenge");
  532. if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN)
  533. fatal(1, "cannot read ticket request in p9sk1");
  534. convM2TR(trbuf, &tr);
  535. u = user;
  536. pass = findkey(&u, tr.authdom);
  537. if(pass == nil)
  538. again:
  539. pass = getkey(u, tr.authdom);
  540. if(pass == nil)
  541. fatal(1, "no password");
  542. passtokey(authkey, pass);
  543. memset(pass, 0, strlen(pass));
  544. tr.type = AuthTreq;
  545. strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u);
  546. strecpy(tr.uid, tr.uid+sizeof tr.uid, u);
  547. convTR2M(&tr, trbuf);
  548. if(gettickets(&tr, authkey, trbuf, tbuf) < 0)
  549. fatal(1, "cannot get auth tickets in p9sk1");
  550. convM2T(tbuf, &t, authkey);
  551. if(t.num != AuthTc){
  552. print("?password mismatch with auth server\n");
  553. goto again;
  554. }
  555. memmove(tbuf, tbuf+TICKETLEN, TICKETLEN);
  556. auth.num = AuthAc;
  557. memmove(auth.chal, tr.chal, CHALLEN);
  558. auth.id = 0;
  559. convA2M(&auth, tbuf+TICKETLEN, t.key);
  560. if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
  561. fatal(1, "cannot send ticket and authenticator back in p9sk1");
  562. if((n=readn(fd, tbuf, AUTHENTLEN)) != AUTHENTLEN ||
  563. memcmp(tbuf, "cpu:", 4) == 0){
  564. if(n <= 4)
  565. fatal(1, "cannot read authenticator in p9sk1");
  566. /*
  567. * didn't send back authenticator:
  568. * sent back fatal error message.
  569. */
  570. memmove(buf, tbuf, n);
  571. i = readn(fd, buf+n, sizeof buf-n-1);
  572. if(i > 0)
  573. n += i;
  574. buf[n] = 0;
  575. werrstr("");
  576. fatal(0, "server says: %s", buf);
  577. }
  578. convM2A(tbuf, &auth, t.key);
  579. if(auth.num != AuthAs
  580. || memcmp(auth.chal, cchal, CHALLEN) != 0
  581. || auth.id != 0){
  582. print("?you and auth server agree about password.\n");
  583. print("?server is confused.\n");
  584. fatal(0, "server lies got %llux.%d want %llux.%d",
  585. *(int64_t*)auth.chal, auth.id, *(int64_t*)cchal, 0);
  586. }
  587. //print("i am %s there.\n", t.suid);
  588. ai = mallocz(sizeof(AuthInfo), 1);
  589. ai->secret = mallocz(8, 1);
  590. des56to64((uint8_t*)t.key, ai->secret);
  591. ai->nsecret = 8;
  592. ai->suid = strdup(t.suid);
  593. ai->cuid = strdup(t.cuid);
  594. memset(authkey, 0, sizeof authkey);
  595. return ai;
  596. }
  597. /*
  598. static int
  599. noauth(int fd)
  600. {
  601. ealgs = nil;
  602. return fd;
  603. }
  604. static int
  605. srvnoauth(int fd, char *user)
  606. {
  607. strecpy(user, user+MaxStr, getuser());
  608. ealgs = nil;
  609. return fd;
  610. }
  611. */
  612. void
  613. loghex(uint8_t *p, int n)
  614. {
  615. char buf[100];
  616. int i;
  617. for(i = 0; i < n; i++)
  618. sprint(buf+2*i, "%2.2ux", p[i]);
  619. // syslog(0, "cpu", buf);
  620. }
  621. static int
  622. srvp9auth(int fd, char *user)
  623. {
  624. return -1;
  625. }
  626. /*
  627. * set authentication mechanism
  628. */
  629. int
  630. setam(char *name)
  631. {
  632. for(am = authmethod; am->name != nil; am++)
  633. if(strcmp(am->name, name) == 0)
  634. return 0;
  635. am = authmethod;
  636. return -1;
  637. }
  638. /*
  639. * set authentication mechanism and encryption/hash algs
  640. *
  641. int
  642. setamalg(char *s)
  643. {
  644. ealgs = strchr(s, ' ');
  645. if(ealgs != nil)
  646. *ealgs++ = 0;
  647. return setam(s);
  648. }
  649. */