From: Michal Kazior <michal@xxxxxxxxx> With the change 'AP: keep track and expose WPA-PSK PMK of each station' it is now possible to tell whether given station is allowed to be connected with password that it used at any point in time. The wpa_psk_file can now be modified and hostapd can be told to re-read it with: $ hostapd_cli reload_wpa_psk Stations that used a passphrases that is no longer in the wpa_psk_file will be disconnected. 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 <michal@xxxxxxxxx> --- hostapd/ctrl_iface.c | 61 +++++++++++++++++++++++++++++++++++++++++++ hostapd/hostapd_cli.c | 9 +++++++ 2 files changed, 70 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index e539a0902..ca2866232 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1488,6 +1488,64 @@ 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); + sta_match = psk->group == 0 && !os_memcmp(sta->addr, psk->addr, ETH_ALEN); + bss_match = psk->group == 1; + + if (pmk_match && (sta_match || bss_match)) + return 0; + } + + wpa_printf(MSG_INFO, "STA " MACSTR " password no longer valid, kicking", 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; + struct hostapd_wpa_psk *psk, *next; + int err; + + for (psk = conf->ssid.wpa_psk; psk; psk = next) { + next = psk->next; + os_free(psk); + } + conf->ssid.wpa_psk = NULL; + + 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 +3071,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_strncmp(buf, "RELOAD_WPA_PSK", 14) == 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 fbec5d246..7e9cee1bb 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -903,6 +903,13 @@ static int hostapd_cli_cmd_hs20_deauth_req(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"); +} + + static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) { hostapd_cli_quit = 1; @@ -1651,6 +1658,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "=Add/Delete/Show/Clear deny MAC ACL" }, { "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations, "<addr> = poll a STA to check connectivity with a QoS null frame" }, + { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, + "=reload wpa_psk_file only" }, { NULL, NULL, NULL, NULL } }; -- 2.19.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap