From 65d50f0ac63b6c7831cc0b04bbd476dd48b0991b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 26 Dec 2008 20:22:12 +0200 Subject: [PATCH] Add RADIUS server support for identity selection hint (RFC 4284) Previously, only the delivery option 1 from RFC 4284 (EAP-Request/Identity from the AP) was supported. Now option 3 (subsequent EAP-Request/Identity from RADIUS server) can also be used when hostapd is used as a RADIUS server. The eap_user file will need to have a Phase 1 user entry pointing to Identity method in order for this to happen (e.g., "* Identity" in the end of the file). The identity hint is configured in the same was as for AP/Authenticator case (eap_message in hostapd.conf). --- hostapd/hostapd.c | 2 ++ src/eap_server/eap.c | 19 +++++++++++++++++++ src/eap_server/eap_identity.c | 2 ++ src/radius/radius_server.c | 21 +++++++++++++++++++++ src/radius/radius_server.h | 2 ++ 5 files changed, 46 insertions(+) diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c index 225ad3abf..6a0c13126 100644 --- a/hostapd/hostapd.c +++ b/hostapd/hostapd.c @@ -1221,6 +1221,8 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd, srv.wps = hapd->wps; srv.ipv6 = conf->radius_server_ipv6; srv.get_eap_user = hostapd_radius_get_eap_user; + srv.eap_req_id_text = conf->eap_req_id_text; + srv.eap_req_id_text_len = conf->eap_req_id_text_len; hapd->radius_srv = radius_server_init(&srv); if (hapd->radius_srv == NULL) { diff --git a/src/eap_server/eap.c b/src/eap_server/eap.c index f3f81f35e..289337f98 100644 --- a/src/eap_server/eap.c +++ b/src/eap_server/eap.c @@ -1051,11 +1051,30 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm) } if ((sm->user == NULL || sm->update_user) && sm->identity) { + /* + * Allow Identity method to be started once to allow identity + * selection hint to be sent from the authentication server, + * but prevent a loop of Identity requests by only allowing + * this to happen once. + */ + int id_req = 0; + if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && + sm->user->methods[0].vendor == EAP_VENDOR_IETF && + sm->user->methods[0].method == EAP_TYPE_IDENTITY) + id_req = 1; if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " "found from database -> FAILURE"); return DECISION_FAILURE; } + if (id_req && sm->user && + sm->user->methods[0].vendor == EAP_VENDOR_IETF && + sm->user->methods[0].method == EAP_TYPE_IDENTITY) { + wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " + "identity request loop -> FAILURE"); + sm->update_user = TRUE; + return DECISION_FAILURE; + } sm->update_user = FALSE; } diff --git a/src/eap_server/eap_identity.c b/src/eap_server/eap_identity.c index 1f16b64ce..cd8da2a63 100644 --- a/src/eap_server/eap_identity.c +++ b/src/eap_server/eap_identity.c @@ -125,6 +125,8 @@ static void eap_identity_process(struct eap_sm *sm, void *priv, return; /* Should not happen - frame already validated */ wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len); + if (sm->identity) + sm->update_user = TRUE; os_free(sm->identity); sm->identity = os_malloc(len ? len : 1); if (sm->identity == NULL) { diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index 11c1b5bc8..1bfb93c70 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -99,6 +99,8 @@ struct radius_server_data { struct radius_server_counters counters; int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); + char *eap_req_id_text; + size_t eap_req_id_text_len; }; @@ -1043,6 +1045,14 @@ radius_server_init(struct radius_server_conf *conf) data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; data->tnc = conf->tnc; data->wps = conf->wps; + if (conf->eap_req_id_text) { + data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); + if (data->eap_req_id_text) { + os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, + conf->eap_req_id_text_len); + data->eap_req_id_text_len = conf->eap_req_id_text_len; + } + } data->clients = radius_server_read_clients(conf->client_file, conf->ipv6); @@ -1090,6 +1100,7 @@ void radius_server_deinit(struct radius_server_data *data) os_free(data->pac_opaque_encr_key); os_free(data->eap_fast_a_id); os_free(data->eap_fast_a_id_info); + os_free(data->eap_req_id_text); os_free(data); } @@ -1217,9 +1228,19 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity, } +static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) +{ + struct radius_session *sess = ctx; + struct radius_server_data *data = sess->server; + *len = data->eap_req_id_text_len; + return data->eap_req_id_text; +} + + static struct eapol_callbacks radius_server_eapol_cb = { .get_eap_user = radius_server_get_eap_user, + .get_eap_req_id_text = radius_server_get_eap_req_id_text, }; diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h index 2911e28d0..d5fb6a1e3 100644 --- a/src/radius/radius_server.h +++ b/src/radius/radius_server.h @@ -37,6 +37,8 @@ struct radius_server_conf { int ipv6; int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); + const char *eap_req_id_text; + size_t eap_req_id_text_len; };