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