chap.c
上传用户:yyhongfa
上传日期:2013-01-18
资源大小:267k
文件大小:23k
开发平台:

C/C++

  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 "ppp.h"
  69. #if PPP_SUPPORT > 0
  70. #include "magic.h"
  71. #if CHAP_SUPPORT > 0
  72. #include "randm.h"
  73. #include "auth.h"
  74. #include "md5.h"
  75. #include "chap.h"
  76. #include "chpms.h"
  77. #include "pppdebug.h"
  78. #include "timer.h"
  79. /*************************/
  80. /*** LOCAL DEFINITIONS ***/
  81. /*************************/
  82. /************************/
  83. /*** LOCAL DATA TYPES ***/
  84. /************************/
  85. /***********************************/
  86. /*** LOCAL FUNCTION DECLARATIONS ***/
  87. /***********************************/
  88. /*
  89.  * Protocol entry points.
  90.  */
  91. static void ChapInit (int);
  92. static void ChapLowerUp (int);
  93. static void ChapLowerDown (int);
  94. static void ChapInput (int, u_char *, int);
  95. static void ChapProtocolReject (int);
  96. static int  ChapPrintPkt (u_char *, int,
  97.       void (*) (void *, char *, ...), void *);
  98. static void ChapChallengeTimeout (void *);
  99. static void ChapResponseTimeout (void *);
  100. static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
  101. static void ChapRechallenge (void *);
  102. static void ChapReceiveResponse (chap_state *, u_char *, int, int);
  103. static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
  104. static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
  105. static void ChapSendStatus (chap_state *, int);
  106. static void ChapSendChallenge (chap_state *);
  107. static void ChapSendResponse (chap_state *);
  108. static void ChapGenChallenge (chap_state *);
  109. /******************************/
  110. /*** PUBLIC DATA STRUCTURES ***/
  111. /******************************/
  112. chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
  113. struct protent chap_protent = {
  114.     PPP_CHAP,
  115.     ChapInit,
  116.     ChapInput,
  117.     ChapProtocolReject,
  118.     ChapLowerUp,
  119.     ChapLowerDown,
  120.     NULL,
  121.     NULL,
  122. #if 0
  123.     ChapPrintPkt,
  124.     NULL,
  125. #endif
  126.     1,
  127.     "CHAP",
  128. #if 0
  129.     NULL,
  130.     NULL,
  131.     NULL
  132. #endif
  133. };
  134. /*****************************/
  135. /*** LOCAL DATA STRUCTURES ***/
  136. /*****************************/
  137. static char *ChapCodenames[] = {
  138. "Challenge", "Response", "Success", "Failure"
  139. };
  140. /***********************************/
  141. /*** PUBLIC FUNCTION DEFINITIONS ***/
  142. /***********************************/
  143. /*
  144.  * ChapAuthWithPeer - Authenticate us with our peer (start client).
  145.  *
  146.  */
  147. void ChapAuthWithPeer(int unit, char *our_name, int digest)
  148. {
  149. chap_state *cstate = &chap[unit];
  150. cstate->resp_name = our_name;
  151. cstate->resp_type = digest;
  152. if (cstate->clientstate == CHAPCS_INITIAL ||
  153. cstate->clientstate == CHAPCS_PENDING) {
  154. /* lower layer isn't up - wait until later */
  155. cstate->clientstate = CHAPCS_PENDING;
  156. return;
  157. }
  158. /*
  159.  * We get here as a result of LCP coming up.
  160.  * So even if CHAP was open before, we will 
  161.  * have to re-authenticate ourselves.
  162.  */
  163. cstate->clientstate = CHAPCS_LISTEN;
  164. }
  165. /*
  166.  * ChapAuthPeer - Authenticate our peer (start server).
  167.  */
  168. void ChapAuthPeer(int unit, char *our_name, int digest)
  169. {
  170. chap_state *cstate = &chap[unit];
  171. cstate->chal_name = our_name;
  172. cstate->chal_type = digest;
  173. if (cstate->serverstate == CHAPSS_INITIAL ||
  174. cstate->serverstate == CHAPSS_PENDING) {
  175. /* lower layer isn't up - wait until later */
  176. cstate->serverstate = CHAPSS_PENDING;
  177. return;
  178. }
  179. ChapGenChallenge(cstate);
  180. ChapSendChallenge(cstate); /* crank it up dude! */
  181. cstate->serverstate = CHAPSS_INITIAL_CHAL;
  182. }
  183. /**********************************/
  184. /*** LOCAL FUNCTION DEFINITIONS ***/
  185. /**********************************/
  186. /*
  187.  * ChapInit - Initialize a CHAP unit.
  188.  */
  189. static void ChapInit(int unit)
  190. {
  191. chap_state *cstate = &chap[unit];
  192. BZERO(cstate, sizeof(*cstate));
  193. cstate->unit = unit;
  194. cstate->clientstate = CHAPCS_INITIAL;
  195. cstate->serverstate = CHAPSS_INITIAL;
  196. cstate->timeouttime = CHAP_DEFTIMEOUT;
  197. cstate->max_transmits = CHAP_DEFTRANSMITS;
  198. /* random number generator is initialized in magic_init */
  199. }
  200. /*
  201.  * ChapChallengeTimeout - Timeout expired on sending challenge.
  202.  */
  203. static void 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. if (cstate->chal_transmits >= cstate->max_transmits) {
  212. /* give up on peer */
  213. CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challengen"));
  214. cstate->serverstate = CHAPSS_BADAUTH;
  215. auth_peer_fail(cstate->unit, PPP_CHAP);
  216. return;
  217. }
  218. ChapSendChallenge(cstate); /* Re-send challenge */
  219. }
  220. /*
  221.  * ChapResponseTimeout - Timeout expired on sending response.
  222.  */
  223. static void ChapResponseTimeout(void *arg)
  224. {
  225. chap_state *cstate = (chap_state *) arg;
  226. /* if we aren't sending a response, don't worry. */
  227. if (cstate->clientstate != CHAPCS_RESPONSE)
  228. return;
  229. ChapSendResponse(cstate); /* re-send response */
  230. }
  231. /*
  232.  * ChapRechallenge - Time to challenge the peer again.
  233.  */
  234. static void ChapRechallenge(void *arg)
  235. {
  236. chap_state *cstate = (chap_state *) arg;
  237. /* if we aren't sending a response, don't worry. */
  238. if (cstate->serverstate != CHAPSS_OPEN)
  239. return;
  240. ChapGenChallenge(cstate);
  241. ChapSendChallenge(cstate);
  242. cstate->serverstate = CHAPSS_RECHALLENGE;
  243. }
  244. /*
  245.  * ChapLowerUp - The lower layer is up.
  246.  *
  247.  * Start up if we have pending requests.
  248.  */
  249. static void ChapLowerUp(int unit)
  250. {
  251. chap_state *cstate = &chap[unit];
  252. if (cstate->clientstate == CHAPCS_INITIAL)
  253. cstate->clientstate = CHAPCS_CLOSED;
  254. else if (cstate->clientstate == CHAPCS_PENDING)
  255. cstate->clientstate = CHAPCS_LISTEN;
  256. if (cstate->serverstate == CHAPSS_INITIAL)
  257. cstate->serverstate = CHAPSS_CLOSED;
  258. else if (cstate->serverstate == CHAPSS_PENDING) {
  259. ChapGenChallenge(cstate);
  260. ChapSendChallenge(cstate);
  261. cstate->serverstate = CHAPSS_INITIAL_CHAL;
  262. }
  263. }
  264. /*
  265.  * ChapLowerDown - The lower layer is down.
  266.  *
  267.  * Cancel all timeouts.
  268.  */
  269. static void ChapLowerDown(int unit)
  270. {
  271. chap_state *cstate = &chap[unit];
  272. /* Timeout(s) pending?  Cancel if so. */
  273. if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
  274. cstate->serverstate == CHAPSS_RECHALLENGE)
  275. UNTIMEOUT(ChapChallengeTimeout, cstate);
  276. else if (cstate->serverstate == CHAPSS_OPEN
  277. && cstate->chal_interval != 0)
  278. UNTIMEOUT(ChapRechallenge, cstate);
  279. if (cstate->clientstate == CHAPCS_RESPONSE)
  280. UNTIMEOUT(ChapResponseTimeout, cstate);
  281. cstate->clientstate = CHAPCS_INITIAL;
  282. cstate->serverstate = CHAPSS_INITIAL;
  283. }
  284. /*
  285.  * ChapProtocolReject - Peer doesn't grok CHAP.
  286.  */
  287. static void ChapProtocolReject(int unit)
  288. {
  289. chap_state *cstate = &chap[unit];
  290. if (cstate->serverstate != CHAPSS_INITIAL &&
  291. cstate->serverstate != CHAPSS_CLOSED)
  292. auth_peer_fail(unit, PPP_CHAP);
  293. if (cstate->clientstate != CHAPCS_INITIAL &&
  294. cstate->clientstate != CHAPCS_CLOSED)
  295. auth_withpeer_fail(unit, PPP_CHAP);
  296. ChapLowerDown(unit); /* shutdown chap */
  297. }
  298. /*
  299.  * ChapInput - Input CHAP packet.
  300.  */
  301. static void ChapInput(int unit, u_char *inpacket, int packet_len)
  302. {
  303. chap_state *cstate = &chap[unit];
  304. u_char *inp;
  305. u_char code, id;
  306. int len;
  307. /*
  308.  * Parse header (code, id and length).
  309.  * If packet too short, drop it.
  310.  */
  311. inp = inpacket;
  312. if (packet_len < CHAP_HEADERLEN) {
  313. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.n"));
  314. return;
  315. }
  316. GETCHAR(code, inp);
  317. GETCHAR(id, inp);
  318. GETSHORT(len, inp);
  319. if (len < CHAP_HEADERLEN) {
  320. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.n"));
  321. return;
  322. }
  323. if (len > packet_len) {
  324. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.n"));
  325. return;
  326. }
  327. len -= CHAP_HEADERLEN;
  328. /*
  329.  * Action depends on code (as in fact it usually does :-).
  330.  */
  331. switch (code) {
  332. case CHAP_CHALLENGE:
  333. ChapReceiveChallenge(cstate, inp, id, len);
  334. break;
  335. case CHAP_RESPONSE:
  336. ChapReceiveResponse(cstate, inp, id, len);
  337. break;
  338. case CHAP_FAILURE:
  339. ChapReceiveFailure(cstate, inp, id, len);
  340. break;
  341. case CHAP_SUCCESS:
  342. ChapReceiveSuccess(cstate, inp, id, len);
  343. break;
  344. default: /* Need code reject? */
  345. CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.n", code));
  346. break;
  347. }
  348. }
  349. /*
  350.  * ChapReceiveChallenge - Receive Challenge and send Response.
  351.  */
  352. static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
  353. {
  354. int rchallenge_len;
  355. u_char *rchallenge;
  356. int secret_len;
  357. char secret[MAXSECRETLEN];
  358. char rhostname[256];
  359. MD5_CTX mdContext;
  360. u_char hash[MD5_SIGNATURE_SIZE];
  361. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.n", id));
  362. if (cstate->clientstate == CHAPCS_CLOSED ||
  363. cstate->clientstate == CHAPCS_PENDING) {
  364. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %dn",
  365.    cstate->clientstate));
  366. return;
  367. }
  368. if (len < 2) {
  369. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.n"));
  370. return;
  371. }
  372. GETCHAR(rchallenge_len, inp);
  373. len -= sizeof (u_char) + rchallenge_len; /* now name field length */
  374. if (len < 0) {
  375. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.n"));
  376. return;
  377. }
  378. rchallenge = inp;
  379. INCPTR(rchallenge_len, inp);
  380. if (len >= sizeof(rhostname))
  381. len = sizeof(rhostname) - 1;
  382. BCOPY(inp, rhostname, len);
  383. rhostname[len] = '00';
  384. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'n",
  385.        rhostname));
  386. /* Microsoft doesn't send their name back in the PPP packet */
  387. if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
  388. strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
  389. rhostname[sizeof(rhostname) - 1] = 0;
  390. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote namen",
  391.    rhostname));
  392. }
  393. /* get secret for authenticating ourselves with the specified host */
  394. if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
  395.     secret, &secret_len, 0)) {
  396. secret_len = 0; /* assume null secret if can't find one */
  397. CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %sn", rhostname));
  398. }
  399. /* cancel response send timeout if necessary */
  400. if (cstate->clientstate == CHAPCS_RESPONSE)
  401. UNTIMEOUT(ChapResponseTimeout, cstate);
  402. cstate->resp_id = id;
  403. cstate->resp_transmits = 0;
  404. /*  generate MD based on negotiated type */
  405. switch (cstate->resp_type) { 
  406. case CHAP_DIGEST_MD5:
  407. MD5Init(&mdContext);
  408. MD5Update(&mdContext, &cstate->resp_id, 1);
  409. MD5Update(&mdContext, (u_char*)secret, secret_len);
  410. MD5Update(&mdContext, rchallenge, rchallenge_len);
  411. MD5Final(hash, &mdContext);
  412. BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
  413. cstate->resp_length = MD5_SIGNATURE_SIZE;
  414. break;
  415. #ifdef CHAPMS
  416. case CHAP_MICROSOFT:
  417. ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
  418. break;
  419. #endif
  420. default:
  421. CHAPDEBUG((LOG_INFO, "unknown digest type %dn", cstate->resp_type));
  422. return;
  423. }
  424. BZERO(secret, sizeof(secret));
  425. ChapSendResponse(cstate);
  426. }
  427. /*
  428.  * ChapReceiveResponse - Receive and process response.
  429.  */
  430. static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
  431. {
  432. u_char *remmd, remmd_len;
  433. int secret_len, old_state;
  434. int code;
  435. char rhostname[256];
  436. MD5_CTX mdContext;
  437. char secret[MAXSECRETLEN];
  438. u_char hash[MD5_SIGNATURE_SIZE];
  439. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.n", id));
  440. if (cstate->serverstate == CHAPSS_CLOSED ||
  441. cstate->serverstate == CHAPSS_PENDING) {
  442. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %dn",
  443. cstate->serverstate));
  444. return;
  445. }
  446. if (id != cstate->chal_id)
  447. return; /* doesn't match ID of last challenge */
  448. /*
  449. * If we have received a duplicate or bogus Response,
  450. * we have to send the same answer (Success/Failure)
  451. * as we did for the first Response we saw.
  452. */
  453. if (cstate->serverstate == CHAPSS_OPEN) {
  454. ChapSendStatus(cstate, CHAP_SUCCESS);
  455. return;
  456. }
  457. if (cstate->serverstate == CHAPSS_BADAUTH) {
  458. ChapSendStatus(cstate, CHAP_FAILURE);
  459. return;
  460. }
  461. if (len < 2) {
  462. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.n"));
  463. return;
  464. }
  465. GETCHAR(remmd_len, inp); /* get length of MD */
  466. remmd = inp; /* get pointer to MD */
  467. INCPTR(remmd_len, inp);
  468. len -= sizeof (u_char) + remmd_len;
  469. if (len < 0) {
  470. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.n"));
  471. return;
  472. }
  473. UNTIMEOUT(ChapChallengeTimeout, cstate);
  474. if (len >= sizeof(rhostname))
  475. len = sizeof(rhostname) - 1;
  476. BCOPY(inp, rhostname, len);
  477. rhostname[len] = '00';
  478. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %sn",
  479. rhostname));
  480. /*
  481. * Get secret for authenticating them with us,
  482. * do the hash ourselves, and compare the result.
  483. */
  484. code = CHAP_FAILURE;
  485. if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
  486. secret, &secret_len, 1)) {
  487. /*        CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %sn", rhostname)); */
  488. CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %sn",
  489. rhostname));
  490. } else {
  491. /*  generate MD based on negotiated type */
  492. switch (cstate->chal_type) { 
  493. case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
  494. if (remmd_len != MD5_SIGNATURE_SIZE)
  495. break; /* it's not even the right length */
  496. MD5Init(&mdContext);
  497. MD5Update(&mdContext, &cstate->chal_id, 1);
  498. MD5Update(&mdContext, (u_char*)secret, secret_len);
  499. MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
  500. MD5Final(hash, &mdContext); 
  501. /* compare local and remote MDs and send the appropriate status */
  502. if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
  503. code = CHAP_SUCCESS; /* they are the same! */
  504. break;
  505. default:
  506. CHAPDEBUG((LOG_INFO, "unknown digest type %dn", cstate->chal_type));
  507. }
  508. }
  509. BZERO(secret, sizeof(secret));
  510. ChapSendStatus(cstate, code);
  511. if (code == CHAP_SUCCESS) {
  512. old_state = cstate->serverstate;
  513. cstate->serverstate = CHAPSS_OPEN;
  514. if (old_state == CHAPSS_INITIAL_CHAL) {
  515. auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
  516. }
  517. if (cstate->chal_interval != 0)
  518. TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
  519. } else {
  520. CHAPDEBUG((LOG_ERR, "CHAP peer authentication failedn"));
  521. cstate->serverstate = CHAPSS_BADAUTH;
  522. auth_peer_fail(cstate->unit, PPP_CHAP);
  523. }
  524. }
  525. /*
  526.  * ChapReceiveSuccess - Receive Success
  527.  */
  528. static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
  529. {
  530. CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.n", id));
  531. if (cstate->clientstate == CHAPCS_OPEN)
  532. /* presumably an answer to a duplicate response */
  533. return;
  534. if (cstate->clientstate != CHAPCS_RESPONSE) {
  535. /* don't know what this is */
  536. CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %dn",
  537.    cstate->clientstate));
  538. return;
  539. }
  540. UNTIMEOUT(ChapResponseTimeout, cstate);
  541. /*
  542.  * Print message.
  543.  */
  544. if (len > 0)
  545. PRINTMSG(inp, len);
  546. cstate->clientstate = CHAPCS_OPEN;
  547. auth_withpeer_success(cstate->unit, PPP_CHAP);
  548. }
  549. /*
  550.  * ChapReceiveFailure - Receive failure.
  551.  */
  552. static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
  553. {
  554. CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.n", id));
  555. if (cstate->clientstate != CHAPCS_RESPONSE) {
  556. /* don't know what this is */
  557. CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %dn",
  558.    cstate->clientstate));
  559. return;
  560. }
  561. UNTIMEOUT(ChapResponseTimeout, cstate);
  562. /*
  563.  * Print message.
  564.  */
  565. if (len > 0)
  566. PRINTMSG(inp, len);
  567. CHAPDEBUG((LOG_ERR, "CHAP authentication failedn"));
  568. auth_withpeer_fail(cstate->unit, PPP_CHAP);
  569. }
  570. /*
  571.  * ChapSendChallenge - Send an Authenticate challenge.
  572.  */
  573. static void ChapSendChallenge(chap_state *cstate)
  574. {
  575. u_char *outp;
  576. int chal_len, name_len;
  577. int outlen;
  578. chal_len = cstate->chal_len;
  579. name_len = strlen(cstate->chal_name);
  580. outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
  581. outp = outpacket_buf[cstate->unit];
  582. MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
  583. PUTCHAR(CHAP_CHALLENGE, outp);
  584. PUTCHAR(cstate->chal_id, outp);
  585. PUTSHORT(outlen, outp);
  586. PUTCHAR(chal_len, outp); /* put length of challenge */
  587. BCOPY(cstate->challenge, outp, chal_len);
  588. INCPTR(chal_len, outp);
  589. BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
  590. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  591. CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.n", cstate->chal_id));
  592. TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
  593. ++cstate->chal_transmits;
  594. }
  595. /*
  596.  * ChapSendStatus - Send a status response (ack or nak).
  597.  */
  598. static void ChapSendStatus(chap_state *cstate, int code)
  599. {
  600. u_char *outp;
  601. int outlen, msglen;
  602. char msg[256];
  603. if (code == CHAP_SUCCESS)
  604. strcpy(msg, "Welcome!");
  605. else
  606. strcpy(msg, "I don't like you.  Go 'way.");
  607. msglen = strlen(msg);
  608. outlen = CHAP_HEADERLEN + msglen;
  609. outp = outpacket_buf[cstate->unit];
  610. MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
  611. PUTCHAR(code, outp);
  612. PUTCHAR(cstate->chal_id, outp);
  613. PUTSHORT(outlen, outp);
  614. BCOPY(msg, outp, msglen);
  615. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  616. CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.n", code,
  617.        cstate->chal_id));
  618. }
  619. /*
  620.  * ChapGenChallenge is used to generate a pseudo-random challenge string of
  621.  * a pseudo-random length between min_len and max_len.  The challenge
  622.  * string and its length are stored in *cstate, and various other fields of
  623.  * *cstate are initialized.
  624.  */
  625. static void ChapGenChallenge(chap_state *cstate)
  626. {
  627. int chal_len;
  628. u_char *ptr = cstate->challenge;
  629. int i;
  630. /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
  631.    MAX_CHALLENGE_LENGTH */  
  632. chal_len = (unsigned)
  633. ((((magic() >> 16) *
  634.         (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
  635.      + MIN_CHALLENGE_LENGTH);
  636. cstate->chal_len = chal_len;
  637. cstate->chal_id = ++cstate->id;
  638. cstate->chal_transmits = 0;
  639. /* generate a random string */
  640. for (i = 0; i < chal_len; i++ )
  641. *ptr++ = (char) (magic() & 0xff);
  642. }
  643. /*
  644.  * ChapSendResponse - send a response packet with values as specified
  645.  * in *cstate.
  646.  */
  647. /* ARGSUSED */
  648. static void ChapSendResponse(chap_state *cstate)
  649. {
  650. u_char *outp;
  651. int outlen, md_len, name_len;
  652. md_len = cstate->resp_length;
  653. name_len = strlen(cstate->resp_name);
  654. outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
  655. outp = outpacket_buf[cstate->unit];
  656. MAKEHEADER(outp, PPP_CHAP);
  657. PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
  658. PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
  659. PUTSHORT(outlen, outp); /* packet length */
  660. PUTCHAR(md_len, outp); /* length of MD */
  661. BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
  662. INCPTR(md_len, outp);
  663. BCOPY(cstate->resp_name, outp, name_len); /* append our name */
  664. /* send the packet */
  665. pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
  666. cstate->clientstate = CHAPCS_RESPONSE;
  667. TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
  668. ++cstate->resp_transmits;
  669. }
  670. /*
  671.  * ChapPrintPkt - print the contents of a CHAP packet.
  672.  */
  673. static int ChapPrintPkt(
  674. u_char *p,
  675. int plen,
  676. void (*printer) (void *, char *, ...),
  677. void *arg
  678. )
  679. {
  680. int code, id, len;
  681. int clen, nlen;
  682. u_char x;
  683. if (plen < CHAP_HEADERLEN)
  684. return 0;
  685. GETCHAR(code, p);
  686. GETCHAR(id, p);
  687. GETSHORT(len, p);
  688. if (len < CHAP_HEADERLEN || len > plen)
  689. return 0;
  690. if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
  691. printer(arg, " %s", ChapCodenames[code-1]);
  692. else
  693. printer(arg, " code=0x%x", code);
  694. printer(arg, " id=0x%x", id);
  695. len -= CHAP_HEADERLEN;
  696. switch (code) {
  697. case CHAP_CHALLENGE:
  698. case CHAP_RESPONSE:
  699. if (len < 1)
  700. break;
  701. clen = p[0];
  702. if (len < clen + 1)
  703. break;
  704. ++p;
  705. nlen = len - clen - 1;
  706. printer(arg, " <");
  707. for (; clen > 0; --clen) {
  708. GETCHAR(x, p);
  709. printer(arg, "%.2x", x);
  710. }
  711. printer(arg, ">, name = %.*Z", nlen, p);
  712. break;
  713. case CHAP_FAILURE:
  714. case CHAP_SUCCESS:
  715. printer(arg, " %.*Z", len, p);
  716. break;
  717. default:
  718. for (clen = len; clen > 0; --clen) {
  719. GETCHAR(x, p);
  720. printer(arg, " %.2x", x);
  721. }
  722. }
  723. return len + CHAP_HEADERLEN;
  724. }
  725. #endif
  726. #endif /* PPP_SUPPORT */