NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
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 */
Generated on Tue Jul 12 2022 11:52:56 by 1.7.2