blob: 052231e34fb8d6857ea02a8d90ec09d3b0bf7416 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.1X-2004 Authenticator
Hai Shalom74f70d42019-02-11 14:42:39 -08003 * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
Hai Shalomc3565922019-10-28 11:58:20 -070010#ifdef CONFIG_SQLITE
11#include <sqlite3.h>
12#endif /* CONFIG_SQLITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013
14#include "utils/common.h"
15#include "utils/eloop.h"
16#include "crypto/md5.h"
17#include "crypto/crypto.h"
18#include "crypto/random.h"
19#include "common/ieee802_11_defs.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "radius/radius.h"
21#include "radius/radius_client.h"
22#include "eap_server/eap.h"
23#include "eap_common/eap_wsc_common.h"
24#include "eapol_auth/eapol_auth_sm.h"
25#include "eapol_auth/eapol_auth_sm_i.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080026#include "p2p/p2p.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include "hostapd.h"
28#include "accounting.h"
29#include "sta_info.h"
30#include "wpa_auth.h"
31#include "preauth_auth.h"
32#include "pmksa_cache_auth.h"
33#include "ap_config.h"
34#include "ap_drv_ops.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080035#include "wps_hostapd.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080036#include "hs20.h"
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080037/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
38#include "ieee802_11.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070039#include "ieee802_1x.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070040#include "wpa_auth_kay.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041
42
Dmitry Shmidtde47be72016-01-07 12:52:55 -080043#ifdef CONFIG_HS20
44static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
45#endif /* CONFIG_HS20 */
Sunil Ravi640215c2023-06-28 23:08:09 +000046static bool ieee802_1x_finished(struct hostapd_data *hapd,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080047 struct sta_info *sta, int success,
Sunil Ravi640215c2023-06-28 23:08:09 +000048 int remediation, bool logoff);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049
50
51static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
52 u8 type, const u8 *data, size_t datalen)
53{
54 u8 *buf;
55 struct ieee802_1x_hdr *xhdr;
56 size_t len;
57 int encrypt = 0;
58
59 len = sizeof(*xhdr) + datalen;
60 buf = os_zalloc(len);
Hai Shalomc3565922019-10-28 11:58:20 -070061 if (!buf) {
62 wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)",
63 __func__, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070064 return;
65 }
66
67 xhdr = (struct ieee802_1x_hdr *) buf;
68 xhdr->version = hapd->conf->eapol_version;
Hai Shalom81f62d82019-07-22 12:10:00 -070069#ifdef CONFIG_MACSEC
70 if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
71 xhdr->version = 2;
72#endif /* CONFIG_MACSEC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070073 xhdr->type = type;
74 xhdr->length = host_to_be16(datalen);
75
76 if (datalen > 0 && data != NULL)
77 os_memcpy(xhdr + 1, data, datalen);
78
79 if (wpa_auth_pairwise_set(sta->wpa_sm))
80 encrypt = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080081#ifdef CONFIG_TESTING_OPTIONS
82 if (hapd->ext_eapol_frame_io) {
83 size_t hex_len = 2 * len + 1;
84 char *hex = os_malloc(hex_len);
85
86 if (hex) {
87 wpa_snprintf_hex(hex, hex_len, buf, len);
88 wpa_msg(hapd->msg_ctx, MSG_INFO,
89 "EAPOL-TX " MACSTR " %s",
90 MAC2STR(sta->addr), hex);
91 os_free(hex);
92 }
93 } else
94#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070095 if (sta->flags & WLAN_STA_PREAUTH) {
96 rsn_preauth_send(hapd, sta, buf, len);
97 } else {
Sunil Ravi2a14cf12023-11-21 00:54:38 +000098 int link_id = -1;
99
100#ifdef CONFIG_IEEE80211BE
101 link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1;
102#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800103 hostapd_drv_hapd_send_eapol(
104 hapd, sta->addr, buf, len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000105 encrypt, hostapd_sta_flags_to_drv(sta->flags), link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106 }
107
108 os_free(buf);
109}
110
111
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000112static void ieee802_1x_set_authorized(struct hostapd_data *hapd,
113 struct sta_info *sta,
114 bool authorized, bool mld)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700115{
116 int res;
117
118 if (sta->flags & WLAN_STA_PREAUTH)
119 return;
120
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000121 ap_sta_set_authorized(hapd, sta, authorized);
122 res = hostapd_set_authorized(hapd, sta, authorized);
123 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
124 HOSTAPD_LEVEL_DEBUG, "%sauthorizing port",
125 authorized ? "" : "un");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700126
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000127 if (!mld && res && errno != ENOENT) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700128 wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
129 " flags for kernel driver (errno=%d).",
130 MAC2STR(sta->addr), errno);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000131 } else if (mld && res) {
132 wpa_printf(MSG_DEBUG,
133 "MLD: Could not set station " MACSTR " flags",
134 MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700135 }
136
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800137 if (authorized) {
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800138 os_get_reltime(&sta->connected_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700139 accounting_sta_start(hapd, sta);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800140 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700141}
142
143
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000144static void ieee802_1x_ml_set_sta_authorized(struct hostapd_data *hapd,
145 struct sta_info *sta,
146 bool authorized)
147{
148#ifdef CONFIG_IEEE80211BE
149 unsigned int i, link_id;
150
151 if (!hostapd_is_mld_ap(hapd))
152 return;
153
154 /*
155 * Authorizing the station should be done only in the station
156 * performing the association
157 */
158 if (authorized && hapd->mld_link_id != sta->mld_assoc_link_id)
159 return;
160
161 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
162 struct mld_link_info *link = &sta->mld_info.links[link_id];
163
164 if (!link->valid)
165 continue;
166
167 for (i = 0; i < hapd->iface->interfaces->count; i++) {
168 struct sta_info *tmp_sta;
169 struct hostapd_data *tmp_hapd =
170 hapd->iface->interfaces->iface[i]->bss[0];
171
172 if (!tmp_hapd->conf->mld_ap ||
173 hapd->conf->mld_id != tmp_hapd->conf->mld_id)
174 continue;
175
176 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
177 tmp_sta = tmp_sta->next) {
178 if (tmp_sta == sta ||
179 tmp_sta->mld_assoc_link_id !=
180 sta->mld_assoc_link_id ||
181 tmp_sta->aid != sta->aid)
182 continue;
183
184 ieee802_1x_set_authorized(tmp_hapd, tmp_sta,
185 authorized, true);
186 break;
187 }
188 }
189 }
190#endif /* CONFIG_IEEE80211BE */
191}
192
193
194
195void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
196 struct sta_info *sta, int authorized)
197{
198 ieee802_1x_set_authorized(hapd, sta, authorized, false);
199 ieee802_1x_ml_set_sta_authorized(hapd, sta, !!authorized);
200}
201
202
Hai Shalomfdcde762020-04-02 11:19:20 -0700203#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800204#ifndef CONFIG_FIPS
205#ifndef CONFIG_NO_RC4
206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700207static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
208 struct sta_info *sta,
209 int idx, int broadcast,
210 u8 *key_data, size_t key_len)
211{
212 u8 *buf, *ekey;
213 struct ieee802_1x_hdr *hdr;
214 struct ieee802_1x_eapol_key *key;
215 size_t len, ekey_len;
216 struct eapol_state_machine *sm = sta->eapol_sm;
217
Hai Shalomc3565922019-10-28 11:58:20 -0700218 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700219 return;
220
221 len = sizeof(*key) + key_len;
222 buf = os_zalloc(sizeof(*hdr) + len);
Hai Shalomc3565922019-10-28 11:58:20 -0700223 if (!buf)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700224 return;
225
226 hdr = (struct ieee802_1x_hdr *) buf;
227 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
228 key->type = EAPOL_KEY_TYPE_RC4;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700229 WPA_PUT_BE16(key->key_length, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700230 wpa_get_ntp_timestamp(key->replay_counter);
Hai Shalom81f62d82019-07-22 12:10:00 -0700231 if (os_memcmp(key->replay_counter,
232 hapd->last_1x_eapol_key_replay_counter,
233 IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
234 /* NTP timestamp did not increment from last EAPOL-Key frame;
235 * use previously used value + 1 instead. */
236 inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
237 IEEE8021X_REPLAY_COUNTER_LEN);
238 os_memcpy(key->replay_counter,
239 hapd->last_1x_eapol_key_replay_counter,
240 IEEE8021X_REPLAY_COUNTER_LEN);
241 } else {
242 os_memcpy(hapd->last_1x_eapol_key_replay_counter,
243 key->replay_counter,
244 IEEE8021X_REPLAY_COUNTER_LEN);
245 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
247 if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
248 wpa_printf(MSG_ERROR, "Could not get random numbers");
249 os_free(buf);
250 return;
251 }
252
253 key->key_index = idx | (broadcast ? 0 : BIT(7));
254 if (hapd->conf->eapol_key_index_workaround) {
255 /* According to some information, WinXP Supplicant seems to
256 * interpret bit7 as an indication whether the key is to be
257 * activated, so make it possible to enable workaround that
258 * sets this bit for all keys. */
259 key->key_index |= BIT(7);
260 }
261
262 /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
263 * MSK[32..63] is used to sign the message. */
Hai Shalomc3565922019-10-28 11:58:20 -0700264 if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) {
265 wpa_printf(MSG_ERROR,
266 "No eapKeyData available for encrypting and signing EAPOL-Key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700267 os_free(buf);
268 return;
269 }
270 os_memcpy((u8 *) (key + 1), key_data, key_len);
271 ekey_len = sizeof(key->key_iv) + 32;
272 ekey = os_malloc(ekey_len);
Hai Shalomc3565922019-10-28 11:58:20 -0700273 if (!ekey) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700274 wpa_printf(MSG_ERROR, "Could not encrypt key");
275 os_free(buf);
276 return;
277 }
278 os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
279 os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
280 rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
281 os_free(ekey);
282
283 /* This header is needed here for HMAC-MD5, but it will be regenerated
284 * in ieee802_1x_send() */
285 hdr->version = hapd->conf->eapol_version;
Hai Shalom81f62d82019-07-22 12:10:00 -0700286#ifdef CONFIG_MACSEC
287 if (hdr->version > 2)
288 hdr->version = 2;
289#endif /* CONFIG_MACSEC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700290 hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
291 hdr->length = host_to_be16(len);
292 hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
293 key->key_signature);
294
295 wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
296 " (%s index=%d)", MAC2STR(sm->addr),
297 broadcast ? "broadcast" : "unicast", idx);
298 ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
299 if (sta->eapol_sm)
300 sta->eapol_sm->dot1xAuthEapolFramesTx++;
301 os_free(buf);
302}
303
304
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800305static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306{
307 struct eapol_authenticator *eapol = hapd->eapol_auth;
308 struct eapol_state_machine *sm = sta->eapol_sm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700309
Hai Shalomc3565922019-10-28 11:58:20 -0700310 if (!sm || !sm->eap_if->eapKeyData)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700311 return;
312
313 wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
314 MAC2STR(sta->addr));
315
316#ifndef CONFIG_NO_VLAN
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800317 if (sta->vlan_id > 0) {
Dmitry Shmidt5393a0f2013-08-08 11:23:34 -0700318 wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
319 return;
320 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700321#endif /* CONFIG_NO_VLAN */
Dmitry Shmidt5393a0f2013-08-08 11:23:34 -0700322
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700323 if (eapol->default_wep_key) {
324 ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
325 eapol->default_wep_key,
326 hapd->conf->default_wep_key_len);
327 }
328
329 if (hapd->conf->individual_wep_key_len > 0) {
330 u8 *ikey;
Hai Shalomc3565922019-10-28 11:58:20 -0700331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700332 ikey = os_malloc(hapd->conf->individual_wep_key_len);
Hai Shalomc3565922019-10-28 11:58:20 -0700333 if (!ikey ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334 random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
335 {
Hai Shalomc3565922019-10-28 11:58:20 -0700336 wpa_printf(MSG_ERROR,
337 "Could not generate random individual WEP key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700338 os_free(ikey);
339 return;
340 }
341
342 wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
343 ikey, hapd->conf->individual_wep_key_len);
344
345 ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
346 hapd->conf->individual_wep_key_len);
347
348 /* TODO: set encryption in TX callback, i.e., only after STA
349 * has ACKed EAPOL-Key frame */
350 if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
Hai Shalomfdcde762020-04-02 11:19:20 -0700351 sta->addr, 0, 0, 1, NULL, 0, ikey,
352 hapd->conf->individual_wep_key_len,
353 KEY_FLAG_PAIRWISE_RX_TX)) {
Hai Shalomc3565922019-10-28 11:58:20 -0700354 wpa_printf(MSG_ERROR,
355 "Could not set individual WEP encryption");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356 }
357
358 os_free(ikey);
359 }
360}
361
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800362#endif /* CONFIG_NO_RC4 */
363#endif /* CONFIG_FIPS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700364#endif /* CONFIG_WEP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800365
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700366
367const char *radius_mode_txt(struct hostapd_data *hapd)
368{
369 switch (hapd->iface->conf->hw_mode) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800370 case HOSTAPD_MODE_IEEE80211AD:
371 return "802.11ad";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372 case HOSTAPD_MODE_IEEE80211A:
373 return "802.11a";
374 case HOSTAPD_MODE_IEEE80211G:
375 return "802.11g";
376 case HOSTAPD_MODE_IEEE80211B:
377 default:
378 return "802.11b";
379 }
380}
381
382
383int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
384{
385 int i;
386 u8 rate = 0;
387
388 for (i = 0; i < sta->supported_rates_len; i++)
389 if ((sta->supported_rates[i] & 0x7f) > rate)
390 rate = sta->supported_rates[i] & 0x7f;
391
392 return rate;
393}
394
395
396#ifndef CONFIG_NO_RADIUS
397static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
398 struct eapol_state_machine *sm,
399 const u8 *eap, size_t len)
400{
401 const u8 *identity;
402 size_t identity_len;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800403 const struct eap_hdr *hdr = (const struct eap_hdr *) eap;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404
405 if (len <= sizeof(struct eap_hdr) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800406 (hdr->code == EAP_CODE_RESPONSE &&
407 eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) ||
408 (hdr->code == EAP_CODE_INITIATE &&
409 eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) ||
410 (hdr->code != EAP_CODE_RESPONSE &&
411 hdr->code != EAP_CODE_INITIATE))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700412 return;
413
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800414 eap_erp_update_identity(sm->eap, eap, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700415 identity = eap_get_identity(sm->eap, &identity_len);
Hai Shalomc3565922019-10-28 11:58:20 -0700416 if (!identity)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417 return;
418
419 /* Save station identity for future RADIUS packets */
420 os_free(sm->identity);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700421 sm->identity = (u8 *) dup_binstr(identity, identity_len);
Hai Shalomc3565922019-10-28 11:58:20 -0700422 if (!sm->identity) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700423 sm->identity_len = 0;
424 return;
425 }
426
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700427 sm->identity_len = identity_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700428 hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
429 HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
430 sm->dot1xAuthEapolRespIdFramesRx++;
431}
432
433
Dmitry Shmidt03658832014-08-13 11:03:49 -0700434static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
435 struct hostapd_radius_attr *req_attr,
436 struct sta_info *sta,
437 struct radius_msg *msg)
438{
439 u32 suite;
440 int ver, val;
441
442 ver = wpa_auth_sta_wpa_version(sta->wpa_sm);
443 val = wpa_auth_get_pairwise(sta->wpa_sm);
444 suite = wpa_cipher_to_suite(ver, val);
445 if (val != -1 &&
446 !hostapd_config_get_radius_attr(req_attr,
447 RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) &&
448 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER,
449 suite)) {
450 wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher");
451 return -1;
452 }
453
Dmitry Shmidt41712582015-06-29 11:02:15 -0700454 suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
455 hapd->conf->osen) ?
Dmitry Shmidt03658832014-08-13 11:03:49 -0700456 WPA_PROTO_RSN : WPA_PROTO_WPA,
457 hapd->conf->wpa_group);
458 if (!hostapd_config_get_radius_attr(req_attr,
459 RADIUS_ATTR_WLAN_GROUP_CIPHER) &&
460 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER,
461 suite)) {
462 wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher");
463 return -1;
464 }
465
466 val = wpa_auth_sta_key_mgmt(sta->wpa_sm);
467 suite = wpa_akm_to_suite(val);
468 if (val != -1 &&
469 !hostapd_config_get_radius_attr(req_attr,
470 RADIUS_ATTR_WLAN_AKM_SUITE) &&
471 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
472 suite)) {
473 wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite");
474 return -1;
475 }
476
Dmitry Shmidt03658832014-08-13 11:03:49 -0700477 if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
478 suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
479 hapd->conf->group_mgmt_cipher);
480 if (!hostapd_config_get_radius_attr(
481 req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) &&
482 !radius_msg_add_attr_int32(
483 msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) {
484 wpa_printf(MSG_ERROR,
485 "Could not add WLAN-Group-Mgmt-Cipher");
486 return -1;
487 }
488 }
Dmitry Shmidt03658832014-08-13 11:03:49 -0700489
490 return 0;
491}
492
493
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700494static int add_common_radius_sta_attr(struct hostapd_data *hapd,
495 struct hostapd_radius_attr *req_attr,
496 struct sta_info *sta,
497 struct radius_msg *msg)
498{
499 char buf[128];
500
501 if (!hostapd_config_get_radius_attr(req_attr,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800502 RADIUS_ATTR_SERVICE_TYPE) &&
503 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
504 RADIUS_SERVICE_TYPE_FRAMED)) {
505 wpa_printf(MSG_ERROR, "Could not add Service-Type");
506 return -1;
507 }
508
509 if (!hostapd_config_get_radius_attr(req_attr,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700510 RADIUS_ATTR_NAS_PORT) &&
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700511 sta->aid > 0 &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700512 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
513 wpa_printf(MSG_ERROR, "Could not add NAS-Port");
514 return -1;
515 }
516
517 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
518 MAC2STR(sta->addr));
519 buf[sizeof(buf) - 1] = '\0';
520 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
521 (u8 *) buf, os_strlen(buf))) {
522 wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
523 return -1;
524 }
525
526 if (sta->flags & WLAN_STA_PREAUTH) {
527 os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
528 sizeof(buf));
529 } else {
530 os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
531 radius_sta_rate(hapd, sta) / 2,
532 (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
533 radius_mode_txt(hapd));
534 buf[sizeof(buf) - 1] = '\0';
535 }
536 if (!hostapd_config_get_radius_attr(req_attr,
537 RADIUS_ATTR_CONNECT_INFO) &&
538 !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
539 (u8 *) buf, os_strlen(buf))) {
540 wpa_printf(MSG_ERROR, "Could not add Connect-Info");
541 return -1;
542 }
543
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800544 if (sta->acct_session_id) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800545 os_snprintf(buf, sizeof(buf), "%016llX",
546 (unsigned long long) sta->acct_session_id);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800547 if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
548 (u8 *) buf, os_strlen(buf))) {
549 wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
550 return -1;
551 }
552 }
553
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800554 if ((hapd->conf->wpa & 2) &&
555 !hapd->conf->disable_pmksa_caching &&
556 sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800557 os_snprintf(buf, sizeof(buf), "%016llX",
558 (unsigned long long)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800559 sta->eapol_sm->acct_multi_session_id);
560 if (!radius_msg_add_attr(
561 msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
562 (u8 *) buf, os_strlen(buf))) {
563 wpa_printf(MSG_INFO,
564 "Could not add Acct-Multi-Session-Id");
565 return -1;
566 }
567 }
568
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800569#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt03658832014-08-13 11:03:49 -0700570 if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
571 sta->wpa_sm &&
572 (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
573 sta->auth_alg == WLAN_AUTH_FT) &&
574 !hostapd_config_get_radius_attr(req_attr,
575 RADIUS_ATTR_MOBILITY_DOMAIN_ID) &&
576 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID,
577 WPA_GET_BE16(
578 hapd->conf->mobility_domain))) {
579 wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
580 return -1;
581 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800582#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt03658832014-08-13 11:03:49 -0700583
Dmitry Shmidt41712582015-06-29 11:02:15 -0700584 if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
Dmitry Shmidt03658832014-08-13 11:03:49 -0700585 add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
586 return -1;
587
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700588 return 0;
589}
590
591
592int add_common_radius_attr(struct hostapd_data *hapd,
593 struct hostapd_radius_attr *req_attr,
594 struct sta_info *sta,
595 struct radius_msg *msg)
596{
597 char buf[128];
598 struct hostapd_radius_attr *attr;
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800599 int len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700600
601 if (!hostapd_config_get_radius_attr(req_attr,
602 RADIUS_ATTR_NAS_IP_ADDRESS) &&
603 hapd->conf->own_ip_addr.af == AF_INET &&
604 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
605 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
606 wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
607 return -1;
608 }
609
610#ifdef CONFIG_IPV6
611 if (!hostapd_config_get_radius_attr(req_attr,
612 RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
613 hapd->conf->own_ip_addr.af == AF_INET6 &&
614 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
615 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
616 wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
617 return -1;
618 }
619#endif /* CONFIG_IPV6 */
620
621 if (!hostapd_config_get_radius_attr(req_attr,
622 RADIUS_ATTR_NAS_IDENTIFIER) &&
623 hapd->conf->nas_identifier &&
624 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
625 (u8 *) hapd->conf->nas_identifier,
626 os_strlen(hapd->conf->nas_identifier))) {
627 wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
628 return -1;
629 }
630
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800631 len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
632 MAC2STR(hapd->own_addr));
633 os_memcpy(&buf[len], hapd->conf->ssid.ssid,
634 hapd->conf->ssid.ssid_len);
635 len += hapd->conf->ssid.ssid_len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700636 if (!hostapd_config_get_radius_attr(req_attr,
637 RADIUS_ATTR_CALLED_STATION_ID) &&
638 !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800639 (u8 *) buf, len)) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700640 wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
641 return -1;
642 }
643
644 if (!hostapd_config_get_radius_attr(req_attr,
645 RADIUS_ATTR_NAS_PORT_TYPE) &&
646 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
647 RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
648 wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
649 return -1;
650 }
651
Dmitry Shmidt03658832014-08-13 11:03:49 -0700652#ifdef CONFIG_INTERWORKING
653 if (hapd->conf->interworking &&
654 !is_zero_ether_addr(hapd->conf->hessid)) {
655 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
656 MAC2STR(hapd->conf->hessid));
657 buf[sizeof(buf) - 1] = '\0';
658 if (!hostapd_config_get_radius_attr(req_attr,
659 RADIUS_ATTR_WLAN_HESSID) &&
660 !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID,
661 (u8 *) buf, os_strlen(buf))) {
662 wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID");
663 return -1;
664 }
665 }
666#endif /* CONFIG_INTERWORKING */
667
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700668 if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
669 return -1;
670
671 for (attr = req_attr; attr; attr = attr->next) {
672 if (!radius_msg_add_attr(msg, attr->type,
673 wpabuf_head(attr->val),
674 wpabuf_len(attr->val))) {
Hai Shalomc3565922019-10-28 11:58:20 -0700675 wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700676 return -1;
677 }
678 }
679
680 return 0;
681}
682
683
Hai Shalomc3565922019-10-28 11:58:20 -0700684int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
685 struct radius_msg *msg, int acct)
686{
687#ifdef CONFIG_SQLITE
688 const char *attrtxt;
689 char addrtxt[3 * ETH_ALEN];
690 char *sql;
691 sqlite3_stmt *stmt = NULL;
692
693 if (!hapd->rad_attr_db)
694 return 0;
695
696 os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
697
698 sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
699 if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
700 NULL) != SQLITE_OK) {
701 wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
702 sqlite3_errmsg(hapd->rad_attr_db));
703 return -1;
704 }
705 sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
706 sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
707 while (sqlite3_step(stmt) == SQLITE_ROW) {
708 struct hostapd_radius_attr *attr;
709 struct radius_attr_hdr *hdr;
710
711 attrtxt = (const char *) sqlite3_column_text(stmt, 0);
712 attr = hostapd_parse_radius_attr(attrtxt);
713 if (!attr) {
714 wpa_printf(MSG_ERROR,
715 "Skipping invalid attribute from SQL: %s",
716 attrtxt);
717 continue;
718 }
719 wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
720 attrtxt);
721 hdr = radius_msg_add_attr(msg, attr->type,
722 wpabuf_head(attr->val),
723 wpabuf_len(attr->val));
724 hostapd_config_free_radius_attr(attr);
725 if (!hdr) {
726 wpa_printf(MSG_ERROR,
727 "Could not add RADIUS attribute from SQL");
728 continue;
729 }
730 }
731
732 sqlite3_reset(stmt);
733 sqlite3_clear_bindings(stmt);
734 sqlite3_finalize(stmt);
735#endif /* CONFIG_SQLITE */
736
737 return 0;
738}
739
740
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800741void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
742 struct sta_info *sta,
743 const u8 *eap, size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700744{
745 struct radius_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746 struct eapol_state_machine *sm = sta->eapol_sm;
747
Hai Shalomc3565922019-10-28 11:58:20 -0700748 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700749 return;
750
751 ieee802_1x_learn_identity(hapd, sm, eap, len);
752
Hai Shalomc3565922019-10-28 11:58:20 -0700753 wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700754
755 sm->radius_identifier = radius_client_get_id(hapd->radius);
756 msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
757 sm->radius_identifier);
Hai Shalomc3565922019-10-28 11:58:20 -0700758 if (!msg) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800759 wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700760 return;
761 }
762
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800763 if (radius_msg_make_authenticator(msg) < 0) {
764 wpa_printf(MSG_INFO, "Could not make Request Authenticator");
765 goto fail;
766 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700767
768 if (sm->identity &&
769 !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
770 sm->identity, sm->identity_len)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800771 wpa_printf(MSG_INFO, "Could not add User-Name");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700772 goto fail;
773 }
774
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700775 if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
776 msg) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700777 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700778
Hai Shalomc3565922019-10-28 11:58:20 -0700779 if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
780 goto fail;
781
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700782 /* TODO: should probably check MTU from driver config; 2304 is max for
783 * IEEE 802.11, but use 1400 to avoid problems with too large packets
784 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700785 if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
786 RADIUS_ATTR_FRAMED_MTU) &&
787 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800788 wpa_printf(MSG_INFO, "Could not add Framed-MTU");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700789 goto fail;
790 }
791
Dmitry Shmidt41712582015-06-29 11:02:15 -0700792 if (!radius_msg_add_eap(msg, eap, len)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800793 wpa_printf(MSG_INFO, "Could not add EAP-Message");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700794 goto fail;
795 }
796
797 /* State attribute must be copied if and only if this packet is
798 * Access-Request reply to the previous Access-Challenge */
799 if (sm->last_recv_radius &&
800 radius_msg_get_hdr(sm->last_recv_radius)->code ==
801 RADIUS_CODE_ACCESS_CHALLENGE) {
802 int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
803 RADIUS_ATTR_STATE);
804 if (res < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -0700805 wpa_printf(MSG_INFO,
806 "Could not copy State attribute from previous Access-Challenge");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700807 goto fail;
808 }
Hai Shalomc3565922019-10-28 11:58:20 -0700809 if (res > 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810 wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700811 }
812
Dmitry Shmidt04949592012-07-19 12:16:46 -0700813 if (hapd->conf->radius_request_cui) {
814 const u8 *cui;
815 size_t cui_len;
816 /* Add previously learned CUI or nul CUI to request CUI */
817 if (sm->radius_cui) {
818 cui = wpabuf_head(sm->radius_cui);
819 cui_len = wpabuf_len(sm->radius_cui);
820 } else {
821 cui = (const u8 *) "\0";
822 cui_len = 1;
823 }
824 if (!radius_msg_add_attr(msg,
825 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
826 cui, cui_len)) {
827 wpa_printf(MSG_ERROR, "Could not add CUI");
828 goto fail;
829 }
830 }
831
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800832#ifdef CONFIG_HS20
833 if (hapd->conf->hs20) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800834 u8 ver = hapd->conf->hs20_release - 1;
835
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800836 if (!radius_msg_add_wfa(
837 msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
838 &ver, 1)) {
Hai Shalomc3565922019-10-28 11:58:20 -0700839 wpa_printf(MSG_ERROR,
840 "Could not add HS 2.0 AP version");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800841 goto fail;
842 }
843
844 if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) {
845 const u8 *pos;
846 u8 buf[3];
847 u16 id;
Hai Shalomc3565922019-10-28 11:58:20 -0700848
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800849 pos = wpabuf_head_u8(sta->hs20_ie);
850 buf[0] = (*pos) >> 4;
851 if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
852 wpabuf_len(sta->hs20_ie) >= 3)
853 id = WPA_GET_LE16(pos + 1);
854 else
855 id = 0;
856 WPA_PUT_BE16(buf + 1, id);
857 if (!radius_msg_add_wfa(
858 msg,
859 RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
860 buf, sizeof(buf))) {
Hai Shalomc3565922019-10-28 11:58:20 -0700861 wpa_printf(MSG_ERROR,
862 "Could not add HS 2.0 STA version");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800863 goto fail;
864 }
865 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700866
867 if (sta->roaming_consortium &&
868 !radius_msg_add_wfa(
869 msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
870 wpabuf_head(sta->roaming_consortium),
871 wpabuf_len(sta->roaming_consortium))) {
872 wpa_printf(MSG_ERROR,
873 "Could not add HS 2.0 Roaming Consortium");
874 goto fail;
875 }
876
877 if (hapd->conf->t_c_filename) {
878 be32 timestamp;
879
880 if (!radius_msg_add_wfa(
881 msg,
882 RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
883 (const u8 *) hapd->conf->t_c_filename,
884 os_strlen(hapd->conf->t_c_filename))) {
885 wpa_printf(MSG_ERROR,
886 "Could not add HS 2.0 T&C Filename");
887 goto fail;
888 }
889
890 timestamp = host_to_be32(hapd->conf->t_c_timestamp);
891 if (!radius_msg_add_wfa(
892 msg,
893 RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
894 (const u8 *) &timestamp,
895 sizeof(timestamp))) {
896 wpa_printf(MSG_ERROR,
897 "Could not add HS 2.0 Timestamp");
898 goto fail;
899 }
900 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800901 }
902#endif /* CONFIG_HS20 */
903
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700904 if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
905 goto fail;
906
907 return;
908
909 fail:
910 radius_msg_free(msg);
911}
912#endif /* CONFIG_NO_RADIUS */
913
914
915static void handle_eap_response(struct hostapd_data *hapd,
916 struct sta_info *sta, struct eap_hdr *eap,
917 size_t len)
918{
919 u8 type, *data;
920 struct eapol_state_machine *sm = sta->eapol_sm;
Hai Shalomc3565922019-10-28 11:58:20 -0700921
922 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700923 return;
924
925 data = (u8 *) (eap + 1);
926
927 if (len < sizeof(*eap) + 1) {
Hai Shalomc3565922019-10-28 11:58:20 -0700928 wpa_printf(MSG_INFO, "%s: too short response data", __func__);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700929 return;
930 }
931
932 sm->eap_type_supp = type = data[0];
933
934 hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
935 HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
936 "id=%d len=%d) from STA: EAP Response-%s (%d)",
937 eap->code, eap->identifier, be_to_host16(eap->length),
938 eap_server_get_name(0, type), type);
939
940 sm->dot1xAuthEapolRespFramesRx++;
941
942 wpabuf_free(sm->eap_if->eapRespData);
943 sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
Hai Shalome21d4e82020-04-29 16:34:06 -0700944 sm->eapolEap = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700945}
946
947
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800948static void handle_eap_initiate(struct hostapd_data *hapd,
949 struct sta_info *sta, struct eap_hdr *eap,
950 size_t len)
951{
952#ifdef CONFIG_ERP
953 u8 type, *data;
954 struct eapol_state_machine *sm = sta->eapol_sm;
955
Hai Shalomc3565922019-10-28 11:58:20 -0700956 if (!sm)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800957 return;
958
959 if (len < sizeof(*eap) + 1) {
Hai Shalomc3565922019-10-28 11:58:20 -0700960 wpa_printf(MSG_INFO, "%s: too short response data", __func__);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800961 return;
962 }
963
964 data = (u8 *) (eap + 1);
965 type = data[0];
966
967 hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -0700968 HOSTAPD_LEVEL_DEBUG,
969 "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800970 eap->code, eap->identifier, be_to_host16(eap->length),
971 type);
972
973 wpabuf_free(sm->eap_if->eapRespData);
974 sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
Hai Shalome21d4e82020-04-29 16:34:06 -0700975 sm->eapolEap = true;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800976#endif /* CONFIG_ERP */
977}
978
979
Hai Shalomc3565922019-10-28 11:58:20 -0700980#ifndef CONFIG_NO_STDOUT_DEBUG
981static const char * eap_code_str(u8 code)
982{
983 switch (code) {
984 case EAP_CODE_REQUEST:
985 return "request";
986 case EAP_CODE_RESPONSE:
987 return "response";
988 case EAP_CODE_SUCCESS:
989 return "success";
990 case EAP_CODE_FAILURE:
991 return "failure";
992 case EAP_CODE_INITIATE:
993 return "initiate";
994 case EAP_CODE_FINISH:
995 return "finish";
996 default:
997 return "unknown";
998 }
999}
1000#endif /* CONFIG_NO_STDOUT_DEBUG */
1001
1002
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001003/* Process incoming EAP packet from Supplicant */
1004static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
1005 u8 *buf, size_t len)
1006{
1007 struct eap_hdr *eap;
1008 u16 eap_len;
1009
1010 if (len < sizeof(*eap)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001011 wpa_printf(MSG_INFO, " too short EAP packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001012 return;
1013 }
1014
1015 eap = (struct eap_hdr *) buf;
1016
1017 eap_len = be_to_host16(eap->length);
Hai Shalomc3565922019-10-28 11:58:20 -07001018 wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d",
1019 eap->code, eap_code_str(eap->code), eap->identifier,
1020 eap_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001021 if (eap_len < sizeof(*eap)) {
1022 wpa_printf(MSG_DEBUG, " Invalid EAP length");
1023 return;
1024 } else if (eap_len > len) {
Hai Shalomc3565922019-10-28 11:58:20 -07001025 wpa_printf(MSG_DEBUG,
1026 " Too short frame to contain this EAP packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001027 return;
1028 } else if (eap_len < len) {
Hai Shalomc3565922019-10-28 11:58:20 -07001029 wpa_printf(MSG_DEBUG,
1030 " Ignoring %lu extra bytes after EAP packet",
1031 (unsigned long) len - eap_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001032 }
1033
1034 switch (eap->code) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001035 case EAP_CODE_RESPONSE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001036 handle_eap_response(hapd, sta, eap, eap_len);
1037 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001038 case EAP_CODE_INITIATE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 handle_eap_initiate(hapd, sta, eap, eap_len);
1040 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001041 }
1042}
1043
1044
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001045struct eapol_state_machine *
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001046ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
1047{
1048 int flags = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07001049
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001050 if (sta->flags & WLAN_STA_PREAUTH)
1051 flags |= EAPOL_SM_PREAUTH;
1052 if (sta->wpa_sm) {
1053 flags |= EAPOL_SM_USES_WPA;
1054 if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
1055 flags |= EAPOL_SM_FROM_PMKSA_CACHE;
1056 }
1057 return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001058 sta->wps_ie, sta->p2p_ie, sta,
1059 sta->identity, sta->radius_cui);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001060}
1061
1062
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001063static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
Sunil8cd6f4d2022-06-28 18:40:46 +00001064 size_t len, enum frame_encryption encrypted)
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001065{
1066 if (sta->pending_eapol_rx) {
1067 wpabuf_free(sta->pending_eapol_rx->buf);
1068 } else {
1069 sta->pending_eapol_rx =
1070 os_malloc(sizeof(*sta->pending_eapol_rx));
1071 if (!sta->pending_eapol_rx)
1072 return;
1073 }
1074
1075 sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
1076 if (!sta->pending_eapol_rx->buf) {
1077 os_free(sta->pending_eapol_rx);
1078 sta->pending_eapol_rx = NULL;
1079 return;
1080 }
1081
Sunil8cd6f4d2022-06-28 18:40:46 +00001082 sta->pending_eapol_rx->encrypted = encrypted;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001083 os_get_reltime(&sta->pending_eapol_rx->rx_time);
1084}
1085
1086
Sunil8cd6f4d2022-06-28 18:40:46 +00001087static bool ieee802_1x_check_encryption(struct sta_info *sta,
1088 enum frame_encryption encrypted,
1089 u8 type)
1090{
1091 if (encrypted != FRAME_NOT_ENCRYPTED)
1092 return true;
1093 if (type != IEEE802_1X_TYPE_EAP_PACKET &&
1094 type != IEEE802_1X_TYPE_EAPOL_START &&
1095 type != IEEE802_1X_TYPE_EAPOL_LOGOFF)
1096 return true;
1097 if (!(sta->flags & WLAN_STA_MFP))
1098 return true;
1099 return !wpa_auth_pairwise_set(sta->wpa_sm);
1100}
1101
1102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103/**
1104 * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
1105 * @hapd: hostapd BSS data
1106 * @sa: Source address (sender of the EAPOL frame)
1107 * @buf: EAPOL frame
1108 * @len: Length of buf in octets
Sunil8cd6f4d2022-06-28 18:40:46 +00001109 * @encrypted: Whether the frame was encrypted
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001110 *
1111 * This function is called for each incoming EAPOL frame from the interface
1112 */
1113void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
Sunil8cd6f4d2022-06-28 18:40:46 +00001114 size_t len, enum frame_encryption encrypted)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115{
1116 struct sta_info *sta;
1117 struct ieee802_1x_hdr *hdr;
1118 struct ieee802_1x_eapol_key *key;
1119 u16 datalen;
1120 struct rsn_pmksa_cache_entry *pmksa;
1121 int key_mgmt;
1122
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001123 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001124 !hapd->conf->wps_state)
1125 return;
1126
Sunil8cd6f4d2022-06-28 18:40:46 +00001127 wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR
1128 " (encrypted=%d)",
1129 (unsigned long) len, MAC2STR(sa), encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001130 sta = ap_get_sta(hapd, sa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001131 if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
1132 !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
Hai Shalomc3565922019-10-28 11:58:20 -07001133 wpa_printf(MSG_DEBUG,
1134 "IEEE 802.1X data frame from not associated/Pre-authenticating STA");
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001135
1136 if (sta && (sta->flags & WLAN_STA_AUTH)) {
1137 wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
1138 " for later use", MAC2STR(sta->addr));
Sunil8cd6f4d2022-06-28 18:40:46 +00001139 ieee802_1x_save_eapol(sta, buf, len, encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001140 }
1141
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001142 return;
1143 }
1144
1145 if (len < sizeof(*hdr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001146 wpa_printf(MSG_INFO, " too short IEEE 802.1X packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001147 return;
1148 }
1149
1150 hdr = (struct ieee802_1x_hdr *) buf;
1151 datalen = be_to_host16(hdr->length);
1152 wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d",
1153 hdr->version, hdr->type, datalen);
1154
1155 if (len - sizeof(*hdr) < datalen) {
Hai Shalomc3565922019-10-28 11:58:20 -07001156 wpa_printf(MSG_INFO,
1157 " frame too short for this IEEE 802.1X packet");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001158 if (sta->eapol_sm)
1159 sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
1160 return;
1161 }
1162 if (len - sizeof(*hdr) > datalen) {
Hai Shalomc3565922019-10-28 11:58:20 -07001163 wpa_printf(MSG_DEBUG,
1164 " ignoring %lu extra octets after IEEE 802.1X packet",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165 (unsigned long) len - sizeof(*hdr) - datalen);
1166 }
1167
1168 if (sta->eapol_sm) {
1169 sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
1170 sta->eapol_sm->dot1xAuthEapolFramesRx++;
1171 }
1172
1173 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
1174 if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
1175 hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
1176 (key->type == EAPOL_KEY_TYPE_WPA ||
1177 key->type == EAPOL_KEY_TYPE_RSN)) {
1178 wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
1179 sizeof(*hdr) + datalen);
1180 return;
1181 }
1182
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001183 if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001184 !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
Hai Shalomc3565922019-10-28 11:58:20 -07001185 wpa_printf(MSG_DEBUG,
1186 "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001187 return;
1188 }
1189
1190 key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001191 if (key_mgmt != -1 &&
1192 (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
1193 key_mgmt == WPA_KEY_MGMT_DPP)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001194 wpa_printf(MSG_DEBUG,
1195 "IEEE 802.1X: Ignore EAPOL message - STA is using PSK");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001196 return;
1197 }
1198
Sunil8cd6f4d2022-06-28 18:40:46 +00001199 if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) {
1200 wpa_printf(MSG_DEBUG,
1201 "IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected");
1202 return;
1203 }
1204
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001205 if (!sta->eapol_sm) {
1206 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
1207 if (!sta->eapol_sm)
1208 return;
1209
1210#ifdef CONFIG_WPS
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001211 if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001212 u32 wflags = sta->flags & (WLAN_STA_WPS |
1213 WLAN_STA_WPS2 |
1214 WLAN_STA_MAYBE_WPS);
1215 if (wflags == WLAN_STA_MAYBE_WPS ||
1216 wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
1217 /*
1218 * Delay EAPOL frame transmission until a
1219 * possible WPS STA initiates the handshake
1220 * with EAPOL-Start. Only allow the wait to be
1221 * skipped if the STA is known to support WPS
1222 * 2.0.
1223 */
Hai Shalomc3565922019-10-28 11:58:20 -07001224 wpa_printf(MSG_DEBUG,
1225 "WPS: Do not start EAPOL until EAPOL-Start is received");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001226 sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
1227 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 }
1229#endif /* CONFIG_WPS */
1230
Hai Shalome21d4e82020-04-29 16:34:06 -07001231 sta->eapol_sm->eap_if->portEnabled = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001232 }
1233
1234 /* since we support version 1, we can ignore version field and proceed
1235 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
1236 /* TODO: actually, we are not version 1 anymore.. However, Version 2
1237 * does not change frame contents, so should be ok to process frames
1238 * more or less identically. Some changes might be needed for
1239 * verification of fields. */
1240
1241 switch (hdr->type) {
1242 case IEEE802_1X_TYPE_EAP_PACKET:
1243 handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
1244 break;
1245
1246 case IEEE802_1X_TYPE_EAPOL_START:
1247 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001248 HOSTAPD_LEVEL_DEBUG,
1249 "received EAPOL-Start from STA");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001250 sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
1251 pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
1252 if (pmksa) {
1253 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
Hai Shalomc3565922019-10-28 11:58:20 -07001254 HOSTAPD_LEVEL_DEBUG,
1255 "cached PMKSA available - ignore it since STA sent EAPOL-Start");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001256 wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
1257 }
Hai Shalome21d4e82020-04-29 16:34:06 -07001258 sta->eapol_sm->eapolStart = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001259 sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
1260 eap_server_clear_identity(sta->eapol_sm->eap);
1261 wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
1262 break;
1263
1264 case IEEE802_1X_TYPE_EAPOL_LOGOFF:
1265 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001266 HOSTAPD_LEVEL_DEBUG,
1267 "received EAPOL-Logoff from STA");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268 sta->acct_terminate_cause =
1269 RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
1270 accounting_sta_stop(hapd, sta);
Hai Shalome21d4e82020-04-29 16:34:06 -07001271 sta->eapol_sm->eapolLogoff = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272 sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
1273 eap_server_clear_identity(sta->eapol_sm->eap);
1274 break;
1275
1276 case IEEE802_1X_TYPE_EAPOL_KEY:
1277 wpa_printf(MSG_DEBUG, " EAPOL-Key");
1278 if (!ap_sta_is_authorized(sta)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001279 wpa_printf(MSG_DEBUG,
1280 " Dropped key data from unauthorized Supplicant");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001281 break;
1282 }
1283 break;
1284
1285 case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
1286 wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert");
1287 /* TODO: implement support for this; show data */
1288 break;
1289
Hai Shalom81f62d82019-07-22 12:10:00 -07001290#ifdef CONFIG_MACSEC
1291 case IEEE802_1X_TYPE_EAPOL_MKA:
1292 wpa_printf(MSG_EXCESSIVE,
1293 "EAPOL type %d will be handled by MKA", hdr->type);
1294 break;
1295#endif /* CONFIG_MACSEC */
1296
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001297 default:
1298 wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
1299 sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
1300 break;
1301 }
1302
1303 eapol_auth_step(sta->eapol_sm);
1304}
1305
1306
1307/**
1308 * ieee802_1x_new_station - Start IEEE 802.1X authentication
1309 * @hapd: hostapd BSS data
1310 * @sta: The station
1311 *
1312 * This function is called to start IEEE 802.1X authentication when a new
1313 * station completes IEEE 802.11 association.
1314 */
1315void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
1316{
1317 struct rsn_pmksa_cache_entry *pmksa;
1318 int reassoc = 1;
1319 int force_1x = 0;
1320 int key_mgmt;
1321
1322#ifdef CONFIG_WPS
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001323 if (hapd->conf->wps_state &&
1324 ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) ||
1325 (sta->flags & WLAN_STA_WPS))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001326 /*
1327 * Need to enable IEEE 802.1X/EAPOL state machines for possible
1328 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
1329 * authentication in this BSS.
1330 */
1331 force_1x = 1;
1332 }
1333#endif /* CONFIG_WPS */
1334
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001335 if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
Hai Shalomc3565922019-10-28 11:58:20 -07001336 wpa_printf(MSG_DEBUG,
1337 "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
Dmitry Shmidt04949592012-07-19 12:16:46 -07001338 /*
1339 * Clear any possible EAPOL authenticator state to support
1340 * reassociation change from WPS to PSK.
1341 */
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001342 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001343 return;
1344 }
1345
1346 key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001347 if (key_mgmt != -1 &&
1348 (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
1349 key_mgmt == WPA_KEY_MGMT_DPP)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001350 wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
Dmitry Shmidt04949592012-07-19 12:16:46 -07001351 /*
1352 * Clear any possible EAPOL authenticator state to support
1353 * reassociation change from WPA-EAP to PSK.
1354 */
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001355 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001356 return;
1357 }
1358
Hai Shalomc3565922019-10-28 11:58:20 -07001359 if (!sta->eapol_sm) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001360 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1361 HOSTAPD_LEVEL_DEBUG, "start authentication");
1362 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001363 if (!sta->eapol_sm) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001364 hostapd_logger(hapd, sta->addr,
1365 HOSTAPD_MODULE_IEEE8021X,
1366 HOSTAPD_LEVEL_INFO,
1367 "failed to allocate state machine");
1368 return;
1369 }
1370 reassoc = 0;
1371 }
1372
1373#ifdef CONFIG_WPS
1374 sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001375 if (!hapd->conf->ieee802_1x && hapd->conf->wps_state &&
1376 !(sta->flags & WLAN_STA_WPS2)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001377 /*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001378 * Delay EAPOL frame transmission until a possible WPS STA
1379 * initiates the handshake with EAPOL-Start. Only allow the
1380 * wait to be skipped if the STA is known to support WPS 2.0.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001381 */
Hai Shalomc3565922019-10-28 11:58:20 -07001382 wpa_printf(MSG_DEBUG,
1383 "WPS: Do not start EAPOL until EAPOL-Start is received");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001384 sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
1385 }
1386#endif /* CONFIG_WPS */
1387
Hai Shalome21d4e82020-04-29 16:34:06 -07001388 sta->eapol_sm->eap_if->portEnabled = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001389
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001390#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001391 if (sta->auth_alg == WLAN_AUTH_FT) {
1392 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1393 HOSTAPD_LEVEL_DEBUG,
1394 "PMK from FT - skip IEEE 802.1X/EAP");
1395 /* Setup EAPOL state machines to already authenticated state
1396 * because of existing FT information from R0KH. */
Hai Shalome21d4e82020-04-29 16:34:06 -07001397 sta->eapol_sm->keyRun = true;
1398 sta->eapol_sm->eap_if->eapKeyAvailable = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001399 sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
1400 sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
Hai Shalome21d4e82020-04-29 16:34:06 -07001401 sta->eapol_sm->authSuccess = true;
1402 sta->eapol_sm->authFail = false;
1403 sta->eapol_sm->portValid = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001404 if (sta->eapol_sm->eap)
1405 eap_sm_notify_cached(sta->eapol_sm->eap);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001406 ap_sta_bind_vlan(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001407 return;
1408 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001409#endif /* CONFIG_IEEE80211R_AP */
1410
1411#ifdef CONFIG_FILS
1412 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
1413 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
1414 sta->auth_alg == WLAN_AUTH_FILS_PK) {
1415 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1416 HOSTAPD_LEVEL_DEBUG,
1417 "PMK from FILS - skip IEEE 802.1X/EAP");
1418 /* Setup EAPOL state machines to already authenticated state
1419 * because of existing FILS information. */
Hai Shalome21d4e82020-04-29 16:34:06 -07001420 sta->eapol_sm->keyRun = true;
1421 sta->eapol_sm->eap_if->eapKeyAvailable = true;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001422 sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
1423 sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
Hai Shalome21d4e82020-04-29 16:34:06 -07001424 sta->eapol_sm->authSuccess = true;
1425 sta->eapol_sm->authFail = false;
1426 sta->eapol_sm->portValid = true;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001427 if (sta->eapol_sm->eap)
1428 eap_sm_notify_cached(sta->eapol_sm->eap);
Hai Shalom81f62d82019-07-22 12:10:00 -07001429 wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001430 return;
1431 }
1432#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001433
1434 pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
1435 if (pmksa) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001436 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1437 HOSTAPD_LEVEL_DEBUG,
1438 "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
1439 /* Setup EAPOL state machines to already authenticated state
1440 * because of existing PMKSA information in the cache. */
Hai Shalome21d4e82020-04-29 16:34:06 -07001441 sta->eapol_sm->keyRun = true;
1442 sta->eapol_sm->eap_if->eapKeyAvailable = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001443 sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
1444 sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
Hai Shalome21d4e82020-04-29 16:34:06 -07001445 sta->eapol_sm->authSuccess = true;
1446 sta->eapol_sm->authFail = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001447 if (sta->eapol_sm->eap)
1448 eap_sm_notify_cached(sta->eapol_sm->eap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001449 pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
Dmitry Shmidt83474442015-04-15 13:47:09 -07001450 ap_sta_bind_vlan(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001451 } else {
1452 if (reassoc) {
1453 /*
1454 * Force EAPOL state machines to start
1455 * re-authentication without having to wait for the
1456 * Supplicant to send EAPOL-Start.
1457 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001458 sta->eapol_sm->reAuthenticate = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001459 }
1460 eapol_auth_step(sta->eapol_sm);
1461 }
1462}
1463
1464
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001465void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001466{
1467 struct eapol_state_machine *sm = sta->eapol_sm;
1468
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001469#ifdef CONFIG_HS20
1470 eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
1471#endif /* CONFIG_HS20 */
1472
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001473 if (sta->pending_eapol_rx) {
1474 wpabuf_free(sta->pending_eapol_rx->buf);
1475 os_free(sta->pending_eapol_rx);
1476 sta->pending_eapol_rx = NULL;
1477 }
1478
Hai Shalomc3565922019-10-28 11:58:20 -07001479 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001480 return;
1481
1482 sta->eapol_sm = NULL;
1483
1484#ifndef CONFIG_NO_RADIUS
1485 radius_msg_free(sm->last_recv_radius);
1486 radius_free_class(&sm->radius_class);
1487#endif /* CONFIG_NO_RADIUS */
1488
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001489 eapol_auth_free(sm);
1490}
1491
1492
1493#ifndef CONFIG_NO_RADIUS
1494static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
1495 struct sta_info *sta)
1496{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001497 struct wpabuf *eap;
1498 const struct eap_hdr *hdr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001499 int eap_type = -1;
1500 char buf[64];
1501 struct radius_msg *msg;
1502 struct eapol_state_machine *sm = sta->eapol_sm;
1503
Hai Shalomc3565922019-10-28 11:58:20 -07001504 if (!sm || !sm->last_recv_radius) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001505 if (sm)
Hai Shalome21d4e82020-04-29 16:34:06 -07001506 sm->eap_if->aaaEapNoReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001507 return;
1508 }
1509
1510 msg = sm->last_recv_radius;
1511
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001512 eap = radius_msg_get_eap(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001513 if (!eap) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 /* RFC 3579, Chap. 2.6.3:
1515 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
1516 * attribute */
1517 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001518 HOSTAPD_LEVEL_WARNING,
1519 "could not extract EAP-Message from RADIUS message");
Hai Shalome21d4e82020-04-29 16:34:06 -07001520 sm->eap_if->aaaEapNoReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001521 return;
1522 }
1523
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001524 if (wpabuf_len(eap) < sizeof(*hdr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001525 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001526 HOSTAPD_LEVEL_WARNING,
1527 "too short EAP packet received from authentication server");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001528 wpabuf_free(eap);
Hai Shalome21d4e82020-04-29 16:34:06 -07001529 sm->eap_if->aaaEapNoReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001530 return;
1531 }
1532
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001533 if (wpabuf_len(eap) > sizeof(*hdr))
1534 eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001535
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001536 hdr = wpabuf_head(eap);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001537 switch (hdr->code) {
1538 case EAP_CODE_REQUEST:
1539 if (eap_type >= 0)
1540 sm->eap_type_authsrv = eap_type;
1541 os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001542 eap_server_get_name(0, eap_type), eap_type);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001543 break;
1544 case EAP_CODE_RESPONSE:
1545 os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001546 eap_server_get_name(0, eap_type), eap_type);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001547 break;
1548 case EAP_CODE_SUCCESS:
1549 os_strlcpy(buf, "EAP Success", sizeof(buf));
1550 break;
1551 case EAP_CODE_FAILURE:
1552 os_strlcpy(buf, "EAP Failure", sizeof(buf));
1553 break;
1554 default:
1555 os_strlcpy(buf, "unknown EAP code", sizeof(buf));
1556 break;
1557 }
1558 buf[sizeof(buf) - 1] = '\0';
1559 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001560 HOSTAPD_LEVEL_DEBUG,
1561 "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001562 hdr->code, hdr->identifier, be_to_host16(hdr->length),
1563 buf);
Hai Shalome21d4e82020-04-29 16:34:06 -07001564 sm->eap_if->aaaEapReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001565
1566 wpabuf_free(sm->eap_if->aaaEapReqData);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001567 sm->eap_if->aaaEapReqData = eap;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001568}
1569
1570
1571static void ieee802_1x_get_keys(struct hostapd_data *hapd,
1572 struct sta_info *sta, struct radius_msg *msg,
1573 struct radius_msg *req,
1574 const u8 *shared_secret,
1575 size_t shared_secret_len)
1576{
1577 struct radius_ms_mppe_keys *keys;
Hai Shalom81f62d82019-07-22 12:10:00 -07001578 u8 *buf;
1579 size_t len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001580 struct eapol_state_machine *sm = sta->eapol_sm;
Hai Shalomc3565922019-10-28 11:58:20 -07001581
1582 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001583 return;
1584
1585 keys = radius_msg_get_ms_keys(msg, req, shared_secret,
1586 shared_secret_len);
1587
1588 if (keys && keys->send && keys->recv) {
Hai Shalom81f62d82019-07-22 12:10:00 -07001589 len = keys->send_len + keys->recv_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001590 wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
1591 keys->send, keys->send_len);
1592 wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
1593 keys->recv, keys->recv_len);
1594
1595 os_free(sm->eap_if->aaaEapKeyData);
1596 sm->eap_if->aaaEapKeyData = os_malloc(len);
1597 if (sm->eap_if->aaaEapKeyData) {
1598 os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
1599 keys->recv_len);
1600 os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
1601 keys->send, keys->send_len);
1602 sm->eap_if->aaaEapKeyDataLen = len;
Hai Shalome21d4e82020-04-29 16:34:06 -07001603 sm->eap_if->aaaEapKeyAvailable = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001604 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001605 } else {
1606 wpa_printf(MSG_DEBUG,
1607 "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p",
1608 keys, keys ? keys->send : NULL,
1609 keys ? keys->recv : NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001610 }
1611
1612 if (keys) {
1613 os_free(keys->send);
1614 os_free(keys->recv);
1615 os_free(keys);
1616 }
Hai Shalom81f62d82019-07-22 12:10:00 -07001617
1618 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
1619 NULL) == 0) {
1620 os_free(sm->eap_if->eapSessionId);
1621 sm->eap_if->eapSessionId = os_memdup(buf, len);
1622 if (sm->eap_if->eapSessionId) {
1623 sm->eap_if->eapSessionIdLen = len;
1624 wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
1625 sm->eap_if->eapSessionId,
1626 sm->eap_if->eapSessionIdLen);
1627 }
1628 } else {
1629 sm->eap_if->eapSessionIdLen = 0;
1630 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001631}
1632
1633
1634static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
1635 struct sta_info *sta,
1636 struct radius_msg *msg)
1637{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001638 u8 *attr_class;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001639 size_t class_len;
1640 struct eapol_state_machine *sm = sta->eapol_sm;
1641 int count, i;
1642 struct radius_attr_data *nclass;
1643 size_t nclass_count;
1644
Hai Shalomc3565922019-10-28 11:58:20 -07001645 if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001646 return;
1647
1648 radius_free_class(&sm->radius_class);
1649 count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
1650 if (count <= 0)
1651 return;
1652
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001653 nclass = os_calloc(count, sizeof(struct radius_attr_data));
Hai Shalomc3565922019-10-28 11:58:20 -07001654 if (!nclass)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001655 return;
1656
1657 nclass_count = 0;
1658
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001659 attr_class = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001660 for (i = 0; i < count; i++) {
1661 do {
1662 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001663 &attr_class, &class_len,
1664 attr_class) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001665 i = count;
1666 break;
1667 }
1668 } while (class_len < 1);
1669
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001670 nclass[nclass_count].data = os_memdup(attr_class, class_len);
Hai Shalomc3565922019-10-28 11:58:20 -07001671 if (!nclass[nclass_count].data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001672 break;
1673
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001674 nclass[nclass_count].len = class_len;
1675 nclass_count++;
1676 }
1677
1678 sm->radius_class.attr = nclass;
1679 sm->radius_class.count = nclass_count;
Hai Shalomc3565922019-10-28 11:58:20 -07001680 wpa_printf(MSG_DEBUG,
1681 "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
1682 MACSTR,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001683 (unsigned long) sm->radius_class.count,
1684 MAC2STR(sta->addr));
1685}
1686
1687
1688/* Update sta->identity based on User-Name attribute in Access-Accept */
1689static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
1690 struct sta_info *sta,
1691 struct radius_msg *msg)
1692{
1693 u8 *buf, *identity;
1694 size_t len;
1695 struct eapol_state_machine *sm = sta->eapol_sm;
1696
Hai Shalomc3565922019-10-28 11:58:20 -07001697 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001698 return;
1699
1700 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
1701 NULL) < 0)
1702 return;
1703
Dmitry Shmidt4b060592013-04-29 16:42:49 -07001704 identity = (u8 *) dup_binstr(buf, len);
Hai Shalomc3565922019-10-28 11:58:20 -07001705 if (!identity)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001706 return;
1707
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001708 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07001709 HOSTAPD_LEVEL_DEBUG,
1710 "old identity '%s' updated with User-Name from Access-Accept '%s'",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001711 sm->identity ? (char *) sm->identity : "N/A",
1712 (char *) identity);
1713
1714 os_free(sm->identity);
1715 sm->identity = identity;
1716 sm->identity_len = len;
1717}
1718
1719
Dmitry Shmidt04949592012-07-19 12:16:46 -07001720/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
1721static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
1722 struct sta_info *sta,
1723 struct radius_msg *msg)
1724{
1725 struct eapol_state_machine *sm = sta->eapol_sm;
1726 struct wpabuf *cui;
1727 u8 *buf;
1728 size_t len;
1729
Hai Shalomc3565922019-10-28 11:58:20 -07001730 if (!sm)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001731 return;
1732
1733 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
1734 &buf, &len, NULL) < 0)
1735 return;
1736
1737 cui = wpabuf_alloc_copy(buf, len);
Hai Shalomc3565922019-10-28 11:58:20 -07001738 if (!cui)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001739 return;
1740
1741 wpabuf_free(sm->radius_cui);
1742 sm->radius_cui = cui;
1743}
1744
1745
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001746#ifdef CONFIG_HS20
1747
1748static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
1749{
1750 sta->remediation = 1;
1751 os_free(sta->remediation_url);
1752 if (len > 2) {
1753 sta->remediation_url = os_malloc(len);
1754 if (!sta->remediation_url)
1755 return;
1756 sta->remediation_method = pos[0];
1757 os_memcpy(sta->remediation_url, pos + 1, len - 1);
1758 sta->remediation_url[len - 1] = '\0';
Hai Shalomc3565922019-10-28 11:58:20 -07001759 wpa_printf(MSG_DEBUG,
1760 "HS 2.0: Subscription remediation needed for "
1761 MACSTR " - server method %u URL %s",
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001762 MAC2STR(sta->addr), sta->remediation_method,
1763 sta->remediation_url);
1764 } else {
1765 sta->remediation_url = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07001766 wpa_printf(MSG_DEBUG,
1767 "HS 2.0: Subscription remediation needed for "
1768 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001769 }
1770 /* TODO: assign the STA into remediation VLAN or add filtering */
1771}
1772
1773
1774static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001775 struct sta_info *sta, const u8 *pos,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001776 size_t len)
1777{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001778 size_t url_len;
1779 unsigned int timeout;
1780
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001781 if (len < 3)
1782 return; /* Malformed information */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001783 url_len = len - 3;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001784 sta->hs20_deauth_requested = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001785 sta->hs20_deauth_on_ack = url_len == 0;
Hai Shalomc3565922019-10-28 11:58:20 -07001786 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001787 "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u URL length %zu",
1788 *pos, WPA_GET_LE16(pos + 1), url_len);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001789 wpabuf_free(sta->hs20_deauth_req);
1790 sta->hs20_deauth_req = wpabuf_alloc(len + 1);
1791 if (sta->hs20_deauth_req) {
1792 wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001793 wpabuf_put_u8(sta->hs20_deauth_req, url_len);
1794 wpabuf_put_data(sta->hs20_deauth_req, pos + 3, url_len);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001795 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00001796 timeout = hapd->conf->hs20_deauth_req_timeout;
1797 /* If there is no URL, no need to provide time to fetch it. Use a short
1798 * timeout here to allow maximum time for completing 4-way handshake and
1799 * WNM-Notification delivery. Acknowledgement of the frame will result
1800 * in cutting this wait further. */
1801 if (!url_len && timeout > 2)
1802 timeout = 2;
1803 ap_sta_session_timeout(hapd, sta, timeout);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001804}
1805
1806
1807static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
1808 struct sta_info *sta, u8 *pos,
1809 size_t len, int session_timeout)
1810{
1811 unsigned int swt;
1812 int warning_time, beacon_int;
1813
1814 if (len < 1)
1815 return; /* Malformed information */
1816 os_free(sta->hs20_session_info_url);
1817 sta->hs20_session_info_url = os_malloc(len);
Hai Shalomc3565922019-10-28 11:58:20 -07001818 if (!sta->hs20_session_info_url)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001819 return;
1820 swt = pos[0];
1821 os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
1822 sta->hs20_session_info_url[len - 1] = '\0';
Hai Shalomc3565922019-10-28 11:58:20 -07001823 wpa_printf(MSG_DEBUG,
1824 "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)",
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001825 sta->hs20_session_info_url, swt, session_timeout);
1826 if (session_timeout < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -07001827 wpa_printf(MSG_DEBUG,
1828 "HS 2.0: No Session-Timeout set - ignore session info URL");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001829 return;
1830 }
1831 if (swt == 255)
1832 swt = 1; /* Use one minute as the AP selected value */
1833
1834 if ((unsigned int) session_timeout < swt * 60)
1835 warning_time = 0;
1836 else
1837 warning_time = session_timeout - swt * 60;
1838
1839 beacon_int = hapd->iconf->beacon_int;
1840 if (beacon_int < 1)
1841 beacon_int = 100; /* best guess */
1842 sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128;
1843 if (sta->hs20_disassoc_timer > 65535)
1844 sta->hs20_disassoc_timer = 65535;
1845
1846 ap_sta_session_warning_timeout(hapd, sta, warning_time);
1847}
1848
Roshan Pius3a1667e2018-07-03 15:17:14 -07001849
1850static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
1851 struct sta_info *sta, u8 *pos,
1852 size_t len)
1853{
1854 if (len < 4)
1855 return; /* Malformed information */
1856 wpa_printf(MSG_DEBUG,
1857 "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
1858 pos[0], pos[1], pos[2], pos[3]);
1859 hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
1860}
1861
1862
1863static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
1864 struct sta_info *sta, u8 *pos, size_t len)
1865{
1866 os_free(sta->t_c_url);
1867 sta->t_c_url = os_malloc(len + 1);
1868 if (!sta->t_c_url)
1869 return;
1870 os_memcpy(sta->t_c_url, pos, len);
1871 sta->t_c_url[len] = '\0';
1872 wpa_printf(MSG_DEBUG,
1873 "HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
1874}
1875
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001876#endif /* CONFIG_HS20 */
1877
1878
1879static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
1880 struct sta_info *sta,
1881 struct radius_msg *msg,
1882 int session_timeout)
1883{
1884#ifdef CONFIG_HS20
1885 u8 *buf, *pos, *end, type, sublen;
1886 size_t len;
1887
1888 buf = NULL;
1889 sta->remediation = 0;
1890 sta->hs20_deauth_requested = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001891 sta->hs20_deauth_on_ack = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001892
1893 for (;;) {
1894 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1895 &buf, &len, buf) < 0)
1896 break;
1897 if (len < 6)
1898 continue;
1899 pos = buf;
1900 end = buf + len;
1901 if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
1902 continue;
1903 pos += 4;
1904
1905 type = *pos++;
1906 sublen = *pos++;
1907 if (sublen < 2)
1908 continue; /* invalid length */
1909 sublen -= 2; /* skip header */
1910 if (pos + sublen > end)
1911 continue; /* invalid WFA VSA */
1912
1913 switch (type) {
1914 case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
1915 ieee802_1x_hs20_sub_rem(sta, pos, sublen);
1916 break;
1917 case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
1918 ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
1919 break;
1920 case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL:
1921 ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
1922 session_timeout);
1923 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001924 case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
1925 ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
1926 break;
1927 case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
1928 ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
1929 break;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001930 }
1931 }
1932#endif /* CONFIG_HS20 */
1933}
1934
1935
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001936struct sta_id_search {
1937 u8 identifier;
1938 struct eapol_state_machine *sm;
1939};
1940
1941
1942static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
1943 struct sta_info *sta,
1944 void *ctx)
1945{
1946 struct sta_id_search *id_search = ctx;
1947 struct eapol_state_machine *sm = sta->eapol_sm;
1948
1949 if (sm && sm->radius_identifier >= 0 &&
1950 sm->radius_identifier == id_search->identifier) {
1951 id_search->sm = sm;
1952 return 1;
1953 }
1954 return 0;
1955}
1956
1957
1958static struct eapol_state_machine *
1959ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
1960{
1961 struct sta_id_search id_search;
Hai Shalomc3565922019-10-28 11:58:20 -07001962
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001963 id_search.identifier = identifier;
1964 id_search.sm = NULL;
1965 ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
1966 return id_search.sm;
1967}
1968
1969
Hai Shalom74f70d42019-02-11 14:42:39 -08001970#ifndef CONFIG_NO_VLAN
1971static int ieee802_1x_update_vlan(struct radius_msg *msg,
1972 struct hostapd_data *hapd,
1973 struct sta_info *sta)
1974{
1975 struct vlan_description vlan_desc;
1976
1977 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
1978 vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
1979 MAX_NUM_TAGGED_VLAN,
1980 vlan_desc.tagged);
1981
1982 if (vlan_desc.notempty &&
1983 !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
Hai Shalome21d4e82020-04-29 16:34:06 -07001984 sta->eapol_sm->authFail = true;
Hai Shalom74f70d42019-02-11 14:42:39 -08001985 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
1986 HOSTAPD_LEVEL_INFO,
1987 "Invalid VLAN %d%s received from RADIUS server",
1988 vlan_desc.untagged,
1989 vlan_desc.tagged[0] ? "+" : "");
1990 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
1991 ap_sta_set_vlan(hapd, sta, &vlan_desc);
1992 return -1;
1993 }
1994
1995 if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
1996 !vlan_desc.notempty) {
Hai Shalome21d4e82020-04-29 16:34:06 -07001997 sta->eapol_sm->authFail = true;
Hai Shalom74f70d42019-02-11 14:42:39 -08001998 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1999 HOSTAPD_LEVEL_INFO,
2000 "authentication server did not include required VLAN ID in Access-Accept");
2001 return -1;
2002 }
2003
2004 return ap_sta_set_vlan(hapd, sta, &vlan_desc);
2005}
2006#endif /* CONFIG_NO_VLAN */
2007
2008
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002009/**
2010 * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
2011 * @msg: RADIUS response message
2012 * @req: RADIUS request message
2013 * @shared_secret: RADIUS shared secret
2014 * @shared_secret_len: Length of shared_secret in octets
2015 * @data: Context data (struct hostapd_data *)
2016 * Returns: Processing status
2017 */
2018static RadiusRxResult
2019ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
2020 const u8 *shared_secret, size_t shared_secret_len,
2021 void *data)
2022{
2023 struct hostapd_data *hapd = data;
2024 struct sta_info *sta;
2025 u32 session_timeout = 0, termination_action, acct_interim_interval;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002026 int session_timeout_set;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002027 u32 reason_code;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002028 struct eapol_state_machine *sm;
2029 int override_eapReq = 0;
2030 struct radius_hdr *hdr = radius_msg_get_hdr(msg);
2031
2032 sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
Hai Shalomc3565922019-10-28 11:58:20 -07002033 if (!sm) {
2034 wpa_printf(MSG_DEBUG,
2035 "IEEE 802.1X: Could not find matching station for this RADIUS message");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002036 return RADIUS_RX_UNKNOWN;
2037 }
2038 sta = sm->sta;
2039
2040 /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
2041 * present when packet contains an EAP-Message attribute */
2042 if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
2043 radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
2044 0) < 0 &&
2045 radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -07002046 wpa_printf(MSG_DEBUG,
2047 "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002048 } else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
2049 req, 1)) {
Hai Shalomc3565922019-10-28 11:58:20 -07002050 wpa_printf(MSG_INFO,
2051 "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002052 return RADIUS_RX_INVALID_AUTHENTICATOR;
2053 }
2054
2055 if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
2056 hdr->code != RADIUS_CODE_ACCESS_REJECT &&
2057 hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002058 wpa_printf(MSG_INFO, "Unknown RADIUS message code");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002059 return RADIUS_RX_UNKNOWN;
2060 }
2061
2062 sm->radius_identifier = -1;
2063 wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
2064 MAC2STR(sta->addr));
2065
2066 radius_msg_free(sm->last_recv_radius);
2067 sm->last_recv_radius = msg;
2068
2069 session_timeout_set =
2070 !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
2071 &session_timeout);
2072 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
2073 &termination_action))
2074 termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
2075
2076 if (hapd->conf->acct_interim_interval == 0 &&
2077 hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
2078 radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
2079 &acct_interim_interval) == 0) {
2080 if (acct_interim_interval < 60) {
2081 hostapd_logger(hapd, sta->addr,
2082 HOSTAPD_MODULE_IEEE8021X,
2083 HOSTAPD_LEVEL_INFO,
Hai Shalomc3565922019-10-28 11:58:20 -07002084 "ignored too small Acct-Interim-Interval %d",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002085 acct_interim_interval);
2086 } else
2087 sta->acct_interim_interval = acct_interim_interval;
2088 }
2089
2090
2091 switch (hdr->code) {
2092 case RADIUS_CODE_ACCESS_ACCEPT:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002093#ifndef CONFIG_NO_VLAN
Hai Shalom74f70d42019-02-11 14:42:39 -08002094 if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
2095 ieee802_1x_update_vlan(msg, hapd, sta) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002096 break;
2097
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002098 if (sta->vlan_id > 0) {
2099 hostapd_logger(hapd, sta->addr,
2100 HOSTAPD_MODULE_RADIUS,
2101 HOSTAPD_LEVEL_INFO,
2102 "VLAN ID %d", sta->vlan_id);
2103 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002104
Dmitry Shmidt83474442015-04-15 13:47:09 -07002105 if ((sta->flags & WLAN_STA_ASSOC) &&
2106 ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002107 break;
Hai Shalom74f70d42019-02-11 14:42:39 -08002108#endif /* CONFIG_NO_VLAN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002109
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002110 sta->session_timeout_set = !!session_timeout_set;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002111 os_get_reltime(&sta->session_timeout);
2112 sta->session_timeout.sec += session_timeout;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002113
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002114 /* RFC 3580, Ch. 3.17 */
2115 if (session_timeout_set && termination_action ==
Roshan Pius3a1667e2018-07-03 15:17:14 -07002116 RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002117 sm->reAuthPeriod = session_timeout;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002118 else if (session_timeout_set)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002119 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002120 else
2121 ap_sta_no_session_timeout(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002122
Hai Shalome21d4e82020-04-29 16:34:06 -07002123 sm->eap_if->aaaSuccess = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002124 override_eapReq = 1;
2125 ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
2126 shared_secret_len);
2127 ieee802_1x_store_radius_class(hapd, sta, msg);
2128 ieee802_1x_update_sta_identity(hapd, sta, msg);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002129 ieee802_1x_update_sta_cui(hapd, sta, msg);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002130 ieee802_1x_check_hs20(hapd, sta, msg,
2131 session_timeout_set ?
2132 (int) session_timeout : -1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002133 break;
2134 case RADIUS_CODE_ACCESS_REJECT:
Hai Shalome21d4e82020-04-29 16:34:06 -07002135 sm->eap_if->aaaFail = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002136 override_eapReq = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002137 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
2138 &reason_code) == 0) {
2139 wpa_printf(MSG_DEBUG,
2140 "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
2141 MACSTR, reason_code, MAC2STR(sta->addr));
2142 sta->disconnect_reason_code = reason_code;
2143 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002144 break;
2145 case RADIUS_CODE_ACCESS_CHALLENGE:
Hai Shalome21d4e82020-04-29 16:34:06 -07002146 sm->eap_if->aaaEapReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002147 if (session_timeout_set) {
2148 /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
2149 sm->eap_if->aaaMethodTimeout = session_timeout;
2150 hostapd_logger(hapd, sm->addr,
2151 HOSTAPD_MODULE_IEEE8021X,
2152 HOSTAPD_LEVEL_DEBUG,
Hai Shalomc3565922019-10-28 11:58:20 -07002153 "using EAP timeout of %d seconds (from RADIUS)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002154 sm->eap_if->aaaMethodTimeout);
2155 } else {
2156 /*
2157 * Use dynamic retransmission behavior per EAP
2158 * specification.
2159 */
2160 sm->eap_if->aaaMethodTimeout = 0;
2161 }
2162 break;
2163 }
2164
2165 ieee802_1x_decapsulate_radius(hapd, sta);
2166 if (override_eapReq)
Hai Shalome21d4e82020-04-29 16:34:06 -07002167 sm->eap_if->aaaEapReq = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002168
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002169#ifdef CONFIG_FILS
2170#ifdef NEED_AP_MLME
Hai Shalom60840252021-02-19 19:02:11 -08002171 if (sta->flags &
2172 (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002173 /* TODO: Add a PMKSA entry on success? */
2174 ieee802_11_finish_fils_auth(
2175 hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
2176 sm->eap_if->aaaEapReqData,
2177 sm->eap_if->aaaEapKeyData,
2178 sm->eap_if->aaaEapKeyDataLen);
2179 }
2180#endif /* NEED_AP_MLME */
2181#endif /* CONFIG_FILS */
2182
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002183 eapol_auth_step(sm);
2184
2185 return RADIUS_RX_QUEUED;
2186}
2187#endif /* CONFIG_NO_RADIUS */
2188
2189
2190void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
2191{
2192 struct eapol_state_machine *sm = sta->eapol_sm;
Hai Shalomc3565922019-10-28 11:58:20 -07002193
2194 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195 return;
2196
2197 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
2198 HOSTAPD_LEVEL_DEBUG, "aborting authentication");
2199
2200#ifndef CONFIG_NO_RADIUS
2201 radius_msg_free(sm->last_recv_radius);
2202 sm->last_recv_radius = NULL;
2203#endif /* CONFIG_NO_RADIUS */
2204
2205 if (sm->eap_if->eapTimeout) {
2206 /*
2207 * Disconnect the STA since it did not reply to the last EAP
2208 * request and we cannot continue EAP processing (EAP-Failure
2209 * could only be sent if the EAP peer actually replied).
2210 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002211 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
2212 MAC2STR(sta->addr));
2213
Hai Shalome21d4e82020-04-29 16:34:06 -07002214 sm->eap_if->portEnabled = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002215 ap_sta_disconnect(hapd, sta, sta->addr,
2216 WLAN_REASON_PREV_AUTH_NOT_VALID);
2217 }
2218}
2219
2220
Hai Shalomfdcde762020-04-02 11:19:20 -07002221#ifdef CONFIG_WEP
2222
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002223static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
2224{
2225 struct eapol_authenticator *eapol = hapd->eapol_auth;
2226
2227 if (hapd->conf->default_wep_key_len < 1)
2228 return 0;
2229
2230 os_free(eapol->default_wep_key);
2231 eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
Hai Shalomc3565922019-10-28 11:58:20 -07002232 if (!eapol->default_wep_key ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 random_get_bytes(eapol->default_wep_key,
2234 hapd->conf->default_wep_key_len)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002235 wpa_printf(MSG_INFO, "Could not generate random WEP key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002236 os_free(eapol->default_wep_key);
2237 eapol->default_wep_key = NULL;
2238 return -1;
2239 }
2240
2241 wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
2242 eapol->default_wep_key,
2243 hapd->conf->default_wep_key_len);
2244
2245 return 0;
2246}
2247
2248
2249static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
2250 struct sta_info *sta, void *ctx)
2251{
2252 if (sta->eapol_sm) {
Hai Shalome21d4e82020-04-29 16:34:06 -07002253 sta->eapol_sm->eap_if->eapKeyAvailable = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002254 eapol_auth_step(sta->eapol_sm);
2255 }
2256 return 0;
2257}
2258
2259
2260static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
2261{
2262 struct hostapd_data *hapd = eloop_ctx;
2263 struct eapol_authenticator *eapol = hapd->eapol_auth;
2264
2265 if (eapol->default_wep_key_idx >= 3)
2266 eapol->default_wep_key_idx =
2267 hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
2268 else
2269 eapol->default_wep_key_idx++;
2270
2271 wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
2272 eapol->default_wep_key_idx);
Dmitry Shmidt29333592017-01-09 12:27:11 -08002273
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002274 if (ieee802_1x_rekey_broadcast(hapd)) {
2275 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07002276 HOSTAPD_LEVEL_WARNING,
2277 "failed to generate a new broadcast key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002278 os_free(eapol->default_wep_key);
2279 eapol->default_wep_key = NULL;
2280 return;
2281 }
2282
2283 /* TODO: Could setup key for RX here, but change default TX keyid only
2284 * after new broadcast key has been sent to all stations. */
2285 if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
2286 broadcast_ether_addr,
Hai Shalomfdcde762020-04-02 11:19:20 -07002287 eapol->default_wep_key_idx, 0, 1, NULL, 0,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002288 eapol->default_wep_key,
Hai Shalomfdcde762020-04-02 11:19:20 -07002289 hapd->conf->default_wep_key_len,
2290 KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07002292 HOSTAPD_LEVEL_WARNING,
2293 "failed to configure a new broadcast key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294 os_free(eapol->default_wep_key);
2295 eapol->default_wep_key = NULL;
2296 return;
2297 }
2298
2299 ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
2300
2301 if (hapd->conf->wep_rekeying_period > 0) {
2302 eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
2303 ieee802_1x_rekey, hapd, NULL);
2304 }
2305}
2306
Hai Shalomfdcde762020-04-02 11:19:20 -07002307#endif /* CONFIG_WEP */
2308
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002309
2310static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
2311 const u8 *data, size_t datalen)
2312{
2313#ifdef CONFIG_WPS
2314 struct sta_info *sta = sta_ctx;
2315
2316 if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
2317 WLAN_STA_MAYBE_WPS) {
2318 const u8 *identity;
2319 size_t identity_len;
2320 struct eapol_state_machine *sm = sta->eapol_sm;
2321
2322 identity = eap_get_identity(sm->eap, &identity_len);
2323 if (identity &&
2324 ((identity_len == WSC_ID_ENROLLEE_LEN &&
2325 os_memcmp(identity, WSC_ID_ENROLLEE,
2326 WSC_ID_ENROLLEE_LEN) == 0) ||
2327 (identity_len == WSC_ID_REGISTRAR_LEN &&
2328 os_memcmp(identity, WSC_ID_REGISTRAR,
2329 WSC_ID_REGISTRAR_LEN) == 0))) {
Hai Shalomc3565922019-10-28 11:58:20 -07002330 wpa_printf(MSG_DEBUG,
2331 "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002332 sta->flags |= WLAN_STA_WPS;
2333 }
2334 }
2335#endif /* CONFIG_WPS */
2336
2337 ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
2338}
2339
2340
2341static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
2342 const u8 *data, size_t datalen)
2343{
2344#ifndef CONFIG_NO_RADIUS
2345 struct hostapd_data *hapd = ctx;
2346 struct sta_info *sta = sta_ctx;
2347
2348 ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
2349#endif /* CONFIG_NO_RADIUS */
2350}
2351
2352
Sunil Ravi640215c2023-06-28 23:08:09 +00002353static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
2354 int preauth, int remediation, bool logoff)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002355{
2356 struct hostapd_data *hapd = ctx;
2357 struct sta_info *sta = sta_ctx;
Hai Shalomc3565922019-10-28 11:58:20 -07002358
Sunil Ravi640215c2023-06-28 23:08:09 +00002359 if (preauth) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002360 rsn_preauth_finished(hapd, sta, success);
Sunil Ravi640215c2023-06-28 23:08:09 +00002361 return false;
2362 }
2363
2364 return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002365}
2366
2367
2368static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
2369 size_t identity_len, int phase2,
2370 struct eap_user *user)
2371{
2372 struct hostapd_data *hapd = ctx;
2373 const struct hostapd_eap_user *eap_user;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002374 int i;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002375 int rv = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002376
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002377 eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
Hai Shalomc3565922019-10-28 11:58:20 -07002378 if (!eap_user)
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002379 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002380
2381 os_memset(user, 0, sizeof(*user));
2382 user->phase2 = phase2;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002383 for (i = 0; i < EAP_MAX_METHODS; i++) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002384 user->methods[i].vendor = eap_user->methods[i].vendor;
2385 user->methods[i].method = eap_user->methods[i].method;
2386 }
2387
2388 if (eap_user->password) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002389 user->password = os_memdup(eap_user->password,
2390 eap_user->password_len);
Hai Shalomc3565922019-10-28 11:58:20 -07002391 if (!user->password)
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002392 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002393 user->password_len = eap_user->password_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002394 user->password_hash = eap_user->password_hash;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002395 if (eap_user->salt && eap_user->salt_len) {
2396 user->salt = os_memdup(eap_user->salt,
2397 eap_user->salt_len);
2398 if (!user->salt)
2399 goto out;
2400 user->salt_len = eap_user->salt_len;
2401 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402 }
2403 user->force_version = eap_user->force_version;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07002404 user->macacl = eap_user->macacl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002405 user->ttls_auth = eap_user->ttls_auth;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002406 user->remediation = eap_user->remediation;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002407 rv = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002408
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002409out:
2410 if (rv)
2411 wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
2412
2413 return rv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002414}
2415
2416
2417static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
2418{
2419 struct hostapd_data *hapd = ctx;
2420 struct sta_info *sta;
Hai Shalomc3565922019-10-28 11:58:20 -07002421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002422 sta = ap_get_sta(hapd, addr);
Hai Shalomc3565922019-10-28 11:58:20 -07002423 if (!sta || !sta->eapol_sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002424 return 0;
2425 return 1;
2426}
2427
2428
2429static void ieee802_1x_logger(void *ctx, const u8 *addr,
2430 eapol_logger_level level, const char *txt)
2431{
2432#ifndef CONFIG_NO_HOSTAPD_LOGGER
2433 struct hostapd_data *hapd = ctx;
2434 int hlevel;
2435
2436 switch (level) {
2437 case EAPOL_LOGGER_WARNING:
2438 hlevel = HOSTAPD_LEVEL_WARNING;
2439 break;
2440 case EAPOL_LOGGER_INFO:
2441 hlevel = HOSTAPD_LEVEL_INFO;
2442 break;
2443 case EAPOL_LOGGER_DEBUG:
2444 default:
2445 hlevel = HOSTAPD_LEVEL_DEBUG;
2446 break;
2447 }
2448
2449 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
2450 txt);
2451#endif /* CONFIG_NO_HOSTAPD_LOGGER */
2452}
2453
2454
2455static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
2456 int authorized)
2457{
2458 struct hostapd_data *hapd = ctx;
2459 struct sta_info *sta = sta_ctx;
Hai Shalomc3565922019-10-28 11:58:20 -07002460
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002461 ieee802_1x_set_sta_authorized(hapd, sta, authorized);
2462}
2463
2464
2465static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
2466{
2467 struct hostapd_data *hapd = ctx;
2468 struct sta_info *sta = sta_ctx;
Hai Shalomc3565922019-10-28 11:58:20 -07002469
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002470 ieee802_1x_abort_auth(hapd, sta);
2471}
2472
2473
Hai Shalomfdcde762020-04-02 11:19:20 -07002474#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002475static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
2476{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002477#ifndef CONFIG_FIPS
2478#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002479 struct hostapd_data *hapd = ctx;
2480 struct sta_info *sta = sta_ctx;
Hai Shalomc3565922019-10-28 11:58:20 -07002481
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002482 ieee802_1x_tx_key(hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002483#endif /* CONFIG_NO_RC4 */
2484#endif /* CONFIG_FIPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002485}
Hai Shalomfdcde762020-04-02 11:19:20 -07002486#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002487
2488
2489static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
2490 enum eapol_event type)
2491{
2492 /* struct hostapd_data *hapd = ctx; */
2493 struct sta_info *sta = sta_ctx;
Hai Shalomc3565922019-10-28 11:58:20 -07002494
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002495 switch (type) {
2496 case EAPOL_AUTH_SM_CHANGE:
2497 wpa_auth_sm_notify(sta->wpa_sm);
2498 break;
2499 case EAPOL_AUTH_REAUTHENTICATE:
2500 wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
2501 break;
2502 }
2503}
2504
2505
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002506#ifdef CONFIG_ERP
2507
2508static struct eap_server_erp_key *
2509ieee802_1x_erp_get_key(void *ctx, const char *keyname)
2510{
2511 struct hostapd_data *hapd = ctx;
2512 struct eap_server_erp_key *erp;
2513
2514 dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key,
2515 list) {
2516 if (os_strcmp(erp->keyname_nai, keyname) == 0)
2517 return erp;
2518 }
2519
2520 return NULL;
2521}
2522
2523
2524static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
2525{
2526 struct hostapd_data *hapd = ctx;
2527
2528 dl_list_add(&hapd->erp_keys, &erp->list);
2529 return 0;
2530}
2531
2532#endif /* CONFIG_ERP */
2533
2534
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002535int ieee802_1x_init(struct hostapd_data *hapd)
2536{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002537 struct eapol_auth_config conf;
2538 struct eapol_auth_cb cb;
2539
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002540 if (hapd->mld_first_bss) {
2541 wpa_printf(MSG_DEBUG,
2542 "MLD: Using IEEE 802.1X state machine of the first BSS");
2543
2544 hapd->eapol_auth = hapd->mld_first_bss->eapol_auth;
2545 return 0;
2546 }
2547
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002548 dl_list_init(&hapd->erp_keys);
2549
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002550 os_memset(&conf, 0, sizeof(conf));
Hai Shalomc3565922019-10-28 11:58:20 -07002551 conf.eap_cfg = hapd->eap_cfg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002552 conf.ctx = hapd;
2553 conf.eap_reauth_period = hapd->conf->eap_reauth_period;
2554 conf.wpa = hapd->conf->wpa;
Hai Shalomfdcde762020-04-02 11:19:20 -07002555#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002556 conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07002557#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002558 conf.eap_req_id_text = hapd->conf->eap_req_id_text;
2559 conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002560 conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
2561 conf.erp_domain = hapd->conf->erp_domain;
Sunil Ravia04bd252022-05-02 22:54:18 -07002562#ifdef CONFIG_TESTING_OPTIONS
2563 conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success;
2564#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002565
2566 os_memset(&cb, 0, sizeof(cb));
2567 cb.eapol_send = ieee802_1x_eapol_send;
2568 cb.aaa_send = ieee802_1x_aaa_send;
2569 cb.finished = _ieee802_1x_finished;
2570 cb.get_eap_user = ieee802_1x_get_eap_user;
2571 cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
2572 cb.logger = ieee802_1x_logger;
2573 cb.set_port_authorized = ieee802_1x_set_port_authorized;
2574 cb.abort_auth = _ieee802_1x_abort_auth;
Hai Shalomfdcde762020-04-02 11:19:20 -07002575#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002576 cb.tx_key = _ieee802_1x_tx_key;
Hai Shalomfdcde762020-04-02 11:19:20 -07002577#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002578 cb.eapol_event = ieee802_1x_eapol_event;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002579#ifdef CONFIG_ERP
2580 cb.erp_get_key = ieee802_1x_erp_get_key;
2581 cb.erp_add_key = ieee802_1x_erp_add_key;
2582#endif /* CONFIG_ERP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002583
2584 hapd->eapol_auth = eapol_auth_init(&conf, &cb);
Hai Shalomc3565922019-10-28 11:58:20 -07002585 if (!hapd->eapol_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002586 return -1;
2587
2588 if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
2589 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
2590 return -1;
2591
2592#ifndef CONFIG_NO_RADIUS
2593 if (radius_client_register(hapd->radius, RADIUS_AUTH,
2594 ieee802_1x_receive_auth, hapd))
2595 return -1;
2596#endif /* CONFIG_NO_RADIUS */
2597
Hai Shalomfdcde762020-04-02 11:19:20 -07002598#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002599 if (hapd->conf->default_wep_key_len) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002600 int i;
2601
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002602 for (i = 0; i < 4; i++)
2603 hostapd_drv_set_key(hapd->conf->iface, hapd,
Hai Shalomfdcde762020-04-02 11:19:20 -07002604 WPA_ALG_NONE, NULL, i, 0, 0, NULL,
2605 0, NULL, 0, KEY_FLAG_GROUP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002606
2607 ieee802_1x_rekey(hapd, NULL);
2608
Hai Shalomc3565922019-10-28 11:58:20 -07002609 if (!hapd->eapol_auth->default_wep_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002610 return -1;
2611 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002612#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002613
2614 return 0;
2615}
2616
2617
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002618void ieee802_1x_erp_flush(struct hostapd_data *hapd)
2619{
2620 struct eap_server_erp_key *erp;
2621
2622 while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key,
2623 list)) != NULL) {
2624 dl_list_del(&erp->list);
2625 bin_clear_free(erp, sizeof(*erp));
2626 }
2627}
2628
2629
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002630void ieee802_1x_deinit(struct hostapd_data *hapd)
2631{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002632 if (hapd->mld_first_bss) {
2633 wpa_printf(MSG_DEBUG,
2634 "MLD: Deinit IEEE 802.1X state machine of a non-first BSS");
2635
2636 hapd->eapol_auth = NULL;
2637 return;
2638 }
2639
Hai Shalomfdcde762020-04-02 11:19:20 -07002640#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002641 eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07002642#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002643
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002644 if (hapd->driver && hapd->drv_priv &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002645 (hapd->conf->ieee802_1x || hapd->conf->wpa))
2646 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
2647
2648 eapol_auth_deinit(hapd->eapol_auth);
2649 hapd->eapol_auth = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002650
2651 ieee802_1x_erp_flush(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002652}
2653
2654
2655int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
2656 const u8 *buf, size_t len, int ack)
2657{
2658 struct ieee80211_hdr *hdr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002659 u8 *pos;
2660 const unsigned char rfc1042_hdr[ETH_ALEN] =
2661 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
2662
Hai Shalomc3565922019-10-28 11:58:20 -07002663 if (!sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002664 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002665 if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002666 return 0;
2667
2668 hdr = (struct ieee80211_hdr *) buf;
2669 pos = (u8 *) (hdr + 1);
2670 if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
2671 return 0;
2672 pos += sizeof(rfc1042_hdr);
2673 if (WPA_GET_BE16(pos) != ETH_P_PAE)
2674 return 0;
2675 pos += 2;
2676
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002677 return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
2678 ack);
2679}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002680
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002681
2682int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
2683 const u8 *buf, int len, int ack)
2684{
2685 const struct ieee802_1x_hdr *xhdr =
2686 (const struct ieee802_1x_hdr *) buf;
2687 const u8 *pos = buf + sizeof(*xhdr);
2688 struct ieee802_1x_eapol_key *key;
2689
2690 if (len < (int) sizeof(*xhdr))
2691 return 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002692 wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
2693 " TX status - version=%d type=%d length=%d - ack=%d",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002694 MAC2STR(sta->addr), xhdr->version, xhdr->type,
2695 be_to_host16(xhdr->length), ack);
2696
Dmitry Shmidt29333592017-01-09 12:27:11 -08002697#ifdef CONFIG_WPS
2698 if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
2699 (sta->flags & WLAN_STA_WPS) &&
2700 ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
2701 wpa_printf(MSG_DEBUG,
2702 "WPS: Indicate EAP completion on ACK for EAP-Failure");
2703 hostapd_wps_eap_completed(hapd);
2704 }
2705#endif /* CONFIG_WPS */
2706
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002707 if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
2708 return 0;
2709
2710 if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002711 const struct wpa_eapol_key *wpa;
Hai Shalomc3565922019-10-28 11:58:20 -07002712
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002713 wpa = (const struct wpa_eapol_key *) pos;
2714 if (wpa->type == EAPOL_KEY_TYPE_RSN ||
2715 wpa->type == EAPOL_KEY_TYPE_WPA)
2716 wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
2717 sta->wpa_sm, ack);
2718 }
2719
2720 /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
2721 * or Authenticator state machines, but EAPOL-Key packets are not
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002722 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002723 * packets couple of times because otherwise STA keys become
2724 * unsynchronized with AP. */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002725 if (!ack && pos + sizeof(*key) <= buf + len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002726 key = (struct ieee802_1x_eapol_key *) pos;
2727 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
Hai Shalomc3565922019-10-28 11:58:20 -07002728 HOSTAPD_LEVEL_DEBUG,
2729 "did not Ack EAPOL-Key frame (%scast index=%d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002730 key->key_index & BIT(7) ? "uni" : "broad",
2731 key->key_index & ~BIT(7));
2732 /* TODO: re-send EAPOL-Key couple of times (with short delay
2733 * between them?). If all attempt fail, report error and
2734 * deauthenticate STA so that it will get new keys when
2735 * authenticating again (e.g., after returning in range).
2736 * Separate limit/transmit state needed both for unicast and
2737 * broadcast keys(?) */
2738 }
2739 /* TODO: could move unicast key configuration from ieee802_1x_tx_key()
2740 * to here and change the key only if the EAPOL-Key packet was Acked.
2741 */
2742
2743 return 1;
2744}
2745
2746
2747u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
2748{
Hai Shalomc3565922019-10-28 11:58:20 -07002749 if (!sm || !sm->identity)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002750 return NULL;
2751
2752 *len = sm->identity_len;
2753 return sm->identity;
2754}
2755
2756
2757u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
2758 int idx)
2759{
Hai Shalomc3565922019-10-28 11:58:20 -07002760 if (!sm || !sm->radius_class.attr ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002761 idx >= (int) sm->radius_class.count)
2762 return NULL;
2763
2764 *len = sm->radius_class.attr[idx].len;
2765 return sm->radius_class.attr[idx].data;
2766}
2767
2768
Dmitry Shmidt04949592012-07-19 12:16:46 -07002769struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
2770{
Hai Shalomc3565922019-10-28 11:58:20 -07002771 if (!sm)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002772 return NULL;
2773 return sm->radius_cui;
2774}
2775
2776
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002777const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
2778{
Jouni Malinen75ecf522011-06-27 15:19:46 -07002779 *len = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002780 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002781 return NULL;
2782
2783 *len = sm->eap_if->eapKeyDataLen;
2784 return sm->eap_if->eapKeyData;
2785}
2786
2787
Hai Shalom81f62d82019-07-22 12:10:00 -07002788#ifdef CONFIG_MACSEC
2789const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
2790 size_t *len)
2791{
2792 *len = 0;
2793 if (!sm || !sm->eap_if)
2794 return NULL;
2795
2796 *len = sm->eap_if->eapSessionIdLen;
2797 return sm->eap_if->eapSessionId;
2798}
2799#endif /* CONFIG_MACSEC */
2800
2801
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002802void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
Hai Shalome21d4e82020-04-29 16:34:06 -07002803 bool enabled)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002804{
Hai Shalomc3565922019-10-28 11:58:20 -07002805 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002806 return;
Hai Shalome21d4e82020-04-29 16:34:06 -07002807 sm->eap_if->portEnabled = enabled;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002808 eapol_auth_step(sm);
2809}
2810
2811
Hai Shalome21d4e82020-04-29 16:34:06 -07002812void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002813{
Hai Shalomc3565922019-10-28 11:58:20 -07002814 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002815 return;
Hai Shalome21d4e82020-04-29 16:34:06 -07002816 sm->portValid = valid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002817 eapol_auth_step(sm);
2818}
2819
2820
Hai Shalome21d4e82020-04-29 16:34:06 -07002821void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002822{
Hai Shalomc3565922019-10-28 11:58:20 -07002823 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002824 return;
2825 if (pre_auth)
2826 sm->flags |= EAPOL_SM_PREAUTH;
2827 else
2828 sm->flags &= ~EAPOL_SM_PREAUTH;
2829}
2830
2831
Hai Shalome21d4e82020-04-29 16:34:06 -07002832static const char * bool_txt(bool val)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002833{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07002834 return val ? "TRUE" : "FALSE";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002835}
2836
2837
2838int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
2839{
2840 /* TODO */
2841 return 0;
2842}
2843
2844
2845int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
2846 char *buf, size_t buflen)
2847{
2848 int len = 0, ret;
2849 struct eapol_state_machine *sm = sta->eapol_sm;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002850 struct os_reltime diff;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08002851 const char *name1;
2852 const char *name2;
Hai Shalom74f70d42019-02-11 14:42:39 -08002853 char *identity_buf = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002854
Hai Shalomc3565922019-10-28 11:58:20 -07002855 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002856 return 0;
2857
2858 ret = os_snprintf(buf + len, buflen - len,
2859 "dot1xPaePortNumber=%d\n"
2860 "dot1xPaePortProtocolVersion=%d\n"
2861 "dot1xPaePortCapabilities=1\n"
2862 "dot1xPaePortInitialize=%d\n"
2863 "dot1xPaePortReauthenticate=FALSE\n",
2864 sta->aid,
2865 EAPOL_VERSION,
2866 sm->initialize);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002867 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002868 return len;
2869 len += ret;
2870
2871 /* dot1xAuthConfigTable */
2872 ret = os_snprintf(buf + len, buflen - len,
2873 "dot1xAuthPaeState=%d\n"
2874 "dot1xAuthBackendAuthState=%d\n"
2875 "dot1xAuthAdminControlledDirections=%d\n"
2876 "dot1xAuthOperControlledDirections=%d\n"
2877 "dot1xAuthAuthControlledPortStatus=%d\n"
2878 "dot1xAuthAuthControlledPortControl=%d\n"
2879 "dot1xAuthQuietPeriod=%u\n"
2880 "dot1xAuthServerTimeout=%u\n"
2881 "dot1xAuthReAuthPeriod=%u\n"
2882 "dot1xAuthReAuthEnabled=%s\n"
2883 "dot1xAuthKeyTxEnabled=%s\n",
2884 sm->auth_pae_state + 1,
2885 sm->be_auth_state + 1,
2886 sm->adminControlledDirections,
2887 sm->operControlledDirections,
2888 sm->authPortStatus,
2889 sm->portControl,
2890 sm->quietPeriod,
2891 sm->serverTimeout,
2892 sm->reAuthPeriod,
2893 bool_txt(sm->reAuthEnabled),
2894 bool_txt(sm->keyTxEnabled));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002895 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002896 return len;
2897 len += ret;
2898
2899 /* dot1xAuthStatsTable */
2900 ret = os_snprintf(buf + len, buflen - len,
2901 "dot1xAuthEapolFramesRx=%u\n"
2902 "dot1xAuthEapolFramesTx=%u\n"
2903 "dot1xAuthEapolStartFramesRx=%u\n"
2904 "dot1xAuthEapolLogoffFramesRx=%u\n"
2905 "dot1xAuthEapolRespIdFramesRx=%u\n"
2906 "dot1xAuthEapolRespFramesRx=%u\n"
2907 "dot1xAuthEapolReqIdFramesTx=%u\n"
2908 "dot1xAuthEapolReqFramesTx=%u\n"
2909 "dot1xAuthInvalidEapolFramesRx=%u\n"
2910 "dot1xAuthEapLengthErrorFramesRx=%u\n"
2911 "dot1xAuthLastEapolFrameVersion=%u\n"
2912 "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
2913 sm->dot1xAuthEapolFramesRx,
2914 sm->dot1xAuthEapolFramesTx,
2915 sm->dot1xAuthEapolStartFramesRx,
2916 sm->dot1xAuthEapolLogoffFramesRx,
2917 sm->dot1xAuthEapolRespIdFramesRx,
2918 sm->dot1xAuthEapolRespFramesRx,
2919 sm->dot1xAuthEapolReqIdFramesTx,
2920 sm->dot1xAuthEapolReqFramesTx,
2921 sm->dot1xAuthInvalidEapolFramesRx,
2922 sm->dot1xAuthEapLengthErrorFramesRx,
2923 sm->dot1xAuthLastEapolFrameVersion,
2924 MAC2STR(sm->addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002925 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002926 return len;
2927 len += ret;
2928
2929 /* dot1xAuthDiagTable */
2930 ret = os_snprintf(buf + len, buflen - len,
2931 "dot1xAuthEntersConnecting=%u\n"
2932 "dot1xAuthEapLogoffsWhileConnecting=%u\n"
2933 "dot1xAuthEntersAuthenticating=%u\n"
2934 "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
2935 "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
2936 "dot1xAuthAuthFailWhileAuthenticating=%u\n"
2937 "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
2938 "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
2939 "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
2940 "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
2941 "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
2942 "dot1xAuthBackendResponses=%u\n"
2943 "dot1xAuthBackendAccessChallenges=%u\n"
2944 "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
2945 "dot1xAuthBackendAuthSuccesses=%u\n"
2946 "dot1xAuthBackendAuthFails=%u\n",
2947 sm->authEntersConnecting,
2948 sm->authEapLogoffsWhileConnecting,
2949 sm->authEntersAuthenticating,
2950 sm->authAuthSuccessesWhileAuthenticating,
2951 sm->authAuthTimeoutsWhileAuthenticating,
2952 sm->authAuthFailWhileAuthenticating,
2953 sm->authAuthEapStartsWhileAuthenticating,
2954 sm->authAuthEapLogoffWhileAuthenticating,
2955 sm->authAuthReauthsWhileAuthenticated,
2956 sm->authAuthEapStartsWhileAuthenticated,
2957 sm->authAuthEapLogoffWhileAuthenticated,
2958 sm->backendResponses,
2959 sm->backendAccessChallenges,
2960 sm->backendOtherRequestsToSupplicant,
2961 sm->backendAuthSuccesses,
2962 sm->backendAuthFails);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002963 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002964 return len;
2965 len += ret;
2966
2967 /* dot1xAuthSessionStatsTable */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002968 os_reltime_age(&sta->acct_session_start, &diff);
Hai Shalom74f70d42019-02-11 14:42:39 -08002969 if (sm->eap && !sm->identity) {
2970 const u8 *id;
2971 size_t id_len;
2972
2973 id = eap_get_identity(sm->eap, &id_len);
2974 if (id)
2975 identity_buf = dup_binstr(id, id_len);
2976 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002977 ret = os_snprintf(buf + len, buflen - len,
2978 /* TODO: dot1xAuthSessionOctetsRx */
2979 /* TODO: dot1xAuthSessionOctetsTx */
2980 /* TODO: dot1xAuthSessionFramesRx */
2981 /* TODO: dot1xAuthSessionFramesTx */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002982 "dot1xAuthSessionId=%016llX\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002983 "dot1xAuthSessionAuthenticMethod=%d\n"
2984 "dot1xAuthSessionTime=%u\n"
2985 "dot1xAuthSessionTerminateCause=999\n"
2986 "dot1xAuthSessionUserName=%s\n",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002987 (unsigned long long) sta->acct_session_id,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002988 (wpa_key_mgmt_wpa_ieee8021x(
2989 wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
2990 1 : 2,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002991 (unsigned int) diff.sec,
Hai Shalom021b0b52019-04-10 11:17:58 -07002992 sm->identity ? (char *) sm->identity :
2993 (identity_buf ? identity_buf : "N/A"));
Hai Shalom74f70d42019-02-11 14:42:39 -08002994 os_free(identity_buf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002995 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002996 return len;
2997 len += ret;
2998
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002999 if (sm->acct_multi_session_id) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003000 ret = os_snprintf(buf + len, buflen - len,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003001 "authMultiSessionId=%016llX\n",
3002 (unsigned long long)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08003003 sm->acct_multi_session_id);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003004 if (os_snprintf_error(buflen - len, ret))
3005 return len;
3006 len += ret;
3007 }
3008
Dmitry Shmidt96be6222014-02-13 10:16:51 -08003009 name1 = eap_server_get_name(0, sm->eap_type_authsrv);
3010 name2 = eap_server_get_name(0, sm->eap_type_supp);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003011 ret = os_snprintf(buf + len, buflen - len,
3012 "last_eap_type_as=%d (%s)\n"
3013 "last_eap_type_sta=%d (%s)\n",
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003014 sm->eap_type_authsrv, name1,
3015 sm->eap_type_supp, name2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003016 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003017 return len;
3018 len += ret;
3019
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003020 return len;
3021}
3022
3023
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003024#ifdef CONFIG_HS20
3025static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
3026{
3027 struct hostapd_data *hapd = eloop_ctx;
3028 struct sta_info *sta = timeout_ctx;
3029
3030 if (sta->remediation) {
3031 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
3032 MACSTR " to indicate Subscription Remediation",
3033 MAC2STR(sta->addr));
3034 hs20_send_wnm_notification(hapd, sta->addr,
3035 sta->remediation_method,
3036 sta->remediation_url);
3037 os_free(sta->remediation_url);
3038 sta->remediation_url = NULL;
3039 }
3040
3041 if (sta->hs20_deauth_req) {
3042 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
3043 MACSTR " to indicate imminent deauthentication",
3044 MAC2STR(sta->addr));
3045 hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
3046 sta->hs20_deauth_req);
3047 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003048
3049 if (sta->hs20_t_c_filtering) {
3050 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
3051 MACSTR " to indicate Terms and Conditions filtering",
3052 MAC2STR(sta->addr));
3053 hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
3054 os_free(sta->t_c_url);
3055 sta->t_c_url = NULL;
3056 }
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003057}
3058#endif /* CONFIG_HS20 */
3059
3060
Sunil Ravi640215c2023-06-28 23:08:09 +00003061static bool ieee802_1x_finished(struct hostapd_data *hapd,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003062 struct sta_info *sta, int success,
Sunil Ravi640215c2023-06-28 23:08:09 +00003063 int remediation, bool logoff)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003064{
3065 const u8 *key;
3066 size_t len;
3067 /* TODO: get PMKLifetime from WPA parameters */
3068 static const int dot11RSNAConfigPMKLifetime = 43200;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07003069 unsigned int session_timeout;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003070 struct os_reltime now, remaining;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003071
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003072#ifdef CONFIG_HS20
3073 if (remediation && !sta->remediation) {
3074 sta->remediation = 1;
3075 os_free(sta->remediation_url);
3076 sta->remediation_url =
3077 os_strdup(hapd->conf->subscr_remediation_url);
3078 sta->remediation_method = 1; /* SOAP-XML SPP */
3079 }
3080
Roshan Pius3a1667e2018-07-03 15:17:14 -07003081 if (success && (sta->remediation || sta->hs20_deauth_req ||
3082 sta->hs20_t_c_filtering)) {
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003083 wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
3084 MACSTR " in 100 ms", MAC2STR(sta->addr));
3085 eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
3086 eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
3087 hapd, sta);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003088 }
3089#endif /* CONFIG_HS20 */
3090
Hai Shalom81f62d82019-07-22 12:10:00 -07003091#ifdef CONFIG_MACSEC
3092 ieee802_1x_notify_create_actor_hapd(hapd, sta);
3093#endif /* CONFIG_MACSEC */
3094
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003095 key = ieee802_1x_get_key(sta->eapol_sm, &len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003096 if (sta->session_timeout_set) {
3097 os_get_reltime(&now);
3098 os_reltime_sub(&sta->session_timeout, &now, &remaining);
3099 session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
3100 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07003101 session_timeout = dot11RSNAConfigPMKLifetime;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003102 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003103 if (success && key && len >= PMK_LEN && !sta->remediation &&
3104 !sta->hs20_deauth_requested &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003105 wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003106 sta->eapol_sm) == 0) {
3107 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
3108 HOSTAPD_LEVEL_DEBUG,
3109 "Added PMKSA cache entry (IEEE 802.1X)");
3110 }
3111
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003112 if (!success) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003113 /*
3114 * Many devices require deauthentication after WPS provisioning
3115 * and some may not be be able to do that themselves, so
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003116 * disconnect the client here. In addition, this may also
3117 * benefit IEEE 802.1X/EAPOL authentication cases, too since
3118 * the EAPOL PAE state machine would remain in HELD state for
3119 * considerable amount of time and some EAP methods, like
3120 * EAP-FAST with anonymous provisioning, may require another
3121 * EAPOL authentication to be started to complete connection.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003122 */
Sunil Ravi640215c2023-06-28 23:08:09 +00003123 ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
3124 logoff ? 0 : 10);
3125 if (logoff && sta->wpa_sm)
3126 return true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003127 }
Sunil Ravi640215c2023-06-28 23:08:09 +00003128
3129 return false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003130}