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