1195972f6Sopenharmony_ci/* 2195972f6Sopenharmony_ci * chap-new.c - New CHAP implementation. 3195972f6Sopenharmony_ci * 4195972f6Sopenharmony_ci * Copyright (c) 2003 Paul Mackerras. All rights reserved. 5195972f6Sopenharmony_ci * 6195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 7195972f6Sopenharmony_ci * modification, are permitted provided that the following conditions 8195972f6Sopenharmony_ci * are met: 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 11195972f6Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 12195972f6Sopenharmony_ci * 13195972f6Sopenharmony_ci * 2. The name(s) of the authors of this software must not be used to 14195972f6Sopenharmony_ci * endorse or promote products derived from this software without 15195972f6Sopenharmony_ci * prior written permission. 16195972f6Sopenharmony_ci * 17195972f6Sopenharmony_ci * 3. Redistributions of any form whatsoever must retain the following 18195972f6Sopenharmony_ci * acknowledgment: 19195972f6Sopenharmony_ci * "This product includes software developed by Paul Mackerras 20195972f6Sopenharmony_ci * <paulus@samba.org>". 21195972f6Sopenharmony_ci * 22195972f6Sopenharmony_ci * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 23195972f6Sopenharmony_ci * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 24195972f6Sopenharmony_ci * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 25195972f6Sopenharmony_ci * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 26195972f6Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 27195972f6Sopenharmony_ci * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 28195972f6Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 29195972f6Sopenharmony_ci */ 30195972f6Sopenharmony_ci 31195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h" 32195972f6Sopenharmony_ci#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ 33195972f6Sopenharmony_ci 34195972f6Sopenharmony_ci#if 0 /* UNUSED */ 35195972f6Sopenharmony_ci#include <stdlib.h> 36195972f6Sopenharmony_ci#include <string.h> 37195972f6Sopenharmony_ci#endif /* UNUSED */ 38195972f6Sopenharmony_ci 39195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h" 40195972f6Sopenharmony_ci 41195972f6Sopenharmony_ci#if 0 /* UNUSED */ 42195972f6Sopenharmony_ci#include "session.h" 43195972f6Sopenharmony_ci#endif /* UNUSED */ 44195972f6Sopenharmony_ci 45195972f6Sopenharmony_ci#include "netif/ppp/chap-new.h" 46195972f6Sopenharmony_ci#include "netif/ppp/chap-md5.h" 47195972f6Sopenharmony_ci#if MSCHAP_SUPPORT 48195972f6Sopenharmony_ci#include "netif/ppp/chap_ms.h" 49195972f6Sopenharmony_ci#endif 50195972f6Sopenharmony_ci#include "netif/ppp/magic.h" 51195972f6Sopenharmony_ci 52195972f6Sopenharmony_ci#if 0 /* UNUSED */ 53195972f6Sopenharmony_ci/* Hook for a plugin to validate CHAP challenge */ 54195972f6Sopenharmony_ciint (*chap_verify_hook)(const char *name, const char *ourname, int id, 55195972f6Sopenharmony_ci const struct chap_digest_type *digest, 56195972f6Sopenharmony_ci const unsigned char *challenge, const unsigned char *response, 57195972f6Sopenharmony_ci char *message, int message_space) = NULL; 58195972f6Sopenharmony_ci#endif /* UNUSED */ 59195972f6Sopenharmony_ci 60195972f6Sopenharmony_ci#if PPP_OPTIONS 61195972f6Sopenharmony_ci/* 62195972f6Sopenharmony_ci * Command-line options. 63195972f6Sopenharmony_ci */ 64195972f6Sopenharmony_cistatic option_t chap_option_list[] = { 65195972f6Sopenharmony_ci { "chap-restart", o_int, &chap_timeout_time, 66195972f6Sopenharmony_ci "Set timeout for CHAP", OPT_PRIO }, 67195972f6Sopenharmony_ci { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits, 68195972f6Sopenharmony_ci "Set max #xmits for challenge", OPT_PRIO }, 69195972f6Sopenharmony_ci { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time, 70195972f6Sopenharmony_ci "Set interval for rechallenge", OPT_PRIO }, 71195972f6Sopenharmony_ci { NULL } 72195972f6Sopenharmony_ci}; 73195972f6Sopenharmony_ci#endif /* PPP_OPTIONS */ 74195972f6Sopenharmony_ci 75195972f6Sopenharmony_ci 76195972f6Sopenharmony_ci/* Values for flags in chap_client_state and chap_server_state */ 77195972f6Sopenharmony_ci#define LOWERUP 1 78195972f6Sopenharmony_ci#define AUTH_STARTED 2 79195972f6Sopenharmony_ci#define AUTH_DONE 4 80195972f6Sopenharmony_ci#define AUTH_FAILED 8 81195972f6Sopenharmony_ci#define TIMEOUT_PENDING 0x10 82195972f6Sopenharmony_ci#define CHALLENGE_VALID 0x20 83195972f6Sopenharmony_ci 84195972f6Sopenharmony_ci/* 85195972f6Sopenharmony_ci * Prototypes. 86195972f6Sopenharmony_ci */ 87195972f6Sopenharmony_cistatic void chap_init(ppp_pcb *pcb); 88195972f6Sopenharmony_cistatic void chap_lowerup(ppp_pcb *pcb); 89195972f6Sopenharmony_cistatic void chap_lowerdown(ppp_pcb *pcb); 90195972f6Sopenharmony_ci#if PPP_SERVER 91195972f6Sopenharmony_cistatic void chap_timeout(void *arg); 92195972f6Sopenharmony_cistatic void chap_generate_challenge(ppp_pcb *pcb); 93195972f6Sopenharmony_cistatic void chap_handle_response(ppp_pcb *pcb, int code, 94195972f6Sopenharmony_ci unsigned char *pkt, int len); 95195972f6Sopenharmony_cistatic int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, 96195972f6Sopenharmony_ci const struct chap_digest_type *digest, 97195972f6Sopenharmony_ci const unsigned char *challenge, const unsigned char *response, 98195972f6Sopenharmony_ci char *message, int message_space); 99195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 100195972f6Sopenharmony_cistatic void chap_respond(ppp_pcb *pcb, int id, 101195972f6Sopenharmony_ci unsigned char *pkt, int len); 102195972f6Sopenharmony_cistatic void chap_handle_status(ppp_pcb *pcb, int code, int id, 103195972f6Sopenharmony_ci unsigned char *pkt, int len); 104195972f6Sopenharmony_cistatic void chap_protrej(ppp_pcb *pcb); 105195972f6Sopenharmony_cistatic void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen); 106195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT 107195972f6Sopenharmony_cistatic int chap_print_pkt(const unsigned char *p, int plen, 108195972f6Sopenharmony_ci void (*printer) (void *, const char *, ...), void *arg); 109195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */ 110195972f6Sopenharmony_ci 111195972f6Sopenharmony_ci/* List of digest types that we know about */ 112195972f6Sopenharmony_cistatic const struct chap_digest_type* const chap_digests[] = { 113195972f6Sopenharmony_ci &md5_digest, 114195972f6Sopenharmony_ci#if MSCHAP_SUPPORT 115195972f6Sopenharmony_ci &chapms_digest, 116195972f6Sopenharmony_ci &chapms2_digest, 117195972f6Sopenharmony_ci#endif /* MSCHAP_SUPPORT */ 118195972f6Sopenharmony_ci NULL 119195972f6Sopenharmony_ci}; 120195972f6Sopenharmony_ci 121195972f6Sopenharmony_ci/* 122195972f6Sopenharmony_ci * chap_init - reset to initial state. 123195972f6Sopenharmony_ci */ 124195972f6Sopenharmony_cistatic void chap_init(ppp_pcb *pcb) { 125195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 126195972f6Sopenharmony_ci 127195972f6Sopenharmony_ci#if 0 /* Not necessary, everything is cleared in ppp_new() */ 128195972f6Sopenharmony_ci memset(&pcb->chap_client, 0, sizeof(chap_client_state)); 129195972f6Sopenharmony_ci#if PPP_SERVER 130195972f6Sopenharmony_ci memset(&pcb->chap_server, 0, sizeof(chap_server_state)); 131195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 132195972f6Sopenharmony_ci#endif /* 0 */ 133195972f6Sopenharmony_ci} 134195972f6Sopenharmony_ci 135195972f6Sopenharmony_ci/* 136195972f6Sopenharmony_ci * chap_lowerup - we can start doing stuff now. 137195972f6Sopenharmony_ci */ 138195972f6Sopenharmony_cistatic void chap_lowerup(ppp_pcb *pcb) { 139195972f6Sopenharmony_ci 140195972f6Sopenharmony_ci pcb->chap_client.flags |= LOWERUP; 141195972f6Sopenharmony_ci#if PPP_SERVER 142195972f6Sopenharmony_ci pcb->chap_server.flags |= LOWERUP; 143195972f6Sopenharmony_ci if (pcb->chap_server.flags & AUTH_STARTED) 144195972f6Sopenharmony_ci chap_timeout(pcb); 145195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 146195972f6Sopenharmony_ci} 147195972f6Sopenharmony_ci 148195972f6Sopenharmony_cistatic void chap_lowerdown(ppp_pcb *pcb) { 149195972f6Sopenharmony_ci 150195972f6Sopenharmony_ci pcb->chap_client.flags = 0; 151195972f6Sopenharmony_ci#if PPP_SERVER 152195972f6Sopenharmony_ci if (pcb->chap_server.flags & TIMEOUT_PENDING) 153195972f6Sopenharmony_ci UNTIMEOUT(chap_timeout, pcb); 154195972f6Sopenharmony_ci pcb->chap_server.flags = 0; 155195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 156195972f6Sopenharmony_ci} 157195972f6Sopenharmony_ci 158195972f6Sopenharmony_ci#if PPP_SERVER 159195972f6Sopenharmony_ci/* 160195972f6Sopenharmony_ci * chap_auth_peer - Start authenticating the peer. 161195972f6Sopenharmony_ci * If the lower layer is already up, we start sending challenges, 162195972f6Sopenharmony_ci * otherwise we wait for the lower layer to come up. 163195972f6Sopenharmony_ci */ 164195972f6Sopenharmony_civoid chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { 165195972f6Sopenharmony_ci const struct chap_digest_type *dp; 166195972f6Sopenharmony_ci int i; 167195972f6Sopenharmony_ci 168195972f6Sopenharmony_ci if (pcb->chap_server.flags & AUTH_STARTED) { 169195972f6Sopenharmony_ci ppp_error("CHAP: peer authentication already started!"); 170195972f6Sopenharmony_ci return; 171195972f6Sopenharmony_ci } 172195972f6Sopenharmony_ci for (i = 0; (dp = chap_digests[i]) != NULL; ++i) 173195972f6Sopenharmony_ci if (dp->code == digest_code) 174195972f6Sopenharmony_ci break; 175195972f6Sopenharmony_ci if (dp == NULL) 176195972f6Sopenharmony_ci ppp_fatal("CHAP digest 0x%x requested but not available", 177195972f6Sopenharmony_ci digest_code); 178195972f6Sopenharmony_ci 179195972f6Sopenharmony_ci pcb->chap_server.digest = dp; 180195972f6Sopenharmony_ci pcb->chap_server.name = our_name; 181195972f6Sopenharmony_ci /* Start with a random ID value */ 182195972f6Sopenharmony_ci pcb->chap_server.id = magic(); 183195972f6Sopenharmony_ci pcb->chap_server.flags |= AUTH_STARTED; 184195972f6Sopenharmony_ci if (pcb->chap_server.flags & LOWERUP) 185195972f6Sopenharmony_ci chap_timeout(pcb); 186195972f6Sopenharmony_ci} 187195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 188195972f6Sopenharmony_ci 189195972f6Sopenharmony_ci/* 190195972f6Sopenharmony_ci * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. 191195972f6Sopenharmony_ci * There isn't much to do until we receive a challenge. 192195972f6Sopenharmony_ci */ 193195972f6Sopenharmony_civoid chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { 194195972f6Sopenharmony_ci const struct chap_digest_type *dp; 195195972f6Sopenharmony_ci int i; 196195972f6Sopenharmony_ci 197195972f6Sopenharmony_ci if(NULL == our_name) 198195972f6Sopenharmony_ci return; 199195972f6Sopenharmony_ci 200195972f6Sopenharmony_ci if (pcb->chap_client.flags & AUTH_STARTED) { 201195972f6Sopenharmony_ci ppp_error("CHAP: authentication with peer already started!"); 202195972f6Sopenharmony_ci return; 203195972f6Sopenharmony_ci } 204195972f6Sopenharmony_ci for (i = 0; (dp = chap_digests[i]) != NULL; ++i) 205195972f6Sopenharmony_ci if (dp->code == digest_code) 206195972f6Sopenharmony_ci break; 207195972f6Sopenharmony_ci 208195972f6Sopenharmony_ci if (dp == NULL) 209195972f6Sopenharmony_ci ppp_fatal("CHAP digest 0x%x requested but not available", 210195972f6Sopenharmony_ci digest_code); 211195972f6Sopenharmony_ci 212195972f6Sopenharmony_ci pcb->chap_client.digest = dp; 213195972f6Sopenharmony_ci pcb->chap_client.name = our_name; 214195972f6Sopenharmony_ci pcb->chap_client.flags |= AUTH_STARTED; 215195972f6Sopenharmony_ci} 216195972f6Sopenharmony_ci 217195972f6Sopenharmony_ci#if PPP_SERVER 218195972f6Sopenharmony_ci/* 219195972f6Sopenharmony_ci * chap_timeout - It's time to send another challenge to the peer. 220195972f6Sopenharmony_ci * This could be either a retransmission of a previous challenge, 221195972f6Sopenharmony_ci * or a new challenge to start re-authentication. 222195972f6Sopenharmony_ci */ 223195972f6Sopenharmony_cistatic void chap_timeout(void *arg) { 224195972f6Sopenharmony_ci ppp_pcb *pcb = (ppp_pcb*)arg; 225195972f6Sopenharmony_ci struct pbuf *p; 226195972f6Sopenharmony_ci 227195972f6Sopenharmony_ci pcb->chap_server.flags &= ~TIMEOUT_PENDING; 228195972f6Sopenharmony_ci if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) { 229195972f6Sopenharmony_ci pcb->chap_server.challenge_xmits = 0; 230195972f6Sopenharmony_ci chap_generate_challenge(pcb); 231195972f6Sopenharmony_ci pcb->chap_server.flags |= CHALLENGE_VALID; 232195972f6Sopenharmony_ci } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) { 233195972f6Sopenharmony_ci pcb->chap_server.flags &= ~CHALLENGE_VALID; 234195972f6Sopenharmony_ci pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED; 235195972f6Sopenharmony_ci auth_peer_fail(pcb, PPP_CHAP); 236195972f6Sopenharmony_ci return; 237195972f6Sopenharmony_ci } 238195972f6Sopenharmony_ci 239195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); 240195972f6Sopenharmony_ci if(NULL == p) 241195972f6Sopenharmony_ci return; 242195972f6Sopenharmony_ci if(p->tot_len != p->len) { 243195972f6Sopenharmony_ci pbuf_free(p); 244195972f6Sopenharmony_ci return; 245195972f6Sopenharmony_ci } 246195972f6Sopenharmony_ci MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen); 247195972f6Sopenharmony_ci ppp_write(pcb, p); 248195972f6Sopenharmony_ci ++pcb->chap_server.challenge_xmits; 249195972f6Sopenharmony_ci pcb->chap_server.flags |= TIMEOUT_PENDING; 250195972f6Sopenharmony_ci TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time); 251195972f6Sopenharmony_ci} 252195972f6Sopenharmony_ci 253195972f6Sopenharmony_ci/* 254195972f6Sopenharmony_ci * chap_generate_challenge - generate a challenge string and format 255195972f6Sopenharmony_ci * the challenge packet in pcb->chap_server.challenge_pkt. 256195972f6Sopenharmony_ci */ 257195972f6Sopenharmony_cistatic void chap_generate_challenge(ppp_pcb *pcb) { 258195972f6Sopenharmony_ci int clen = 1, nlen, len; 259195972f6Sopenharmony_ci unsigned char *p; 260195972f6Sopenharmony_ci 261195972f6Sopenharmony_ci p = pcb->chap_server.challenge; 262195972f6Sopenharmony_ci MAKEHEADER(p, PPP_CHAP); 263195972f6Sopenharmony_ci p += CHAP_HDRLEN; 264195972f6Sopenharmony_ci pcb->chap_server.digest->generate_challenge(pcb, p); 265195972f6Sopenharmony_ci clen = *p; 266195972f6Sopenharmony_ci nlen = strlen(pcb->chap_server.name); 267195972f6Sopenharmony_ci memcpy(p + 1 + clen, pcb->chap_server.name, nlen); 268195972f6Sopenharmony_ci 269195972f6Sopenharmony_ci len = CHAP_HDRLEN + 1 + clen + nlen; 270195972f6Sopenharmony_ci pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len; 271195972f6Sopenharmony_ci 272195972f6Sopenharmony_ci p = pcb->chap_server.challenge + PPP_HDRLEN; 273195972f6Sopenharmony_ci p[0] = CHAP_CHALLENGE; 274195972f6Sopenharmony_ci p[1] = ++pcb->chap_server.id; 275195972f6Sopenharmony_ci p[2] = len >> 8; 276195972f6Sopenharmony_ci p[3] = len; 277195972f6Sopenharmony_ci} 278195972f6Sopenharmony_ci 279195972f6Sopenharmony_ci/* 280195972f6Sopenharmony_ci * chap_handle_response - check the response to our challenge. 281195972f6Sopenharmony_ci */ 282195972f6Sopenharmony_cistatic void chap_handle_response(ppp_pcb *pcb, int id, 283195972f6Sopenharmony_ci unsigned char *pkt, int len) { 284195972f6Sopenharmony_ci int response_len, ok, mlen; 285195972f6Sopenharmony_ci const unsigned char *response; 286195972f6Sopenharmony_ci unsigned char *outp; 287195972f6Sopenharmony_ci struct pbuf *p; 288195972f6Sopenharmony_ci const char *name = NULL; /* initialized to shut gcc up */ 289195972f6Sopenharmony_ci#if 0 /* UNUSED */ 290195972f6Sopenharmony_ci int (*verifier)(const char *, const char *, int, const struct chap_digest_type *, 291195972f6Sopenharmony_ci const unsigned char *, const unsigned char *, char *, int); 292195972f6Sopenharmony_ci#endif /* UNUSED */ 293195972f6Sopenharmony_ci char rname[MAXNAMELEN+1]; 294195972f6Sopenharmony_ci char message[256]; 295195972f6Sopenharmony_ci 296195972f6Sopenharmony_ci if ((pcb->chap_server.flags & LOWERUP) == 0) 297195972f6Sopenharmony_ci return; 298195972f6Sopenharmony_ci if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2) 299195972f6Sopenharmony_ci return; 300195972f6Sopenharmony_ci if (pcb->chap_server.flags & CHALLENGE_VALID) { 301195972f6Sopenharmony_ci response = pkt; 302195972f6Sopenharmony_ci GETCHAR(response_len, pkt); 303195972f6Sopenharmony_ci len -= response_len + 1; /* length of name */ 304195972f6Sopenharmony_ci name = (char *)pkt + response_len; 305195972f6Sopenharmony_ci if (len < 0) 306195972f6Sopenharmony_ci return; 307195972f6Sopenharmony_ci 308195972f6Sopenharmony_ci if (pcb->chap_server.flags & TIMEOUT_PENDING) { 309195972f6Sopenharmony_ci pcb->chap_server.flags &= ~TIMEOUT_PENDING; 310195972f6Sopenharmony_ci UNTIMEOUT(chap_timeout, pcb); 311195972f6Sopenharmony_ci } 312195972f6Sopenharmony_ci#if PPP_REMOTENAME 313195972f6Sopenharmony_ci if (pcb->settings.explicit_remote) { 314195972f6Sopenharmony_ci name = pcb->remote_name; 315195972f6Sopenharmony_ci } else 316195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */ 317195972f6Sopenharmony_ci { 318195972f6Sopenharmony_ci /* Null terminate and clean remote name. */ 319195972f6Sopenharmony_ci ppp_slprintf(rname, sizeof(rname), "%.*v", len, name); 320195972f6Sopenharmony_ci name = rname; 321195972f6Sopenharmony_ci } 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci#if 0 /* UNUSED */ 324195972f6Sopenharmony_ci if (chap_verify_hook) 325195972f6Sopenharmony_ci verifier = chap_verify_hook; 326195972f6Sopenharmony_ci else 327195972f6Sopenharmony_ci verifier = chap_verify_response; 328195972f6Sopenharmony_ci ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest, 329195972f6Sopenharmony_ci pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, 330195972f6Sopenharmony_ci response, pcb->chap_server.message, sizeof(pcb->chap_server.message)); 331195972f6Sopenharmony_ci#endif /* UNUSED */ 332195972f6Sopenharmony_ci ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest, 333195972f6Sopenharmony_ci pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, 334195972f6Sopenharmony_ci response, message, sizeof(message)); 335195972f6Sopenharmony_ci#if 0 /* UNUSED */ 336195972f6Sopenharmony_ci if (!ok || !auth_number()) { 337195972f6Sopenharmony_ci#endif /* UNUSED */ 338195972f6Sopenharmony_ci if (!ok) { 339195972f6Sopenharmony_ci pcb->chap_server.flags |= AUTH_FAILED; 340195972f6Sopenharmony_ci ppp_warn("Peer %q failed CHAP authentication", name); 341195972f6Sopenharmony_ci } 342195972f6Sopenharmony_ci } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) 343195972f6Sopenharmony_ci return; 344195972f6Sopenharmony_ci 345195972f6Sopenharmony_ci /* send the response */ 346195972f6Sopenharmony_ci mlen = strlen(message); 347195972f6Sopenharmony_ci len = CHAP_HDRLEN + mlen; 348195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); 349195972f6Sopenharmony_ci if(NULL == p) 350195972f6Sopenharmony_ci return; 351195972f6Sopenharmony_ci if(p->tot_len != p->len) { 352195972f6Sopenharmony_ci pbuf_free(p); 353195972f6Sopenharmony_ci return; 354195972f6Sopenharmony_ci } 355195972f6Sopenharmony_ci 356195972f6Sopenharmony_ci outp = (unsigned char *)p->payload; 357195972f6Sopenharmony_ci MAKEHEADER(outp, PPP_CHAP); 358195972f6Sopenharmony_ci 359195972f6Sopenharmony_ci outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; 360195972f6Sopenharmony_ci outp[1] = id; 361195972f6Sopenharmony_ci outp[2] = len >> 8; 362195972f6Sopenharmony_ci outp[3] = len; 363195972f6Sopenharmony_ci if (mlen > 0) 364195972f6Sopenharmony_ci memcpy(outp + CHAP_HDRLEN, message, mlen); 365195972f6Sopenharmony_ci ppp_write(pcb, p); 366195972f6Sopenharmony_ci 367195972f6Sopenharmony_ci if (pcb->chap_server.flags & CHALLENGE_VALID) { 368195972f6Sopenharmony_ci pcb->chap_server.flags &= ~CHALLENGE_VALID; 369195972f6Sopenharmony_ci if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) { 370195972f6Sopenharmony_ci 371195972f6Sopenharmony_ci#if 0 /* UNUSED */ 372195972f6Sopenharmony_ci /* 373195972f6Sopenharmony_ci * Auth is OK, so now we need to check session restrictions 374195972f6Sopenharmony_ci * to ensure everything is OK, but only if we used a 375195972f6Sopenharmony_ci * plugin, and only if we're configured to check. This 376195972f6Sopenharmony_ci * allows us to do PAM checks on PPP servers that 377195972f6Sopenharmony_ci * authenticate against ActiveDirectory, and use AD for 378195972f6Sopenharmony_ci * account info (like when using Winbind integrated with 379195972f6Sopenharmony_ci * PAM). 380195972f6Sopenharmony_ci */ 381195972f6Sopenharmony_ci if (session_mgmt && 382195972f6Sopenharmony_ci session_check(name, NULL, devnam, NULL) == 0) { 383195972f6Sopenharmony_ci pcb->chap_server.flags |= AUTH_FAILED; 384195972f6Sopenharmony_ci ppp_warn("Peer %q failed CHAP Session verification", name); 385195972f6Sopenharmony_ci } 386195972f6Sopenharmony_ci#endif /* UNUSED */ 387195972f6Sopenharmony_ci 388195972f6Sopenharmony_ci } 389195972f6Sopenharmony_ci if (pcb->chap_server.flags & AUTH_FAILED) { 390195972f6Sopenharmony_ci auth_peer_fail(pcb, PPP_CHAP); 391195972f6Sopenharmony_ci } else { 392195972f6Sopenharmony_ci if ((pcb->chap_server.flags & AUTH_DONE) == 0) 393195972f6Sopenharmony_ci auth_peer_success(pcb, PPP_CHAP, 394195972f6Sopenharmony_ci pcb->chap_server.digest->code, 395195972f6Sopenharmony_ci name, strlen(name)); 396195972f6Sopenharmony_ci if (pcb->settings.chap_rechallenge_time) { 397195972f6Sopenharmony_ci pcb->chap_server.flags |= TIMEOUT_PENDING; 398195972f6Sopenharmony_ci TIMEOUT(chap_timeout, pcb, 399195972f6Sopenharmony_ci pcb->settings.chap_rechallenge_time); 400195972f6Sopenharmony_ci } 401195972f6Sopenharmony_ci } 402195972f6Sopenharmony_ci pcb->chap_server.flags |= AUTH_DONE; 403195972f6Sopenharmony_ci } 404195972f6Sopenharmony_ci} 405195972f6Sopenharmony_ci 406195972f6Sopenharmony_ci/* 407195972f6Sopenharmony_ci * chap_verify_response - check whether the peer's response matches 408195972f6Sopenharmony_ci * what we think it should be. Returns 1 if it does (authentication 409195972f6Sopenharmony_ci * succeeded), or 0 if it doesn't. 410195972f6Sopenharmony_ci */ 411195972f6Sopenharmony_cistatic int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, 412195972f6Sopenharmony_ci const struct chap_digest_type *digest, 413195972f6Sopenharmony_ci const unsigned char *challenge, const unsigned char *response, 414195972f6Sopenharmony_ci char *message, int message_space) { 415195972f6Sopenharmony_ci int ok; 416195972f6Sopenharmony_ci unsigned char secret[MAXSECRETLEN]; 417195972f6Sopenharmony_ci int secret_len; 418195972f6Sopenharmony_ci 419195972f6Sopenharmony_ci /* Get the secret that the peer is supposed to know */ 420195972f6Sopenharmony_ci if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { 421195972f6Sopenharmony_ci ppp_error("No CHAP secret found for authenticating %q", name); 422195972f6Sopenharmony_ci return 0; 423195972f6Sopenharmony_ci } 424195972f6Sopenharmony_ci ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, 425195972f6Sopenharmony_ci response, message, message_space); 426195972f6Sopenharmony_ci memset(secret, 0, sizeof(secret)); 427195972f6Sopenharmony_ci 428195972f6Sopenharmony_ci return ok; 429195972f6Sopenharmony_ci} 430195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 431195972f6Sopenharmony_ci 432195972f6Sopenharmony_ci/* 433195972f6Sopenharmony_ci * chap_respond - Generate and send a response to a challenge. 434195972f6Sopenharmony_ci */ 435195972f6Sopenharmony_cistatic void chap_respond(ppp_pcb *pcb, int id, 436195972f6Sopenharmony_ci unsigned char *pkt, int len) { 437195972f6Sopenharmony_ci int clen, nlen; 438195972f6Sopenharmony_ci int secret_len; 439195972f6Sopenharmony_ci struct pbuf *p; 440195972f6Sopenharmony_ci u_char *outp; 441195972f6Sopenharmony_ci char rname[MAXNAMELEN+1]; 442195972f6Sopenharmony_ci char secret[MAXSECRETLEN+1]; 443195972f6Sopenharmony_ci 444195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); 445195972f6Sopenharmony_ci if(NULL == p) 446195972f6Sopenharmony_ci return; 447195972f6Sopenharmony_ci if(p->tot_len != p->len) { 448195972f6Sopenharmony_ci pbuf_free(p); 449195972f6Sopenharmony_ci return; 450195972f6Sopenharmony_ci } 451195972f6Sopenharmony_ci 452195972f6Sopenharmony_ci if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) 453195972f6Sopenharmony_ci return; /* not ready */ 454195972f6Sopenharmony_ci if (len < 2 || len < pkt[0] + 1) 455195972f6Sopenharmony_ci return; /* too short */ 456195972f6Sopenharmony_ci clen = pkt[0]; 457195972f6Sopenharmony_ci nlen = len - (clen + 1); 458195972f6Sopenharmony_ci 459195972f6Sopenharmony_ci /* Null terminate and clean remote name. */ 460195972f6Sopenharmony_ci ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); 461195972f6Sopenharmony_ci 462195972f6Sopenharmony_ci#if PPP_REMOTENAME 463195972f6Sopenharmony_ci /* Microsoft doesn't send their name back in the PPP packet */ 464195972f6Sopenharmony_ci if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0)) 465195972f6Sopenharmony_ci strlcpy(rname, pcb->settings.remote_name, sizeof(rname)); 466195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */ 467195972f6Sopenharmony_ci 468195972f6Sopenharmony_ci /* get secret for authenticating ourselves with the specified host */ 469195972f6Sopenharmony_ci if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { 470195972f6Sopenharmony_ci secret_len = 0; /* assume null secret if can't find one */ 471195972f6Sopenharmony_ci ppp_warn("No CHAP secret found for authenticating us to %q", rname); 472195972f6Sopenharmony_ci } 473195972f6Sopenharmony_ci 474195972f6Sopenharmony_ci outp = (u_char*)p->payload; 475195972f6Sopenharmony_ci MAKEHEADER(outp, PPP_CHAP); 476195972f6Sopenharmony_ci outp += CHAP_HDRLEN; 477195972f6Sopenharmony_ci 478195972f6Sopenharmony_ci pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt, 479195972f6Sopenharmony_ci secret, secret_len, pcb->chap_client.priv); 480195972f6Sopenharmony_ci memset(secret, 0, secret_len); 481195972f6Sopenharmony_ci 482195972f6Sopenharmony_ci clen = *outp; 483195972f6Sopenharmony_ci nlen = strlen(pcb->chap_client.name); 484195972f6Sopenharmony_ci memcpy(outp + clen + 1, pcb->chap_client.name, nlen); 485195972f6Sopenharmony_ci 486195972f6Sopenharmony_ci outp = (u_char*)p->payload + PPP_HDRLEN; 487195972f6Sopenharmony_ci len = CHAP_HDRLEN + clen + 1 + nlen; 488195972f6Sopenharmony_ci outp[0] = CHAP_RESPONSE; 489195972f6Sopenharmony_ci outp[1] = id; 490195972f6Sopenharmony_ci outp[2] = len >> 8; 491195972f6Sopenharmony_ci outp[3] = len; 492195972f6Sopenharmony_ci 493195972f6Sopenharmony_ci pbuf_realloc(p, PPP_HDRLEN + len); 494195972f6Sopenharmony_ci ppp_write(pcb, p); 495195972f6Sopenharmony_ci} 496195972f6Sopenharmony_ci 497195972f6Sopenharmony_cistatic void chap_handle_status(ppp_pcb *pcb, int code, int id, 498195972f6Sopenharmony_ci unsigned char *pkt, int len) { 499195972f6Sopenharmony_ci const char *msg = NULL; 500195972f6Sopenharmony_ci LWIP_UNUSED_ARG(id); 501195972f6Sopenharmony_ci 502195972f6Sopenharmony_ci if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) 503195972f6Sopenharmony_ci != (AUTH_STARTED|LOWERUP)) 504195972f6Sopenharmony_ci return; 505195972f6Sopenharmony_ci pcb->chap_client.flags |= AUTH_DONE; 506195972f6Sopenharmony_ci 507195972f6Sopenharmony_ci if (code == CHAP_SUCCESS) { 508195972f6Sopenharmony_ci /* used for MS-CHAP v2 mutual auth, yuck */ 509195972f6Sopenharmony_ci if (pcb->chap_client.digest->check_success != NULL) { 510195972f6Sopenharmony_ci if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv)) 511195972f6Sopenharmony_ci code = CHAP_FAILURE; 512195972f6Sopenharmony_ci } else 513195972f6Sopenharmony_ci msg = "CHAP authentication succeeded"; 514195972f6Sopenharmony_ci } else { 515195972f6Sopenharmony_ci if (pcb->chap_client.digest->handle_failure != NULL) 516195972f6Sopenharmony_ci (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len); 517195972f6Sopenharmony_ci else 518195972f6Sopenharmony_ci msg = "CHAP authentication failed"; 519195972f6Sopenharmony_ci } 520195972f6Sopenharmony_ci if (msg) { 521195972f6Sopenharmony_ci if (len > 0) 522195972f6Sopenharmony_ci ppp_info("%s: %.*v", msg, len, pkt); 523195972f6Sopenharmony_ci else 524195972f6Sopenharmony_ci ppp_info("%s", msg); 525195972f6Sopenharmony_ci } 526195972f6Sopenharmony_ci if (code == CHAP_SUCCESS) 527195972f6Sopenharmony_ci auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); 528195972f6Sopenharmony_ci else { 529195972f6Sopenharmony_ci pcb->chap_client.flags |= AUTH_FAILED; 530195972f6Sopenharmony_ci ppp_error("CHAP authentication failed"); 531195972f6Sopenharmony_ci auth_withpeer_fail(pcb, PPP_CHAP); 532195972f6Sopenharmony_ci } 533195972f6Sopenharmony_ci} 534195972f6Sopenharmony_ci 535195972f6Sopenharmony_cistatic void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) { 536195972f6Sopenharmony_ci unsigned char code, id; 537195972f6Sopenharmony_ci int len; 538195972f6Sopenharmony_ci 539195972f6Sopenharmony_ci if (pktlen < CHAP_HDRLEN) 540195972f6Sopenharmony_ci return; 541195972f6Sopenharmony_ci GETCHAR(code, pkt); 542195972f6Sopenharmony_ci GETCHAR(id, pkt); 543195972f6Sopenharmony_ci GETSHORT(len, pkt); 544195972f6Sopenharmony_ci if (len < CHAP_HDRLEN || len > pktlen) 545195972f6Sopenharmony_ci return; 546195972f6Sopenharmony_ci len -= CHAP_HDRLEN; 547195972f6Sopenharmony_ci 548195972f6Sopenharmony_ci switch (code) { 549195972f6Sopenharmony_ci case CHAP_CHALLENGE: 550195972f6Sopenharmony_ci chap_respond(pcb, id, pkt, len); 551195972f6Sopenharmony_ci break; 552195972f6Sopenharmony_ci#if PPP_SERVER 553195972f6Sopenharmony_ci case CHAP_RESPONSE: 554195972f6Sopenharmony_ci chap_handle_response(pcb, id, pkt, len); 555195972f6Sopenharmony_ci break; 556195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 557195972f6Sopenharmony_ci case CHAP_FAILURE: 558195972f6Sopenharmony_ci case CHAP_SUCCESS: 559195972f6Sopenharmony_ci chap_handle_status(pcb, code, id, pkt, len); 560195972f6Sopenharmony_ci break; 561195972f6Sopenharmony_ci default: 562195972f6Sopenharmony_ci break; 563195972f6Sopenharmony_ci } 564195972f6Sopenharmony_ci} 565195972f6Sopenharmony_ci 566195972f6Sopenharmony_cistatic void chap_protrej(ppp_pcb *pcb) { 567195972f6Sopenharmony_ci 568195972f6Sopenharmony_ci#if PPP_SERVER 569195972f6Sopenharmony_ci if (pcb->chap_server.flags & TIMEOUT_PENDING) { 570195972f6Sopenharmony_ci pcb->chap_server.flags &= ~TIMEOUT_PENDING; 571195972f6Sopenharmony_ci UNTIMEOUT(chap_timeout, pcb); 572195972f6Sopenharmony_ci } 573195972f6Sopenharmony_ci if (pcb->chap_server.flags & AUTH_STARTED) { 574195972f6Sopenharmony_ci pcb->chap_server.flags = 0; 575195972f6Sopenharmony_ci auth_peer_fail(pcb, PPP_CHAP); 576195972f6Sopenharmony_ci } 577195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 578195972f6Sopenharmony_ci if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { 579195972f6Sopenharmony_ci pcb->chap_client.flags &= ~AUTH_STARTED; 580195972f6Sopenharmony_ci ppp_error("CHAP authentication failed due to protocol-reject"); 581195972f6Sopenharmony_ci auth_withpeer_fail(pcb, PPP_CHAP); 582195972f6Sopenharmony_ci } 583195972f6Sopenharmony_ci} 584195972f6Sopenharmony_ci 585195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT 586195972f6Sopenharmony_ci/* 587195972f6Sopenharmony_ci * chap_print_pkt - print the contents of a CHAP packet. 588195972f6Sopenharmony_ci */ 589195972f6Sopenharmony_cistatic const char* const chap_code_names[] = { 590195972f6Sopenharmony_ci "Challenge", "Response", "Success", "Failure" 591195972f6Sopenharmony_ci}; 592195972f6Sopenharmony_ci 593195972f6Sopenharmony_cistatic int chap_print_pkt(const unsigned char *p, int plen, 594195972f6Sopenharmony_ci void (*printer) (void *, const char *, ...), void *arg) { 595195972f6Sopenharmony_ci int code, id, len; 596195972f6Sopenharmony_ci int clen, nlen; 597195972f6Sopenharmony_ci unsigned char x; 598195972f6Sopenharmony_ci 599195972f6Sopenharmony_ci if (plen < CHAP_HDRLEN) 600195972f6Sopenharmony_ci return 0; 601195972f6Sopenharmony_ci GETCHAR(code, p); 602195972f6Sopenharmony_ci GETCHAR(id, p); 603195972f6Sopenharmony_ci GETSHORT(len, p); 604195972f6Sopenharmony_ci if (len < CHAP_HDRLEN || len > plen) 605195972f6Sopenharmony_ci return 0; 606195972f6Sopenharmony_ci 607195972f6Sopenharmony_ci if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names)) 608195972f6Sopenharmony_ci printer(arg, " %s", chap_code_names[code-1]); 609195972f6Sopenharmony_ci else 610195972f6Sopenharmony_ci printer(arg, " code=0x%x", code); 611195972f6Sopenharmony_ci printer(arg, " id=0x%x", id); 612195972f6Sopenharmony_ci len -= CHAP_HDRLEN; 613195972f6Sopenharmony_ci switch (code) { 614195972f6Sopenharmony_ci case CHAP_CHALLENGE: 615195972f6Sopenharmony_ci case CHAP_RESPONSE: 616195972f6Sopenharmony_ci if (len < 1) 617195972f6Sopenharmony_ci break; 618195972f6Sopenharmony_ci clen = p[0]; 619195972f6Sopenharmony_ci if (len < clen + 1) 620195972f6Sopenharmony_ci break; 621195972f6Sopenharmony_ci ++p; 622195972f6Sopenharmony_ci nlen = len - clen - 1; 623195972f6Sopenharmony_ci printer(arg, " <"); 624195972f6Sopenharmony_ci for (; clen > 0; --clen) { 625195972f6Sopenharmony_ci GETCHAR(x, p); 626195972f6Sopenharmony_ci printer(arg, "%.2x", x); 627195972f6Sopenharmony_ci } 628195972f6Sopenharmony_ci printer(arg, ">, name = "); 629195972f6Sopenharmony_ci ppp_print_string(p, nlen, printer, arg); 630195972f6Sopenharmony_ci break; 631195972f6Sopenharmony_ci case CHAP_FAILURE: 632195972f6Sopenharmony_ci case CHAP_SUCCESS: 633195972f6Sopenharmony_ci printer(arg, " "); 634195972f6Sopenharmony_ci ppp_print_string(p, len, printer, arg); 635195972f6Sopenharmony_ci break; 636195972f6Sopenharmony_ci default: 637195972f6Sopenharmony_ci for (clen = len; clen > 0; --clen) { 638195972f6Sopenharmony_ci GETCHAR(x, p); 639195972f6Sopenharmony_ci printer(arg, " %.2x", x); 640195972f6Sopenharmony_ci } 641195972f6Sopenharmony_ci /* no break */ 642195972f6Sopenharmony_ci } 643195972f6Sopenharmony_ci 644195972f6Sopenharmony_ci return len + CHAP_HDRLEN; 645195972f6Sopenharmony_ci} 646195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */ 647195972f6Sopenharmony_ci 648195972f6Sopenharmony_ciconst struct protent chap_protent = { 649195972f6Sopenharmony_ci PPP_CHAP, 650195972f6Sopenharmony_ci chap_init, 651195972f6Sopenharmony_ci chap_input, 652195972f6Sopenharmony_ci chap_protrej, 653195972f6Sopenharmony_ci chap_lowerup, 654195972f6Sopenharmony_ci chap_lowerdown, 655195972f6Sopenharmony_ci NULL, /* open */ 656195972f6Sopenharmony_ci NULL, /* close */ 657195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT 658195972f6Sopenharmony_ci chap_print_pkt, 659195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */ 660195972f6Sopenharmony_ci#if PPP_DATAINPUT 661195972f6Sopenharmony_ci NULL, /* datainput */ 662195972f6Sopenharmony_ci#endif /* PPP_DATAINPUT */ 663195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT 664195972f6Sopenharmony_ci "CHAP", /* name */ 665195972f6Sopenharmony_ci NULL, /* data_name */ 666195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */ 667195972f6Sopenharmony_ci#if PPP_OPTIONS 668195972f6Sopenharmony_ci chap_option_list, 669195972f6Sopenharmony_ci NULL, /* check_options */ 670195972f6Sopenharmony_ci#endif /* PPP_OPTIONS */ 671195972f6Sopenharmony_ci#if DEMAND_SUPPORT 672195972f6Sopenharmony_ci NULL, 673195972f6Sopenharmony_ci NULL 674195972f6Sopenharmony_ci#endif /* DEMAND_SUPPORT */ 675195972f6Sopenharmony_ci}; 676195972f6Sopenharmony_ci 677195972f6Sopenharmony_ci#endif /* PPP_SUPPORT && CHAP_SUPPORT */ 678