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