]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/eap.c
Changing USE_SRP to PPP_WITH_SRP for consistency
[ppp.git] / pppd / eap.c
index 94407f56a336b2d1d0609d67ed5f082a21dd8f63..4ad67a5c5eb70810ccbfb632819eb98907394d21 100644 (file)
  * Based on draft-ietf-pppext-eap-srp-03.txt.
  */
 
-#define RCSID  "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
-
 /*
- * TODO:
+ * Modification by Beniamino Galvani, Mar 2005
+ * Implemented EAP-TLS authentication
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #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 <time.h>
+#endif
 #include <t_pwd.h>
 #include <t_server.h>
 #include <t_client.h>
 #include "pppcrypt.h"
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
 
 #ifndef SHA_DIGESTSIZE
 #define        SHA_DIGESTSIZE 20
 #endif
 
+#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
 
@@ -96,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,
@@ -110,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 */
@@ -138,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.
  */
@@ -175,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 };
 
@@ -196,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];
 
@@ -208,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
 }
 
 /*
@@ -215,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;
 
@@ -235,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];
 
@@ -261,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;
 
@@ -286,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;
 
@@ -306,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.
@@ -341,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;
 
@@ -367,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;
 
@@ -389,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;
@@ -412,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
@@ -421,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;
@@ -434,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) {
@@ -450,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,
@@ -545,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;
@@ -560,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) {
@@ -583,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 {
@@ -600,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 {
@@ -615,6 +704,9 @@ int status;
                }
                break;
 
+#ifdef PPP_WITH_CHAPMS
+       case eapMSCHAPv2Chall:
+#endif
        case eapMD5Chall:
                if (status != 0) {
                        esp->es_server.ea_state = eapBadAuth;
@@ -629,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;
@@ -645,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 &&
@@ -717,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);
@@ -846,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;
@@ -870,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];
 
@@ -900,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);
 }
@@ -918,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;
 
@@ -935,8 +1189,7 @@ void *arg;
 }
 
 static void
-srp_lwrechallenge(arg)
-void *arg;
+srp_lwrechallenge(void *arg)
 {
        eap_state *esp = (eap_state *)arg;
 
@@ -959,8 +1212,7 @@ void *arg;
  * thing.
  */
 static void
-eap_lowerup(unit)
-int unit;
+eap_lowerup(int unit)
 {
        eap_state *esp = &eap_states[unit];
 
@@ -983,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];
 
@@ -1018,8 +1269,7 @@ int unit;
  * failure.
  */
 static void
-eap_protrej(unit)
-int unit;
+eap_protrej(int unit)
 {
        eap_state *esp = &eap_states[unit];
 
@@ -1038,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;
@@ -1069,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;
@@ -1100,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;
@@ -1137,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;
@@ -1163,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;
@@ -1189,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;
@@ -1217,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;
@@ -1233,7 +1532,7 @@ mode_t modebits;
 }
 
 static void
-remove_pn_file()
+remove_pn_file(void)
 {
        char *path;
 
@@ -1244,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;
@@ -1300,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;
@@ -1319,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
@@ -1357,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 &&
@@ -1383,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;
 
@@ -1420,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';
@@ -1455,7 +1791,97 @@ int len;
                    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");
@@ -1685,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);
@@ -1700,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;
@@ -1729,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,
@@ -1775,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;
@@ -1806,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) {
@@ -1846,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';
@@ -1887,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");
@@ -1988,7 +2740,7 @@ int len;
                        break;
                }
                break;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
 
        default:
                /* This can't happen. */
@@ -2011,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);
        }
@@ -2033,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);
 }
@@ -2041,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),
@@ -2065,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);
 }
 
@@ -2072,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;
@@ -2136,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);
@@ -2213,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, ", <Name ");
+                                       print_string((char *)inp, len, printer, arg);
+                                       printer(arg, ">");
+                                       INCPTR(len, inp);
+                                       len = 0;
+                               } else {
+                                       printer(arg, ", <No name>");
+                               }
+                               break;
+                       case CHAP_SUCCESS:
+                               INCPTR(3, inp);
+                               len -= 3;
+                               printer(arg, " Success <Message ");
+                               print_string((char *)inp, len, printer, arg);
+                               printer(arg, ">");
+                               break;
+                       case CHAP_FAILURE:
+                               INCPTR(3, inp);
+                               len -= 3;
+                               printer(arg, " Failure <Message ");
+                               print_string((char *)inp, len, printer, arg);
+                               printer(arg, ">");
+                               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;
@@ -2300,6 +3149,7 @@ void *arg;
                                break;
                        }
                        break;
+#endif  /* PPP_WITH_SRP */
                }
                break;
 
@@ -2324,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, " <missing hint>");
@@ -2333,7 +3202,7 @@ void *arg;
                        len--;
                        printer(arg, " <Suggested-type %02X", rtype);
                        if (rtype >= 1 &&
-                           rtype < sizeof (eap_typenames) / sizeof (char *))
+                           rtype <= sizeof (eap_typenames) / sizeof (char *))
                                printer(arg, " (%s)", eap_typenames[rtype-1]);
                        printer(arg, ">");
                        break;
@@ -2361,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, ", <Name ");
+                                       print_string((char *)inp, len, printer, arg);
+                                       printer(arg, ">");
+                                       INCPTR(len, inp);
+                                       len = 0;
+                               } else {
+                                       printer(arg, ", <No name>");
+                               }
+                               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;
@@ -2405,6 +3320,7 @@ void *arg;
                                break;
                        }
                        break;
+#endif  /* PPP_WITH_SRP */
                }
                break;