mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-21 06:33:41 +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:
parent
f352ca5a8a
commit
c67d5189a4
@ -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()
|
||||||
};
|
};
|
||||||
@ -871,6 +873,10 @@ 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);
|
||||||
hostapd.udebug_set("hostapd", hostapd.data.ubus);
|
hostapd.udebug_set("hostapd", hostapd.data.ubus);
|
||||||
|
|
||||||
function bss_event(type, name, data) {
|
function bss_event(type, name, data) {
|
||||||
@ -897,5 +903,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;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"subscribe": [ "udebug" ],
|
"subscribe": [ "udebug" ],
|
||||||
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ],
|
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*", "hostapd-auth" ],
|
||||||
"send": [ "bss.*", "wps_credentials" ]
|
"send": [ "bss.*", "wps_credentials" ]
|
||||||
}
|
}
|
||||||
|
@ -678,3 +678,138 @@ as adding/removing interfaces.
|
|||||||
#ifdef CONFIG_MATCH_IFACE
|
#ifdef CONFIG_MATCH_IFACE
|
||||||
int matched;
|
int matched;
|
||||||
#endif /* CONFIG_MATCH_IFACE */
|
#endif /* CONFIG_MATCH_IFACE */
|
||||||
|
--- a/src/ap/ieee802_11.c
|
||||||
|
+++ b/src/ap/ieee802_11.c
|
||||||
|
@@ -548,12 +548,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 ||
|
||||||
|
@@ -575,12 +580,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3123,6 +3144,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
|
||||||
|
@@ -430,6 +430,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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1434,6 +1437,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
|
||||||
|
@@ -195,6 +195,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
|
||||||
|
@@ -347,6 +347,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)
|
||||||
|
@@ -393,13 +394,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,
|
||||||
|
@@ -416,6 +420,8 @@ static const u8 * hostapd_wpa_auth_get_p
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ if (psk)
|
||||||
|
+ sta->psk_idx = psk_idx;
|
||||||
|
}
|
||||||
|
return psk;
|
||||||
|
}
|
||||||
|
@ -29,7 +29,7 @@ a VLAN interface on top of the bridge, instead of using the bridge directly
|
|||||||
int bridge_hairpin; /* hairpin_mode on bridge members */
|
int bridge_hairpin; /* hairpin_mode on bridge members */
|
||||||
--- a/src/ap/wpa_auth_glue.c
|
--- a/src/ap/wpa_auth_glue.c
|
||||||
+++ b/src/ap/wpa_auth_glue.c
|
+++ b/src/ap/wpa_auth_glue.c
|
||||||
@@ -1777,8 +1777,12 @@ int hostapd_setup_wpa(struct hostapd_dat
|
@@ -1783,8 +1783,12 @@ int hostapd_setup_wpa(struct hostapd_dat
|
||||||
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
||||||
const char *ft_iface;
|
const char *ft_iface;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -701,6 +702,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);
|
||||||
@ -42,6 +44,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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user