Fixes from clang / scan-build
[freeradius.git] / src / modules / rlm_eap / rlm_eap.c
index 9f4627d..e6399ba 100644 (file)
@@ -39,6 +39,8 @@ static const CONF_PARSER module_config[] = {
          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 */
 };
@@ -54,6 +56,7 @@ 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);
 
@@ -63,6 +66,7 @@ static int eap_detach(void *instance)
        }
 
        pthread_mutex_destroy(&(inst->session_mutex));
+       if (fr_debug_flag) pthread_mutex_destroy(&(inst->handler_mutex));
 
        free(inst);
 
@@ -79,15 +83,32 @@ static int eap_handler_cmp(const void *a, const void *b)
        const EAP_HANDLER *one = a;
        const EAP_HANDLER *two = b;
 
-#if 0
        if (one->eap_id < two->eap_id) return -1;
        if (one->eap_id > two->eap_id) return +1;
-#endif
 
-       rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr);
+       rcode = memcmp(one->state, two->state, sizeof(one->state));
        if (rcode != 0) return rcode;
 
-       return memcmp(one->state, two->state, sizeof(one->state));
+       /*
+        *      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));
 }
 
 
@@ -118,6 +139,10 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
                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;
@@ -133,7 +158,7 @@ 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;
@@ -155,7 +180,7 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
                if ((eap_type == PW_EAP_TLS) ||
                    (eap_type == PW_EAP_TTLS) ||
                    (eap_type == PW_EAP_PEAP)) {
-                       DEBUG2("rlm_eap: Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type);
+                       DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type);
                        continue;
                }
 #endif
@@ -224,7 +249,26 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
                return -1;
        }
 
-       pthread_mutex_init(&(inst->session_mutex), NULL);
+       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;
+       }
 
        *instance = inst;
        return 0;
@@ -243,12 +287,17 @@ static int eap_authenticate(void *instance, REQUEST *request)
 
        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_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;
        }
 
@@ -259,7 +308,7 @@ 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;
        }
 
@@ -274,16 +323,17 @@ static int eap_authenticate(void *instance, REQUEST *request)
         */
        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) {
-               DEBUG2("  Not-EAP proxy set.  Not composing EAP");
+               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
@@ -297,8 +347,9 @@ static int eap_authenticate(void *instance, REQUEST *request)
 
                return RLM_MODULE_HANDLED;
        }
+#endif
 
-
+#ifdef WITH_PROXY
        /*
         *      Maybe the request was marked to be proxied.  If so,
         *      proxy it.
@@ -323,9 +374,9 @@ static int eap_authenticate(void *instance, REQUEST *request)
                 *      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);
@@ -339,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);
 
-               DEBUG2("  Tunneled session will be proxied.  Not doing EAP.");
+               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
@@ -355,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,
@@ -368,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);
        }
 
        /*
@@ -393,10 +457,13 @@ 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->vp_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);
                }
@@ -428,12 +495,14 @@ static int eap_authorize(void *instance, REQUEST *request)
 
        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
@@ -468,14 +537,18 @@ 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->vp_integer != PW_AUTHTYPE_REJECT)) {
-               vp = pairmake("Auth-Type", "EAP", T_OP_EQ);
+               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;
@@ -483,6 +556,8 @@ static int eap_authorize(void *instance, REQUEST *request)
        return RLM_MODULE_UPDATED;
 }
 
+
+#ifdef WITH_PROXY
 /*
  *     If we're proxying EAP, then there may be magic we need
  *     to do.
@@ -495,6 +570,11 @@ static int eap_post_proxy(void *inst, REQUEST *request)
        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...
         */
@@ -510,19 +590,21 @@ 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) {
+                       RDEBUG2("Failed in post-proxy callback");
                        eap_fail(handler);
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                        return RLM_MODULE_REJECT;
                }
 
@@ -530,7 +612,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                 *      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
@@ -538,12 +620,16 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                 */
                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);
                }
 
                /*
@@ -556,7 +642,7 @@ 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->vp_strvalue,
                                              T_OP_EQ);
@@ -566,9 +652,10 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                }
 
                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.
@@ -582,7 +669,7 @@ 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;
                }
@@ -606,7 +693,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
         *      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;
        }
@@ -632,7 +719,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
 
        return RLM_MODULE_UPDATED;
 }
-
+#endif
 
 /*
  *     The module name should be the only globally exported symbol.
@@ -651,7 +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 */
        },
 };