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