X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Feap.c;h=4ad67a5c5eb70810ccbfb632819eb98907394d21;hb=509f04959ad891d7f981f035ed461d51bd1f74b0;hp=ede5ff0d3a2f09fd7015763bfadfdbda7abc0902;hpb=ace9c1c9bd73b7ed5777ec5b066ac61ba4ab2079;p=ppp.git diff --git a/pppd/eap.c b/pppd/eap.c index ede5ff0..4ad67a5 100644 --- a/pppd/eap.c +++ b/pppd/eap.c @@ -48,9 +48,9 @@ * Implemented EAP-TLS authentication */ -/* - * TODO: - */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -67,29 +67,37 @@ #include "pathnames.h" #include "md5.h" #include "eap.h" +#ifdef PPP_WITH_PEAP +#include "peap.h" +#endif /* PPP_WITH_PEAP */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP +#ifdef HAVE_TIME_H +#include +#endif #include #include #include #include "pppcrypt.h" -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ #ifndef SHA_DIGESTSIZE #define SHA_DIGESTSIZE 20 #endif -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS #include "eap-tls.h" -#endif /* USE_EAPTLS */ -#ifdef CHAPMS -#include "magic.h" +#endif /* PPP_WITH_EAPTLS */ + +#ifdef PPP_WITH_CHAPMS #include "chap_ms.h" #include "chap-new.h" -#endif /* CHAPMS */ + +extern int chapms_strip_domain; +#endif /* PPP_WITH_CHAPMS */ eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP static char *pn_secret = NULL; /* Pseudonym generating secret */ #endif @@ -107,7 +115,7 @@ static option_t eap_option_list[] = { "Set max number of EAP Requests allows (client)" }, { "eap-interval", o_int, &eap_states[0].es_rechallenge, "Set interval for EAP rechallenge" }, -#ifdef USE_SRP +#ifdef PPP_WITH_SRP { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, "Set interval for SRP lightweight rechallenge" }, { "srp-pn-secret", o_string, &pn_secret, @@ -149,7 +157,7 @@ struct protent eap_protent = { NULL /* say whether to bring up link for this pkt */ }; -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* * A well-known 2048 bit modulus. */ @@ -187,7 +195,7 @@ static const u_char wkmodulus[] = { 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 }; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ /* Local forward declarations. */ static void eap_server_timeout (void *arg); @@ -219,9 +227,13 @@ eap_init(int unit) esp->es_server.ea_id = (u_char)(drand48() * 0x100); esp->es_client.ea_timeout = EAP_DEFREQTIME; esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS esp->es_client.ea_using_eaptls = 0; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ +#ifdef PPP_WITH_CHAPMS + esp->es_client.digest = chap_find_digest(CHAP_MICROSOFT_V2); + esp->es_server.digest = chap_find_digest(CHAP_MICROSOFT_V2); +#endif } /* @@ -315,7 +327,7 @@ eap_send_success(eap_state *esp) esp->es_server.ea_peer, esp->es_server.ea_peerlen); } -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* * Set DES key according to pseudonym-generating secret and current * date. @@ -411,7 +423,7 @@ b64dec(struct b64state *bs, u_char *inp, int inlen, u_char *outp) } return (outlen); } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ /* * Assume that current waiting server state is complete and figure @@ -422,7 +434,7 @@ b64dec(struct b64state *bs, u_char *inp, int inlen, u_char *outp) static void eap_figure_next_state(eap_state *esp, int status) { -#ifdef USE_SRP +#ifdef PPP_WITH_SRP unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp; struct t_pw tpw; struct t_confent *tce, mytce; @@ -431,23 +443,23 @@ eap_figure_next_state(eap_state *esp, int status) int id, i, plen, toffs; u_char vals[2]; struct b64state bs; -#endif /* USE_SRP */ -#ifdef USE_EAPTLS +#endif /* PPP_WITH_SRP */ +#ifdef PPP_WITH_EAPTLS struct eaptls_session *ets; int secret_len; char secret[MAXWORDLEN]; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ esp->es_server.ea_timeout = esp->es_savedtime; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS esp->es_server.ea_prev_state = esp->es_server.ea_state; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ switch (esp->es_server.ea_state) { case eapBadAuth: return; case eapIdentify: -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* Discard any previous session. */ ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL) { @@ -455,12 +467,12 @@ eap_figure_next_state(eap_state *esp, int status) esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ if (status != 0) { esp->es_server.ea_state = eapBadAuth; break; } -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* If we've got a pseudonym, try to decode to real name. */ if (esp->es_server.ea_peerlen > SRP_PSEUDO_LEN && strncmp(esp->es_server.ea_peer, SRP_PSEUDO_ID, @@ -550,7 +562,7 @@ eap_figure_next_state(eap_state *esp, int status) tpw.pebuf.name = esp->es_server.ea_peer; tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, cp); - tpw.pebuf.password.data = tpw.pwbuf; + tpw.pebuf.password.data = (char*) tpw.pwbuf; tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, cp2); tpw.pebuf.salt.data = tpw.saltbuf; @@ -565,20 +577,20 @@ eap_figure_next_state(eap_state *esp, int status) t_servergenexp(ts); break; } -#endif /* USE_SRP */ -#ifdef USE_EAPTLS +#endif /* PPP_WITH_SRP */ +#ifdef PPP_WITH_EAPTLS if (!get_secret(esp->es_unit, esp->es_server.ea_peer, esp->es_server.ea_name, secret, &secret_len, 1)) { esp->es_server.ea_state = eapTlsStart; break; } -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ esp->es_server.ea_state = eapMD5Chall; break; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case eapTlsStart: /* Initialize ssl session */ if(!eaptls_init_ssl_server(esp)) { @@ -639,17 +651,17 @@ eap_figure_next_state(eap_state *esp, int status) case eapTlsSendAlert: esp->es_server.ea_state = eapTlsRecvAlertAck; break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ case eapSRP1: -#ifdef USE_SRP +#ifdef PPP_WITH_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ if (status == 1) { esp->es_server.ea_state = eapMD5Chall; } else if (status != 0 || esp->es_server.ea_session == NULL) { @@ -660,14 +672,14 @@ eap_figure_next_state(eap_state *esp, int status) break; case eapSRP2: -#ifdef USE_SRP +#ifdef PPP_WITH_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ if (status != 0 || esp->es_server.ea_session == NULL) { esp->es_server.ea_state = eapBadAuth; } else { @@ -677,14 +689,14 @@ eap_figure_next_state(eap_state *esp, int status) case eapSRP3: case eapSRP4: -#ifdef USE_SRP +#ifdef PPP_WITH_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ if (status != 0 || esp->es_server.ea_session == NULL) { esp->es_server.ea_state = eapBadAuth; } else { @@ -692,7 +704,7 @@ eap_figure_next_state(eap_state *esp, int status) } break; -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case eapMSCHAPv2Chall: #endif case eapMD5Chall: @@ -710,98 +722,12 @@ eap_figure_next_state(eap_state *esp, int status) if (esp->es_server.ea_state == eapBadAuth) eap_send_failure(esp); -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state)); -#endif /* USE_EAPTLS */ -} - -#if CHAPMS -static int -eap_chapms2_verify_response(int id, char *name, - unsigned char *secret, int secret_len, - unsigned char *challenge, unsigned char *response, - char *message, int message_space) -{ - unsigned char md[MS_CHAP2_RESPONSE_LEN]; - char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; - int challenge_len, response_len; - - challenge_len = *challenge++; /* skip length, is 16 */ - response_len = *response++; - if (response_len != MS_CHAP2_RESPONSE_LEN) - goto bad; /* not even the right length */ - - /* Generate the expected response and our mutual auth. */ - ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name, - (char *)secret, secret_len, md, - (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); - - /* compare MDs and send the appropriate status */ - /* - * Per RFC 2759, success message must be formatted as - * "S= M=" - * where - * is the Authenticator Response (mutual auth) - * is a text message - * - * However, some versions of Windows (win98 tested) do not know - * about the M= part (required per RFC 2759) and flag - * it as an error (reported incorrectly as an encryption error - * to the user). Since the RFC requires it, and it can be - * useful information, we supply it if the peer is a conforming - * system. Luckily (?), win98 sets the Flags field to 0x04 - * (contrary to RFC requirements) so we can use that to - * distinguish between conforming and non-conforming systems. - * - * Special thanks to Alex Swiridov for - * help debugging this. - */ - if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP], - MS_CHAP2_NTRESP_LEN) == 0) { - if (response[MS_CHAP2_FLAGS]) - slprintf(message, message_space, "S=%s", saresponse); - else - slprintf(message, message_space, "S=%s M=%s", - saresponse, "Access granted"); - return 1; - } - - bad: - /* - * Failure message must be formatted as - * "E=e R=r C=c V=v M=m" - * where - * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) - * r = retry (we use 1, ok to retry) - * c = challenge to use for next response, we reuse previous - * v = Change Password version supported, we use 0 - * m = text message - * - * The M=m part is only for MS-CHAPv2. Neither win2k nor - * win98 (others untested) display the message to the user anyway. - * They also both ignore the E=e code. - * - * Note that it's safe to reuse the same challenge as we don't - * actually accept another response based on the error message - * (and no clients try to resend a response anyway). - * - * Basically, this whole bit is useless code, even the small - * implementation here is only because of overspecification. - */ - slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", - challenge_len, challenge, "Access denied"); - return 0; +#endif /* PPP_WITH_EAPTLS */ } -static struct chap_digest_type eap_chapms2_digest = { - CHAP_MICROSOFT_V2, /* code */ - NULL, /* chapms2_generate_challenge, */ - eap_chapms2_verify_response, - NULL, /* chapms2_make_response, */ - NULL, /* chapms2_check_success, */ - NULL, /* chapms_handle_failure, */ -}; - +#if PPP_WITH_CHAPMS /* * eap_chap_verify_response - check whether the peer's response matches * what we think it should be. Returns 1 if it does (authentication @@ -869,7 +795,7 @@ eap_chapms2_send_request(eap_state *esp, u_char id, auth_peer_fail(esp->es_unit, PPP_EAP); } } -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ /* * Format an EAP Request message and send it to the peer. Message @@ -884,13 +810,13 @@ eap_send_request(eap_state *esp) int outlen; int challen; char *str; -#ifdef USE_SRP +#ifdef PPP_WITH_SRP struct t_server *ts; u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; int i, j; struct b64state b64; SHA1_CTX ctxt; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ /* Handle both initial auth and restart */ if (esp->es_server.ea_state < eapIdentify && @@ -956,12 +882,11 @@ eap_send_request(eap_state *esp) INCPTR(esp->es_server.ea_namelen, outp); break; -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case eapMSCHAPv2Chall: - challen = 0x10; + esp->es_server.digest->generate_challenge(esp->es_challenge); + challen = esp->es_challenge[0]; esp->es_challen = challen; - esp->es_challenge[0] = challen; - random_bytes(&esp->es_challenge[1], challen); PUTCHAR(EAPT_MSCHAPV2, outp); PUTCHAR(CHAP_CHALLENGE, outp); @@ -978,9 +903,9 @@ eap_send_request(eap_state *esp) esp->es_server.ea_namelen); INCPTR(esp->es_server.ea_namelen, outp); break; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case eapTlsStart: PUTCHAR(EAPT_TLS, outp); PUTCHAR(EAP_TLS_FLAGS_START, outp); @@ -1002,9 +927,9 @@ eap_send_request(eap_state *esp) eaptls_send(esp->es_server.ea_session, &outp); eap_figure_next_state(esp, 0); break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_CHALLENGE, outp); @@ -1133,7 +1058,7 @@ eap_send_request(eap_state *esp) BCOPY(esp->es_challenge, outp, esp->es_challen); INCPTR(esp->es_challen, outp); break; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ default: return; @@ -1187,18 +1112,18 @@ eap_authpeer(int unit, char *localname) static void eap_server_timeout(void *arg) { -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS u_char *outp; u_char *lenloc; int outlen; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ eap_state *esp = (eap_state *) arg; if (!eap_server_active(esp)) return; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS switch(esp->es_server.ea_prev_state) { /* @@ -1236,7 +1161,7 @@ eap_server_timeout(void *arg) default: break; } -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ /* EAP ID number must not change on timeout. */ eap_send_request(esp); @@ -1417,7 +1342,7 @@ eap_chap_response(eap_state *esp, u_char id, u_char *hash, output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* * Format and send a SRP EAP Response message. */ @@ -1472,9 +1397,9 @@ eap_srpval_response(eap_state *esp, u_char id, u_int32_t flags, u_char *str) output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS /* * Send an EAP-TLS response message with tls data */ @@ -1541,7 +1466,7 @@ eap_tls_sendack(eap_state *esp, u_char id) output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); } -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ static void eap_send_nak(eap_state *esp, u_char id, u_char type) @@ -1564,7 +1489,7 @@ eap_send_nak(eap_state *esp, u_char id, u_char type) output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } -#ifdef USE_SRP +#ifdef PPP_WITH_SRP static char * name_of_pn_file(void) { @@ -1671,7 +1596,40 @@ write_pseudonym(eap_state *esp, u_char *inp, int len, int id) remove_pn_file(); } } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ + +#if PPP_WITH_CHAPMS +/* + * Format and send an CHAPV2-Challenge EAP Response message. + */ +static void +eap_chapv2_response(eap_state *esp, u_char id, u_char chapid, u_char *response, char *user, int user_len) +{ + u_char *outp; + int msglen; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + esp->es_client.ea_id = id; + msglen = EAP_HEADERLEN + 6 * sizeof (u_char) + MS_CHAP2_RESPONSE_LEN + user_len; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_MSCHAPV2, outp); + PUTCHAR(CHAP_RESPONSE, outp); + PUTCHAR(chapid, outp); + PUTCHAR(0, outp); + /* len */ + PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp); + BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1); // VLEN + VALUE + INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp); + BCOPY(user, outp, user_len); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); +} +#endif /* * eap_request - Receive EAP Request message (client mode). @@ -1686,19 +1644,19 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS u_char flags; struct eaptls_session *ets = esp->es_client.ea_session; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP struct t_client *tc; struct t_num sval, gval, Nval, *Ap, Bval; u_char vals[2]; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; int fd; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ /* * Ignore requests if we're not open @@ -1735,7 +1693,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) case EAPT_IDENTITY: if (len > 0) info("EAP: Identity prompt \"%.*q\"", len, inp); -#ifdef USE_SRP +#ifdef PPP_WITH_SRP if (esp->es_usepseudo && (esp->es_usedpseudo == 0 || (esp->es_usedpseudo == 1 && @@ -1761,7 +1719,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) remove_pn_file(); esp->es_usedpseudo = 2; } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ eap_send_response(esp, id, typenum, (u_char *)esp->es_client.ea_name, esp->es_client.ea_namelen); break; @@ -1833,7 +1791,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) esp->es_client.ea_namelen); break; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case EAPT_TLS: switch(esp->es_client.ea_state) { @@ -1859,7 +1817,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) /* Init ssl session */ if(!eaptls_init_ssl_client(esp)) { dbglog("cannot init ssl"); - eap_send_nak(esp, id, EAPT_TLS); + eap_send_nak(esp, id, EAPT_MSCHAPV2); esp->es_client.ea_using_eaptls = 0; break; } @@ -1871,7 +1829,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) } /* The server has sent a bad start packet. */ - eap_send_nak(esp, id, EAPT_TLS); + eap_send_nak(esp, id, EAPT_MSCHAPV2); break; case eapTlsRecvAck: @@ -1901,7 +1859,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) /* Check if TLS handshake is finished */ if(eaptls_is_init_finished(ets)) { -#ifdef MPPE +#ifdef PPP_WITH_MPPE eaptls_gen_mppe_keys(ets, 1); #endif eaptls_free_session(ets); @@ -1915,15 +1873,15 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) break; default: - eap_send_nak(esp, id, EAPT_TLS); + eap_send_nak(esp, id, EAPT_MSCHAPV2); esp->es_client.ea_using_eaptls = 0; break; } break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) { error("EAP: received empty SRP Request"); @@ -2153,7 +2111,137 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) break; } break; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ + +#ifdef PPP_WITH_CHAPMS + case EAPT_MSCHAPV2: + if (len < 4) { + error("EAP: received invalid MSCHAPv2 packet, too short"); + return; + } + unsigned char opcode; + GETCHAR(opcode, inp); + unsigned char chapid; /* Chapv2-ID */ + GETCHAR(chapid, inp); + short mssize; + GETSHORT(mssize, inp); + + /* Validate the mssize field */ + if (len != mssize) { + error("EAP: received invalid MSCHAPv2 packet, invalid length"); + return; + } + len -= 4; + + /* If MSCHAPv2 digest was not found, NAK the packet */ + if (!esp->es_client.digest) { + error("EAP MSCHAPv2 not supported"); + eap_send_nak(esp, id, EAPT_SRP); + return; + } + + switch (opcode) { + case CHAP_CHALLENGE: { + + /* make_response() expects: VLEN + VALUE */ + u_char *challenge = inp; + + unsigned char vsize; + GETCHAR(vsize, inp); + len -= 1; + + /* Validate the VALUE field */ + if (vsize != MS_CHAP2_PEER_CHAL_LEN || len < MS_CHAP2_PEER_CHAL_LEN) { + error("EAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize); + return; + } + + /* Increment past the VALUE field */ + INCPTR(MS_CHAP2_PEER_CHAL_LEN, inp); + len -= MS_CHAP2_PEER_CHAL_LEN; + + /* Extract the hostname */ + rhostname[0] = '\0'; + if (len > 0) { + if (len >= sizeof (rhostname)) { + dbglog("EAP: trimming really long peer name down"); + len = sizeof(rhostname) - 1; + } + BCOPY(inp, rhostname, len); + rhostname[len] = '\0'; + } + + /* In case the remote doesn't give us his name. */ + if (explicit_remote || (remote_name[0] != '\0' && len == 0)) + strlcpy(rhostname, remote_name, sizeof(rhostname)); + + /* Get the secret for authenticating ourselves with the specified host. */ + if (!get_secret(esp->es_unit, esp->es_client.ea_name, + rhostname, secret, &secret_len, 0)) { + dbglog("EAP: no CHAP secret for auth to %q", rhostname); + eap_send_nak(esp, id, EAPT_SRP); + break; + } + esp->es_client.ea_namelen = strlen(esp->es_client.ea_name); + + /* Create the MSCHAPv2 response (and add to cache) */ + unsigned char response[MS_CHAP2_RESPONSE_LEN+1]; // VLEN + VALUE + esp->es_client.digest->make_response(response, chapid, esp->es_client.ea_name, + challenge, secret, secret_len, NULL); + + eap_chapv2_response(esp, id, chapid, response, esp->es_client.ea_name, esp->es_client.ea_namelen); + break; + } + case CHAP_SUCCESS: { + + /* Check response for mutual authentication */ + u_char status = CHAP_FAILURE; + if (esp->es_client.digest->check_success(chapid, inp, len) == 1) { + info("Chap authentication succeeded! %.*v", len, inp); + status = CHAP_SUCCESS; + } + eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status)); + break; + } + case CHAP_FAILURE: { + + /* Process the failure string, and log appropriate information */ + esp->es_client.digest->handle_failure(inp, len); + + u_char status = CHAP_FAILURE; + eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status)); + goto client_failure; /* force termination */ + } + default: + + error("EAP: received invalid MSCHAPv2 packet, invalid or unsupported opcode: %d", opcode); + eap_send_nak(esp, id, EAPT_SRP); + } + + break; +#endif /* PPP_WITH_CHAPMS */ +#ifdef PPP_WITH_PEAP + case EAPT_PEAP: + + /* Initialize the PEAP context (if not already initialized) */ + if (!esp->ea_peap) { + rhostname[0] = '\0'; + if (explicit_remote || (remote_name[0] != '\0')) { + strlcpy(rhostname, remote_name, sizeof (rhostname)); + } + if (peap_init(&esp->ea_peap, rhostname)) { + eap_send_nak(esp, id, EAPT_TLS); + break; + } + } + + /* Process the PEAP packet */ + if (peap_process(esp, id, inp, len)) { + eap_send_nak(esp, id, EAPT_TLS); + } + + break; +#endif // PPP_WITH_PEAP default: info("EAP: unknown authentication type %d; Naking", typenum); @@ -2168,16 +2256,16 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) } return; -#ifdef USE_SRP client_failure: esp->es_client.ea_state = eapBadAuth; if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } esp->es_client.ea_session = NULL; +#ifdef PPP_WITH_SRP t_clientclose(tc); auth_withpeer_fail(esp->es_unit, PPP_EAP); -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ } /* @@ -2193,25 +2281,23 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; -#ifdef USE_SRP +#ifdef PPP_WITH_SRP struct t_server *ts; struct t_num A; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS struct eaptls_session *ets; u_char flags; -#endif /* USE_EAPTLS */ -#ifdef CHAPMS +#endif /* PPP_WITH_EAPTLS */ +#ifdef PPP_WITH_CHAPMS u_char opcode; int (*chap_verifier)(char *, char *, int, struct chap_digest_type *, unsigned char *, unsigned char *, char *, int); char response_message[256]; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ /* * Ignore responses if we're not open @@ -2258,7 +2344,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) eap_figure_next_state(esp, 0); break; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case EAPT_TLS: switch(esp->es_server.ea_state) { @@ -2288,7 +2374,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) GETCHAR(flags, inp); if(len == 1 && !flags) { /* Ack = ok */ -#ifdef MPPE +#ifdef PPP_WITH_MPPE eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 ); #endif eap_send_success(esp); @@ -2314,7 +2400,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) break; } break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ case EAPT_NOTIFICATION: dbglog("EAP unexpected Notification; response discarded"); @@ -2347,19 +2433,25 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) esp->es_server.ea_state = eapMD5Chall; break; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS /* Send EAP-TLS start packet */ case EAPT_TLS: esp->es_server.ea_state = eapTlsStart; break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case EAPT_MSCHAPV2: info("EAP: peer proposes MSCHAPv2"); + /* If MSCHAPv2 digest was not found, NAK the packet */ + if (!esp->es_server.digest) { + error("EAP MSCHAPv2 not supported"); + eap_send_nak(esp, id, EAPT_SRP); + break; + } esp->es_server.ea_state = eapMSCHAPv2Chall; break; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ default: dbglog("EAP: peer requesting unknown Type %d", vallen); @@ -2442,7 +2534,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); break; -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case EAPT_MSCHAPV2: if (len < 1) { error("EAP: received MSCHAPv2 with no data"); @@ -2486,6 +2578,14 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) (remote_name[0] != '\0' && vallen == len)) strlcpy(rhostname, remote_name, sizeof (rhostname)); + /* strip the MS domain name */ + if (chapms_strip_domain && strrchr(rhostname, '\\')) { + char tmp[MAXNAMELEN+1]; + + strcpy(tmp, strrchr(rhostname, '\\') + 1); + strcpy(rhostname, tmp); + } + if (chap_verify_hook) chap_verifier = chap_verify_hook; else @@ -2495,7 +2595,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) if ((*chap_verifier)(rhostname, esp->es_server.ea_name, id, - &eap_chapms2_digest, + esp->es_server.digest, esp->es_challenge, inp - 1, response_message, @@ -2537,9 +2637,9 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) } break; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ -#ifdef USE_SRP +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) { error("EAP: empty SRP Response"); @@ -2640,7 +2740,7 @@ eap_response(eap_state *esp, u_char *inp, int id, int len) break; } break; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ default: /* This can't happen. */ @@ -2666,9 +2766,9 @@ static void eap_success(eap_state *esp, u_char *inp, int id, int len) { if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp) -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS && esp->es_client.ea_state != eapTlsRecvSuccess -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ ) { dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(esp->es_client.ea_state), @@ -2676,7 +2776,7 @@ eap_success(eap_state *esp, u_char *inp, int id, int len) return; } -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state != eapTlsRecvSuccess) { dbglog("EAP-TLS unexpected success message in state %s (%d)", @@ -2684,7 +2784,7 @@ eap_success(eap_state *esp, u_char *inp, int id, int len) esp->es_client.ea_state); return; } -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); @@ -2695,6 +2795,10 @@ eap_success(eap_state *esp, u_char *inp, int id, int len) PRINTMSG(inp, len); } +#ifdef PPP_WITH_PEAP + peap_finish(&esp->ea_peap); +#endif + esp->es_client.ea_state = eapOpen; auth_withpeer_success(esp->es_unit, PPP_EAP, 0); } @@ -2729,6 +2833,11 @@ eap_failure(eap_state *esp, u_char *inp, int id, int len) esp->es_client.ea_state = eapBadAuth; error("EAP: peer reports authentication failure"); + +#ifdef PPP_WITH_PEAP + peap_finish(&esp->ea_peap); +#endif + auth_withpeer_fail(esp->es_unit, PPP_EAP); } @@ -2809,12 +2918,12 @@ eap_printpkt(u_char *inp, int inlen, int code, id, len, rtype, vallen; u_char *pstart; u_int32_t uval; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS u_char flags; -#endif /* USE_EAPTLS */ -#ifdef CHAPMS +#endif /* PPP_WITH_EAPTLS */ +#ifdef PPP_WITH_CHAPMS u_char opcode; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ if (inlen < EAP_HEADERLEN) return (0); @@ -2879,7 +2988,7 @@ eap_printpkt(u_char *inp, int inlen, } break; -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case EAPT_MSCHAPV2: if (len <= 0) break; @@ -2932,9 +3041,9 @@ eap_printpkt(u_char *inp, int inlen, break; } break; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case EAPT_TLS: if (len < 1) break; @@ -2950,8 +3059,9 @@ eap_printpkt(u_char *inp, int inlen, printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 3) goto truncated; @@ -3039,6 +3149,7 @@ eap_printpkt(u_char *inp, int inlen, break; } break; +#endif /* PPP_WITH_SRP */ } break; @@ -3063,7 +3174,7 @@ eap_printpkt(u_char *inp, int inlen, } break; -#ifdef USE_EAPTLS +#ifdef PPP_WITH_EAPTLS case EAPT_TLS: if (len < 1) break; @@ -3080,7 +3191,7 @@ eap_printpkt(u_char *inp, int inlen, printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); break; -#endif /* USE_EAPTLS */ +#endif /* PPP_WITH_EAPTLS */ case EAPT_NAK: if (len <= 0) { @@ -3091,7 +3202,7 @@ eap_printpkt(u_char *inp, int inlen, len--; printer(arg, " = 1 && - rtype < sizeof (eap_typenames) / sizeof (char *)) + rtype <= sizeof (eap_typenames) / sizeof (char *)) printer(arg, " (%s)", eap_typenames[rtype-1]); printer(arg, ">"); break; @@ -3119,7 +3230,7 @@ eap_printpkt(u_char *inp, int inlen, } break; -#ifdef CHAPMS +#ifdef PPP_WITH_CHAPMS case EAPT_MSCHAPV2: if (len <= 0) break; @@ -3162,8 +3273,9 @@ eap_printpkt(u_char *inp, int inlen, break; } break; -#endif /* CHAPMS */ +#endif /* PPP_WITH_CHAPMS */ +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) goto truncated; @@ -3208,6 +3320,7 @@ eap_printpkt(u_char *inp, int inlen, break; } break; +#endif /* PPP_WITH_SRP */ } break;