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