mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-30 18:07:52 +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:
		 Felix Fietkau
					Felix Fietkau
				
			
				
					committed by
					
						 John Crispin
						John Crispin
					
				
			
			
				
	
			
			
			 John Crispin
						John Crispin
					
				
			
						parent
						
							b5048d8305
						
					
				
				
					commit
					6afc11838e
				
			| @@ -833,6 +833,8 @@ let main_obj = { | |||||||
| 			hostapd.printf(`Set new config for phy ${phy}: ${file}`); | 			hostapd.printf(`Set new config for phy ${phy}: ${file}`); | ||||||
| 			iface_set_config(phy, config); | 			iface_set_config(phy, config); | ||||||
|  |  | ||||||
|  | 			hostapd.data.auth_obj.notify("reload", { phy }); | ||||||
|  |  | ||||||
| 			return { | 			return { | ||||||
| 				pid: hostapd.getpid() | 				pid: hostapd.getpid() | ||||||
| 			}; | 			}; | ||||||
| @@ -872,6 +874,9 @@ let main_obj = { | |||||||
| hostapd.data.ubus = ubus; | hostapd.data.ubus = ubus; | ||||||
| hostapd.data.obj = ubus.publish("hostapd", main_obj); | hostapd.data.obj = ubus.publish("hostapd", main_obj); | ||||||
|  |  | ||||||
|  | let auth_obj = {}; | ||||||
|  | hostapd.data.auth_obj = ubus.publish("hostapd-auth", auth_obj); | ||||||
|  |  | ||||||
| function bss_event(type, name, data) { | function bss_event(type, name, data) { | ||||||
| 	let ubus = hostapd.data.ubus; | 	let ubus = hostapd.data.ubus; | ||||||
|  |  | ||||||
| @@ -901,5 +906,23 @@ return { | |||||||
| 	}, | 	}, | ||||||
| 	bss_remove: function(name, obj) { | 	bss_remove: function(name, obj) { | ||||||
| 		bss_event("remove", name); | 		bss_event("remove", name); | ||||||
| 	} | 	}, | ||||||
|  | 	sta_auth: function(iface, sta) { | ||||||
|  | 		let msg = { iface, sta }; | ||||||
|  | 		let ret = {}; | ||||||
|  | 		let data_cb = (type, data) => { | ||||||
|  | 			ret = { ...ret, ...data }; | ||||||
|  | 		}; | ||||||
|  | 		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 }; | ||||||
|  | 		}; | ||||||
|  | 		hostapd.data.auth_obj.notify("sta_connected", msg, data_cb, null, null, 1000); | ||||||
|  | 		return ret; | ||||||
|  | 	}, | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -14,6 +14,6 @@ | |||||||
| 			"methods": [ "request" ] | 			"methods": [ "request" ] | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ], | 	"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*", "hostapd-auth" ], | ||||||
| 	"send": [ "bss.*", "wps_credentials" ] | 	"send": [ "bss.*", "wps_credentials" ] | ||||||
| } | } | ||||||
|   | |||||||
| @@ -587,7 +587,7 @@ | |||||||
|  	.sta_add = wpa_driver_nl80211_sta_add, |  	.sta_add = wpa_driver_nl80211_sta_add, | ||||||
| --- a/src/ap/ucode.c | --- a/src/ap/ucode.c | ||||||
| +++ b/src/ap/ucode.c | +++ b/src/ap/ucode.c | ||||||
| @@ -255,6 +255,7 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, s | @@ -256,6 +256,7 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, s | ||||||
|   |   | ||||||
|  	hostapd_setup_bss(hapd, hapd == iface->bss[0], true); |  	hostapd_setup_bss(hapd, hapd == iface->bss[0], true); | ||||||
|  	hostapd_ucode_update_interfaces(); |  	hostapd_ucode_update_interfaces(); | ||||||
| @@ -595,7 +595,7 @@ | |||||||
|   |   | ||||||
|  done: |  done: | ||||||
|  	ret = 0; |  	ret = 0; | ||||||
| @@ -375,6 +376,7 @@ uc_hostapd_iface_add_bss(uc_vm_t *vm, si | @@ -376,6 +377,7 @@ uc_hostapd_iface_add_bss(uc_vm_t *vm, si | ||||||
|  	conf->bss[idx] = NULL; |  	conf->bss[idx] = NULL; | ||||||
|  	ret = hostapd_ucode_bss_get_uval(hapd); |  	ret = hostapd_ucode_bss_get_uval(hapd); | ||||||
|  	hostapd_ucode_update_interfaces(); |  	hostapd_ucode_update_interfaces(); | ||||||
| @@ -603,7 +603,7 @@ | |||||||
|  	goto out; |  	goto out; | ||||||
|   |   | ||||||
|  deinit_ctrl: |  deinit_ctrl: | ||||||
| @@ -602,6 +604,7 @@ out: | @@ -603,6 +605,7 @@ out: | ||||||
|   |   | ||||||
|  		ieee802_11_set_beacon(hapd); |  		ieee802_11_set_beacon(hapd); | ||||||
|  	} |  	} | ||||||
| @@ -611,7 +611,7 @@ | |||||||
|   |   | ||||||
|  	return ucv_boolean_new(true); |  	return ucv_boolean_new(true); | ||||||
|  } |  } | ||||||
| @@ -693,6 +696,7 @@ uc_hostapd_bss_rename(uc_vm_t *vm, size_ | @@ -694,6 +697,7 @@ uc_hostapd_bss_rename(uc_vm_t *vm, size_ | ||||||
|  	hostapd_ubus_add_bss(hapd); |  	hostapd_ubus_add_bss(hapd); | ||||||
|   |   | ||||||
|  	hostapd_ucode_update_interfaces(); |  	hostapd_ucode_update_interfaces(); | ||||||
| @@ -619,3 +619,146 @@ | |||||||
|  out: |  out: | ||||||
|  	if (interfaces->ctrl_iface_init) |  	if (interfaces->ctrl_iface_init) | ||||||
|  		interfaces->ctrl_iface_init(hapd); |  		interfaces->ctrl_iface_init(hapd); | ||||||
|  | --- a/src/ap/ieee802_11.c | ||||||
|  | +++ b/src/ap/ieee802_11.c | ||||||
|  | @@ -494,11 +494,17 @@ static const char * sae_get_password(str | ||||||
|  |  				     struct sae_pt **s_pt, | ||||||
|  |  				     const struct sae_pk **s_pk) | ||||||
|  |  { | ||||||
|  | +	struct hostapd_bss_config *conf = hapd->conf; | ||||||
|  | +	struct hostapd_ssid *ssid = &conf->ssid; | ||||||
|  | +	struct hostapd_sta_wpa_psk_short *psk; | ||||||
|  |  	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; | ||||||
|  |   | ||||||
|  | +	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) && | ||||||
|  |  		    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0) | ||||||
|  | @@ -519,6 +525,31 @@ static const char * sae_get_password(str | ||||||
|  |  		pt = hapd->conf->ssid.pt; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +use_sta_psk: | ||||||
|  | +	if (!password && sta) { | ||||||
|  | +		for (psk = sta->psk; psk; psk = psk->next) { | ||||||
|  | +			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; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	if (pw_entry) | ||||||
|  |  		*pw_entry = pw; | ||||||
|  |  	if (s_pt) | ||||||
|  | @@ -3698,6 +3729,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 | ||||||
|  | @@ -412,6 +412,9 @@ void ap_free_sta(struct hostapd_data *ha | ||||||
|  |  	os_free(sta->sae_postponed_commit); | ||||||
|  |  #endif /* CONFIG_TESTING_OPTIONS */ | ||||||
|  |   | ||||||
|  | +	if (sta->sae_pt) | ||||||
|  | +		sae_deinit_pt(sta->sae_pt); | ||||||
|  | + | ||||||
|  |  	os_free(sta); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1280,6 +1283,8 @@ void ap_sta_set_authorized(struct hostap | ||||||
|  |  	else | ||||||
|  |  		sta->flags &= ~WLAN_STA_AUTHORIZED; | ||||||
|  |   | ||||||
|  | +	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 | ||||||
|  | @@ -201,6 +201,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 | ||||||
|  | @@ -337,6 +337,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) | ||||||
|  | @@ -381,13 +382,18 @@ 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; | ||||||
|  |   | ||||||
|  |  		if (vlan_id) | ||||||
|  |  			*vlan_id = 0; | ||||||
|  |  		psk = sta->psk->psk; | ||||||
|  | +		sta->psk_idx = psk_idx = 1; | ||||||
|  |  		for (pos = sta->psk; pos; pos = pos->next) { | ||||||
|  | +			psk_idx++; | ||||||
|  |  			if (pos->is_passphrase) { | ||||||
|  |  				pbkdf2_sha1(pos->passphrase, | ||||||
|  |  					    hapd->conf->ssid.ssid, | ||||||
|  | @@ -396,10 +402,14 @@ static const u8 * hostapd_wpa_auth_get_p | ||||||
|  |  				pos->is_passphrase = 0; | ||||||
|  |  			} | ||||||
|  |  			if (pos->psk == prev_psk) { | ||||||
|  | +				sta->psk_idx = psk_idx; | ||||||
|  |  				psk = pos->next ? pos->next->psk : NULL; | ||||||
|  |  				break; | ||||||
|  |  			} | ||||||
|  |  		} | ||||||
|  | + | ||||||
|  | +		if (!psk) | ||||||
|  | +			sta->psk_idx = 0; | ||||||
|  |  	} | ||||||
|  |  	return psk; | ||||||
|  |  } | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
| #include "ap_drv_ops.h" | #include "ap_drv_ops.h" | ||||||
| #include "dfs.h" | #include "dfs.h" | ||||||
| #include "acs.h" | #include "acs.h" | ||||||
|  | #include "ieee802_11_auth.h" | ||||||
| #include <libubox/uloop.h> | #include <libubox/uloop.h> | ||||||
|  |  | ||||||
| static uc_resource_type_t *global_type, *bss_type, *iface_type; | static uc_resource_type_t *global_type, *bss_type, *iface_type; | ||||||
| @@ -700,6 +701,110 @@ out: | |||||||
| 	return ret ? NULL : ucv_boolean_new(true); | 	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) | int hostapd_ucode_init(struct hapd_interfaces *ifaces) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -23,6 +23,8 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces); | |||||||
|  |  | ||||||
| void hostapd_ucode_free(void); | void hostapd_ucode_free(void); | ||||||
| void hostapd_ucode_free_iface(struct hostapd_iface *iface); | void hostapd_ucode_free_iface(struct hostapd_iface *iface); | ||||||
|  | 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); | ||||||
| void hostapd_ucode_add_bss(struct hostapd_data *hapd); | void hostapd_ucode_add_bss(struct hostapd_data *hapd); | ||||||
| void hostapd_ucode_free_bss(struct hostapd_data *hapd); | void hostapd_ucode_free_bss(struct hostapd_data *hapd); | ||||||
| void hostapd_ucode_reload_bss(struct hostapd_data *hapd); | void hostapd_ucode_reload_bss(struct hostapd_data *hapd); | ||||||
| @@ -44,6 +46,13 @@ static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface) | |||||||
| static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd) | static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd) | ||||||
| { | { | ||||||
| } | } | ||||||
|  | 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_add_bss(struct hostapd_data *hapd) | static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd) | ||||||
| { | { | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user