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