/*
* 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;
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);
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;
return num;
}
+
static EAP_HANDLER *eaplist_delete(rlm_eap_t *inst, EAP_HANDLER *handler)
{
rbnode_t *node;
* 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);
inst->session_head = NULL;
inst->session_tail = NULL;
}
- eap_handler_free(handler);
+ eap_handler_free(inst, 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;
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++;