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