NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chap.c Source File

chap.c

00001 /*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
00002 /*****************************************************************************
00003 * chap.c - Network Challenge Handshake Authentication Protocol program file.
00004 *
00005 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00006 * portions Copyright (c) 1997 by Global Election Systems Inc.
00007 *
00008 * The authors hereby grant permission to use, copy, modify, distribute,
00009 * and license this software and its documentation for any purpose, provided
00010 * that existing copyright notices are retained in all copies and that this
00011 * notice and the following disclaimer are included verbatim in any 
00012 * distributions. No written agreement, license, or royalty fee is required
00013 * for any of the authorized uses.
00014 *
00015 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00017 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00018 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00019 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00020 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00021 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00022 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00023 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00024 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 *
00026 ******************************************************************************
00027 * REVISION HISTORY
00028 *
00029 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00030 *   Ported to lwIP.
00031 * 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00032 *   Original based on BSD chap.c.
00033 *****************************************************************************/
00034 /*
00035  * chap.c - Challenge Handshake Authentication Protocol.
00036  *
00037  * Copyright (c) 1993 The Australian National University.
00038  * All rights reserved.
00039  *
00040  * Redistribution and use in source and binary forms are permitted
00041  * provided that the above copyright notice and this paragraph are
00042  * duplicated in all such forms and that any documentation,
00043  * advertising materials, and other materials related to such
00044  * distribution and use acknowledge that the software was developed
00045  * by the Australian National University.  The name of the University
00046  * may not be used to endorse or promote products derived from this
00047  * software without specific prior written permission.
00048  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00049  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00050  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00051  *
00052  * Copyright (c) 1991 Gregory M. Christy.
00053  * All rights reserved.
00054  *
00055  * Redistribution and use in source and binary forms are permitted
00056  * provided that the above copyright notice and this paragraph are
00057  * duplicated in all such forms and that any documentation,
00058  * advertising materials, and other materials related to such
00059  * distribution and use acknowledge that the software was developed
00060  * by Gregory M. Christy.  The name of the author may not be used to
00061  * endorse or promote products derived from this software without
00062  * specific prior written permission.
00063  *
00064  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00065  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00066  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00067  */
00068 
00069 #include "lwip/opt.h"
00070 
00071 #if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
00072 
00073 #if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00074 
00075 #include "ppp.h"
00076 #include "pppdebug.h"
00077 
00078 #include "magic.h"
00079 #include "randm.h"
00080 #include "auth.h"
00081 #include "md5.h"
00082 #include "chap.h"
00083 #include "chpms.h"
00084 
00085 #include <string.h>
00086 
00087 #if 0 /* UNUSED */
00088 /*
00089  * Command-line options.
00090  */
00091 static option_t chap_option_list[] = {
00092     { "chap-restart", o_int, &chap[0].timeouttime,
00093       "Set timeout for CHAP" },
00094     { "chap-max-challenge", o_int, &chap[0].max_transmits,
00095       "Set max #xmits for challenge" },
00096     { "chap-interval", o_int, &chap[0].chal_interval,
00097       "Set interval for rechallenge" },
00098 #ifdef MSLANMAN
00099     { "ms-lanman", o_bool, &ms_lanman,
00100       "Use LanMan passwd when using MS-CHAP", 1 },
00101 #endif
00102     { NULL }
00103 };
00104 #endif /* UNUSED */
00105 
00106 /*
00107  * Protocol entry points.
00108  */
00109 static void ChapInit (int);
00110 static void ChapLowerUp (int);
00111 static void ChapLowerDown (int);
00112 static void ChapInput (int, u_char *, int);
00113 static void ChapProtocolReject (int);
00114 #if PPP_ADDITIONAL_CALLBACKS
00115 static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
00116 #endif
00117 
00118 struct protent chap_protent = {
00119   PPP_CHAP,
00120   ChapInit,
00121   ChapInput,
00122   ChapProtocolReject,
00123   ChapLowerUp,
00124   ChapLowerDown,
00125   NULL,
00126   NULL,
00127 #if PPP_ADDITIONAL_CALLBACKS
00128   ChapPrintPkt,
00129   NULL,
00130 #endif /* PPP_ADDITIONAL_CALLBACKS */
00131   1,
00132   "CHAP",
00133 #if PPP_ADDITIONAL_CALLBACKS
00134   NULL,
00135   NULL,
00136   NULL
00137 #endif /* PPP_ADDITIONAL_CALLBACKS */
00138 };
00139 
00140 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
00141 
00142 static void ChapChallengeTimeout (void *);
00143 static void ChapResponseTimeout (void *);
00144 static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int);
00145 static void ChapRechallenge (void *);
00146 static void ChapReceiveResponse (chap_state *, u_char *, int, int);
00147 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
00148 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
00149 static void ChapSendStatus (chap_state *, int);
00150 static void ChapSendChallenge (chap_state *);
00151 static void ChapSendResponse (chap_state *);
00152 static void ChapGenChallenge (chap_state *);
00153 
00154 /*
00155  * ChapInit - Initialize a CHAP unit.
00156  */
00157 static void
00158 ChapInit(int unit)
00159 {
00160   chap_state *cstate = &chap[unit];
00161 
00162   BZERO(cstate, sizeof(*cstate));
00163   cstate->unit = unit;
00164   cstate->clientstate = CHAPCS_INITIAL;
00165   cstate->serverstate = CHAPSS_INITIAL;
00166   cstate->timeouttime = CHAP_DEFTIMEOUT;
00167   cstate->max_transmits = CHAP_DEFTRANSMITS;
00168   /* random number generator is initialized in magic_init */
00169 }
00170 
00171 
00172 /*
00173  * ChapAuthWithPeer - Authenticate us with our peer (start client).
00174  *
00175  */
00176 void
00177 ChapAuthWithPeer(int unit, char *our_name, u_char digest)
00178 {
00179   chap_state *cstate = &chap[unit];
00180 
00181   cstate->resp_name = our_name;
00182   cstate->resp_type = digest;
00183 
00184   if (cstate->clientstate == CHAPCS_INITIAL ||
00185       cstate->clientstate == CHAPCS_PENDING) {
00186     /* lower layer isn't up - wait until later */
00187     cstate->clientstate = CHAPCS_PENDING;
00188     return;
00189   }
00190 
00191   /*
00192    * We get here as a result of LCP coming up.
00193    * So even if CHAP was open before, we will 
00194    * have to re-authenticate ourselves.
00195    */
00196   cstate->clientstate = CHAPCS_LISTEN;
00197 }
00198 
00199 
00200 /*
00201  * ChapAuthPeer - Authenticate our peer (start server).
00202  */
00203 void
00204 ChapAuthPeer(int unit, char *our_name, u_char digest)
00205 {
00206   chap_state *cstate = &chap[unit];
00207 
00208   cstate->chal_name = our_name;
00209   cstate->chal_type = digest;
00210   
00211   if (cstate->serverstate == CHAPSS_INITIAL ||
00212       cstate->serverstate == CHAPSS_PENDING) {
00213     /* lower layer isn't up - wait until later */
00214     cstate->serverstate = CHAPSS_PENDING;
00215     return;
00216   }
00217 
00218   ChapGenChallenge(cstate);
00219   ChapSendChallenge(cstate);    /* crank it up dude! */
00220   cstate->serverstate = CHAPSS_INITIAL_CHAL;
00221 }
00222 
00223 
00224 /*
00225  * ChapChallengeTimeout - Timeout expired on sending challenge.
00226  */
00227 static void
00228 ChapChallengeTimeout(void *arg)
00229 {
00230   chap_state *cstate = (chap_state *) arg;
00231 
00232   /* if we aren't sending challenges, don't worry.  then again we */
00233   /* probably shouldn't be here either */
00234   if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
00235       cstate->serverstate != CHAPSS_RECHALLENGE) {
00236     return;
00237   }
00238 
00239   if (cstate->chal_transmits >= cstate->max_transmits) {
00240     /* give up on peer */
00241     CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n"));
00242     cstate->serverstate = CHAPSS_BADAUTH;
00243     auth_peer_fail(cstate->unit, PPP_CHAP);
00244     return;
00245   }
00246 
00247   ChapSendChallenge(cstate); /* Re-send challenge */
00248 }
00249 
00250 
00251 /*
00252  * ChapResponseTimeout - Timeout expired on sending response.
00253  */
00254 static void
00255 ChapResponseTimeout(void *arg)
00256 {
00257   chap_state *cstate = (chap_state *) arg;
00258 
00259   /* if we aren't sending a response, don't worry. */
00260   if (cstate->clientstate != CHAPCS_RESPONSE) {
00261     return;
00262   }
00263 
00264   ChapSendResponse(cstate);    /* re-send response */
00265 }
00266 
00267 
00268 /*
00269  * ChapRechallenge - Time to challenge the peer again.
00270  */
00271 static void
00272 ChapRechallenge(void *arg)
00273 {
00274   chap_state *cstate = (chap_state *) arg;
00275   
00276   /* if we aren't sending a response, don't worry. */
00277   if (cstate->serverstate != CHAPSS_OPEN) {
00278     return;
00279   }
00280 
00281   ChapGenChallenge(cstate);
00282   ChapSendChallenge(cstate);
00283   cstate->serverstate = CHAPSS_RECHALLENGE;
00284 }
00285 
00286 
00287 /*
00288  * ChapLowerUp - The lower layer is up.
00289  *
00290  * Start up if we have pending requests.
00291  */
00292 static void
00293 ChapLowerUp(int unit)
00294 {
00295   chap_state *cstate = &chap[unit];
00296 
00297   if (cstate->clientstate == CHAPCS_INITIAL) {
00298     cstate->clientstate = CHAPCS_CLOSED;
00299   } else if (cstate->clientstate == CHAPCS_PENDING) {
00300     cstate->clientstate = CHAPCS_LISTEN;
00301   }
00302 
00303   if (cstate->serverstate == CHAPSS_INITIAL) {
00304     cstate->serverstate = CHAPSS_CLOSED;
00305   } else if (cstate->serverstate == CHAPSS_PENDING) {
00306     ChapGenChallenge(cstate);
00307     ChapSendChallenge(cstate);
00308     cstate->serverstate = CHAPSS_INITIAL_CHAL;
00309   }
00310 }
00311 
00312 
00313 /*
00314  * ChapLowerDown - The lower layer is down.
00315  *
00316  * Cancel all timeouts.
00317  */
00318 static void
00319 ChapLowerDown(int unit)
00320 {
00321   chap_state *cstate = &chap[unit];
00322 
00323   /* Timeout(s) pending?  Cancel if so. */
00324   if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
00325       cstate->serverstate == CHAPSS_RECHALLENGE) {
00326     UNTIMEOUT(ChapChallengeTimeout, cstate);
00327   } else if (cstate->serverstate == CHAPSS_OPEN
00328       && cstate->chal_interval != 0) {
00329     UNTIMEOUT(ChapRechallenge, cstate);
00330   }
00331   if (cstate->clientstate == CHAPCS_RESPONSE) {
00332     UNTIMEOUT(ChapResponseTimeout, cstate);
00333   }
00334   cstate->clientstate = CHAPCS_INITIAL;
00335   cstate->serverstate = CHAPSS_INITIAL;
00336 }
00337 
00338 
00339 /*
00340  * ChapProtocolReject - Peer doesn't grok CHAP.
00341  */
00342 static void
00343 ChapProtocolReject(int unit)
00344 {
00345   chap_state *cstate = &chap[unit];
00346   
00347   if (cstate->serverstate != CHAPSS_INITIAL &&
00348       cstate->serverstate != CHAPSS_CLOSED) {
00349     auth_peer_fail(unit, PPP_CHAP);
00350   }
00351   if (cstate->clientstate != CHAPCS_INITIAL &&
00352       cstate->clientstate != CHAPCS_CLOSED) {
00353     auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
00354   }
00355   ChapLowerDown(unit); /* shutdown chap */
00356 }
00357 
00358 
00359 /*
00360  * ChapInput - Input CHAP packet.
00361  */
00362 static void
00363 ChapInput(int unit, u_char *inpacket, int packet_len)
00364 {
00365   chap_state *cstate = &chap[unit];
00366   u_char *inp;
00367   u_char code, id;
00368   int len;
00369   
00370   /*
00371    * Parse header (code, id and length).
00372    * If packet too short, drop it.
00373    */
00374   inp = inpacket;
00375   if (packet_len < CHAP_HEADERLEN) {
00376     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n"));
00377     return;
00378   }
00379   GETCHAR(code, inp);
00380   GETCHAR(id, inp);
00381   GETSHORT(len, inp);
00382   if (len < CHAP_HEADERLEN) {
00383     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n"));
00384     return;
00385   }
00386   if (len > packet_len) {
00387     CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n"));
00388     return;
00389   }
00390   len -= CHAP_HEADERLEN;
00391   
00392   /*
00393    * Action depends on code (as in fact it usually does :-).
00394    */
00395   switch (code) {
00396     case CHAP_CHALLENGE:
00397       ChapReceiveChallenge(cstate, inp, id, len);
00398       break;
00399     
00400     case CHAP_RESPONSE:
00401       ChapReceiveResponse(cstate, inp, id, len);
00402       break;
00403     
00404     case CHAP_FAILURE:
00405       ChapReceiveFailure(cstate, inp, id, len);
00406       break;
00407     
00408     case CHAP_SUCCESS:
00409       ChapReceiveSuccess(cstate, inp, id, len);
00410       break;
00411     
00412     default:        /* Need code reject? */
00413       CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code));
00414       break;
00415   }
00416 }
00417 
00418 
00419 /*
00420  * ChapReceiveChallenge - Receive Challenge and send Response.
00421  */
00422 static void
00423 ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
00424 {
00425   int rchallenge_len;
00426   u_char *rchallenge;
00427   int secret_len;
00428   char secret[MAXSECRETLEN];
00429   char rhostname[256];
00430   MD5_CTX mdContext;
00431   u_char hash[MD5_SIGNATURE_SIZE];
00432 
00433   CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
00434   if (cstate->clientstate == CHAPCS_CLOSED ||
00435     cstate->clientstate == CHAPCS_PENDING) {
00436     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n",
00437          cstate->clientstate));
00438     return;
00439   }
00440 
00441   if (len < 2) {
00442     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
00443     return;
00444   }
00445 
00446   GETCHAR(rchallenge_len, inp);
00447   len -= sizeof (u_char) + rchallenge_len;  /* now name field length */
00448   if (len < 0) {
00449     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
00450     return;
00451   }
00452   rchallenge = inp;
00453   INCPTR(rchallenge_len, inp);
00454 
00455   if (len >= (int)sizeof(rhostname)) {
00456     len = sizeof(rhostname) - 1;
00457   }
00458   BCOPY(inp, rhostname, len);
00459   rhostname[len] = '\000';
00460 
00461   CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n",
00462              rhostname));
00463 
00464   /* Microsoft doesn't send their name back in the PPP packet */
00465   if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
00466     strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
00467     rhostname[sizeof(rhostname) - 1] = 0;
00468     CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n",
00469                rhostname));
00470   }
00471 
00472   /* get secret for authenticating ourselves with the specified host */
00473   if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
00474                   secret, &secret_len, 0)) {
00475     secret_len = 0;    /* assume null secret if can't find one */
00476     CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n",
00477                rhostname));
00478   }
00479 
00480   /* cancel response send timeout if necessary */
00481   if (cstate->clientstate == CHAPCS_RESPONSE) {
00482     UNTIMEOUT(ChapResponseTimeout, cstate);
00483   }
00484 
00485   cstate->resp_id = id;
00486   cstate->resp_transmits = 0;
00487 
00488   /*  generate MD based on negotiated type */
00489   switch (cstate->resp_type) { 
00490 
00491   case CHAP_DIGEST_MD5:
00492     MD5Init(&mdContext);
00493     MD5Update(&mdContext, &cstate->resp_id, 1);
00494     MD5Update(&mdContext, (u_char*)secret, secret_len);
00495     MD5Update(&mdContext, rchallenge, rchallenge_len);
00496     MD5Final(hash, &mdContext);
00497     BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
00498     cstate->resp_length = MD5_SIGNATURE_SIZE;
00499     break;
00500   
00501 #if MSCHAP_SUPPORT
00502   case CHAP_MICROSOFT:
00503     ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
00504     break;
00505 #endif
00506 
00507   default:
00508     CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type));
00509     return;
00510   }
00511 
00512   BZERO(secret, sizeof(secret));
00513   ChapSendResponse(cstate);
00514 }
00515 
00516 
00517 /*
00518  * ChapReceiveResponse - Receive and process response.
00519  */
00520 static void
00521 ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
00522 {
00523   u_char *remmd, remmd_len;
00524   int secret_len, old_state;
00525   int code;
00526   char rhostname[256];
00527   MD5_CTX mdContext;
00528   char secret[MAXSECRETLEN];
00529   u_char hash[MD5_SIGNATURE_SIZE];
00530 
00531   CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
00532   
00533   if (cstate->serverstate == CHAPSS_CLOSED ||
00534       cstate->serverstate == CHAPSS_PENDING) {
00535     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n",
00536     cstate->serverstate));
00537     return;
00538   }
00539 
00540   if (id != cstate->chal_id) {
00541     return;      /* doesn't match ID of last challenge */
00542   }
00543 
00544   /*
00545   * If we have received a duplicate or bogus Response,
00546   * we have to send the same answer (Success/Failure)
00547   * as we did for the first Response we saw.
00548   */
00549   if (cstate->serverstate == CHAPSS_OPEN) {
00550     ChapSendStatus(cstate, CHAP_SUCCESS);
00551     return;
00552   }
00553   if (cstate->serverstate == CHAPSS_BADAUTH) {
00554     ChapSendStatus(cstate, CHAP_FAILURE);
00555     return;
00556   }
00557   
00558   if (len < 2) {
00559     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
00560     return;
00561   }
00562   GETCHAR(remmd_len, inp); /* get length of MD */
00563   remmd = inp;             /* get pointer to MD */
00564   INCPTR(remmd_len, inp);
00565   
00566   len -= sizeof (u_char) + remmd_len;
00567   if (len < 0) {
00568     CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
00569     return;
00570   }
00571 
00572   UNTIMEOUT(ChapChallengeTimeout, cstate);
00573   
00574   if (len >= (int)sizeof(rhostname)) {
00575     len = sizeof(rhostname) - 1;
00576   }
00577   BCOPY(inp, rhostname, len);
00578   rhostname[len] = '\000';
00579 
00580   CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n",
00581              rhostname));
00582 
00583   /*
00584   * Get secret for authenticating them with us,
00585   * do the hash ourselves, and compare the result.
00586   */
00587   code = CHAP_FAILURE;
00588   if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
00589                   secret, &secret_len, 1)) {
00590     CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
00591                rhostname));
00592   } else {
00593     /*  generate MD based on negotiated type */
00594     switch (cstate->chal_type) {
00595 
00596       case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */
00597         if (remmd_len != MD5_SIGNATURE_SIZE) {
00598           break;      /* it's not even the right length */
00599         }
00600         MD5Init(&mdContext);
00601         MD5Update(&mdContext, &cstate->chal_id, 1);
00602         MD5Update(&mdContext, (u_char*)secret, secret_len);
00603         MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
00604         MD5Final(hash, &mdContext); 
00605         
00606         /* compare local and remote MDs and send the appropriate status */
00607         if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {
00608           code = CHAP_SUCCESS;  /* they are the same! */
00609         }
00610         break;
00611       
00612       default:
00613         CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type));
00614     }
00615   }
00616   
00617   BZERO(secret, sizeof(secret));
00618   ChapSendStatus(cstate, code);
00619 
00620   if (code == CHAP_SUCCESS) {
00621     old_state = cstate->serverstate;
00622     cstate->serverstate = CHAPSS_OPEN;
00623     if (old_state == CHAPSS_INITIAL_CHAL) {
00624       auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
00625     }
00626     if (cstate->chal_interval != 0) {
00627       TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
00628     }
00629   } else {
00630     CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n"));
00631     cstate->serverstate = CHAPSS_BADAUTH;
00632     auth_peer_fail(cstate->unit, PPP_CHAP);
00633   }
00634 }
00635 
00636 /*
00637  * ChapReceiveSuccess - Receive Success
00638  */
00639 static void
00640 ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
00641 {
00642   LWIP_UNUSED_ARG(id);
00643   LWIP_UNUSED_ARG(inp);
00644 
00645   CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id));
00646 
00647   if (cstate->clientstate == CHAPCS_OPEN) {
00648     /* presumably an answer to a duplicate response */
00649     return;
00650   }
00651 
00652   if (cstate->clientstate != CHAPCS_RESPONSE) {
00653     /* don't know what this is */
00654     CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n",
00655                cstate->clientstate));
00656     return;
00657   }
00658   
00659   UNTIMEOUT(ChapResponseTimeout, cstate);
00660   
00661   /*
00662    * Print message.
00663    */
00664   if (len > 0) {
00665     PRINTMSG(inp, len);
00666   }
00667 
00668   cstate->clientstate = CHAPCS_OPEN;
00669 
00670   auth_withpeer_success(cstate->unit, PPP_CHAP);
00671 }
00672 
00673 
00674 /*
00675  * ChapReceiveFailure - Receive failure.
00676  */
00677 static void
00678 ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
00679 {
00680   LWIP_UNUSED_ARG(id);
00681   LWIP_UNUSED_ARG(inp);
00682 
00683   CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id));
00684 
00685   if (cstate->clientstate != CHAPCS_RESPONSE) {
00686     /* don't know what this is */
00687     CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n",
00688                cstate->clientstate));
00689     return;
00690   }
00691 
00692   UNTIMEOUT(ChapResponseTimeout, cstate);
00693 
00694   /*
00695    * Print message.
00696    */
00697   if (len > 0) {
00698     PRINTMSG(inp, len);
00699   }
00700 
00701   CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n"));
00702   auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
00703 }
00704 
00705 
00706 /*
00707  * ChapSendChallenge - Send an Authenticate challenge.
00708  */
00709 static void
00710 ChapSendChallenge(chap_state *cstate)
00711 {
00712   u_char *outp;
00713   int chal_len, name_len;
00714   int outlen;
00715   
00716   chal_len = cstate->chal_len;
00717   name_len = (int)strlen(cstate->chal_name);
00718   outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
00719   outp = outpacket_buf[cstate->unit];
00720 
00721   MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */
00722 
00723   PUTCHAR(CHAP_CHALLENGE, outp);
00724   PUTCHAR(cstate->chal_id, outp);
00725   PUTSHORT(outlen, outp);
00726 
00727   PUTCHAR(chal_len, outp);    /* put length of challenge */
00728   BCOPY(cstate->challenge, outp, chal_len);
00729   INCPTR(chal_len, outp);
00730 
00731   BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */
00732   
00733   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00734 
00735   CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
00736   
00737   TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
00738   ++cstate->chal_transmits;
00739 }
00740 
00741 
00742 /*
00743  * ChapSendStatus - Send a status response (ack or nak).
00744  */
00745 static void
00746 ChapSendStatus(chap_state *cstate, int code)
00747 {
00748   u_char *outp;
00749   int outlen, msglen;
00750   char msg[256]; /* @todo: this can be a char*, no strcpy needed */
00751 
00752   if (code == CHAP_SUCCESS) {
00753     strcpy(msg, "Welcome!");
00754   } else {
00755     strcpy(msg, "I don't like you.  Go 'way.");
00756   }
00757   msglen = (int)strlen(msg);
00758 
00759   outlen = CHAP_HEADERLEN + msglen;
00760   outp = outpacket_buf[cstate->unit];
00761 
00762   MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */
00763   
00764   PUTCHAR(code, outp);
00765   PUTCHAR(cstate->chal_id, outp);
00766   PUTSHORT(outlen, outp);
00767   BCOPY(msg, outp, msglen);
00768   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00769 
00770   CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
00771              cstate->chal_id));
00772 }
00773 
00774 /*
00775  * ChapGenChallenge is used to generate a pseudo-random challenge string of
00776  * a pseudo-random length between min_len and max_len.  The challenge
00777  * string and its length are stored in *cstate, and various other fields of
00778  * *cstate are initialized.
00779  */
00780 
00781 static void
00782 ChapGenChallenge(chap_state *cstate)
00783 {
00784   int chal_len;
00785   u_char *ptr = cstate->challenge;
00786   int i;
00787 
00788   /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
00789      MAX_CHALLENGE_LENGTH */  
00790   chal_len = (unsigned)
00791         ((((magic() >> 16) *
00792               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
00793            + MIN_CHALLENGE_LENGTH);
00794   LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff);
00795   cstate->chal_len = (u_char)chal_len;
00796   cstate->chal_id = ++cstate->id;
00797   cstate->chal_transmits = 0;
00798 
00799   /* generate a random string */
00800   for (i = 0; i < chal_len; i++ ) {
00801     *ptr++ = (char) (magic() & 0xff);
00802   }
00803 }
00804 
00805 /*
00806  * ChapSendResponse - send a response packet with values as specified
00807  * in *cstate.
00808  */
00809 /* ARGSUSED */
00810 static void
00811 ChapSendResponse(chap_state *cstate)
00812 {
00813   u_char *outp;
00814   int outlen, md_len, name_len;
00815 
00816   md_len = cstate->resp_length;
00817   name_len = (int)strlen(cstate->resp_name);
00818   outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
00819   outp = outpacket_buf[cstate->unit];
00820 
00821   MAKEHEADER(outp, PPP_CHAP);
00822   
00823   PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */
00824   PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */
00825   PUTSHORT(outlen, outp);      /* packet length */
00826   
00827   PUTCHAR(md_len, outp);      /* length of MD */
00828   BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */
00829   INCPTR(md_len, outp);
00830 
00831   BCOPY(cstate->resp_name, outp, name_len);  /* append our name */
00832 
00833   /* send the packet */
00834   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00835 
00836   cstate->clientstate = CHAPCS_RESPONSE;
00837   TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
00838   ++cstate->resp_transmits;
00839 }
00840 
00841 #if PPP_ADDITIONAL_CALLBACKS
00842 static char *ChapCodenames[] = {
00843   "Challenge", "Response", "Success", "Failure"
00844 };
00845 /*
00846  * ChapPrintPkt - print the contents of a CHAP packet.
00847  */
00848 static int
00849 ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
00850 {
00851   int code, id, len;
00852   int clen, nlen;
00853   u_char x;
00854 
00855   if (plen < CHAP_HEADERLEN) {
00856     return 0;
00857   }
00858   GETCHAR(code, p);
00859   GETCHAR(id, p);
00860   GETSHORT(len, p);
00861   if (len < CHAP_HEADERLEN || len > plen) {
00862     return 0;
00863   }
00864 
00865   if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
00866     printer(arg, " %s", ChapCodenames[code-1]);
00867   } else {
00868     printer(arg, " code=0x%x", code);
00869   }
00870   printer(arg, " id=0x%x", id);
00871   len -= CHAP_HEADERLEN;
00872   switch (code) {
00873     case CHAP_CHALLENGE:
00874     case CHAP_RESPONSE:
00875       if (len < 1) {
00876         break;
00877       }
00878       clen = p[0];
00879       if (len < clen + 1) {
00880         break;
00881       }
00882       ++p;
00883       nlen = len - clen - 1;
00884       printer(arg, " <");
00885       for (; clen > 0; --clen) {
00886         GETCHAR(x, p);
00887         printer(arg, "%.2x", x);
00888       }
00889       printer(arg, ">, name = %.*Z", nlen, p);
00890       break;
00891     case CHAP_FAILURE:
00892     case CHAP_SUCCESS:
00893       printer(arg, " %.*Z", len, p);
00894       break;
00895     default:
00896       for (clen = len; clen > 0; --clen) {
00897         GETCHAR(x, p);
00898         printer(arg, " %.2x", x);
00899       }
00900   }
00901 
00902   return len + CHAP_HEADERLEN;
00903 }
00904 #endif /* PPP_ADDITIONAL_CALLBACKS */
00905 
00906 #endif /* CHAP_SUPPORT */
00907 
00908 #endif /* PPP_SUPPORT */