p9sk1.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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. * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
  11. * p9sk2 is an incomplete flawed variant of p9sk1.
  12. *
  13. * Client protocol:
  14. * write challenge[challen] (p9sk1 only)
  15. * read tickreq[tickreqlen]
  16. * write ticket[ticketlen]
  17. * read authenticator[authentlen]
  18. *
  19. * Server protocol:
  20. * read challenge[challen] (p9sk1 only)
  21. * write tickreq[tickreqlen]
  22. * read ticket[ticketlen]
  23. * write authenticator[authentlen]
  24. */
  25. #include "dat.h"
  26. struct State
  27. {
  28. int vers;
  29. Key *key;
  30. Ticket t;
  31. Ticketreq tr;
  32. char cchal[CHALLEN];
  33. char tbuf[TICKETLEN+AUTHENTLEN];
  34. char authkey[DESKEYLEN];
  35. uint8_t *secret;
  36. int speakfor;
  37. };
  38. enum
  39. {
  40. /* client phases */
  41. CHaveChal,
  42. CNeedTreq,
  43. CHaveTicket,
  44. CNeedAuth,
  45. /* server phases */
  46. SNeedChal,
  47. SHaveTreq,
  48. SNeedTicket,
  49. SHaveAuth,
  50. Maxphase,
  51. };
  52. static char *phasenames[Maxphase] =
  53. {
  54. [CHaveChal] = "CHaveChal",
  55. [CNeedTreq] = "CNeedTreq",
  56. [CHaveTicket] = "CHaveTicket",
  57. [CNeedAuth] = "CNeedAuth",
  58. [SNeedChal] = "SNeedChal",
  59. [SHaveTreq] = "SHaveTreq",
  60. [SNeedTicket] = "SNeedTicket",
  61. [SHaveAuth] = "SHaveAuth",
  62. };
  63. static int gettickets(State*, char*, char*);
  64. static int
  65. p9skinit(Proto *p, Fsstate *fss)
  66. {
  67. State *s;
  68. int iscli, ret;
  69. Key *k;
  70. Keyinfo ki;
  71. Attr *attr;
  72. if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
  73. return failure(fss, nil);
  74. s = emalloc(sizeof *s);
  75. fss->phasename = phasenames;
  76. fss->maxphase = Maxphase;
  77. if(p == &p9sk1)
  78. s->vers = 1;
  79. else if(p == &p9sk2)
  80. s->vers = 2;
  81. else
  82. abort();
  83. if(iscli){
  84. switch(s->vers){
  85. case 1:
  86. fss->phase = CHaveChal;
  87. memrandom(s->cchal, CHALLEN);
  88. break;
  89. case 2:
  90. fss->phase = CNeedTreq;
  91. break;
  92. }
  93. }else{
  94. s->tr.type = AuthTreq;
  95. attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
  96. mkkeyinfo(&ki, fss, attr);
  97. ki.user = nil;
  98. ret = findkey(&k, &ki, "user? dom?");
  99. _freeattr(attr);
  100. if(ret != RpcOk){
  101. free(s);
  102. return ret;
  103. }
  104. safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid));
  105. safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom));
  106. s->key = k;
  107. memrandom(s->tr.chal, sizeof s->tr.chal);
  108. switch(s->vers){
  109. case 1:
  110. fss->phase = SNeedChal;
  111. break;
  112. case 2:
  113. fss->phase = SHaveTreq;
  114. memmove(s->cchal, s->tr.chal, CHALLEN);
  115. break;
  116. }
  117. }
  118. fss->ps = s;
  119. return RpcOk;
  120. }
  121. static int
  122. p9skread(Fsstate *fss, void *a, uint *n)
  123. {
  124. int m;
  125. State *s;
  126. s = fss->ps;
  127. switch(fss->phase){
  128. default:
  129. return phaseerror(fss, "read");
  130. case CHaveChal:
  131. m = CHALLEN;
  132. if(*n < m)
  133. return toosmall(fss, m);
  134. *n = m;
  135. memmove(a, s->cchal, m);
  136. fss->phase = CNeedTreq;
  137. return RpcOk;
  138. case SHaveTreq:
  139. m = TICKREQLEN;
  140. if(*n < m)
  141. return toosmall(fss, m);
  142. *n = m;
  143. convTR2M(&s->tr, a);
  144. fss->phase = SNeedTicket;
  145. return RpcOk;
  146. case CHaveTicket:
  147. m = TICKETLEN+AUTHENTLEN;
  148. if(*n < m)
  149. return toosmall(fss, m);
  150. *n = m;
  151. memmove(a, s->tbuf, m);
  152. fss->phase = CNeedAuth;
  153. return RpcOk;
  154. case SHaveAuth:
  155. m = AUTHENTLEN;
  156. if(*n < m)
  157. return toosmall(fss, m);
  158. *n = m;
  159. memmove(a, s->tbuf+TICKETLEN, m);
  160. fss->ai.cuid = s->t.cuid;
  161. fss->ai.suid = s->t.suid;
  162. s->secret = emalloc(8);
  163. des56to64((uint8_t*)s->t.key, s->secret);
  164. fss->ai.secret = s->secret;
  165. fss->ai.nsecret = 8;
  166. fss->haveai = 1;
  167. fss->phase = Established;
  168. return RpcOk;
  169. }
  170. }
  171. static int
  172. p9skwrite(Fsstate *fss, void *a, uint n)
  173. {
  174. int m, ret, sret;
  175. char tbuf[2*TICKETLEN], trbuf[TICKREQLEN], *user;
  176. Attr *attr;
  177. Authenticator auth;
  178. State *s;
  179. Key *srvkey;
  180. Keyinfo ki;
  181. s = fss->ps;
  182. switch(fss->phase){
  183. default:
  184. return phaseerror(fss, "write");
  185. case SNeedChal:
  186. m = CHALLEN;
  187. if(n < m)
  188. return toosmall(fss, m);
  189. memmove(s->cchal, a, m);
  190. fss->phase = SHaveTreq;
  191. return RpcOk;
  192. case CNeedTreq:
  193. m = TICKREQLEN;
  194. if(n < m)
  195. return toosmall(fss, m);
  196. /* remember server's chal */
  197. convM2TR(a, &s->tr);
  198. if(s->vers == 2)
  199. memmove(s->cchal, s->tr.chal, CHALLEN);
  200. if(s->key != nil)
  201. closekey(s->key);
  202. attr = _delattr(_delattr(_copyattr(fss->attr), "role"), "user");
  203. attr = setattr(attr, "proto=p9sk1");
  204. user = _strfindattr(fss->attr, "user");
  205. /*
  206. * If our client is the user who started factotum (client==owner), then
  207. * he can use whatever keys we have to speak as whoever he pleases.
  208. * If, on the other hand, we're speaking on behalf of someone else,
  209. * we will only vouch for their name on the local system.
  210. *
  211. * We do the sysuser findkey second so that if we return RpcNeedkey,
  212. * the correct key information gets asked for.
  213. */
  214. srvkey = nil;
  215. s->speakfor = 0;
  216. sret = RpcFailure;
  217. if(user==nil || strcmp(user, fss->sysuser) == 0){
  218. mkkeyinfo(&ki, fss, attr);
  219. ki.user = nil;
  220. sret = findkey(&srvkey, &ki,
  221. "role=speakfor dom=%q user?", s->tr.authdom);
  222. }
  223. if(user != nil)
  224. attr = setattr(attr, "user=%q", user);
  225. mkkeyinfo(&ki, fss, attr);
  226. ret = findkey(&s->key, &ki,
  227. "role=client dom=%q %s", s->tr.authdom, p9sk1.keyprompt);
  228. if(ret == RpcOk)
  229. closekey(srvkey);
  230. else if(sret == RpcOk){
  231. s->key = srvkey;
  232. s->speakfor = 1;
  233. }else if(ret == RpcConfirm || sret == RpcConfirm){
  234. _freeattr(attr);
  235. return RpcConfirm;
  236. }else{
  237. _freeattr(attr);
  238. return ret;
  239. }
  240. /* fill in the rest of the request */
  241. s->tr.type = AuthTreq;
  242. safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid);
  243. if(s->speakfor)
  244. safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid);
  245. else
  246. safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
  247. convTR2M(&s->tr, trbuf);
  248. /* get tickets, from auth server or invent if we can */
  249. if(gettickets(s, trbuf, tbuf) < 0){
  250. _freeattr(attr);
  251. return failure(fss, nil);
  252. }
  253. convM2T(tbuf, &s->t, (char*)s->key->priv);
  254. if(s->t.num != AuthTc){
  255. if(s->key->successes == 0 && !s->speakfor)
  256. disablekey(s->key);
  257. if(askforkeys && !s->speakfor){
  258. snprint(fss->keyinfo, sizeof fss->keyinfo,
  259. "%A %s", attr, p9sk1.keyprompt);
  260. _freeattr(attr);
  261. return RpcNeedkey;
  262. }else{
  263. _freeattr(attr);
  264. return failure(fss, Ebadkey);
  265. }
  266. }
  267. s->key->successes++;
  268. _freeattr(attr);
  269. memmove(s->tbuf, tbuf+TICKETLEN, TICKETLEN);
  270. auth.num = AuthAc;
  271. memmove(auth.chal, s->tr.chal, CHALLEN);
  272. auth.id = 0;
  273. convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
  274. fss->phase = CHaveTicket;
  275. return RpcOk;
  276. case SNeedTicket:
  277. m = TICKETLEN+AUTHENTLEN;
  278. if(n < m)
  279. return toosmall(fss, m);
  280. convM2T(a, &s->t, (char*)s->key->priv);
  281. if(s->t.num != AuthTs
  282. || memcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
  283. return failure(fss, Easproto);
  284. convM2A((char*)a+TICKETLEN, &auth, s->t.key);
  285. if(auth.num != AuthAc
  286. || memcmp(auth.chal, s->tr.chal, CHALLEN) != 0
  287. || auth.id != 0)
  288. return failure(fss, Easproto);
  289. auth.num = AuthAs;
  290. memmove(auth.chal, s->cchal, CHALLEN);
  291. auth.id = 0;
  292. convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
  293. fss->phase = SHaveAuth;
  294. return RpcOk;
  295. case CNeedAuth:
  296. m = AUTHENTLEN;
  297. if(n < m)
  298. return toosmall(fss, m);
  299. convM2A(a, &auth, s->t.key);
  300. if(auth.num != AuthAs
  301. || memcmp(auth.chal, s->cchal, CHALLEN) != 0
  302. || auth.id != 0)
  303. return failure(fss, Easproto);
  304. fss->ai.cuid = s->t.cuid;
  305. fss->ai.suid = s->t.suid;
  306. s->secret = emalloc(8);
  307. des56to64((uint8_t*)s->t.key, s->secret);
  308. fss->ai.secret = s->secret;
  309. fss->ai.nsecret = 8;
  310. fss->haveai = 1;
  311. fss->phase = Established;
  312. return RpcOk;
  313. }
  314. }
  315. static void
  316. p9skclose(Fsstate *fss)
  317. {
  318. State *s;
  319. s = fss->ps;
  320. if(s->secret != nil){
  321. free(s->secret);
  322. s->secret = nil;
  323. }
  324. if(s->key != nil){
  325. closekey(s->key);
  326. s->key = nil;
  327. }
  328. free(s);
  329. }
  330. static int
  331. unhex(char c)
  332. {
  333. if('0' <= c && c <= '9')
  334. return c-'0';
  335. if('a' <= c && c <= 'f')
  336. return c-'a'+10;
  337. if('A' <= c && c <= 'F')
  338. return c-'A'+10;
  339. abort();
  340. return -1;
  341. }
  342. static int
  343. hexparse(char *hex, uint8_t *dat, int ndat)
  344. {
  345. int i;
  346. if(strlen(hex) != 2*ndat)
  347. return -1;
  348. if(hex[strspn(hex, "0123456789abcdefABCDEF")] != '\0')
  349. return -1;
  350. for(i=0; i<ndat; i++)
  351. dat[i] = (unhex(hex[2*i])<<4)|unhex(hex[2*i+1]);
  352. return 0;
  353. }
  354. static int
  355. p9skaddkey(Key *k, int before)
  356. {
  357. char *s;
  358. k->priv = emalloc(DESKEYLEN);
  359. if((s = _strfindattr(k->privattr, "!hex")) != nil){
  360. if(hexparse(s, k->priv, 7) < 0){
  361. free(k->priv);
  362. k->priv = nil;
  363. werrstr("malformed key data");
  364. return -1;
  365. }
  366. }else if((s = _strfindattr(k->privattr, "!password")) != nil){
  367. passtokey((char*)k->priv, s);
  368. }else{
  369. werrstr("no key data");
  370. free(k->priv);
  371. k->priv = nil;
  372. return -1;
  373. }
  374. return replacekey(k, before);
  375. }
  376. static void
  377. p9skclosekey(Key *k)
  378. {
  379. free(k->priv);
  380. }
  381. static int
  382. getastickets(State *s, char *trbuf, char *tbuf)
  383. {
  384. int asfd, rv;
  385. char *dom;
  386. if((dom = _strfindattr(s->key->attr, "dom")) == nil){
  387. werrstr("auth key has no domain");
  388. return -1;
  389. }
  390. asfd = _authdial(nil, dom);
  391. if(asfd < 0)
  392. return -1;
  393. rv = _asgetticket(asfd, trbuf, tbuf);
  394. close(asfd);
  395. return rv;
  396. }
  397. static int
  398. mkserverticket(State *s, char *tbuf)
  399. {
  400. Ticketreq *tr = &s->tr;
  401. Ticket t;
  402. if(strcmp(tr->authid, tr->hostid) != 0)
  403. return -1;
  404. /* this keeps creating accounts on martha from working. -- presotto
  405. if(strcmp(tr->uid, "none") == 0)
  406. return -1;
  407. */
  408. memset(&t, 0, sizeof(t));
  409. memmove(t.chal, tr->chal, CHALLEN);
  410. strcpy(t.cuid, tr->uid);
  411. strcpy(t.suid, tr->uid);
  412. memrandom(t.key, DESKEYLEN);
  413. t.num = AuthTc;
  414. convT2M(&t, tbuf, s->key->priv);
  415. t.num = AuthTs;
  416. convT2M(&t, tbuf+TICKETLEN, s->key->priv);
  417. return 0;
  418. }
  419. static int
  420. gettickets(State *s, char *trbuf, char *tbuf)
  421. {
  422. /*
  423. if(mktickets(s, trbuf, tbuf) >= 0)
  424. return 0;
  425. */
  426. if(getastickets(s, trbuf, tbuf) >= 0)
  427. return 0;
  428. return mkserverticket(s, tbuf);
  429. }
  430. Proto p9sk1 = {
  431. .name= "p9sk1",
  432. .init= p9skinit,
  433. .write= p9skwrite,
  434. .read= p9skread,
  435. .close= p9skclose,
  436. .addkey= p9skaddkey,
  437. .closekey= p9skclosekey,
  438. .keyprompt= "user? !password?"
  439. };
  440. Proto p9sk2 = {
  441. .name= "p9sk2",
  442. .init= p9skinit,
  443. .write= p9skwrite,
  444. .read= p9skread,
  445. .close= p9skclose,
  446. };