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