}
}
} 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);
RDEBUG("Identity Unknown, authentication failed");
free(*eap_packet_p);
*eap_packet_p = NULL;
- eap_handler_free(handler);
+ eap_handler_free(inst, handler);
return NULL;
}
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;
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;
}
}
if (handler->eap_ds == NULL) {
free(*eap_packet_p);
*eap_packet_p = NULL;
- eap_handler_free(handler);
+ eap_handler_free(inst, handler);
return NULL;
}
int stage;
int trips;
+
+ int tls;
+ int finished;
} EAP_HANDLER;
/*
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;
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;
/*
* 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;
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);
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;
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++;
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);
/*
+ * 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)
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;
*/
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;
}
*/
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);
}
/*
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;
}
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;
}
(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);
}
/*
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];
/*
/* 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,
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