Allow remote RADIUS authentication with local VLAN management

Message ID 20180419233549.30190-1-nils.nieuwejaar@gmail.com
State New
Headers show
Series
  • Allow remote RADIUS authentication with local VLAN management
Related show

Commit Message

Nils Nieuwejaar April 19, 2018, 11:35 p.m.
If dynamic_vlan=0 (disabled), then vlan assignments will be managed
using the local accept_mac_file ACL file, even if a RADIUS server if
being used for user authentication.  This allows us to manage users and
devices independently.

Signed-off-by: Nils Nieuwejaar <nils.nieuwejaar@gmail.com>
---
 hostapd/hostapd.conf     |  2 +-
 src/ap/ieee802_11_auth.c | 17 +++++----
 src/ap/ieee802_1x.c      | 90 +++++++++++++++++++++++++-----------------------
 src/ap/sta_info.c        |  3 --
 4 files changed, 58 insertions(+), 54 deletions(-)

Patch

diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 220625651..7f13b147d 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1104,7 +1104,7 @@  own_ip_addr=127.0.0.1
 # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
 # VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
 # be used to set static client MAC address to VLAN ID mapping.
-# 0 = disabled (default)
+# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
 # 1 = option; use default interface if RADIUS server does not include VLAN ID
 # 2 = required; reject authentication if RADIUS server does not include VLAN ID
 #dynamic_vlan=0
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 5cb7fb145..b2ea12c3a 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -289,6 +289,9 @@  int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			return HOSTAPD_ACL_ACCEPT;
 		};
 
+		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			vlan_id = NULL;
+
 		/* 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,
@@ -574,12 +577,14 @@  hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 			cache->acct_interim_interval = 0;
 		}
 
-		notempty = &cache->vlan_id.notempty;
-		untagged = &cache->vlan_id.untagged;
-		tagged = cache->vlan_id.tagged;
-		*notempty = !!radius_msg_get_vlanid(msg, untagged,
-						    MAX_NUM_TAGGED_VLAN,
-						    tagged);
+		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
+			notempty = &cache->vlan_id.notempty;
+			untagged = &cache->vlan_id.untagged;
+			tagged = cache->vlan_id.tagged;
+			*notempty = !!radius_msg_get_vlanid(msg, untagged,
+							    MAX_NUM_TAGGED_VLAN,
+							    tagged);
+		}
 
 		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
 					msg, req, cache);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 4fcccce72..ffff58d55 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1683,6 +1683,49 @@  ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
 }
 
 
+#ifndef CONFIG_NO_VLAN
+static int
+ieee802_1x_update_vlan(struct radius_msg *msg,
+		       struct hostapd_data *hapd,
+		       struct sta_info *sta)
+{
+	struct vlan_description vlan_desc;
+	int *untagged, *tagged, *notempty;
+
+	os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+	notempty = &vlan_desc.notempty;
+	untagged = &vlan_desc.untagged;
+	tagged = vlan_desc.tagged;
+	*notempty = !!radius_msg_get_vlanid(msg, untagged, MAX_NUM_TAGGED_VLAN,
+					    tagged);
+
+	if (vlan_desc.notempty &&
+	    !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+		sta->eapol_sm->authFail = TRUE;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO,
+			       "Invalid VLAN %d%s received from RADIUS server",
+			       vlan_desc.untagged,
+			       vlan_desc.tagged[0] ? "+" : "");
+		os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+		ap_sta_set_vlan(hapd, sta, &vlan_desc);
+		return -1;
+	}
+
+	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+	    !vlan_desc.notempty) {
+		sta->eapol_sm->authFail = TRUE;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_INFO, "authentication server did "
+			       "not include required VLAN ID in Access-Accept");
+		return -1;
+	}
+
+	return (ap_sta_set_vlan(hapd, sta, &vlan_desc));
+}
+#endif /* CONFIG_NO_VLAN */
+
+
 /**
  * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
  * @msg: RADIUS response message
@@ -1705,12 +1748,6 @@  ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
 	struct eapol_state_machine *sm;
 	int override_eapReq = 0;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-	struct vlan_description vlan_desc;
-#ifndef CONFIG_NO_VLAN
-	int *untagged, *tagged, *notempty;
-#endif /* CONFIG_NO_VLAN */
-
-	os_memset(&vlan_desc, 0, sizeof(vlan_desc));
 
 	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
 	if (sm == NULL) {
@@ -1775,56 +1812,21 @@  ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
 	switch (hdr->code) {
 	case RADIUS_CODE_ACCESS_ACCEPT:
 #ifndef CONFIG_NO_VLAN
-		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
-			notempty = &vlan_desc.notempty;
-			untagged = &vlan_desc.untagged;
-			tagged = vlan_desc.tagged;
-			*notempty = !!radius_msg_get_vlanid(msg, untagged,
-							    MAX_NUM_TAGGED_VLAN,
-							    tagged);
-		}
-
-		if (vlan_desc.notempty &&
-		    !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
-			sta->eapol_sm->authFail = TRUE;
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_INFO,
-				       "Invalid VLAN %d%s received from RADIUS server",
-				       vlan_desc.untagged,
-				       vlan_desc.tagged[0] ? "+" : "");
-			os_memset(&vlan_desc, 0, sizeof(vlan_desc));
-			ap_sta_set_vlan(hapd, sta, &vlan_desc);
-			break;
-		}
-
-		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
-		    !vlan_desc.notempty) {
-			sta->eapol_sm->authFail = TRUE;
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE8021X,
-				       HOSTAPD_LEVEL_INFO, "authentication "
-				       "server did not include required VLAN "
-				       "ID in Access-Accept");
-			break;
-		}
-#endif /* CONFIG_NO_VLAN */
-
-		if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+		    ieee802_1x_update_vlan(msg, hapd, sta) < 0)
 			break;
 
-#ifndef CONFIG_NO_VLAN
 		if (sta->vlan_id > 0) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
 				       "VLAN ID %d", sta->vlan_id);
 		}
-#endif /* CONFIG_NO_VLAN */
 
 		if ((sta->flags & WLAN_STA_ASSOC) &&
 		    ap_sta_bind_vlan(hapd, sta) < 0)
 			break;
+#endif /* CONFIG_NO_VLAN */
 
 		sta->session_timeout_set = !!session_timeout_set;
 		os_get_reltime(&sta->session_timeout);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index cb9be2832..94833ee1e 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -893,9 +893,6 @@  int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
 	struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
 	int old_vlan_id, vlan_id = 0, ret = 0;
 
-	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-		vlan_desc = NULL;
-
 	/* Check if there is something to do */
 	if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
 		/* This sta is lacking its own vif */