Same fix for eap session and handler trees
[freeradius.git] / src / modules / rlm_eap / rlm_eap.c
index f506739..b3ff531 100644 (file)
@@ -30,18 +30,13 @@ RCSID("$Id$")
 #include "rlm_eap.h"
 
 static const CONF_PARSER module_config[] = {
-       { "default_eap_type", PW_TYPE_STRING_PTR,
-         offsetof(rlm_eap_t, default_method_name), NULL, "md5" },
-       { "timer_expire", PW_TYPE_INTEGER,
-         offsetof(rlm_eap_t, timer_limit), NULL, "60"},
-       { "ignore_unknown_eap_types", PW_TYPE_BOOLEAN,
-         offsetof(rlm_eap_t, ignore_unknown_types), NULL, "no" },
-       { "mod_accounting_username_bug", PW_TYPE_BOOLEAN,
-         offsetof(rlm_eap_t, mod_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 */
+       { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_t, default_method_name), "md5" },
+       { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, timer_limit), "60" },
+       { "ignore_unknown_eap_types", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, ignore_unknown_types), "no" },
+       { "mod_accounting_username_bug", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, mod_accounting_username_bug), "no" },
+       { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, max_sessions), "2048" },
+
+       { NULL, -1, 0, NULL, NULL }        /* end the list */
 };
 
 /*
@@ -59,7 +54,14 @@ static int mod_detach(void *instance)
 #endif
 
        rbtree_free(inst->session_tree);
-       if (inst->handler_tree) rbtree_free(inst->handler_tree);
+       if (inst->handler_tree) {
+               rbtree_free(inst->handler_tree);
+               /*
+                *  Must be NULL else when nodes are freed they try to
+                *  delete themselves from the tree.
+                */
+               inst->handler_tree = NULL;
+       }
        inst->session_tree = NULL;
        eaplist_free(inst);
 
@@ -73,8 +75,8 @@ static int mod_detach(void *instance)
 static int eap_handler_cmp(void const *a, void const *b)
 {
        int rcode;
-       const eap_handler_t *one = a;
-       const eap_handler_t *two = b;
+       eap_handler_t const *one = a;
+       eap_handler_t const *two = b;
 
        if (one->eap_id < two->eap_id) return -1;
        if (one->eap_id > two->eap_id) return +1;
@@ -89,7 +91,7 @@ static int eap_handler_cmp(void const *a, void const *b)
         *      EAP work.
         */
        if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) {
-               WDEBUG("EAP packets are arriving from two different upstream "
+               WARN("EAP packets are arriving from two different upstream "
                       "servers.  Has there been a proxy fail-over?");
        }
 
@@ -146,10 +148,10 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
 
                method = eap_name2type(name);
                if (method == PW_EAP_INVALID) {
-                       cf_log_err_cs(cs, "Unknown EAP method %s", name);
+                       cf_log_err_cs(cs, "No dictionary definition for EAP method %s", name);
                        return -1;
                }
-               
+
                if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) {
                        cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name);
                        return -1;
@@ -181,9 +183,9 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
                 *      Load the type.
                 */
                ret = eap_module_load(inst, &inst->methods[method], method, scs);
-               
+
                (void) talloc_get_type_abort(inst->methods[method], eap_module_t);
-               
+
                if (ret < 0) {
                        (void) talloc_steal(inst, inst->methods[method]);
                        return -1;
@@ -203,7 +205,7 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
         */
        method = eap_name2type(inst->default_method_name);
        if (method == PW_EAP_INVALID) {
-               cf_log_err_cs(cs, "Unknown default EAP method '%s'",
+               cf_log_err_cs(cs, "No dictionary definition for default EAP method '%s'",
                       inst->default_method_name);
                return -1;
        }
@@ -224,22 +226,24 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
         *      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);
+       inst->session_tree = rbtree_create(NULL, eap_handler_cmp, NULL, 0);
        if (!inst->session_tree) {
                ERROR("rlm_eap (%s): Cannot initialize tree", inst->xlat_name);
                return -1;
        }
+       fr_link_talloc_ctx_free(inst, inst->session_tree);
 
        if (fr_debug_flag) {
-               inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0);
+               inst->handler_tree = rbtree_create(NULL, eap_handler_ptr_cmp, NULL, 0);
                if (!inst->handler_tree) {
                        ERROR("rlm_eap (%s): Cannot initialize tree", inst->xlat_name);
                        return -1;
                }
+               fr_link_talloc_ctx_free(inst, inst->handler_tree);
 
 #ifdef HAVE_PTHREAD_H
                if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) {
-                       ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
+                       ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno));
                        return -1;
                }
 #endif
@@ -247,7 +251,7 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
 
 #ifdef HAVE_PTHREAD_H
        if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
-               ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
+               ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno));
                return -1;
        }
 #endif
@@ -259,7 +263,7 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
 /*
  *     For backwards compatibility.
  */
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
 {
        rlm_eap_t               *inst;
        eap_handler_t           *handler;
@@ -306,7 +310,7 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
         */
        if (status == EAP_INVALID) {
                eap_fail(handler);
-               eap_handler_free(inst, handler);
+               talloc_free(handler);
                RDEBUG2("Failed in EAP select");
                return RLM_MODULE_INVALID;
        }
@@ -315,17 +319,16 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
        /*
         *      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");
+       if ((request->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+               RDEBUG2("No 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.
                 */
                handler->inst_holder = inst;
-               status = request_data_add(request,
-                                         inst, REQUEST_DATA_eap_handler_t,
-                                         handler, (void *) eap_opaque_free);
+               status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true);
+
                rad_assert(status == 0);
                return RLM_MODULE_HANDLED;
        }
@@ -347,10 +350,9 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
                 *      send a response.
                 */
                handler->inst_holder = inst;
-               status = request_data_add(request,
-                                         inst, REQUEST_DATA_eap_handler_t,
-                                         handler,
-                                         (void *) eap_opaque_free);
+
+               status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true);
+
                rad_assert(status == 0);
 
                /*
@@ -375,7 +377,7 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
                 */
                pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY);
 
-               RDEBUG2("  Tunneled session will be proxied.  Not doing EAP.");
+               RDEBUG2("Tunneled session will be proxied.  Not doing EAP");
                return RLM_MODULE_HANDLED;
        }
 #endif
@@ -419,14 +421,14 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
                if (!eaplist_add(inst, handler)) {
                        RDEBUG("Failed adding handler to the list");
                        eap_fail(handler);
-                       eap_handler_free(inst, handler);
+                       talloc_free(handler);
                        return RLM_MODULE_FAIL;
                }
 
        } else {
                RDEBUG2("Freeing handler");
                /* handler is not required any more, free it now */
-               eap_handler_free(inst, handler);
+               talloc_free(handler);
        }
 
        /*
@@ -434,7 +436,7 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
         *      says that we MUST include a User-Name attribute in the
         *      Access-Accept.
         */
-       if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
+       if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) &&
            request->username) {
                VALUE_PAIR *vp;
 
@@ -450,15 +452,16 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
                /*
                 *      Cisco AP1230 has a bug and needs a zero
                 *      terminated string in Access-Accept.
-                *
-                *      @todo: fix this
                 */
-               if ((inst->mod_accounting_username_bug) &&
-                   (vp->length < (int) sizeof(vp->vp_strvalue))) {
-#if 0
-                       vp->vp_strvalue[vp->length] = '\0';
+               if (inst->mod_accounting_username_bug) {
+                       char const *old = vp->vp_strvalue;
+                       char *new = talloc_zero_array(vp, char, vp->length + 1);
+
+                       memcpy(new, old, vp->length);
+                       vp->vp_strvalue = new;
                        vp->length++;
-#endif
+
+                       rad_const_free(old);
                }
        }
 
@@ -467,10 +470,10 @@ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
 
 /*
  * EAP authorization DEPENDS on other rlm authorizations,
- * to check for user existance & get their configured values.
+ * to check for user existence & get their configured values.
  * It Handles EAP-START Messages, User-Name initilization.
  */
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
 {
        rlm_eap_t       *inst;
        int             status;
@@ -542,7 +545,7 @@ static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
  *     If we're proxying EAP, then there may be magic we need
  *     to do.
  */
-static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *inst, REQUEST *request)
 {
        size_t          i;
        size_t          len;
@@ -552,15 +555,10 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
        vp_cursor_t     cursor;
 
        /*
-        *      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...
         */
-       handler = request_data_get(request, inst, REQUEST_DATA_eap_handler_t);
+       handler = request_data_get(request, inst, REQUEST_DATA_EAP_HANDLER);
        if (handler != NULL) {
                rlm_rcode_t rcode;
                eap_tunnel_data_t *data;
@@ -573,7 +571,7 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
                                                              REQUEST_DATA_EAP_TUNNEL_CALLBACK);
                if (!data) {
                        RERROR("Failed to retrieve callback for tunneled session!");
-                       eap_handler_free(inst, handler);
+                       talloc_free(handler);
                        return RLM_MODULE_FAIL;
                }
 
@@ -582,11 +580,11 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
                 */
                RDEBUG2("Doing post-proxy callback");
                rcode = data->callback(handler, data->tls_session);
-               free(data);
+               talloc_free(data);
                if (rcode == 0) {
                        RDEBUG2("Failed in post-proxy callback");
                        eap_fail(handler);
-                       eap_handler_free(inst, handler);
+                       talloc_free(handler);
                        return RLM_MODULE_REJECT;
                }
 
@@ -604,14 +602,14 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
                    (handler->eap_ds->request->type.num >= PW_EAP_MD5)) {
                        if (!eaplist_add(inst, handler)) {
                                eap_fail(handler);
-                               eap_handler_free(inst, handler);
+                               talloc_free(handler);
                                return RLM_MODULE_FAIL;
                        }
-                       
+
                } else {        /* couldn't have been LEAP, there's no tunnel */
                        RDEBUG2("Freeing handler");
                        /* handler is not required any more, free it now */
-                       eap_handler_free(inst, handler);
+                       talloc_free(handler);
                }
 
                /*
@@ -619,7 +617,7 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
                 *      says that we MUST include a User-Name attribute in the
                 *      Access-Accept.
                 */
-               if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
+               if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) &&
                    request->username) {
                        /*
                         *      Doesn't exist, add it in.
@@ -638,10 +636,15 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
        }
 
        /*
+        *      This is allowed.
+        */
+       if (!request->proxy_reply) return RLM_MODULE_NOOP;
+
+       /*
         *      There may be more than one Cisco-AVPair.
         *      Ensure we find the one with the LEAP attribute.
         */
-       paircursor(&cursor, &request->proxy_reply->vps);
+       fr_cursor_init(&cursor, &request->proxy_reply->vps);
        for (;;) {
                /*
                 *      Hmm... there's got to be a better way to
@@ -650,7 +653,7 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
                 *      This is vendor Cisco (9), Cisco-AVPair
                 *      attribute (1)
                 */
-               vp = pairfindnext(&cursor, 1, 9, TAG_ANY);
+               vp = fr_cursor_next_by_num(&cursor, 1, 9, TAG_ANY);
                if (!vp) {
                        return RLM_MODULE_NOOP;
                }
@@ -668,20 +671,22 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
        /*
         *      The format is very specific.
         */
-       if (vp->length != 17 + 34) {
-               RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
+       if (vp->length != (17 + 34)) {
+               RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %zu: Expected %d",
                       vp->length, 17 + 34);
                return RLM_MODULE_NOOP;
        }
 
        /*
         *      Decrypt the session key, using the proxy data.
+        *
+        *      Note that the session key is *binary*, and therefore
+        *      may contain embedded zeros.  So we have to use memdup.
         */
-       i = 34;                 /* starts off with 34 octets */
-       p = talloc_strdup(vp, vp->vp_strvalue);
-       len = rad_tunnel_pwdecode((uint8_t *)p + 17, &i,
-                                 request->home_server->secret,
-                                 request->proxy->vector);
+       i = 34;
+       p = talloc_memdup(vp, vp->vp_octets, vp->length);
+       talloc_set_type(p, uint8_t);
+       len = rad_tunnel_pwdecode((uint8_t *)p + 17, &i, request->home_server->secret, request->proxy->vector);
 
        /*
         *      FIXME: Assert that i == 16.
@@ -693,37 +698,36 @@ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
        rad_tunnel_pwencode(p + 17, &len,
                            request->client->secret,
                            request->packet->vector);
-//     talloc_free(vp->vp_strvalue);
-       vp->vp_strvalue = p;
+       pairstrsteal(vp, p);
 
        return RLM_MODULE_UPDATED;
 }
 #endif
 
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
 {
        rlm_eap_t       *inst = instance;
        VALUE_PAIR      *vp;
        eap_handler_t   *handler;
        eap_packet_raw_t        *eap_packet;
-       
+
        /*
         * Only build a failure message if something previously rejected the request
         */
        vp = pairfind(request->config_items, PW_POSTAUTHTYPE, 0, TAG_ANY);
 
        if (!vp || (vp->vp_integer != PW_POSTAUTHTYPE_REJECT)) return RLM_MODULE_NOOP;
-       
+
        if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
                RDEBUG2("Request didn't contain an EAP-Message, not inserting EAP-Failure");
                return RLM_MODULE_NOOP;
        }
-       
+
        if (pairfind(request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
                RDEBUG2("Reply already contained an EAP-Message, not inserting EAP-Failure");
                return RLM_MODULE_NOOP;
        }
-       
+
        eap_packet = eap_vp2packet(request, request->packet->vps);
        if (!eap_packet) {
                RERROR("Malformed EAP Message");
@@ -738,8 +742,8 @@ static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
 
        RDEBUG2("Request was previously rejected, inserting EAP-Failure");
        eap_fail(handler);
-       eap_handler_free(inst, handler);
-       
+       talloc_free(handler);
+
        /*
         * Make sure there's a message authenticator attribute in the response
         * RADIUS protocol code will calculate the correct value later...
@@ -759,7 +763,7 @@ static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
 module_t rlm_eap = {
        RLM_MODULE_INIT,
        "eap",
-       RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
+       0,      /* type */
        sizeof(rlm_eap_t),
        module_config,
        mod_instantiate,                /* instantiation */