From b389a77a0f6dccf495dbce5be9476000f6ec06a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20M=C3=A9lotte?= <raphael.melotte@mind.be>
Date: Wed, 9 Dec 2020 19:55:53 +0100
Subject: [PATCH] wps: reconfigure credentials on reload
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When new credentials are configured and hostapd is reconfigured using
SIGHUP (or reload on the ctrl_iface), also update the wps credentials.

Before these changes, when WPS is triggered the registar always serves
the credentials that were configured when hostapd started.

Signed-off-by: Raphaël Mélotte <raphael.melotte@mind.be>
---
 src/ap/wps_hostapd.c    | 86 +++++++++++++++++++++++++++++++++++++++--
 src/wps/wps.h           |  6 +++
 src/wps/wps_registrar.c | 29 ++++++++++++++
 3 files changed, 118 insertions(+), 3 deletions(-)

--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1375,6 +1375,43 @@ static void hostapd_wps_nfc_clear(struct
 #endif /* CONFIG_WPS_NFC */
 }
 
+int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
+				struct wps_registrar *reg) {
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 *multi_ap_backhaul_network_key = NULL;
+	size_t multi_ap_backhaul_network_key_len = 0;
+	int ret = -1;
+
+	if ((conf->multi_ap & FRONTHAUL_BSS) &&
+	    conf->multi_ap_backhaul_ssid.ssid_len) {
+		if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+			multi_ap_backhaul_network_key =
+				(u8 *) os_strdup(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+			if (multi_ap_backhaul_network_key == NULL)
+				return -1;
+			multi_ap_backhaul_network_key_len =
+				os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+		} else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+			multi_ap_backhaul_network_key = os_malloc(2 * PMK_LEN + 1);
+			if (multi_ap_backhaul_network_key == NULL)
+				return -1;
+			wpa_snprintf_hex((char *) multi_ap_backhaul_network_key,
+					 2 * PMK_LEN + 1,
+					 conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+					 PMK_LEN);
+			multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+		}
+		ret = wps_registrar_update_multi_ap(reg,
+						    conf->multi_ap_backhaul_ssid.ssid,
+						    conf->multi_ap_backhaul_ssid.ssid_len,
+						    multi_ap_backhaul_network_key,
+						    multi_ap_backhaul_network_key_len);
+		os_free(multi_ap_backhaul_network_key);
+	}
+	return ret;
+}
+
+
 
 void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
@@ -1409,11 +1446,54 @@ void hostapd_update_wps(struct hostapd_d
 	hapd->wps->upc = hapd->conf->upc;
 #endif /* CONFIG_WPS_UPNP */
 
-	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
-	hostapd_wps_set_application_ext(hapd, hapd->wps);
+	struct wps_context *wps = hapd->wps;
+	struct hostapd_bss_config *conf = hapd->conf;
+
+	os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len);
+	wps->ssid_len = conf->ssid.ssid_len;
+
+	/* Clear wps settings, then fill them again */
+	os_free(wps->network_key);
+	wps->network_key = NULL;
+	wps->network_key_len = 0;
+	wps->psk_set = 0;
+	if (conf->ssid.wpa_psk_file) {
+		/* Use per-device PSKs */
+	} else if (conf->ssid.wpa_passphrase) {
+		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+		if (wps->network_key == NULL)
+			return;
+		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+	} else if (conf->ssid.wpa_psk) {
+		wps->network_key = os_malloc(2 * PMK_LEN + 1);
+		if (wps->network_key == NULL)
+			return;
+		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+				 conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
+	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+		if (wps->network_key == NULL)
+			return;
+		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+			  conf->ssid.wep.len[0]);
+		wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
+	}
+
+	if (conf->ssid.wpa_psk) {
+		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->psk_set = 1;
+	}
+
+	hostapd_wps_update_multi_ap(hapd, wps->registrar);
+
+	hostapd_wps_set_vendor_ext(hapd, wps);
+	hostapd_wps_set_application_ext(hapd, wps);
 
 	if (hapd->conf->wps_state)
-		wps_registrar_update_ie(hapd->wps->registrar);
+		wps_registrar_update_ie(wps->registrar);
 	else
 		hostapd_deinit_wps(hapd);
 }
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -938,6 +938,12 @@ struct wpabuf * wps_build_nfc_handover_s
 					       struct wpabuf *nfc_dh_pubkey,
 					       struct wpabuf *nfc_dev_pw);
 
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+				  const u8 *multi_ap_backhaul_ssid,
+				  size_t multi_ap_backhaul_ssid_len,
+				  const u8 *multi_ap_backhaul_network_key,
+				  size_t multi_ap_backhaul_network_key_len);
+
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
 struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -3669,6 +3669,35 @@ int wps_registrar_config_ap(struct wps_r
 }
 
 
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+				  const u8 *multi_ap_backhaul_ssid,
+				  size_t multi_ap_backhaul_ssid_len,
+				  const u8 *multi_ap_backhaul_network_key,
+				  size_t multi_ap_backhaul_network_key_len)
+{
+	if (multi_ap_backhaul_ssid != NULL) {
+		os_memcpy(reg->multi_ap_backhaul_ssid,
+			  multi_ap_backhaul_ssid,
+			  multi_ap_backhaul_ssid_len);
+		reg->multi_ap_backhaul_ssid_len =
+			multi_ap_backhaul_ssid_len;
+	}
+	os_free(reg->multi_ap_backhaul_network_key);
+	reg->multi_ap_backhaul_network_key = NULL;
+	reg->multi_ap_backhaul_network_key_len = 0;
+
+	if (multi_ap_backhaul_network_key != NULL) {
+		reg->multi_ap_backhaul_network_key =
+			os_memdup(multi_ap_backhaul_network_key,
+				  multi_ap_backhaul_network_key_len);
+		if (reg->multi_ap_backhaul_network_key == NULL)
+			return -1;
+		reg->multi_ap_backhaul_network_key_len =
+			multi_ap_backhaul_network_key_len;
+	}
+	return 0;
+}
+
 #ifdef CONFIG_WPS_NFC
 
 int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
