[1/1] ieee80211: fix possible memory leak of radius data in handle_auth
diff mbox series

Message ID 20190428111457.15149-1-michael-dev@fami-braun.de
State New
Headers show
Series
  • [1/1] ieee80211: fix possible memory leak of radius data in handle_auth
Related show

Commit Message

Michael Braun April 28, 2019, 11:14 a.m. UTC
When returning from handle_auth after ieee802_11_allowed_address returned
HOSTAPD_ACL_ACCEPT but before ieee802_11_set_radius_info has been called,
identity, radius_cui and psk might not have been consumed.

Fix this by avoiding the need to free these variables at all.

While at it, move the radius cached attributes into a struct so that they
can be passed around more easily and less places need to be altered when
adding support for new RADIUS attributes.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
 src/ap/beacon.c          |  10 +--
 src/ap/ieee802_11.c      |  84 +++++++++--------------
 src/ap/ieee802_11.h      |  11 +--
 src/ap/ieee802_11_auth.c | 171 +++++++++++++++++------------------------------
 src/ap/ieee802_11_auth.h |  17 +++--
 5 files changed, 108 insertions(+), 185 deletions(-)

Patch
diff mbox series

diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3e62991d0..8adfc88c0 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -739,11 +739,7 @@  void handle_probe_req(struct hostapd_data *hapd,
 	int ret;
 	u16 csa_offs[2];
 	size_t csa_offs_len;
-	u32 session_timeout, acct_interim_interval;
-	struct vlan_description vlan_id;
-	struct hostapd_sta_wpa_psk_short *psk = NULL;
-	char *identity = NULL;
-	char *radius_cui = NULL;
+	struct radius_sta info;
 
 	if (len < IEEE80211_HDRLEN)
 		return;
@@ -753,9 +749,7 @@  void handle_probe_req(struct hostapd_data *hapd,
 	ie_len = len - IEEE80211_HDRLEN;
 
 	ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
-					 &session_timeout,
-					 &acct_interim_interval, &vlan_id,
-					 &psk, &identity, &radius_cui, 1);
+					 &info, 1);
 	if (ret == HOSTAPD_ACL_REJECT) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 			"Ignore Probe Request frame from " MACSTR
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index fde19b526..2742d73b5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1930,19 +1930,12 @@  void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
 
 int
 ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *msg, size_t len, u32 *session_timeout,
-			   u32 *acct_interim_interval,
-			   struct vlan_description *vlan_id,
-			   struct hostapd_sta_wpa_psk_short **psk,
-			   char **identity, char **radius_cui, int is_probe_req)
+			   const u8 *msg, size_t len, struct radius_sta *info,
+			   int is_probe_req)
 {
 	int res;
 
-	os_memset(vlan_id, 0, sizeof(*vlan_id));
-	res = hostapd_allowed_address(hapd, addr, msg, len,
-				      session_timeout, acct_interim_interval,
-				      vlan_id, psk, identity, radius_cui,
-				      is_probe_req);
+	res = hostapd_allowed_address(hapd, addr, msg, len, info, is_probe_req);
 
 	if (res == HOSTAPD_ACL_REJECT) {
 		if (!is_probe_req)
@@ -1969,12 +1962,15 @@  ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 
 static int
 ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int res, u32 session_timeout,
-			   u32 acct_interim_interval,
-			   struct vlan_description *vlan_id,
-			   struct hostapd_sta_wpa_psk_short **psk,
-			   char **identity, char **radius_cui)
+			   int res, struct radius_sta *info)
 {
+	u32 session_timeout = info->session_timeout;
+	u32 acct_interim_interval = info->acct_interim_interval;
+	struct vlan_description *vlan_id = &info->vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk = info->psk;
+	char *identity = info->identity;
+	char *radius_cui = info->radius_cui;
+
 	if (vlan_id->notempty &&
 	    !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -1991,20 +1987,22 @@  ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 
 	hostapd_free_psk_list(sta->psk);
-	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-		sta->psk = *psk;
-		*psk = NULL;
-	} else {
+	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+		hostapd_copy_psk_list(&sta->psk, psk);
+	else
 		sta->psk = NULL;
-	}
 
 	os_free(sta->identity);
-	sta->identity = *identity;
-	*identity = NULL;
+	if (identity)
+		sta->identity = os_strdup(identity);
+	else
+		sta->identity = NULL;
 
 	os_free(sta->radius_cui);
-	sta->radius_cui = *radius_cui;
-	*radius_cui = NULL;
+	if (radius_cui)
+		sta->radius_cui = os_strdup(radius_cui);
+	else
+		sta->radius_cui = NULL;
 
 	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
 		sta->acct_interim_interval = acct_interim_interval;
@@ -2032,14 +2030,10 @@  static void handle_auth(struct hostapd_data *hapd,
 	int res, reply_res;
 	u16 fc;
 	const u8 *challenge = NULL;
-	u32 session_timeout, acct_interim_interval;
-	struct vlan_description vlan_id;
-	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;
-	char *radius_cui = NULL;
 	u16 seq_ctrl;
+	struct radius_sta info;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2191,9 +2185,7 @@  static void handle_auth(struct hostapd_data *hapd,
 	}
 
 	res = ieee802_11_allowed_address(
-		hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
-		&acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
-		0);
+		hapd, mgmt->sa, (const u8 *) mgmt, len, &info, 0);
 	if (res == HOSTAPD_ACL_REJECT) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 			"Ignore Authentication frame from " MACSTR
@@ -2276,9 +2268,7 @@  static void handle_auth(struct hostapd_data *hapd,
 	sta->auth_rssi = rssi;
 #endif /* CONFIG_MBO */
 
-	res = ieee802_11_set_radius_info(
-		hapd, sta, res, session_timeout, acct_interim_interval,
-		&vlan_id, &psk, &identity, &radius_cui);
+	res = ieee802_11_set_radius_info(hapd, sta, res, &info);
 	if (res) {
 		wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2417,10 +2407,6 @@  static void handle_auth(struct hostapd_data *hapd,
 	}
 
  fail:
-	os_free(identity);
-	os_free(radius_cui);
-	hostapd_free_psk_list(psk);
-
 	reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
 				    auth_transaction + 1, resp, resp_ies,
 				    resp_ies_len, "handle-auth");
@@ -3702,9 +3688,6 @@  static void handle_assoc(struct hostapd_data *hapd,
 	int left, i;
 	struct sta_info *sta;
 	u8 *tmp = NULL;
-	struct hostapd_sta_wpa_psk_short *psk = NULL;
-	char *identity = NULL;
-	char *radius_cui = NULL;
 #ifdef CONFIG_FILS
 	int delay_assoc = 0;
 #endif /* CONFIG_FILS */
@@ -3784,13 +3767,11 @@  static void handle_assoc(struct hostapd_data *hapd,
 		    hapd->iface->current_mode->mode ==
 			HOSTAPD_MODE_IEEE80211AD) {
 			int acl_res;
-			u32 session_timeout, acct_interim_interval;
-			struct vlan_description vlan_id;
+			struct radius_sta info;
 
-			acl_res = ieee802_11_allowed_address(
-				hapd, mgmt->sa, (const u8 *) mgmt, len,
-				&session_timeout, &acct_interim_interval,
-				&vlan_id, &psk, &identity, &radius_cui, 0);
+			acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+							     (const u8 *) mgmt,
+							     len, &info, 0);
 			if (acl_res == HOSTAPD_ACL_REJECT) {
 				wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 					"Ignore Association Request frame from "
@@ -3815,9 +3796,7 @@  static void handle_assoc(struct hostapd_data *hapd,
 			}
 
 			acl_res = ieee802_11_set_radius_info(
-				hapd, sta, acl_res, session_timeout,
-				acct_interim_interval, &vlan_id, &psk,
-				&identity, &radius_cui);
+				hapd, sta, acl_res, &info);
 			if (acl_res) {
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 				goto fail;
@@ -4020,9 +3999,6 @@  static void handle_assoc(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
  fail:
-	os_free(identity);
-	os_free(radius_cui);
-	hostapd_free_psk_list(psk);
 
 	/*
 	 * In case of a successful response, add the station to the driver.
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index db7badcff..eccafcbb5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,8 +16,7 @@  struct hostapd_frame_info;
 struct ieee80211_ht_capabilities;
 struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		    struct hostapd_frame_info *fi);
@@ -165,12 +164,8 @@  void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
 size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
 u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
 int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			       const u8 *msg, size_t len, u32 *session_timeout,
-			       u32 *acct_interim_interval,
-			       struct vlan_description *vlan_id,
-			       struct hostapd_sta_wpa_psk_short **psk,
-			       char **identity, char **radius_cui,
-			       int is_probe_req);
+			       const u8 *msg, size_t len,
+			       struct radius_sta *info, int is_probe_req);
 
 int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
 		      int ap_seg1_idx, int *bandwidth, int *seg1_idx);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 931d4d065..0d155e627 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@  struct hostapd_cached_radius_acl {
 	macaddr addr;
 	int accepted; /* HOSTAPD_ACL_* */
 	struct hostapd_cached_radius_acl *next;
-	u32 session_timeout;
-	u32 acct_interim_interval;
-	struct vlan_description vlan_id;
-	struct hostapd_sta_wpa_psk_short *psk;
-	char *identity;
-	char *radius_cui;
+	struct radius_sta info;
 };
 
 
@@ -54,9 +49,9 @@  struct hostapd_acl_query_data {
 #ifndef CONFIG_NO_RADIUS
 static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
 {
-	os_free(e->identity);
-	os_free(e->radius_cui);
-	hostapd_free_psk_list(e->psk);
+	os_free(e->info.identity);
+	os_free(e->info.radius_cui);
+	hostapd_free_psk_list(e->info.psk);
 	os_free(e);
 }
 
@@ -73,25 +68,8 @@  static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
 }
 
 
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
-			  struct hostapd_sta_wpa_psk_short *src)
-{
-	if (!psk)
-		return;
-
-	if (src)
-		src->ref++;
-
-	*psk = src;
-}
-
-
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
-				 u32 *session_timeout,
-				 u32 *acct_interim_interval,
-				 struct vlan_description *vlan_id,
-				 struct hostapd_sta_wpa_psk_short **psk,
-				 char **identity, char **radius_cui)
+				 struct radius_sta *out)
 {
 	struct hostapd_cached_radius_acl *entry;
 	struct os_reltime now;
@@ -105,27 +83,9 @@  static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 		if (os_reltime_expired(&now, &entry->timestamp,
 				       RADIUS_ACL_TIMEOUT))
 			return -1; /* entry has expired */
-		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-			if (session_timeout)
-				*session_timeout = entry->session_timeout;
-		if (acct_interim_interval)
-			*acct_interim_interval =
-				entry->acct_interim_interval;
-		if (vlan_id)
-			*vlan_id = entry->vlan_id;
-		copy_psk_list(psk, entry->psk);
-		if (identity) {
-			if (entry->identity)
-				*identity = os_strdup(entry->identity);
-			else
-				*identity = NULL;
-		}
-		if (radius_cui) {
-			if (entry->radius_cui)
-				*radius_cui = os_strdup(entry->radius_cui);
-			else
-				*radius_cui = NULL;
-		}
+		if (out)
+			*out = entry->info;
+
 		return entry->accepted;
 	}
 
@@ -238,42 +198,28 @@  int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
  * @addr: MAC address of the STA
  * @msg: Authentication message
  * @len: Length of msg in octets
- * @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: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.radius_cui: Buffer for returning CUI (from RADIUS)
  * @is_probe_req: Whether this query for a Probe Request frame
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
  *
- * The caller is responsible for freeing the returned *identity and *radius_cui
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval,
-			    struct vlan_description *vlan_id,
-			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui,
+			    const u8 *msg, size_t len, struct radius_sta *out,
 			    int is_probe_req)
 {
 	int res;
 
-	if (session_timeout)
-		*session_timeout = 0;
-	if (acct_interim_interval)
-		*acct_interim_interval = 0;
-	if (vlan_id)
-		os_memset(vlan_id, 0, sizeof(*vlan_id));
-	if (psk)
-		*psk = NULL;
-	if (identity)
-		*identity = NULL;
-	if (radius_cui)
-		*radius_cui = NULL;
-
-	res = hostapd_check_acl(hapd, addr, vlan_id);
+	if (out)
+		os_memset(out, 0, sizeof(*out));
+
+	res = hostapd_check_acl(hapd, addr, &out->vlan_id);
 	if (res != HOSTAPD_ACL_PENDING)
 		return res;
 
@@ -290,12 +236,10 @@  int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 		};
 
 		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			vlan_id = NULL;
+			os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
 
 		/* Check whether ACL cache has an entry for this station */
-		res = hostapd_acl_cache_get(hapd, addr, session_timeout,
-					    acct_interim_interval, vlan_id, psk,
-					    identity, radius_cui);
+		res = hostapd_acl_cache_get(hapd, addr, out);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			return res;
@@ -307,14 +251,6 @@  int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
 				/* pending query in RADIUS retransmit queue;
 				 * do not generate a new one */
-				if (identity) {
-					os_free(*identity);
-					*identity = NULL;
-				}
-				if (radius_cui) {
-					os_free(*radius_cui);
-					*radius_cui = NULL;
-				}
 				return HOSTAPD_ACL_PENDING;
 			}
 			query = query->next;
@@ -488,8 +424,8 @@  static void decode_tunnel_passwords(struct hostapd_data *hapd,
 					  passphraselen);
 				psk->is_passphrase = 1;
 			}
-			psk->next = cache->psk;
-			cache->psk = psk;
+			psk->next = cache->info.psk;
+			cache->info.psk = psk;
 			psk = NULL;
 		}
 skip:
@@ -518,6 +454,7 @@  hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 	struct hostapd_data *hapd = data;
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
+	struct radius_sta *info;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
 
 	query = hapd->acl_queries;
@@ -555,65 +492,66 @@  hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 	}
 	os_get_reltime(&cache->timestamp);
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+	info = &cache->info;
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
 		u8 *buf;
 		size_t len;
 
 		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
-					      &cache->session_timeout) == 0)
+					      &info->session_timeout) == 0)
 			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
 		else
 			cache->accepted = HOSTAPD_ACL_ACCEPT;
 
 		if (radius_msg_get_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
-			    &cache->acct_interim_interval) == 0 &&
-		    cache->acct_interim_interval < 60) {
+			    &info->acct_interim_interval) == 0 &&
+		    info->acct_interim_interval < 60) {
 			wpa_printf(MSG_DEBUG, "Ignored too small "
 				   "Acct-Interim-Interval %d for STA " MACSTR,
-				   cache->acct_interim_interval,
+				   info->acct_interim_interval,
 				   MAC2STR(query->addr));
-			cache->acct_interim_interval = 0;
+			info->acct_interim_interval = 0;
 		}
 
 		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
-			cache->vlan_id.notempty = !!radius_msg_get_vlanid(
-				msg, &cache->vlan_id.untagged,
-				MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
+			info->vlan_id.notempty = !!radius_msg_get_vlanid(
+				msg, &info->vlan_id.untagged,
+				MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
 
 		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
 					msg, req, cache);
 
 		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
 					    &buf, &len, NULL) == 0) {
-			cache->identity = os_zalloc(len + 1);
-			if (cache->identity)
-				os_memcpy(cache->identity, buf, len);
+			info->identity = os_zalloc(len + 1);
+			if (info->identity)
+				os_memcpy(info->identity, buf, len);
 		}
 		if (radius_msg_get_attr_ptr(
 			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
 			    &buf, &len, NULL) == 0) {
-			cache->radius_cui = os_zalloc(len + 1);
-			if (cache->radius_cui)
-				os_memcpy(cache->radius_cui, buf, len);
+			info->radius_cui = os_zalloc(len + 1);
+			if (info->radius_cui)
+				os_memcpy(info->radius_cui, buf, len);
 		}
 
 		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
-		    !cache->psk)
+		    !info->psk)
 			cache->accepted = HOSTAPD_ACL_REJECT;
 
-		if (cache->vlan_id.notempty &&
-		    !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+		if (info->vlan_id.notempty &&
+		    !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
 			hostapd_logger(hapd, query->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
 				       "Invalid VLAN %d%s received from RADIUS server",
-				       cache->vlan_id.untagged,
-				       cache->vlan_id.tagged[0] ? "+" : "");
-			os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+				       info->vlan_id.untagged,
+				       info->vlan_id.tagged[0] ? "+" : "");
+			os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
 		}
 		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
-		    !cache->vlan_id.notempty)
+		    !info->vlan_id.notempty)
 			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
@@ -685,6 +623,19 @@  void hostapd_acl_deinit(struct hostapd_data *hapd)
 }
 
 
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+			   struct hostapd_sta_wpa_psk_short *src)
+{
+	if (!psk)
+		return;
+
+	if (src)
+		src->ref++;
+
+	*psk = src;
+}
+
+
 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
 {
 	if (psk && psk->ref) {
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 5aece5183..9410f55c5 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@  enum {
 	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
 };
 
+struct radius_sta {
+	u32 session_timeout;
+	u32 acct_interim_interval;
+	struct vlan_description vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk;
+	char *identity;
+	char *radius_cui;
+};
+
 int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
 		      struct vlan_description *vlan_id);
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval,
-			    struct vlan_description *vlan_id,
-			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui,
+			    const u8 *msg, size_t len, struct radius_sta *out,
 			    int is_probe_req);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
 void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+			   struct hostapd_sta_wpa_psk_short *src);
 
 #endif /* IEEE802_11_AUTH_H */