[PATCH v2 3/4] cache list of PSK entries

Michael Braun michael-dev
Fri Nov 16 07:12:57 PST 2012


---
 src/ap/hostapd.c         |    2 +
 src/ap/ieee802_11.c      |   16 ++++++----
 src/ap/ieee802_11_auth.c |   75 +++++++++++++++++++++++++++++-----------------
 src/ap/ieee802_11_auth.h |    2 +
 4 files changed, 60 insertions(+), 35 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 1c968a7..1e562d4 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -16,6 +16,7 @@
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "authsrv.h"
+#include "ap_config.h"
 #include "sta_info.h"
 #include "accounting.h"
 #include "ap_list.h"
@@ -29,7 +30,6 @@
 #include "hw_features.h"
 #include "wpa_auth_glue.h"
 #include "ap_drv_ops.h"
-#include "ap_config.h"
 #include "p2p_hostapd.h"
 #include "gas_serv.h"
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 8d5268e..5f8cca9 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -23,6 +23,7 @@
 #include "wps/wps.h"
 #include "hostapd.h"
 #include "beacon.h"
+#include "ap_config.h"
 #include "ieee802_11_auth.h"
 #include "sta_info.h"
 #include "ieee802_1x.h"
@@ -30,7 +31,6 @@
 #include "wmm.h"
 #include "ap_list.h"
 #include "accounting.h"
-#include "ap_config.h"
 #include "ap_mlme.h"
 #include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
@@ -443,8 +443,7 @@ static void handle_auth(struct hostapd_data *hapd,
 	const u8 *challenge = NULL;
 	u32 session_timeout, acct_interim_interval;
 	int vlan_id = 0;
-	u8 psk[PMK_LEN];
-	int has_psk = 0;
+	struct hostapd_sta_wpa_psk_short* psk = NULL;
 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
 	size_t resp_ies_len = 0;
 	char *identity = NULL;
@@ -514,7 +513,7 @@ static void handle_auth(struct hostapd_data *hapd,
 	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
 				      &session_timeout,
 				      &acct_interim_interval, &vlan_id,
-				      psk, &has_psk, &identity, &radius_cui);
+				      &psk, &identity, &radius_cui);
 
 	if (res == HOSTAPD_ACL_REJECT) {
 		printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -553,11 +552,11 @@ static void handle_auth(struct hostapd_data *hapd,
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 	}
 
-	if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+	if (psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
 		os_free(sta->psk);
 		sta->psk = os_malloc(PMK_LEN);
 		if (sta->psk)
-			os_memcpy(sta->psk, psk, PMK_LEN);
+			os_memcpy(sta->psk, psk->psk, PMK_LEN);
 	} else {
 		os_free(sta->psk);
 		sta->psk = NULL;
@@ -636,6 +635,11 @@ static void handle_auth(struct hostapd_data *hapd,
  fail:
 	os_free(identity);
 	os_free(radius_cui);
+	while (psk) {
+		struct hostapd_sta_wpa_psk_short *prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
 
 	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
 			auth_transaction + 1, resp, resp_ies, resp_ies_len);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 12b65b5..7fb2aed 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl {
 	u32 session_timeout;
 	u32 acct_interim_interval;
 	int vlan_id;
-	int has_psk;
-	u8 psk[PMK_LEN];
+	struct hostapd_sta_wpa_psk_short* psk;
 	char *identity;
 	char *radius_cui;
 };
@@ -58,6 +57,12 @@ static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
 {
 	os_free(e->identity);
 	os_free(e->radius_cui);
+	struct hostapd_sta_wpa_psk_short* psk = e->psk;
+	while (psk) {
+		struct hostapd_sta_wpa_psk_short* prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
 	os_free(e);
 }
 
@@ -73,11 +78,10 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
 	}
 }
 
-
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 				 u32 *session_timeout,
 				 u32 *acct_interim_interval, int *vlan_id,
-				 u8 *psk, int *has_psk, char **identity,
+				 struct hostapd_sta_wpa_psk_short **psk, char **identity,
 				 char **radius_cui)
 {
 	struct hostapd_cached_radius_acl *entry;
@@ -99,10 +103,21 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 				entry->acct_interim_interval;
 		if (vlan_id)
 			*vlan_id = entry->vlan_id;
-		if (psk)
-			os_memcpy(psk, entry->psk, PMK_LEN);
-		if (has_psk)
-			*has_psk = entry->has_psk;
+		/* copy PSK linked list */
+		{
+			struct hostapd_sta_wpa_psk_short ** copy_to = psk;
+			struct hostapd_sta_wpa_psk_short * copy_from = entry->psk;
+			while (copy_from && copy_to) {
+				*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+				if (*copy_to == NULL)
+					break;
+				os_memcpy(*copy_to, copy_from, sizeof(struct hostapd_sta_wpa_psk_short));
+				copy_from = copy_from->next;
+				copy_to = &((*copy_to)->next);
+			}
+			if (copy_to)
+				*copy_to = NULL;
+		}
 		if (identity) {
 			if (entry->identity)
 				*identity = os_strdup(entry->identity);
@@ -200,8 +215,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
  * @session_timeout: Buffer for returning session timeout (from RADIUS)
  * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
  * @vlan_id: Buffer for returning VLAN ID
- * @psk: Buffer for returning WPA PSK
- * @has_psk: Buffer for indicating whether psk was filled
+ * @psk: Linked list buffer for returning WPA PSK
  * @identity: Buffer for returning identity (from RADIUS)
  * @radius_cui: Buffer for returning CUI (from RADIUS)
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
@@ -212,7 +226,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
 			    u32 *acct_interim_interval, int *vlan_id,
-			    u8 *psk, int *has_psk, char **identity,
+			    struct hostapd_sta_wpa_psk_short **psk, char **identity,
 			    char **radius_cui)
 {
 	if (session_timeout)
@@ -221,10 +235,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 		*acct_interim_interval = 0;
 	if (vlan_id)
 		*vlan_id = 0;
-	if (has_psk)
-		*has_psk = 0;
 	if (psk)
-		os_memset(psk, 0, PMK_LEN);
+		*psk = NULL;
 	if (identity)
 		*identity = NULL;
 	if (radius_cui)
@@ -253,7 +265,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
 						acct_interim_interval,
-						vlan_id, psk, has_psk,
+						vlan_id, psk,
 						identity, radius_cui);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
@@ -456,6 +468,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
 		int passphraselen;
 		char *passphrase;
+		size_t i;
 		u8 *buf;
 		size_t len;
 
@@ -477,27 +490,35 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 		}
 
 		cache->vlan_id = radius_msg_get_vlanid(msg);
-
-		passphrase = radius_msg_get_tunnel_password(
-			msg, &passphraselen,
-			hapd->conf->radius->auth_server->shared_secret,
-			hapd->conf->radius->auth_server->shared_secret_len,
-			req, 0);
-		cache->has_psk = passphrase != NULL;
-		if (passphrase != NULL) {
+		/* decode all tunnel passwords as PSK and save them into a linked list */
+		for (i=0;;i++) {
+			passphrase = radius_msg_get_tunnel_password(
+				msg, &passphraselen,
+				hapd->conf->radius->auth_server->shared_secret,
+				hapd->conf->radius->auth_server->shared_secret_len,
+				req, i);
+			/* passphrase is NULL iff there is no i-th Tunnel-Password attribute in msg */
+			if (passphrase == NULL)
+				break;
 			/* passphrase does not contain the NULL termination.
 			 * Add it here as pbkdf2_sha1 requires it. */
 			char *strpassphrase = os_zalloc(passphraselen + 1);
-			if (strpassphrase) {
+			struct hostapd_sta_wpa_psk_short* psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+			if (strpassphrase && psk) {
 				os_memcpy(strpassphrase, passphrase,
 					  passphraselen);
 				pbkdf2_sha1(strpassphrase,
 					    hapd->conf->ssid.ssid,
 					    hapd->conf->ssid.ssid_len, 4096,
-					    cache->psk, PMK_LEN);
-				os_free(strpassphrase);
+					    psk->psk, PMK_LEN);
+				psk->next = cache->psk;
+				cache->psk = psk;
+				psk = NULL;
 			}
+			os_free(strpassphrase);
+			os_free(psk);
 			os_free(passphrase);
+			passphrase = NULL;
 		}
 		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
 					    &buf, &len, NULL) == 0) {
@@ -514,7 +535,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 		}
 
 		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
-		    !cache->has_psk)
+		    !cache->psk)
 			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 0e8d1cb..a830115 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -19,7 +19,7 @@ enum {
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
 			    u32 *acct_interim_interval, int *vlan_id,
-			    u8 *psk, int *has_psk, char **identity,
+			    struct hostapd_sta_wpa_psk_short **psk, char **identity,
 			    char **radius_cui);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);




More information about the Hostap mailing list