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