diff mbox series

[2/3] AP: allow identifying which passphrase station used with wpa_psk_file

Message ID 20190116123520.17602-3-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>

It is now possible to optionally specify keyid for
each wpa_psk_file entry:

 keyid=something 00:00:00:00:00:00 secretpassphrase

When station connects and the passphrase it used
has an associated keyid it will be appended to the
AP-STA-CONNECTED event string:

 wlan0: AP-STA-CONNECTED 00:36:76:21:dc:7b keyid=something

It's also possible to retrieve it through cli:

 $ hostapd_cli all_sta
 Selected interface 'ap0'
 00:36:76:21:dc:7b
 ...
 keyid=something

New hostap is able to read old wpa_psk_file.
However old hostap will not be able to read new
wpa_psk_file if it includes keyids.

Signed-off-by: Michal Kazior <michal@plume.com>
---

Notes:
    v1:
     - add keyid=xx parsing to wpa_psk_file
     - use keyid instead of PMK
     - re-use AP-STA-CONNECTED event by appending
       keyid=xx (similar to p2p's ip_addr=)
       instead of introducing a new event string
     - split out the pmk part to a separate patch
       since it's independentaly re-usable by this
       patch and the reload_wpa_psk patch

 src/ap/ap_config.c     | 49 +++++++++++++++++++++++++++++++++++++-----
 src/ap/ap_config.h     |  2 ++
 src/ap/ctrl_iface_ap.c |  5 +++++
 src/ap/sta_info.c      | 45 ++++++++++++++++++++++++++++++++++----
 src/ap/sta_info.h      |  2 ++
 5 files changed, 94 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index f9b6f2959..46169a786 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -248,6 +248,12 @@  static int hostapd_config_read_wpa_psk(const char *fname,
 {
 	FILE *f;
 	char buf[128], *pos;
+	const char *keyid;
+	char *context;
+	char *context2;
+	char *token;
+	char *name;
+	char *value;
 	int line = 0, ret = 0, len, ok;
 	u8 addr[ETH_ALEN];
 	struct hostapd_wpa_psk *psk;
@@ -277,9 +283,31 @@  static int hostapd_config_read_wpa_psk(const char *fname,
 		if (buf[0] == '\0')
 			continue;
 
-		if (hwaddr_aton(buf, addr)) {
+		context = NULL;
+		keyid = NULL;
+		while ((token = str_token(buf, " ", &context))) {
+			if (!os_strchr(token, '='))
+				break;
+			context2 = NULL;
+			name = str_token(token, "=", &context2);
+			value = str_token(token, "", &context2) ?: "";
+			if (!strcmp(name, "keyid")) {
+				keyid = value;
+			} else {
+				wpa_printf(MSG_ERROR,
+					   "Unrecognized '%s=%s' on line %d in '%s'",
+					   name, value, line, fname);
+				ret = -1;
+				break;
+			}
+		}
+
+		if (ret == -1)
+			break;
+
+		if (hwaddr_aton(token ?: "", addr)) {
 			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
-				   "line %d in '%s'", buf, line, fname);
+				   "line %d in '%s'", token, line, fname);
 			ret = -1;
 			break;
 		}
@@ -295,15 +323,14 @@  static int hostapd_config_read_wpa_psk(const char *fname,
 		else
 			os_memcpy(psk->addr, addr, ETH_ALEN);
 
-		pos = buf + 17;
-		if (*pos == '\0') {
+		pos = str_token(buf, "", &context);
+		if (!pos) {
 			wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
 				   line, fname);
 			os_free(psk);
 			ret = -1;
 			break;
 		}
-		pos++;
 
 		ok = 0;
 		len = os_strlen(pos);
@@ -322,6 +349,18 @@  static int hostapd_config_read_wpa_psk(const char *fname,
 			break;
 		}
 
+		if (keyid) {
+			len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid));
+			if (len >= sizeof(psk->keyid)) {
+				wpa_printf(MSG_ERROR,
+					   "PSK keyid too long on line %d in '%s'",
+					   line, fname);
+				os_free(psk);
+				ret = -1;
+				break;
+			}
+		}
+
 		psk->next = ssid->wpa_psk;
 		ssid->wpa_psk = psk;
 	}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 778366d49..2cbb66201 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -132,6 +132,7 @@  struct hostapd_vlan {
 };
 
 #define PMK_LEN 32
+#define KEYID_LEN 32
 #define MIN_PASSPHRASE_LEN 8
 #define MAX_PASSPHRASE_LEN 63
 struct hostapd_sta_wpa_psk_short {
@@ -145,6 +146,7 @@  struct hostapd_sta_wpa_psk_short {
 struct hostapd_wpa_psk {
 	struct hostapd_wpa_psk *next;
 	int group;
+	char keyid[KEYID_LEN];
 	u8 psk[PMK_LEN];
 	u8 addr[ETH_ALEN];
 	u8 p2p_dev_addr[ETH_ALEN];
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 21b813ee1..ee417d01e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -207,6 +207,7 @@  static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 				      char *buf, size_t buflen)
 {
 	int len, res, ret, i;
+	const char *keyid;
 
 	if (!sta)
 		return 0;
@@ -341,6 +342,10 @@  static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 			len += ret;
 	}
 
+	keyid = ap_sta_wpa_get_keyid(hapd, sta);
+	if (keyid)
+		len += os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
+
 	return len;
 }
 
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 179cf43b6..0b9273e5e 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1165,6 +1165,34 @@  void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
 #endif /* CONFIG_IEEE80211W */
 
 
+const char *ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+				 struct sta_info *sta)
+{
+	struct hostapd_wpa_psk *psk;
+	struct hostapd_ssid *ssid;
+	const u8 *pmk;
+	int pmk_len;
+
+	ssid = &hapd->conf->ssid;
+
+	pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+	if (!pmk)
+		return NULL;
+	if (pmk_len != PMK_LEN)
+		return NULL;
+
+	for (psk = ssid->wpa_psk; psk; psk = psk->next)
+		if (!os_memcmp(pmk, psk->psk, PMK_LEN))
+			break;
+	if (!psk)
+		return NULL;
+	if (!strlen(psk->keyid))
+		return NULL;
+
+	return psk->keyid;
+}
+
+
 void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 			   int authorized)
 {
@@ -1203,7 +1231,10 @@  void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 					sta->addr, authorized, dev_addr);
 
 	if (authorized) {
+		const char *keyid;
+		char keyid_buf[100];
 		char ip_addr[100];
+		keyid_buf[0] = '\0';
 		ip_addr[0] = '\0';
 #ifdef CONFIG_P2P
 		if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
@@ -1214,14 +1245,20 @@  void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 		}
 #endif /* CONFIG_P2P */
 
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
-			buf, ip_addr);
+		keyid = ap_sta_wpa_get_keyid(hapd, sta);
+		if (keyid) {
+			os_snprintf(keyid_buf, sizeof(keyid_buf),
+				    " keyid=%s", keyid);
+		}
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
+			buf, ip_addr, keyid_buf);
 
 		if (hapd->msg_ctx_parent &&
 		    hapd->msg_ctx_parent != hapd->msg_ctx)
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
-					  AP_STA_CONNECTED "%s%s",
-					  buf, ip_addr);
+					  AP_STA_CONNECTED "%s%s%s",
+					  buf, ip_addr, keyid_buf);
 	} else {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9cac6f157..b7fd60809 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -320,6 +320,8 @@  int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
 void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+const char *ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+				 struct sta_info *sta);
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *addr, u16 reason);