]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Do not disconnect EAPOL-Logoff before authentication
authorJouni Malinen <quic_jouni@quicinc.com>
Thu, 4 May 2023 07:18:34 +0000 (10:18 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 4 May 2023 08:10:16 +0000 (11:10 +0300)
Some station devices are apparently sending the EAPOL-Logoff message in
some cases before the initial authentication for WPA2/WPA3-Enterprise.
hostapd would have forced a "post EAP-Failure" disconnection in 10 ms
for such cases while still allowing the EAP authentication to try to
complete.

This is not ideal and could result in interoperability issues, so skip
the forced disconnection in the particular case where the EAPOL-Logoff
message is received before the first authentication is completed.

In addition, disconnect the STA without starting new EAP authentication
and the 10 ms delay if an EAPOL-Logoff message is received after
authentication has been completed successfully. This results in cleaner
behavior by avoiding the extra start of a new EAP authentication in a
case where the STA is going to be disconnected shortly.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/ap/ieee802_1x.c
src/ap/sta_info.c
src/ap/sta_info.h
src/eapol_auth/eapol_auth_sm.c
src/eapol_auth/eapol_auth_sm.h
src/eapol_auth/eapol_auth_sm_i.h

index 46a47d06e7d425dcebf82a1e81055b5897c99404..8b67669bb90be51ec849e7084b751238bf524791 100644 (file)
@@ -43,9 +43,9 @@
 #ifdef CONFIG_HS20
 static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_HS20 */
-static void ieee802_1x_finished(struct hostapd_data *hapd,
+static bool ieee802_1x_finished(struct hostapd_data *hapd,
                                struct sta_info *sta, int success,
-                               int remediation);
+                               int remediation, bool logoff);
 
 
 static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -2287,16 +2287,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
 }
 
 
-static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
-                                int preauth, int remediation)
+static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
+                                int preauth, int remediation, bool logoff)
 {
        struct hostapd_data *hapd = ctx;
        struct sta_info *sta = sta_ctx;
 
-       if (preauth)
+       if (preauth) {
                rsn_preauth_finished(hapd, sta, success);
-       else
-               ieee802_1x_finished(hapd, sta, success, remediation);
+               return false;
+       }
+
+       return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
 }
 
 
@@ -2977,9 +2979,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
 #endif /* CONFIG_HS20 */
 
 
-static void ieee802_1x_finished(struct hostapd_data *hapd,
+static bool ieee802_1x_finished(struct hostapd_data *hapd,
                                struct sta_info *sta, int success,
-                               int remediation)
+                               int remediation, bool logoff)
 {
        const u8 *key;
        size_t len;
@@ -3039,6 +3041,11 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                 * EAP-FAST with anonymous provisioning, may require another
                 * EAPOL authentication to be started to complete connection.
                 */
-               ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
+               ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
+                                                      logoff ? 0 : 10);
+               if (logoff && sta->wpa_sm)
+                       return true;
        }
+
+       return false;
 }
index 63f514c9e8d3c0f3f0274f9e36c6ef067c6dd1e1..0897bcda4dd1e47f95c1d6e59afd1eb0fafb8ad2 100644 (file)
@@ -1536,11 +1536,12 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
 
 
 void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
-                                           struct sta_info *sta)
+                                           struct sta_info *sta,
+                                           unsigned timeout)
 {
        wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
                "IEEE 802.1X: Force disconnection of " MACSTR
-               " after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+               " after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
 
        /*
         * Add a small sleep to increase likelihood of previously requested
@@ -1548,8 +1549,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
         * operations.
         */
        eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
-       eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
-                              hapd, sta);
+       eloop_register_timeout(0, timeout * 1000,
+                              ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
 }
 
 
index b59b7584b34af8ddd7892eb0b4efcb1eb2683d0a..8433ff8d6071acf5bd1c59ebe049297f57a27cc6 100644 (file)
@@ -373,7 +373,8 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
 void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
-                                           struct sta_info *sta);
+                                           struct sta_info *sta,
+                                           unsigned timeout);
 int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
                                                   struct sta_info *sta);
 int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
index 1c11cb613bd53e64e423ccdf8c1ef413ff123f5f..e1b82ebe36051295b10b9dbd1978898d0e3273f9 100644 (file)
@@ -217,6 +217,9 @@ SM_STATE(AUTH_PAE, INITIALIZE)
 SM_STATE(AUTH_PAE, DISCONNECTED)
 {
        int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
+       bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING &&
+               sm->eapolLogoff && !sm->authenticated;
+       bool logoff = sm->eapolLogoff;
 
        if (sm->eapolLogoff) {
                if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
@@ -231,10 +234,14 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
        setPortUnauthorized();
        sm->reAuthCount = 0;
        sm->eapolLogoff = false;
-       if (!from_initialize) {
-               sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-                                      sm->flags & EAPOL_SM_PREAUTH,
-                                      sm->remediation);
+       if (!from_initialize && !pre_auth_logoff) {
+               if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
+                                          sm->flags & EAPOL_SM_PREAUTH,
+                                          sm->remediation, logoff)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff");
+                       sm->stopped = true;
+               }
        }
 }
 
@@ -291,7 +298,8 @@ SM_STATE(AUTH_PAE, HELD)
                                   eap_server_get_name(0, sm->eap_type_supp));
        }
        sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-                              sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
+                              sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
+                              false);
 }
 
 
@@ -316,8 +324,11 @@ SM_STATE(AUTH_PAE, AUTHENTICATED)
                           sm->eap_type_authsrv,
                           eap_server_get_name(0, sm->eap_type_authsrv),
                           extra);
+       if (sm->authSuccess)
+               sm->authenticated++;
        sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
-                              sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
+                              sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
+                              false);
 }
 
 
@@ -397,7 +408,8 @@ SM_STEP(AUTH_PAE)
                        SM_ENTER(AUTH_PAE, DISCONNECTED);
                        break;
                case AUTH_PAE_DISCONNECTED:
-                       SM_ENTER(AUTH_PAE, RESTART);
+                       if (!sm->stopped)
+                               SM_ENTER(AUTH_PAE, RESTART);
                        break;
                case AUTH_PAE_RESTART:
                        if (!sm->eap_if->eapRestart)
index 61b7039d6b3178c0057c461b783e3bd89e2bca92..7296a3acaafe7008a5bc3554413b7eda41b2523c 100644 (file)
@@ -46,8 +46,8 @@ struct eapol_auth_cb {
                           size_t datalen);
        void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
                         size_t datalen);
-       void (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
-                        int remediation);
+       bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
+                        int remediation, bool logoff);
        int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
                            int phase2, struct eap_user *user);
        int (*sta_entry_alive)(void *ctx, const u8 *addr);
index 3c689831028463c15af1cc42c9c30068ce444831..a0cef0f8ec061a6fec55a59fc05eb2ac9534bd89 100644 (file)
@@ -171,6 +171,10 @@ struct eapol_state_machine {
        int remediation;
 
        u64 acct_multi_session_id;
+
+       unsigned int authenticated; /* The number of times authentication has
+                                    * been completed successfully. */
+       bool stopped;
 };
 
 #endif /* EAPOL_AUTH_SM_I_H */