diff mbox series

[3/3] AP: add wpa_psk_file reloading in runtime

Message ID 20190116123520.17602-4-kazikcz@gmail.com
State Accepted
Headers show
Series AP: make wpa_psk_file more dynamic | expand

Commit Message

MichaƂ Kazior Jan. 16, 2019, 12:35 p.m. UTC
From: Michal Kazior <michal@plume.com>

The wpa_psk_file can now be modified and hostapd
can be told to re-read it with:

 $ 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 <michal@plume.com>
---

Notes:
    v1:
     - use hostapd_config_clear_wpa_psk() instead of
       hand crafted for() loop, so now it also does a
       memset before freeing like the rest of the code
     - tweak commit log

 hostapd/ctrl_iface.c  | 56 +++++++++++++++++++++++++++++++++++++++++++
 hostapd/hostapd_cli.c |  9 +++++++
 2 files changed, 65 insertions(+)
diff mbox series

Patch

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index e539a0902..059e03cb2 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1488,6 +1488,59 @@  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;
+	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 +3066,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 }
 };