Skip to content

Commit

Permalink
hostapd: add support for authenticating with multiple PSKs via ubus h…
Browse files Browse the repository at this point in the history
…elper

Also supports assigning a VLAN ID based on the PSK

Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 authored and blogic committed Jul 3, 2024
1 parent b5048d8 commit 7587f12
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 2 deletions.
25 changes: 24 additions & 1 deletion feeds/ipq807x_v5.4/hostapd/files/hostapd.uc
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,8 @@ let main_obj = {
hostapd.printf(`Set new config for phy ${phy}: ${file}`);
iface_set_config(phy, config);
hostapd.data.auth_obj.notify("reload", { phy });
return {
pid: hostapd.getpid()
};
Expand Down Expand Up @@ -872,6 +874,9 @@ 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);
function bss_event(type, name, data) {
let ubus = hostapd.data.ubus;
Expand Down Expand Up @@ -901,5 +906,23 @@ return {
},
bss_remove: function(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 };
};
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;
},
};
2 changes: 1 addition & 1 deletion feeds/ipq807x_v5.4/hostapd/files/wpad_acl.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"methods": [ "request" ]
}
},
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ],
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*", "hostapd-auth" ],
"send": [ "bss.*", "wps_credentials" ]
}
136 changes: 136 additions & 0 deletions feeds/ipq807x_v5.4/hostapd/patches/601-ucode_support.patch
Original file line number Diff line number Diff line change
Expand Up @@ -619,3 +619,139 @@
out:
if (interfaces->ctrl_iface_init)
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,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) {
pbkdf2_sha1(pos->passphrase,
hapd->conf->ssid.ssid,
@@ -400,6 +404,8 @@ static const u8 * hostapd_wpa_auth_get_p
break;
}
}
+ if (psk)
+ sta->psk_idx = psk_idx;
}
return psk;
}
105 changes: 105 additions & 0 deletions feeds/ipq807x_v5.4/hostapd/src/src/ap/ucode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -700,6 +701,110 @@ uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
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)
{
Expand Down
9 changes: 9 additions & 0 deletions feeds/ipq807x_v5.4/hostapd/src/src/ap/ucode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces);

void hostapd_ucode_free(void);
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_free_bss(struct hostapd_data *hapd);
void hostapd_ucode_reload_bss(struct hostapd_data *hapd);
Expand All @@ -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 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)
{
}
Expand Down

0 comments on commit 7587f12

Please sign in to comment.