Print out WARNING if EAP session did not finish.
authorAlan T. DeKok <aland@freeradius.org>
Mon, 9 Aug 2010 12:04:13 +0000 (14:04 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 9 Aug 2010 12:06:57 +0000 (14:06 +0200)
This functionality has been sorely needed for some time.  It works
ONLY in debugging mode.  It prints out a warning if the handler still
exists when the request packet is cleaned up.

src/modules/rlm_eap/eap.c
src/modules/rlm_eap/eap.h
src/modules/rlm_eap/libeap/eap_tls.c
src/modules/rlm_eap/mem.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/rlm_eap.h
src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c

index bfbc550..4ce74d0 100644 (file)
@@ -1051,7 +1051,7 @@ EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
                        }
               }
        } else {                /* packet was EAP identity */
-               handler = eap_handler_alloc();
+               handler = eap_handler_alloc(inst);
                if (handler == NULL) {
                        RDEBUG("Out of memory.");
                        free(*eap_packet_p);
@@ -1067,7 +1067,7 @@ EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
                        RDEBUG("Identity Unknown, authentication failed");
                        free(*eap_packet_p);
                        *eap_packet_p = NULL;
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                        return NULL;
                }
 
@@ -1086,7 +1086,7 @@ EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
                                RDEBUG("Out of memory");
                                free(*eap_packet_p);
                                *eap_packet_p = NULL;
-                              eap_handler_free(handler);
+                              eap_handler_free(inst, handler);
                                return NULL;
                        }
                        vp->next = request->packet->vps;
@@ -1103,7 +1103,7 @@ EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
                                RDEBUG("Identity does not match User-Name, setting from EAP Identity.");
                                free(*eap_packet_p);
                                *eap_packet_p = NULL;
-                               eap_handler_free(handler);
+                               eap_handler_free(inst, handler);
                                return NULL;
                        }
               }
@@ -1113,7 +1113,7 @@ EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
        if (handler->eap_ds == NULL) {
                free(*eap_packet_p);
                *eap_packet_p = NULL;
-               eap_handler_free(handler);
+               eap_handler_free(inst, handler);
                return NULL;
        }
 
index 6f2943b..b8774d6 100644 (file)
@@ -113,6 +113,9 @@ typedef struct _eap_handler {
        int             stage;
 
        int             trips;
+
+       int             tls;
+       int             finished;
 } EAP_HANDLER;
 
 /*
index 6983713..2152352 100644 (file)
@@ -109,6 +109,7 @@ int eaptls_success(EAP_HANDLER *handler, int peap_flag)
        REQUEST *request = handler->request;
        tls_session_t *tls_session = handler->opaque;
 
+       handler->finished = TRUE;
        reply.code = EAPTLS_SUCCESS;
        reply.length = TLS_HEADER_LEN;
        reply.flags = peap_flag;
@@ -209,6 +210,7 @@ int eaptls_fail(EAP_HANDLER *handler, int peap_flag)
        EAPTLS_PACKET   reply;
        tls_session_t *tls_session = handler->opaque;
 
+       handler->finished = TRUE;
        reply.code = EAPTLS_FAIL;
        reply.length = TLS_HEADER_LEN;
        reply.flags = peap_flag;
index 4f1c3fd..f782d2f 100644 (file)
@@ -112,20 +112,33 @@ void eap_ds_free(EAP_DS **eap_ds_p)
 /*
  * Allocate a new EAP_HANDLER
  */
-EAP_HANDLER *eap_handler_alloc(void)
+EAP_HANDLER *eap_handler_alloc(rlm_eap_t *inst)
 {
        EAP_HANDLER     *handler;
 
        handler = rad_malloc(sizeof(EAP_HANDLER));
        memset(handler, 0, sizeof(EAP_HANDLER));
+
+       if (fr_debug_flag && inst->handler_tree) {
+               pthread_mutex_lock(&(inst->session_mutex));
+               rbtree_insert(inst->handler_tree, handler);
+               pthread_mutex_unlock(&(inst->session_mutex));
+       
+       }
        return handler;
 }
 
-void eap_handler_free(EAP_HANDLER *handler)
+void eap_handler_free(rlm_eap_t *inst, EAP_HANDLER *handler)
 {
        if (!handler)
                return;
 
+       if (inst->handler_tree) {
+               pthread_mutex_lock(&(inst->session_mutex));
+               rbtree_deletebydata(inst->handler_tree, handler);
+               pthread_mutex_unlock(&(inst->session_mutex));
+       }
+
        if (handler->identity) {
                free(handler->identity);
                handler->identity = NULL;
@@ -147,6 +160,49 @@ void eap_handler_free(EAP_HANDLER *handler)
        free(handler);
 }
 
+
+typedef struct check_handler_t {
+       rlm_eap_t       *inst;
+       EAP_HANDLER     *handler;
+       int             trips;
+} check_handler_t;
+
+static void check_handler(void *data)
+{
+       check_handler_t *check = data;
+
+       if (!check) return;
+       if (!check->inst || !check->handler) {
+               free(check);
+               return;
+       }
+
+       pthread_mutex_lock(&(check->inst->session_mutex));
+       if (!rbtree_finddata(check->inst->handler_tree, check->handler)) {
+               goto done;
+       }
+
+       if (check->handler->trips > check->trips) {
+               goto done;
+       }
+
+       if (check->handler->tls && !check->handler->finished) {
+               DEBUG("WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+               DEBUG("WARNING: !! EAP session for state 0x%02x%02x%02x%02x%02x%02x%02x%02x did not finish!",
+                     check->handler->state[0], check->handler->state[1],
+                     check->handler->state[2], check->handler->state[3],
+                     check->handler->state[4], check->handler->state[5],
+                     check->handler->state[6], check->handler->state[7]);
+
+               DEBUG("WARNING: !! Please read http://wiki.freeradius.org/Certificate_Compatibility");
+               DEBUG("WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+       }
+
+done:
+       pthread_mutex_unlock(&(check->inst->session_mutex));
+       free(check);
+}
+
 void eaptype_free(EAP_TYPES *i)
 {
        if (i->type->detach) (i->type->detach)(i->type_data);
@@ -162,7 +218,7 @@ void eaplist_free(rlm_eap_t *inst)
 
                for (node = inst->session_head; node != NULL; node = next) {
                next = node->next;
-               eap_handler_free(node);
+               eap_handler_free(inst, node);
        }
 
        inst->session_head = inst->session_tail = NULL;
@@ -184,6 +240,7 @@ static uint32_t eap_rand(fr_randctx *ctx)
        return num;
 }
 
+
 static EAP_HANDLER *eaplist_delete(rlm_eap_t *inst, EAP_HANDLER *handler)
 {
        rbnode_t *node;
@@ -253,7 +310,7 @@ static void eaplist_expire(rlm_eap_t *inst, time_t timestamp)
                                inst->session_head = NULL;
                                inst->session_tail = NULL;
                        }
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                }
        }
 }
@@ -343,6 +400,18 @@ int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
         */
        status = rbtree_insert(inst->session_tree, handler);
 
+       /*
+        *      Catch Access-Challenge without response.
+        */
+       if (fr_debug_flag) {
+               check_handler_t *check = rad_malloc(sizeof(*check));
+
+               check->inst = inst;
+               check->handler = handler;
+               check->trips = handler->trips;
+               request_data_add(request, inst, 0, check, check_handler);
+       }
+
        if (status) {
                EAP_HANDLER *prev;
 
@@ -443,7 +512,7 @@ EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request,
 
        if (handler->trips >= 50) {
                RDEBUG2("More than 50 authentication packets for this EAP session.  Aborted.");
-               eap_handler_free(handler);
+               eap_handler_free(inst, handler);
                return NULL;
        }
        handler->trips++;
index 974fd0b..7424a52 100644 (file)
@@ -56,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);
 
@@ -102,6 +103,15 @@ static int eap_handler_cmp(const void *a, const void *b)
 
 
 /*
+ *     Compare two handler pointers
+ */
+static int eap_handler_ptr_cmp(const void *a, const void *b)
+{
+  return (a - b);
+}
+
+
+/*
  * read the config section and load all the eap authentication types present.
  */
 static int eap_instantiate(CONF_SECTION *cs, void **instance)
@@ -238,6 +248,15 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance)
                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;
+               }
+       }
+
        pthread_mutex_init(&(inst->session_mutex), NULL);
 
        *instance = inst;
@@ -293,7 +312,7 @@ static int eap_authenticate(void *instance, REQUEST *request)
         */
        if (rcode == EAP_INVALID) {
                eap_fail(handler);
-               eap_handler_free(handler);
+               eap_handler_free(inst, handler);
                RDEBUG2("Failed in EAP select");
                return RLM_MODULE_INVALID;
        }
@@ -405,14 +424,14 @@ static int eap_authenticate(void *instance, REQUEST *request)
                 */
                if (!eaplist_add(inst, handler)) {
                        eap_fail(handler);
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                        return RLM_MODULE_FAIL;
                }
 
        } else {
                RDEBUG2("Freeing handler");
                /* handler is not required any more, free it now */
-               eap_handler_free(handler);
+               eap_handler_free(inst, handler);
        }
 
        /*
@@ -561,7 +580,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                                                              REQUEST_DATA_EAP_TUNNEL_CALLBACK);
                if (!data) {
                        radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!");
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                        return RLM_MODULE_FAIL;
                }
 
@@ -574,7 +593,7 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                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;
                }
 
@@ -592,14 +611,14 @@ static int eap_post_proxy(void *inst, REQUEST *request)
                    (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
                        if (!eaplist_add(inst, handler)) {
                                eap_fail(handler);
-                               eap_handler_free(handler);
+                               eap_handler_free(inst, 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(handler);
+                       eap_handler_free(inst, handler);
                }
 
                /*
index f005231..4802db7 100644 (file)
@@ -51,6 +51,7 @@ typedef struct eap_types_t {
 typedef struct rlm_eap_t {
        rbtree_t        *session_tree;
        EAP_HANDLER     *session_head, *session_tail;
+       rbtree_t        *handler_tree; /* for debugging only */
        EAP_TYPES       *types[PW_EAP_MAX_TYPES + 1];
 
        /*
@@ -100,10 +101,10 @@ EAP_HANDLER       *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_msg, REQUEST *requ
 /* Memory Management */
 EAP_PACKET     *eap_packet_alloc(void);
 EAP_DS         *eap_ds_alloc(void);
-EAP_HANDLER    *eap_handler_alloc(void);
+EAP_HANDLER    *eap_handler_alloc(rlm_eap_t *inst);
 void           eap_packet_free(EAP_PACKET **eap_packet);
 void           eap_ds_free(EAP_DS **eap_ds);
-void           eap_handler_free(EAP_HANDLER *handler);
+void           eap_handler_free(rlm_eap_t *inst, EAP_HANDLER *handler);
 
 int            eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler);
 EAP_HANDLER    *eaplist_find(rlm_eap_t *inst, REQUEST *request,
index 11ed96a..5b624ee 100644 (file)
@@ -851,6 +851,9 @@ static int eaptls_initiate(void *type_arg, EAP_HANDLER *handler)
 
        inst = (eap_tls_t *)type_arg;
 
+       handler->tls = TRUE;
+       handler->finished = FALSE;
+
        /*
         *      Manually flush the sessions every so often.  If HALF
         *      of the session lifetime has passed since we last