X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_eap%2Frlm_eap.c;h=e6399ba54623b593fbd697157e733956b0d25d5d;hb=94dc4bb60ec649ce899c1d5e32b575d9523a48f2;hp=4f9a848e15aecc7a1f8549ecd769d3e005161423;hpb=57dfe2c2a4090fd843662b99e21ecc0498944c80;p=freeradius.git diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c index 4f9a848..e6399ba 100644 --- a/src/modules/rlm_eap/rlm_eap.c +++ b/src/modules/rlm_eap/rlm_eap.c @@ -15,18 +15,20 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2000-2003 The FreeRADIUS server project + * Copyright 2000-2003,2006 The FreeRADIUS server project * Copyright 2001 hereUare Communications, Inc. * Copyright 2003 Alan DeKok */ -#include "autoconf.h" -#include "rlm_eap.h" -#include "modules.h" +#include +RCSID("$Id$") + +#include +#include -static const char rcsid[] = "$Id$"; +#include "rlm_eap.h" static const CONF_PARSER module_config[] = { { "default_eap_type", PW_TYPE_STRING_PTR, @@ -37,6 +39,8 @@ static const CONF_PARSER module_config[] = { offsetof(rlm_eap_t, ignore_unknown_eap_types), NULL, "no" }, { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN, offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" }, + { "max_sessions", PW_TYPE_INTEGER, + offsetof(rlm_eap_t, max_sessions), NULL, "2048"}, { NULL, -1, 0, NULL, NULL } /* end the list */ }; @@ -52,6 +56,7 @@ static int eap_detach(void *instance) 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); @@ -61,8 +66,8 @@ static int eap_detach(void *instance) } pthread_mutex_destroy(&(inst->session_mutex)); + if (fr_debug_flag) pthread_mutex_destroy(&(inst->handler_mutex)); - if (inst->default_eap_type_name) free(inst->default_eap_type_name); free(inst); return 0; @@ -74,16 +79,36 @@ static int eap_detach(void *instance) */ static int eap_handler_cmp(const void *a, const void *b) { + int rcode; const EAP_HANDLER *one = a; const EAP_HANDLER *two = b; if (one->eap_id < two->eap_id) return -1; if (one->eap_id > two->eap_id) return +1; - if (one->src_ipaddr < two->src_ipaddr) return -1; - if (one->src_ipaddr > two->src_ipaddr) return +1; + rcode = memcmp(one->state, two->state, sizeof(one->state)); + if (rcode != 0) return rcode; + + /* + * As of 2.1.8, we don't key off of source IP. This + * a NAS to send packets load-balanced (or fail-over) + * across multiple intermediate proxies, and still have + * EAP work. + */ + if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) { + DEBUG("WARNING: EAP packets are arriving from two different upstream servers. Has there been a proxy fail-over?"); + } + + return 0; +} + - return memcmp(one->state, two->state, sizeof(one->state)); +/* + * Compare two handler pointers + */ +static int eap_handler_ptr_cmp(const void *a, const void *b) +{ + return (((uint8_t *) a) - ((uint8_t *) b)); } @@ -92,7 +117,7 @@ static int eap_handler_cmp(const void *a, const void *b) */ static int eap_instantiate(CONF_SECTION *cs, void **instance) { - int eap_type; + int i, eap_type; int num_types; CONF_SECTION *scs; rlm_eap_t *inst; @@ -107,13 +132,25 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance) return -1; } + /* + * Create our own random pool. + */ + for (i = 0; i < 256; i++) { + inst->rand_pool.randrsl[i] = fr_rand(); + } + fr_randinit(&inst->rand_pool, 1); + inst->rand_pool.randcnt = 0; + + inst->xlat_name = cf_section_name2(cs); + if (!inst->xlat_name) inst->xlat_name = "EAP"; + /* Load all the configured EAP-Types */ num_types = 0; for(scs=cf_subsection_find_next(cs, NULL, NULL); scs != NULL; scs=cf_subsection_find_next(cs, scs, NULL)) { - char *auth_type; + const char *auth_type; auth_type = cf_section_name1(scs); @@ -121,12 +158,33 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance) eap_type = eaptype_name2type(auth_type); if (eap_type < 0) { - radlog(L_ERR|L_CONS, "rlm_eap: Unknown EAP type %s", + radlog(L_ERR, "rlm_eap: Unknown EAP type %s", auth_type); eap_detach(inst); return -1; } +#ifndef HAVE_OPENSSL_SSL_H + /* + * This allows the default configuration to be + * shipped with EAP-TLS, etc. enabled. If the + * system doesn't have OpenSSL, they will be + * ignored. + * + * If the system does have OpenSSL, then this + * code will not be used. The administrator will + * then have to delete the tls, + * etc. configurations from eap.conf in order to + * have EAP without the TLS types. + */ + if ((eap_type == PW_EAP_TLS) || + (eap_type == PW_EAP_TTLS) || + (eap_type == PW_EAP_PEAP)) { + DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type); + continue; + } +#endif + /* * If we're asked to load TTLS or PEAP, ensure * that we've first loaded TLS. @@ -180,9 +238,6 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance) * of 'inst', above. */ - /* Generate a state key, specific to eap */ - generate_key(); - /* * Lookup sessions in the tree. We don't free them in * the tree, as that's taken care of elsewhere... @@ -194,7 +249,26 @@ static int eap_instantiate(CONF_SECTION *cs, void **instance) return -1; } - pthread_mutex_init(&(inst->session_mutex), NULL); + 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; + } + + if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) { + radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno)); + eap_detach(inst); + return -1; + } + } + + if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) { + radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno)); + eap_detach(inst); + return -1; + } *instance = inst; return 0; @@ -213,12 +287,17 @@ static int eap_authenticate(void *instance, REQUEST *request) inst = (rlm_eap_t *) instance; + if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0)) { + RDEBUG("ERROR: You set 'Auth-Type = EAP' for a request that does not contain an EAP-Message attribute!"); + return RLM_MODULE_INVALID; + } + /* * Get the eap packet to start with */ - eap_packet = eap_attribute(request->packet->vps); + eap_packet = eap_vp2packet(request->packet->vps); if (eap_packet == NULL) { - radlog(L_ERR, "rlm_eap: Malformed EAP Message"); + radlog_request(L_ERR, 0, request, "Malformed EAP Message"); return RLM_MODULE_FAIL; } @@ -229,32 +308,11 @@ static int eap_authenticate(void *instance, REQUEST *request) */ handler = eap_handler(inst, &eap_packet, request); if (handler == NULL) { - DEBUG2(" rlm_eap: Failed in handler"); + RDEBUG2("Failed in handler"); return RLM_MODULE_INVALID; } /* - * If it's a recursive request, then disallow - * TLS, TTLS, and PEAP, inside of the TLS tunnel. - */ - if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) { - switch(handler->eap_ds->response->type.type) { - case PW_EAP_TLS: - case PW_EAP_TTLS: - case PW_EAP_PEAP: - DEBUG2(" rlm_eap: Unable to tunnel TLS inside of TLS"); - eap_fail(handler); - eap_handler_free(handler); - return RLM_MODULE_INVALID; - break; - - default: /* It may be OK, allow it to proceed */ - break; - - } - } - - /* * Select the appropriate eap_type or default to the * configured one */ @@ -265,16 +323,17 @@ static int eap_authenticate(void *instance, REQUEST *request) */ if (rcode == EAP_INVALID) { eap_fail(handler); - eap_handler_free(handler); - DEBUG2(" rlm_eap: Failed in EAP select"); + eap_handler_free(inst, handler); + RDEBUG2("Failed in EAP select"); return RLM_MODULE_INVALID; } +#ifdef WITH_PROXY /* * If we're doing horrible tunneling work, remember it. */ if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) { - DEBUG2(" Not-EAP proxy set. Not composing EAP"); + RDEBUG2(" Not-EAP proxy set. Not composing EAP"); /* * Add the handle to the proxied list, so that we * can retrieve it in the post-proxy stage, and @@ -282,13 +341,15 @@ static int eap_authenticate(void *instance, REQUEST *request) */ rcode = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, - handler, eap_handler_free); + handler, + (void *) eap_handler_free); rad_assert(rcode == 0); return RLM_MODULE_HANDLED; } +#endif - +#ifdef WITH_PROXY /* * Maybe the request was marked to be proxied. If so, * proxy it. @@ -305,16 +366,17 @@ static int eap_authenticate(void *instance, REQUEST *request) */ rcode = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, - handler, eap_handler_free); + handler, + (void *) eap_handler_free); rad_assert(rcode == 0); /* * Some simple sanity checks. These should really * be handled by the radius library... */ - vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE); + vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE, 0); if (vp) { - vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR); + vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0); if (!vp) { vp = pairmake("Message-Authenticator", "0x00", T_OP_EQ); @@ -322,17 +384,18 @@ static int eap_authenticate(void *instance, REQUEST *request) pairadd(&(request->proxy->vps), vp); } } - + /* * Delete the "proxied to" attribute, as it's * set to 127.0.0.1 for tunneled requests, and * we don't want to tell the world that... */ - pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO); + pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS); - DEBUG2(" Tunneled session will be proxied. Not doing EAP."); + RDEBUG2(" Tunneled session will be proxied. Not doing EAP."); return RLM_MODULE_HANDLED; } +#endif /* * We are done, wrap the EAP-request in RADIUS to send @@ -344,9 +407,8 @@ static int eap_authenticate(void *instance, REQUEST *request) * Add to the list only if it is EAP-Request, OR if * it's LEAP, and a response. */ - if ((handler->eap_ds->request->code == PW_EAP_REQUEST) && - (handler->eap_ds->request->type.type >= PW_EAP_MD5)) { - eaplist_add(inst, handler); + if (((handler->eap_ds->request->code == PW_EAP_REQUEST) && + (handler->eap_ds->request->type.type >= PW_EAP_MD5)) || /* * LEAP is a little different. At Stage 4, @@ -357,17 +419,30 @@ static int eap_authenticate(void *instance, REQUEST *request) * At stage 6, LEAP sends an EAP-Response, which * isn't put into the list. */ - } else if ((handler->eap_ds->response->code == PW_EAP_RESPONSE) && - (handler->eap_ds->response->type.type == PW_EAP_LEAP) && - (handler->eap_ds->request->code == PW_EAP_SUCCESS) && - (handler->eap_ds->request->type.type == 0)) { + ((handler->eap_ds->response->code == PW_EAP_RESPONSE) && + (handler->eap_ds->response->type.type == PW_EAP_LEAP) && + (handler->eap_ds->request->code == PW_EAP_SUCCESS) && + (handler->eap_ds->request->type.type == 0))) { - eaplist_add(inst, handler); + /* + * Return FAIL if we can't remember the handler. + * This is actually disallowed by the + * specification, as unexpected FAILs could have + * been forged. However, we want to signal to + * everyone else involved that we are + * intentionally failing the session, as opposed + * to accidentally failing it. + */ + if (!eaplist_add(inst, handler)) { + eap_fail(handler); + eap_handler_free(inst, handler); + return RLM_MODULE_FAIL; + } } else { - DEBUG2(" rlm_eap: Freeing handler"); + RDEBUG2("Freeing handler"); /* handler is not required any more, free it now */ - eap_handler_free(handler); + eap_handler_free(inst, handler); } /* @@ -382,10 +457,13 @@ static int eap_authenticate(void *instance, REQUEST *request) /* * Doesn't exist, add it in. */ - vp = pairfind(request->reply->vps, PW_USER_NAME); + vp = pairfind(request->reply->vps, PW_USER_NAME, 0); if (!vp) { - vp = pairmake("User-Name", request->username->strvalue, + vp = pairmake("User-Name", "", T_OP_EQ); + strlcpy(vp->vp_strvalue, request->username->vp_strvalue, + sizeof(vp->vp_strvalue)); + vp->length = request->username->length; rad_assert(vp != NULL); pairadd(&(request->reply->vps), vp); } @@ -395,8 +473,8 @@ static int eap_authenticate(void *instance, REQUEST *request) * terminated string in Access-Accept. */ if ((inst->cisco_accounting_username_bug) && - (vp->length < (int) sizeof(vp->strvalue))) { - vp->strvalue[vp->length] = '\0'; + (vp->length < (int) sizeof(vp->vp_strvalue))) { + vp->vp_strvalue[vp->length] = '\0'; vp->length++; } } @@ -417,12 +495,14 @@ static int eap_authorize(void *instance, REQUEST *request) inst = (rlm_eap_t *)instance; +#ifdef WITH_PROXY /* * We don't do authorization again, once we've seen the * proxy reply (or the proxied packet) */ if (request->proxy != NULL) return RLM_MODULE_NOOP; +#endif /* * For EAP_START, send Access-Challenge with EAP Identity @@ -442,6 +522,7 @@ static int eap_authorize(void *instance, REQUEST *request) return RLM_MODULE_FAIL; case EAP_FOUND: return RLM_MODULE_HANDLED; + case EAP_OK: case EAP_NOTFOUND: default: break; @@ -456,30 +537,44 @@ static int eap_authorize(void *instance, REQUEST *request) * and to get excited if it doesn't appear. */ - vp = pairfind(request->config_items, PW_AUTH_TYPE); + vp = pairfind(request->config_items, PW_AUTH_TYPE, 0); if ((!vp) || - (vp->lvalue != PW_AUTHTYPE_REJECT)) { - vp = pairmake("Auth-Type", "EAP", T_OP_EQ); + (vp->vp_integer != PW_AUTHTYPE_REJECT)) { + vp = pairmake("Auth-Type", inst->xlat_name, T_OP_EQ); if (!vp) { + RDEBUG2("Failed to create Auth-Type %s: %s\n", + inst->xlat_name, fr_strerror()); return RLM_MODULE_FAIL; } pairadd(&request->config_items, vp); + } else { + RDEBUG2("WARNING: Auth-Type already set. Not setting to EAP"); } + if (status == EAP_OK) return RLM_MODULE_OK; + return RLM_MODULE_UPDATED; } + +#ifdef WITH_PROXY /* * If we're proxying EAP, then there may be magic we need * to do. */ static int eap_post_proxy(void *inst, REQUEST *request) { - int i, len; + size_t i; + size_t len; VALUE_PAIR *vp; EAP_HANDLER *handler; /* + * Just in case the admin lists EAP in post-proxy-type Fail. + */ + if (!request->proxy_reply) return RLM_MODULE_NOOP; + + /* * If there was a handler associated with this request, * then it's a tunneled request which was proxied... */ @@ -495,19 +590,21 @@ static int eap_post_proxy(void *inst, REQUEST *request) request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK); if (!data) { - radlog(L_ERR, "rlm_eap: Failed to retrieve callback for tunneled session!"); - eap_handler_free(handler); + radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!"); + eap_handler_free(inst, handler); return RLM_MODULE_FAIL; } /* * Do the callback... */ + RDEBUG2("Doing post-proxy callback"); rcode = data->callback(handler, data->tls_session); free(data); 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; } @@ -515,7 +612,7 @@ static int eap_post_proxy(void *inst, REQUEST *request) * We are done, wrap the EAP-request in RADIUS to send * with all other required radius attributes */ - rcode = eap_compose(handler); + eap_compose(handler); /* * Add to the list only if it is EAP-Request, OR if @@ -523,12 +620,16 @@ static int eap_post_proxy(void *inst, REQUEST *request) */ if ((handler->eap_ds->request->code == PW_EAP_REQUEST) && (handler->eap_ds->request->type.type >= PW_EAP_MD5)) { - eaplist_add(inst, handler); - + if (!eaplist_add(inst, handler)) { + eap_fail(handler); + eap_handler_free(inst, handler); + return RLM_MODULE_FAIL; + } + } else { /* couldn't have been LEAP, there's no tunnel */ - DEBUG2(" rlm_eap: Freeing handler"); + RDEBUG2("Freeing handler"); /* handler is not required any more, free it now */ - eap_handler_free(handler); + eap_handler_free(inst, handler); } /* @@ -541,9 +642,9 @@ static int eap_post_proxy(void *inst, REQUEST *request) /* * Doesn't exist, add it in. */ - vp = pairfind(request->reply->vps, PW_USER_NAME); + vp = pairfind(request->reply->vps, PW_USER_NAME, 0); if (!vp) { - vp = pairmake("User-Name", request->username->strvalue, + vp = pairmake("User-Name", request->username->vp_strvalue, T_OP_EQ); rad_assert(vp != NULL); pairadd(&(request->reply->vps), vp); @@ -551,9 +652,10 @@ static int eap_post_proxy(void *inst, REQUEST *request) } return RLM_MODULE_OK; + } else { + RDEBUG2("No pre-existing handler found"); } - /* * There may be more than one Cisco-AVPair. * Ensure we find the one with the LEAP attribute. @@ -567,7 +669,7 @@ static int eap_post_proxy(void *inst, REQUEST *request) * This is vendor Cisco (9), Cisco-AVPair * attribute (1) */ - vp = pairfind(vp, (9 << 16) | 1); + vp = pairfind(vp, 1, 9); if (!vp) { return RLM_MODULE_NOOP; } @@ -577,7 +679,7 @@ static int eap_post_proxy(void *inst, REQUEST *request) * * The format is VERY specific! */ - if (strncasecmp(vp->strvalue, "leap:session-key=", 17) == 0) { + if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) { break; } @@ -591,7 +693,7 @@ static int eap_post_proxy(void *inst, REQUEST *request) * The format is very specific. */ if (vp->length != 17 + 34) { - DEBUG2(" rlm_eap: Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d", + RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d", vp->length, 17 + 34); return RLM_MODULE_NOOP; } @@ -600,8 +702,8 @@ static int eap_post_proxy(void *inst, REQUEST *request) * Decrypt the session key, using the proxy data. */ i = 34; /* starts off with 34 octets */ - len = rad_tunnel_pwdecode(vp->strvalue + 17, &i, - request->proxysecret, + len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i, + request->home_server->secret, request->proxy->vector); /* @@ -611,23 +713,24 @@ static int eap_post_proxy(void *inst, REQUEST *request) /* * Encrypt the session key again, using the request data. */ - rad_tunnel_pwencode(vp->strvalue + 17, &len, - request->secret, + rad_tunnel_pwencode(vp->vp_strvalue + 17, &len, + request->client->secret, request->packet->vector); return RLM_MODULE_UPDATED; } - +#endif /* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. */ module_t rlm_eap = { + RLM_MODULE_INIT, "eap", - RLM_TYPE_THREAD_SAFE, /* type */ - NULL, /* initialization */ + RLM_TYPE_CHECK_CONFIG_SAFE, /* type */ eap_instantiate, /* instantiation */ + eap_detach, /* detach */ { eap_authenticate, /* authentication */ eap_authorize, /* authorization */ @@ -635,9 +738,11 @@ module_t rlm_eap = { NULL, /* accounting */ NULL, /* checksimul */ NULL, /* pre-proxy */ +#ifdef WITH_PROXY eap_post_proxy, /* post-proxy */ +#else + NULL, +#endif NULL /* post-auth */ }, - eap_detach, /* detach */ - NULL, /* destroy */ };