Add RADIUS server support for identity selection hint (RFC 4284)
authorJouni Malinen <j@w1.fi>
Fri, 26 Dec 2008 18:22:12 +0000 (20:22 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 26 Dec 2008 18:22:12 +0000 (20:22 +0200)
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
src/eap_server/eap.c
src/eap_server/eap_identity.c
src/radius/radius_server.c
src/radius/radius_server.h

index 225ad3a..6a0c131 100644 (file)
@@ -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) {
index f3f81f3..289337f 100644 (file)
@@ -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;
        }
 
index 1f16b64..cd8da2a 100644 (file)
@@ -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) {
index 11c1b5b..1bfb93c 100644 (file)
@@ -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,
 };
 
 
index 2911e28..d5fb6a1 100644 (file)
@@ -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;
 };