mirror of
				https://github.com/optim-enterprises-bv/openwrt-ipq.git
				synced 2025-10-31 18:28:28 +00:00 
			
		
		
		
	hostapd: add support for authenticating with multiple PSKs via ubus helper
Also supports assigning a VLAN ID based on the PSK Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
		| @@ -890,6 +890,9 @@ let main_obj = { | ||||
| 			hostapd.printf(`Set new config for phy ${phy}: ${file}`); | ||||
| 			iface_set_config(phy, config); | ||||
|  | ||||
| 			if (hostapd.data.auth_obj) | ||||
| 				hostapd.data.auth_obj.notify("reload", { phy }); | ||||
|  | ||||
| 			return { | ||||
| 				pid: hostapd.getpid() | ||||
| 			}; | ||||
| @@ -954,6 +957,10 @@ let main_obj = { | ||||
|  | ||||
| hostapd.data.ubus = ubus; | ||||
| hostapd.data.obj = ubus.publish("hostapd", main_obj); | ||||
|  | ||||
|  | ||||
| let auth_obj = {}; | ||||
| hostapd.data.auth_obj = ubus.publish("hostapd-auth", auth_obj); | ||||
| hostapd.udebug_set("hostapd", hostapd.data.ubus); | ||||
|  | ||||
| function bss_event(type, name, data) { | ||||
| @@ -980,5 +987,25 @@ return { | ||||
| 	}, | ||||
| 	bss_remove: function(phy, name, obj) { | ||||
| 		bss_event("remove", name); | ||||
| 	} | ||||
| 	}, | ||||
| 	sta_auth: function(iface, sta) { | ||||
| 		let msg = { iface, sta }; | ||||
| 		let ret = {}; | ||||
| 		let data_cb = (type, data) => { | ||||
| 			ret = { ...ret, ...data }; | ||||
| 		}; | ||||
| 		if (hostapd.data.auth_obj) | ||||
| 			hostapd.data.auth_obj.notify("sta_auth", msg, data_cb, null, null, 1000); | ||||
| 		return ret; | ||||
| 	}, | ||||
| 	sta_connected: function(iface, sta, data) { | ||||
| 		let msg = { iface, sta, ...data }; | ||||
| 		let ret = {}; | ||||
| 		let data_cb = (type, data) => { | ||||
| 			ret = { ...ret, ...data }; | ||||
| 		}; | ||||
| 		if (hostapd.data.auth_obj) | ||||
| 			hostapd.data.auth_obj.notify("sta_connected", msg, data_cb, null, null, 1000); | ||||
| 		return ret; | ||||
| 	}, | ||||
| }; | ||||
|   | ||||
| @@ -15,6 +15,6 @@ | ||||
| 		} | ||||
| 	}, | ||||
| 	"subscribe": [ "udebug" ], | ||||
| 	"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ], | ||||
| 	"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*", "hostapd-auth" ], | ||||
| 	"send": [ "bss.*", "wps_credentials" ] | ||||
| } | ||||
|   | ||||
| @@ -704,3 +704,138 @@ as adding/removing interfaces. | ||||
|  #ifdef CONFIG_MATCH_IFACE | ||||
|  	int matched; | ||||
|  #endif /* CONFIG_MATCH_IFACE */ | ||||
| --- a/src/ap/ieee802_11.c | ||||
| +++ b/src/ap/ieee802_11.c | ||||
| @@ -555,12 +555,17 @@ const char * sae_get_password(struct hos | ||||
|  			      struct sae_pt **s_pt, | ||||
|  			      const struct sae_pk **s_pk) | ||||
|  { | ||||
| +	struct hostapd_bss_config *conf = hapd->conf; | ||||
| +	struct hostapd_ssid *ssid = &conf->ssid; | ||||
|  	const char *password = NULL; | ||||
| -	struct sae_password_entry *pw; | ||||
| +	struct sae_password_entry *pw = NULL; | ||||
|  	struct sae_pt *pt = NULL; | ||||
|  	const struct sae_pk *pk = NULL; | ||||
|  	struct hostapd_sta_wpa_psk_short *psk = NULL; | ||||
|   | ||||
| +	if (sta && sta->use_sta_psk) | ||||
| +		goto use_sta_psk; | ||||
| + | ||||
|  	for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { | ||||
|  		if (!is_broadcast_ether_addr(pw->peer_addr) && | ||||
|  		    (!sta || | ||||
| @@ -582,12 +587,28 @@ const char * sae_get_password(struct hos | ||||
|  		pt = hapd->conf->ssid.pt; | ||||
|  	} | ||||
|   | ||||
| +use_sta_psk: | ||||
|  	if (!password && sta) { | ||||
|  		for (psk = sta->psk; psk; psk = psk->next) { | ||||
| -			if (psk->is_passphrase) { | ||||
| -				password = psk->passphrase; | ||||
| +			if (!psk->is_passphrase) | ||||
| +				continue; | ||||
| + | ||||
| +			password = psk->passphrase; | ||||
| +			if (!sta->use_sta_psk) | ||||
| +				break; | ||||
| + | ||||
| +			if (sta->sae_pt) { | ||||
| +				pt = sta->sae_pt; | ||||
|  				break; | ||||
|  			} | ||||
| + | ||||
| +			pt = sae_derive_pt(conf->sae_groups, ssid->ssid, | ||||
| +					   ssid->ssid_len, | ||||
| +					   (const u8 *) password, | ||||
| +					   os_strlen(password), | ||||
| +					   NULL); | ||||
| +			sta->sae_pt = pt; | ||||
| +			break; | ||||
|  		} | ||||
|  	} | ||||
|   | ||||
| @@ -3229,6 +3250,12 @@ static void handle_auth(struct hostapd_d | ||||
|  		goto fail; | ||||
|  	} | ||||
|   | ||||
| +	res = hostapd_ucode_sta_auth(hapd, sta); | ||||
| +	if (res) { | ||||
| +		resp = res; | ||||
| +		goto fail; | ||||
| +	} | ||||
| + | ||||
|  	sta->flags &= ~WLAN_STA_PREAUTH; | ||||
|  	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); | ||||
|   | ||||
| --- a/src/ap/sta_info.c | ||||
| +++ b/src/ap/sta_info.c | ||||
| @@ -474,6 +474,9 @@ void ap_free_sta(struct hostapd_data *ha | ||||
|  	forced_memzero(sta->last_tk, WPA_TK_MAX_LEN); | ||||
|  #endif /* CONFIG_TESTING_OPTIONS */ | ||||
|   | ||||
| +	if (sta->sae_pt) | ||||
| +		sae_deinit_pt(sta->sae_pt); | ||||
| + | ||||
|  	os_free(sta); | ||||
|  } | ||||
|   | ||||
| @@ -1507,6 +1510,8 @@ void ap_sta_set_authorized_event(struct | ||||
|  #endif /* CONFIG_P2P */ | ||||
|  	const u8 *ip_ptr = NULL; | ||||
|   | ||||
| +	if (authorized) | ||||
| +		hostapd_ucode_sta_connected(hapd, sta); | ||||
|  #ifdef CONFIG_P2P | ||||
|  	if (hapd->p2p_group == NULL) { | ||||
|  		if (sta->p2p_ie != NULL && | ||||
| --- a/src/ap/sta_info.h | ||||
| +++ b/src/ap/sta_info.h | ||||
| @@ -180,6 +180,9 @@ struct sta_info { | ||||
|  	int vlan_id_bound; /* updated by ap_sta_bind_vlan() */ | ||||
|  	 /* PSKs from RADIUS authentication server */ | ||||
|  	struct hostapd_sta_wpa_psk_short *psk; | ||||
| +	struct sae_pt *sae_pt; | ||||
| +	int use_sta_psk; | ||||
| +	int psk_idx; | ||||
|   | ||||
|  	char *identity; /* User-Name from RADIUS */ | ||||
|  	char *radius_cui; /* Chargeable-User-Identity from RADIUS */ | ||||
| --- a/src/ap/wpa_auth_glue.c | ||||
| +++ b/src/ap/wpa_auth_glue.c | ||||
| @@ -400,6 +400,7 @@ static const u8 * hostapd_wpa_auth_get_p | ||||
|  	struct sta_info *sta = ap_get_sta(hapd, addr); | ||||
|  	const u8 *psk; | ||||
|   | ||||
| +	sta->psk_idx = 0; | ||||
|  	if (vlan_id) | ||||
|  		*vlan_id = 0; | ||||
|  	if (psk_len) | ||||
| @@ -446,13 +447,16 @@ static const u8 * hostapd_wpa_auth_get_p | ||||
|  	 * returned psk which should not be returned again. | ||||
|  	 * logic list (all hostapd_get_psk; all sta->psk) | ||||
|  	 */ | ||||
| +	if (sta && sta->use_sta_psk) | ||||
| +		psk = NULL; | ||||
|  	if (sta && sta->psk && !psk) { | ||||
|  		struct hostapd_sta_wpa_psk_short *pos; | ||||
| +		int psk_idx = 1; | ||||
|   | ||||
|  		if (vlan_id) | ||||
|  			*vlan_id = 0; | ||||
|  		psk = sta->psk->psk; | ||||
| -		for (pos = sta->psk; pos; pos = pos->next) { | ||||
| +		for (pos = sta->psk; pos; pos = pos->next, psk_idx++) { | ||||
|  			if (pos->is_passphrase) { | ||||
|  				if (pbkdf2_sha1(pos->passphrase, | ||||
|  						hapd->conf->ssid.ssid, | ||||
| @@ -469,6 +473,8 @@ static const u8 * hostapd_wpa_auth_get_p | ||||
|  				break; | ||||
|  			} | ||||
|  		} | ||||
| +		if (psk) | ||||
| +			sta->psk_idx = psk_idx; | ||||
|  	} | ||||
|  	return psk; | ||||
|  } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "ap_drv_ops.h" | ||||
| #include "dfs.h" | ||||
| #include "acs.h" | ||||
| #include "ieee802_11_auth.h" | ||||
| #include <libubox/uloop.h> | ||||
|  | ||||
| static uc_resource_type_t *global_type, *bss_type, *iface_type; | ||||
| @@ -711,6 +712,110 @@ out: | ||||
| 	return ret ? NULL : ucv_boolean_new(true); | ||||
| } | ||||
|  | ||||
| int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta) | ||||
| { | ||||
| 	char addr[sizeof(MACSTR)]; | ||||
| 	uc_value_t *val, *cur; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	if (wpa_ucode_call_prepare("sta_auth")) | ||||
| 		return 0; | ||||
|  | ||||
| 	uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface))); | ||||
|  | ||||
| 	snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sta->addr)); | ||||
| 	val = ucv_string_new(addr); | ||||
| 	uc_value_push(ucv_get(val)); | ||||
|  | ||||
| 	val = wpa_ucode_call(2); | ||||
|  | ||||
| 	cur = ucv_object_get(val, "psk", NULL); | ||||
| 	if (ucv_type(cur) == UC_ARRAY) { | ||||
| 		struct hostapd_sta_wpa_psk_short *p, **next; | ||||
| 		size_t len = ucv_array_length(cur); | ||||
|  | ||||
| 		next = &sta->psk; | ||||
| 		hostapd_free_psk_list(*next); | ||||
| 		*next = NULL; | ||||
|  | ||||
| 		for (size_t i = 0; i < len; i++) { | ||||
| 			uc_value_t *cur_psk; | ||||
| 			const char *str; | ||||
| 			size_t str_len; | ||||
|  | ||||
| 			cur_psk = ucv_array_get(cur, i); | ||||
| 			str = ucv_string_get(cur_psk); | ||||
| 			str_len = strlen(str); | ||||
| 			if (!str || str_len < 8 || str_len > 64) | ||||
| 				continue; | ||||
|  | ||||
| 			p = os_zalloc(sizeof(*p)); | ||||
| 			if (len == 64) { | ||||
| 				if (hexstr2bin(str, p->psk, PMK_LEN) < 0) { | ||||
| 					free(p); | ||||
| 					continue; | ||||
| 				} | ||||
| 			} else { | ||||
| 				p->is_passphrase = 1; | ||||
| 				memcpy(p->passphrase, str, str_len + 1); | ||||
| 			} | ||||
|  | ||||
| 			*next = p; | ||||
| 			next = &p->next; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	cur = ucv_object_get(val, "force_psk", NULL); | ||||
| 	sta->use_sta_psk = ucv_is_truish(cur); | ||||
|  | ||||
| 	cur = ucv_object_get(val, "status", NULL); | ||||
| 	if (ucv_type(cur) == UC_INTEGER) | ||||
| 		ret = ucv_int64_get(cur); | ||||
|  | ||||
| 	ucv_put(val); | ||||
| 	ucv_gc(vm); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta) | ||||
| { | ||||
| 	char addr[sizeof(MACSTR)]; | ||||
| 	uc_value_t *val, *cur; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	if (wpa_ucode_call_prepare("sta_connected")) | ||||
| 		return; | ||||
|  | ||||
| 	uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface))); | ||||
|  | ||||
| 	snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sta->addr)); | ||||
| 	val = ucv_string_new(addr); | ||||
| 	uc_value_push(ucv_get(val)); | ||||
|  | ||||
| 	val = ucv_object_new(vm); | ||||
| 	if (sta->psk_idx) | ||||
| 		ucv_object_add(val, "psk_idx", ucv_int64_new(sta->psk_idx - 1)); | ||||
| 	uc_value_push(ucv_get(val)); | ||||
|  | ||||
| 	val = wpa_ucode_call(3); | ||||
| 	if (ucv_type(val) != UC_OBJECT) | ||||
| 		goto out; | ||||
|  | ||||
| 	cur = ucv_object_get(val, "vlan", NULL); | ||||
| 	if (ucv_type(cur) == UC_INTEGER) { | ||||
| 		struct vlan_description vdesc = { | ||||
| 			.notempty = 1, | ||||
| 			.untagged = ucv_int64_get(cur), | ||||
| 		}; | ||||
|  | ||||
| 		ap_sta_set_vlan(hapd, sta, &vdesc); | ||||
| 		ap_sta_bind_vlan(hapd, sta); | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	ucv_put(val); | ||||
| } | ||||
|  | ||||
| int hostapd_ucode_init(struct hapd_interfaces *ifaces) | ||||
| { | ||||
|   | ||||
| @@ -25,6 +25,8 @@ void hostapd_ucode_free(void); | ||||
| void hostapd_ucode_free_iface(struct hostapd_iface *iface); | ||||
| void hostapd_ucode_free_bss(struct hostapd_data *hapd); | ||||
| void hostapd_ucode_bss_cb(struct hostapd_data *hapd, const char *type); | ||||
| int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta); | ||||
| void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta); | ||||
|  | ||||
| #ifdef CONFIG_APUP | ||||
| void hostapd_ucode_apup_newpeer(struct hostapd_data *hapd, const char *ifname); | ||||
| @@ -45,6 +47,13 @@ static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface) | ||||
| static inline void hostapd_ucode_bss_cb(struct hostapd_data *hapd, const char *type) | ||||
| { | ||||
| } | ||||
| static inline int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta) | ||||
| { | ||||
| } | ||||
| static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd) | ||||
| { | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau