2008-02-28 02:34:43 +01:00
|
|
|
/*
|
|
|
|
* hostapd / IEEE 802.11 authentication (ACL)
|
2022-04-02 12:12:43 +02:00
|
|
|
* Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
|
2008-02-28 02:34:43 +01:00
|
|
|
*
|
2012-02-11 15:46:35 +01:00
|
|
|
* This software may be distributed under the terms of the BSD license.
|
|
|
|
* See README for more details.
|
2009-01-08 15:33:00 +01:00
|
|
|
*
|
|
|
|
* Access control list for IEEE 802.11 authentication can uses statically
|
|
|
|
* configured ACL from configuration files or an external RADIUS server.
|
|
|
|
* Results from external RADIUS queries are cached to allow faster
|
|
|
|
* authentication frame processing.
|
2008-02-28 02:34:43 +01:00
|
|
|
*/
|
|
|
|
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "utils/includes.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "utils/common.h"
|
|
|
|
#include "utils/eloop.h"
|
|
|
|
#include "radius/radius.h"
|
|
|
|
#include "radius/radius_client.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "hostapd.h"
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "ap_config.h"
|
2010-11-24 15:34:49 +01:00
|
|
|
#include "ap_drv_ops.h"
|
2022-04-02 12:12:43 +02:00
|
|
|
#include "sta_info.h"
|
|
|
|
#include "wpa_auth.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "ieee802_11.h"
|
2012-08-07 18:13:15 +02:00
|
|
|
#include "ieee802_1x.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "ieee802_11_auth.h"
|
|
|
|
|
|
|
|
#define RADIUS_ACL_TIMEOUT 30
|
|
|
|
|
|
|
|
|
|
|
|
struct hostapd_cached_radius_acl {
|
2013-11-25 21:56:08 +01:00
|
|
|
struct os_reltime timestamp;
|
2008-02-28 02:34:43 +01:00
|
|
|
macaddr addr;
|
|
|
|
int accepted; /* HOSTAPD_ACL_* */
|
|
|
|
struct hostapd_cached_radius_acl *next;
|
2019-04-28 13:14:57 +02:00
|
|
|
struct radius_sta info;
|
2008-02-28 02:34:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct hostapd_acl_query_data {
|
2013-11-25 21:56:08 +01:00
|
|
|
struct os_reltime timestamp;
|
2008-02-28 02:34:43 +01:00
|
|
|
u8 radius_id;
|
|
|
|
macaddr addr;
|
|
|
|
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
|
|
|
|
size_t auth_msg_len;
|
|
|
|
struct hostapd_acl_query_data *next;
|
2022-04-02 12:12:43 +02:00
|
|
|
bool radius_psk;
|
|
|
|
int akm;
|
2022-04-15 16:36:25 +02:00
|
|
|
u8 *anonce;
|
|
|
|
u8 *eapol;
|
|
|
|
size_t eapol_len;
|
2008-02-28 02:34:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2012-08-19 13:09:28 +02:00
|
|
|
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
|
|
|
|
{
|
2019-04-28 13:14:57 +02:00
|
|
|
os_free(e->info.identity);
|
|
|
|
os_free(e->info.radius_cui);
|
|
|
|
hostapd_free_psk_list(e->info.psk);
|
2012-08-19 13:09:28 +02:00
|
|
|
os_free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
|
|
|
|
{
|
|
|
|
struct hostapd_cached_radius_acl *prev;
|
|
|
|
|
|
|
|
while (acl_cache) {
|
|
|
|
prev = acl_cache;
|
|
|
|
acl_cache = acl_cache->next;
|
2012-08-19 13:09:28 +02:00
|
|
|
hostapd_acl_cache_free_entry(prev);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
2019-04-28 13:14:57 +02:00
|
|
|
struct radius_sta *out)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
struct hostapd_cached_radius_acl *entry;
|
2013-11-25 21:56:08 +01:00
|
|
|
struct os_reltime now;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2013-11-25 21:56:08 +01:00
|
|
|
os_get_reltime(&now);
|
2012-08-19 12:46:23 +02:00
|
|
|
|
|
|
|
for (entry = hapd->acl_cache; entry; entry = entry->next) {
|
Use ether_addr_equal() to compare whether two MAC addresses are equal
This was done with spatch using the following semantic patch and minor
manual edits to clean up coding style and avoid compiler warnings in
driver_wext.c:
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !os_memcmp(a, b, ETH_ALEN)
+ ether_addr_equal(a, b)
Signed-off-by: Jouni Malinen <j@w1.fi>
2024-01-13 22:15:36 +01:00
|
|
|
if (!ether_addr_equal(entry->addr, addr))
|
2012-08-19 12:46:23 +02:00
|
|
|
continue;
|
|
|
|
|
2013-11-25 21:56:08 +01:00
|
|
|
if (os_reltime_expired(&now, &entry->timestamp,
|
|
|
|
RADIUS_ACL_TIMEOUT))
|
2012-08-19 12:46:23 +02:00
|
|
|
return -1; /* entry has expired */
|
2019-04-28 13:14:57 +02:00
|
|
|
*out = entry->info;
|
|
|
|
|
2012-08-19 12:46:23 +02:00
|
|
|
return entry->accepted;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
|
|
|
|
{
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!query)
|
2008-02-28 02:34:43 +01:00
|
|
|
return;
|
|
|
|
os_free(query->auth_msg);
|
2022-04-15 16:36:25 +02:00
|
|
|
os_free(query->anonce);
|
|
|
|
os_free(query->eapol);
|
2008-02-28 02:34:43 +01:00
|
|
|
os_free(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2008-02-28 02:34:43 +01:00
|
|
|
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
|
|
|
struct hostapd_acl_query_data *query)
|
|
|
|
{
|
|
|
|
struct radius_msg *msg;
|
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
query->radius_id = radius_client_get_id(hapd->radius);
|
|
|
|
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!msg)
|
2008-02-28 02:34:43 +01:00
|
|
|
return -1;
|
|
|
|
|
2016-01-27 14:22:48 +01:00
|
|
|
if (radius_msg_make_authenticator(msg) < 0) {
|
|
|
|
wpa_printf(MSG_INFO, "Could not make Request Authenticator");
|
|
|
|
goto fail;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
|
|
|
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
|
|
|
|
os_strlen(buf))) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add User-Name");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radius_msg_add_attr_user_password(
|
|
|
|
msg, (u8 *) buf, os_strlen(buf),
|
|
|
|
hapd->conf->radius->auth_server->shared_secret,
|
|
|
|
hapd->conf->radius->auth_server->shared_secret_len)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add User-Password");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2012-08-07 18:13:15 +02:00
|
|
|
if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
|
|
|
|
NULL, msg) < 0)
|
2008-02-28 02:34:43 +01:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
|
|
|
|
MAC2STR(addr));
|
|
|
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
|
|
|
(u8 *) buf, os_strlen(buf))) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
|
|
|
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
|
|
|
|
(u8 *) buf, os_strlen(buf))) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2022-04-02 12:12:43 +02:00
|
|
|
if (query->akm &&
|
|
|
|
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
|
|
|
|
wpa_akm_to_suite(query->akm))) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2022-04-15 16:36:25 +02:00
|
|
|
if (query->anonce &&
|
|
|
|
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
|
|
|
|
RADIUS_VENDOR_ID_FREERADIUS,
|
|
|
|
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
|
|
|
|
query->anonce, WPA_NONCE_LEN)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->eapol &&
|
|
|
|
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
|
|
|
|
RADIUS_VENDOR_ID_FREERADIUS,
|
|
|
|
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
|
|
|
|
query->eapol, query->eapol_len)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2012-04-01 16:55:20 +02:00
|
|
|
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
|
|
|
|
goto fail;
|
2008-02-28 02:34:43 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
radius_msg_free(msg);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
|
2015-10-22 18:48:04 +02:00
|
|
|
/**
|
|
|
|
* hostapd_check_acl - Check a specified STA against accept/deny ACLs
|
|
|
|
* @hapd: hostapd BSS data
|
|
|
|
* @addr: MAC address of the STA
|
|
|
|
* @vlan_id: Buffer for returning VLAN ID
|
|
|
|
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
|
|
|
*/
|
2016-01-21 14:51:56 +01:00
|
|
|
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
|
|
|
|
struct vlan_description *vlan_id)
|
2015-10-22 18:48:04 +02:00
|
|
|
{
|
|
|
|
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
|
|
|
hapd->conf->num_accept_mac, addr, vlan_id))
|
|
|
|
return HOSTAPD_ACL_ACCEPT;
|
|
|
|
|
|
|
|
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
|
|
|
hapd->conf->num_deny_mac, addr, vlan_id))
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
|
|
|
|
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
|
|
|
|
return HOSTAPD_ACL_ACCEPT;
|
|
|
|
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
|
|
|
|
return HOSTAPD_ACL_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* hostapd_allowed_address - Check whether a specified STA can be authenticated
|
|
|
|
* @hapd: hostapd BSS data
|
|
|
|
* @addr: MAC address of the STA
|
|
|
|
* @msg: Authentication message
|
|
|
|
* @len: Length of msg in octets
|
2019-04-28 13:14:57 +02:00
|
|
|
* @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)
|
2018-02-14 14:43:56 +01:00
|
|
|
* @is_probe_req: Whether this query for a Probe Request frame
|
2009-01-08 15:33:00 +01:00
|
|
|
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
2012-08-19 13:20:10 +02:00
|
|
|
*
|
2019-04-28 13:14:57 +02:00
|
|
|
* The caller is responsible for properly cloning the returned out->identity and
|
|
|
|
* out->radius_cui and out->psk values.
|
2009-01-08 15:33:00 +01:00
|
|
|
*/
|
2008-02-28 02:34:43 +01:00
|
|
|
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
2019-04-28 13:14:57 +02:00
|
|
|
const u8 *msg, size_t len, struct radius_sta *out,
|
2018-02-14 14:43:56 +01:00
|
|
|
int is_probe_req)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
2015-10-22 18:48:04 +02:00
|
|
|
int res;
|
|
|
|
|
2019-04-28 13:14:57 +02:00
|
|
|
os_memset(out, 0, sizeof(*out));
|
|
|
|
|
|
|
|
res = hostapd_check_acl(hapd, addr, &out->vlan_id);
|
2015-10-22 18:48:04 +02:00
|
|
|
if (res != HOSTAPD_ACL_PENDING)
|
|
|
|
return res;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifdef CONFIG_NO_RADIUS
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
#else /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
struct hostapd_acl_query_data *query;
|
|
|
|
|
2018-02-14 14:43:56 +01:00
|
|
|
if (is_probe_req) {
|
|
|
|
/* Skip RADIUS queries for Probe Request frames to avoid
|
|
|
|
* excessive load on the authentication server. */
|
|
|
|
return HOSTAPD_ACL_ACCEPT;
|
|
|
|
};
|
|
|
|
|
Allow remote RADIUS authentication with local VLAN management
The documentation in the hostapd.conf file says that the dynamic_vlan
variable is used to control whether VLAN assignments are accepted from a
RADIUS server. The implication seems to be that a static VLAN assignment
will come from the accept_mac_file if dynamic_vlan is set to 0, and a
dynamic assignment will come from the RADIUS server if dynamic_vlan is
set to 1. Instead, I'm seeing that the static settings from the
accept_mac_file are ignored if dynamic_vlan is set to 0, but used if
dynamic_vlan is set to 1. If dynamic_vlan is set to 1 and the RADIUS
server does not provide a VLAN, then the accept_mac_file assignment is
overridden and the STA is assigned to the default non-VLANed interface.
If my understanding of the expected behavior is correct, then I believe
the problem is in ap_sta_set_vlan(). That routine checks the
dynamic_vlan setting, but has no way of determining whether the incoming
vlan_desc is static (i.e., from accept_mac_file) or dynamic (i.e., from
a RADIUS server).
I've attached a patch that gets hostapd working as I believe it's meant
to, and updates the documentation to make the implicit behavior
explicit.
The functional changes are:
- hostapd_allowed_address() will always extract the vlan_id from the
accept_macs file. It will not update the vlan_id from the RADIUS cache
if dynamic_vlan is DISABLED.
- hostapd_acl_recv_radius() will not update the cached vlan_id if
dynamic_vlan is DISABLED.
- ieee802_1x_receive_auth() will not update the vlan_id if dynamic_vlan
is DISABLED.
More cosmetic:
Most of the delta is just moving code out of ieee802_1x_receive_auth()
into a new ieee802_1x_update_vlan() routine. While I initially did this
because the new DISABLED check introduced excessive indentation, it has
the added advantage of eliminating the vlan_description allocation and
os_memset() call for all DYNAMIC_VLAN_DISABLED configs.
I've done a couple rounds of review offline with Michael Braun (who has
done much of the work in this part of the code) and incorporated his
feedback.
If dynamic_vlan=0 (disabled), vlan assignments will be managed using the
local accept_mac_file ACL file, even if a RADIUS server is being used
for user authentication. This allows us to manage users and devices
independently.
Signed-off-by: Nils Nieuwejaar <nils.nieuwejaar@gmail.com>
2018-05-30 23:09:01 +02:00
|
|
|
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
2019-04-28 13:14:57 +02:00
|
|
|
os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
|
Allow remote RADIUS authentication with local VLAN management
The documentation in the hostapd.conf file says that the dynamic_vlan
variable is used to control whether VLAN assignments are accepted from a
RADIUS server. The implication seems to be that a static VLAN assignment
will come from the accept_mac_file if dynamic_vlan is set to 0, and a
dynamic assignment will come from the RADIUS server if dynamic_vlan is
set to 1. Instead, I'm seeing that the static settings from the
accept_mac_file are ignored if dynamic_vlan is set to 0, but used if
dynamic_vlan is set to 1. If dynamic_vlan is set to 1 and the RADIUS
server does not provide a VLAN, then the accept_mac_file assignment is
overridden and the STA is assigned to the default non-VLANed interface.
If my understanding of the expected behavior is correct, then I believe
the problem is in ap_sta_set_vlan(). That routine checks the
dynamic_vlan setting, but has no way of determining whether the incoming
vlan_desc is static (i.e., from accept_mac_file) or dynamic (i.e., from
a RADIUS server).
I've attached a patch that gets hostapd working as I believe it's meant
to, and updates the documentation to make the implicit behavior
explicit.
The functional changes are:
- hostapd_allowed_address() will always extract the vlan_id from the
accept_macs file. It will not update the vlan_id from the RADIUS cache
if dynamic_vlan is DISABLED.
- hostapd_acl_recv_radius() will not update the cached vlan_id if
dynamic_vlan is DISABLED.
- ieee802_1x_receive_auth() will not update the vlan_id if dynamic_vlan
is DISABLED.
More cosmetic:
Most of the delta is just moving code out of ieee802_1x_receive_auth()
into a new ieee802_1x_update_vlan() routine. While I initially did this
because the new DISABLED check introduced excessive indentation, it has
the added advantage of eliminating the vlan_description allocation and
os_memset() call for all DYNAMIC_VLAN_DISABLED configs.
I've done a couple rounds of review offline with Michael Braun (who has
done much of the work in this part of the code) and incorporated his
feedback.
If dynamic_vlan=0 (disabled), vlan assignments will be managed using the
local accept_mac_file ACL file, even if a RADIUS server is being used
for user authentication. This allows us to manage users and devices
independently.
Signed-off-by: Nils Nieuwejaar <nils.nieuwejaar@gmail.com>
2018-05-30 23:09:01 +02:00
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
/* Check whether ACL cache has an entry for this station */
|
2019-04-28 13:14:57 +02:00
|
|
|
res = hostapd_acl_cache_get(hapd, addr, out);
|
2008-02-28 02:34:43 +01:00
|
|
|
if (res == HOSTAPD_ACL_ACCEPT ||
|
|
|
|
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
|
|
|
return res;
|
|
|
|
if (res == HOSTAPD_ACL_REJECT)
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
|
|
|
|
query = hapd->acl_queries;
|
|
|
|
while (query) {
|
Use ether_addr_equal() to compare whether two MAC addresses are equal
This was done with spatch using the following semantic patch and minor
manual edits to clean up coding style and avoid compiler warnings in
driver_wext.c:
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !os_memcmp(a, b, ETH_ALEN)
+ ether_addr_equal(a, b)
Signed-off-by: Jouni Malinen <j@w1.fi>
2024-01-13 22:15:36 +01:00
|
|
|
if (ether_addr_equal(query->addr, addr)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
/* pending query in RADIUS retransmit queue;
|
|
|
|
* do not generate a new one */
|
|
|
|
return HOSTAPD_ACL_PENDING;
|
|
|
|
}
|
|
|
|
query = query->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hapd->conf->radius->auth_server)
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
|
|
|
|
/* No entry in the cache - query external RADIUS server */
|
|
|
|
query = os_zalloc(sizeof(*query));
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!query) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_printf(MSG_ERROR, "malloc for query data failed");
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
}
|
2013-11-25 21:56:08 +01:00
|
|
|
os_get_reltime(&query->timestamp);
|
2008-02-28 02:34:43 +01:00
|
|
|
os_memcpy(query->addr, addr, ETH_ALEN);
|
|
|
|
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Failed to send Access-Request for ACL query.");
|
2008-02-28 02:34:43 +01:00
|
|
|
hostapd_acl_query_free(query);
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
}
|
|
|
|
|
2017-03-07 10:17:23 +01:00
|
|
|
query->auth_msg = os_memdup(msg, len);
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!query->auth_msg) {
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_ERROR,
|
|
|
|
"Failed to allocate memory for auth frame.");
|
2008-02-28 02:34:43 +01:00
|
|
|
hostapd_acl_query_free(query);
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
}
|
|
|
|
query->auth_msg_len = len;
|
|
|
|
query->next = hapd->acl_queries;
|
|
|
|
hapd->acl_queries = query;
|
|
|
|
|
|
|
|
/* Queued data will be processed in hostapd_acl_recv_radius()
|
|
|
|
* when RADIUS server replies to the sent Access-Request. */
|
|
|
|
return HOSTAPD_ACL_PENDING;
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return HOSTAPD_ACL_REJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2013-11-25 21:56:08 +01:00
|
|
|
static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
|
|
|
|
struct os_reltime *now)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
entry = hapd->acl_cache;
|
|
|
|
|
|
|
|
while (entry) {
|
2013-11-25 21:56:08 +01:00
|
|
|
if (os_reltime_expired(now, &entry->timestamp,
|
|
|
|
RADIUS_ACL_TIMEOUT)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
|
|
|
|
" has expired.", MAC2STR(entry->addr));
|
|
|
|
if (prev)
|
|
|
|
prev->next = entry->next;
|
|
|
|
else
|
|
|
|
hapd->acl_cache = entry->next;
|
2010-11-24 15:34:49 +01:00
|
|
|
hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
|
2008-02-28 02:34:43 +01:00
|
|
|
tmp = entry;
|
|
|
|
entry = entry->next;
|
2012-08-19 13:09:28 +02:00
|
|
|
hostapd_acl_cache_free_entry(tmp);
|
2008-02-28 02:34:43 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = entry;
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-11 17:33:48 +02:00
|
|
|
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
|
2013-11-25 21:56:08 +01:00
|
|
|
struct os_reltime *now)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
struct hostapd_acl_query_data *prev, *entry, *tmp;
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
entry = hapd->acl_queries;
|
|
|
|
|
|
|
|
while (entry) {
|
2013-11-25 21:56:08 +01:00
|
|
|
if (os_reltime_expired(now, &entry->timestamp,
|
|
|
|
RADIUS_ACL_TIMEOUT)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
|
|
|
|
" has expired.", MAC2STR(entry->addr));
|
|
|
|
if (prev)
|
|
|
|
prev->next = entry->next;
|
|
|
|
else
|
|
|
|
hapd->acl_queries = entry->next;
|
|
|
|
|
|
|
|
tmp = entry;
|
|
|
|
entry = entry->next;
|
|
|
|
hostapd_acl_query_free(tmp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = entry;
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* hostapd_acl_expire - ACL cache expiration callback
|
2015-07-20 12:39:22 +02:00
|
|
|
* @hapd: struct hostapd_data *
|
2009-01-08 15:33:00 +01:00
|
|
|
*/
|
2015-07-20 12:39:22 +02:00
|
|
|
void hostapd_acl_expire(struct hostapd_data *hapd)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
2013-11-25 21:56:08 +01:00
|
|
|
struct os_reltime now;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2013-11-25 21:56:08 +01:00
|
|
|
os_get_reltime(&now);
|
|
|
|
hostapd_acl_expire_cache(hapd, &now);
|
|
|
|
hostapd_acl_expire_queries(hapd, &now);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-25 16:41:13 +01:00
|
|
|
static void decode_tunnel_passwords(struct hostapd_data *hapd,
|
2012-11-25 16:52:56 +01:00
|
|
|
const u8 *shared_secret,
|
|
|
|
size_t shared_secret_len,
|
2012-11-25 16:41:13 +01:00
|
|
|
struct radius_msg *msg,
|
|
|
|
struct radius_msg *req,
|
|
|
|
struct hostapd_cached_radius_acl *cache)
|
|
|
|
{
|
|
|
|
int passphraselen;
|
2016-02-24 12:53:36 +01:00
|
|
|
char *passphrase;
|
2012-11-25 16:41:13 +01:00
|
|
|
size_t i;
|
|
|
|
struct hostapd_sta_wpa_psk_short *psk;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decode all tunnel passwords as PSK and save them into a linked list.
|
|
|
|
*/
|
|
|
|
for (i = 0; ; i++) {
|
|
|
|
passphrase = radius_msg_get_tunnel_password(
|
2012-11-25 16:52:56 +01:00
|
|
|
msg, &passphraselen, shared_secret, shared_secret_len,
|
2012-11-25 16:41:13 +01:00
|
|
|
req, i);
|
|
|
|
/*
|
|
|
|
* Passphrase is NULL iff there is no i-th Tunnel-Password
|
|
|
|
* attribute in msg.
|
|
|
|
*/
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!passphrase)
|
2012-11-25 16:41:13 +01:00
|
|
|
break;
|
2016-02-24 12:53:38 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Passphase should be 8..63 chars (to be hashed with SSID)
|
|
|
|
* or 64 chars hex string (no separate hashing with SSID).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (passphraselen < MIN_PASSPHRASE_LEN ||
|
|
|
|
passphraselen > MAX_PASSPHRASE_LEN + 1)
|
2016-04-07 12:30:59 +02:00
|
|
|
goto free_pass;
|
2016-02-24 12:53:38 +01:00
|
|
|
|
2012-11-25 16:41:13 +01:00
|
|
|
/*
|
|
|
|
* passphrase does not contain the NULL termination.
|
|
|
|
* Add it here as pbkdf2_sha1() requires it.
|
|
|
|
*/
|
|
|
|
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
|
2016-02-24 12:53:36 +01:00
|
|
|
if (psk) {
|
2016-02-24 12:53:38 +01:00
|
|
|
if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
|
|
|
|
(hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
|
|
|
|
hostapd_logger(hapd, cache->addr,
|
|
|
|
HOSTAPD_MODULE_RADIUS,
|
|
|
|
HOSTAPD_LEVEL_WARNING,
|
|
|
|
"invalid hex string (%d chars) in Tunnel-Password",
|
|
|
|
passphraselen);
|
|
|
|
goto skip;
|
|
|
|
} else if (passphraselen <= MAX_PASSPHRASE_LEN) {
|
|
|
|
os_memcpy(psk->passphrase, passphrase,
|
|
|
|
passphraselen);
|
|
|
|
psk->is_passphrase = 1;
|
|
|
|
}
|
2019-04-28 13:14:57 +02:00
|
|
|
psk->next = cache->info.psk;
|
|
|
|
cache->info.psk = psk;
|
2012-11-25 16:41:13 +01:00
|
|
|
psk = NULL;
|
|
|
|
}
|
2016-02-24 12:53:38 +01:00
|
|
|
skip:
|
2012-11-25 16:41:13 +01:00
|
|
|
os_free(psk);
|
2016-04-07 12:30:59 +02:00
|
|
|
free_pass:
|
2012-11-25 16:41:13 +01:00
|
|
|
os_free(passphrase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
|
|
|
|
* @msg: RADIUS response message
|
|
|
|
* @req: RADIUS request message
|
|
|
|
* @shared_secret: RADIUS shared secret
|
|
|
|
* @shared_secret_len: Length of shared_secret in octets
|
|
|
|
* @data: Context data (struct hostapd_data *)
|
|
|
|
* Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
|
|
|
|
* was processed here) or RADIUS_RX_UNKNOWN if not.
|
|
|
|
*/
|
2008-02-28 02:34:43 +01:00
|
|
|
static RadiusRxResult
|
|
|
|
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
2009-01-08 15:41:47 +01:00
|
|
|
const u8 *shared_secret, size_t shared_secret_len,
|
2008-02-28 02:34:43 +01:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = data;
|
|
|
|
struct hostapd_acl_query_data *query, *prev;
|
|
|
|
struct hostapd_cached_radius_acl *cache;
|
2019-04-28 13:14:57 +02:00
|
|
|
struct radius_sta *info;
|
2009-12-19 16:26:57 +01:00
|
|
|
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
query = hapd->acl_queries;
|
|
|
|
prev = NULL;
|
|
|
|
while (query) {
|
2009-12-19 16:26:57 +01:00
|
|
|
if (query->radius_id == hdr->identifier)
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
prev = query;
|
|
|
|
query = query->next;
|
|
|
|
}
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!query)
|
2008-02-28 02:34:43 +01:00
|
|
|
return RADIUS_RX_UNKNOWN;
|
|
|
|
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Found matching Access-Request for RADIUS message (id=%d)",
|
|
|
|
query->radius_id);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_INFO,
|
|
|
|
"Incoming RADIUS packet did not have correct authenticator - dropped");
|
2008-02-28 02:34:43 +01:00
|
|
|
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
|
|
|
}
|
|
|
|
|
2009-12-19 16:26:57 +01:00
|
|
|
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
|
|
|
|
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Unknown RADIUS message code %d to ACL query",
|
|
|
|
hdr->code);
|
2008-02-28 02:34:43 +01:00
|
|
|
return RADIUS_RX_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert Accept/Reject info into ACL cache */
|
|
|
|
cache = os_zalloc(sizeof(*cache));
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!cache) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
|
|
|
|
goto done;
|
|
|
|
}
|
2013-11-25 21:56:08 +01:00
|
|
|
os_get_reltime(&cache->timestamp);
|
2008-02-28 02:34:43 +01:00
|
|
|
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
|
2019-04-28 13:14:57 +02:00
|
|
|
info = &cache->info;
|
2009-12-19 16:26:57 +01:00
|
|
|
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
|
2012-08-19 13:09:28 +02:00
|
|
|
u8 *buf;
|
|
|
|
size_t len;
|
2011-12-11 12:01:57 +01:00
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
|
2019-04-28 13:14:57 +02:00
|
|
|
&info->session_timeout) == 0)
|
2008-02-28 02:34:43 +01:00
|
|
|
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
|
|
|
|
else
|
|
|
|
cache->accepted = HOSTAPD_ACL_ACCEPT;
|
|
|
|
|
|
|
|
if (radius_msg_get_attr_int32(
|
|
|
|
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
|
2019-04-28 13:14:57 +02:00
|
|
|
&info->acct_interim_interval) == 0 &&
|
|
|
|
info->acct_interim_interval < 60) {
|
2022-04-02 15:28:12 +02:00
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Ignored too small Acct-Interim-Interval %d for STA "
|
|
|
|
MACSTR,
|
2019-04-28 13:14:57 +02:00
|
|
|
info->acct_interim_interval,
|
2008-02-28 02:34:43 +01:00
|
|
|
MAC2STR(query->addr));
|
2019-04-28 13:14:57 +02:00
|
|
|
info->acct_interim_interval = 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
Allow remote RADIUS authentication with local VLAN management
The documentation in the hostapd.conf file says that the dynamic_vlan
variable is used to control whether VLAN assignments are accepted from a
RADIUS server. The implication seems to be that a static VLAN assignment
will come from the accept_mac_file if dynamic_vlan is set to 0, and a
dynamic assignment will come from the RADIUS server if dynamic_vlan is
set to 1. Instead, I'm seeing that the static settings from the
accept_mac_file are ignored if dynamic_vlan is set to 0, but used if
dynamic_vlan is set to 1. If dynamic_vlan is set to 1 and the RADIUS
server does not provide a VLAN, then the accept_mac_file assignment is
overridden and the STA is assigned to the default non-VLANed interface.
If my understanding of the expected behavior is correct, then I believe
the problem is in ap_sta_set_vlan(). That routine checks the
dynamic_vlan setting, but has no way of determining whether the incoming
vlan_desc is static (i.e., from accept_mac_file) or dynamic (i.e., from
a RADIUS server).
I've attached a patch that gets hostapd working as I believe it's meant
to, and updates the documentation to make the implicit behavior
explicit.
The functional changes are:
- hostapd_allowed_address() will always extract the vlan_id from the
accept_macs file. It will not update the vlan_id from the RADIUS cache
if dynamic_vlan is DISABLED.
- hostapd_acl_recv_radius() will not update the cached vlan_id if
dynamic_vlan is DISABLED.
- ieee802_1x_receive_auth() will not update the vlan_id if dynamic_vlan
is DISABLED.
More cosmetic:
Most of the delta is just moving code out of ieee802_1x_receive_auth()
into a new ieee802_1x_update_vlan() routine. While I initially did this
because the new DISABLED check introduced excessive indentation, it has
the added advantage of eliminating the vlan_description allocation and
os_memset() call for all DYNAMIC_VLAN_DISABLED configs.
I've done a couple rounds of review offline with Michael Braun (who has
done much of the work in this part of the code) and incorporated his
feedback.
If dynamic_vlan=0 (disabled), vlan assignments will be managed using the
local accept_mac_file ACL file, even if a RADIUS server is being used
for user authentication. This allows us to manage users and devices
independently.
Signed-off-by: Nils Nieuwejaar <nils.nieuwejaar@gmail.com>
2018-05-30 23:09:01 +02:00
|
|
|
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
|
2019-04-28 13:14:57 +02:00
|
|
|
info->vlan_id.notempty = !!radius_msg_get_vlanid(
|
|
|
|
msg, &info->vlan_id.untagged,
|
|
|
|
MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
|
2011-12-11 12:01:57 +01:00
|
|
|
|
2012-11-25 16:52:56 +01:00
|
|
|
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
|
|
|
|
msg, req, cache);
|
2012-11-25 16:41:13 +01:00
|
|
|
|
2012-08-19 13:09:28 +02:00
|
|
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
|
|
|
|
&buf, &len, NULL) == 0) {
|
2019-04-28 13:14:57 +02:00
|
|
|
info->identity = os_zalloc(len + 1);
|
|
|
|
if (info->identity)
|
|
|
|
os_memcpy(info->identity, buf, len);
|
2012-08-19 13:09:28 +02:00
|
|
|
}
|
|
|
|
if (radius_msg_get_attr_ptr(
|
|
|
|
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
|
|
|
|
&buf, &len, NULL) == 0) {
|
2019-04-28 13:14:57 +02:00
|
|
|
info->radius_cui = os_zalloc(len + 1);
|
|
|
|
if (info->radius_cui)
|
|
|
|
os_memcpy(info->radius_cui, buf, len);
|
2012-08-19 13:09:28 +02:00
|
|
|
}
|
2011-12-11 12:01:57 +01:00
|
|
|
|
|
|
|
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
|
2019-04-28 13:14:57 +02:00
|
|
|
!info->psk)
|
2011-12-11 12:01:57 +01:00
|
|
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
2015-04-14 16:56:38 +02:00
|
|
|
|
2019-04-28 13:14:57 +02:00
|
|
|
if (info->vlan_id.notempty &&
|
|
|
|
!hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
|
2015-04-14 16:56:38 +02:00
|
|
|
hostapd_logger(hapd, query->addr,
|
|
|
|
HOSTAPD_MODULE_RADIUS,
|
|
|
|
HOSTAPD_LEVEL_INFO,
|
2016-01-21 14:51:57 +01:00
|
|
|
"Invalid VLAN %d%s received from RADIUS server",
|
2019-04-28 13:14:57 +02:00
|
|
|
info->vlan_id.untagged,
|
|
|
|
info->vlan_id.tagged[0] ? "+" : "");
|
|
|
|
os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
|
2015-04-14 16:56:38 +02:00
|
|
|
}
|
|
|
|
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
2019-04-28 13:14:57 +02:00
|
|
|
!info->vlan_id.notempty)
|
2015-04-14 16:56:38 +02:00
|
|
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
2008-02-28 02:34:43 +01:00
|
|
|
} else
|
|
|
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
|
|
|
cache->next = hapd->acl_cache;
|
|
|
|
hapd->acl_cache = cache;
|
|
|
|
|
2022-04-02 12:12:43 +02:00
|
|
|
if (query->radius_psk) {
|
|
|
|
struct sta_info *sta;
|
|
|
|
bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
|
|
|
|
|
|
|
|
sta = ap_get_sta(hapd, query->addr);
|
|
|
|
if (!sta || !sta->wpa_sm) {
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"No STA/SM entry found for the RADIUS PSK response");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#ifdef NEED_AP_MLME
|
|
|
|
if (success &&
|
|
|
|
(ieee802_11_set_radius_info(hapd, sta, cache->accepted,
|
|
|
|
info) < 0 ||
|
|
|
|
ap_sta_bind_vlan(hapd, sta) < 0))
|
|
|
|
success = false;
|
|
|
|
#endif /* NEED_AP_MLME */
|
|
|
|
wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
|
|
|
|
} else {
|
2008-03-12 10:43:55 +01:00
|
|
|
#ifdef CONFIG_DRIVER_RADIUS_ACL
|
2022-04-02 12:12:43 +02:00
|
|
|
hostapd_drv_set_radius_acl_auth(hapd, query->addr,
|
|
|
|
cache->accepted,
|
|
|
|
info->session_timeout);
|
2008-03-12 10:43:55 +01:00
|
|
|
#else /* CONFIG_DRIVER_RADIUS_ACL */
|
2009-08-14 19:01:41 +02:00
|
|
|
#ifdef NEED_AP_MLME
|
2022-04-02 12:12:43 +02:00
|
|
|
/* Re-send original authentication frame for 802.11 processing
|
|
|
|
*/
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Re-sending authentication frame after successful RADIUS ACL query");
|
|
|
|
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
|
|
|
|
NULL);
|
2009-08-14 19:01:41 +02:00
|
|
|
#endif /* NEED_AP_MLME */
|
2008-03-12 10:43:55 +01:00
|
|
|
#endif /* CONFIG_DRIVER_RADIUS_ACL */
|
2022-04-02 12:12:43 +02:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
done:
|
2022-04-02 15:29:31 +02:00
|
|
|
if (!prev)
|
2008-02-28 02:34:43 +01:00
|
|
|
hapd->acl_queries = query->next;
|
|
|
|
else
|
|
|
|
prev->next = query->next;
|
|
|
|
|
|
|
|
hostapd_acl_query_free(query);
|
|
|
|
|
|
|
|
return RADIUS_RX_PROCESSED;
|
|
|
|
}
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* hostapd_acl_init: Initialize IEEE 802.11 ACL
|
|
|
|
* @hapd: hostapd BSS data
|
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*/
|
2008-02-28 02:34:43 +01:00
|
|
|
int hostapd_acl_init(struct hostapd_data *hapd)
|
|
|
|
{
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2008-02-28 02:34:43 +01:00
|
|
|
if (radius_client_register(hapd->radius, RADIUS_AUTH,
|
|
|
|
hostapd_acl_recv_radius, hapd))
|
|
|
|
return -1;
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
|
|
|
|
* @hapd: hostapd BSS data
|
|
|
|
*/
|
2008-02-28 02:34:43 +01:00
|
|
|
void hostapd_acl_deinit(struct hostapd_data *hapd)
|
|
|
|
{
|
|
|
|
struct hostapd_acl_query_data *query, *prev;
|
|
|
|
|
2009-01-08 18:15:25 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2008-02-28 02:34:43 +01:00
|
|
|
hostapd_acl_cache_free(hapd->acl_cache);
|
2017-02-08 16:37:50 +01:00
|
|
|
hapd->acl_cache = NULL;
|
2009-01-08 18:15:25 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
query = hapd->acl_queries;
|
2017-02-08 16:37:50 +01:00
|
|
|
hapd->acl_queries = NULL;
|
2008-02-28 02:34:43 +01:00
|
|
|
while (query) {
|
|
|
|
prev = query;
|
|
|
|
query = query->next;
|
|
|
|
hostapd_acl_query_free(prev);
|
|
|
|
}
|
|
|
|
}
|
2012-11-25 17:01:55 +01:00
|
|
|
|
|
|
|
|
2019-04-28 13:14:57 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-25 17:01:55 +01:00
|
|
|
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
|
|
|
|
{
|
2016-02-24 12:53:37 +01:00
|
|
|
if (psk && psk->ref) {
|
|
|
|
/* This will be freed when the last reference is dropped. */
|
|
|
|
psk->ref--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-25 17:01:55 +01:00
|
|
|
while (psk) {
|
|
|
|
struct hostapd_sta_wpa_psk_short *prev = psk;
|
|
|
|
psk = psk->next;
|
2022-02-26 12:39:35 +01:00
|
|
|
bin_clear_free(prev, sizeof(*prev));
|
2012-11-25 17:01:55 +01:00
|
|
|
}
|
|
|
|
}
|
2022-04-02 12:12:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_NO_RADIUS
|
|
|
|
void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
|
|
|
|
int key_mgmt, const u8 *anonce,
|
|
|
|
const u8 *eapol, size_t eapol_len)
|
|
|
|
{
|
|
|
|
struct hostapd_acl_query_data *query;
|
|
|
|
|
|
|
|
query = os_zalloc(sizeof(*query));
|
|
|
|
if (!query)
|
|
|
|
return;
|
|
|
|
|
|
|
|
query->radius_psk = true;
|
|
|
|
query->akm = key_mgmt;
|
|
|
|
os_get_reltime(&query->timestamp);
|
|
|
|
os_memcpy(query->addr, addr, ETH_ALEN);
|
2022-04-15 16:36:25 +02:00
|
|
|
if (anonce)
|
|
|
|
query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
|
|
|
|
if (eapol) {
|
|
|
|
query->eapol = os_memdup(eapol, eapol_len);
|
|
|
|
query->eapol_len = eapol_len;
|
|
|
|
}
|
2022-04-02 12:12:43 +02:00
|
|
|
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"Failed to send Access-Request for RADIUS PSK/ACL query");
|
|
|
|
hostapd_acl_query_free(query);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
query->next = hapd->acl_queries;
|
|
|
|
hapd->acl_queries = query;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NO_RADIUS */
|