SAMV71 Xplained Ultra Software Package 1.4

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 /*************************/
00088 /*** LOCAL DEFINITIONS ***/
00089 /*************************/
00090 
00091 
00092 /************************/
00093 /*** LOCAL DATA TYPES ***/
00094 /************************/
00095 
00096 
00097 /***********************************/
00098 /*** LOCAL FUNCTION DECLARATIONS ***/
00099 /***********************************/
00100 /*
00101  * Protocol entry points.
00102  */
00103 static void ChapInit (int);
00104 static void ChapLowerUp (int);
00105 static void ChapLowerDown (int);
00106 static void ChapInput (int, u_char *, int);
00107 static void ChapProtocolReject (int);
00108 #if 0
00109 static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
00110 #endif
00111 
00112 static void ChapChallengeTimeout (void *);
00113 static void ChapResponseTimeout (void *);
00114 static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
00115 static void ChapRechallenge (void *);
00116 static void ChapReceiveResponse (chap_state *, u_char *, int, int);
00117 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
00118 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
00119 static void ChapSendStatus (chap_state *, int);
00120 static void ChapSendChallenge (chap_state *);
00121 static void ChapSendResponse (chap_state *);
00122 static void ChapGenChallenge (chap_state *);
00123 
00124 
00125 /******************************/
00126 /*** PUBLIC DATA STRUCTURES ***/
00127 /******************************/
00128 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
00129 
00130 struct protent chap_protent = {
00131   PPP_CHAP,
00132   ChapInit,
00133   ChapInput,
00134   ChapProtocolReject,
00135   ChapLowerUp,
00136   ChapLowerDown,
00137   NULL,
00138   NULL,
00139 #if 0
00140   ChapPrintPkt,
00141   NULL,
00142 #endif
00143   1,
00144   "CHAP",
00145 #if 0
00146   NULL,
00147   NULL,
00148   NULL
00149 #endif
00150 };
00151 
00152 
00153 /***********************************/
00154 /*** PUBLIC FUNCTION DEFINITIONS ***/
00155 /***********************************/
00156 /*
00157  * ChapAuthWithPeer - Authenticate us with our peer (start client).
00158  *
00159  */
00160 void
00161 ChapAuthWithPeer(int unit, char *our_name, int digest)
00162 {
00163   chap_state *cstate = &chap[unit];
00164 
00165   cstate->resp_name = our_name;
00166   cstate->resp_type = digest;
00167 
00168   if (cstate->clientstate == CHAPCS_INITIAL ||
00169       cstate->clientstate == CHAPCS_PENDING) {
00170     /* lower layer isn't up - wait until later */
00171     cstate->clientstate = CHAPCS_PENDING;
00172     return;
00173   }
00174 
00175   /*
00176    * We get here as a result of LCP coming up.
00177    * So even if CHAP was open before, we will 
00178    * have to re-authenticate ourselves.
00179    */
00180   cstate->clientstate = CHAPCS_LISTEN;
00181 }
00182 
00183 
00184 /*
00185  * ChapAuthPeer - Authenticate our peer (start server).
00186  */
00187 void
00188 ChapAuthPeer(int unit, char *our_name, int digest)
00189 {
00190   chap_state *cstate = &chap[unit];
00191 
00192   cstate->chal_name = our_name;
00193   cstate->chal_type = digest;
00194   
00195   if (cstate->serverstate == CHAPSS_INITIAL ||
00196       cstate->serverstate == CHAPSS_PENDING) {
00197     /* lower layer isn't up - wait until later */
00198     cstate->serverstate = CHAPSS_PENDING;
00199     return;
00200   }
00201 
00202   ChapGenChallenge(cstate);
00203   ChapSendChallenge(cstate);    /* crank it up dude! */
00204   cstate->serverstate = CHAPSS_INITIAL_CHAL;
00205 }
00206 
00207 
00208 /**********************************/
00209 /*** LOCAL FUNCTION DEFINITIONS ***/
00210 /**********************************/
00211 /*
00212  * ChapInit - Initialize a CHAP unit.
00213  */
00214 static void
00215 ChapInit(int unit)
00216 {
00217   chap_state *cstate = &chap[unit];
00218 
00219   BZERO(cstate, sizeof(*cstate));
00220   cstate->unit = unit;
00221   cstate->clientstate = CHAPCS_INITIAL;
00222   cstate->serverstate = CHAPSS_INITIAL;
00223   cstate->timeouttime = CHAP_DEFTIMEOUT;
00224   cstate->max_transmits = CHAP_DEFTRANSMITS;
00225   /* random number generator is initialized in magic_init */
00226 }
00227 
00228 
00229 /*
00230  * ChapChallengeTimeout - Timeout expired on sending challenge.
00231  */
00232 static void
00233 ChapChallengeTimeout(void *arg)
00234 {
00235   chap_state *cstate = (chap_state *) arg;
00236 
00237   /* if we aren't sending challenges, don't worry.  then again we */
00238   /* probably shouldn't be here either */
00239   if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
00240       cstate->serverstate != CHAPSS_RECHALLENGE) {
00241     return;
00242   }
00243 
00244   if (cstate->chal_transmits >= cstate->max_transmits) {
00245     /* give up on peer */
00246     CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
00247     cstate->serverstate = CHAPSS_BADAUTH;
00248     auth_peer_fail(cstate->unit, PPP_CHAP);
00249     return;
00250   }
00251 
00252   ChapSendChallenge(cstate); /* Re-send challenge */
00253 }
00254 
00255 
00256 /*
00257  * ChapResponseTimeout - Timeout expired on sending response.
00258  */
00259 static void
00260 ChapResponseTimeout(void *arg)
00261 {
00262   chap_state *cstate = (chap_state *) arg;
00263 
00264   /* if we aren't sending a response, don't worry. */
00265   if (cstate->clientstate != CHAPCS_RESPONSE) {
00266     return;
00267   }
00268 
00269   ChapSendResponse(cstate);    /* re-send response */
00270 }
00271 
00272 
00273 /*
00274  * ChapRechallenge - Time to challenge the peer again.
00275  */
00276 static void
00277 ChapRechallenge(void *arg)
00278 {
00279   chap_state *cstate = (chap_state *) arg;
00280   
00281   /* if we aren't sending a response, don't worry. */
00282   if (cstate->serverstate != CHAPSS_OPEN) {
00283     return;
00284   }
00285 
00286   ChapGenChallenge(cstate);
00287   ChapSendChallenge(cstate);
00288   cstate->serverstate = CHAPSS_RECHALLENGE;
00289 }
00290 
00291 
00292 /*
00293  * ChapLowerUp - The lower layer is up.
00294  *
00295  * Start up if we have pending requests.
00296  */
00297 static void
00298 ChapLowerUp(int unit)
00299 {
00300   chap_state *cstate = &chap[unit];
00301 
00302   if (cstate->clientstate == CHAPCS_INITIAL) {
00303     cstate->clientstate = CHAPCS_CLOSED;
00304   } else if (cstate->clientstate == CHAPCS_PENDING) {
00305     cstate->clientstate = CHAPCS_LISTEN;
00306   }
00307 
00308   if (cstate->serverstate == CHAPSS_INITIAL) {
00309     cstate->serverstate = CHAPSS_CLOSED;
00310   } else if (cstate->serverstate == CHAPSS_PENDING) {
00311     ChapGenChallenge(cstate);
00312     ChapSendChallenge(cstate);
00313     cstate->serverstate = CHAPSS_INITIAL_CHAL;
00314   }
00315 }
00316 
00317 
00318 /*
00319  * ChapLowerDown - The lower layer is down.
00320  *
00321  * Cancel all timeouts.
00322  */
00323 static void
00324 ChapLowerDown(int unit)
00325 {
00326   chap_state *cstate = &chap[unit];
00327 
00328   /* Timeout(s) pending?  Cancel if so. */
00329   if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
00330       cstate->serverstate == CHAPSS_RECHALLENGE) {
00331     UNTIMEOUT(ChapChallengeTimeout, cstate);
00332   } else if (cstate->serverstate == CHAPSS_OPEN
00333       && cstate->chal_interval != 0) {
00334     UNTIMEOUT(ChapRechallenge, cstate);
00335   }
00336   if (cstate->clientstate == CHAPCS_RESPONSE) {
00337     UNTIMEOUT(ChapResponseTimeout, cstate);
00338   }
00339   cstate->clientstate = CHAPCS_INITIAL;
00340   cstate->serverstate = CHAPSS_INITIAL;
00341 }
00342 
00343 
00344 /*
00345  * ChapProtocolReject - Peer doesn't grok CHAP.
00346  */
00347 static void
00348 ChapProtocolReject(int unit)
00349 {
00350   chap_state *cstate = &chap[unit];
00351   
00352   if (cstate->serverstate != CHAPSS_INITIAL &&
00353       cstate->serverstate != CHAPSS_CLOSED) {
00354     auth_peer_fail(unit, PPP_CHAP);
00355   }
00356   if (cstate->clientstate != CHAPCS_INITIAL &&
00357       cstate->clientstate != CHAPCS_CLOSED) {
00358     auth_withpeer_fail(unit, PPP_CHAP);
00359   }
00360   ChapLowerDown(unit); /* shutdown chap */
00361 }
00362 
00363 
00364 /*
00365  * ChapInput - Input CHAP packet.
00366  */
00367 static void
00368 ChapInput(int unit, u_char *inpacket, int packet_len)
00369 {
00370   chap_state *cstate = &chap[unit];
00371   u_char *inp;
00372   u_char code, id;
00373   int len;
00374   
00375   /*
00376    * Parse header (code, id and length).
00377    * If packet too short, drop it.
00378    */
00379   inp = inpacket;
00380   if (packet_len < CHAP_HEADERLEN) {
00381     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
00382     return;
00383   }
00384   GETCHAR(code, inp);
00385   GETCHAR(id, inp);
00386   GETSHORT(len, inp);
00387   if (len < CHAP_HEADERLEN) {
00388     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
00389     return;
00390   }
00391   if (len > packet_len) {
00392     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
00393     return;
00394   }
00395   len -= CHAP_HEADERLEN;
00396   
00397   /*
00398    * Action depends on code (as in fact it usually does :-).
00399    */
00400   switch (code) {
00401     case CHAP_CHALLENGE:
00402       ChapReceiveChallenge(cstate, inp, id, len);
00403       break;
00404     
00405     case CHAP_RESPONSE:
00406       ChapReceiveResponse(cstate, inp, id, len);
00407       break;
00408     
00409     case CHAP_FAILURE:
00410       ChapReceiveFailure(cstate, inp, id, len);
00411       break;
00412     
00413     case CHAP_SUCCESS:
00414       ChapReceiveSuccess(cstate, inp, id, len);
00415       break;
00416     
00417     default:        /* Need code reject? */
00418       CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
00419       break;
00420   }
00421 }
00422 
00423 
00424 /*
00425  * ChapReceiveChallenge - Receive Challenge and send Response.
00426  */
00427 static void
00428 ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
00429 {
00430   int rchallenge_len;
00431   u_char *rchallenge;
00432   int secret_len;
00433   char secret[MAXSECRETLEN];
00434   char rhostname[256];
00435   MD5_CTX mdContext;
00436   u_char hash[MD5_SIGNATURE_SIZE];
00437   
00438   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
00439   if (cstate->clientstate == CHAPCS_CLOSED ||
00440     cstate->clientstate == CHAPCS_PENDING) {
00441     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
00442          cstate->clientstate));
00443     return;
00444   }
00445 
00446   if (len < 2) {
00447     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
00448     return;
00449   }
00450 
00451   GETCHAR(rchallenge_len, inp);
00452   len -= sizeof (u_char) + rchallenge_len;  /* now name field length */
00453   if (len < 0) {
00454     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
00455     return;
00456   }
00457   rchallenge = inp;
00458   INCPTR(rchallenge_len, inp);
00459 
00460   if (len >= sizeof(rhostname)) {
00461     len = sizeof(rhostname) - 1;
00462   }
00463   BCOPY(inp, rhostname, len);
00464   rhostname[len] = '\000';
00465 
00466   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname));
00467 
00468   /* Microsoft doesn't send their name back in the PPP packet */
00469   if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
00470     strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
00471     rhostname[sizeof(rhostname) - 1] = 0;
00472     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname));
00473   }
00474 
00475   /* get secret for authenticating ourselves with the specified host */
00476   if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {
00477     secret_len = 0;    /* assume null secret if can't find one */
00478     CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
00479   }
00480 
00481   /* cancel response send timeout if necessary */
00482   if (cstate->clientstate == CHAPCS_RESPONSE) {
00483     UNTIMEOUT(ChapResponseTimeout, cstate);
00484   }
00485 
00486   cstate->resp_id = id;
00487   cstate->resp_transmits = 0;
00488 
00489   /*  generate MD based on negotiated type */
00490   switch (cstate->resp_type) { 
00491 
00492   case CHAP_DIGEST_MD5:
00493     MD5Init(&mdContext);
00494     MD5Update(&mdContext, &cstate->resp_id, 1);
00495     MD5Update(&mdContext, (u_char*)secret, secret_len);
00496     MD5Update(&mdContext, rchallenge, rchallenge_len);
00497     MD5Final(hash, &mdContext);
00498     BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
00499     cstate->resp_length = MD5_SIGNATURE_SIZE;
00500     break;
00501   
00502 #ifdef CHAPMS
00503   case CHAP_MICROSOFT:
00504     ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
00505     break;
00506 #endif
00507 
00508   default:
00509     CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
00510     return;
00511   }
00512 
00513   BZERO(secret, sizeof(secret));
00514   ChapSendResponse(cstate);
00515 }
00516 
00517 
00518 /*
00519  * ChapReceiveResponse - Receive and process response.
00520  */
00521 static void
00522 ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
00523 {
00524   u_char *remmd, remmd_len;
00525   int secret_len, old_state;
00526   int code;
00527   char rhostname[256];
00528   MD5_CTX mdContext;
00529   char secret[MAXSECRETLEN];
00530   u_char hash[MD5_SIGNATURE_SIZE];
00531   
00532   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
00533   
00534   if (cstate->serverstate == CHAPSS_CLOSED ||
00535       cstate->serverstate == CHAPSS_PENDING) {
00536     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
00537     cstate->serverstate));
00538     return;
00539   }
00540 
00541   if (id != cstate->chal_id) {
00542     return;      /* doesn't match ID of last challenge */
00543   }
00544 
00545   /*
00546   * If we have received a duplicate or bogus Response,
00547   * we have to send the same answer (Success/Failure)
00548   * as we did for the first Response we saw.
00549   */
00550   if (cstate->serverstate == CHAPSS_OPEN) {
00551     ChapSendStatus(cstate, CHAP_SUCCESS);
00552     return;
00553   }
00554   if (cstate->serverstate == CHAPSS_BADAUTH) {
00555     ChapSendStatus(cstate, CHAP_FAILURE);
00556     return;
00557   }
00558   
00559   if (len < 2) {
00560     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
00561     return;
00562   }
00563   GETCHAR(remmd_len, inp); /* get length of MD */
00564   remmd = inp;             /* get pointer to MD */
00565   INCPTR(remmd_len, inp);
00566   
00567   len -= sizeof (u_char) + remmd_len;
00568   if (len < 0) {
00569     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
00570     return;
00571   }
00572 
00573   UNTIMEOUT(ChapChallengeTimeout, cstate);
00574   
00575   if (len >= sizeof(rhostname)) {
00576     len = sizeof(rhostname) - 1;
00577   }
00578   BCOPY(inp, rhostname, len);
00579   rhostname[len] = '\000';
00580 
00581   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", 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, secret, &secret_len, 1)) {
00589     /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
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", cstate->clientstate));
00655     return;
00656   }
00657   
00658   UNTIMEOUT(ChapResponseTimeout, cstate);
00659   
00660   /*
00661    * Print message.
00662    */
00663   if (len > 0) {
00664     PRINTMSG(inp, len);
00665   }
00666 
00667   cstate->clientstate = CHAPCS_OPEN;
00668 
00669   auth_withpeer_success(cstate->unit, PPP_CHAP);
00670 }
00671 
00672 
00673 /*
00674  * ChapReceiveFailure - Receive failure.
00675  */
00676 static void
00677 ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
00678 {
00679   LWIP_UNUSED_ARG(id);
00680   LWIP_UNUSED_ARG(inp);
00681 
00682   CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
00683 
00684   if (cstate->clientstate != CHAPCS_RESPONSE) {
00685     /* don't know what this is */
00686     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate));
00687     return;
00688   }
00689 
00690   UNTIMEOUT(ChapResponseTimeout, cstate);
00691 
00692   /*
00693    * Print message.
00694    */
00695   if (len > 0) {
00696     PRINTMSG(inp, len);
00697   }
00698 
00699   CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
00700   auth_withpeer_fail(cstate->unit, PPP_CHAP);
00701 }
00702 
00703 
00704 /*
00705  * ChapSendChallenge - Send an Authenticate challenge.
00706  */
00707 static void
00708 ChapSendChallenge(chap_state *cstate)
00709 {
00710   u_char *outp;
00711   int chal_len, name_len;
00712   int outlen;
00713   
00714   chal_len = cstate->chal_len;
00715   name_len = strlen(cstate->chal_name);
00716   outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
00717   outp = outpacket_buf[cstate->unit];
00718   
00719   MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */
00720   
00721   PUTCHAR(CHAP_CHALLENGE, outp);
00722   PUTCHAR(cstate->chal_id, outp);
00723   PUTSHORT(outlen, outp);
00724   
00725   PUTCHAR(chal_len, outp);    /* put length of challenge */
00726   BCOPY(cstate->challenge, outp, chal_len);
00727   INCPTR(chal_len, outp);
00728   
00729   BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */
00730   
00731   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00732   
00733   CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
00734   
00735   TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
00736   ++cstate->chal_transmits;
00737 }
00738 
00739 
00740 /*
00741  * ChapSendStatus - Send a status response (ack or nak).
00742  */
00743 static void
00744 ChapSendStatus(chap_state *cstate, int code)
00745 {
00746   u_char *outp;
00747   int outlen, msglen;
00748   char msg[256];
00749   
00750   if (code == CHAP_SUCCESS) {
00751     strcpy(msg, "Welcome!");
00752   } else {
00753     strcpy(msg, "I don't like you.  Go 'way.");
00754   }
00755   msglen = strlen(msg);
00756   
00757   outlen = CHAP_HEADERLEN + msglen;
00758   outp = outpacket_buf[cstate->unit];
00759   
00760   MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */
00761   
00762   PUTCHAR(code, outp);
00763   PUTCHAR(cstate->chal_id, outp);
00764   PUTSHORT(outlen, outp);
00765   BCOPY(msg, outp, msglen);
00766   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00767   
00768   CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id));
00769 }
00770 
00771 /*
00772  * ChapGenChallenge is used to generate a pseudo-random challenge string of
00773  * a pseudo-random length between min_len and max_len.  The challenge
00774  * string and its length are stored in *cstate, and various other fields of
00775  * *cstate are initialized.
00776  */
00777 
00778 static void
00779 ChapGenChallenge(chap_state *cstate)
00780 {
00781   int chal_len;
00782   u_char *ptr = cstate->challenge;
00783   int i;
00784   
00785   /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
00786      MAX_CHALLENGE_LENGTH */  
00787   chal_len = (unsigned)
00788         ((((magic() >> 16) *
00789               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
00790            + MIN_CHALLENGE_LENGTH);
00791   cstate->chal_len = chal_len;
00792   cstate->chal_id = ++cstate->id;
00793   cstate->chal_transmits = 0;
00794   
00795   /* generate a random string */
00796   for (i = 0; i < chal_len; i++ ) {
00797     *ptr++ = (char) (magic() & 0xff);
00798   }
00799 }
00800 
00801 /*
00802  * ChapSendResponse - send a response packet with values as specified
00803  * in *cstate.
00804  */
00805 /* ARGSUSED */
00806 static void
00807 ChapSendResponse(chap_state *cstate)
00808 {
00809   u_char *outp;
00810   int outlen, md_len, name_len;
00811   
00812   md_len = cstate->resp_length;
00813   name_len = strlen(cstate->resp_name);
00814   outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
00815   outp = outpacket_buf[cstate->unit];
00816   
00817   MAKEHEADER(outp, PPP_CHAP);
00818   
00819   PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */
00820   PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */
00821   PUTSHORT(outlen, outp);      /* packet length */
00822   
00823   PUTCHAR(md_len, outp);      /* length of MD */
00824   BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */
00825   INCPTR(md_len, outp);
00826   
00827   BCOPY(cstate->resp_name, outp, name_len);  /* append our name */
00828   
00829   /* send the packet */
00830   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
00831   
00832   cstate->clientstate = CHAPCS_RESPONSE;
00833   TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
00834   ++cstate->resp_transmits;
00835 }
00836 
00837 #if 0
00838 static char *ChapCodenames[] = {
00839   "Challenge", "Response", "Success", "Failure"
00840 };
00841 /*
00842  * ChapPrintPkt - print the contents of a CHAP packet.
00843  */
00844 static int
00845 ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
00846 {
00847   int code, id, len;
00848   int clen, nlen;
00849   u_char x;
00850   
00851   if (plen < CHAP_HEADERLEN) {
00852     return 0;
00853   }
00854   GETCHAR(code, p);
00855   GETCHAR(id, p);
00856   GETSHORT(len, p);
00857   if (len < CHAP_HEADERLEN || len > plen) {
00858     return 0;
00859   }
00860   if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
00861     printer(arg, " %s", ChapCodenames[code-1]);
00862   } else {
00863     printer(arg, " code=0x%x", code);
00864   }
00865   printer(arg, " id=0x%x", id);
00866   len -= CHAP_HEADERLEN;
00867   switch (code) {
00868     case CHAP_CHALLENGE:
00869     case CHAP_RESPONSE:
00870       if (len < 1) {
00871         break;
00872       }
00873       clen = p[0];
00874       if (len < clen + 1) {
00875         break;
00876       }
00877       ++p;
00878       nlen = len - clen - 1;
00879       printer(arg, " <");
00880       for (; clen > 0; --clen) {
00881         GETCHAR(x, p);
00882         printer(arg, "%.2x", x);
00883       }
00884       printer(arg, ">, name = %.*Z", nlen, p);
00885       break;
00886     case CHAP_FAILURE:
00887     case CHAP_SUCCESS:
00888       printer(arg, " %.*Z", len, p);
00889       break;
00890     default:
00891       for (clen = len; clen > 0; --clen) {
00892         GETCHAR(x, p);
00893         printer(arg, " %.2x", x);
00894       }
00895   }
00896 
00897   return len + CHAP_HEADERLEN;
00898 }
00899 #endif
00900 
00901 #endif /* CHAP_SUPPORT */
00902 
00903 #endif /* PPP_SUPPORT */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines