Browse Source

RADIUS DAS: Allow PMKSA cache entry to be removed without association

This extends Disconnect-Request processing to check against PMKSA cache
entries if no active session (STA association) match the request.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 10 years ago
parent
commit
cbc210de09
5 changed files with 99 additions and 0 deletions
  1. 14 0
      src/ap/hostapd.c
  2. 72 0
      src/ap/pmksa_cache_auth.c
  3. 2 0
      src/ap/pmksa_cache_auth.h
  4. 7 0
      src/ap/wpa_auth.c
  5. 4 0
      src/ap/wpa_auth.h

+ 14 - 0
src/ap/hostapd.c

@@ -794,6 +794,15 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
 }
 }
 
 
 
 
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+					struct radius_das_attrs *attr)
+{
+	if (!hapd->wpa_auth)
+		return -1;
+	return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
+}
+
+
 static enum radius_das_res
 static enum radius_das_res
 hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
 hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
 {
 {
@@ -811,6 +820,11 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
 				   "RADIUS DAS: Multiple sessions match - not supported");
 				   "RADIUS DAS: Multiple sessions match - not supported");
 			return RADIUS_DAS_MULTI_SESSION_MATCH;
 			return RADIUS_DAS_MULTI_SESSION_MATCH;
 		}
 		}
+		if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: PMKSA cache entry matched");
+			return RADIUS_DAS_SUCCESS;
+		}
 		wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
 		wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
 		return RADIUS_DAS_SESSION_NOT_FOUND;
 		return RADIUS_DAS_SESSION_NOT_FOUND;
 	}
 	}

+ 72 - 0
src/ap/pmksa_cache_auth.c

@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "utils/eloop.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
 #include "sta_info.h"
 #include "sta_info.h"
 #include "ap_config.h"
 #include "ap_config.h"
 #include "pmksa_cache_auth.h"
 #include "pmksa_cache_auth.h"
@@ -452,3 +453,74 @@ pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
 
 
 	return pmksa;
 	return pmksa;
 }
 }
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+			  struct radius_das_attrs *attr)
+{
+	int match = 0;
+
+	if (attr->sta_addr) {
+		if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->acct_multi_session_id) {
+		char buf[20];
+
+		if (attr->acct_multi_session_id_len != 17)
+			return 0;
+		os_snprintf(buf, sizeof(buf), "%08X+%08X",
+			    entry->acct_multi_session_id_hi,
+			    entry->acct_multi_session_id_lo);
+		if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->cui) {
+		if (!entry->cui ||
+		    attr->cui_len != wpabuf_len(entry->cui) ||
+		    os_memcmp(attr->cui, wpabuf_head(entry->cui),
+			      attr->cui_len) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->user_name) {
+		if (!entry->identity ||
+		    attr->user_name_len != entry->identity_len ||
+		    os_memcmp(attr->user_name, entry->identity,
+			      attr->user_name_len) != 0)
+			return 0;
+		match++;
+	}
+
+	return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+					   struct radius_das_attrs *attr)
+{
+	int found = 0;
+	struct rsn_pmksa_cache_entry *entry, *prev;
+
+	if (attr->acct_session_id)
+		return -1;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (das_attr_match(entry, attr)) {
+			found++;
+			prev = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, prev);
+			continue;
+		}
+		entry = entry->next;
+	}
+
+	return found ? 0 : -1;
+}

+ 2 - 0
src/ap/pmksa_cache_auth.h

@@ -61,5 +61,7 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
 			       struct eapol_state_machine *eapol);
 			       struct eapol_state_machine *eapol);
 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 			    struct rsn_pmksa_cache_entry *entry);
 			    struct rsn_pmksa_cache_entry *entry);
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+					   struct radius_das_attrs *attr);
 
 
 #endif /* PMKSA_CACHE_H */
 #endif /* PMKSA_CACHE_H */

+ 7 - 0
src/ap/wpa_auth.c

@@ -3340,3 +3340,10 @@ int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
 	return 0;
 	return 0;
 }
 }
 #endif /* CONFIG_P2P */
 #endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+					 struct radius_das_attrs *attr)
+{
+	return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}

+ 4 - 0
src/ap/wpa_auth.h

@@ -315,4 +315,8 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
 
 
 int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
 int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
 
 
+struct radius_das_attrs;
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+					 struct radius_das_attrs *attr);
+
 #endif /* WPA_AUTH_H */
 #endif /* WPA_AUTH_H */