1 /* 2 * chap.c - New CHAP implementation. 3 * 4 * Copyright (c) 2003-2024 Paul Mackerras. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 19 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 20 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 23 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 24 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 */ 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <stdlib.h> 32 #include <string.h> 33 #include "pppd-private.h" 34 #include "options.h" 35 #include "session.h" 36 #include "chap.h" 37 #include "chap-md5.h" 38 39 #ifdef PPP_WITH_CHAPMS 40 #include "chap_ms.h" 41 #define MDTYPE_ALL (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) 42 #else 43 #define MDTYPE_ALL (MDTYPE_MD5) 44 #endif 45 46 int chap_mdtype_all = MDTYPE_ALL; 47 48 /* Hook for a plugin to validate CHAP challenge */ 49 chap_verify_hook_fn *chap_verify_hook = NULL; 50 51 /* 52 * Option variables. 53 */ 54 int chap_server_timeout_time = 3; 55 int chap_max_transmits = 10; 56 int chap_rechallenge_time = 0; 57 int chap_client_timeout_time = 60; 58 int chapms_strip_domain = 0; 59 60 /* 61 * Command-line options. 62 */ 63 static struct option chap_option_list[] = { 64 { "chap-restart", o_int, &chap_server_timeout_time, 65 "Set timeout for CHAP (as server)", OPT_PRIO }, 66 { "chap-max-challenge", o_int, &chap_max_transmits, 67 "Set max #xmits for challenge", OPT_PRIO }, 68 { "chap-interval", o_int, &chap_rechallenge_time, 69 "Set interval for rechallenge", OPT_PRIO }, 70 { "chap-timeout", o_int, &chap_client_timeout_time, 71 "Set timeout for CHAP (as client)", OPT_PRIO }, 72 { "chapms-strip-domain", o_bool, &chapms_strip_domain, 73 "Strip the domain prefix before the Username", 1 }, 74 { NULL } 75 }; 76 77 /* 78 * Internal state. 79 */ 80 static struct chap_client_state { 81 int flags; 82 char *name; 83 struct chap_digest_type *digest; 84 unsigned char priv[64]; /* private area for digest's use */ 85 } client; 86 87 /* 88 * These limits apply to challenge and response packets we send. 89 * The +4 is the +1 that we actually need rounded up. 90 */ 91 #define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) 92 #define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) 93 94 static struct chap_server_state { 95 int flags; 96 int id; 97 char *name; 98 struct chap_digest_type *digest; 99 int challenge_xmits; 100 int challenge_pktlen; 101 unsigned char challenge[CHAL_MAX_PKTLEN]; 102 char message[256]; 103 } server; 104 105 /* Values for flags in chap_client_state and chap_server_state */ 106 #define LOWERUP 1 107 #define AUTH_STARTED 2 108 #define AUTH_DONE 4 109 #define AUTH_FAILED 8 110 #define TIMEOUT_PENDING 0x10 111 #define CHALLENGE_VALID 0x20 112 113 /* 114 * Prototypes. 115 */ 116 static void chap_init(int unit); 117 static void chap_lowerup(int unit); 118 static void chap_lowerdown(int unit); 119 static void chap_server_timeout(void *arg); 120 static void chap_client_timeout(void *arg); 121 static void chap_generate_challenge(struct chap_server_state *ss); 122 static void chap_handle_response(struct chap_server_state *ss, int code, 123 unsigned char *pkt, int len); 124 static chap_verify_hook_fn chap_verify_response; 125 static void chap_respond(struct chap_client_state *cs, int id, 126 unsigned char *pkt, int len); 127 static void chap_handle_status(struct chap_client_state *cs, int code, int id, 128 unsigned char *pkt, int len); 129 static void chap_protrej(int unit); 130 static void chap_input(int unit, unsigned char *pkt, int pktlen); 131 static int chap_print_pkt(unsigned char *p, int plen, 132 void (*printer)(void *, char *, ...), void *arg); 133 134 /* List of digest types that we know about */ 135 static struct chap_digest_type *chap_digests; 136 137 /* 138 * chap_init - reset to initial state. 139 */ 140 static void 141 chap_init(int unit) 142 { 143 memset(&client, 0, sizeof(client)); 144 memset(&server, 0, sizeof(server)); 145 146 chap_md5_init(); 147 #ifdef PPP_WITH_CHAPMS 148 chapms_init(); 149 #endif 150 } 151 152 /* 153 * Add a new digest type to the list. 154 */ 155 void 156 chap_register_digest(struct chap_digest_type *dp) 157 { 158 dp->next = chap_digests; 159 chap_digests = dp; 160 } 161 162 /* 163 * Lookup a digest type by code 164 */ 165 struct chap_digest_type * 166 chap_find_digest(int digest_code) { 167 struct chap_digest_type *dp = NULL; 168 for (dp = chap_digests; dp != NULL; dp = dp->next) 169 if (dp->code == digest_code) 170 break; 171 return dp; 172 } 173 174 /* 175 * chap_lowerup - we can start doing stuff now. 176 */ 177 static void 178 chap_lowerup(int unit) 179 { 180 struct chap_client_state *cs = &client; 181 struct chap_server_state *ss = &server; 182 183 cs->flags |= LOWERUP; 184 ss->flags |= LOWERUP; 185 if (ss->flags & AUTH_STARTED) 186 chap_server_timeout(ss); 187 } 188 189 static void 190 chap_lowerdown(int unit) 191 { 192 struct chap_client_state *cs = &client; 193 struct chap_server_state *ss = &server; 194 195 if (cs->flags & TIMEOUT_PENDING) 196 UNTIMEOUT(chap_client_timeout, cs); 197 cs->flags = 0; 198 if (ss->flags & TIMEOUT_PENDING) 199 UNTIMEOUT(chap_server_timeout, ss); 200 ss->flags = 0; 201 } 202 203 /* 204 * chap_auth_peer - Start authenticating the peer. 205 * If the lower layer is already up, we start sending challenges, 206 * otherwise we wait for the lower layer to come up. 207 */ 208 void 209 chap_auth_peer(int unit, char *our_name, int digest_code) 210 { 211 struct chap_server_state *ss = &server; 212 struct chap_digest_type *dp; 213 214 if (ss->flags & AUTH_STARTED) { 215 error("CHAP: peer authentication already started!"); 216 return; 217 } 218 219 dp = chap_find_digest(digest_code); 220 if (dp == NULL) 221 fatal("CHAP digest 0x%x requested but not available", 222 digest_code); 223 224 ss->digest = dp; 225 ss->name = our_name; 226 /* Start with a random ID value */ 227 ss->id = (unsigned char)(drand48() * 256); 228 ss->flags |= AUTH_STARTED; 229 if (ss->flags & LOWERUP) 230 chap_server_timeout(ss); 231 } 232 233 /* 234 * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. 235 * There isn't much to do until we receive a challenge. 236 */ 237 void 238 chap_auth_with_peer(int unit, char *our_name, int digest_code) 239 { 240 struct chap_client_state *cs = &client; 241 struct chap_digest_type *dp; 242 243 if (cs->flags & AUTH_STARTED) { 244 error("CHAP: authentication with peer already started!"); 245 return; 246 } 247 for (dp = chap_digests; dp != NULL; dp = dp->next) 248 if (dp->code == digest_code) 249 break; 250 if (dp == NULL) 251 fatal("CHAP digest 0x%x requested but not available", 252 digest_code); 253 254 cs->digest = dp; 255 cs->name = our_name; 256 cs->flags |= AUTH_STARTED | TIMEOUT_PENDING; 257 TIMEOUT(chap_client_timeout, cs, chap_client_timeout_time); 258 } 259 260 /* 261 * chap_server_timeout - It's time to send another challenge to the peer. 262 * This could be either a retransmission of a previous challenge, 263 * or a new challenge to start re-authentication. 264 */ 265 static void 266 chap_server_timeout(void *arg) 267 { 268 struct chap_server_state *ss = arg; 269 270 ss->flags &= ~TIMEOUT_PENDING; 271 if ((ss->flags & CHALLENGE_VALID) == 0) { 272 ss->challenge_xmits = 0; 273 chap_generate_challenge(ss); 274 ss->flags |= CHALLENGE_VALID; 275 } else if (ss->challenge_xmits >= chap_max_transmits) { 276 ss->flags &= ~CHALLENGE_VALID; 277 ss->flags |= AUTH_DONE | AUTH_FAILED; 278 auth_peer_fail(0, PPP_CHAP); 279 return; 280 } 281 282 output(0, ss->challenge, ss->challenge_pktlen); 283 ++ss->challenge_xmits; 284 ss->flags |= TIMEOUT_PENDING; 285 TIMEOUT(chap_server_timeout, arg, chap_server_timeout_time); 286 } 287 288 /* chap_client_timeout - Authentication with peer timed out. */ 289 static void 290 chap_client_timeout(void *arg) 291 { 292 struct chap_client_state *cs = arg; 293 294 cs->flags &= ~TIMEOUT_PENDING; 295 cs->flags |= AUTH_DONE | AUTH_FAILED; 296 error("CHAP authentication timed out"); 297 auth_withpeer_fail(0, PPP_CHAP); 298 } 299 300 /* 301 * chap_generate_challenge - generate a challenge string and format 302 * the challenge packet in ss->challenge_pkt. 303 */ 304 static void 305 chap_generate_challenge(struct chap_server_state *ss) 306 { 307 int clen = 1, nlen, len; 308 unsigned char *p; 309 310 p = ss->challenge; 311 MAKEHEADER(p, PPP_CHAP); 312 p += CHAP_HDRLEN; 313 ss->digest->generate_challenge(p); 314 clen = *p; 315 nlen = strlen(ss->name); 316 memcpy(p + 1 + clen, ss->name, nlen); 317 318 len = CHAP_HDRLEN + 1 + clen + nlen; 319 ss->challenge_pktlen = PPP_HDRLEN + len; 320 321 p = ss->challenge + PPP_HDRLEN; 322 p[0] = CHAP_CHALLENGE; 323 p[1] = ++ss->id; 324 p[2] = len >> 8; 325 p[3] = len; 326 } 327 328 /* 329 * chap_handle_response - check the response to our challenge. 330 */ 331 static void 332 chap_handle_response(struct chap_server_state *ss, int id, 333 unsigned char *pkt, int len) 334 { 335 int response_len, ok, mlen; 336 unsigned char *response, *p; 337 char *name = NULL; 338 chap_verify_hook_fn *verifier; 339 char rname[MAXNAMELEN+1]; 340 341 if ((ss->flags & LOWERUP) == 0) 342 return; 343 if (id != ss->challenge[PPP_HDRLEN+1] || len < 2) 344 return; 345 if (ss->flags & CHALLENGE_VALID) { 346 response = pkt; 347 GETCHAR(response_len, pkt); 348 len -= response_len + 1; /* length of name */ 349 name = (char *)pkt + response_len; 350 if (len < 0) 351 return; 352 353 if (ss->flags & TIMEOUT_PENDING) { 354 ss->flags &= ~TIMEOUT_PENDING; 355 UNTIMEOUT(chap_server_timeout, ss); 356 } 357 358 if (explicit_remote) { 359 name = remote_name; 360 } else { 361 /* Null terminate and clean remote name. */ 362 slprintf(rname, sizeof(rname), "%.*v", len, name); 363 name = rname; 364 365 /* strip the MS domain name */ 366 if (chapms_strip_domain && strrchr(rname, '\\')) { 367 char tmp[MAXNAMELEN+1]; 368 369 strcpy(tmp, strrchr(rname, '\\') + 1); 370 strcpy(rname, tmp); 371 } 372 } 373 374 if (chap_verify_hook) 375 verifier = chap_verify_hook; 376 else 377 verifier = chap_verify_response; 378 ok = (*verifier)(name, ss->name, id, ss->digest, 379 ss->challenge + PPP_HDRLEN + CHAP_HDRLEN, 380 response, ss->message, sizeof(ss->message)); 381 if (!ok || !auth_number()) { 382 ss->flags |= AUTH_FAILED; 383 warn("Peer %q failed CHAP authentication", name); 384 } 385 } else if ((ss->flags & AUTH_DONE) == 0) 386 return; 387 388 /* send the response */ 389 p = outpacket_buf; 390 MAKEHEADER(p, PPP_CHAP); 391 mlen = strlen(ss->message); 392 len = CHAP_HDRLEN + mlen; 393 p[0] = (ss->flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; 394 p[1] = id; 395 p[2] = len >> 8; 396 p[3] = len; 397 if (mlen > 0) 398 memcpy(p + CHAP_HDRLEN, ss->message, mlen); 399 output(0, outpacket_buf, PPP_HDRLEN + len); 400 401 if (ss->flags & CHALLENGE_VALID) { 402 ss->flags &= ~CHALLENGE_VALID; 403 if (!(ss->flags & AUTH_DONE) && !(ss->flags & AUTH_FAILED)) { 404 /* 405 * Auth is OK, so now we need to check session restrictions 406 * to ensure everything is OK, but only if we used a 407 * plugin, and only if we're configured to check. This 408 * allows us to do PAM checks on PPP servers that 409 * authenticate against ActiveDirectory, and use AD for 410 * account info (like when using Winbind integrated with 411 * PAM). 412 */ 413 if (session_mgmt && 414 session_check(name, NULL, devnam, NULL) == 0) { 415 ss->flags |= AUTH_FAILED; 416 warn("Peer %q failed CHAP Session verification", name); 417 } 418 } 419 if (ss->flags & AUTH_FAILED) { 420 auth_peer_fail(0, PPP_CHAP); 421 } else { 422 if ((ss->flags & AUTH_DONE) == 0) 423 auth_peer_success(0, PPP_CHAP, 424 ss->digest->code, 425 name, strlen(name)); 426 if (chap_rechallenge_time) { 427 ss->flags |= TIMEOUT_PENDING; 428 TIMEOUT(chap_server_timeout, ss, 429 chap_rechallenge_time); 430 } 431 } 432 ss->flags |= AUTH_DONE; 433 } 434 } 435 436 /* 437 * chap_verify_response - check whether the peer's response matches 438 * what we think it should be. Returns 1 if it does (authentication 439 * succeeded), or 0 if it doesn't. 440 */ 441 static int 442 chap_verify_response(char *name, char *ourname, int id, 443 struct chap_digest_type *digest, 444 unsigned char *challenge, unsigned char *response, 445 char *message, int message_space) 446 { 447 int ok; 448 unsigned char secret[MAXSECRETLEN]; 449 int secret_len; 450 451 /* Get the secret that the peer is supposed to know */ 452 if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) { 453 error("No CHAP secret found for authenticating %q", name); 454 return 0; 455 } 456 457 ok = digest->verify_response(id, name, secret, secret_len, challenge, 458 response, message, message_space); 459 memset(secret, 0, sizeof(secret)); 460 461 return ok; 462 } 463 464 /* 465 * chap_respond - Generate and send a response to a challenge. 466 */ 467 static void 468 chap_respond(struct chap_client_state *cs, int id, 469 unsigned char *pkt, int len) 470 { 471 int clen, nlen; 472 int secret_len; 473 unsigned char *p; 474 unsigned char response[RESP_MAX_PKTLEN]; 475 char rname[MAXNAMELEN+1]; 476 char secret[MAXSECRETLEN+1]; 477 478 if ((cs->flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) 479 return; /* not ready */ 480 if (len < 2 || len < pkt[0] + 1) 481 return; /* too short */ 482 clen = pkt[0]; 483 nlen = len - (clen + 1); 484 485 /* Null terminate and clean remote name. */ 486 slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); 487 488 /* Microsoft doesn't send their name back in the PPP packet */ 489 if (explicit_remote || (remote_name[0] != 0 && rname[0] == 0)) 490 strlcpy(rname, remote_name, sizeof(rname)); 491 492 /* get secret for authenticating ourselves with the specified host */ 493 if (!get_secret(0, cs->name, rname, secret, &secret_len, 0)) { 494 secret_len = 0; /* assume null secret if can't find one */ 495 warn("No CHAP secret found for authenticating us to %q", rname); 496 } 497 498 p = response; 499 MAKEHEADER(p, PPP_CHAP); 500 p += CHAP_HDRLEN; 501 502 cs->digest->make_response(p, id, cs->name, pkt, 503 secret, secret_len, cs->priv); 504 memset(secret, 0, secret_len); 505 506 clen = *p; 507 nlen = strlen(cs->name); 508 memcpy(p + clen + 1, cs->name, nlen); 509 510 p = response + PPP_HDRLEN; 511 len = CHAP_HDRLEN + clen + 1 + nlen; 512 p[0] = CHAP_RESPONSE; 513 p[1] = id; 514 p[2] = len >> 8; 515 p[3] = len; 516 517 output(0, response, PPP_HDRLEN + len); 518 } 519 520 static void 521 chap_handle_status(struct chap_client_state *cs, int code, int id, 522 unsigned char *pkt, int len) 523 { 524 const char *msg = NULL; 525 526 if ((cs->flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) 527 != (AUTH_STARTED|LOWERUP)) 528 return; 529 cs->flags |= AUTH_DONE; 530 531 UNTIMEOUT(chap_client_timeout, cs); 532 cs->flags &= ~TIMEOUT_PENDING; 533 534 if (code == CHAP_SUCCESS) { 535 /* used for MS-CHAP v2 mutual auth, yuck */ 536 if (cs->digest->check_success != NULL) { 537 if (!(*cs->digest->check_success)(id, pkt, len)) 538 code = CHAP_FAILURE; 539 } else 540 msg = "CHAP authentication succeeded"; 541 } else { 542 if (cs->digest->handle_failure != NULL) 543 (*cs->digest->handle_failure)(pkt, len); 544 else 545 msg = "CHAP authentication failed"; 546 } 547 if (msg) { 548 if (len > 0) 549 info("%s: %.*v", msg, len, pkt); 550 else 551 info("%s", msg); 552 } 553 if (code == CHAP_SUCCESS) 554 auth_withpeer_success(0, PPP_CHAP, cs->digest->code); 555 else { 556 cs->flags |= AUTH_FAILED; 557 error("CHAP authentication failed"); 558 auth_withpeer_fail(0, PPP_CHAP); 559 } 560 } 561 562 static void 563 chap_input(int unit, unsigned char *pkt, int pktlen) 564 { 565 struct chap_client_state *cs = &client; 566 struct chap_server_state *ss = &server; 567 unsigned char code, id; 568 int len; 569 570 if (pktlen < CHAP_HDRLEN) 571 return; 572 GETCHAR(code, pkt); 573 GETCHAR(id, pkt); 574 GETSHORT(len, pkt); 575 if (len < CHAP_HDRLEN || len > pktlen) 576 return; 577 len -= CHAP_HDRLEN; 578 579 switch (code) { 580 case CHAP_CHALLENGE: 581 chap_respond(cs, id, pkt, len); 582 break; 583 case CHAP_RESPONSE: 584 chap_handle_response(ss, id, pkt, len); 585 break; 586 case CHAP_FAILURE: 587 case CHAP_SUCCESS: 588 chap_handle_status(cs, code, id, pkt, len); 589 break; 590 } 591 } 592 593 static void 594 chap_protrej(int unit) 595 { 596 struct chap_client_state *cs = &client; 597 struct chap_server_state *ss = &server; 598 599 if (ss->flags & TIMEOUT_PENDING) { 600 ss->flags &= ~TIMEOUT_PENDING; 601 UNTIMEOUT(chap_server_timeout, ss); 602 } 603 if (ss->flags & AUTH_STARTED) { 604 ss->flags = 0; 605 auth_peer_fail(0, PPP_CHAP); 606 } 607 if ((cs->flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { 608 cs->flags &= ~AUTH_STARTED; 609 error("CHAP authentication failed due to protocol-reject"); 610 auth_withpeer_fail(0, PPP_CHAP); 611 } 612 } 613 614 /* 615 * chap_print_pkt - print the contents of a CHAP packet. 616 */ 617 static char *chap_code_names[] = { 618 "Challenge", "Response", "Success", "Failure" 619 }; 620 621 static int 622 chap_print_pkt(unsigned char *p, int plen, 623 void (*printer)(void *, char *, ...), void *arg) 624 { 625 int code, id, len; 626 int clen, nlen; 627 unsigned char x; 628 629 if (plen < CHAP_HDRLEN) 630 return 0; 631 GETCHAR(code, p); 632 GETCHAR(id, p); 633 GETSHORT(len, p); 634 if (len < CHAP_HDRLEN || len > plen) 635 return 0; 636 637 if (code >= 1 && code <= sizeof(chap_code_names) / sizeof(char *)) 638 printer(arg, " %s", chap_code_names[code-1]); 639 else 640 printer(arg, " code=0x%x", code); 641 printer(arg, " id=0x%x", id); 642 len -= CHAP_HDRLEN; 643 switch (code) { 644 case CHAP_CHALLENGE: 645 case CHAP_RESPONSE: 646 if (len < 1) 647 break; 648 clen = p[0]; 649 if (len < clen + 1) 650 break; 651 ++p; 652 nlen = len - clen - 1; 653 printer(arg, " <"); 654 for (; clen > 0; --clen) { 655 GETCHAR(x, p); 656 printer(arg, "%.2x", x); 657 } 658 printer(arg, ">, name = "); 659 print_string((char *)p, nlen, printer, arg); 660 break; 661 case CHAP_FAILURE: 662 case CHAP_SUCCESS: 663 printer(arg, " "); 664 print_string((char *)p, len, printer, arg); 665 break; 666 default: 667 for (clen = len; clen > 0; --clen) { 668 GETCHAR(x, p); 669 printer(arg, " %.2x", x); 670 } 671 } 672 673 return len + CHAP_HDRLEN; 674 } 675 676 struct protent chap_protent = { 677 PPP_CHAP, 678 chap_init, 679 chap_input, 680 chap_protrej, 681 chap_lowerup, 682 chap_lowerdown, 683 NULL, /* open */ 684 NULL, /* close */ 685 chap_print_pkt, 686 NULL, /* datainput */ 687 1, /* enabled_flag */ 688 "CHAP", /* name */ 689 NULL, /* data_name */ 690 chap_option_list, 691 NULL, /* check_options */ 692 }; 693