chap.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * CHAP, MSCHAP
  3. *
  4. * The client does not authenticate the server, hence no CAI
  5. *
  6. * Client protocol:
  7. * unimplemented
  8. *
  9. * Server protocol:
  10. * read challenge: 8 bytes binary
  11. * write user: utf8
  12. * write response: Chapreply or MSchapreply structure
  13. */
  14. #include "dat.h"
  15. enum {
  16. ChapChallen = 8,
  17. };
  18. static int dochal(State*);
  19. static int doreply(State*, void*, int);
  20. struct State
  21. {
  22. char *protoname;
  23. int astype;
  24. int asfd;
  25. Key *key;
  26. Ticket t;
  27. Ticketreq tr;
  28. char chal[ChapChallen];
  29. char err[ERRMAX];
  30. char user[64];
  31. uchar secret[16]; /* for mschap */
  32. int nsecret;
  33. };
  34. enum
  35. {
  36. SHaveChal,
  37. SNeedUser,
  38. SNeedResp,
  39. SHaveZero,
  40. SHaveCAI,
  41. Maxphase
  42. };
  43. static char *phasenames[Maxphase] =
  44. {
  45. [SHaveChal] "SHaveChal",
  46. [SNeedUser] "SNeedUser",
  47. [SNeedResp] "SNeedResp",
  48. [SHaveZero] "SHaveZero",
  49. [SHaveCAI] "SHaveCAI",
  50. };
  51. static int
  52. chapinit(Proto *p, Fsstate *fss)
  53. {
  54. int iscli, ret;
  55. State *s;
  56. if((iscli = isclient(_str_findattr(fss->attr, "role"))) < 0)
  57. return failure(fss, nil);
  58. if(iscli)
  59. return failure(fss, "%s client not supported", p->name);
  60. s = emalloc(sizeof *s);
  61. fss->phasename = phasenames;
  62. fss->maxphase = Maxphase;
  63. s->asfd = -1;
  64. if(p == &chap){
  65. s->astype = AuthChap;
  66. s->protoname = "chap";
  67. }else{
  68. s->astype = AuthMSchap;
  69. s->protoname = "mschap";
  70. }
  71. if((ret = findp9authkey(&s->key, fss)) != RpcOk){
  72. free(s);
  73. return ret;
  74. }
  75. if(dochal(s) < 0){
  76. free(s);
  77. return failure(fss, nil);
  78. }
  79. fss->phase = SHaveChal;
  80. fss->ps = s;
  81. return RpcOk;
  82. }
  83. static void
  84. chapclose(Fsstate *fss)
  85. {
  86. State *s;
  87. s = fss->ps;
  88. if(s->asfd >= 0){
  89. close(s->asfd);
  90. s->asfd = -1;
  91. }
  92. free(s);
  93. }
  94. static int
  95. chapwrite(Fsstate *fss, void *va, uint n)
  96. {
  97. int nreply;
  98. void *reply;
  99. State *s;
  100. Chapreply cr;
  101. MSchapreply mcr;
  102. OChapreply ocr;
  103. OMSchapreply omcr;
  104. s = fss->ps;
  105. switch(fss->phase){
  106. default:
  107. return phaseerror(fss, "write");
  108. case SNeedUser:
  109. if(n >= sizeof s->user)
  110. return failure(fss, "user name too long");
  111. memmove(s->user, va, n);
  112. s->user[n] = '\0';
  113. fss->phase = SNeedResp;
  114. return RpcOk;
  115. case SNeedResp:
  116. switch(s->astype){
  117. default:
  118. return failure(fss, "chap internal botch");
  119. case AuthChap:
  120. if(n != sizeof(Chapreply))
  121. return failure(fss, "did not get Chapreply");
  122. memmove(&cr, va, sizeof cr);
  123. ocr.id = cr.id;
  124. memmove(ocr.resp, cr.resp, sizeof ocr.resp);
  125. strecpy(ocr.uid, ocr.uid+sizeof ocr.uid, s->user);
  126. reply = &ocr;
  127. nreply = sizeof ocr;
  128. break;
  129. case AuthMSchap:
  130. if(n != sizeof(MSchapreply))
  131. return failure(fss, "did not get MSchapreply");
  132. memmove(&mcr, va, sizeof mcr);
  133. memmove(omcr.LMresp, mcr.LMresp, sizeof omcr.LMresp);
  134. memmove(omcr.NTresp, mcr.NTresp, sizeof omcr.NTresp);
  135. strecpy(omcr.uid, omcr.uid+sizeof omcr.uid, s->user);
  136. reply = &omcr;
  137. nreply = sizeof omcr;
  138. break;
  139. }
  140. if(doreply(s, reply, nreply) < 0)
  141. return failure(fss, nil);
  142. fss->phase = Established;
  143. fss->ai.cuid = s->t.cuid;
  144. fss->ai.suid = s->t.suid;
  145. fss->ai.secret = s->secret;
  146. fss->ai.nsecret = s->nsecret;
  147. fss->haveai = 1;
  148. return RpcOk;
  149. }
  150. }
  151. static int
  152. chapread(Fsstate *fss, void *va, uint *n)
  153. {
  154. State *s;
  155. s = fss->ps;
  156. switch(fss->phase){
  157. default:
  158. return phaseerror(fss, "read");
  159. case SHaveChal:
  160. if(*n > sizeof s->chal)
  161. *n = sizeof s->chal;
  162. memmove(va, s->chal, *n);
  163. fss->phase = SNeedUser;
  164. return RpcOk;
  165. }
  166. }
  167. static int
  168. dochal(State *s)
  169. {
  170. char *dom, *user;
  171. char trbuf[TICKREQLEN];
  172. s->asfd = -1;
  173. /* send request to authentication server and get challenge */
  174. if((dom = _str_findattr(s->key->attr, "dom")) == nil
  175. || (user = _str_findattr(s->key->attr, "user")) == nil){
  176. werrstr("chap/dochal cannot happen");
  177. goto err;
  178. }
  179. s->asfd = _authdial(nil, dom);
  180. if(s->asfd < 0)
  181. goto err;
  182. memset(&s->tr, 0, sizeof(s->tr));
  183. s->tr.type = s->astype;
  184. safecpy(s->tr.authdom, dom, sizeof s->tr.authdom);
  185. safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
  186. convTR2M(&s->tr, trbuf);
  187. if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
  188. goto err;
  189. /* readn, not _asrdresp. needs to match auth.srv.c. */
  190. if(readn(s->asfd, s->chal, sizeof s->chal) != sizeof s->chal)
  191. goto err;
  192. return 0;
  193. err:
  194. if(s->asfd >= 0)
  195. close(s->asfd);
  196. s->asfd = -1;
  197. return -1;
  198. }
  199. static int
  200. doreply(State *s, void *reply, int nreply)
  201. {
  202. char ticket[TICKETLEN+AUTHENTLEN];
  203. int n;
  204. Authenticator a;
  205. if((n=write(s->asfd, reply, nreply)) != nreply){
  206. if(n >= 0)
  207. werrstr("short write to auth server");
  208. goto err;
  209. }
  210. if(_asrdresp(s->asfd, ticket, TICKETLEN+AUTHENTLEN) < 0){
  211. /* leave connection open so we can try again */
  212. return -1;
  213. }
  214. s->nsecret = readn(s->asfd, s->secret, sizeof s->secret);
  215. if(s->nsecret < 0)
  216. s->nsecret = 0;
  217. close(s->asfd);
  218. s->asfd = -1;
  219. convM2T(ticket, &s->t, s->key->priv);
  220. if(s->t.num != AuthTs
  221. || memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
  222. werrstr(Easproto);
  223. return -1;
  224. }
  225. convM2A(ticket+TICKETLEN, &a, s->t.key);
  226. if(a.num != AuthAc
  227. || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
  228. || a.id != 0){
  229. werrstr(Easproto);
  230. return -1;
  231. }
  232. return 0;
  233. err:
  234. if(s->asfd >= 0)
  235. close(s->asfd);
  236. s->asfd = -1;
  237. return -1;
  238. }
  239. Proto chap = {
  240. .name= "chap",
  241. .init= chapinit,
  242. .write= chapwrite,
  243. .read= chapread,
  244. .close= chapclose,
  245. };
  246. Proto mschap = {
  247. .name= "mschap",
  248. .init= chapinit,
  249. .write= chapwrite,
  250. .read= chapread,
  251. .close= chapclose,
  252. };