Home | History | Annotate | Download | only in ppp
      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 (at) mbsi.ca>
     30 *   Ported to lwIP.
     31 * 97-12-04 Guy Lancaster <lancasterg (at) 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 
     69 #include "lwip/opt.h"
     70 
     71 #if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
     72 
     73 #if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
     74 
     75 #include "ppp.h"
     76 #include "pppdebug.h"
     77 
     78 #include "magic.h"
     79 #include "randm.h"
     80 #include "auth.h"
     81 #include "md5.h"
     82 #include "chap.h"
     83 #include "chpms.h"
     84 
     85 #include <string.h>
     86 
     87 #if 0 /* UNUSED */
     88 /*
     89  * Command-line options.
     90  */
     91 static option_t chap_option_list[] = {
     92     { "chap-restart", o_int, &chap[0].timeouttime,
     93       "Set timeout for CHAP" },
     94     { "chap-max-challenge", o_int, &chap[0].max_transmits,
     95       "Set max #xmits for challenge" },
     96     { "chap-interval", o_int, &chap[0].chal_interval,
     97       "Set interval for rechallenge" },
     98 #ifdef MSLANMAN
     99     { "ms-lanman", o_bool, &ms_lanman,
    100       "Use LanMan passwd when using MS-CHAP", 1 },
    101 #endif
    102     { NULL }
    103 };
    104 #endif /* UNUSED */
    105 
    106 /*
    107  * Protocol entry points.
    108  */
    109 static void ChapInit (int);
    110 static void ChapLowerUp (int);
    111 static void ChapLowerDown (int);
    112 static void ChapInput (int, u_char *, int);
    113 static void ChapProtocolReject (int);
    114 #if PPP_ADDITIONAL_CALLBACKS
    115 static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
    116 #endif
    117 
    118 struct protent chap_protent = {
    119   PPP_CHAP,
    120   ChapInit,
    121   ChapInput,
    122   ChapProtocolReject,
    123   ChapLowerUp,
    124   ChapLowerDown,
    125   NULL,
    126   NULL,
    127 #if PPP_ADDITIONAL_CALLBACKS
    128   ChapPrintPkt,
    129   NULL,
    130 #endif /* PPP_ADDITIONAL_CALLBACKS */
    131   1,
    132   "CHAP",
    133 #if PPP_ADDITIONAL_CALLBACKS
    134   NULL,
    135   NULL,
    136   NULL
    137 #endif /* PPP_ADDITIONAL_CALLBACKS */
    138 };
    139 
    140 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
    141 
    142 static void ChapChallengeTimeout (void *);
    143 static void ChapResponseTimeout (void *);
    144 static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int);
    145 static void ChapRechallenge (void *);
    146 static void ChapReceiveResponse (chap_state *, u_char *, int, int);
    147 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
    148 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
    149 static void ChapSendStatus (chap_state *, int);
    150 static void ChapSendChallenge (chap_state *);
    151 static void ChapSendResponse (chap_state *);
    152 static void ChapGenChallenge (chap_state *);
    153 
    154 /*
    155  * ChapInit - Initialize a CHAP unit.
    156  */
    157 static void
    158 ChapInit(int unit)
    159 {
    160   chap_state *cstate = &chap[unit];
    161 
    162   BZERO(cstate, sizeof(*cstate));
    163   cstate->unit = unit;
    164   cstate->clientstate = CHAPCS_INITIAL;
    165   cstate->serverstate = CHAPSS_INITIAL;
    166   cstate->timeouttime = CHAP_DEFTIMEOUT;
    167   cstate->max_transmits = CHAP_DEFTRANSMITS;
    168   /* random number generator is initialized in magic_init */
    169 }
    170 
    171 
    172 /*
    173  * ChapAuthWithPeer - Authenticate us with our peer (start client).
    174  *
    175  */
    176 void
    177 ChapAuthWithPeer(int unit, char *our_name, u_char digest)
    178 {
    179   chap_state *cstate = &chap[unit];
    180 
    181   cstate->resp_name = our_name;
    182   cstate->resp_type = digest;
    183 
    184   if (cstate->clientstate == CHAPCS_INITIAL ||
    185       cstate->clientstate == CHAPCS_PENDING) {
    186     /* lower layer isn't up - wait until later */
    187     cstate->clientstate = CHAPCS_PENDING;
    188     return;
    189   }
    190 
    191   /*
    192    * We get here as a result of LCP coming up.
    193    * So even if CHAP was open before, we will
    194    * have to re-authenticate ourselves.
    195    */
    196   cstate->clientstate = CHAPCS_LISTEN;
    197 }
    198 
    199 
    200 /*
    201  * ChapAuthPeer - Authenticate our peer (start server).
    202  */
    203 void
    204 ChapAuthPeer(int unit, char *our_name, u_char digest)
    205 {
    206   chap_state *cstate = &chap[unit];
    207 
    208   cstate->chal_name = our_name;
    209   cstate->chal_type = digest;
    210 
    211   if (cstate->serverstate == CHAPSS_INITIAL ||
    212       cstate->serverstate == CHAPSS_PENDING) {
    213     /* lower layer isn't up - wait until later */
    214     cstate->serverstate = CHAPSS_PENDING;
    215     return;
    216   }
    217 
    218   ChapGenChallenge(cstate);
    219   ChapSendChallenge(cstate);    /* crank it up dude! */
    220   cstate->serverstate = CHAPSS_INITIAL_CHAL;
    221 }
    222 
    223 
    224 /*
    225  * ChapChallengeTimeout - Timeout expired on sending challenge.
    226  */
    227 static void
    228 ChapChallengeTimeout(void *arg)
    229 {
    230   chap_state *cstate = (chap_state *) arg;
    231 
    232   /* if we aren't sending challenges, don't worry.  then again we */
    233   /* probably shouldn't be here either */
    234   if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
    235       cstate->serverstate != CHAPSS_RECHALLENGE) {
    236     return;
    237   }
    238 
    239   if (cstate->chal_transmits >= cstate->max_transmits) {
    240     /* give up on peer */
    241     CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n"));
    242     cstate->serverstate = CHAPSS_BADAUTH;
    243     auth_peer_fail(cstate->unit, PPP_CHAP);
    244     return;
    245   }
    246 
    247   ChapSendChallenge(cstate); /* Re-send challenge */
    248 }
    249 
    250 
    251 /*
    252  * ChapResponseTimeout - Timeout expired on sending response.
    253  */
    254 static void
    255 ChapResponseTimeout(void *arg)
    256 {
    257   chap_state *cstate = (chap_state *) arg;
    258 
    259   /* if we aren't sending a response, don't worry. */
    260   if (cstate->clientstate != CHAPCS_RESPONSE) {
    261     return;
    262   }
    263 
    264   ChapSendResponse(cstate);    /* re-send response */
    265 }
    266 
    267 
    268 /*
    269  * ChapRechallenge - Time to challenge the peer again.
    270  */
    271 static void
    272 ChapRechallenge(void *arg)
    273 {
    274   chap_state *cstate = (chap_state *) arg;
    275 
    276   /* if we aren't sending a response, don't worry. */
    277   if (cstate->serverstate != CHAPSS_OPEN) {
    278     return;
    279   }
    280 
    281   ChapGenChallenge(cstate);
    282   ChapSendChallenge(cstate);
    283   cstate->serverstate = CHAPSS_RECHALLENGE;
    284 }
    285 
    286 
    287 /*
    288  * ChapLowerUp - The lower layer is up.
    289  *
    290  * Start up if we have pending requests.
    291  */
    292 static void
    293 ChapLowerUp(int unit)
    294 {
    295   chap_state *cstate = &chap[unit];
    296 
    297   if (cstate->clientstate == CHAPCS_INITIAL) {
    298     cstate->clientstate = CHAPCS_CLOSED;
    299   } else if (cstate->clientstate == CHAPCS_PENDING) {
    300     cstate->clientstate = CHAPCS_LISTEN;
    301   }
    302 
    303   if (cstate->serverstate == CHAPSS_INITIAL) {
    304     cstate->serverstate = CHAPSS_CLOSED;
    305   } else if (cstate->serverstate == CHAPSS_PENDING) {
    306     ChapGenChallenge(cstate);
    307     ChapSendChallenge(cstate);
    308     cstate->serverstate = CHAPSS_INITIAL_CHAL;
    309   }
    310 }
    311 
    312 
    313 /*
    314  * ChapLowerDown - The lower layer is down.
    315  *
    316  * Cancel all timeouts.
    317  */
    318 static void
    319 ChapLowerDown(int unit)
    320 {
    321   chap_state *cstate = &chap[unit];
    322 
    323   /* Timeout(s) pending?  Cancel if so. */
    324   if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
    325       cstate->serverstate == CHAPSS_RECHALLENGE) {
    326     UNTIMEOUT(ChapChallengeTimeout, cstate);
    327   } else if (cstate->serverstate == CHAPSS_OPEN
    328       && cstate->chal_interval != 0) {
    329     UNTIMEOUT(ChapRechallenge, cstate);
    330   }
    331   if (cstate->clientstate == CHAPCS_RESPONSE) {
    332     UNTIMEOUT(ChapResponseTimeout, cstate);
    333   }
    334   cstate->clientstate = CHAPCS_INITIAL;
    335   cstate->serverstate = CHAPSS_INITIAL;
    336 }
    337 
    338 
    339 /*
    340  * ChapProtocolReject - Peer doesn't grok CHAP.
    341  */
    342 static void
    343 ChapProtocolReject(int unit)
    344 {
    345   chap_state *cstate = &chap[unit];
    346 
    347   if (cstate->serverstate != CHAPSS_INITIAL &&
    348       cstate->serverstate != CHAPSS_CLOSED) {
    349     auth_peer_fail(unit, PPP_CHAP);
    350   }
    351   if (cstate->clientstate != CHAPCS_INITIAL &&
    352       cstate->clientstate != CHAPCS_CLOSED) {
    353     auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
    354   }
    355   ChapLowerDown(unit); /* shutdown chap */
    356 }
    357 
    358 
    359 /*
    360  * ChapInput - Input CHAP packet.
    361  */
    362 static void
    363 ChapInput(int unit, u_char *inpacket, int packet_len)
    364 {
    365   chap_state *cstate = &chap[unit];
    366   u_char *inp;
    367   u_char code, id;
    368   int len;
    369 
    370   /*
    371    * Parse header (code, id and length).
    372    * If packet too short, drop it.
    373    */
    374   inp = inpacket;
    375   if (packet_len < CHAP_HEADERLEN) {
    376     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n"));
    377     return;
    378   }
    379   GETCHAR(code, inp);
    380   GETCHAR(id, inp);
    381   GETSHORT(len, inp);
    382   if (len < CHAP_HEADERLEN) {
    383     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n"));
    384     return;
    385   }
    386   if (len > packet_len) {
    387     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n"));
    388     return;
    389   }
    390   len -= CHAP_HEADERLEN;
    391 
    392   /*
    393    * Action depends on code (as in fact it usually does :-).
    394    */
    395   switch (code) {
    396     case CHAP_CHALLENGE:
    397       ChapReceiveChallenge(cstate, inp, id, len);
    398       break;
    399 
    400     case CHAP_RESPONSE:
    401       ChapReceiveResponse(cstate, inp, id, len);
    402       break;
    403 
    404     case CHAP_FAILURE:
    405       ChapReceiveFailure(cstate, inp, id, len);
    406       break;
    407 
    408     case CHAP_SUCCESS:
    409       ChapReceiveSuccess(cstate, inp, id, len);
    410       break;
    411 
    412     default:        /* Need code reject? */
    413       CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code));
    414       break;
    415   }
    416 }
    417 
    418 
    419 /*
    420  * ChapReceiveChallenge - Receive Challenge and send Response.
    421  */
    422 static void
    423 ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
    424 {
    425   int rchallenge_len;
    426   u_char *rchallenge;
    427   int secret_len;
    428   char secret[MAXSECRETLEN];
    429   char rhostname[256];
    430   MD5_CTX mdContext;
    431   u_char hash[MD5_SIGNATURE_SIZE];
    432 
    433   CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
    434   if (cstate->clientstate == CHAPCS_CLOSED ||
    435     cstate->clientstate == CHAPCS_PENDING) {
    436     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n",
    437          cstate->clientstate));
    438     return;
    439   }
    440 
    441   if (len < 2) {
    442     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
    443     return;
    444   }
    445 
    446   GETCHAR(rchallenge_len, inp);
    447   len -= sizeof (u_char) + rchallenge_len;  /* now name field length */
    448   if (len < 0) {
    449     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
    450     return;
    451   }
    452   rchallenge = inp;
    453   INCPTR(rchallenge_len, inp);
    454 
    455   if (len >= (int)sizeof(rhostname)) {
    456     len = sizeof(rhostname) - 1;
    457   }
    458   BCOPY(inp, rhostname, len);
    459   rhostname[len] = '\000';
    460 
    461   CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n",
    462              rhostname));
    463 
    464   /* Microsoft doesn't send their name back in the PPP packet */
    465   if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
    466     strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
    467     rhostname[sizeof(rhostname) - 1] = 0;
    468     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n",
    469                rhostname));
    470   }
    471 
    472   /* get secret for authenticating ourselves with the specified host */
    473   if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
    474                   secret, &secret_len, 0)) {
    475     secret_len = 0;    /* assume null secret if can't find one */
    476     CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n",
    477                rhostname));
    478   }
    479 
    480   /* cancel response send timeout if necessary */
    481   if (cstate->clientstate == CHAPCS_RESPONSE) {
    482     UNTIMEOUT(ChapResponseTimeout, cstate);
    483   }
    484 
    485   cstate->resp_id = id;
    486   cstate->resp_transmits = 0;
    487 
    488   /*  generate MD based on negotiated type */
    489   switch (cstate->resp_type) {
    490 
    491   case CHAP_DIGEST_MD5:
    492     MD5Init(&mdContext);
    493     MD5Update(&mdContext, &cstate->resp_id, 1);
    494     MD5Update(&mdContext, (u_char*)secret, secret_len);
    495     MD5Update(&mdContext, rchallenge, rchallenge_len);
    496     MD5Final(hash, &mdContext);
    497     BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
    498     cstate->resp_length = MD5_SIGNATURE_SIZE;
    499     break;
    500 
    501 #if MSCHAP_SUPPORT
    502   case CHAP_MICROSOFT:
    503     ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
    504     break;
    505 #endif
    506 
    507   default:
    508     CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type));
    509     return;
    510   }
    511 
    512   BZERO(secret, sizeof(secret));
    513   ChapSendResponse(cstate);
    514 }
    515 
    516 
    517 /*
    518  * ChapReceiveResponse - Receive and process response.
    519  */
    520 static void
    521 ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
    522 {
    523   u_char *remmd, remmd_len;
    524   int secret_len, old_state;
    525   int code;
    526   char rhostname[256];
    527   MD5_CTX mdContext;
    528   char secret[MAXSECRETLEN];
    529   u_char hash[MD5_SIGNATURE_SIZE];
    530 
    531   CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
    532 
    533   if (cstate->serverstate == CHAPSS_CLOSED ||
    534       cstate->serverstate == CHAPSS_PENDING) {
    535     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n",
    536     cstate->serverstate));
    537     return;
    538   }
    539 
    540   if (id != cstate->chal_id) {
    541     return;      /* doesn't match ID of last challenge */
    542   }
    543 
    544   /*
    545   * If we have received a duplicate or bogus Response,
    546   * we have to send the same answer (Success/Failure)
    547   * as we did for the first Response we saw.
    548   */
    549   if (cstate->serverstate == CHAPSS_OPEN) {
    550     ChapSendStatus(cstate, CHAP_SUCCESS);
    551     return;
    552   }
    553   if (cstate->serverstate == CHAPSS_BADAUTH) {
    554     ChapSendStatus(cstate, CHAP_FAILURE);
    555     return;
    556   }
    557 
    558   if (len < 2) {
    559     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
    560     return;
    561   }
    562   GETCHAR(remmd_len, inp); /* get length of MD */
    563   remmd = inp;             /* get pointer to MD */
    564   INCPTR(remmd_len, inp);
    565 
    566   len -= sizeof (u_char) + remmd_len;
    567   if (len < 0) {
    568     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
    569     return;
    570   }
    571 
    572   UNTIMEOUT(ChapChallengeTimeout, cstate);
    573 
    574   if (len >= (int)sizeof(rhostname)) {
    575     len = sizeof(rhostname) - 1;
    576   }
    577   BCOPY(inp, rhostname, len);
    578   rhostname[len] = '\000';
    579 
    580   CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n",
    581              rhostname));
    582 
    583   /*
    584   * Get secret for authenticating them with us,
    585   * do the hash ourselves, and compare the result.
    586   */
    587   code = CHAP_FAILURE;
    588   if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
    589                   secret, &secret_len, 1)) {
    590     CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
    591                rhostname));
    592   } else {
    593     /*  generate MD based on negotiated type */
    594     switch (cstate->chal_type) {
    595 
    596       case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */
    597         if (remmd_len != MD5_SIGNATURE_SIZE) {
    598           break;      /* it's not even the right length */
    599         }
    600         MD5Init(&mdContext);
    601         MD5Update(&mdContext, &cstate->chal_id, 1);
    602         MD5Update(&mdContext, (u_char*)secret, secret_len);
    603         MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
    604         MD5Final(hash, &mdContext);
    605 
    606         /* compare local and remote MDs and send the appropriate status */
    607         if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {
    608           code = CHAP_SUCCESS;  /* they are the same! */
    609         }
    610         break;
    611 
    612       default:
    613         CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type));
    614     }
    615   }
    616 
    617   BZERO(secret, sizeof(secret));
    618   ChapSendStatus(cstate, code);
    619 
    620   if (code == CHAP_SUCCESS) {
    621     old_state = cstate->serverstate;
    622     cstate->serverstate = CHAPSS_OPEN;
    623     if (old_state == CHAPSS_INITIAL_CHAL) {
    624       auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
    625     }
    626     if (cstate->chal_interval != 0) {
    627       TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
    628     }
    629   } else {
    630     CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n"));
    631     cstate->serverstate = CHAPSS_BADAUTH;
    632     auth_peer_fail(cstate->unit, PPP_CHAP);
    633   }
    634 }
    635 
    636 /*
    637  * ChapReceiveSuccess - Receive Success
    638  */
    639 static void
    640 ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
    641 {
    642   LWIP_UNUSED_ARG(id);
    643   LWIP_UNUSED_ARG(inp);
    644 
    645   CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id));
    646 
    647   if (cstate->clientstate == CHAPCS_OPEN) {
    648     /* presumably an answer to a duplicate response */
    649     return;
    650   }
    651 
    652   if (cstate->clientstate != CHAPCS_RESPONSE) {
    653     /* don't know what this is */
    654     CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n",
    655                cstate->clientstate));
    656     return;
    657   }
    658 
    659   UNTIMEOUT(ChapResponseTimeout, cstate);
    660 
    661   /*
    662    * Print message.
    663    */
    664   if (len > 0) {
    665     PRINTMSG(inp, len);
    666   }
    667 
    668   cstate->clientstate = CHAPCS_OPEN;
    669 
    670   auth_withpeer_success(cstate->unit, PPP_CHAP);
    671 }
    672 
    673 
    674 /*
    675  * ChapReceiveFailure - Receive failure.
    676  */
    677 static void
    678 ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
    679 {
    680   LWIP_UNUSED_ARG(id);
    681   LWIP_UNUSED_ARG(inp);
    682 
    683   CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id));
    684 
    685   if (cstate->clientstate != CHAPCS_RESPONSE) {
    686     /* don't know what this is */
    687     CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n",
    688                cstate->clientstate));
    689     return;
    690   }
    691 
    692   UNTIMEOUT(ChapResponseTimeout, cstate);
    693 
    694   /*
    695    * Print message.
    696    */
    697   if (len > 0) {
    698     PRINTMSG(inp, len);
    699   }
    700 
    701   CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n"));
    702   auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
    703 }
    704 
    705 
    706 /*
    707  * ChapSendChallenge - Send an Authenticate challenge.
    708  */
    709 static void
    710 ChapSendChallenge(chap_state *cstate)
    711 {
    712   u_char *outp;
    713   int chal_len, name_len;
    714   int outlen;
    715 
    716   chal_len = cstate->chal_len;
    717   name_len = (int)strlen(cstate->chal_name);
    718   outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
    719   outp = outpacket_buf[cstate->unit];
    720 
    721   MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */
    722 
    723   PUTCHAR(CHAP_CHALLENGE, outp);
    724   PUTCHAR(cstate->chal_id, outp);
    725   PUTSHORT(outlen, outp);
    726 
    727   PUTCHAR(chal_len, outp);    /* put length of challenge */
    728   BCOPY(cstate->challenge, outp, chal_len);
    729   INCPTR(chal_len, outp);
    730 
    731   BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */
    732 
    733   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
    734 
    735   CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
    736 
    737   TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
    738   ++cstate->chal_transmits;
    739 }
    740 
    741 
    742 /*
    743  * ChapSendStatus - Send a status response (ack or nak).
    744  */
    745 static void
    746 ChapSendStatus(chap_state *cstate, int code)
    747 {
    748   u_char *outp;
    749   int outlen, msglen;
    750   char msg[256]; /* @todo: this can be a char*, no strcpy needed */
    751 
    752   if (code == CHAP_SUCCESS) {
    753     strcpy(msg, "Welcome!");
    754   } else {
    755     strcpy(msg, "I don't like you.  Go 'way.");
    756   }
    757   msglen = (int)strlen(msg);
    758 
    759   outlen = CHAP_HEADERLEN + msglen;
    760   outp = outpacket_buf[cstate->unit];
    761 
    762   MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */
    763 
    764   PUTCHAR(code, outp);
    765   PUTCHAR(cstate->chal_id, outp);
    766   PUTSHORT(outlen, outp);
    767   BCOPY(msg, outp, msglen);
    768   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
    769 
    770   CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
    771              cstate->chal_id));
    772 }
    773 
    774 /*
    775  * ChapGenChallenge is used to generate a pseudo-random challenge string of
    776  * a pseudo-random length between min_len and max_len.  The challenge
    777  * string and its length are stored in *cstate, and various other fields of
    778  * *cstate are initialized.
    779  */
    780 
    781 static void
    782 ChapGenChallenge(chap_state *cstate)
    783 {
    784   int chal_len;
    785   u_char *ptr = cstate->challenge;
    786   int i;
    787 
    788   /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
    789      MAX_CHALLENGE_LENGTH */
    790   chal_len = (unsigned)
    791         ((((magic() >> 16) *
    792               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
    793            + MIN_CHALLENGE_LENGTH);
    794   LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff);
    795   cstate->chal_len = (u_char)chal_len;
    796   cstate->chal_id = ++cstate->id;
    797   cstate->chal_transmits = 0;
    798 
    799   /* generate a random string */
    800   for (i = 0; i < chal_len; i++ ) {
    801     *ptr++ = (char) (magic() & 0xff);
    802   }
    803 }
    804 
    805 /*
    806  * ChapSendResponse - send a response packet with values as specified
    807  * in *cstate.
    808  */
    809 /* ARGSUSED */
    810 static void
    811 ChapSendResponse(chap_state *cstate)
    812 {
    813   u_char *outp;
    814   int outlen, md_len, name_len;
    815 
    816   md_len = cstate->resp_length;
    817   name_len = (int)strlen(cstate->resp_name);
    818   outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
    819   outp = outpacket_buf[cstate->unit];
    820 
    821   MAKEHEADER(outp, PPP_CHAP);
    822 
    823   PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */
    824   PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */
    825   PUTSHORT(outlen, outp);      /* packet length */
    826 
    827   PUTCHAR(md_len, outp);      /* length of MD */
    828   BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */
    829   INCPTR(md_len, outp);
    830 
    831   BCOPY(cstate->resp_name, outp, name_len);  /* append our name */
    832 
    833   /* send the packet */
    834   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
    835 
    836   cstate->clientstate = CHAPCS_RESPONSE;
    837   TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
    838   ++cstate->resp_transmits;
    839 }
    840 
    841 #if PPP_ADDITIONAL_CALLBACKS
    842 static char *ChapCodenames[] = {
    843   "Challenge", "Response", "Success", "Failure"
    844 };
    845 /*
    846  * ChapPrintPkt - print the contents of a CHAP packet.
    847  */
    848 static int
    849 ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
    850 {
    851   int code, id, len;
    852   int clen, nlen;
    853   u_char x;
    854 
    855   if (plen < CHAP_HEADERLEN) {
    856     return 0;
    857   }
    858   GETCHAR(code, p);
    859   GETCHAR(id, p);
    860   GETSHORT(len, p);
    861   if (len < CHAP_HEADERLEN || len > plen) {
    862     return 0;
    863   }
    864 
    865   if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
    866     printer(arg, " %s", ChapCodenames[code-1]);
    867   } else {
    868     printer(arg, " code=0x%x", code);
    869   }
    870   printer(arg, " id=0x%x", id);
    871   len -= CHAP_HEADERLEN;
    872   switch (code) {
    873     case CHAP_CHALLENGE:
    874     case CHAP_RESPONSE:
    875       if (len < 1) {
    876         break;
    877       }
    878       clen = p[0];
    879       if (len < clen + 1) {
    880         break;
    881       }
    882       ++p;
    883       nlen = len - clen - 1;
    884       printer(arg, " <");
    885       for (; clen > 0; --clen) {
    886         GETCHAR(x, p);
    887         printer(arg, "%.2x", x);
    888       }
    889       printer(arg, ">, name = %.*Z", nlen, p);
    890       break;
    891     case CHAP_FAILURE:
    892     case CHAP_SUCCESS:
    893       printer(arg, " %.*Z", len, p);
    894       break;
    895     default:
    896       for (clen = len; clen > 0; --clen) {
    897         GETCHAR(x, p);
    898         printer(arg, " %.2x", x);
    899       }
    900   }
    901 
    902   return len + CHAP_HEADERLEN;
    903 }
    904 #endif /* PPP_ADDITIONAL_CALLBACKS */
    905 
    906 #endif /* CHAP_SUPPORT */
    907 
    908 #endif /* PPP_SUPPORT */
    909