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@xxxxxxxxxxxxx> --- 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(-) 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 */ -- 2.11.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap