/*
* 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;
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);
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);
handler->next->prev = NULL;
} else {
inst->session_head = NULL;
+ inst->session_tail = NULL;
}
- eap_handler_free(handler);
+ eap_handler_free(inst, handler);
}
}
}
{
int status = 0;
VALUE_PAIR *state;
+ REQUEST *request = handler->request;
rad_assert(handler != NULL);
- rad_assert(handler->request != NULL);
+ rad_assert(request != NULL);
/*
* Generate State, since we've been asked to add it to
*/
state = pairmake("State", "0x00", T_OP_EQ);
if (!state) return 0;
- pairadd(&(handler->request->reply->vps), state);
/*
* The time at which this request was made was the time
* at which it was received by the RADIUS server.
*/
- handler->timestamp = handler->request->timestamp;
+ handler->timestamp = request->timestamp;
handler->status = 1;
- handler->src_ipaddr = handler->request->packet->src_ipaddr;
+ handler->src_ipaddr = request->packet->src_ipaddr;
handler->eap_id = handler->eap_ds->request->id;
/*
- * We don't need this any more.
- */
- handler->request = NULL;
-
- /*
* Playing with a data structure shared among threads
* means that we need a lock, to avoid conflict.
*/
* 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;
}
*/
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;
* unlock it.
*/
done:
+
+ /*
+ * We don't need this any more.
+ */
+ if (status > 0) handler->request = NULL;
+
pthread_mutex_unlock(&(inst->session_mutex));
- if (!status) {
- radlog(L_ERR, "rlm_eap: Failed to store handler");
+ if (status <= 0) {
+ pairfree(&state);
+
+ 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;
}
+ pairadd(&(request->reply->vps), state);
+
return 1;
}
* 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;
}
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.