Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

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 */