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