X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Feap.c;h=4ad67a5c5eb70810ccbfb632819eb98907394d21;hp=6a50a599e45756b3471586ea22fa0a31603ba0fc;hb=a12ffcd5b0a1cf9a4920064295c9b02b127465b3;hpb=71d3de90eae52087b405e962ca650b71cec79c67 diff --git a/pppd/eap.c b/pppd/eap.c index 6a50a59..4ad67a5 100644 --- a/pppd/eap.c +++ b/pppd/eap.c @@ -43,12 +43,15 @@ * Based on draft-ietf-pppext-eap-srp-03.txt. */ -#define RCSID "$Id: eap.c,v 1.3 2003/06/11 23:56:26 paulus Exp $" - /* - * TODO: + * Modification by Beniamino Galvani, Mar 2005 + * Implemented EAP-TLS authentication */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -64,22 +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 -static const char rcsid[] = RCSID; +#ifdef PPP_WITH_EAPTLS +#include "eap-tls.h" +#endif /* PPP_WITH_EAPTLS */ + +#ifdef PPP_WITH_CHAPMS +#include "chap_ms.h" +#include "chap-new.h" + +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 @@ -97,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, @@ -111,13 +129,13 @@ static option_t eap_option_list[] = { /* * Protocol entry points. */ -static void eap_init __P((int unit)); -static void eap_input __P((int unit, u_char *inp, int inlen)); -static void eap_protrej __P((int unit)); -static void eap_lowerup __P((int unit)); -static void eap_lowerdown __P((int unit)); -static int eap_printpkt __P((u_char *inp, int inlen, - void (*)(void *arg, char *fmt, ...), void *arg)); +static void eap_init (int unit); +static void eap_input (int unit, u_char *inp, int inlen); +static void eap_protrej (int unit); +static void eap_lowerup (int unit); +static void eap_lowerdown (int unit); +static int eap_printpkt (u_char *inp, int inlen, + void (*)(void *arg, char *fmt, ...), void *arg); struct protent eap_protent = { PPP_EAP, /* protocol number */ @@ -139,6 +157,7 @@ struct protent eap_protent = { NULL /* say whether to bring up link for this pkt */ }; +#ifdef PPP_WITH_SRP /* * A well-known 2048 bit modulus. */ @@ -176,16 +195,16 @@ static const u_char wkmodulus[] = { 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 }; +#endif /* PPP_WITH_SRP */ /* Local forward declarations. */ -static void eap_server_timeout __P((void *arg)); +static void eap_server_timeout (void *arg); /* * Convert EAP state code to printable string for debug. */ static const char * -eap_state_name(esc) -enum eap_state_code esc; +eap_state_name(enum eap_state_code esc) { static const char *state_names[] = { EAP_STATES }; @@ -197,8 +216,7 @@ enum eap_state_code esc; * called once by main() during start-up. */ static void -eap_init(unit) -int unit; +eap_init(int unit) { eap_state *esp = &eap_states[unit]; @@ -209,6 +227,13 @@ 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 PPP_WITH_EAPTLS + esp->es_client.ea_using_eaptls = 0; +#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 } /* @@ -216,8 +241,7 @@ int unit; * Request messages. */ static void -eap_client_timeout(arg) -void *arg; +eap_client_timeout(void *arg) { eap_state *esp = (eap_state *) arg; @@ -236,9 +260,7 @@ void *arg; * after eap_lowerup. */ void -eap_authwithpeer(unit, localname) -int unit; -char *localname; +eap_authwithpeer(int unit, char *localname) { eap_state *esp = &eap_states[unit]; @@ -262,8 +284,7 @@ char *localname; * (Server operation) */ static void -eap_send_failure(esp) -eap_state *esp; +eap_send_failure(eap_state *esp) { u_char *outp; @@ -287,8 +308,7 @@ eap_state *esp; * (Server operation) */ static void -eap_send_success(esp) -eap_state *esp; +eap_send_success(eap_state *esp) { u_char *outp; @@ -307,7 +327,7 @@ 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. @@ -342,11 +362,7 @@ struct b64state { }; static int -b64enc(bs, inp, inlen, outp) -struct b64state *bs; -u_char *inp; -int inlen; -u_char *outp; +b64enc(struct b64state *bs, u_char *inp, int inlen, u_char *outp) { int outlen = 0; @@ -368,9 +384,7 @@ u_char *outp; } static int -b64flush(bs, outp) -struct b64state *bs; -u_char *outp; +b64flush(struct b64state *bs, u_char *outp) { int outlen = 0; @@ -390,11 +404,7 @@ u_char *outp; } static int -b64dec(bs, inp, inlen, outp) -struct b64state *bs; -u_char *inp; -int inlen; -u_char *outp; +b64dec(struct b64state *bs, u_char *inp, int inlen, u_char *outp) { int outlen = 0; char *cp; @@ -413,7 +423,7 @@ u_char *outp; } return (outlen); } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ /* * Assume that current waiting server state is complete and figure @@ -422,11 +432,9 @@ u_char *outp; * 0 for success and non-zero for failure. */ static void -eap_figure_next_state(esp, status) -eap_state *esp; -int status; +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; @@ -435,15 +443,23 @@ int status; int id, i, plen, toffs; u_char vals[2]; struct b64state bs; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ +#ifdef PPP_WITH_EAPTLS + struct eaptls_session *ets; + int secret_len; + char secret[MAXWORDLEN]; +#endif /* PPP_WITH_EAPTLS */ esp->es_server.ea_timeout = esp->es_savedtime; +#ifdef PPP_WITH_EAPTLS + esp->es_server.ea_prev_state = esp->es_server.ea_state; +#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) { @@ -451,12 +467,12 @@ 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, @@ -546,7 +562,7 @@ 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; @@ -561,19 +577,91 @@ int status; t_servergenexp(ts); break; } -#endif /* USE_SRP */ +#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 /* PPP_WITH_EAPTLS */ + esp->es_server.ea_state = eapMD5Chall; break; +#ifdef PPP_WITH_EAPTLS + case eapTlsStart: + /* Initialize ssl session */ + if(!eaptls_init_ssl_server(esp)) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecv: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->alert_sent) { + esp->es_server.ea_state = eapTlsSendAlert; + break; + } + + if (status) { + esp->es_server.ea_state = eapBadAuth; + break; + } + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsSendAck; + else + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSend: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsRecvAck; + else + if(SSL_is_init_finished(ets->ssl)) + esp->es_server.ea_state = eapTlsRecvClient; + else + /* JJK Add "TLS empty record" message here ??? */ + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsSendAck: + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecvAck: + if (status) + { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSendAlert: + esp->es_server.ea_state = eapTlsRecvAlertAck; + break; +#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) { @@ -584,14 +672,14 @@ 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 { @@ -601,14 +689,14 @@ 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 { @@ -616,6 +704,9 @@ int status; } break; +#ifdef PPP_WITH_CHAPMS + case eapMSCHAPv2Chall: +#endif case eapMD5Chall: if (status != 0) { esp->es_server.ea_state = eapBadAuth; @@ -630,15 +721,88 @@ int status; } if (esp->es_server.ea_state == eapBadAuth) eap_send_failure(esp); + +#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 /* PPP_WITH_EAPTLS */ } +#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 + * succeeded), or 0 if it doesn't. + */ +static int +eap_chap_verify_response(char *name, char *ourname, int id, + struct chap_digest_type *digest, + unsigned char *challenge, unsigned char *response, + char *message, int message_space) +{ + int ok; + unsigned char secret[MAXSECRETLEN]; + int secret_len; + + /* Get the secret that the peer is supposed to know */ + if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) { + error("No CHAP secret found for authenticating %q", name); + return 0; + } + + ok = digest->verify_response(id, name, secret, secret_len, challenge, + response, message, message_space); + memset(secret, 0, sizeof(secret)); + + return ok; +} + +/* + * Format and send an CHAPV2-Success/Failure EAP Request message. + */ +static void +eap_chapms2_send_request(eap_state *esp, u_char id, + u_char opcode, u_char chapid, + char *message, int message_len) +{ + u_char *outp; + int msglen; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + msglen = EAP_HEADERLEN + 5 * sizeof (u_char); + msglen += message_len; + + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(id, outp); + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_MSCHAPV2, outp); + PUTCHAR(opcode, outp); + PUTCHAR(chapid, outp); + /* MS len */ + PUTSHORT(msglen - 5, outp); + BCOPY(message, outp, message_len); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); + + if (opcode == CHAP_SUCCESS) { + auth_peer_success(esp->es_unit, PPP_EAP, 0, + esp->es_server.ea_peer, esp->es_server.ea_peerlen); + } + else { + esp->es_server.ea_state = eapBadAuth; + auth_peer_fail(esp->es_unit, PPP_EAP); + } +} +#endif /* PPP_WITH_CHAPMS */ + /* * Format an EAP Request message and send it to the peer. Message * type depends on current state. (Server operation) */ static void -eap_send_request(esp) -eap_state *esp; +eap_send_request(eap_state *esp) { u_char *outp; u_char *lenloc; @@ -646,13 +810,13 @@ 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 && @@ -718,7 +882,54 @@ eap_state *esp; INCPTR(esp->es_server.ea_namelen, outp); break; -#ifdef USE_SRP +#ifdef PPP_WITH_CHAPMS + case eapMSCHAPv2Chall: + esp->es_server.digest->generate_challenge(esp->es_challenge); + challen = esp->es_challenge[0]; + esp->es_challen = challen; + + PUTCHAR(EAPT_MSCHAPV2, outp); + PUTCHAR(CHAP_CHALLENGE, outp); + PUTCHAR(esp->es_server.ea_id, outp); + /* MS len */ + PUTSHORT(5 + challen + + esp->es_server.ea_namelen, + outp); + /* challen + challenge */ + BCOPY(esp->es_challenge, outp, challen+1); + INCPTR(challen+1, outp); + BCOPY(esp->es_server.ea_name, + outp, + esp->es_server.ea_namelen); + INCPTR(esp->es_server.ea_namelen, outp); + break; +#endif /* PPP_WITH_CHAPMS */ + +#ifdef PPP_WITH_EAPTLS + case eapTlsStart: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(EAP_TLS_FLAGS_START, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSend: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAck: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAlert: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; +#endif /* PPP_WITH_EAPTLS */ + +#ifdef PPP_WITH_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_CHALLENGE, outp); @@ -847,7 +1058,7 @@ 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; @@ -871,9 +1082,7 @@ eap_state *esp; * after eap_lowerup. */ void -eap_authpeer(unit, localname) -int unit; -char *localname; +eap_authpeer(int unit, char *localname) { eap_state *esp = &eap_states[unit]; @@ -901,14 +1110,59 @@ char *localname; * expired. */ static void -eap_server_timeout(arg) -void *arg; +eap_server_timeout(void *arg) { +#ifdef PPP_WITH_EAPTLS + u_char *outp; + u_char *lenloc; + int outlen; +#endif /* PPP_WITH_EAPTLS */ + eap_state *esp = (eap_state *) arg; if (!eap_server_active(esp)) return; +#ifdef PPP_WITH_EAPTLS + switch(esp->es_server.ea_prev_state) { + + /* + * In eap-tls the state changes after a request, so we return to + * previous state ... + */ + case(eapTlsStart): + case(eapTlsSendAck): + esp->es_server.ea_state = esp->es_server.ea_prev_state; + break; + + /* + * ... or resend the stored data + */ + case(eapTlsSend): + case(eapTlsSendAlert): + outp = outpacket_buf; + MAKEHEADER(outp, PPP_EAP); + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(esp->es_server.ea_id, outp); + lenloc = outp; + INCPTR(2, outp); + + eaptls_retransmit(esp->es_server.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN); + esp->es_server.ea_requests++; + + if (esp->es_server.ea_timeout > 0) + TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout); + + return; + default: + break; + } +#endif /* PPP_WITH_EAPTLS */ + /* EAP ID number must not change on timeout. */ eap_send_request(esp); } @@ -919,8 +1173,7 @@ void *arg; * will restart the timer. If it fails, then the link is dropped. */ static void -eap_rechallenge(arg) -void *arg; +eap_rechallenge(void *arg) { eap_state *esp = (eap_state *)arg; @@ -936,8 +1189,7 @@ void *arg; } static void -srp_lwrechallenge(arg) -void *arg; +srp_lwrechallenge(void *arg) { eap_state *esp = (eap_state *)arg; @@ -960,8 +1212,7 @@ void *arg; * thing. */ static void -eap_lowerup(unit) -int unit; +eap_lowerup(int unit) { eap_state *esp = &eap_states[unit]; @@ -984,8 +1235,7 @@ int unit; * Cancel all timeouts and return to initial state. */ static void -eap_lowerdown(unit) -int unit; +eap_lowerdown(int unit) { eap_state *esp = &eap_states[unit]; @@ -1019,8 +1269,7 @@ int unit; * failure. */ static void -eap_protrej(unit) -int unit; +eap_protrej(int unit) { eap_state *esp = &eap_states[unit]; @@ -1039,12 +1288,8 @@ int unit; * Format and send a regular EAP Response message. */ static void -eap_send_response(esp, id, typenum, str, lenstr) -eap_state *esp; -u_char id; -u_char typenum; -u_char *str; -int lenstr; +eap_send_response(eap_state *esp, u_char id, u_char typenum, + u_char *str, int lenstr) { u_char *outp; int msglen; @@ -1070,12 +1315,8 @@ int lenstr; * Format and send an MD5-Challenge EAP Response message. */ static void -eap_chap_response(esp, id, hash, name, namelen) -eap_state *esp; -u_char id; -u_char *hash; -char *name; -int namelen; +eap_chap_response(eap_state *esp, u_char id, u_char *hash, + char *name, int namelen) { u_char *outp; int msglen; @@ -1101,17 +1342,13 @@ int namelen; output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } -#ifdef USE_SRP +#ifdef PPP_WITH_SRP /* * Format and send a SRP EAP Response message. */ static void -eap_srp_response(esp, id, subtypenum, str, lenstr) -eap_state *esp; -u_char id; -u_char subtypenum; -u_char *str; -int lenstr; +eap_srp_response(eap_state *esp, u_char id, u_char subtypenum, + u_char *str, int lenstr) { u_char *outp; int msglen; @@ -1138,11 +1375,7 @@ int lenstr; * Format and send a SRP EAP Client Validator Response message. */ static void -eap_srpval_response(esp, id, flags, str) -eap_state *esp; -u_char id; -u_int32_t flags; -u_char *str; +eap_srpval_response(eap_state *esp, u_char id, u_int32_t flags, u_char *str) { u_char *outp; int msglen; @@ -1164,13 +1397,79 @@ u_char *str; output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ + +#ifdef PPP_WITH_EAPTLS +/* + * Send an EAP-TLS response message with tls data + */ +static void +eap_tls_response(eap_state *esp, u_char id) +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + + lenloc = outp; + INCPTR(2, outp); + + /* + If the id in the request is unchanged, we must retransmit + the old data + */ + if(id == esp->es_client.ea_id) + eaptls_retransmit(esp->es_client.ea_session, &outp); + else + eaptls_send(esp->es_client.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); + + esp->es_client.ea_id = id; +} + +/* + * Send an EAP-TLS ack + */ +static void +eap_tls_sendack(eap_state *esp, u_char id) +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + esp->es_client.ea_id = id; + + lenloc = outp; + INCPTR(2, outp); + + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); +} +#endif /* PPP_WITH_EAPTLS */ static void -eap_send_nak(esp, id, type) -eap_state *esp; -u_char id; -u_char type; +eap_send_nak(eap_state *esp, u_char id, u_char type) { u_char *outp; int msglen; @@ -1190,9 +1489,9 @@ 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() +name_of_pn_file(void) { char *user, *path, *file; struct passwd *pw; @@ -1218,8 +1517,7 @@ name_of_pn_file() } static int -open_pn_file(modebits) -mode_t modebits; +open_pn_file(mode_t modebits) { char *path; int fd, err; @@ -1234,7 +1532,7 @@ mode_t modebits; } static void -remove_pn_file() +remove_pn_file(void) { char *path; @@ -1245,10 +1543,7 @@ remove_pn_file() } static void -write_pseudonym(esp, inp, len, id) -eap_state *esp; -u_char *inp; -int len, id; +write_pseudonym(eap_state *esp, u_char *inp, int len, int id) { u_char val; u_char *datp, *digp; @@ -1301,17 +1596,46 @@ int len, 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). */ static void -eap_request(esp, inp, id, len) -eap_state *esp; -u_char *inp; -int id; -int len; +eap_request(eap_state *esp, u_char *inp, int id, int len) { u_char typenum; u_char vallen; @@ -1320,14 +1644,25 @@ int len; char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; -#ifdef USE_SRP +#ifdef PPP_WITH_EAPTLS + u_char flags; + struct eaptls_session *ets = esp->es_client.ea_session; +#endif /* PPP_WITH_EAPTLS */ + +#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 + */ + if (esp->es_client.ea_state <= eapClosed) + return; /* * Note: we update es_client.ea_id *only if* a Response @@ -1358,7 +1693,7 @@ 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 && @@ -1384,8 +1719,8 @@ int len; remove_pn_file(); esp->es_usedpseudo = 2; } -#endif /* USE_SRP */ - eap_send_response(esp, id, typenum, esp->es_client.ea_name, +#endif /* PPP_WITH_SRP */ + eap_send_response(esp, id, typenum, (u_char *)esp->es_client.ea_name, esp->es_client.ea_namelen); break; @@ -1421,7 +1756,7 @@ int len; } /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { + if (len - vallen >= sizeof (rhostname)) { dbglog("EAP: trimming really long peer name down"); BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; @@ -1445,18 +1780,108 @@ int len; eap_send_nak(esp, id, EAPT_SRP); break; } - MD5Init(&mdContext); + MD5_Init(&mdContext); typenum = id; - MD5Update(&mdContext, &typenum, 1); - MD5Update(&mdContext, secret, secret_len); + MD5_Update(&mdContext, &typenum, 1); + MD5_Update(&mdContext, (u_char *)secret, secret_len); BZERO(secret, sizeof (secret)); - MD5Update(&mdContext, inp, vallen); - MD5Final(hash, &mdContext); + MD5_Update(&mdContext, inp, vallen); + MD5_Final(hash, &mdContext); eap_chap_response(esp, id, hash, esp->es_client.ea_name, esp->es_client.ea_namelen); break; -#ifdef USE_SRP +#ifdef PPP_WITH_EAPTLS + case EAPT_TLS: + + switch(esp->es_client.ea_state) { + + case eapListen: + + if (len < 1) { + error("EAP: received EAP-TLS Listen packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + GETCHAR(flags, inp); + if(flags & EAP_TLS_FLAGS_START){ + + esp->es_client.ea_using_eaptls = 1; + + if (explicit_remote){ + esp->es_client.ea_peer = strdup(remote_name); + esp->es_client.ea_peerlen = strlen(remote_name); + } else + esp->es_client.ea_peer = NULL; + + /* Init ssl session */ + if(!eaptls_init_ssl_client(esp)) { + dbglog("cannot init ssl"); + eap_send_nak(esp, id, EAPT_MSCHAPV2); + esp->es_client.ea_using_eaptls = 0; + break; + } + + ets = esp->es_client.ea_session; + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + } + + /* The server has sent a bad start packet. */ + eap_send_nak(esp, id, EAPT_MSCHAPV2); + break; + + case eapTlsRecvAck: + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + case eapTlsRecv: + if (len < 1) { + error("EAP: discarding EAP-TLS Receive packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + eaptls_receive(ets, inp, len); + + if(ets->frag) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecv; + break; + } + + if(ets->alert_recv) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvFailure; + break; + } + + /* Check if TLS handshake is finished */ + if(eaptls_is_init_finished(ets)) { +#ifdef PPP_WITH_MPPE + eaptls_gen_mppe_keys(ets, 1); +#endif + eaptls_free_session(ets); + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvSuccess; + break; + } + + eap_tls_response(esp,id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + default: + eap_send_nak(esp, id, EAPT_MSCHAPV2); + esp->es_client.ea_using_eaptls = 0; + break; + } + + break; +#endif /* PPP_WITH_EAPTLS */ + +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) { error("EAP: received empty SRP Request"); @@ -1686,7 +2111,137 @@ 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); @@ -1701,27 +2256,23 @@ 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 */ } /* * eap_response - Receive EAP Response message (server mode). */ static void -eap_response(esp, inp, id, len) -eap_state *esp; -u_char *inp; -int id; -int len; +eap_response(eap_state *esp, u_char *inp, int id, int len) { u_char typenum; u_char vallen; @@ -1730,12 +2281,29 @@ 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]; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ + +#ifdef PPP_WITH_EAPTLS + struct eaptls_session *ets; + u_char flags; +#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 /* PPP_WITH_CHAPMS */ + + /* + * Ignore responses if we're not open + */ + if (esp->es_server.ea_state <= eapClosed) + return; if (esp->es_server.ea_id != id) { dbglog("EAP: discarding Response %d; expected ID %d", id, @@ -1776,6 +2344,64 @@ int len; eap_figure_next_state(esp, 0); break; +#ifdef PPP_WITH_EAPTLS + case EAPT_TLS: + switch(esp->es_server.ea_state) { + + case eapTlsRecv: + + ets = (struct eaptls_session *) esp->es_server.ea_session; + + eap_figure_next_state(esp, + eaptls_receive(esp->es_server.ea_session, inp, len)); + + if(ets->alert_recv) { + eap_send_failure(esp); + break; + } + break; + + case eapTlsRecvAck: + if(len > 1) { + dbglog("EAP-TLS ACK with extra data"); + } + eap_figure_next_state(esp, 0); + break; + + case eapTlsRecvClient: + /* Receive authentication response from client */ + if (len > 0) { + GETCHAR(flags, inp); + + if(len == 1 && !flags) { /* Ack = ok */ +#ifdef PPP_WITH_MPPE + eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 ); +#endif + eap_send_success(esp); + } + else { /* failure */ + warn("Server authentication failed"); + eap_send_failure(esp); + } + } + else + warn("Bogus EAP-TLS packet received from client"); + + eaptls_free_session(esp->es_server.ea_session); + + break; + + case eapTlsRecvAlertAck: + eap_send_failure(esp); + break; + + default: + eap_figure_next_state(esp, 1); + break; + } + break; +#endif /* PPP_WITH_EAPTLS */ + case EAPT_NOTIFICATION: dbglog("EAP unexpected Notification; response discarded"); break; @@ -1807,6 +2433,26 @@ int len; esp->es_server.ea_state = eapMD5Chall; break; +#ifdef PPP_WITH_EAPTLS + /* Send EAP-TLS start packet */ + case EAPT_TLS: + esp->es_server.ea_state = eapTlsStart; + break; +#endif /* PPP_WITH_EAPTLS */ + +#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 /* PPP_WITH_CHAPMS */ + default: dbglog("EAP: peer requesting unknown Type %d", vallen); switch (esp->es_server.ea_state) { @@ -1847,7 +2493,7 @@ int len; } /* Not so likely to happen. */ - if (vallen >= len + sizeof (rhostname)) { + if (len - vallen >= sizeof (rhostname)) { dbglog("EAP: trimming really long peer name down"); BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; @@ -1871,12 +2517,12 @@ int len; eap_send_failure(esp); break; } - MD5Init(&mdContext); - MD5Update(&mdContext, &esp->es_server.ea_id, 1); - MD5Update(&mdContext, secret, secret_len); + MD5_Init(&mdContext); + MD5_Update(&mdContext, &esp->es_server.ea_id, 1); + MD5_Update(&mdContext, (u_char *)secret, secret_len); BZERO(secret, sizeof (secret)); - MD5Update(&mdContext, esp->es_challenge, esp->es_challen); - MD5Final(hash, &mdContext); + MD5_Update(&mdContext, esp->es_challenge, esp->es_challen); + MD5_Final(hash, &mdContext); if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) { eap_send_failure(esp); break; @@ -1888,7 +2534,112 @@ int len; TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); break; -#ifdef USE_SRP +#ifdef PPP_WITH_CHAPMS + case EAPT_MSCHAPV2: + if (len < 1) { + error("EAP: received MSCHAPv2 with no data"); + eap_figure_next_state(esp, 1); + break; + } + GETCHAR(opcode, inp); + len--; + + switch (opcode) { + case CHAP_RESPONSE: + if (esp->es_server.ea_state != eapMSCHAPv2Chall) { + error("EAP: unexpected MSCHAPv2-Response"); + eap_figure_next_state(esp, 1); + break; + } + /* skip MS ID + len */ + INCPTR(3, inp); + GETCHAR(vallen, inp); + len -= 4; + + if (vallen != MS_CHAP2_RESPONSE_LEN || vallen > len) { + error("EAP: Invalid MSCHAPv2-Response " + "length %d", vallen); + eap_figure_next_state(esp, 1); + break; + } + + /* Not so likely to happen. */ + if (len - vallen >= sizeof (rhostname)) { + dbglog("EAP: trimming really long peer name down"); + BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); + rhostname[sizeof (rhostname) - 1] = '\0'; + } else { + BCOPY(inp + vallen, rhostname, len - vallen); + rhostname[len - vallen] = '\0'; + } + + /* In case the remote doesn't give us his name. */ + if (explicit_remote || + (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 + chap_verifier = eap_chap_verify_response; + + esp->es_server.ea_id += 1; + if ((*chap_verifier)(rhostname, + esp->es_server.ea_name, + id, + esp->es_server.digest, + esp->es_challenge, + inp - 1, + response_message, + sizeof(response_message))) + { + info("EAP: MSCHAPv2 success for peer %q", + rhostname); + esp->es_server.ea_type = EAPT_MSCHAPV2; + eap_chapms2_send_request(esp, + esp->es_server.ea_id, + CHAP_SUCCESS, + esp->es_server.ea_id, + response_message, + strlen(response_message)); + eap_figure_next_state(esp, 0); + if (esp->es_rechallenge != 0) + TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); + } + else { + warn("EAP: MSCHAPv2 failure for peer %q", + rhostname); + eap_chapms2_send_request(esp, + esp->es_server.ea_id, + CHAP_FAILURE, + esp->es_server.ea_id, + response_message, + strlen(response_message)); + } + break; + case CHAP_SUCCESS: + info("EAP: MSCHAPv2 success confirmed"); + break; + case CHAP_FAILURE: + info("EAP: MSCHAPv2 failure confirmed"); + break; + default: + error("EAP: Unhandled MSCHAPv2 opcode %d", opcode); + eap_send_nak(esp, id, EAPT_SRP); + } + + break; +#endif /* PPP_WITH_CHAPMS */ + +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) { error("EAP: empty SRP Response"); @@ -1989,7 +2740,7 @@ int len; break; } break; -#endif /* USE_SRP */ +#endif /* PPP_WITH_SRP */ default: /* This can't happen. */ @@ -2012,19 +2763,29 @@ int len; * eap_success - Receive EAP Success message (client mode). */ static void -eap_success(esp, inp, id, len) -eap_state *esp; -u_char *inp; -int id; -int len; +eap_success(eap_state *esp, u_char *inp, int id, int len) { - if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) { + if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp) +#ifdef PPP_WITH_EAPTLS + && esp->es_client.ea_state != eapTlsRecvSuccess +#endif /* PPP_WITH_EAPTLS */ + ) { dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(esp->es_client.ea_state), esp->es_client.ea_state); return; } +#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)", + eap_state_name(esp->es_client.ea_state), + esp->es_client.ea_state); + return; + } +#endif /* PPP_WITH_EAPTLS */ + if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } @@ -2034,6 +2795,10 @@ 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); } @@ -2042,12 +2807,14 @@ int len; * eap_failure - Receive EAP Failure message (client mode). */ static void -eap_failure(esp, inp, id, len) -eap_state *esp; -u_char *inp; -int id; -int len; +eap_failure(eap_state *esp, u_char *inp, int id, int len) { + /* + * Ignore failure messages if we're not open + */ + if (esp->es_client.ea_state <= eapClosed) + return; + if (!eap_client_active(esp)) { dbglog("EAP unexpected failure message in state %s (%d)", eap_state_name(esp->es_client.ea_state), @@ -2066,6 +2833,11 @@ 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); } @@ -2073,10 +2845,7 @@ int len; * eap_input - Handle received EAP message. */ static void -eap_input(unit, inp, inlen) -int unit; -u_char *inp; -int inlen; +eap_input(int unit, u_char *inp, int inlen) { eap_state *esp = &eap_states[unit]; u_char code, id; @@ -2137,19 +2906,24 @@ static char *eap_typenames[] = { "OTP", "Generic-Token", NULL, NULL, "RSA", "DSS", "KEA", "KEA-Validate", "TLS", "Defender", "Windows 2000", "Arcot", - "Cisco", "Nokia", "SRP" + "Cisco", "Nokia", "SRP", NULL, + "TTLS", "RAS", "AKA", "3COM", "PEAP", + "MSCHAPv2" }; static int -eap_printpkt(inp, inlen, printer, arg) -u_char *inp; -int inlen; -void (*printer) __P((void *, char *, ...)); -void *arg; +eap_printpkt(u_char *inp, int inlen, + void (*printer) (void *, char *, ...), void *arg) { int code, id, len, rtype, vallen; u_char *pstart; u_int32_t uval; +#ifdef PPP_WITH_EAPTLS + u_char flags; +#endif /* PPP_WITH_EAPTLS */ +#ifdef PPP_WITH_CHAPMS + u_char opcode; +#endif /* PPP_WITH_CHAPMS */ if (inlen < EAP_HEADERLEN) return (0); @@ -2214,6 +2988,80 @@ void *arg; } break; +#ifdef PPP_WITH_CHAPMS + case EAPT_MSCHAPV2: + if (len <= 0) + break; + GETCHAR(opcode, inp); + len--; + switch (opcode) { + case CHAP_CHALLENGE: + INCPTR(3, inp); + len -= 3; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + len -= vallen; + printer(arg, " Challenge <"); + for (; vallen > 0; --vallen) { + u_char val; + GETCHAR(val, inp); + printer(arg, "%.2x", val); + } + printer(arg, ">"); + if (len > 0) { + printer(arg, ", "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, ", "); + } + break; + case CHAP_SUCCESS: + INCPTR(3, inp); + len -= 3; + printer(arg, " Success "); + break; + case CHAP_FAILURE: + INCPTR(3, inp); + len -= 3; + printer(arg, " Failure "); + break; + default: + INCPTR(3, inp); + len -= 3; + printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp); + break; + } + break; +#endif /* PPP_WITH_CHAPMS */ + +#ifdef PPP_WITH_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + break; +#endif /* PPP_WITH_EAPTLS */ + +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 3) goto truncated; @@ -2301,6 +3149,7 @@ void *arg; break; } break; +#endif /* PPP_WITH_SRP */ } break; @@ -2325,6 +3174,25 @@ void *arg; } break; +#ifdef PPP_WITH_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + + break; +#endif /* PPP_WITH_EAPTLS */ + case EAPT_NAK: if (len <= 0) { printer(arg, " "); @@ -2334,7 +3202,7 @@ void *arg; 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; @@ -2362,6 +3230,52 @@ void *arg; } break; +#ifdef PPP_WITH_CHAPMS + case EAPT_MSCHAPV2: + if (len <= 0) + break; + GETCHAR(opcode, inp); + len--; + switch (opcode) { + case CHAP_RESPONSE: + INCPTR(3, inp); + len -= 3; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + len -= vallen; + printer(arg, " Response <"); + for (; vallen > 0; --vallen) { + u_char val; + GETCHAR(val, inp); + printer(arg, "%.2x", val); + } + printer(arg, ">"); + if (len > 0) { + printer(arg, ", "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, ", "); + } + break; + case CHAP_SUCCESS: + printer(arg, " Success"); + break; + case CHAP_FAILURE: + printer(arg, " Failure"); + break; + default: + printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp); + break; + } + break; +#endif /* PPP_WITH_CHAPMS */ + +#ifdef PPP_WITH_SRP case EAPT_SRP: if (len < 1) goto truncated; @@ -2406,6 +3320,7 @@ void *arg; break; } break; +#endif /* PPP_WITH_SRP */ } break;