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