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