X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_eap%2Frlm_eap.c;h=d204a94a6f5c512796380af826f51a16a3f7c3a8;hb=33862cbe5c186cf3133ccdc79bcab840bfd7192a;hp=22a946bab0e4af4c0c6505a5a97a81923ece071a;hpb=1c4fbb8d7d5beb5319193cbbc73b79b91caf065d;p=freeradius.git diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c index 22a946b..d204a94 100644 --- a/src/modules/rlm_eap/rlm_eap.c +++ b/src/modules/rlm_eap/rlm_eap.c @@ -25,10 +25,11 @@ #include RCSID("$Id$") -#include -#include "rlm_eap.h" +#include #include +#include "rlm_eap.h" + static const CONF_PARSER module_config[] = { { "default_eap_type", PW_TYPE_STRING_PTR, offsetof(rlm_eap_t, default_eap_type_name), NULL, "md5" }, @@ -38,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,7 +55,13 @@ static int eap_detach(void *instance) inst = (rlm_eap_t *)instance; +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&(inst->session_mutex)); + if (inst->handler_tree) pthread_mutex_destroy(&(inst->handler_mutex)); +#endif + rbtree_free(inst->session_tree); + if (inst->handler_tree) rbtree_free(inst->handler_tree); inst->session_tree = NULL; eaplist_free(inst); @@ -61,9 +70,6 @@ static int eap_detach(void *instance) inst->types[i] = NULL; } - pthread_mutex_destroy(&(inst->session_mutex)); - - if (inst->default_eap_type_name) free(inst->default_eap_type_name); free(inst); return 0; @@ -79,36 +85,32 @@ static int eap_handler_cmp(const void *a, const void *b) const EAP_HANDLER *one = a; const EAP_HANDLER *two = b; - - if (one->src_ipaddr.af < two->src_ipaddr.af) return -1; - if (one->src_ipaddr.af > two->src_ipaddr.af) return +1; - if (one->eap_id < two->eap_id) return -1; if (one->eap_id > two->eap_id) return +1; - switch (one->src_ipaddr.af) { - case AF_INET: - rcode = memcmp(&one->src_ipaddr.ipaddr.ip4addr, - &two->src_ipaddr.ipaddr.ip4addr, - sizeof(one->src_ipaddr.ipaddr.ip4addr)); - break; - case AF_INET6: - rcode = memcmp(&one->src_ipaddr.ipaddr.ip6addr, - &two->src_ipaddr.ipaddr.ip6addr, - sizeof(one->src_ipaddr.ipaddr.ip6addr)); - break; - default: - return -1; /* FIXME: die! */ - break; - } + rcode = memcmp(one->state, two->state, sizeof(one->state)); + if (rcode != 0) return rcode; + /* - * We could optimize this away, but the compiler should - * do that work for us, and this coding style helps us - * remember what to do if we add more checks later. + * 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 (rcode != 0) return rcode; + 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 memcmp(one->state, two->state, sizeof(one->state)); + return 0; +} + + +/* + * Compare two handler pointers + */ +static int eap_handler_ptr_cmp(const void *a, const void *b) +{ + return (((uint8_t *) a) - ((uint8_t *) b)); } @@ -117,7 +119,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; @@ -132,13 +134,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); @@ -146,12 +160,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. @@ -205,9 +240,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... @@ -219,7 +251,30 @@ 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; + } + +#ifdef HAVE_PTHREAD_H + 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; + } +#endif + } + +#ifdef HAVE_PTHREAD_H + 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; + } +#endif *instance = inst; return 0; @@ -238,12 +293,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; } @@ -254,32 +314,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 */ @@ -290,16 +329,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 @@ -307,13 +347,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. @@ -330,16 +372,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); @@ -347,17 +390,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 @@ -369,9 +413,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, @@ -382,17 +425,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); } /* @@ -407,10 +463,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->vp_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); } @@ -442,12 +501,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 @@ -467,6 +528,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; @@ -481,30 +543,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... */ @@ -520,19 +596,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; } @@ -540,7 +618,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 @@ -548,12 +626,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); } /* @@ -566,7 +648,7 @@ 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->vp_strvalue, T_OP_EQ); @@ -576,9 +658,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. @@ -592,7 +675,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; } @@ -616,7 +699,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; } @@ -625,8 +708,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->vp_strvalue + 17, &i, - request->proxysecret, + len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i, + request->home_server->secret, request->proxy->vector); /* @@ -637,12 +720,12 @@ static int eap_post_proxy(void *inst, REQUEST *request) * Encrypt the session key again, using the request data. */ rad_tunnel_pwencode(vp->vp_strvalue + 17, &len, - request->secret, + request->client->secret, request->packet->vector); return RLM_MODULE_UPDATED; } - +#endif /* * The module name should be the only globally exported symbol. @@ -651,7 +734,7 @@ static int eap_post_proxy(void *inst, REQUEST *request) module_t rlm_eap = { RLM_MODULE_INIT, "eap", - RLM_TYPE_THREAD_SAFE, /* type */ + RLM_TYPE_CHECK_CONFIG_SAFE, /* type */ eap_instantiate, /* instantiation */ eap_detach, /* detach */ { @@ -661,7 +744,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 */ }, };