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