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