From 83c8608132f5e4b756aaac2df6ab06f6776f6642 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Jan 2019 13:35:20 +0100 Subject: [PATCH] AP: Add wpa_psk_file reloading in runtime The wpa_psk_file can now be modified and hostapd can be told to re-read it with the control interface RELOAD_WPA_PSK command: $ hostapd_cli reload_wpa_psk It must be noted special care must be taken if WPS is configured (wps_state=2, eap_server=1) because WPS appends PMKs to the wpa_psk_file. Signed-off-by: Michal Kazior --- hostapd/ctrl_iface.c | 60 +++++++++++++++++++++++++++++++++++++++++++ hostapd/hostapd_cli.c | 9 +++++++ 2 files changed, 69 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 18621d02c..df2524a35 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1488,6 +1488,63 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) } +static int +hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd, + struct sta_info *sta, void *ctx) +{ + struct hostapd_wpa_psk *psk; + const u8 *pmk; + int pmk_len; + int pmk_match; + int sta_match; + int bss_match; + int reason; + + pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); + + for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) { + pmk_match = PMK_LEN == pmk_len && + os_memcmp(psk->psk, pmk, pmk_len) == 0; + sta_match = psk->group == 0 && + os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0; + bss_match = psk->group == 1; + + if (pmk_match && (sta_match || bss_match)) + return 0; + } + + wpa_printf(MSG_INFO, "STA " MACSTR + " PSK/passphrase no longer valid - disconnect", + MAC2STR(sta->addr)); + reason = WLAN_REASON_PREV_AUTH_NOT_VALID; + hostapd_drv_sta_deauth(hapd, sta->addr, reason); + ap_sta_deauthenticate(hapd, sta, reason); + + return 0; +} + + +static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd) +{ + struct hostapd_bss_config *conf = hapd->conf; + int err; + + hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk); + + err = hostapd_setup_wpa_psk(conf); + if (err < 0) { + wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d", + err); + return -1; + } + + ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter, + NULL); + + return 0; +} + + #ifdef CONFIG_TESTING_OPTIONS static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) @@ -3013,6 +3070,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "ENABLE", 6) == 0) { if (hostapd_ctrl_iface_enable(hapd->iface)) reply_len = -1; + } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) { + if (hostapd_ctrl_iface_reload_wpa_psk(hapd)) + reply_len = -1; } else if (os_strncmp(buf, "RELOAD", 6) == 0) { if (hostapd_ctrl_iface_reload(hapd->iface)) reply_len = -1; diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 3339924eb..23c592a6b 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1494,6 +1494,13 @@ static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK"); +} + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); @@ -1669,6 +1676,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " = poll a STA to check connectivity with a QoS null frame" }, { "req_beacon", hostapd_cli_cmd_req_beacon, NULL, " [req_mode=] = send a Beacon report request to a station" }, + { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, + "= reload wpa_psk_file only" }, { NULL, NULL, NULL, NULL } };