Use handler mutex for checks, not session mutex
[freeradius.git] / src / modules / rlm_eap / mem.c
index 992337f..5f6d6d8 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->handler_mutex));
+               rbtree_insert(inst->handler_tree, handler);
+               pthread_mutex_unlock(&(inst->handler_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->handler_mutex));
+               rbtree_deletebydata(inst->handler_tree, handler);
+               pthread_mutex_unlock(&(inst->handler_mutex));
+       }
+
        if (handler->identity) {
                free(handler->identity);
                handler->identity = NULL;
@@ -144,9 +157,66 @@ void eap_handler_free(EAP_HANDLER *handler)
        handler->opaque = NULL;
        handler->free_opaque = NULL;
 
+       if (handler->certs) pairfree(&handler->certs);
+
        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)
+{
+       int do_warning = FALSE;
+       uint8_t state[8];
+       check_handler_t *check = data;
+
+       if (!check) return;
+
+       if (!check->inst || !check->handler) {
+               free(check);
+               return;
+       }
+
+       pthread_mutex_lock(&(check->inst->handler_mutex));
+       if (!rbtree_finddata(check->inst->handler_tree, check->handler)) {
+               goto done;
+       }
+
+       /*
+        *      The session has continued *after* this packet.
+        *      Don't do a warning.
+        */
+       if (check->handler->trips > check->trips) {
+               goto done;
+       }
+
+       if (check->handler->tls && !check->handler->finished) {
+               do_warning = TRUE;
+               memcpy(state, check->handler->state, sizeof(state));
+       }
+
+done:
+       pthread_mutex_unlock(&(check->inst->handler_mutex));
+       free(check);
+
+       if (do_warning) {
+               DEBUG("WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+               DEBUG("WARNING: !! EAP session for state 0x%02x%02x%02x%02x%02x%02x%02x%02x did not finish!",
+                     state[0], state[1],
+                     state[2], state[3],
+                     state[4], state[5],
+                     state[6], state[7]);
+
+               DEBUG("WARNING: !! Please read http://wiki.freeradius.org/Certificate_Compatibility");
+               DEBUG("WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+       }
+}
+
 void eaptype_free(EAP_TYPES *i)
 {
        if (i->type->detach) (i->type->detach)(i->type_data);
@@ -162,7 +232,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 +254,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;
@@ -229,10 +300,15 @@ static void eaplist_expire(rlm_eap_t *inst, time_t timestamp)
         *      handlers to be deleted.
         *
         */
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < 3; i++) {
                handler = inst->session_head;
-               if (handler &&
-                   ((timestamp - handler->timestamp) > inst->timer_limit)) {
+               if (!handler) break;
+
+               /*
+                *      Expire entries from the start of the list.
+                *      They should be the oldest ones.
+                */
+               if ((timestamp - handler->timestamp) > inst->timer_limit) {
                        rbnode_t *node;
                        node = rbtree_find(inst->session_tree, handler);
                        rad_assert(node != NULL);
@@ -248,7 +324,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);
                }
        }
 }
@@ -338,6 +414,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;
 
@@ -438,7 +526,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++;