chap.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:21k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* chap.c - Crytographic Handshake Authentication Protocol */
  2. /* Copyright 1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1991 Gregory M. Christy.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by Gregory M. Christy.  The name of the author may not be used to
  14.  * endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. /*
  22. modification history
  23. --------------------
  24. 01e,30jun95,dzb  removed floating point operation (srand48() and drand48()).
  25. 01d,16jun95,dzb  header file consolidation.
  26.                  changed [UN]TIMEOUT macros to PPP_[UN]TIMEOUT.
  27. 01c,08jun95,dzb  changed CHAP response messages to be more informative.
  28. 01b,16jan95,dzb  changed to use PPP specific md5 routines.
  29. 01a,21dec94,dab  VxWorks port - first WRS version.
  30.            +dzb  added: path for ppp header files, WRS copyright, NO_DRAND48.
  31. */
  32. #include "vxWorks.h"
  33. #include "stdio.h"
  34. #include "string.h"
  35. #include "sys/types.h"
  36. #include "sys/times.h"
  37. #include "pppLib.h"
  38. static void ChapChallengeTimeout __ARGS((caddr_t));
  39. static void ChapResponseTimeout __ARGS((caddr_t));
  40. static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, int, int));
  41. static void ChapReceiveResponse __ARGS((chap_state *, u_char *, int, int));
  42. static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, int, int));
  43. static void ChapReceiveFailure __ARGS((chap_state *, u_char *, int, int));
  44. static void ChapSendStatus __ARGS((chap_state *, int));
  45. static void ChapSendChallenge __ARGS((chap_state *));
  46. static void ChapSendResponse __ARGS((chap_state *));
  47. static void ChapGenChallenge __ARGS((chap_state *));
  48. /*
  49.  * ChapInit - Initialize a CHAP unit.
  50.  */
  51. void
  52. ChapInit(unit)
  53.     int unit;
  54. {
  55.     chap_state *cstate = &ppp_if[unit]->chap;
  56.     BZERO((char *)cstate, sizeof(*cstate));
  57.     cstate->unit = unit;
  58.     cstate->clientstate = CHAPCS_INITIAL;
  59.     cstate->serverstate = CHAPSS_INITIAL;
  60.     cstate->timeouttime = CHAP_DEFTIMEOUT;
  61.     cstate->max_transmits = CHAP_DEFTRANSMITS;
  62.     srandom((long) time(NULL)); /* joggle random number generator */
  63. }
  64. /*
  65.  * ChapAuthWithPeer - Authenticate us with our peer (start client).
  66.  *
  67.  */
  68. void
  69. ChapAuthWithPeer(unit, our_name, digest)
  70.     int unit;
  71.     char *our_name;
  72.     int digest;
  73. {
  74.     chap_state *cstate = &ppp_if[unit]->chap;
  75.     cstate->resp_name = our_name;
  76.     cstate->resp_type = digest;
  77.     if (cstate->clientstate == CHAPCS_INITIAL ||
  78. cstate->clientstate == CHAPCS_PENDING) {
  79. /* lower layer isn't up - wait until later */
  80. cstate->clientstate = CHAPCS_PENDING;
  81. return;
  82.     }
  83.     /*
  84.      * We get here as a result of LCP coming up.
  85.      * So even if CHAP was open before, we will 
  86.      * have to re-authenticate ourselves.
  87.      */
  88.     cstate->clientstate = CHAPCS_LISTEN;
  89. }
  90. /*
  91.  * ChapAuthPeer - Authenticate our peer (start server).
  92.  */
  93. void
  94. ChapAuthPeer(unit, our_name, digest)
  95.     int unit;
  96.     char *our_name;
  97.     int digest;
  98. {
  99.     chap_state *cstate = &ppp_if[unit]->chap;
  100.   
  101.     cstate->chal_name = our_name;
  102.     cstate->chal_type = digest;
  103.     if (cstate->serverstate == CHAPSS_INITIAL ||
  104. cstate->serverstate == CHAPSS_PENDING) {
  105. /* lower layer isn't up - wait until later */
  106. cstate->serverstate = CHAPSS_PENDING;
  107. return;
  108.     }
  109.     ChapGenChallenge(cstate);
  110.     ChapSendChallenge(cstate); /* crank it up dude! */
  111.     cstate->serverstate = CHAPSS_INITIAL_CHAL;
  112. }
  113. /*
  114.  * ChapChallengeTimeout - Timeout expired on sending challenge.
  115.  */
  116. static void
  117. ChapChallengeTimeout(arg)
  118.     caddr_t arg;
  119. {
  120.     chap_state *cstate = (chap_state *) arg;
  121.   
  122.     /* if we aren't sending challenges, don't worry.  then again we */
  123.     /* probably shouldn't be here either */
  124.     if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
  125. cstate->serverstate != CHAPSS_RECHALLENGE)
  126. return;
  127.     if (cstate->chal_transmits >= cstate->max_transmits) {
  128. /* give up on peer */
  129. syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
  130. cstate->serverstate = CHAPSS_BADAUTH;
  131. auth_peer_fail(cstate->unit, CHAP);
  132. return;
  133.     }
  134.     ChapSendChallenge(cstate); /* Re-send challenge */
  135. }
  136. /*
  137.  * ChapResponseTimeout - Timeout expired on sending response.
  138.  */
  139. static void
  140. ChapResponseTimeout(arg)
  141.     caddr_t arg;
  142. {
  143.     chap_state *cstate = (chap_state *) arg;
  144.     /* if we aren't sending a response, don't worry. */
  145.     if (cstate->clientstate != CHAPCS_RESPONSE)
  146. return;
  147.     ChapSendResponse(cstate); /* re-send response */
  148. }
  149. /*
  150.  * ChapRechallenge - Time to challenge the peer again.
  151.  */
  152. static void
  153. ChapRechallenge(arg)
  154.     caddr_t arg;
  155. {
  156.     chap_state *cstate = (chap_state *) arg;
  157.     /* if we aren't sending a response, don't worry. */
  158.     if (cstate->serverstate != CHAPSS_OPEN)
  159. return;
  160.     ChapGenChallenge(cstate);
  161.     ChapSendChallenge(cstate);
  162.     cstate->serverstate = CHAPSS_RECHALLENGE;
  163.     if (cstate->chal_interval != 0)
  164. PPP_TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
  165. }
  166. /*
  167.  * ChapLowerUp - The lower layer is up.
  168.  *
  169.  * Start up if we have pending requests.
  170.  */
  171. void
  172. ChapLowerUp(unit)
  173.     int unit;
  174. {
  175.     chap_state *cstate = &ppp_if[unit]->chap;
  176.   
  177.     if (cstate->clientstate == CHAPCS_INITIAL)
  178. cstate->clientstate = CHAPCS_CLOSED;
  179.     else if (cstate->clientstate == CHAPCS_PENDING)
  180. cstate->clientstate = CHAPCS_LISTEN;
  181.     if (cstate->serverstate == CHAPSS_INITIAL)
  182. cstate->serverstate = CHAPSS_CLOSED;
  183.     else if (cstate->serverstate == CHAPSS_PENDING) {
  184. ChapGenChallenge(cstate);
  185. ChapSendChallenge(cstate);
  186. cstate->serverstate = CHAPSS_INITIAL_CHAL;
  187.     }
  188. }
  189. /*
  190.  * ChapLowerDown - The lower layer is down.
  191.  *
  192.  * Cancel all timeouts.
  193.  */
  194. void
  195. ChapLowerDown(unit)
  196.     int unit;
  197. {
  198.     chap_state *cstate = &ppp_if[unit]->chap;
  199.   
  200.     /* Timeout(s) pending?  Cancel if so. */
  201.     if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
  202. cstate->serverstate == CHAPSS_RECHALLENGE)
  203. PPP_UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
  204.     else if (cstate->serverstate == CHAPSS_OPEN
  205.      && cstate->chal_interval != 0)
  206. PPP_UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
  207.     if (cstate->clientstate == CHAPCS_RESPONSE)
  208. PPP_UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  209.     cstate->clientstate = CHAPCS_INITIAL;
  210.     cstate->serverstate = CHAPSS_INITIAL;
  211. }
  212. /*
  213.  * ChapProtocolReject - Peer doesn't grok CHAP.
  214.  */
  215. void
  216. ChapProtocolReject(unit)
  217.     int unit;
  218. {
  219.     chap_state *cstate = &ppp_if[unit]->chap;
  220.     if (cstate->serverstate != CHAPSS_INITIAL &&
  221. cstate->serverstate != CHAPSS_CLOSED)
  222. auth_peer_fail(unit, CHAP);
  223.     if (cstate->clientstate != CHAPCS_INITIAL &&
  224. cstate->clientstate != CHAPCS_CLOSED)
  225. auth_withpeer_fail(unit, CHAP);
  226.     ChapLowerDown(unit); /* shutdown chap */
  227. }
  228. /*
  229.  * ChapInput - Input CHAP packet.
  230.  */
  231. void
  232. ChapInput(unit, inpacket, packet_len)
  233.     int unit;
  234.     u_char *inpacket;
  235.     int packet_len;
  236. {
  237.     chap_state *cstate = &ppp_if[unit]->chap;
  238.     u_char *inp;
  239.     u_char code, id;
  240.     int len;
  241.   
  242.     /*
  243.      * Parse header (code, id and length).
  244.      * If packet too short, drop it.
  245.      */
  246.     inp = inpacket;
  247.     if (packet_len < CHAP_HEADERLEN) {
  248. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
  249. return;
  250.     }
  251.     GETCHAR(code, inp);
  252.     GETCHAR(id, inp);
  253.     GETSHORT(len, inp);
  254.     if (len < CHAP_HEADERLEN) {
  255. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
  256. return;
  257.     }
  258.     if (len > packet_len) {
  259. CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
  260. return;
  261.     }
  262.     len -= CHAP_HEADERLEN;
  263.   
  264.     /*
  265.      * Action depends on code (as in fact it usually does :-).
  266.      */
  267.     switch (code) {
  268.     case CHAP_CHALLENGE:
  269. ChapReceiveChallenge(cstate, inp, id, len);
  270. break;
  271.     
  272.     case CHAP_RESPONSE:
  273. ChapReceiveResponse(cstate, inp, id, len);
  274. break;
  275.     
  276.     case CHAP_FAILURE:
  277. ChapReceiveFailure(cstate, inp, id, len);
  278. break;
  279.     case CHAP_SUCCESS:
  280. ChapReceiveSuccess(cstate, inp, id, len);
  281. break;
  282.     default: /* Need code reject? */
  283. syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
  284. break;
  285.     }
  286. }
  287. /*
  288.  * ChapReceiveChallenge - Receive Challenge and send Response.
  289.  */
  290. static void
  291. ChapReceiveChallenge(cstate, inp, id, len)
  292.     chap_state *cstate;
  293.     u_char *inp;
  294.     int id;
  295.     int len;
  296. {
  297.     int rchallenge_len;
  298.     u_char *rchallenge;
  299.     int secret_len;
  300.     char secret[MAXSECRETLEN];
  301.     char rhostname[256];
  302.     MD5_CTX mdContext;
  303.  
  304.     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
  305.     if (cstate->clientstate == CHAPCS_CLOSED ||
  306. cstate->clientstate == CHAPCS_PENDING) {
  307. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
  308.    cstate->clientstate));
  309. return;
  310.     }
  311.     if (len < 2) {
  312. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
  313. return;
  314.     }
  315.     GETCHAR(rchallenge_len, inp);
  316.     len -= sizeof (u_char) + rchallenge_len; /* now name field length */
  317.     if (len < 0) {
  318. CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
  319. return;
  320.     }
  321.     rchallenge = inp;
  322.     INCPTR(rchallenge_len, inp);
  323.     if (len >= sizeof(rhostname))
  324. len = sizeof(rhostname) - 1;
  325.     BCOPY((char *)inp, rhostname, len);
  326.     rhostname[len] = '00';
  327.     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
  328.        rhostname));
  329.     /* get secret for authenticating ourselves with the specified host */
  330.     if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
  331.     secret, &secret_len, 0)) {
  332. secret_len = 0; /* assume null secret if can't find one */
  333. syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
  334.        rhostname);
  335.     }
  336.     /* cancel response send timeout if necessary */
  337.     if (cstate->clientstate == CHAPCS_RESPONSE)
  338. PPP_UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  339.     cstate->resp_id = id;
  340.     cstate->resp_transmits = 0;
  341.     /*  generate MD based on negotiated type */
  342.     switch (cstate->resp_type) { 
  343.     case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
  344. ppp_MD5Init(&mdContext);
  345. ppp_MD5Update(&mdContext, &cstate->resp_id, 1);
  346. ppp_MD5Update(&mdContext, (u_char *) secret, secret_len);
  347. ppp_MD5Update(&mdContext, rchallenge, rchallenge_len);
  348. ppp_MD5Final(&mdContext);
  349. BCOPY((char *)mdContext.digest, (char *)cstate->response,
  350.               MD5_SIGNATURE_SIZE);
  351. cstate->resp_length = MD5_SIGNATURE_SIZE;
  352. break;
  353.     default:
  354. CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
  355. return;
  356.     }
  357.     ChapSendResponse(cstate);
  358. }
  359. /*
  360.  * ChapReceiveResponse - Receive and process response.
  361.  */
  362. static void
  363. ChapReceiveResponse(cstate, inp, id, len)
  364.     chap_state *cstate;
  365.     u_char *inp;
  366.     int id;
  367.     int len;
  368. {
  369.     u_char *remmd, remmd_len;
  370.     int secret_len, old_state;
  371.     int code;
  372.     char rhostname[256];
  373.     MD5_CTX mdContext;
  374.     char secret[MAXSECRETLEN];
  375.     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
  376.     if (cstate->serverstate == CHAPSS_CLOSED ||
  377. cstate->serverstate == CHAPSS_PENDING) {
  378. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
  379.    cstate->serverstate));
  380. return;
  381.     }
  382.     if (id != cstate->chal_id)
  383. return; /* doesn't match ID of last challenge */
  384.     /*
  385.      * If we have received a duplicate or bogus Response,
  386.      * we have to send the same answer (Success/Failure)
  387.      * as we did for the first Response we saw.
  388.      */
  389.     if (cstate->serverstate == CHAPSS_OPEN) {
  390. ChapSendStatus(cstate, CHAP_SUCCESS);
  391. return;
  392.     }
  393.     if (cstate->serverstate == CHAPSS_BADAUTH) {
  394. ChapSendStatus(cstate, CHAP_FAILURE);
  395. return;
  396.     }
  397.     if (len < 2) {
  398. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
  399. return;
  400.     }
  401.     GETCHAR(remmd_len, inp); /* get length of MD */
  402.     remmd = inp; /* get pointer to MD */
  403.     INCPTR(remmd_len, inp);
  404.     len -= sizeof (u_char) + remmd_len;
  405.     if (len < 0) {
  406. CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
  407. return;
  408.     }
  409.     PPP_UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
  410.     if (len >= sizeof(rhostname))
  411. len = sizeof(rhostname) - 1;
  412.     BCOPY((char *)inp, rhostname, len);
  413.     rhostname[len] = '00';
  414.     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
  415.        rhostname));
  416.     /*
  417.      * Get secret for authenticating them with us,
  418.      * do the hash ourselves, and compare the result.
  419.      */
  420.     code = CHAP_FAILURE;
  421.     if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
  422.    secret, &secret_len, 1)) {
  423. syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
  424.                rhostname);
  425.     } else {
  426. /*  generate MD based on negotiated type */
  427. switch (cstate->chal_type) { 
  428. case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
  429.     if (remmd_len != MD5_SIGNATURE_SIZE)
  430. break; /* it's not even the right length */
  431.     ppp_MD5Init(&mdContext);
  432.     ppp_MD5Update(&mdContext, &cstate->chal_id, 1);
  433.     ppp_MD5Update(&mdContext, (u_char *) secret, secret_len);
  434.     ppp_MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
  435.     ppp_MD5Final(&mdContext); 
  436.     /* compare local and remote MDs and send the appropriate status */
  437.     if (bcmp ((char *)mdContext.digest, (char *)remmd,
  438. MD5_SIGNATURE_SIZE) == 0)
  439. code = CHAP_SUCCESS; /* they are the same! */
  440.     break;
  441. default:
  442.     CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
  443. }
  444.     }
  445.     ChapSendStatus(cstate, code);
  446.     if (code == CHAP_SUCCESS) {
  447. old_state = cstate->serverstate;
  448. cstate->serverstate = CHAPSS_OPEN;
  449. if (old_state == CHAPSS_INITIAL_CHAL) {
  450.     auth_peer_success(cstate->unit, CHAP);
  451. }
  452. if (cstate->chal_interval != 0)
  453.     PPP_TIMEOUT(ChapRechallenge, (caddr_t) cstate,
  454. cstate->chal_interval);
  455.     } else {
  456. syslog(LOG_ERR, "CHAP peer authentication failed");
  457. cstate->serverstate = CHAPSS_BADAUTH;
  458. auth_peer_fail(cstate->unit, CHAP);
  459.     }
  460. }
  461. /*
  462.  * ChapReceiveSuccess - Receive Success
  463.  */
  464. static void
  465. ChapReceiveSuccess(cstate, inp, id, len)
  466.     chap_state *cstate;
  467.     u_char *inp;
  468.     u_char id;
  469.     int len;
  470. {
  471.     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
  472.     if (cstate->clientstate == CHAPCS_OPEN)
  473. /* presumably an answer to a duplicate response */
  474. return;
  475.     if (cstate->clientstate != CHAPCS_RESPONSE) {
  476. /* don't know what this is */
  477. CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d",
  478.    cstate->clientstate));
  479. return;
  480.     }
  481.     PPP_UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  482.     /*
  483.      * Print message.
  484.      */
  485.     if (len > 0)
  486. PRINTMSG(inp, len);
  487.     cstate->clientstate = CHAPCS_OPEN;
  488.     auth_withpeer_success(cstate->unit, CHAP);
  489. }
  490. /*
  491.  * ChapReceiveFailure - Receive failure.
  492.  */
  493. static void
  494. ChapReceiveFailure(cstate, inp, id, len)
  495.     chap_state *cstate;
  496.     u_char *inp;
  497.     u_char id;
  498.     int len;
  499. {
  500.     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
  501.     if (cstate->clientstate != CHAPCS_RESPONSE) {
  502. /* don't know what this is */
  503. CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d",
  504.    cstate->clientstate));
  505. return;
  506.     }
  507.     PPP_UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  508.     /*
  509.      * Print message.
  510.      */
  511.     if (len > 0)
  512. PRINTMSG(inp, len);
  513.     syslog(LOG_ERR, "CHAP authentication failed");
  514.     auth_withpeer_fail(cstate->unit, CHAP);
  515. }
  516. /*
  517.  * ChapSendChallenge - Send an Authenticate challenge.
  518.  */
  519. static void
  520. ChapSendChallenge(cstate)
  521.     chap_state *cstate;
  522. {
  523.     u_char *outp;
  524.     int chal_len, name_len;
  525.     int outlen;
  526.     chal_len = cstate->chal_len;
  527.     name_len = strlen(cstate->chal_name);
  528.     outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
  529.     outp = ppp_if[cstate->unit]->outpacket_buf;
  530.     MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
  531.     PUTCHAR(CHAP_CHALLENGE, outp);
  532.     PUTCHAR(cstate->chal_id, outp);
  533.     PUTSHORT(outlen, outp);
  534.     PUTCHAR(chal_len, outp); /* put length of challenge */
  535.     BCOPY((char *)cstate->challenge, (char *)outp, chal_len);
  536.     INCPTR(chal_len, outp);
  537.     BCOPY(cstate->chal_name, (char *)outp, name_len); /* append hostname */
  538.     output(cstate->unit, ppp_if[cstate->unit]->outpacket_buf, outlen + DLLHEADERLEN);
  539.   
  540.     CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
  541.     PPP_TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
  542.     ++cstate->chal_transmits;
  543. }
  544. /*
  545.  * ChapSendStatus - Send a status response (ack or nak).
  546.  */
  547. static void
  548. ChapSendStatus(cstate, code)
  549.     chap_state *cstate;
  550.     int code;
  551. {
  552.     u_char *outp;
  553.     int outlen, msglen;
  554.     char msg[256];
  555.     if (code == CHAP_SUCCESS)
  556. sprintf(msg, "CHAP authentication success, unit %d", cstate->unit);
  557.     else
  558. sprintf(msg, "CHAP authentication failure, unit %d", cstate->unit);
  559.     msglen = strlen(msg);
  560.     outlen = CHAP_HEADERLEN + msglen;
  561.     outp = ppp_if[cstate->unit]->outpacket_buf;
  562.     MAKEHEADER(outp, CHAP); /* paste in a header */
  563.   
  564.     PUTCHAR(code, outp);
  565.     PUTCHAR(cstate->chal_id, outp);
  566.     PUTSHORT(outlen, outp);
  567.     BCOPY(msg, (char *)outp, msglen);
  568.     output(cstate->unit, ppp_if[cstate->unit]->outpacket_buf, outlen + DLLHEADERLEN);
  569.   
  570.     CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
  571.        cstate->chal_id));
  572. }
  573. /*
  574.  * ChapGenChallenge is used to generate a pseudo-random challenge string of
  575.  * a pseudo-random length between min_len and max_len.  The challenge
  576.  * string and its length are stored in *cstate, and various other fields of
  577.  * *cstate are initialized.
  578.  */
  579. static void
  580. ChapGenChallenge(cstate)
  581.     chap_state *cstate;
  582. {
  583.     int chal_len;
  584.     u_char *ptr = cstate->challenge;
  585.     unsigned int i;
  586.     /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
  587.        MAX_CHALLENGE_LENGTH */  
  588.     chal_len =  (unsigned) ((random() %
  589.      (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
  590.     MIN_CHALLENGE_LENGTH);
  591.     cstate->chal_len = chal_len;
  592.     cstate->chal_id = ++cstate->id;
  593.     cstate->chal_transmits = 0;
  594.     /* generate a random string */
  595.     for (i = 0; i < chal_len; i++ )
  596. *ptr++ = (char) (random() % 0xff);
  597. }
  598. /*
  599.  * ChapSendResponse - send a response packet with values as specified
  600.  * in *cstate.
  601.  */
  602. /* ARGSUSED */
  603. static void
  604. ChapSendResponse(cstate)
  605.     chap_state *cstate;
  606. {
  607.     u_char *outp;
  608.     int outlen, md_len, name_len;
  609.     md_len = cstate->resp_length;
  610.     name_len = strlen(cstate->resp_name);
  611.     outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
  612.     outp = ppp_if[cstate->unit]->outpacket_buf;
  613.     MAKEHEADER(outp, CHAP);
  614.     PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
  615.     PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
  616.     PUTSHORT(outlen, outp); /* packet length */
  617.     PUTCHAR(md_len, outp); /* length of MD */
  618.     BCOPY((char *)cstate->response, (char *)outp, md_len); /* copy MD to buffer */
  619.     INCPTR(md_len, outp);
  620.     BCOPY(cstate->resp_name, (char *)outp, name_len); /* append our name */
  621.     /* send the packet */
  622.     output(cstate->unit, ppp_if[cstate->unit]->outpacket_buf, outlen + DLLHEADERLEN);
  623.     cstate->clientstate = CHAPCS_RESPONSE;
  624.     PPP_TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
  625.     ++cstate->resp_transmits;
  626. }
  627. /*
  628.  * ChapPrintPkt - print the contents of a CHAP packet.
  629.  */
  630. char *ChapCodenames[] = {
  631.     "Challenge", "Response", "Success", "Failure"
  632. };
  633. int
  634. ChapPrintPkt(p, plen, printer, arg)
  635.     u_char *p;
  636.     int plen;
  637.     void (*printer) __ARGS((void *, char *, ...));
  638.     void *arg;
  639. {
  640.     int code, id, len;
  641.     int clen, nlen;
  642.     u_char x;
  643.     if (plen < CHAP_HEADERLEN)
  644.         return 0;
  645.     GETCHAR(code, p);
  646.     GETCHAR(id, p);
  647.     GETSHORT(len, p);
  648.     if (len < CHAP_HEADERLEN || len > plen)
  649.         return 0;
  650.     if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
  651.         printer(arg, " %s", ChapCodenames[code-1]);
  652.     else
  653.         printer(arg, " code=0x%x", code);
  654.     printer(arg, " id=0x%x", id);
  655.     len -= CHAP_HEADERLEN;
  656.     switch (code) {
  657.     case CHAP_CHALLENGE:
  658.     case CHAP_RESPONSE:
  659.         if (len < 1)
  660.             break;
  661.         clen = p[0];
  662.         if (len < clen + 1)
  663.             break;
  664.         ++p;
  665.         nlen = len - clen - 1;
  666.         printer(arg, " <");
  667.         for (; clen > 0; --clen) {
  668.             GETCHAR(x, p);
  669.             printer(arg, "%.2x", x);
  670.         }
  671.         printer(arg, ">, name = ");
  672.         print_string((char *)p, nlen, printer, arg);
  673.         break;
  674.     case CHAP_FAILURE:
  675.     case CHAP_SUCCESS:
  676.         printer(arg, " ");
  677.         print_string((char *)p, len, printer, arg);
  678.         break;
  679.     default:
  680.         for (clen = len; clen > 0; --clen) {
  681.             GETCHAR(x, p);
  682.             printer(arg, " %.2x", x);
  683.         }
  684.     }
  685.     return len + CHAP_HEADERLEN;
  686. }