Added support for TLS-Cert-* and TLS-Client-Cert-* attributes
[freeradius.git] / src / modules / rlm_eap / mem.c
index e9a049c..5bdf633 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;
@@ -144,9 +157,54 @@ 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)
+{
+       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 +220,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 +242,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 +288,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);
@@ -246,8 +310,9 @@ static void eaplist_expire(rlm_eap_t *inst, time_t timestamp)
                                handler->next->prev = NULL;
                        } else {
                                inst->session_head = NULL;
+                               inst->session_tail = NULL;
                        }
-                       eap_handler_free(handler);
+                       eap_handler_free(inst, handler);
                }
        }
 }
@@ -294,6 +359,7 @@ int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
         *      If we have a DoS attack, discard new sessions.
         */
        if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) {
+               status = -1;
                eaplist_expire(inst, handler->timestamp);
                goto done;
        }
@@ -336,6 +402,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;
 
@@ -360,13 +438,23 @@ int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
        /*
         *      We don't need this any more.
         */
-       if (status) handler->request = NULL;
+       if (status > 0) handler->request = NULL;
 
        pthread_mutex_unlock(&(inst->session_mutex));
 
-       if (!status) {
+       if (status <= 0) {
                pairfree(&state);
-               radlog(L_ERR, "rlm_eap: Failed to store handler");
+
+               if (status < 0) {
+                       static time_t last_logged = 0;
+
+                       if (last_logged < handler->timestamp) {
+                               last_logged = handler->timestamp;
+                               radlog(L_ERR, "rlm_eap: Too many open sessions.  Try increasing \"max_sessions\" in the EAP module configuration");
+                       }                                      
+               } else {
+                       radlog(L_ERR, "rlm_eap: Internal error: failed to store handler");
+               }
                return 0;
        }
 
@@ -395,7 +483,7 @@ EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request,
         *      We key the sessions off of the 'state' attribute, so it
         *      must exist.
         */
-       state = pairfind(request->packet->vps, PW_STATE);
+       state = pairfind(request->packet->vps, PW_STATE, 0);
        if (!state ||
            (state->length != EAP_STATE_LEN)) {
                return NULL;
@@ -425,13 +513,13 @@ EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request,
        }
 
        if (handler->trips >= 50) {
-               DEBUG2("  rlm_eap: More than 50 authentication packets for this EAP session.  Aborted.");
-               eap_handler_free(handler);
+               RDEBUG2("More than 50 authentication packets for this EAP session.  Aborted.");
+               eap_handler_free(inst, handler);
                return NULL;
        }
        handler->trips++;
 
-       DEBUG2("  rlm_eap: Request found, released from the list");
+       RDEBUG2("Request found, released from the list");
 
        /*
         *      Remember what the previous request was.