📄 rlm_eap2.c
字号:
/* * rlm_eap.c contains handles that are called from modules. * * Version: $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2007 Alan DeKok <aland@deployingradius.com> */#include <freeradius-devel/ident.h>RCSID("$Id$")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/rad_assert.h>/* * Hostap includes. */#include <utils/includes.h>#include <utils/common.h>#include <eap_server/eap.h>#include <crypto/tls.h>struct eap_server_ctx { struct eap_eapol_interface *eap_if; struct eap_sm *eap; void *tls_ctx;};#define EAP_STATE_LEN (AUTH_VECTOR_LEN)typedef struct EAP_HANDLER { struct EAP_HANDLER *prev, *next; uint8_t state[EAP_STATE_LEN]; fr_ipaddr_t src_ipaddr; time_t timestamp; REQUEST *request; struct rlm_eap_t *inst; struct eapol_callbacks eap_cb; struct eap_config eap_conf; struct eap_server_ctx server_ctx;} EAP_HANDLER;typedef struct rlm_eap_t { rbtree_t *session_tree; EAP_HANDLER *session_head, *session_tail; /* * Configuration items. */ int timer_limit; int cisco_accounting_username_bug; struct tls_connection_params tparams; int num_types; EapType methods[EAP_MAX_METHODS]; int vendors[EAP_MAX_METHODS];#ifdef HAVE_PTHREAD_H pthread_mutex_t session_mutex;#endif fr_randctx rand_pool; void *tls_ctx;} rlm_eap_t;static void eap_handler_free(EAP_HANDLER *handler){ eap_server_sm_deinit(handler->server_ctx.eap); free(handler);}static void eaplist_free(rlm_eap_t *inst){ EAP_HANDLER *node, *next; for (node = inst->session_head; node != NULL; node = next) { next = node->next; eap_handler_free(node); } inst->session_head = inst->session_tail = NULL;}/* * Return a 32-bit random number. */static uint32_t eap_rand(fr_randctx *ctx){ uint32_t num; num = ctx->randrsl[ctx->randcnt++]; if (ctx->randcnt == 256) { ctx->randcnt = 0; fr_isaac(ctx); } return num;}/* * Add a handler to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */static int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler){ int i, status; uint32_t lvalue; VALUE_PAIR *state; rad_assert(handler != NULL); rad_assert(handler->request != NULL); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake("State", "0x00", T_OP_EQ); if (!state) return 0; pairadd(&(handler->request->reply->vps), state); state->length = EAP_STATE_LEN; /* * 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->src_ipaddr = handler->request->packet->src_ipaddr; /* * 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. */ pthread_mutex_lock(&(inst->session_mutex)); /* * Create a completely random state. */ for (i = 0; i < 4; i++) { lvalue = eap_rand(&inst->rand_pool); memcpy(state->vp_octets + i * 4, &lvalue, sizeof(lvalue)); } memcpy(handler->state, state->vp_strvalue, sizeof(handler->state)); /* * Big-time failure. */ status = rbtree_insert(inst->session_tree, handler); if (status) { EAP_HANDLER *prev; prev = inst->session_tail; if (prev) { prev->next = handler; handler->prev = prev; handler->next = NULL; inst->session_tail = handler; } else { inst->session_head = inst->session_tail = handler; handler->next = handler->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ pthread_mutex_unlock(&(inst->session_mutex)); if (!status) { radlog(L_ERR, "rlm_eap2: Failed to remember handler!"); eap_handler_free(handler); return 0; } return 1;}/* * Find a a previous EAP-Request sent by us, which matches * the current EAP-Response. * * Then, release the handle from the list, and return it to * the caller. * * Also since we fill the eap_ds with the present EAP-Response we * got to free the prev_eapds & move the eap_ds to prev_eapds */static EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request){ int i; VALUE_PAIR *state; rbnode_t *node; EAP_HANDLER *handler, myHandler; /* * We key the sessions off of the 'state' attribute, so it * must exist. */ state = pairfind(request->packet->vps, PW_STATE); if (!state || (state->length != EAP_STATE_LEN)) { return NULL; } myHandler.src_ipaddr = request->packet->src_ipaddr; memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state)); /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ pthread_mutex_lock(&(inst->session_mutex)); /* * Check the first few handlers in the list, and delete * them if they're too old. We don't need to check them * all, as incoming requests will quickly cause older * handlers to be deleted. * */ for (i = 0; i < 2; i++) { handler = inst->session_head; if (handler && ((request->timestamp - handler->timestamp) > inst->timer_limit)) { node = rbtree_find(inst->session_tree, handler); rad_assert(node != NULL); rbtree_delete(inst->session_tree, node); /* * handler == inst->session_head */ inst->session_head = handler->next; if (handler->next) { handler->next->prev = NULL; } else { inst->session_head = NULL; } eap_handler_free(handler); } } handler = NULL; node = rbtree_find(inst->session_tree, &myHandler); if (node) { handler = rbtree_node2data(inst->session_tree, node); /* * Delete old handler from the tree. */ rbtree_delete(inst->session_tree, node); /* * And unsplice it from the linked list. */ if (handler->prev) { handler->prev->next = handler->next; } else { inst->session_head = handler->next; } if (handler->next) { handler->next->prev = handler->prev; } else { inst->session_tail = handler->prev; } handler->prev = handler->next = NULL; } pthread_mutex_unlock(&(inst->session_mutex)); /* * Not found. */ if (!node) { RDEBUG2("Request not found in the list"); return NULL; } /* * Found, but state verification failed. */ if (!handler) { radlog(L_ERR, "rlm_eap2: State verification failed."); return NULL; } RDEBUG2("Request found, released from the list"); return handler;}/* * delete all the allocated space by eap module */static int eap_detach(void *instance){ rlm_eap_t *inst; inst = (rlm_eap_t *)instance; rbtree_free(inst->session_tree); inst->session_tree = NULL; eaplist_free(inst); eap_server_unregister_methods(); tls_deinit(inst->tls_ctx); pthread_mutex_destroy(&(inst->session_mutex)); free(inst); return 0;}/* * Compare two handlers. */static int eap_handler_cmp(const void *a, const void *b){ int rcode; const EAP_HANDLER *one = a; const EAP_HANDLER *two = b; rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr); if (rcode != 0) return rcode; return memcmp(one->state, two->state, sizeof(one->state));}static int server_get_eap_user(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user){ int i; VALUE_PAIR *vp; EAP_HANDLER *handler = ctx; REQUEST *request = handler->request; os_memset(user, 0, sizeof(*user)); /* * FIXME: Run through "authorise" again to look up * password for the given identity */ identity = identity; /* -Wunused */ identity_len = identity_len; /* -Wunused */ /* * Do this always, just in case. */ vp = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD); if (vp) { user->password = (u8 *) os_strdup(vp->vp_strvalue); user->password_len = vp->length; } if (!vp) vp = pairfind(request->config_items, PW_NT_PASSWORD); if (vp) { user->password = (u8 *) malloc(vp->length); memcpy(user->password, vp->vp_octets, vp->length); user->password_len = vp->length; } if (!phase2) { for (i = 0; i < handler->inst->num_types; i++) { user->methods[i].vendor = handler->inst->vendors[i]; user->methods[i].method = handler->inst->methods[i]; } return 0; } /* * FIXME: run tunneled sessions through the tunneled portion... */ /* * FIXME: Selectively control tunneled EAP types. */ user->methods[0].vendor = EAP_VENDOR_IETF; user->methods[0].method = EAP_TYPE_MD5; user->methods[1].vendor = EAP_VENDOR_IETF; user->methods[1].method = EAP_TYPE_MSCHAPV2; /* * No password configured... */ return 0;}static const char * server_get_eap_req_id_text(void *ctx, size_t *len){ ctx = ctx; /* -Wunused */ *len = 0; return NULL;}static CONF_PARSER tls_config[] = { /* * TLS parameters. */ { "ca_cert", PW_TYPE_STRING_PTR, offsetof(rlm_eap_t, tparams.ca_cert), NULL, "${confdir}/certs/ca.pem" }, { "server_cert", PW_TYPE_STRING_PTR, offsetof(rlm_eap_t, tparams.client_cert), NULL, "${confdir}/certs/server.pem" }, { "private_key_file", PW_TYPE_STRING_PTR, offsetof(rlm_eap_t, tparams.private_key), NULL, "${confdir}/certs/server.pem" }, { "private_key_password", PW_TYPE_STRING_PTR, offsetof(rlm_eap_t, tparams.private_key_passwd), NULL, "whatever" }, { NULL, -1, 0, NULL, NULL } /* end the list */};static const CONF_PARSER module_config[] = { { "timer_expire", PW_TYPE_INTEGER, offsetof(rlm_eap_t, timer_limit), NULL, "60"}, { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN, offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" }, { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config }, { NULL, -1, 0, NULL, NULL } /* end the list */};static int eap_example_server_init_tls(rlm_eap_t *inst){ struct tls_config tconf; os_memset(&tconf, 0, sizeof(tconf)); inst->tls_ctx = tls_init(&tconf); if (inst->tls_ctx == NULL) return -1; if (tls_global_set_params(inst->tls_ctx, &inst->tparams)) { radlog(L_ERR, "rlm_eap2: Failed to set TLS parameters"); return -1; } if (tls_global_set_verify(inst->tls_ctx, 0)) { radlog(L_ERR, "rlm_eap2: Failed to set check_crl"); return -1; } return 0;}/* * read the config section and load all the eap authentication types present. */static int eap_instantiate(CONF_SECTION *cs, void **instance){ int i, num_types; int has_tls, do_tls; rlm_eap_t *inst;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -