p9cr.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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. * p9cr, vnc - textual challenge/response authentication
  11. *
  12. * Client protocol: [currently unimplemented]
  13. * write challenge
  14. * read response
  15. *
  16. * Server protocol:
  17. * write user
  18. * read challenge
  19. * write response
  20. */
  21. #include "dat.h"
  22. enum
  23. {
  24. Maxchal= 64,
  25. };
  26. typedef struct State State;
  27. struct State
  28. {
  29. Key *key;
  30. int astype;
  31. int asfd;
  32. Ticket t;
  33. Ticketreq tr;
  34. char chal[Maxchal];
  35. int challen;
  36. char resp[Maxchal];
  37. int resplen;
  38. };
  39. enum
  40. {
  41. CNeedChal,
  42. CHaveResp,
  43. SHaveChal,
  44. SNeedResp,
  45. Maxphase,
  46. };
  47. static char *phasenames[Maxphase] =
  48. {
  49. [CNeedChal] "CNeedChal",
  50. [CHaveResp] "CHaveResp",
  51. [SHaveChal] "SHaveChal",
  52. [SNeedResp] "SNeedResp",
  53. };
  54. static void
  55. p9crclose(Fsstate *fss)
  56. {
  57. State *s;
  58. s = fss->ps;
  59. if(s->asfd >= 0){
  60. close(s->asfd);
  61. s->asfd = -1;
  62. }
  63. free(s);
  64. }
  65. static int getchal(State*, Fsstate*);
  66. static int
  67. p9crinit(Proto *p, Fsstate *fss)
  68. {
  69. int iscli, ret;
  70. char *user;
  71. State *s;
  72. Attr *attr;
  73. Keyinfo ki;
  74. if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
  75. return failure(fss, nil);
  76. s = emalloc(sizeof(*s));
  77. s->asfd = -1;
  78. if(p == &p9cr){
  79. s->astype = AuthChal;
  80. s->challen = NETCHLEN;
  81. }else if(p == &vnc){
  82. s->astype = AuthVNC;
  83. s->challen = Maxchal;
  84. }else
  85. abort();
  86. if(iscli){
  87. fss->phase = CNeedChal;
  88. if(p == &p9cr)
  89. attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
  90. else
  91. attr = nil;
  92. ret = findkey(&s->key, mkkeyinfo(&ki, fss, attr),
  93. "role=client %s", p->keyprompt);
  94. _freeattr(attr);
  95. if(ret != RpcOk){
  96. free(s);
  97. return ret;
  98. }
  99. fss->ps = s;
  100. }else{
  101. if((ret = findp9authkey(&s->key, fss)) != RpcOk){
  102. free(s);
  103. return ret;
  104. }
  105. if((user = _strfindattr(fss->attr, "user")) == nil){
  106. free(s);
  107. return failure(fss, "no user name specified in start msg");
  108. }
  109. if(strlen(user) >= sizeof s->tr.uid){
  110. free(s);
  111. return failure(fss, "user name too long");
  112. }
  113. fss->ps = s;
  114. strcpy(s->tr.uid, user);
  115. ret = getchal(s, fss);
  116. if(ret != RpcOk){
  117. p9crclose(fss); /* frees s */
  118. fss->ps = nil;
  119. }
  120. }
  121. fss->phasename = phasenames;
  122. fss->maxphase = Maxphase;
  123. return ret;
  124. }
  125. static int
  126. p9crread(Fsstate *fss, void *va, uint *n)
  127. {
  128. int m;
  129. State *s;
  130. s = fss->ps;
  131. switch(fss->phase){
  132. default:
  133. return phaseerror(fss, "read");
  134. case CHaveResp:
  135. if(s->resplen < *n)
  136. *n = s->resplen;
  137. memmove(va, s->resp, *n);
  138. fss->phase = Established;
  139. return RpcOk;
  140. case SHaveChal:
  141. if(s->astype == AuthChal)
  142. m = strlen(s->chal); /* ascii string */
  143. else
  144. m = s->challen; /* fixed length binary */
  145. if(m > *n)
  146. return toosmall(fss, m);
  147. *n = m;
  148. memmove(va, s->chal, m);
  149. fss->phase = SNeedResp;
  150. return RpcOk;
  151. }
  152. }
  153. static int
  154. p9response(Fsstate *fss, State *s)
  155. {
  156. char key[DESKEYLEN];
  157. uint8_t buf[8];
  158. uint32_t chal;
  159. char *pw;
  160. pw = _strfindattr(s->key->privattr, "!password");
  161. if(pw == nil)
  162. return failure(fss, "vncresponse cannot happen");
  163. passtokey(key, pw);
  164. memset(buf, 0, 8);
  165. snprint((char*)buf, sizeof buf, "%d", atoi(s->chal));
  166. if(encrypt(key, buf, 8) < 0)
  167. return failure(fss, "can't encrypt response");
  168. chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
  169. s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal);
  170. return RpcOk;
  171. }
  172. static uint8_t tab[256];
  173. /* VNC reverses the bits of each byte before using as a des key */
  174. static void
  175. mktab(void)
  176. {
  177. int i, j, k;
  178. static int once;
  179. if(once)
  180. return;
  181. once = 1;
  182. for(i=0; i<256; i++) {
  183. j=i;
  184. tab[i] = 0;
  185. for(k=0; k<8; k++) {
  186. tab[i] = (tab[i]<<1) | (j&1);
  187. j >>= 1;
  188. }
  189. }
  190. }
  191. static int
  192. vncaddkey(Key *k, int before)
  193. {
  194. uint8_t *p;
  195. char *s;
  196. k->priv = emalloc(8+1);
  197. if(s = _strfindattr(k->privattr, "!password")){
  198. mktab();
  199. memset(k->priv, 0, 8+1);
  200. strncpy((char*)k->priv, s, 8);
  201. for(p=k->priv; *p; p++)
  202. *p = tab[*p];
  203. }else{
  204. werrstr("no key data");
  205. return -1;
  206. }
  207. return replacekey(k, before);
  208. }
  209. static int
  210. vncresponse(Fsstate* f, State *s)
  211. {
  212. DESstate des;
  213. memmove(s->resp, s->chal, sizeof s->chal);
  214. setupDESstate(&des, s->key->priv, nil);
  215. desECBencrypt((uint8_t*)s->resp, s->challen, &des);
  216. s->resplen = s->challen;
  217. return RpcOk;
  218. }
  219. static int
  220. p9crwrite(Fsstate *fss, void *va, uint n)
  221. {
  222. char tbuf[TICKETLEN+AUTHENTLEN];
  223. State *s;
  224. char *data = va;
  225. Authenticator a;
  226. char resp[Maxchal];
  227. int ret;
  228. s = fss->ps;
  229. switch(fss->phase){
  230. default:
  231. return phaseerror(fss, "write");
  232. case CNeedChal:
  233. if(n >= sizeof(s->chal))
  234. return failure(fss, Ebadarg);
  235. memset(s->chal, 0, sizeof s->chal);
  236. memmove(s->chal, data, n);
  237. s->challen = n;
  238. if(s->astype == AuthChal)
  239. ret = p9response(fss, s);
  240. else
  241. ret = vncresponse(fss, s);
  242. if(ret != RpcOk)
  243. return ret;
  244. fss->phase = CHaveResp;
  245. return RpcOk;
  246. case SNeedResp:
  247. /* send response to auth server and get ticket */
  248. if(n > sizeof(resp))
  249. return failure(fss, Ebadarg);
  250. memset(resp, 0, sizeof resp);
  251. memmove(resp, data, n);
  252. if(write(s->asfd, resp, s->challen) != s->challen)
  253. return failure(fss, Easproto);
  254. /* get ticket plus authenticator from auth server */
  255. if(_asrdresp(s->asfd, tbuf, TICKETLEN+AUTHENTLEN) < 0)
  256. return failure(fss, nil);
  257. /* check ticket */
  258. convM2T(tbuf, &s->t, s->key->priv);
  259. if(s->t.num != AuthTs
  260. || memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
  261. if (s->key->successes == 0)
  262. disablekey(s->key);
  263. return failure(fss, Easproto);
  264. }
  265. s->key->successes++;
  266. convM2A(tbuf+TICKETLEN, &a, s->t.key);
  267. if(a.num != AuthAc
  268. || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
  269. || a.id != 0)
  270. return failure(fss, Easproto);
  271. fss->haveai = 1;
  272. fss->ai.cuid = s->t.cuid;
  273. fss->ai.suid = s->t.suid;
  274. fss->ai.nsecret = 0;
  275. fss->ai.secret = nil;
  276. fss->phase = Established;
  277. return RpcOk;
  278. }
  279. }
  280. static int
  281. getchal(State *s, Fsstate *fss)
  282. {
  283. char trbuf[TICKREQLEN];
  284. int n;
  285. safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof(s->tr.hostid));
  286. safecpy(s->tr.authdom, _strfindattr(s->key->attr, "dom"), sizeof(s->tr.authdom));
  287. s->tr.type = s->astype;
  288. convTR2M(&s->tr, trbuf);
  289. /* get challenge from auth server */
  290. s->asfd = _authdial(nil, _strfindattr(s->key->attr, "dom"));
  291. if(s->asfd < 0)
  292. return failure(fss, Easproto);
  293. if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
  294. return failure(fss, Easproto);
  295. n = _asrdresp(s->asfd, s->chal, s->challen);
  296. if(n <= 0){
  297. if(n == 0)
  298. werrstr("_asrdresp short read");
  299. return failure(fss, nil);
  300. }
  301. s->challen = n;
  302. fss->phase = SHaveChal;
  303. return RpcOk;
  304. }
  305. Proto p9cr =
  306. {
  307. .name= "p9cr",
  308. .init= p9crinit,
  309. .write= p9crwrite,
  310. .read= p9crread,
  311. .close= p9crclose,
  312. .keyprompt= "user? !password?",
  313. };
  314. Proto vnc =
  315. {
  316. .name= "vnc",
  317. .init= p9crinit,
  318. .write= p9crwrite,
  319. .read= p9crread,
  320. .close= p9crclose,
  321. .keyprompt= "!password?",
  322. .addkey= vncaddkey,
  323. };