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