chap.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
  2. /*****************************************************************************
  3. * chap.c - Network Challenge Handshake Authentication Protocol program file.
  4. *
  5. * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
  6. * portions Copyright (c) 1997 by Global Election Systems Inc.
  7. *
  8. * The authors hereby grant permission to use, copy, modify, distribute,
  9. * and license this software and its documentation for any purpose, provided
  10. * that existing copyright notices are retained in all copies and that this
  11. * notice and the following disclaimer are included verbatim in any
  12. * distributions. No written agreement, license, or royalty fee is required
  13. * for any of the authorized uses.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. ******************************************************************************
  27. * REVISION HISTORY
  28. *
  29. * 03-01-01 Marc Boucher <marc@mbsi.ca>
  30. * Ported to lwIP.
  31. * 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
  32. * Original based on BSD chap.c.
  33. *****************************************************************************/
  34. /*
  35. * chap.c - Challenge Handshake Authentication Protocol.
  36. *
  37. * Copyright (c) 1993 The Australian National University.
  38. * All rights reserved.
  39. *
  40. * Redistribution and use in source and binary forms are permitted
  41. * provided that the above copyright notice and this paragraph are
  42. * duplicated in all such forms and that any documentation,
  43. * advertising materials, and other materials related to such
  44. * distribution and use acknowledge that the software was developed
  45. * by the Australian National University. The name of the University
  46. * may not be used to endorse or promote products derived from this
  47. * software without specific prior written permission.
  48. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  49. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  50. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  51. *
  52. * Copyright (c) 1991 Gregory M. Christy.
  53. * All rights reserved.
  54. *
  55. * Redistribution and use in source and binary forms are permitted
  56. * provided that the above copyright notice and this paragraph are
  57. * duplicated in all such forms and that any documentation,
  58. * advertising materials, and other materials related to such
  59. * distribution and use acknowledge that the software was developed
  60. * by Gregory M. Christy. The name of the author may not be used to
  61. * endorse or promote products derived from this software without
  62. * specific prior written permission.
  63. *
  64. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  65. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  66. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  67. */
  68. #include "lwip/opt.h"
  69. #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
  70. #if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
  71. #include "ppp_impl.h"
  72. #include "pppdebug.h"
  73. #include "magic.h"
  74. #include "randm.h"
  75. #include "auth.h"
  76. #include "md5.h"
  77. #include "chap.h"
  78. #include "chpms.h"
  79. #include <string.h>
  80. #if 0 /* UNUSED */
  81. /*
  82. * Command-line options.
  83. */
  84. static option_t chap_option_list[] = {
  85. { "chap-restart", o_int, &chap[0].timeouttime,
  86. "Set timeout for CHAP" },
  87. { "chap-max-challenge", o_int, &chap[0].max_transmits,
  88. "Set max #xmits for challenge" },
  89. { "chap-interval", o_int, &chap[0].chal_interval,
  90. "Set interval for rechallenge" },
  91. #ifdef MSLANMAN
  92. { "ms-lanman", o_bool, &ms_lanman,
  93. "Use LanMan passwd when using MS-CHAP", 1 },
  94. #endif
  95. { NULL }
  96. };
  97. #endif /* UNUSED */
  98. /*
  99. * Protocol entry points.
  100. */
  101. static void ChapInit (int);
  102. static void ChapLowerUp (int);
  103. static void ChapLowerDown (int);
  104. static void ChapInput (int, u_char *, int);
  105. static void ChapProtocolReject (int);
  106. #if PPP_ADDITIONAL_CALLBACKS
  107. static int ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
  108. #endif
  109. struct protent chap_protent = {
  110. PPP_CHAP,
  111. ChapInit,
  112. ChapInput,
  113. ChapProtocolReject,
  114. ChapLowerUp,
  115. ChapLowerDown,
  116. NULL,
  117. NULL,
  118. #if PPP_ADDITIONAL_CALLBACKS
  119. ChapPrintPkt,
  120. NULL,
  121. #endif /* PPP_ADDITIONAL_CALLBACKS */
  122. 1,
  123. "CHAP",
  124. #if PPP_ADDITIONAL_CALLBACKS
  125. NULL,
  126. NULL,
  127. NULL
  128. #endif /* PPP_ADDITIONAL_CALLBACKS */
  129. };
  130. chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
  131. static void ChapChallengeTimeout (void *);
  132. static void ChapResponseTimeout (void *);
  133. static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int);
  134. static void ChapRechallenge (void *);
  135. static void ChapReceiveResponse (chap_state *, u_char *, int, int);
  136. static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
  137. static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
  138. static void ChapSendStatus (chap_state *, int);
  139. static void ChapSendChallenge (chap_state *);
  140. static void ChapSendResponse (chap_state *);
  141. static void ChapGenChallenge (chap_state *);
  142. /*
  143. * ChapInit - Initialize a CHAP unit.
  144. */
  145. static void
  146. ChapInit(int unit)
  147. {
  148. chap_state *cstate = &chap[unit];
  149. BZERO(cstate, sizeof(*cstate));
  150. cstate->unit = unit;
  151. cstate->clientstate = CHAPCS_INITIAL;
  152. cstate->serverstate = CHAPSS_INITIAL;
  153. cstate->timeouttime = CHAP_DEFTIMEOUT;
  154. cstate->max_transmits = CHAP_DEFTRANSMITS;
  155. /* random number generator is initialized in magic_init */
  156. }
  157. /*
  158. * ChapAuthWithPeer - Authenticate us with our peer (start client).
  159. *
  160. */
  161. void
  162. ChapAuthWithPeer(int unit, char *our_name, u_char digest)
  163. {
  164. chap_state *cstate = &chap[unit];
  165. cstate->resp_name = our_name;
  166. cstate->resp_type = digest;
  167. if (cstate->clientstate == CHAPCS_INITIAL ||
  168. cstate->clientstate == CHAPCS_PENDING) {
  169. /* lower layer isn't up - wait until later */
  170. cstate->clientstate = CHAPCS_PENDING;
  171. return;
  172. }
  173. /*
  174. * We get here as a result of LCP coming up.
  175. * So even if CHAP was open before, we will
  176. * have to re-authenticate ourselves.
  177. */
  178. cstate->clientstate = CHAPCS_LISTEN;
  179. }
  180. /*
  181. * ChapAuthPeer - Authenticate our peer (start server).
  182. */
  183. void
  184. ChapAuthPeer(int unit, char *our_name, u_char digest)
  185. {
  186. chap_state *cstate = &chap[unit];
  187. cstate->chal_name = our_name;
  188. cstate->chal_type = digest;
  189. if (cstate->serverstate == CHAPSS_INITIAL ||
  190. cstate->serverstate == CHAPSS_PENDING) {
  191. /* lower layer isn't up - wait until later */
  192. cstate->serverstate = CHAPSS_PENDING;
  193. return;
  194. }
  195. ChapGenChallenge(cstate);
  196. ChapSendChallenge(cstate); /* crank it up dude! */
  197. cstate->serverstate = CHAPSS_INITIAL_CHAL;
  198. }
  199. /*
  200. * ChapChallengeTimeout - Timeout expired on sending challenge.
  201. */
  202. static void
  203. ChapChallengeTimeout(void *arg)
  204. {
  205. chap_state *cstate = (chap_state *) arg;
  206. /* if we aren't sending challenges, don't worry. then again we */
  207. /* probably shouldn't be here either */
  208. if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
  209. cstate->serverstate != CHAPSS_RECHALLENGE) {
  210. return;
  211. }
  212. if (cstate->chal_transmits >= cstate->max_transmits) {
  213. /* give up on peer */
  214. CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n"));
  215. cstate->serverstate = CHAPSS_BADAUTH;
  216. auth_peer_fail(cstate->unit, PPP_CHAP);
  217. return;
  218. }
  219. ChapSendChallenge(cstate); /* Re-send challenge */
  220. }
  221. /*
  222. * ChapResponseTimeout - Timeout expired on sending response.
  223. */
  224. static void
  225. ChapResponseTimeout(void *arg)
  226. {
  227. chap_state *cstate = (chap_state *) arg;
  228. /* if we aren't sending a response, don't worry. */
  229. if (cstate->clientstate != CHAPCS_RESPONSE) {
  230. return;
  231. }
  232. ChapSendResponse(cstate); /* re-send response */
  233. }
  234. /*
  235. * ChapRechallenge - Time to challenge the peer again.
  236. */
  237. static void
  238. ChapRechallenge(void *arg)
  239. {
  240. chap_state *cstate = (chap_state *) arg;
  241. /* if we aren't sending a response, don't worry. */
  242. if (cstate->serverstate != CHAPSS_OPEN) {
  243. return;
  244. }
  245. ChapGenChallenge(cstate);
  246. ChapSendChallenge(cstate);
  247. cstate->serverstate = CHAPSS_RECHALLENGE;
  248. }
  249. /*
  250. * ChapLowerUp - The lower layer is up.
  251. *
  252. * Start up if we have pending requests.
  253. */
  254. static void
  255. ChapLowerUp(int unit)
  256. {
  257. chap_state *cstate = &chap[unit];
  258. if (cstate->clientstate == CHAPCS_INITIAL) {
  259. cstate->clientstate = CHAPCS_CLOSED;
  260. } else if (cstate->clientstate == CHAPCS_PENDING) {
  261. cstate->clientstate = CHAPCS_LISTEN;
  262. }
  263. if (cstate->serverstate == CHAPSS_INITIAL) {
  264. cstate->serverstate = CHAPSS_CLOSED;
  265. } else if (cstate->serverstate == CHAPSS_PENDING) {
  266. ChapGenChallenge(cstate);
  267. ChapSendChallenge(cstate);
  268. cstate->serverstate = CHAPSS_INITIAL_CHAL;
  269. }
  270. }
  271. /*
  272. * ChapLowerDown - The lower layer is down.
  273. *
  274. * Cancel all timeouts.
  275. */
  276. static void
  277. ChapLowerDown(int unit)
  278. {
  279. chap_state *cstate = &chap[unit];
  280. /* Timeout(s) pending? Cancel if so. */
  281. if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
  282. cstate->serverstate == CHAPSS_RECHALLENGE) {
  283. UNTIMEOUT(ChapChallengeTimeout, cstate);
  284. } else if (cstate->serverstate == CHAPSS_OPEN
  285. && cstate->chal_interval != 0) {
  286. UNTIMEOUT(ChapRechallenge, cstate);
  287. }
  288. if (cstate->clientstate == CHAPCS_RESPONSE) {
  289. UNTIMEOUT(ChapResponseTimeout, cstate);
  290. }
  291. cstate->clientstate = CHAPCS_INITIAL;
  292. cstate->serverstate = CHAPSS_INITIAL;
  293. }
  294. /*
  295. * ChapProtocolReject - Peer doesn't grok CHAP.
  296. */
  297. static void
  298. ChapProtocolReject(int unit)
  299. {
  300. chap_state *cstate = &chap[unit];
  301. if (cstate->serverstate != CHAPSS_INITIAL &&
  302. cstate->serverstate != CHAPSS_CLOSED) {
  303. auth_peer_fail(unit, PPP_CHAP);
  304. }
  305. if (cstate->clientstate != CHAPCS_INITIAL &&
  306. cstate->clientstate != CHAPCS_CLOSED) {
  307. auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
  308. }
  309. ChapLowerDown(unit); /* shutdown chap */
  310. }
  311. /*
  312. * ChapInput - Input CHAP packet.
  313. */
  314. static void
  315. ChapInput(int unit, u_char *inpacket, int packet_len)
  316. {
  317. chap_state *cstate = &chap[unit];
  318. u_char *inp;
  319. u_char code, id;
  320. int len;
  321. /*
  322. * Parse header (code, id and length).
  323. * If packet too short, drop it.
  324. */
  325. inp = inpacket;
  326. if (packet_len < CHAP_HEADERLEN) {
  327. CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n"));
  328. return;
  329. }
  330. GETCHAR(code, inp);
  331. GETCHAR(id, inp);
  332. GETSHORT(len, inp);
  333. if (len < CHAP_HEADERLEN) {
  334. CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n"));
  335. return;
  336. }
  337. if (len > packet_len) {
  338. CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n"));
  339. return;
  340. }
  341. len -= CHAP_HEADERLEN;
  342. /*
  343. * Action depends on code (as in fact it usually does :-).
  344. */
  345. switch (code) {
  346. case CHAP_CHALLENGE:
  347. ChapReceiveChallenge(cstate, inp, id, len);
  348. break;
  349. case CHAP_RESPONSE:
  350. ChapReceiveResponse(cstate, inp, id, len);
  351. break;
  352. case CHAP_FAILURE:
  353. ChapReceiveFailure(cstate, inp, id, len);
  354. break;
  355. case CHAP_SUCCESS:
  356. ChapReceiveSuccess(cstate, inp, id, len);
  357. break;
  358. default: /* Need code reject? */
  359. CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code));
  360. break;
  361. }
  362. }
  363. /*
  364. * ChapReceiveChallenge - Receive Challenge and send Response.
  365. */
  366. static void
  367. ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
  368. {
  369. int rchallenge_len;
  370. u_char *rchallenge;
  371. int secret_len;
  372. char secret[MAXSECRETLEN];
  373. char rhostname[256];
  374. MD5_CTX mdContext;
  375. u_char hash[MD5_SIGNATURE_SIZE];
  376. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
  377. if (cstate->clientstate == CHAPCS_CLOSED ||
  378. cstate->clientstate == CHAPCS_PENDING) {
  379. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n",
  380. cstate->clientstate));
  381. return;
  382. }
  383. if (len < 2) {
  384. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
  385. return;
  386. }
  387. GETCHAR(rchallenge_len, inp);
  388. len -= sizeof (u_char) + rchallenge_len; /* now name field length */
  389. if (len < 0) {
  390. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
  391. return;
  392. }
  393. rchallenge = inp;
  394. INCPTR(rchallenge_len, inp);
  395. if (len >= (int)sizeof(rhostname)) {
  396. len = sizeof(rhostname) - 1;
  397. }
  398. BCOPY(inp, rhostname, len);
  399. rhostname[len] = '\000';
  400. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n",
  401. rhostname));
  402. /* Microsoft doesn't send their name back in the PPP packet */
  403. if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
  404. strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
  405. rhostname[sizeof(rhostname) - 1] = 0;
  406. CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n",
  407. rhostname));
  408. }
  409. /* get secret for authenticating ourselves with the specified host */
  410. if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
  411. secret, &secret_len, 0)) {
  412. secret_len = 0; /* assume null secret if can't find one */
  413. CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n",
  414. rhostname));
  415. }
  416. /* cancel response send timeout if necessary */
  417. if (cstate->clientstate == CHAPCS_RESPONSE) {
  418. UNTIMEOUT(ChapResponseTimeout, cstate);
  419. }
  420. cstate->resp_id = id;
  421. cstate->resp_transmits = 0;
  422. /* generate MD based on negotiated type */
  423. switch (cstate->resp_type) {
  424. case CHAP_DIGEST_MD5:
  425. MD5Init(&mdContext);
  426. MD5Update(&mdContext, &cstate->resp_id, 1);
  427. MD5Update(&mdContext, (u_char*)secret, secret_len);
  428. MD5Update(&mdContext, rchallenge, rchallenge_len);
  429. MD5Final(hash, &mdContext);
  430. BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
  431. cstate->resp_length = MD5_SIGNATURE_SIZE;
  432. break;
  433. #if MSCHAP_SUPPORT
  434. case CHAP_MICROSOFT:
  435. ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
  436. break;
  437. #endif
  438. default:
  439. CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type));
  440. return;
  441. }
  442. BZERO(secret, sizeof(secret));
  443. ChapSendResponse(cstate);
  444. }
  445. /*
  446. * ChapReceiveResponse - Receive and process response.
  447. */
  448. static void
  449. ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
  450. {
  451. u_char *remmd, remmd_len;
  452. int secret_len, old_state;
  453. int code;
  454. char rhostname[256];
  455. MD5_CTX mdContext;
  456. char secret[MAXSECRETLEN];
  457. u_char hash[MD5_SIGNATURE_SIZE];
  458. CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
  459. if (cstate->serverstate == CHAPSS_CLOSED ||
  460. cstate->serverstate == CHAPSS_PENDING) {
  461. CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n",
  462. cstate->serverstate));
  463. return;
  464. }
  465. if (id != cstate->chal_id) {
  466. return; /* doesn't match ID of last challenge */
  467. }
  468. /*
  469. * If we have received a duplicate or bogus Response,
  470. * we have to send the same answer (Success/Failure)
  471. * as we did for the first Response we saw.
  472. */
  473. if (cstate->serverstate == CHAPSS_OPEN) {
  474. ChapSendStatus(cstate, CHAP_SUCCESS);
  475. return;
  476. }
  477. if (cstate->serverstate == CHAPSS_BADAUTH) {
  478. ChapSendStatus(cstate, CHAP_FAILURE);
  479. return;
  480. }
  481. if (len < 2) {
  482. CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
  483. return;
  484. }
  485. GETCHAR(remmd_len, inp); /* get length of MD */
  486. remmd = inp; /* get pointer to MD */
  487. INCPTR(remmd_len, inp);
  488. len -= sizeof (u_char) + remmd_len;
  489. if (len < 0) {
  490. CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
  491. return;
  492. }
  493. UNTIMEOUT(ChapChallengeTimeout, cstate);
  494. if (len >= (int)sizeof(rhostname)) {
  495. len = sizeof(rhostname) - 1;
  496. }
  497. BCOPY(inp, rhostname, len);
  498. rhostname[len] = '\000';
  499. CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n",
  500. rhostname));
  501. /*
  502. * Get secret for authenticating them with us,
  503. * do the hash ourselves, and compare the result.
  504. */
  505. code = CHAP_FAILURE;
  506. if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
  507. secret, &secret_len, 1)) {
  508. CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
  509. rhostname));
  510. } else {
  511. /* generate MD based on negotiated type */
  512. switch (cstate->chal_type) {
  513. case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
  514. if (remmd_len != MD5_SIGNATURE_SIZE) {
  515. break; /* it's not even the right length */
  516. }
  517. MD5Init(&mdContext);
  518. MD5Update(&mdContext, &cstate->chal_id, 1);
  519. MD5Update(&mdContext, (u_char*)secret, secret_len);
  520. MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
  521. MD5Final(hash, &mdContext);
  522. /* compare local and remote MDs and send the appropriate status */
  523. if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {
  524. code = CHAP_SUCCESS; /* they are the same! */
  525. }
  526. break;
  527. default:
  528. CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type));
  529. }
  530. }
  531. BZERO(secret, sizeof(secret));
  532. ChapSendStatus(cstate, code);
  533. if (code == CHAP_SUCCESS) {
  534. old_state = cstate->serverstate;
  535. cstate->serverstate = CHAPSS_OPEN;
  536. if (old_state == CHAPSS_INITIAL_CHAL) {
  537. auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
  538. }
  539. if (cstate->chal_interval != 0) {
  540. TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
  541. }
  542. } else {
  543. CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n"));
  544. cstate->serverstate = CHAPSS_BADAUTH;
  545. auth_peer_fail(cstate->unit, PPP_CHAP);
  546. }
  547. }
  548. /*
  549. * ChapReceiveSuccess - Receive Success
  550. */
  551. static void
  552. ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
  553. {
  554. LWIP_UNUSED_ARG(id);
  555. LWIP_UNUSED_ARG(inp);
  556. CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id));
  557. if (cstate->clientstate == CHAPCS_OPEN) {
  558. /* presumably an answer to a duplicate response */
  559. return;
  560. }
  561. if (cstate->clientstate != CHAPCS_RESPONSE) {
  562. /* don't know what this is */
  563. CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n",
  564. cstate->clientstate));
  565. return;
  566. }
  567. UNTIMEOUT(ChapResponseTimeout, cstate);
  568. /*
  569. * Print message.
  570. */
  571. if (len > 0) {
  572. PRINTMSG(inp, len);
  573. }
  574. cstate->clientstate = CHAPCS_OPEN;
  575. auth_withpeer_success(cstate->unit, PPP_CHAP);
  576. }
  577. /*
  578. * ChapReceiveFailure - Receive failure.
  579. */
  580. static void
  581. ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
  582. {
  583. LWIP_UNUSED_ARG(id);
  584. LWIP_UNUSED_ARG(inp);
  585. CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id));
  586. if (cstate->clientstate != CHAPCS_RESPONSE) {
  587. /* don't know what this is */
  588. CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n",
  589. cstate->clientstate));
  590. return;
  591. }
  592. UNTIMEOUT(ChapResponseTimeout, cstate);
  593. /*
  594. * Print message.
  595. */
  596. if (len > 0) {
  597. PRINTMSG(inp, len);
  598. }
  599. CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n"));
  600. auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
  601. }
  602. /*
  603. * ChapSendChallenge - Send an Authenticate challenge.
  604. */
  605. static void
  606. ChapSendChallenge(chap_state *cstate)
  607. {
  608. u_char *outp;
  609. int chal_len, name_len;
  610. int outlen;
  611. chal_len = cstate->chal_len;
  612. name_len = (int)strlen(cstate->chal_name);
  613. outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
  614. outp = outpacket_buf[cstate->unit];
  615. MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
  616. PUTCHAR(CHAP_CHALLENGE, outp);
  617. PUTCHAR(cstate->chal_id, outp);
  618. PUTSHORT(outlen, outp);
  619. PUTCHAR(chal_len, outp); /* put length of challenge */
  620. BCOPY(cstate->challenge, outp, chal_len);
  621. INCPTR(chal_len, outp);
  622. BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
  623. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  624. CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
  625. TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
  626. ++cstate->chal_transmits;
  627. }
  628. /*
  629. * ChapSendStatus - Send a status response (ack or nak).
  630. */
  631. static void
  632. ChapSendStatus(chap_state *cstate, int code)
  633. {
  634. u_char *outp;
  635. int outlen, msglen;
  636. char msg[256]; /* @todo: this can be a char*, no strcpy needed */
  637. if (code == CHAP_SUCCESS) {
  638. strcpy(msg, "Welcome!");
  639. } else {
  640. strcpy(msg, "I don't like you. Go 'way.");
  641. }
  642. msglen = (int)strlen(msg);
  643. outlen = CHAP_HEADERLEN + msglen;
  644. outp = outpacket_buf[cstate->unit];
  645. MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
  646. PUTCHAR(code, outp);
  647. PUTCHAR(cstate->chal_id, outp);
  648. PUTSHORT(outlen, outp);
  649. BCOPY(msg, outp, msglen);
  650. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  651. CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
  652. cstate->chal_id));
  653. }
  654. /*
  655. * ChapGenChallenge is used to generate a pseudo-random challenge string of
  656. * a pseudo-random length between min_len and max_len. The challenge
  657. * string and its length are stored in *cstate, and various other fields of
  658. * *cstate are initialized.
  659. */
  660. static void
  661. ChapGenChallenge(chap_state *cstate)
  662. {
  663. int chal_len;
  664. u_char *ptr = cstate->challenge;
  665. int i;
  666. /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
  667. MAX_CHALLENGE_LENGTH */
  668. chal_len = (unsigned)
  669. ((((magic() >> 16) *
  670. (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
  671. + MIN_CHALLENGE_LENGTH);
  672. LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff);
  673. cstate->chal_len = (u_char)chal_len;
  674. cstate->chal_id = ++cstate->id;
  675. cstate->chal_transmits = 0;
  676. /* generate a random string */
  677. for (i = 0; i < chal_len; i++ ) {
  678. *ptr++ = (char) (magic() & 0xff);
  679. }
  680. }
  681. /*
  682. * ChapSendResponse - send a response packet with values as specified
  683. * in *cstate.
  684. */
  685. /* ARGSUSED */
  686. static void
  687. ChapSendResponse(chap_state *cstate)
  688. {
  689. u_char *outp;
  690. int outlen, md_len, name_len;
  691. md_len = cstate->resp_length;
  692. name_len = (int)strlen(cstate->resp_name);
  693. outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
  694. outp = outpacket_buf[cstate->unit];
  695. MAKEHEADER(outp, PPP_CHAP);
  696. PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
  697. PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
  698. PUTSHORT(outlen, outp); /* packet length */
  699. PUTCHAR(md_len, outp); /* length of MD */
  700. BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
  701. INCPTR(md_len, outp);
  702. BCOPY(cstate->resp_name, outp, name_len); /* append our name */
  703. /* send the packet */
  704. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  705. cstate->clientstate = CHAPCS_RESPONSE;
  706. TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
  707. ++cstate->resp_transmits;
  708. }
  709. #if PPP_ADDITIONAL_CALLBACKS
  710. static char *ChapCodenames[] = {
  711. "Challenge", "Response", "Success", "Failure"
  712. };
  713. /*
  714. * ChapPrintPkt - print the contents of a CHAP packet.
  715. */
  716. static int
  717. ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
  718. {
  719. int code, id, len;
  720. int clen, nlen;
  721. u_char x;
  722. if (plen < CHAP_HEADERLEN) {
  723. return 0;
  724. }
  725. GETCHAR(code, p);
  726. GETCHAR(id, p);
  727. GETSHORT(len, p);
  728. if (len < CHAP_HEADERLEN || len > plen) {
  729. return 0;
  730. }
  731. if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
  732. printer(arg, " %s", ChapCodenames[code-1]);
  733. } else {
  734. printer(arg, " code=0x%x", code);
  735. }
  736. printer(arg, " id=0x%x", id);
  737. len -= CHAP_HEADERLEN;
  738. switch (code) {
  739. case CHAP_CHALLENGE:
  740. case CHAP_RESPONSE:
  741. if (len < 1) {
  742. break;
  743. }
  744. clen = p[0];
  745. if (len < clen + 1) {
  746. break;
  747. }
  748. ++p;
  749. nlen = len - clen - 1;
  750. printer(arg, " <");
  751. for (; clen > 0; --clen) {
  752. GETCHAR(x, p);
  753. printer(arg, "%.2x", x);
  754. }
  755. printer(arg, ">, name = %.*Z", nlen, p);
  756. break;
  757. case CHAP_FAILURE:
  758. case CHAP_SUCCESS:
  759. printer(arg, " %.*Z", len, p);
  760. break;
  761. default:
  762. for (clen = len; clen > 0; --clen) {
  763. GETCHAR(x, p);
  764. printer(arg, " %.2x", x);
  765. }
  766. }
  767. return len + CHAP_HEADERLEN;
  768. }
  769. #endif /* PPP_ADDITIONAL_CALLBACKS */
  770. #endif /* CHAP_SUPPORT */
  771. #endif /* PPP_SUPPORT */