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