Fixes from clang / scan-build
[freeradius.git] / src / modules / rlm_eap / rlm_eap.c
index f977d14..e6399ba 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000-2003  The FreeRADIUS server project
+ * Copyright 2000-2003,2006  The FreeRADIUS server project
  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
  * Copyright 2003  Alan DeKok <aland@freeradius.org>
  */
 
-#include "autoconf.h"
-#include "rlm_eap.h"
-#include "modules.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
 
-static const char rcsid[] = "$Id$";
+#include "rlm_eap.h"
 
 static const CONF_PARSER module_config[] = {
        { "default_eap_type", PW_TYPE_STRING_PTR,
@@ -35,16 +37,14 @@ static const CONF_PARSER module_config[] = {
          offsetof(rlm_eap_t, timer_limit), NULL, "60"},
        { "ignore_unknown_eap_types", PW_TYPE_BOOLEAN,
          offsetof(rlm_eap_t, ignore_unknown_eap_types), NULL, "no" },
-       
+       { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN,
+         offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" },
+       { "max_sessions", PW_TYPE_INTEGER,
+         offsetof(rlm_eap_t, max_sessions), NULL, "2048"},
+
        { NULL, -1, 0, NULL, NULL }           /* end the list */
 };
 
-static int eap_init(void)
-{
-       return 0;
-}
-
-
 /*
  * delete all the allocated space by eap module
  */
@@ -55,6 +55,9 @@ static int eap_detach(void *instance)
 
        inst = (rlm_eap_t *)instance;
 
+       rbtree_free(inst->session_tree);
+       if (inst->handler_tree) rbtree_free(inst->handler_tree);
+       inst->session_tree = NULL;
        eaplist_free(inst);
 
        for (i = 0; i < PW_EAP_MAX_TYPES; i++) {
@@ -62,12 +65,9 @@ static int eap_detach(void *instance)
                inst->types[i] = NULL;
        }
 
-#ifdef HAVE_PTHREAD_H
        pthread_mutex_destroy(&(inst->session_mutex));
-       pthread_mutex_destroy(&(inst->module_mutex));
-#endif
+       if (fr_debug_flag) pthread_mutex_destroy(&(inst->handler_mutex));
 
-       if (inst->default_eap_type_name) free(inst->default_eap_type_name);
        free(inst);
 
        return 0;
@@ -75,15 +75,53 @@ static int eap_detach(void *instance)
 
 
 /*
+ *     Compare two handlers.
+ */
+static int eap_handler_cmp(const void *a, const void *b)
+{
+       int rcode;
+       const EAP_HANDLER *one = a;
+       const EAP_HANDLER *two = b;
+
+       if (one->eap_id < two->eap_id) return -1;
+       if (one->eap_id > two->eap_id) return +1;
+
+       rcode = memcmp(one->state, two->state, sizeof(one->state));
+       if (rcode != 0) return rcode;
+
+       /*
+        *      As of 2.1.8, we don't key off of source IP.  This
+        *      a NAS to send packets load-balanced (or fail-over)
+        *      across multiple intermediate proxies, and still have
+        *      EAP work.
+        */
+       if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) {
+               DEBUG("WARNING: EAP packets are arriving from two different upstream servers.  Has there been a proxy fail-over?");
+       }
+
+       return 0;
+}
+
+
+/*
+ *     Compare two handler pointers
+ */
+static int eap_handler_ptr_cmp(const void *a, const void *b)
+{
+  return (((uint8_t *) a) - ((uint8_t *) b));
+}
+
+
+/*
  * read the config section and load all the eap authentication types present.
  */
 static int eap_instantiate(CONF_SECTION *cs, void **instance)
 {
-       int             eap_type;
+       int             i, eap_type;
        int             num_types;
        CONF_SECTION    *scs;
        rlm_eap_t       *inst;
-       
+
        inst = (rlm_eap_t *) malloc(sizeof(*inst));
        if (!inst) {
                return -1;
@@ -94,13 +132,25 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
                return -1;
        }
 
+       /*
+        *      Create our own random pool.
+        */
+       for (i = 0; i < 256; i++) {
+               inst->rand_pool.randrsl[i] = fr_rand();
+       }
+       fr_randinit(&inst->rand_pool, 1);
+       inst->rand_pool.randcnt = 0;
+
+       inst->xlat_name = cf_section_name2(cs);
+       if (!inst->xlat_name) inst->xlat_name = "EAP";
+
        /* Load all the configured EAP-Types */
        num_types = 0;
        for(scs=cf_subsection_find_next(cs, NULL, NULL);
                scs != NULL;
                scs=cf_subsection_find_next(cs, scs, NULL)) {
 
-               char    *auth_type;
+               const char      *auth_type;
 
                auth_type = cf_section_name1(scs);
 
@@ -108,12 +158,33 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
 
                eap_type = eaptype_name2type(auth_type);
                if (eap_type < 0) {
-                       radlog(L_ERR|L_CONS, "rlm_eap: Unknown EAP type %s",
+                       radlog(L_ERR, "rlm_eap: Unknown EAP type %s",
                               auth_type);
                        eap_detach(inst);
                        return -1;
                }
 
+#ifndef HAVE_OPENSSL_SSL_H
+               /*
+                *      This allows the default configuration to be
+                *      shipped with EAP-TLS, etc. enabled.  If the
+                *      system doesn't have OpenSSL, they will be
+                *      ignored.
+                *
+                *      If the system does have OpenSSL, then this
+                *      code will not be used.  The administrator will
+                *      then have to delete the tls,
+                *      etc. configurations from eap.conf in order to
+                *      have EAP without the TLS types.
+                */
+               if ((eap_type == PW_EAP_TLS) ||
+                   (eap_type == PW_EAP_TTLS) ||
+                   (eap_type == PW_EAP_PEAP)) {
+                       DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type);
+                       continue;
+               }
+#endif
+
                /*
                 *      If we're asked to load TTLS or PEAP, ensure
                 *      that we've first loaded TLS.
@@ -167,27 +238,42 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
         *      of 'inst', above.
         */
 
-       /* Generate a state key, specific to eap */
-       generate_key();
+       /*
+        *      Lookup sessions in the tree.  We don't free them in
+        *      the tree, as that's taken care of elsewhere...
+        */
+       inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
+       if (!inst->session_tree) {
+               radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree");
+               eap_detach(inst);
+               return -1;
+       }
+
+       if (fr_debug_flag) {
+               inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0);
+               if (!inst->handler_tree) {
+                       radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree");
+                       eap_detach(inst);
+                       return -1;
+               }
+
+               if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) {
+                       radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno));
+                       eap_detach(inst);
+                       return -1;
+               }
+       }
+
+       if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
+               radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno));
+               eap_detach(inst);
+               return -1;
+       }
 
-#ifdef HAVE_PTHREAD_H
-       pthread_mutex_init(&(inst->session_mutex), NULL);
-       pthread_mutex_init(&(inst->module_mutex), NULL);
-#endif
-       
        *instance = inst;
        return 0;
 }
 
-/*
- *     Dumb wrapper.
- *     FIXME: this should be done more intelligently...
- */
-static void my_handler_free(void *data)
-{
-  EAP_HANDLER *handler = (EAP_HANDLER *) data;
-  eap_handler_free(&handler);
-}
 
 /*
  *     For backwards compatibility.
@@ -198,18 +284,20 @@ static int eap_authenticate(void *instance, REQUEST *request)
        EAP_HANDLER     *handler;
        eap_packet_t    *eap_packet;
        int             rcode;
-#ifdef HAVE_PTHREAD_H
-       int             locked = FALSE;
-#endif
 
        inst = (rlm_eap_t *) instance;
 
+       if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0)) {
+               RDEBUG("ERROR: You set 'Auth-Type = EAP' for a request that does not contain an EAP-Message attribute!");
+               return RLM_MODULE_INVALID;
+       }
+
        /*
         *      Get the eap packet  to start with
         */
-       eap_packet = eap_attribute(request->packet->vps);
+       eap_packet = eap_vp2packet(request->packet->vps);
        if (eap_packet == NULL) {
-               radlog(L_ERR, "rlm_eap: Malformed EAP Message");
+               radlog_request(L_ERR, 0, request, "Malformed EAP Message");
                return RLM_MODULE_FAIL;
        }
 
@@ -220,74 +308,54 @@ static int eap_authenticate(void *instance, REQUEST *request)
         */
        handler = eap_handler(inst, &eap_packet, request);
        if (handler == NULL) {
-               DEBUG2("  rlm_eap: Failed in handler");
+               RDEBUG2("Failed in handler");
                return RLM_MODULE_INVALID;
        }
 
        /*
-        *      If it's a recursive request, then disallow
-        *      TLS, TTLS, and PEAP, inside of the TLS tunnel.
-        */
-       if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) {
-               switch(handler->eap_ds->response->type.type) {
-               case PW_EAP_TLS:
-               case PW_EAP_TTLS:
-               case PW_EAP_PEAP:
-                       DEBUG2(" rlm_eap: Unable to tunnel TLS inside of TLS");
-                       eap_fail(handler);
-                       eap_handler_free(&handler);
-                       return RLM_MODULE_INVALID;
-                       break;
-
-               default:        /* It may be OK, allow it to proceed */
-                       break;
-
-               }
-       }
-
-#ifdef HAVE_PTHREAD_H
-       else {                  /* it's a normal request from a NAS */
-               /*
-                *      The OpenSSL code isn't strictly thread-safe,
-                *      as we've got to provide callback functions.
-                *
-                *      Rather than doing that, we just ensure that the
-                *      sub-modules are locked via a mutex.
-                *
-                *      Don't lock it if we're calling ourselves recursively,
-                *      we've already got the lock.
-                */
-               pthread_mutex_lock(&(inst->module_mutex));
-               locked = TRUE;  /* for recursive calls to the module */
-       }
-#endif
-
-       /*
         *      Select the appropriate eap_type or default to the
         *      configured one
         */
        rcode = eaptype_select(inst, handler);
 
-#ifdef HAVE_PTHREAD_H
-       if (locked) pthread_mutex_unlock(&(inst->module_mutex));
-#endif
-
        /*
         *      If it failed, die.
         */
        if (rcode == EAP_INVALID) {
                eap_fail(handler);
-               eap_handler_free(&handler);
-               DEBUG2("  rlm_eap: Failed in EAP select");
+               eap_handler_free(inst, handler);
+               RDEBUG2("Failed in EAP select");
                return RLM_MODULE_INVALID;
        }
 
+#ifdef WITH_PROXY
+       /*
+        *      If we're doing horrible tunneling work, remember it.
+        */
+       if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+               RDEBUG2("  Not-EAP proxy set.  Not composing EAP");
+               /*
+                *      Add the handle to the proxied list, so that we
+                *      can retrieve it in the post-proxy stage, and
+                *      send a response.
+                */
+               rcode = request_data_add(request,
+                                        inst, REQUEST_DATA_EAP_HANDLER,
+                                        handler,
+                                        (void *) eap_handler_free);
+               rad_assert(rcode == 0);
+
+               return RLM_MODULE_HANDLED;
+       }
+#endif
+
+#ifdef WITH_PROXY
        /*
         *      Maybe the request was marked to be proxied.  If so,
         *      proxy it.
         */
        if (request->proxy != NULL) {
-               VALUE_PAIR *vp;
+               VALUE_PAIR *vp = NULL;
 
                rad_assert(request->proxy_reply == NULL);
 
@@ -297,17 +365,18 @@ static int eap_authenticate(void *instance, REQUEST *request)
                 *      send a response.
                 */
                rcode = request_data_add(request,
-                                        instance, REQUEST_DATA_EAP_HANDLER,
-                                        handler, my_handler_free);
+                                        inst, REQUEST_DATA_EAP_HANDLER,
+                                        handler,
+                                        (void *) eap_handler_free);
                rad_assert(rcode == 0);
 
                /*
                 *      Some simple sanity checks.  These should really
                 *      be handled by the radius library...
                 */
-               vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE);
+               vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE, 0);
                if (vp) {
-                       vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR);
+                       vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0);
                        if (!vp) {
                                vp = pairmake("Message-Authenticator",
                                              "0x00", T_OP_EQ);
@@ -321,11 +390,12 @@ static int eap_authenticate(void *instance, REQUEST *request)
                 *      set to 127.0.0.1 for tunneled requests, and
                 *      we don't want to tell the world that...
                 */
-               pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO);
+               pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS);
 
+               RDEBUG2("  Tunneled session will be proxied.  Not doing EAP.");
                return RLM_MODULE_HANDLED;
        }
-
+#endif
 
        /*
         *      We are done, wrap the EAP-request in RADIUS to send
@@ -337,9 +407,8 @@ static int eap_authenticate(void *instance, REQUEST *request)
         *      Add to the list only if it is EAP-Request, OR if
         *      it's LEAP, and a response.
         */
-       if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
-           (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
-               eaplist_add(inst, handler);
+       if (((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
+           (handler->eap_ds->request->type.type >= PW_EAP_MD5)) ||
 
                /*
                 *      LEAP is a little different.  At Stage 4,
@@ -350,17 +419,30 @@ static int eap_authenticate(void *instance, REQUEST *request)
                 *      At stage 6, LEAP sends an EAP-Response, which
                 *      isn't put into the list.
                 */
-       } else if ((handler->eap_ds->response->code == PW_EAP_RESPONSE) &&
-                  (handler->eap_ds->response->type.type == PW_EAP_LEAP) &&
-                  (handler->eap_ds->request->code == PW_EAP_SUCCESS) &&
-                  (handler->eap_ds->request->type.type == 0)) {
+           ((handler->eap_ds->response->code == PW_EAP_RESPONSE) &&
+            (handler->eap_ds->response->type.type == PW_EAP_LEAP) &&
+            (handler->eap_ds->request->code == PW_EAP_SUCCESS) &&
+            (handler->eap_ds->request->type.type == 0))) {
 
-               eaplist_add(inst, handler);
+               /*
+                *      Return FAIL if we can't remember the handler.
+                *      This is actually disallowed by the
+                *      specification, as unexpected FAILs could have
+                *      been forged.  However, we want to signal to
+                *      everyone else involved that we are
+                *      intentionally failing the session, as opposed
+                *      to accidentally failing it.
+                */
+               if (!eaplist_add(inst, handler)) {
+                       eap_fail(handler);
+                       eap_handler_free(inst, handler);
+                       return RLM_MODULE_FAIL;
+               }
 
        } else {
-               DEBUG2("  rlm_eap: Freeing handler");
+               RDEBUG2("Freeing handler");
                /* handler is not required any more, free it now */
-               eap_handler_free(&handler);
+               eap_handler_free(inst, handler);
        }
 
        /*
@@ -375,13 +457,26 @@ static int eap_authenticate(void *instance, REQUEST *request)
                /*
                 *      Doesn't exist, add it in.
                 */
-               vp = pairfind(request->reply->vps, PW_USER_NAME);
+               vp = pairfind(request->reply->vps, PW_USER_NAME, 0);
                if (!vp) {
-                       vp = pairmake("User-Name", request->username->strvalue,
+                       vp = pairmake("User-Name", "",
                                      T_OP_EQ);
+                       strlcpy(vp->vp_strvalue, request->username->vp_strvalue,
+                               sizeof(vp->vp_strvalue));
+                       vp->length = request->username->length;
                        rad_assert(vp != NULL);
                        pairadd(&(request->reply->vps), vp);
                }
+
+               /*
+                *      Cisco AP1230 has a bug and needs a zero
+                *      terminated string in Access-Accept.
+                */
+               if ((inst->cisco_accounting_username_bug) &&
+                   (vp->length < (int) sizeof(vp->vp_strvalue))) {
+                       vp->vp_strvalue[vp->length] = '\0';
+                       vp->length++;
+               }
        }
 
        return rcode;
@@ -397,15 +492,17 @@ static int eap_authorize(void *instance, REQUEST *request)
        rlm_eap_t       *inst;
        int             status;
        VALUE_PAIR      *vp;
-       
+
        inst = (rlm_eap_t *)instance;
 
+#ifdef WITH_PROXY
        /*
         *      We don't do authorization again, once we've seen the
         *      proxy reply (or the proxied packet)
         */
        if (request->proxy != NULL)
                 return RLM_MODULE_NOOP;
+#endif
 
        /*
         *      For EAP_START, send Access-Challenge with EAP Identity
@@ -425,11 +522,12 @@ static int eap_authorize(void *instance, REQUEST *request)
                return RLM_MODULE_FAIL;
        case EAP_FOUND:
                return RLM_MODULE_HANDLED;
+       case EAP_OK:
        case EAP_NOTFOUND:
        default:
                break;
        }
-       
+
        /*
         *      RFC 2869, Section 2.3.1.  If a NAS sends an EAP-Identity,
         *      it MUST copy the identity into the User-Name attribute.
@@ -439,30 +537,44 @@ static int eap_authorize(void *instance, REQUEST *request)
         *      and to get excited if it doesn't appear.
         */
 
-       vp = pairfind(request->config_items, PW_AUTH_TYPE);
+       vp = pairfind(request->config_items, PW_AUTH_TYPE, 0);
        if ((!vp) ||
-           (vp->lvalue != PW_AUTHTYPE_REJECT)) {
-               vp = pairmake("Auth-Type", "EAP", T_OP_EQ);
+           (vp->vp_integer != PW_AUTHTYPE_REJECT)) {
+               vp = pairmake("Auth-Type", inst->xlat_name, T_OP_EQ);
                if (!vp) {
+                       RDEBUG2("Failed to create Auth-Type %s: %s\n",
+                               inst->xlat_name, fr_strerror());
                        return RLM_MODULE_FAIL;
                }
                pairadd(&request->config_items, vp);
+       } else {
+               RDEBUG2("WARNING: Auth-Type already set.  Not setting to EAP");
        }
 
+       if (status == EAP_OK) return RLM_MODULE_OK;
+
        return RLM_MODULE_UPDATED;
 }
 
+
+#ifdef WITH_PROXY
 /*
  *     If we're proxying EAP, then there may be magic we need
  *     to do.
  */
 static int eap_post_proxy(void *inst, REQUEST *request)
 {
-       int             i, len;
+       size_t          i;
+       size_t          len;
        VALUE_PAIR      *vp;
        EAP_HANDLER     *handler;
 
        /*
+        *      Just in case the admin lists EAP in post-proxy-type Fail.
+        */
+       if (!request->proxy_reply) return RLM_MODULE_NOOP;
+
+       /*
         *      If there was a handler associated with this request,
         *      then it's a tunneled request which was proxied...
         */
@@ -478,41 +590,48 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                                                              request->proxy,
                                                              REQUEST_DATA_EAP_TUNNEL_CALLBACK);
                if (!data) {
-                       radlog(L_ERR, "rlm_eap: Failed to retrieve callback for tunneled session!");
-                       eap_handler_free(&handler);
+                       radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!");
+                       eap_handler_free(inst, handler);
                        return RLM_MODULE_FAIL;
                }
 
                /*
                 *      Do the callback...
                 */
+               RDEBUG2("Doing post-proxy callback");
                rcode = data->callback(handler, data->tls_session);
                free(data);
                if (rcode == 0) {
-                       eap_handler_free(&handler);
+                       RDEBUG2("Failed in post-proxy callback");
+                       eap_fail(handler);
+                       eap_handler_free(inst, handler);
                        return RLM_MODULE_REJECT;
                }
-               
+
                /*
                 *      We are done, wrap the EAP-request in RADIUS to send
                 *      with all other required radius attributes
                 */
-               rcode = eap_compose(handler);
-               
+               eap_compose(handler);
+
                /*
                 *      Add to the list only if it is EAP-Request, OR if
                 *      it's LEAP, and a response.
                 */
                if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
                    (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
-                       eaplist_add(inst, handler);
-
+                       if (!eaplist_add(inst, handler)) {
+                               eap_fail(handler);
+                               eap_handler_free(inst, handler);
+                               return RLM_MODULE_FAIL;
+                       }
+                       
                } else {        /* couldn't have been LEAP, there's no tunnel */
-                       DEBUG2("  rlm_eap: Freeing handler");
+                       RDEBUG2("Freeing handler");
                        /* handler is not required any more, free it now */
-                       eap_handler_free(&handler);
+                       eap_handler_free(inst, handler);
                }
-               
+
                /*
                 *      If it's an Access-Accept, RFC 2869, Section 2.3.1
                 *      says that we MUST include a User-Name attribute in the
@@ -523,19 +642,20 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                        /*
                         *      Doesn't exist, add it in.
                         */
-                       vp = pairfind(request->reply->vps, PW_USER_NAME);
+                       vp = pairfind(request->reply->vps, PW_USER_NAME, 0);
                        if (!vp) {
-                               vp = pairmake("User-Name", request->username->strvalue,
+                               vp = pairmake("User-Name", request->username->vp_strvalue,
                                              T_OP_EQ);
                                rad_assert(vp != NULL);
                                pairadd(&(request->reply->vps), vp);
                        }
                }
-               
+
                return RLM_MODULE_OK;
+       } else {
+               RDEBUG2("No pre-existing handler found");
        }
 
-
        /*
         *      There may be more than one Cisco-AVPair.
         *      Ensure we find the one with the LEAP attribute.
@@ -549,26 +669,31 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                 *      This is vendor Cisco (9), Cisco-AVPair
                 *      attribute (1)
                 */
-               vp = pairfind(vp, (9 << 16)  | 1);
+               vp = pairfind(vp, 1, 9);
                if (!vp) {
                        return RLM_MODULE_NOOP;
                }
-               
+
                /*
                 *      If it's "leap:session-key", then stop.
                 *
                 *      The format is VERY specific!
                 */
-               if (strncasecmp(vp->strvalue, "leap:session-key=", 17) == 0) {
+               if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) {
                        break;
                }
+
+               /*
+                *      Not this AV-pair.  Go to the next one.
+                */
+               vp = vp->next;
        }
 
        /*
         *      The format is very specific.
         */
        if (vp->length != 17 + 34) {
-               DEBUG2("  rlm_eap: Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
+               RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
                       vp->length, 17 + 34);
                return RLM_MODULE_NOOP;
        }
@@ -577,8 +702,8 @@ static int eap_post_proxy(void *inst, REQUEST *request)
         *      Decrypt the session key, using the proxy data.
         */
        i = 34;                 /* starts off with 34 octets */
-       len = rad_tunnel_pwdecode(vp->strvalue + 17, &i,
-                                 request->proxysecret,
+       len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i,
+                                 request->home_server->secret,
                                  request->proxy->vector);
 
        /*
@@ -588,23 +713,24 @@ static int eap_post_proxy(void *inst, REQUEST *request)
        /*
         *      Encrypt the session key again, using the request data.
         */
-       rad_tunnel_pwencode(vp->strvalue + 17, &len,
-                           request->secret,
+       rad_tunnel_pwencode(vp->vp_strvalue + 17, &len,
+                           request->client->secret,
                            request->packet->vector);
 
        return RLM_MODULE_UPDATED;
 }
-
+#endif
 
 /*
  *     The module name should be the only globally exported symbol.
  *     That is, everything else should be 'static'.
  */
 module_t rlm_eap = {
+       RLM_MODULE_INIT,
        "eap",
-       RLM_TYPE_THREAD_SAFE,           /* type */
-       eap_init,                       /* initialization */
+       RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
        eap_instantiate,                /* instantiation */
+       eap_detach,                     /* detach */
        {
                eap_authenticate,       /* authentication */
                eap_authorize,          /* authorization */
@@ -612,9 +738,11 @@ module_t rlm_eap = {
                NULL,                   /* accounting */
                NULL,                   /* checksimul */
                NULL,                   /* pre-proxy */
+#ifdef WITH_PROXY
                eap_post_proxy,         /* post-proxy */
+#else
+               NULL,
+#endif
                NULL                    /* post-auth */
        },
-       eap_detach,                     /* detach */
-       NULL,                           /* destroy */
 };