1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / IEEE 802.1X-2004 Authenticator 34bc52338SCy Schubert * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10*206b73d0SCy Schubert #ifdef CONFIG_SQLITE 11*206b73d0SCy Schubert #include <sqlite3.h> 12*206b73d0SCy Schubert #endif /* CONFIG_SQLITE */ 13e28a4053SRui Paulo 14e28a4053SRui Paulo #include "utils/common.h" 15e28a4053SRui Paulo #include "utils/eloop.h" 16e28a4053SRui Paulo #include "crypto/md5.h" 17e28a4053SRui Paulo #include "crypto/crypto.h" 18f05cddf9SRui Paulo #include "crypto/random.h" 19e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 20e28a4053SRui Paulo #include "radius/radius.h" 21e28a4053SRui Paulo #include "radius/radius_client.h" 22e28a4053SRui Paulo #include "eap_server/eap.h" 23e28a4053SRui Paulo #include "eap_common/eap_wsc_common.h" 24e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h" 25e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h" 26f05cddf9SRui Paulo #include "p2p/p2p.h" 27e28a4053SRui Paulo #include "hostapd.h" 28e28a4053SRui Paulo #include "accounting.h" 29e28a4053SRui Paulo #include "sta_info.h" 30e28a4053SRui Paulo #include "wpa_auth.h" 31e28a4053SRui Paulo #include "preauth_auth.h" 32e28a4053SRui Paulo #include "pmksa_cache_auth.h" 33e28a4053SRui Paulo #include "ap_config.h" 34f05cddf9SRui Paulo #include "ap_drv_ops.h" 355b9c547cSRui Paulo #include "wps_hostapd.h" 365b9c547cSRui Paulo #include "hs20.h" 3785732ac8SCy Schubert /* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */ 3885732ac8SCy Schubert #include "ieee802_11.h" 39e28a4053SRui Paulo #include "ieee802_1x.h" 40*206b73d0SCy Schubert #include "wpa_auth_kay.h" 41e28a4053SRui Paulo 42e28a4053SRui Paulo 43780fb4a2SCy Schubert #ifdef CONFIG_HS20 44780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); 45780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 46e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 475b9c547cSRui Paulo struct sta_info *sta, int success, 485b9c547cSRui Paulo int remediation); 49e28a4053SRui Paulo 50e28a4053SRui Paulo 51e28a4053SRui Paulo static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 52e28a4053SRui Paulo u8 type, const u8 *data, size_t datalen) 53e28a4053SRui Paulo { 54e28a4053SRui Paulo u8 *buf; 55e28a4053SRui Paulo struct ieee802_1x_hdr *xhdr; 56e28a4053SRui Paulo size_t len; 57e28a4053SRui Paulo int encrypt = 0; 58e28a4053SRui Paulo 59e28a4053SRui Paulo len = sizeof(*xhdr) + datalen; 60e28a4053SRui Paulo buf = os_zalloc(len); 61e28a4053SRui Paulo if (buf == NULL) { 62e28a4053SRui Paulo wpa_printf(MSG_ERROR, "malloc() failed for " 63e28a4053SRui Paulo "ieee802_1x_send(len=%lu)", 64e28a4053SRui Paulo (unsigned long) len); 65e28a4053SRui Paulo return; 66e28a4053SRui Paulo } 67e28a4053SRui Paulo 68e28a4053SRui Paulo xhdr = (struct ieee802_1x_hdr *) buf; 69e28a4053SRui Paulo xhdr->version = hapd->conf->eapol_version; 70*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 71*206b73d0SCy Schubert if (xhdr->version > 2 && hapd->conf->macsec_policy == 0) 72*206b73d0SCy Schubert xhdr->version = 2; 73*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 74e28a4053SRui Paulo xhdr->type = type; 75e28a4053SRui Paulo xhdr->length = host_to_be16(datalen); 76e28a4053SRui Paulo 77e28a4053SRui Paulo if (datalen > 0 && data != NULL) 78e28a4053SRui Paulo os_memcpy(xhdr + 1, data, datalen); 79e28a4053SRui Paulo 80e28a4053SRui Paulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 81e28a4053SRui Paulo encrypt = 1; 825b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 835b9c547cSRui Paulo if (hapd->ext_eapol_frame_io) { 845b9c547cSRui Paulo size_t hex_len = 2 * len + 1; 855b9c547cSRui Paulo char *hex = os_malloc(hex_len); 865b9c547cSRui Paulo 875b9c547cSRui Paulo if (hex) { 885b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, buf, len); 895b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, 905b9c547cSRui Paulo "EAPOL-TX " MACSTR " %s", 915b9c547cSRui Paulo MAC2STR(sta->addr), hex); 925b9c547cSRui Paulo os_free(hex); 935b9c547cSRui Paulo } 945b9c547cSRui Paulo } else 955b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 96e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 97e28a4053SRui Paulo rsn_preauth_send(hapd, sta, buf, len); 98e28a4053SRui Paulo } else { 99f05cddf9SRui Paulo hostapd_drv_hapd_send_eapol( 100f05cddf9SRui Paulo hapd, sta->addr, buf, len, 101f05cddf9SRui Paulo encrypt, hostapd_sta_flags_to_drv(sta->flags)); 102e28a4053SRui Paulo } 103e28a4053SRui Paulo 104e28a4053SRui Paulo os_free(buf); 105e28a4053SRui Paulo } 106e28a4053SRui Paulo 107e28a4053SRui Paulo 108e28a4053SRui Paulo void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 109e28a4053SRui Paulo struct sta_info *sta, int authorized) 110e28a4053SRui Paulo { 111e28a4053SRui Paulo int res; 112e28a4053SRui Paulo 113e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 114e28a4053SRui Paulo return; 115e28a4053SRui Paulo 116e28a4053SRui Paulo if (authorized) { 117f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 1); 118f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 1); 119e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 120e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 121e28a4053SRui Paulo } else { 122f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 123f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 0); 124e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 125e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 126e28a4053SRui Paulo } 127e28a4053SRui Paulo 128e28a4053SRui Paulo if (res && errno != ENOENT) { 1295b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 1305b9c547cSRui Paulo " flags for kernel driver (errno=%d).", 1315b9c547cSRui Paulo MAC2STR(sta->addr), errno); 132e28a4053SRui Paulo } 133e28a4053SRui Paulo 134f05cddf9SRui Paulo if (authorized) { 1355b9c547cSRui Paulo os_get_reltime(&sta->connected_time); 136e28a4053SRui Paulo accounting_sta_start(hapd, sta); 137e28a4053SRui Paulo } 138f05cddf9SRui Paulo } 139e28a4053SRui Paulo 140e28a4053SRui Paulo 141325151a3SRui Paulo #ifndef CONFIG_FIPS 142325151a3SRui Paulo #ifndef CONFIG_NO_RC4 143325151a3SRui Paulo 144e28a4053SRui Paulo static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 145e28a4053SRui Paulo struct sta_info *sta, 146e28a4053SRui Paulo int idx, int broadcast, 147e28a4053SRui Paulo u8 *key_data, size_t key_len) 148e28a4053SRui Paulo { 149e28a4053SRui Paulo u8 *buf, *ekey; 150e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 151e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 152e28a4053SRui Paulo size_t len, ekey_len; 153e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 154e28a4053SRui Paulo 155e28a4053SRui Paulo if (sm == NULL) 156e28a4053SRui Paulo return; 157e28a4053SRui Paulo 158e28a4053SRui Paulo len = sizeof(*key) + key_len; 159e28a4053SRui Paulo buf = os_zalloc(sizeof(*hdr) + len); 160e28a4053SRui Paulo if (buf == NULL) 161e28a4053SRui Paulo return; 162e28a4053SRui Paulo 163e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 164e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 165e28a4053SRui Paulo key->type = EAPOL_KEY_TYPE_RC4; 166f05cddf9SRui Paulo WPA_PUT_BE16(key->key_length, key_len); 167e28a4053SRui Paulo wpa_get_ntp_timestamp(key->replay_counter); 168*206b73d0SCy Schubert if (os_memcmp(key->replay_counter, 169*206b73d0SCy Schubert hapd->last_1x_eapol_key_replay_counter, 170*206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN) <= 0) { 171*206b73d0SCy Schubert /* NTP timestamp did not increment from last EAPOL-Key frame; 172*206b73d0SCy Schubert * use previously used value + 1 instead. */ 173*206b73d0SCy Schubert inc_byte_array(hapd->last_1x_eapol_key_replay_counter, 174*206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 175*206b73d0SCy Schubert os_memcpy(key->replay_counter, 176*206b73d0SCy Schubert hapd->last_1x_eapol_key_replay_counter, 177*206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 178*206b73d0SCy Schubert } else { 179*206b73d0SCy Schubert os_memcpy(hapd->last_1x_eapol_key_replay_counter, 180*206b73d0SCy Schubert key->replay_counter, 181*206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 182*206b73d0SCy Schubert } 183e28a4053SRui Paulo 184f05cddf9SRui Paulo if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 185e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 186e28a4053SRui Paulo os_free(buf); 187e28a4053SRui Paulo return; 188e28a4053SRui Paulo } 189e28a4053SRui Paulo 190e28a4053SRui Paulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 191e28a4053SRui Paulo if (hapd->conf->eapol_key_index_workaround) { 192e28a4053SRui Paulo /* According to some information, WinXP Supplicant seems to 193e28a4053SRui Paulo * interpret bit7 as an indication whether the key is to be 194e28a4053SRui Paulo * activated, so make it possible to enable workaround that 195e28a4053SRui Paulo * sets this bit for all keys. */ 196e28a4053SRui Paulo key->key_index |= BIT(7); 197e28a4053SRui Paulo } 198e28a4053SRui Paulo 199e28a4053SRui Paulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 200e28a4053SRui Paulo * MSK[32..63] is used to sign the message. */ 201e28a4053SRui Paulo if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 202e28a4053SRui Paulo wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 203e28a4053SRui Paulo "and signing EAPOL-Key"); 204e28a4053SRui Paulo os_free(buf); 205e28a4053SRui Paulo return; 206e28a4053SRui Paulo } 207e28a4053SRui Paulo os_memcpy((u8 *) (key + 1), key_data, key_len); 208e28a4053SRui Paulo ekey_len = sizeof(key->key_iv) + 32; 209e28a4053SRui Paulo ekey = os_malloc(ekey_len); 210e28a4053SRui Paulo if (ekey == NULL) { 211e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 212e28a4053SRui Paulo os_free(buf); 213e28a4053SRui Paulo return; 214e28a4053SRui Paulo } 215e28a4053SRui Paulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 216e28a4053SRui Paulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 217e28a4053SRui Paulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 218e28a4053SRui Paulo os_free(ekey); 219e28a4053SRui Paulo 220e28a4053SRui Paulo /* This header is needed here for HMAC-MD5, but it will be regenerated 221e28a4053SRui Paulo * in ieee802_1x_send() */ 222e28a4053SRui Paulo hdr->version = hapd->conf->eapol_version; 223*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 224*206b73d0SCy Schubert if (hdr->version > 2) 225*206b73d0SCy Schubert hdr->version = 2; 226*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 227e28a4053SRui Paulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 228e28a4053SRui Paulo hdr->length = host_to_be16(len); 229e28a4053SRui Paulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 230e28a4053SRui Paulo key->key_signature); 231e28a4053SRui Paulo 232e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 233e28a4053SRui Paulo " (%s index=%d)", MAC2STR(sm->addr), 234e28a4053SRui Paulo broadcast ? "broadcast" : "unicast", idx); 235e28a4053SRui Paulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 236e28a4053SRui Paulo if (sta->eapol_sm) 237e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 238e28a4053SRui Paulo os_free(buf); 239e28a4053SRui Paulo } 240e28a4053SRui Paulo 241e28a4053SRui Paulo 242325151a3SRui Paulo static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 243e28a4053SRui Paulo { 244e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 245e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 246e28a4053SRui Paulo 247e28a4053SRui Paulo if (sm == NULL || !sm->eap_if->eapKeyData) 248e28a4053SRui Paulo return; 249e28a4053SRui Paulo 250e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 251e28a4053SRui Paulo MAC2STR(sta->addr)); 252e28a4053SRui Paulo 253e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 254780fb4a2SCy Schubert if (sta->vlan_id > 0) { 2555b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 2565b9c547cSRui Paulo return; 2575b9c547cSRui Paulo } 258e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */ 2595b9c547cSRui Paulo 260e28a4053SRui Paulo if (eapol->default_wep_key) { 261e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 262e28a4053SRui Paulo eapol->default_wep_key, 263e28a4053SRui Paulo hapd->conf->default_wep_key_len); 264e28a4053SRui Paulo } 265e28a4053SRui Paulo 266e28a4053SRui Paulo if (hapd->conf->individual_wep_key_len > 0) { 267e28a4053SRui Paulo u8 *ikey; 268e28a4053SRui Paulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 269e28a4053SRui Paulo if (ikey == NULL || 270f05cddf9SRui Paulo random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 271f05cddf9SRui Paulo { 272e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not generate random " 273e28a4053SRui Paulo "individual WEP key."); 274e28a4053SRui Paulo os_free(ikey); 275e28a4053SRui Paulo return; 276e28a4053SRui Paulo } 277e28a4053SRui Paulo 278e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 279e28a4053SRui Paulo ikey, hapd->conf->individual_wep_key_len); 280e28a4053SRui Paulo 281e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 282e28a4053SRui Paulo hapd->conf->individual_wep_key_len); 283e28a4053SRui Paulo 284e28a4053SRui Paulo /* TODO: set encryption in TX callback, i.e., only after STA 285e28a4053SRui Paulo * has ACKed EAPOL-Key frame */ 286f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 287e28a4053SRui Paulo sta->addr, 0, 1, NULL, 0, ikey, 288e28a4053SRui Paulo hapd->conf->individual_wep_key_len)) { 289e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not set individual WEP " 290e28a4053SRui Paulo "encryption."); 291e28a4053SRui Paulo } 292e28a4053SRui Paulo 293e28a4053SRui Paulo os_free(ikey); 294e28a4053SRui Paulo } 295e28a4053SRui Paulo } 296e28a4053SRui Paulo 297325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 298325151a3SRui Paulo #endif /* CONFIG_FIPS */ 299325151a3SRui Paulo 300e28a4053SRui Paulo 301e28a4053SRui Paulo const char *radius_mode_txt(struct hostapd_data *hapd) 302e28a4053SRui Paulo { 303e28a4053SRui Paulo switch (hapd->iface->conf->hw_mode) { 304f05cddf9SRui Paulo case HOSTAPD_MODE_IEEE80211AD: 305f05cddf9SRui Paulo return "802.11ad"; 306e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211A: 307e28a4053SRui Paulo return "802.11a"; 308e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211G: 309e28a4053SRui Paulo return "802.11g"; 310e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211B: 311e28a4053SRui Paulo default: 312e28a4053SRui Paulo return "802.11b"; 313e28a4053SRui Paulo } 314e28a4053SRui Paulo } 315e28a4053SRui Paulo 316e28a4053SRui Paulo 317e28a4053SRui Paulo int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 318e28a4053SRui Paulo { 319e28a4053SRui Paulo int i; 320e28a4053SRui Paulo u8 rate = 0; 321e28a4053SRui Paulo 322e28a4053SRui Paulo for (i = 0; i < sta->supported_rates_len; i++) 323e28a4053SRui Paulo if ((sta->supported_rates[i] & 0x7f) > rate) 324e28a4053SRui Paulo rate = sta->supported_rates[i] & 0x7f; 325e28a4053SRui Paulo 326e28a4053SRui Paulo return rate; 327e28a4053SRui Paulo } 328e28a4053SRui Paulo 329e28a4053SRui Paulo 330e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 331e28a4053SRui Paulo static void ieee802_1x_learn_identity(struct hostapd_data *hapd, 332e28a4053SRui Paulo struct eapol_state_machine *sm, 333e28a4053SRui Paulo const u8 *eap, size_t len) 334e28a4053SRui Paulo { 335e28a4053SRui Paulo const u8 *identity; 336e28a4053SRui Paulo size_t identity_len; 3375b9c547cSRui Paulo const struct eap_hdr *hdr = (const struct eap_hdr *) eap; 338e28a4053SRui Paulo 339e28a4053SRui Paulo if (len <= sizeof(struct eap_hdr) || 3405b9c547cSRui Paulo (hdr->code == EAP_CODE_RESPONSE && 3415b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) || 3425b9c547cSRui Paulo (hdr->code == EAP_CODE_INITIATE && 3435b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) || 3445b9c547cSRui Paulo (hdr->code != EAP_CODE_RESPONSE && 3455b9c547cSRui Paulo hdr->code != EAP_CODE_INITIATE)) 346e28a4053SRui Paulo return; 347e28a4053SRui Paulo 34885732ac8SCy Schubert eap_erp_update_identity(sm->eap, eap, len); 349e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 350e28a4053SRui Paulo if (identity == NULL) 351e28a4053SRui Paulo return; 352e28a4053SRui Paulo 353e28a4053SRui Paulo /* Save station identity for future RADIUS packets */ 354e28a4053SRui Paulo os_free(sm->identity); 3555b9c547cSRui Paulo sm->identity = (u8 *) dup_binstr(identity, identity_len); 356e28a4053SRui Paulo if (sm->identity == NULL) { 357e28a4053SRui Paulo sm->identity_len = 0; 358e28a4053SRui Paulo return; 359e28a4053SRui Paulo } 360e28a4053SRui Paulo 361e28a4053SRui Paulo sm->identity_len = identity_len; 362e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 363e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 364e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx++; 365e28a4053SRui Paulo } 366e28a4053SRui Paulo 367e28a4053SRui Paulo 3685b9c547cSRui Paulo static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, 3695b9c547cSRui Paulo struct hostapd_radius_attr *req_attr, 3705b9c547cSRui Paulo struct sta_info *sta, 3715b9c547cSRui Paulo struct radius_msg *msg) 3725b9c547cSRui Paulo { 3735b9c547cSRui Paulo u32 suite; 3745b9c547cSRui Paulo int ver, val; 3755b9c547cSRui Paulo 3765b9c547cSRui Paulo ver = wpa_auth_sta_wpa_version(sta->wpa_sm); 3775b9c547cSRui Paulo val = wpa_auth_get_pairwise(sta->wpa_sm); 3785b9c547cSRui Paulo suite = wpa_cipher_to_suite(ver, val); 3795b9c547cSRui Paulo if (val != -1 && 3805b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 3815b9c547cSRui Paulo RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && 3825b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, 3835b9c547cSRui Paulo suite)) { 3845b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); 3855b9c547cSRui Paulo return -1; 3865b9c547cSRui Paulo } 3875b9c547cSRui Paulo 388325151a3SRui Paulo suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || 389325151a3SRui Paulo hapd->conf->osen) ? 3905b9c547cSRui Paulo WPA_PROTO_RSN : WPA_PROTO_WPA, 3915b9c547cSRui Paulo hapd->conf->wpa_group); 3925b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 3935b9c547cSRui Paulo RADIUS_ATTR_WLAN_GROUP_CIPHER) && 3945b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, 3955b9c547cSRui Paulo suite)) { 3965b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); 3975b9c547cSRui Paulo return -1; 3985b9c547cSRui Paulo } 3995b9c547cSRui Paulo 4005b9c547cSRui Paulo val = wpa_auth_sta_key_mgmt(sta->wpa_sm); 4015b9c547cSRui Paulo suite = wpa_akm_to_suite(val); 4025b9c547cSRui Paulo if (val != -1 && 4035b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 4045b9c547cSRui Paulo RADIUS_ATTR_WLAN_AKM_SUITE) && 4055b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, 4065b9c547cSRui Paulo suite)) { 4075b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); 4085b9c547cSRui Paulo return -1; 4095b9c547cSRui Paulo } 4105b9c547cSRui Paulo 4115b9c547cSRui Paulo #ifdef CONFIG_IEEE80211W 4125b9c547cSRui Paulo if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 4135b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, 4145b9c547cSRui Paulo hapd->conf->group_mgmt_cipher); 4155b9c547cSRui Paulo if (!hostapd_config_get_radius_attr( 4165b9c547cSRui Paulo req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && 4175b9c547cSRui Paulo !radius_msg_add_attr_int32( 4185b9c547cSRui Paulo msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { 4195b9c547cSRui Paulo wpa_printf(MSG_ERROR, 4205b9c547cSRui Paulo "Could not add WLAN-Group-Mgmt-Cipher"); 4215b9c547cSRui Paulo return -1; 4225b9c547cSRui Paulo } 4235b9c547cSRui Paulo } 4245b9c547cSRui Paulo #endif /* CONFIG_IEEE80211W */ 4255b9c547cSRui Paulo 4265b9c547cSRui Paulo return 0; 4275b9c547cSRui Paulo } 4285b9c547cSRui Paulo 4295b9c547cSRui Paulo 430f05cddf9SRui Paulo static int add_common_radius_sta_attr(struct hostapd_data *hapd, 431f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 432f05cddf9SRui Paulo struct sta_info *sta, 433f05cddf9SRui Paulo struct radius_msg *msg) 434f05cddf9SRui Paulo { 435f05cddf9SRui Paulo char buf[128]; 436f05cddf9SRui Paulo 437f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 438780fb4a2SCy Schubert RADIUS_ATTR_SERVICE_TYPE) && 439780fb4a2SCy Schubert !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, 440780fb4a2SCy Schubert RADIUS_SERVICE_TYPE_FRAMED)) { 441780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Could not add Service-Type"); 442780fb4a2SCy Schubert return -1; 443780fb4a2SCy Schubert } 444780fb4a2SCy Schubert 445780fb4a2SCy Schubert if (!hostapd_config_get_radius_attr(req_attr, 446f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT) && 447780fb4a2SCy Schubert sta->aid > 0 && 448f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 449f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 450f05cddf9SRui Paulo return -1; 451f05cddf9SRui Paulo } 452f05cddf9SRui Paulo 453f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 454f05cddf9SRui Paulo MAC2STR(sta->addr)); 455f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 456f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 457f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 458f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 459f05cddf9SRui Paulo return -1; 460f05cddf9SRui Paulo } 461f05cddf9SRui Paulo 462f05cddf9SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 463f05cddf9SRui Paulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 464f05cddf9SRui Paulo sizeof(buf)); 465f05cddf9SRui Paulo } else { 466f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 467f05cddf9SRui Paulo radius_sta_rate(hapd, sta) / 2, 468f05cddf9SRui Paulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 469f05cddf9SRui Paulo radius_mode_txt(hapd)); 470f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 471f05cddf9SRui Paulo } 472f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 473f05cddf9SRui Paulo RADIUS_ATTR_CONNECT_INFO) && 474f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 475f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 476f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 477f05cddf9SRui Paulo return -1; 478f05cddf9SRui Paulo } 479f05cddf9SRui Paulo 480780fb4a2SCy Schubert if (sta->acct_session_id) { 481780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 482780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id); 483f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 484f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 485f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 486f05cddf9SRui Paulo return -1; 487f05cddf9SRui Paulo } 488f05cddf9SRui Paulo } 489f05cddf9SRui Paulo 490780fb4a2SCy Schubert if ((hapd->conf->wpa & 2) && 491780fb4a2SCy Schubert !hapd->conf->disable_pmksa_caching && 492780fb4a2SCy Schubert sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) { 493780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 494780fb4a2SCy Schubert (unsigned long long) 495780fb4a2SCy Schubert sta->eapol_sm->acct_multi_session_id); 496780fb4a2SCy Schubert if (!radius_msg_add_attr( 497780fb4a2SCy Schubert msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 498780fb4a2SCy Schubert (u8 *) buf, os_strlen(buf))) { 499780fb4a2SCy Schubert wpa_printf(MSG_INFO, 500780fb4a2SCy Schubert "Could not add Acct-Multi-Session-Id"); 501780fb4a2SCy Schubert return -1; 502780fb4a2SCy Schubert } 503780fb4a2SCy Schubert } 504780fb4a2SCy Schubert 50585732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 5065b9c547cSRui Paulo if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 5075b9c547cSRui Paulo sta->wpa_sm && 5085b9c547cSRui Paulo (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || 5095b9c547cSRui Paulo sta->auth_alg == WLAN_AUTH_FT) && 5105b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 5115b9c547cSRui Paulo RADIUS_ATTR_MOBILITY_DOMAIN_ID) && 5125b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, 5135b9c547cSRui Paulo WPA_GET_BE16( 5145b9c547cSRui Paulo hapd->conf->mobility_domain))) { 5155b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); 5165b9c547cSRui Paulo return -1; 5175b9c547cSRui Paulo } 51885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 5195b9c547cSRui Paulo 520325151a3SRui Paulo if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && 5215b9c547cSRui Paulo add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) 5225b9c547cSRui Paulo return -1; 5235b9c547cSRui Paulo 524f05cddf9SRui Paulo return 0; 525f05cddf9SRui Paulo } 526f05cddf9SRui Paulo 527f05cddf9SRui Paulo 528f05cddf9SRui Paulo int add_common_radius_attr(struct hostapd_data *hapd, 529f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 530f05cddf9SRui Paulo struct sta_info *sta, 531f05cddf9SRui Paulo struct radius_msg *msg) 532f05cddf9SRui Paulo { 533f05cddf9SRui Paulo char buf[128]; 534f05cddf9SRui Paulo struct hostapd_radius_attr *attr; 535780fb4a2SCy Schubert int len; 536f05cddf9SRui Paulo 537f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 538f05cddf9SRui Paulo RADIUS_ATTR_NAS_IP_ADDRESS) && 539f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET && 540f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 541f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 542f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 543f05cddf9SRui Paulo return -1; 544f05cddf9SRui Paulo } 545f05cddf9SRui Paulo 546f05cddf9SRui Paulo #ifdef CONFIG_IPV6 547f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 548f05cddf9SRui Paulo RADIUS_ATTR_NAS_IPV6_ADDRESS) && 549f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET6 && 550f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 551f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 552f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 553f05cddf9SRui Paulo return -1; 554f05cddf9SRui Paulo } 555f05cddf9SRui Paulo #endif /* CONFIG_IPV6 */ 556f05cddf9SRui Paulo 557f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 558f05cddf9SRui Paulo RADIUS_ATTR_NAS_IDENTIFIER) && 559f05cddf9SRui Paulo hapd->conf->nas_identifier && 560f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 561f05cddf9SRui Paulo (u8 *) hapd->conf->nas_identifier, 562f05cddf9SRui Paulo os_strlen(hapd->conf->nas_identifier))) { 563f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 564f05cddf9SRui Paulo return -1; 565f05cddf9SRui Paulo } 566f05cddf9SRui Paulo 567780fb4a2SCy Schubert len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":", 568780fb4a2SCy Schubert MAC2STR(hapd->own_addr)); 569780fb4a2SCy Schubert os_memcpy(&buf[len], hapd->conf->ssid.ssid, 570780fb4a2SCy Schubert hapd->conf->ssid.ssid_len); 571780fb4a2SCy Schubert len += hapd->conf->ssid.ssid_len; 572f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 573f05cddf9SRui Paulo RADIUS_ATTR_CALLED_STATION_ID) && 574f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 575780fb4a2SCy Schubert (u8 *) buf, len)) { 576f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 577f05cddf9SRui Paulo return -1; 578f05cddf9SRui Paulo } 579f05cddf9SRui Paulo 580f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 581f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT_TYPE) && 582f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 583f05cddf9SRui Paulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 584f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 585f05cddf9SRui Paulo return -1; 586f05cddf9SRui Paulo } 587f05cddf9SRui Paulo 5885b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING 5895b9c547cSRui Paulo if (hapd->conf->interworking && 5905b9c547cSRui Paulo !is_zero_ether_addr(hapd->conf->hessid)) { 5915b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 5925b9c547cSRui Paulo MAC2STR(hapd->conf->hessid)); 5935b9c547cSRui Paulo buf[sizeof(buf) - 1] = '\0'; 5945b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 5955b9c547cSRui Paulo RADIUS_ATTR_WLAN_HESSID) && 5965b9c547cSRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, 5975b9c547cSRui Paulo (u8 *) buf, os_strlen(buf))) { 5985b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); 5995b9c547cSRui Paulo return -1; 6005b9c547cSRui Paulo } 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */ 6035b9c547cSRui Paulo 604f05cddf9SRui Paulo if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 605f05cddf9SRui Paulo return -1; 606f05cddf9SRui Paulo 607f05cddf9SRui Paulo for (attr = req_attr; attr; attr = attr->next) { 608f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, attr->type, 609f05cddf9SRui Paulo wpabuf_head(attr->val), 610f05cddf9SRui Paulo wpabuf_len(attr->val))) { 611f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS " 612f05cddf9SRui Paulo "attribute"); 613f05cddf9SRui Paulo return -1; 614f05cddf9SRui Paulo } 615f05cddf9SRui Paulo } 616f05cddf9SRui Paulo 617f05cddf9SRui Paulo return 0; 618f05cddf9SRui Paulo } 619f05cddf9SRui Paulo 620f05cddf9SRui Paulo 621*206b73d0SCy Schubert int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta, 622*206b73d0SCy Schubert struct radius_msg *msg, int acct) 623*206b73d0SCy Schubert { 624*206b73d0SCy Schubert #ifdef CONFIG_SQLITE 625*206b73d0SCy Schubert const char *attrtxt; 626*206b73d0SCy Schubert char addrtxt[3 * ETH_ALEN]; 627*206b73d0SCy Schubert char *sql; 628*206b73d0SCy Schubert sqlite3_stmt *stmt = NULL; 629*206b73d0SCy Schubert 630*206b73d0SCy Schubert if (!hapd->rad_attr_db) 631*206b73d0SCy Schubert return 0; 632*206b73d0SCy Schubert 633*206b73d0SCy Schubert os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr)); 634*206b73d0SCy Schubert 635*206b73d0SCy Schubert sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);"; 636*206b73d0SCy Schubert if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt, 637*206b73d0SCy Schubert NULL) != SQLITE_OK) { 638*206b73d0SCy Schubert wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s", 639*206b73d0SCy Schubert sqlite3_errmsg(hapd->rad_attr_db)); 640*206b73d0SCy Schubert return -1; 641*206b73d0SCy Schubert } 642*206b73d0SCy Schubert sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC); 643*206b73d0SCy Schubert sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC); 644*206b73d0SCy Schubert while (sqlite3_step(stmt) == SQLITE_ROW) { 645*206b73d0SCy Schubert struct hostapd_radius_attr *attr; 646*206b73d0SCy Schubert struct radius_attr_hdr *hdr; 647*206b73d0SCy Schubert 648*206b73d0SCy Schubert attrtxt = (const char *) sqlite3_column_text(stmt, 0); 649*206b73d0SCy Schubert attr = hostapd_parse_radius_attr(attrtxt); 650*206b73d0SCy Schubert if (!attr) { 651*206b73d0SCy Schubert wpa_printf(MSG_ERROR, 652*206b73d0SCy Schubert "Skipping invalid attribute from SQL: %s", 653*206b73d0SCy Schubert attrtxt); 654*206b73d0SCy Schubert continue; 655*206b73d0SCy Schubert } 656*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s", 657*206b73d0SCy Schubert attrtxt); 658*206b73d0SCy Schubert hdr = radius_msg_add_attr(msg, attr->type, 659*206b73d0SCy Schubert wpabuf_head(attr->val), 660*206b73d0SCy Schubert wpabuf_len(attr->val)); 661*206b73d0SCy Schubert hostapd_config_free_radius_attr(attr); 662*206b73d0SCy Schubert if (!hdr) { 663*206b73d0SCy Schubert wpa_printf(MSG_ERROR, 664*206b73d0SCy Schubert "Could not add RADIUS attribute from SQL"); 665*206b73d0SCy Schubert continue; 666*206b73d0SCy Schubert } 667*206b73d0SCy Schubert } 668*206b73d0SCy Schubert 669*206b73d0SCy Schubert sqlite3_reset(stmt); 670*206b73d0SCy Schubert sqlite3_clear_bindings(stmt); 671*206b73d0SCy Schubert sqlite3_finalize(stmt); 672*206b73d0SCy Schubert #endif /* CONFIG_SQLITE */ 673*206b73d0SCy Schubert 674*206b73d0SCy Schubert return 0; 675*206b73d0SCy Schubert } 676*206b73d0SCy Schubert 677*206b73d0SCy Schubert 67885732ac8SCy Schubert void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 679e28a4053SRui Paulo struct sta_info *sta, 680e28a4053SRui Paulo const u8 *eap, size_t len) 681e28a4053SRui Paulo { 682e28a4053SRui Paulo struct radius_msg *msg; 683e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 684e28a4053SRui Paulo 685e28a4053SRui Paulo if (sm == NULL) 686e28a4053SRui Paulo return; 687e28a4053SRui Paulo 688e28a4053SRui Paulo ieee802_1x_learn_identity(hapd, sm, eap, len); 689e28a4053SRui Paulo 690e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 691e28a4053SRui Paulo "packet"); 692e28a4053SRui Paulo 693e28a4053SRui Paulo sm->radius_identifier = radius_client_get_id(hapd->radius); 694e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 695e28a4053SRui Paulo sm->radius_identifier); 696e28a4053SRui Paulo if (msg == NULL) { 6975b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 698e28a4053SRui Paulo return; 699e28a4053SRui Paulo } 700e28a4053SRui Paulo 701780fb4a2SCy Schubert if (radius_msg_make_authenticator(msg) < 0) { 702780fb4a2SCy Schubert wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 703780fb4a2SCy Schubert goto fail; 704780fb4a2SCy Schubert } 705e28a4053SRui Paulo 706e28a4053SRui Paulo if (sm->identity && 707e28a4053SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 708e28a4053SRui Paulo sm->identity, sm->identity_len)) { 7095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add User-Name"); 710e28a4053SRui Paulo goto fail; 711e28a4053SRui Paulo } 712e28a4053SRui Paulo 713f05cddf9SRui Paulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 714f05cddf9SRui Paulo msg) < 0) 715e28a4053SRui Paulo goto fail; 716e28a4053SRui Paulo 717*206b73d0SCy Schubert if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0) 718*206b73d0SCy Schubert goto fail; 719*206b73d0SCy Schubert 720e28a4053SRui Paulo /* TODO: should probably check MTU from driver config; 2304 is max for 721e28a4053SRui Paulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 722e28a4053SRui Paulo */ 723f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 724f05cddf9SRui Paulo RADIUS_ATTR_FRAMED_MTU) && 725f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 7265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 727e28a4053SRui Paulo goto fail; 728e28a4053SRui Paulo } 729e28a4053SRui Paulo 730325151a3SRui Paulo if (!radius_msg_add_eap(msg, eap, len)) { 7315b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add EAP-Message"); 732e28a4053SRui Paulo goto fail; 733e28a4053SRui Paulo } 734e28a4053SRui Paulo 735e28a4053SRui Paulo /* State attribute must be copied if and only if this packet is 736e28a4053SRui Paulo * Access-Request reply to the previous Access-Challenge */ 737e28a4053SRui Paulo if (sm->last_recv_radius && 738e28a4053SRui Paulo radius_msg_get_hdr(sm->last_recv_radius)->code == 739e28a4053SRui Paulo RADIUS_CODE_ACCESS_CHALLENGE) { 740e28a4053SRui Paulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 741e28a4053SRui Paulo RADIUS_ATTR_STATE); 742e28a4053SRui Paulo if (res < 0) { 7435b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); 744e28a4053SRui Paulo goto fail; 745e28a4053SRui Paulo } 746e28a4053SRui Paulo if (res > 0) { 747e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 748e28a4053SRui Paulo } 749e28a4053SRui Paulo } 750e28a4053SRui Paulo 751f05cddf9SRui Paulo if (hapd->conf->radius_request_cui) { 752f05cddf9SRui Paulo const u8 *cui; 753f05cddf9SRui Paulo size_t cui_len; 754f05cddf9SRui Paulo /* Add previously learned CUI or nul CUI to request CUI */ 755f05cddf9SRui Paulo if (sm->radius_cui) { 756f05cddf9SRui Paulo cui = wpabuf_head(sm->radius_cui); 757f05cddf9SRui Paulo cui_len = wpabuf_len(sm->radius_cui); 758f05cddf9SRui Paulo } else { 759f05cddf9SRui Paulo cui = (const u8 *) "\0"; 760f05cddf9SRui Paulo cui_len = 1; 761f05cddf9SRui Paulo } 762f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, 763f05cddf9SRui Paulo RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 764f05cddf9SRui Paulo cui, cui_len)) { 765f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add CUI"); 766f05cddf9SRui Paulo goto fail; 767f05cddf9SRui Paulo } 768f05cddf9SRui Paulo } 769f05cddf9SRui Paulo 7705b9c547cSRui Paulo #ifdef CONFIG_HS20 7715b9c547cSRui Paulo if (hapd->conf->hs20) { 7724bc52338SCy Schubert u8 ver = hapd->conf->hs20_release - 1; 7734bc52338SCy Schubert 7745b9c547cSRui Paulo if (!radius_msg_add_wfa( 7755b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, 7765b9c547cSRui Paulo &ver, 1)) { 7775b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP " 7785b9c547cSRui Paulo "version"); 7795b9c547cSRui Paulo goto fail; 7805b9c547cSRui Paulo } 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) { 7835b9c547cSRui Paulo const u8 *pos; 7845b9c547cSRui Paulo u8 buf[3]; 7855b9c547cSRui Paulo u16 id; 7865b9c547cSRui Paulo pos = wpabuf_head_u8(sta->hs20_ie); 7875b9c547cSRui Paulo buf[0] = (*pos) >> 4; 7885b9c547cSRui Paulo if (((*pos) & HS20_PPS_MO_ID_PRESENT) && 7895b9c547cSRui Paulo wpabuf_len(sta->hs20_ie) >= 3) 7905b9c547cSRui Paulo id = WPA_GET_LE16(pos + 1); 7915b9c547cSRui Paulo else 7925b9c547cSRui Paulo id = 0; 7935b9c547cSRui Paulo WPA_PUT_BE16(buf + 1, id); 7945b9c547cSRui Paulo if (!radius_msg_add_wfa( 7955b9c547cSRui Paulo msg, 7965b9c547cSRui Paulo RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION, 7975b9c547cSRui Paulo buf, sizeof(buf))) { 7985b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 " 7995b9c547cSRui Paulo "STA version"); 8005b9c547cSRui Paulo goto fail; 8015b9c547cSRui Paulo } 8025b9c547cSRui Paulo } 80385732ac8SCy Schubert 80485732ac8SCy Schubert if (sta->roaming_consortium && 80585732ac8SCy Schubert !radius_msg_add_wfa( 80685732ac8SCy Schubert msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM, 80785732ac8SCy Schubert wpabuf_head(sta->roaming_consortium), 80885732ac8SCy Schubert wpabuf_len(sta->roaming_consortium))) { 80985732ac8SCy Schubert wpa_printf(MSG_ERROR, 81085732ac8SCy Schubert "Could not add HS 2.0 Roaming Consortium"); 81185732ac8SCy Schubert goto fail; 81285732ac8SCy Schubert } 81385732ac8SCy Schubert 81485732ac8SCy Schubert if (hapd->conf->t_c_filename) { 81585732ac8SCy Schubert be32 timestamp; 81685732ac8SCy Schubert 81785732ac8SCy Schubert if (!radius_msg_add_wfa( 81885732ac8SCy Schubert msg, 81985732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME, 82085732ac8SCy Schubert (const u8 *) hapd->conf->t_c_filename, 82185732ac8SCy Schubert os_strlen(hapd->conf->t_c_filename))) { 82285732ac8SCy Schubert wpa_printf(MSG_ERROR, 82385732ac8SCy Schubert "Could not add HS 2.0 T&C Filename"); 82485732ac8SCy Schubert goto fail; 82585732ac8SCy Schubert } 82685732ac8SCy Schubert 82785732ac8SCy Schubert timestamp = host_to_be32(hapd->conf->t_c_timestamp); 82885732ac8SCy Schubert if (!radius_msg_add_wfa( 82985732ac8SCy Schubert msg, 83085732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP, 83185732ac8SCy Schubert (const u8 *) ×tamp, 83285732ac8SCy Schubert sizeof(timestamp))) { 83385732ac8SCy Schubert wpa_printf(MSG_ERROR, 83485732ac8SCy Schubert "Could not add HS 2.0 Timestamp"); 83585732ac8SCy Schubert goto fail; 83685732ac8SCy Schubert } 83785732ac8SCy Schubert } 8385b9c547cSRui Paulo } 8395b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 8405b9c547cSRui Paulo 841f05cddf9SRui Paulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 842f05cddf9SRui Paulo goto fail; 843f05cddf9SRui Paulo 844e28a4053SRui Paulo return; 845e28a4053SRui Paulo 846e28a4053SRui Paulo fail: 847e28a4053SRui Paulo radius_msg_free(msg); 848e28a4053SRui Paulo } 849e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 850e28a4053SRui Paulo 851e28a4053SRui Paulo 852e28a4053SRui Paulo static void handle_eap_response(struct hostapd_data *hapd, 853e28a4053SRui Paulo struct sta_info *sta, struct eap_hdr *eap, 854e28a4053SRui Paulo size_t len) 855e28a4053SRui Paulo { 856e28a4053SRui Paulo u8 type, *data; 857e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 858e28a4053SRui Paulo if (sm == NULL) 859e28a4053SRui Paulo return; 860e28a4053SRui Paulo 861e28a4053SRui Paulo data = (u8 *) (eap + 1); 862e28a4053SRui Paulo 863e28a4053SRui Paulo if (len < sizeof(*eap) + 1) { 8645b9c547cSRui Paulo wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); 865e28a4053SRui Paulo return; 866e28a4053SRui Paulo } 867e28a4053SRui Paulo 868e28a4053SRui Paulo sm->eap_type_supp = type = data[0]; 869e28a4053SRui Paulo 870e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 871e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 872e28a4053SRui Paulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 873e28a4053SRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 874e28a4053SRui Paulo eap_server_get_name(0, type), type); 875e28a4053SRui Paulo 876e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx++; 877e28a4053SRui Paulo 878e28a4053SRui Paulo wpabuf_free(sm->eap_if->eapRespData); 879e28a4053SRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 880e28a4053SRui Paulo sm->eapolEap = TRUE; 881e28a4053SRui Paulo } 882e28a4053SRui Paulo 883e28a4053SRui Paulo 8845b9c547cSRui Paulo static void handle_eap_initiate(struct hostapd_data *hapd, 8855b9c547cSRui Paulo struct sta_info *sta, struct eap_hdr *eap, 8865b9c547cSRui Paulo size_t len) 8875b9c547cSRui Paulo { 8885b9c547cSRui Paulo #ifdef CONFIG_ERP 8895b9c547cSRui Paulo u8 type, *data; 8905b9c547cSRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 8915b9c547cSRui Paulo 8925b9c547cSRui Paulo if (sm == NULL) 8935b9c547cSRui Paulo return; 8945b9c547cSRui Paulo 8955b9c547cSRui Paulo if (len < sizeof(*eap) + 1) { 8965b9c547cSRui Paulo wpa_printf(MSG_INFO, 8975b9c547cSRui Paulo "handle_eap_initiate: too short response data"); 8985b9c547cSRui Paulo return; 8995b9c547cSRui Paulo } 9005b9c547cSRui Paulo 9015b9c547cSRui Paulo data = (u8 *) (eap + 1); 9025b9c547cSRui Paulo type = data[0]; 9035b9c547cSRui Paulo 9045b9c547cSRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 9055b9c547cSRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 9065b9c547cSRui Paulo "id=%d len=%d) from STA: EAP Initiate type %u", 9075b9c547cSRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 9085b9c547cSRui Paulo type); 9095b9c547cSRui Paulo 9105b9c547cSRui Paulo wpabuf_free(sm->eap_if->eapRespData); 9115b9c547cSRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 9125b9c547cSRui Paulo sm->eapolEap = TRUE; 9135b9c547cSRui Paulo #endif /* CONFIG_ERP */ 9145b9c547cSRui Paulo } 9155b9c547cSRui Paulo 9165b9c547cSRui Paulo 917e28a4053SRui Paulo /* Process incoming EAP packet from Supplicant */ 918e28a4053SRui Paulo static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 919e28a4053SRui Paulo u8 *buf, size_t len) 920e28a4053SRui Paulo { 921e28a4053SRui Paulo struct eap_hdr *eap; 922e28a4053SRui Paulo u16 eap_len; 923e28a4053SRui Paulo 924e28a4053SRui Paulo if (len < sizeof(*eap)) { 9255b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short EAP packet"); 926e28a4053SRui Paulo return; 927e28a4053SRui Paulo } 928e28a4053SRui Paulo 929e28a4053SRui Paulo eap = (struct eap_hdr *) buf; 930e28a4053SRui Paulo 931e28a4053SRui Paulo eap_len = be_to_host16(eap->length); 932e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 933e28a4053SRui Paulo eap->code, eap->identifier, eap_len); 934e28a4053SRui Paulo if (eap_len < sizeof(*eap)) { 935e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 936e28a4053SRui Paulo return; 937e28a4053SRui Paulo } else if (eap_len > len) { 938e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 939e28a4053SRui Paulo "packet"); 940e28a4053SRui Paulo return; 941e28a4053SRui Paulo } else if (eap_len < len) { 942e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 943e28a4053SRui Paulo "packet", (unsigned long) len - eap_len); 944e28a4053SRui Paulo } 945e28a4053SRui Paulo 946e28a4053SRui Paulo switch (eap->code) { 947e28a4053SRui Paulo case EAP_CODE_REQUEST: 948e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (request)"); 949e28a4053SRui Paulo return; 950e28a4053SRui Paulo case EAP_CODE_RESPONSE: 951e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (response)"); 952e28a4053SRui Paulo handle_eap_response(hapd, sta, eap, eap_len); 953e28a4053SRui Paulo break; 954e28a4053SRui Paulo case EAP_CODE_SUCCESS: 955e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (success)"); 956e28a4053SRui Paulo return; 957e28a4053SRui Paulo case EAP_CODE_FAILURE: 958e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (failure)"); 959e28a4053SRui Paulo return; 9605b9c547cSRui Paulo case EAP_CODE_INITIATE: 9615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, " (initiate)"); 9625b9c547cSRui Paulo handle_eap_initiate(hapd, sta, eap, eap_len); 9635b9c547cSRui Paulo break; 9645b9c547cSRui Paulo case EAP_CODE_FINISH: 9655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, " (finish)"); 9665b9c547cSRui Paulo break; 967e28a4053SRui Paulo default: 968e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (unknown code)"); 969e28a4053SRui Paulo return; 970e28a4053SRui Paulo } 971e28a4053SRui Paulo } 972e28a4053SRui Paulo 973e28a4053SRui Paulo 97485732ac8SCy Schubert struct eapol_state_machine * 975e28a4053SRui Paulo ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 976e28a4053SRui Paulo { 977e28a4053SRui Paulo int flags = 0; 978e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 979e28a4053SRui Paulo flags |= EAPOL_SM_PREAUTH; 980e28a4053SRui Paulo if (sta->wpa_sm) { 981e28a4053SRui Paulo flags |= EAPOL_SM_USES_WPA; 982e28a4053SRui Paulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 983e28a4053SRui Paulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 984e28a4053SRui Paulo } 985e28a4053SRui Paulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 986f05cddf9SRui Paulo sta->wps_ie, sta->p2p_ie, sta, 987f05cddf9SRui Paulo sta->identity, sta->radius_cui); 988e28a4053SRui Paulo } 989e28a4053SRui Paulo 990e28a4053SRui Paulo 991780fb4a2SCy Schubert static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, 992780fb4a2SCy Schubert size_t len) 993780fb4a2SCy Schubert { 994780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 995780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 996780fb4a2SCy Schubert } else { 997780fb4a2SCy Schubert sta->pending_eapol_rx = 998780fb4a2SCy Schubert os_malloc(sizeof(*sta->pending_eapol_rx)); 999780fb4a2SCy Schubert if (!sta->pending_eapol_rx) 1000780fb4a2SCy Schubert return; 1001780fb4a2SCy Schubert } 1002780fb4a2SCy Schubert 1003780fb4a2SCy Schubert sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); 1004780fb4a2SCy Schubert if (!sta->pending_eapol_rx->buf) { 1005780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 1006780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 1007780fb4a2SCy Schubert return; 1008780fb4a2SCy Schubert } 1009780fb4a2SCy Schubert 1010780fb4a2SCy Schubert os_get_reltime(&sta->pending_eapol_rx->rx_time); 1011780fb4a2SCy Schubert } 1012780fb4a2SCy Schubert 1013780fb4a2SCy Schubert 1014e28a4053SRui Paulo /** 1015e28a4053SRui Paulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 1016e28a4053SRui Paulo * @hapd: hostapd BSS data 1017e28a4053SRui Paulo * @sa: Source address (sender of the EAPOL frame) 1018e28a4053SRui Paulo * @buf: EAPOL frame 1019e28a4053SRui Paulo * @len: Length of buf in octets 1020e28a4053SRui Paulo * 1021e28a4053SRui Paulo * This function is called for each incoming EAPOL frame from the interface 1022e28a4053SRui Paulo */ 1023e28a4053SRui Paulo void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 1024e28a4053SRui Paulo size_t len) 1025e28a4053SRui Paulo { 1026e28a4053SRui Paulo struct sta_info *sta; 1027e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 1028e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 1029e28a4053SRui Paulo u16 datalen; 1030e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 1031f05cddf9SRui Paulo int key_mgmt; 1032e28a4053SRui Paulo 10335b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && 1034e28a4053SRui Paulo !hapd->conf->wps_state) 1035e28a4053SRui Paulo return; 1036e28a4053SRui Paulo 1037e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 1038e28a4053SRui Paulo (unsigned long) len, MAC2STR(sa)); 1039e28a4053SRui Paulo sta = ap_get_sta(hapd, sa); 1040f05cddf9SRui Paulo if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 1041f05cddf9SRui Paulo !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 1042e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 1043f05cddf9SRui Paulo "associated/Pre-authenticating STA"); 1044780fb4a2SCy Schubert 1045780fb4a2SCy Schubert if (sta && (sta->flags & WLAN_STA_AUTH)) { 1046780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR 1047780fb4a2SCy Schubert " for later use", MAC2STR(sta->addr)); 1048780fb4a2SCy Schubert ieee802_1x_save_eapol(sta, buf, len); 1049780fb4a2SCy Schubert } 1050780fb4a2SCy Schubert 1051e28a4053SRui Paulo return; 1052e28a4053SRui Paulo } 1053e28a4053SRui Paulo 1054e28a4053SRui Paulo if (len < sizeof(*hdr)) { 10555b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 1056e28a4053SRui Paulo return; 1057e28a4053SRui Paulo } 1058e28a4053SRui Paulo 1059e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 1060e28a4053SRui Paulo datalen = be_to_host16(hdr->length); 1061e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 1062e28a4053SRui Paulo hdr->version, hdr->type, datalen); 1063e28a4053SRui Paulo 1064e28a4053SRui Paulo if (len - sizeof(*hdr) < datalen) { 10655b9c547cSRui Paulo wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); 1066e28a4053SRui Paulo if (sta->eapol_sm) 1067e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 1068e28a4053SRui Paulo return; 1069e28a4053SRui Paulo } 1070e28a4053SRui Paulo if (len - sizeof(*hdr) > datalen) { 1071e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 1072e28a4053SRui Paulo "IEEE 802.1X packet", 1073e28a4053SRui Paulo (unsigned long) len - sizeof(*hdr) - datalen); 1074e28a4053SRui Paulo } 1075e28a4053SRui Paulo 1076e28a4053SRui Paulo if (sta->eapol_sm) { 1077e28a4053SRui Paulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 1078e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 1079e28a4053SRui Paulo } 1080e28a4053SRui Paulo 1081e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 1082e28a4053SRui Paulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 1083e28a4053SRui Paulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 1084e28a4053SRui Paulo (key->type == EAPOL_KEY_TYPE_WPA || 1085e28a4053SRui Paulo key->type == EAPOL_KEY_TYPE_RSN)) { 1086e28a4053SRui Paulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 1087e28a4053SRui Paulo sizeof(*hdr) + datalen); 1088e28a4053SRui Paulo return; 1089e28a4053SRui Paulo } 1090e28a4053SRui Paulo 10915b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->osen && 1092f05cddf9SRui Paulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 1093f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1094f05cddf9SRui Paulo "802.1X not enabled and WPS not used"); 1095e28a4053SRui Paulo return; 1096f05cddf9SRui Paulo } 1097f05cddf9SRui Paulo 1098f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 109985732ac8SCy Schubert if (key_mgmt != -1 && 110085732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 110185732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1102f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1103f05cddf9SRui Paulo "STA is using PSK"); 1104f05cddf9SRui Paulo return; 1105f05cddf9SRui Paulo } 1106e28a4053SRui Paulo 1107e28a4053SRui Paulo if (!sta->eapol_sm) { 1108e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1109e28a4053SRui Paulo if (!sta->eapol_sm) 1110e28a4053SRui Paulo return; 1111e28a4053SRui Paulo 1112e28a4053SRui Paulo #ifdef CONFIG_WPS 11135b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { 1114f05cddf9SRui Paulo u32 wflags = sta->flags & (WLAN_STA_WPS | 1115f05cddf9SRui Paulo WLAN_STA_WPS2 | 1116f05cddf9SRui Paulo WLAN_STA_MAYBE_WPS); 1117f05cddf9SRui Paulo if (wflags == WLAN_STA_MAYBE_WPS || 1118f05cddf9SRui Paulo wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 1119e28a4053SRui Paulo /* 1120f05cddf9SRui Paulo * Delay EAPOL frame transmission until a 1121f05cddf9SRui Paulo * possible WPS STA initiates the handshake 1122f05cddf9SRui Paulo * with EAPOL-Start. Only allow the wait to be 1123f05cddf9SRui Paulo * skipped if the STA is known to support WPS 1124f05cddf9SRui Paulo * 2.0. 1125e28a4053SRui Paulo */ 1126f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Do not start " 1127f05cddf9SRui Paulo "EAPOL until EAPOL-Start is " 1128f05cddf9SRui Paulo "received"); 1129e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1130e28a4053SRui Paulo } 1131f05cddf9SRui Paulo } 1132e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1133e28a4053SRui Paulo 1134e28a4053SRui Paulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1135e28a4053SRui Paulo } 1136e28a4053SRui Paulo 1137e28a4053SRui Paulo /* since we support version 1, we can ignore version field and proceed 1138e28a4053SRui Paulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 1139e28a4053SRui Paulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 1140e28a4053SRui Paulo * does not change frame contents, so should be ok to process frames 1141e28a4053SRui Paulo * more or less identically. Some changes might be needed for 1142e28a4053SRui Paulo * verification of fields. */ 1143e28a4053SRui Paulo 1144e28a4053SRui Paulo switch (hdr->type) { 1145e28a4053SRui Paulo case IEEE802_1X_TYPE_EAP_PACKET: 1146e28a4053SRui Paulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 1147e28a4053SRui Paulo break; 1148e28a4053SRui Paulo 1149e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_START: 1150e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1151e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 1152e28a4053SRui Paulo "from STA"); 1153e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1154e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1155e28a4053SRui Paulo if (pmksa) { 1156e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1157e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 1158e28a4053SRui Paulo "available - ignore it since " 1159e28a4053SRui Paulo "STA sent EAPOL-Start"); 1160e28a4053SRui Paulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 1161e28a4053SRui Paulo } 1162e28a4053SRui Paulo sta->eapol_sm->eapolStart = TRUE; 1163e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 1164f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1165e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1166e28a4053SRui Paulo break; 1167e28a4053SRui Paulo 1168e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 1169e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1170e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 1171e28a4053SRui Paulo "from STA"); 1172e28a4053SRui Paulo sta->acct_terminate_cause = 1173e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1174e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 1175e28a4053SRui Paulo sta->eapol_sm->eapolLogoff = TRUE; 1176e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 1177f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1178e28a4053SRui Paulo break; 1179e28a4053SRui Paulo 1180e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_KEY: 1181e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 1182f05cddf9SRui Paulo if (!ap_sta_is_authorized(sta)) { 1183e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Dropped key data from " 1184e28a4053SRui Paulo "unauthorized Supplicant"); 1185e28a4053SRui Paulo break; 1186e28a4053SRui Paulo } 1187e28a4053SRui Paulo break; 1188e28a4053SRui Paulo 1189e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 1190e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 1191e28a4053SRui Paulo /* TODO: implement support for this; show data */ 1192e28a4053SRui Paulo break; 1193e28a4053SRui Paulo 1194*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 1195*206b73d0SCy Schubert case IEEE802_1X_TYPE_EAPOL_MKA: 1196*206b73d0SCy Schubert wpa_printf(MSG_EXCESSIVE, 1197*206b73d0SCy Schubert "EAPOL type %d will be handled by MKA", hdr->type); 1198*206b73d0SCy Schubert break; 1199*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 1200*206b73d0SCy Schubert 1201e28a4053SRui Paulo default: 1202e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 1203e28a4053SRui Paulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 1204e28a4053SRui Paulo break; 1205e28a4053SRui Paulo } 1206e28a4053SRui Paulo 1207e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1208e28a4053SRui Paulo } 1209e28a4053SRui Paulo 1210e28a4053SRui Paulo 1211e28a4053SRui Paulo /** 1212e28a4053SRui Paulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 1213e28a4053SRui Paulo * @hapd: hostapd BSS data 1214e28a4053SRui Paulo * @sta: The station 1215e28a4053SRui Paulo * 1216e28a4053SRui Paulo * This function is called to start IEEE 802.1X authentication when a new 1217e28a4053SRui Paulo * station completes IEEE 802.11 association. 1218e28a4053SRui Paulo */ 1219e28a4053SRui Paulo void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 1220e28a4053SRui Paulo { 1221e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 1222e28a4053SRui Paulo int reassoc = 1; 1223e28a4053SRui Paulo int force_1x = 0; 1224f05cddf9SRui Paulo int key_mgmt; 1225e28a4053SRui Paulo 1226e28a4053SRui Paulo #ifdef CONFIG_WPS 12275b9c547cSRui Paulo if (hapd->conf->wps_state && 12285b9c547cSRui Paulo ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) || 12295b9c547cSRui Paulo (sta->flags & WLAN_STA_WPS))) { 1230e28a4053SRui Paulo /* 1231e28a4053SRui Paulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 1232e28a4053SRui Paulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 1233e28a4053SRui Paulo * authentication in this BSS. 1234e28a4053SRui Paulo */ 1235e28a4053SRui Paulo force_1x = 1; 1236e28a4053SRui Paulo } 1237e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1238e28a4053SRui Paulo 12395b9c547cSRui Paulo if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { 1240f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 1241f05cddf9SRui Paulo "802.1X not enabled or forced for WPS"); 1242f05cddf9SRui Paulo /* 1243f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1244f05cddf9SRui Paulo * reassociation change from WPS to PSK. 1245f05cddf9SRui Paulo */ 1246780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1247e28a4053SRui Paulo return; 1248f05cddf9SRui Paulo } 1249f05cddf9SRui Paulo 1250f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 125185732ac8SCy Schubert if (key_mgmt != -1 && 125285732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 125385732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1254f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 1255f05cddf9SRui Paulo /* 1256f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1257f05cddf9SRui Paulo * reassociation change from WPA-EAP to PSK. 1258f05cddf9SRui Paulo */ 1259780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1260f05cddf9SRui Paulo return; 1261f05cddf9SRui Paulo } 1262e28a4053SRui Paulo 1263e28a4053SRui Paulo if (sta->eapol_sm == NULL) { 1264e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1265e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 1266e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1267e28a4053SRui Paulo if (sta->eapol_sm == NULL) { 1268e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1269e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1270e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1271e28a4053SRui Paulo "failed to allocate state machine"); 1272e28a4053SRui Paulo return; 1273e28a4053SRui Paulo } 1274e28a4053SRui Paulo reassoc = 0; 1275e28a4053SRui Paulo } 1276e28a4053SRui Paulo 1277e28a4053SRui Paulo #ifdef CONFIG_WPS 1278e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 12795b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && 12805b9c547cSRui Paulo !(sta->flags & WLAN_STA_WPS2)) { 1281e28a4053SRui Paulo /* 1282f05cddf9SRui Paulo * Delay EAPOL frame transmission until a possible WPS STA 1283f05cddf9SRui Paulo * initiates the handshake with EAPOL-Start. Only allow the 1284f05cddf9SRui Paulo * wait to be skipped if the STA is known to support WPS 2.0. 1285e28a4053SRui Paulo */ 1286f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 1287f05cddf9SRui Paulo "EAPOL-Start is received"); 1288e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1289e28a4053SRui Paulo } 1290e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1291e28a4053SRui Paulo 1292e28a4053SRui Paulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1293e28a4053SRui Paulo 129485732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1295f05cddf9SRui Paulo if (sta->auth_alg == WLAN_AUTH_FT) { 1296f05cddf9SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1297f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, 1298f05cddf9SRui Paulo "PMK from FT - skip IEEE 802.1X/EAP"); 1299f05cddf9SRui Paulo /* Setup EAPOL state machines to already authenticated state 1300f05cddf9SRui Paulo * because of existing FT information from R0KH. */ 1301f05cddf9SRui Paulo sta->eapol_sm->keyRun = TRUE; 1302f05cddf9SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1303f05cddf9SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1304f05cddf9SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1305f05cddf9SRui Paulo sta->eapol_sm->authSuccess = TRUE; 1306f05cddf9SRui Paulo sta->eapol_sm->authFail = FALSE; 1307780fb4a2SCy Schubert sta->eapol_sm->portValid = TRUE; 1308f05cddf9SRui Paulo if (sta->eapol_sm->eap) 1309f05cddf9SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 131085732ac8SCy Schubert ap_sta_bind_vlan(hapd, sta); 1311f05cddf9SRui Paulo return; 1312f05cddf9SRui Paulo } 131385732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 131485732ac8SCy Schubert 131585732ac8SCy Schubert #ifdef CONFIG_FILS 131685732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FILS_SK || 131785732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 131885732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) { 131985732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 132085732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, 132185732ac8SCy Schubert "PMK from FILS - skip IEEE 802.1X/EAP"); 132285732ac8SCy Schubert /* Setup EAPOL state machines to already authenticated state 132385732ac8SCy Schubert * because of existing FILS information. */ 132485732ac8SCy Schubert sta->eapol_sm->keyRun = TRUE; 132585732ac8SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 132685732ac8SCy Schubert sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 132785732ac8SCy Schubert sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 132885732ac8SCy Schubert sta->eapol_sm->authSuccess = TRUE; 132985732ac8SCy Schubert sta->eapol_sm->authFail = FALSE; 133085732ac8SCy Schubert sta->eapol_sm->portValid = TRUE; 133185732ac8SCy Schubert if (sta->eapol_sm->eap) 133285732ac8SCy Schubert eap_sm_notify_cached(sta->eapol_sm->eap); 13334bc52338SCy Schubert wpa_auth_set_ptk_rekey_timer(sta->wpa_sm); 133485732ac8SCy Schubert return; 133585732ac8SCy Schubert } 133685732ac8SCy Schubert #endif /* CONFIG_FILS */ 1337f05cddf9SRui Paulo 1338e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1339e28a4053SRui Paulo if (pmksa) { 1340e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1341e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1342e28a4053SRui Paulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1343e28a4053SRui Paulo /* Setup EAPOL state machines to already authenticated state 1344e28a4053SRui Paulo * because of existing PMKSA information in the cache. */ 1345e28a4053SRui Paulo sta->eapol_sm->keyRun = TRUE; 1346e28a4053SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1347e28a4053SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1348e28a4053SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1349e28a4053SRui Paulo sta->eapol_sm->authSuccess = TRUE; 1350f05cddf9SRui Paulo sta->eapol_sm->authFail = FALSE; 1351e28a4053SRui Paulo if (sta->eapol_sm->eap) 1352e28a4053SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 1353780fb4a2SCy Schubert pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 1354325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta); 1355e28a4053SRui Paulo } else { 1356e28a4053SRui Paulo if (reassoc) { 1357e28a4053SRui Paulo /* 1358e28a4053SRui Paulo * Force EAPOL state machines to start 1359e28a4053SRui Paulo * re-authentication without having to wait for the 1360e28a4053SRui Paulo * Supplicant to send EAPOL-Start. 1361e28a4053SRui Paulo */ 1362e28a4053SRui Paulo sta->eapol_sm->reAuthenticate = TRUE; 1363e28a4053SRui Paulo } 1364e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1365e28a4053SRui Paulo } 1366e28a4053SRui Paulo } 1367e28a4053SRui Paulo 1368e28a4053SRui Paulo 1369780fb4a2SCy Schubert void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) 1370e28a4053SRui Paulo { 1371e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1372e28a4053SRui Paulo 1373780fb4a2SCy Schubert #ifdef CONFIG_HS20 1374780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 1375780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 1376780fb4a2SCy Schubert 1377780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 1378780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 1379780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 1380780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 1381780fb4a2SCy Schubert } 1382780fb4a2SCy Schubert 1383e28a4053SRui Paulo if (sm == NULL) 1384e28a4053SRui Paulo return; 1385e28a4053SRui Paulo 1386e28a4053SRui Paulo sta->eapol_sm = NULL; 1387e28a4053SRui Paulo 1388e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1389e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1390e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1391e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 1392e28a4053SRui Paulo 1393e28a4053SRui Paulo eapol_auth_free(sm); 1394e28a4053SRui Paulo } 1395e28a4053SRui Paulo 1396e28a4053SRui Paulo 1397e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1398e28a4053SRui Paulo static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1399e28a4053SRui Paulo struct sta_info *sta) 1400e28a4053SRui Paulo { 1401f05cddf9SRui Paulo struct wpabuf *eap; 1402f05cddf9SRui Paulo const struct eap_hdr *hdr; 1403e28a4053SRui Paulo int eap_type = -1; 1404e28a4053SRui Paulo char buf[64]; 1405e28a4053SRui Paulo struct radius_msg *msg; 1406e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1407e28a4053SRui Paulo 1408e28a4053SRui Paulo if (sm == NULL || sm->last_recv_radius == NULL) { 1409e28a4053SRui Paulo if (sm) 1410e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1411e28a4053SRui Paulo return; 1412e28a4053SRui Paulo } 1413e28a4053SRui Paulo 1414e28a4053SRui Paulo msg = sm->last_recv_radius; 1415e28a4053SRui Paulo 1416f05cddf9SRui Paulo eap = radius_msg_get_eap(msg); 1417e28a4053SRui Paulo if (eap == NULL) { 1418e28a4053SRui Paulo /* RFC 3579, Chap. 2.6.3: 1419e28a4053SRui Paulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1420e28a4053SRui Paulo * attribute */ 1421e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1422e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "could not extract " 1423e28a4053SRui Paulo "EAP-Message from RADIUS message"); 1424e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1425e28a4053SRui Paulo return; 1426e28a4053SRui Paulo } 1427e28a4053SRui Paulo 1428f05cddf9SRui Paulo if (wpabuf_len(eap) < sizeof(*hdr)) { 1429e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1430e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1431e28a4053SRui Paulo "received from authentication server"); 1432f05cddf9SRui Paulo wpabuf_free(eap); 1433e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1434e28a4053SRui Paulo return; 1435e28a4053SRui Paulo } 1436e28a4053SRui Paulo 1437f05cddf9SRui Paulo if (wpabuf_len(eap) > sizeof(*hdr)) 1438f05cddf9SRui Paulo eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1439e28a4053SRui Paulo 1440f05cddf9SRui Paulo hdr = wpabuf_head(eap); 1441e28a4053SRui Paulo switch (hdr->code) { 1442e28a4053SRui Paulo case EAP_CODE_REQUEST: 1443e28a4053SRui Paulo if (eap_type >= 0) 1444e28a4053SRui Paulo sm->eap_type_authsrv = eap_type; 1445e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 14465b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1447e28a4053SRui Paulo break; 1448e28a4053SRui Paulo case EAP_CODE_RESPONSE: 1449e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 14505b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1451e28a4053SRui Paulo break; 1452e28a4053SRui Paulo case EAP_CODE_SUCCESS: 1453e28a4053SRui Paulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 1454e28a4053SRui Paulo break; 1455e28a4053SRui Paulo case EAP_CODE_FAILURE: 1456e28a4053SRui Paulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1457e28a4053SRui Paulo break; 1458e28a4053SRui Paulo default: 1459e28a4053SRui Paulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1460e28a4053SRui Paulo break; 1461e28a4053SRui Paulo } 1462e28a4053SRui Paulo buf[sizeof(buf) - 1] = '\0'; 1463e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1464e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1465e28a4053SRui Paulo "id=%d len=%d) from RADIUS server: %s", 1466e28a4053SRui Paulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1467e28a4053SRui Paulo buf); 1468e28a4053SRui Paulo sm->eap_if->aaaEapReq = TRUE; 1469e28a4053SRui Paulo 1470e28a4053SRui Paulo wpabuf_free(sm->eap_if->aaaEapReqData); 1471f05cddf9SRui Paulo sm->eap_if->aaaEapReqData = eap; 1472e28a4053SRui Paulo } 1473e28a4053SRui Paulo 1474e28a4053SRui Paulo 1475e28a4053SRui Paulo static void ieee802_1x_get_keys(struct hostapd_data *hapd, 1476e28a4053SRui Paulo struct sta_info *sta, struct radius_msg *msg, 1477e28a4053SRui Paulo struct radius_msg *req, 1478e28a4053SRui Paulo const u8 *shared_secret, 1479e28a4053SRui Paulo size_t shared_secret_len) 1480e28a4053SRui Paulo { 1481e28a4053SRui Paulo struct radius_ms_mppe_keys *keys; 1482*206b73d0SCy Schubert u8 *buf; 1483*206b73d0SCy Schubert size_t len; 1484e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1485e28a4053SRui Paulo if (sm == NULL) 1486e28a4053SRui Paulo return; 1487e28a4053SRui Paulo 1488e28a4053SRui Paulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1489e28a4053SRui Paulo shared_secret_len); 1490e28a4053SRui Paulo 1491e28a4053SRui Paulo if (keys && keys->send && keys->recv) { 1492*206b73d0SCy Schubert len = keys->send_len + keys->recv_len; 1493e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1494e28a4053SRui Paulo keys->send, keys->send_len); 1495e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1496e28a4053SRui Paulo keys->recv, keys->recv_len); 1497e28a4053SRui Paulo 1498e28a4053SRui Paulo os_free(sm->eap_if->aaaEapKeyData); 1499e28a4053SRui Paulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1500e28a4053SRui Paulo if (sm->eap_if->aaaEapKeyData) { 1501e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1502e28a4053SRui Paulo keys->recv_len); 1503e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1504e28a4053SRui Paulo keys->send, keys->send_len); 1505e28a4053SRui Paulo sm->eap_if->aaaEapKeyDataLen = len; 1506e28a4053SRui Paulo sm->eap_if->aaaEapKeyAvailable = TRUE; 1507e28a4053SRui Paulo } 15085b9c547cSRui Paulo } else { 15095b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 15105b9c547cSRui Paulo "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p", 15115b9c547cSRui Paulo keys, keys ? keys->send : NULL, 15125b9c547cSRui Paulo keys ? keys->recv : NULL); 1513e28a4053SRui Paulo } 1514e28a4053SRui Paulo 1515e28a4053SRui Paulo if (keys) { 1516e28a4053SRui Paulo os_free(keys->send); 1517e28a4053SRui Paulo os_free(keys->recv); 1518e28a4053SRui Paulo os_free(keys); 1519e28a4053SRui Paulo } 1520*206b73d0SCy Schubert 1521*206b73d0SCy Schubert if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, 1522*206b73d0SCy Schubert NULL) == 0) { 1523*206b73d0SCy Schubert os_free(sm->eap_if->eapSessionId); 1524*206b73d0SCy Schubert sm->eap_if->eapSessionId = os_memdup(buf, len); 1525*206b73d0SCy Schubert if (sm->eap_if->eapSessionId) { 1526*206b73d0SCy Schubert sm->eap_if->eapSessionIdLen = len; 1527*206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-Key Name", 1528*206b73d0SCy Schubert sm->eap_if->eapSessionId, 1529*206b73d0SCy Schubert sm->eap_if->eapSessionIdLen); 1530*206b73d0SCy Schubert } 1531*206b73d0SCy Schubert } else { 1532*206b73d0SCy Schubert sm->eap_if->eapSessionIdLen = 0; 1533*206b73d0SCy Schubert } 1534e28a4053SRui Paulo } 1535e28a4053SRui Paulo 1536e28a4053SRui Paulo 1537e28a4053SRui Paulo static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1538e28a4053SRui Paulo struct sta_info *sta, 1539e28a4053SRui Paulo struct radius_msg *msg) 1540e28a4053SRui Paulo { 1541325151a3SRui Paulo u8 *attr_class; 1542e28a4053SRui Paulo size_t class_len; 1543e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1544e28a4053SRui Paulo int count, i; 1545e28a4053SRui Paulo struct radius_attr_data *nclass; 1546e28a4053SRui Paulo size_t nclass_count; 1547e28a4053SRui Paulo 1548e28a4053SRui Paulo if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1549e28a4053SRui Paulo sm == NULL) 1550e28a4053SRui Paulo return; 1551e28a4053SRui Paulo 1552e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1553e28a4053SRui Paulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1554e28a4053SRui Paulo if (count <= 0) 1555e28a4053SRui Paulo return; 1556e28a4053SRui Paulo 1557f05cddf9SRui Paulo nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1558e28a4053SRui Paulo if (nclass == NULL) 1559e28a4053SRui Paulo return; 1560e28a4053SRui Paulo 1561e28a4053SRui Paulo nclass_count = 0; 1562e28a4053SRui Paulo 1563325151a3SRui Paulo attr_class = NULL; 1564e28a4053SRui Paulo for (i = 0; i < count; i++) { 1565e28a4053SRui Paulo do { 1566e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1567325151a3SRui Paulo &attr_class, &class_len, 1568325151a3SRui Paulo attr_class) < 0) { 1569e28a4053SRui Paulo i = count; 1570e28a4053SRui Paulo break; 1571e28a4053SRui Paulo } 1572e28a4053SRui Paulo } while (class_len < 1); 1573e28a4053SRui Paulo 157485732ac8SCy Schubert nclass[nclass_count].data = os_memdup(attr_class, class_len); 1575e28a4053SRui Paulo if (nclass[nclass_count].data == NULL) 1576e28a4053SRui Paulo break; 1577e28a4053SRui Paulo 1578e28a4053SRui Paulo nclass[nclass_count].len = class_len; 1579e28a4053SRui Paulo nclass_count++; 1580e28a4053SRui Paulo } 1581e28a4053SRui Paulo 1582e28a4053SRui Paulo sm->radius_class.attr = nclass; 1583e28a4053SRui Paulo sm->radius_class.count = nclass_count; 1584e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1585e28a4053SRui Paulo "attributes for " MACSTR, 1586e28a4053SRui Paulo (unsigned long) sm->radius_class.count, 1587e28a4053SRui Paulo MAC2STR(sta->addr)); 1588e28a4053SRui Paulo } 1589e28a4053SRui Paulo 1590e28a4053SRui Paulo 1591e28a4053SRui Paulo /* Update sta->identity based on User-Name attribute in Access-Accept */ 1592e28a4053SRui Paulo static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1593e28a4053SRui Paulo struct sta_info *sta, 1594e28a4053SRui Paulo struct radius_msg *msg) 1595e28a4053SRui Paulo { 1596e28a4053SRui Paulo u8 *buf, *identity; 1597e28a4053SRui Paulo size_t len; 1598e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1599e28a4053SRui Paulo 1600e28a4053SRui Paulo if (sm == NULL) 1601e28a4053SRui Paulo return; 1602e28a4053SRui Paulo 1603e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1604e28a4053SRui Paulo NULL) < 0) 1605e28a4053SRui Paulo return; 1606e28a4053SRui Paulo 16075b9c547cSRui Paulo identity = (u8 *) dup_binstr(buf, len); 1608e28a4053SRui Paulo if (identity == NULL) 1609e28a4053SRui Paulo return; 1610e28a4053SRui Paulo 1611e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1612e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1613e28a4053SRui Paulo "User-Name from Access-Accept '%s'", 1614e28a4053SRui Paulo sm->identity ? (char *) sm->identity : "N/A", 1615e28a4053SRui Paulo (char *) identity); 1616e28a4053SRui Paulo 1617e28a4053SRui Paulo os_free(sm->identity); 1618e28a4053SRui Paulo sm->identity = identity; 1619e28a4053SRui Paulo sm->identity_len = len; 1620e28a4053SRui Paulo } 1621e28a4053SRui Paulo 1622e28a4053SRui Paulo 1623f05cddf9SRui Paulo /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1624f05cddf9SRui Paulo static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1625f05cddf9SRui Paulo struct sta_info *sta, 1626f05cddf9SRui Paulo struct radius_msg *msg) 1627f05cddf9SRui Paulo { 1628f05cddf9SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1629f05cddf9SRui Paulo struct wpabuf *cui; 1630f05cddf9SRui Paulo u8 *buf; 1631f05cddf9SRui Paulo size_t len; 1632f05cddf9SRui Paulo 1633f05cddf9SRui Paulo if (sm == NULL) 1634f05cddf9SRui Paulo return; 1635f05cddf9SRui Paulo 1636f05cddf9SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1637f05cddf9SRui Paulo &buf, &len, NULL) < 0) 1638f05cddf9SRui Paulo return; 1639f05cddf9SRui Paulo 1640f05cddf9SRui Paulo cui = wpabuf_alloc_copy(buf, len); 1641f05cddf9SRui Paulo if (cui == NULL) 1642f05cddf9SRui Paulo return; 1643f05cddf9SRui Paulo 1644f05cddf9SRui Paulo wpabuf_free(sm->radius_cui); 1645f05cddf9SRui Paulo sm->radius_cui = cui; 1646f05cddf9SRui Paulo } 1647f05cddf9SRui Paulo 1648f05cddf9SRui Paulo 16495b9c547cSRui Paulo #ifdef CONFIG_HS20 16505b9c547cSRui Paulo 16515b9c547cSRui Paulo static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) 16525b9c547cSRui Paulo { 16535b9c547cSRui Paulo sta->remediation = 1; 16545b9c547cSRui Paulo os_free(sta->remediation_url); 16555b9c547cSRui Paulo if (len > 2) { 16565b9c547cSRui Paulo sta->remediation_url = os_malloc(len); 16575b9c547cSRui Paulo if (!sta->remediation_url) 16585b9c547cSRui Paulo return; 16595b9c547cSRui Paulo sta->remediation_method = pos[0]; 16605b9c547cSRui Paulo os_memcpy(sta->remediation_url, pos + 1, len - 1); 16615b9c547cSRui Paulo sta->remediation_url[len - 1] = '\0'; 16625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 16635b9c547cSRui Paulo "for " MACSTR " - server method %u URL %s", 16645b9c547cSRui Paulo MAC2STR(sta->addr), sta->remediation_method, 16655b9c547cSRui Paulo sta->remediation_url); 16665b9c547cSRui Paulo } else { 16675b9c547cSRui Paulo sta->remediation_url = NULL; 16685b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 16695b9c547cSRui Paulo "for " MACSTR, MAC2STR(sta->addr)); 16705b9c547cSRui Paulo } 16715b9c547cSRui Paulo /* TODO: assign the STA into remediation VLAN or add filtering */ 16725b9c547cSRui Paulo } 16735b9c547cSRui Paulo 16745b9c547cSRui Paulo 16755b9c547cSRui Paulo static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, 16765b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 16775b9c547cSRui Paulo size_t len) 16785b9c547cSRui Paulo { 16795b9c547cSRui Paulo if (len < 3) 16805b9c547cSRui Paulo return; /* Malformed information */ 16815b9c547cSRui Paulo sta->hs20_deauth_requested = 1; 16825b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u " 16835b9c547cSRui Paulo "Re-auth Delay %u", 16845b9c547cSRui Paulo *pos, WPA_GET_LE16(pos + 1)); 16855b9c547cSRui Paulo wpabuf_free(sta->hs20_deauth_req); 16865b9c547cSRui Paulo sta->hs20_deauth_req = wpabuf_alloc(len + 1); 16875b9c547cSRui Paulo if (sta->hs20_deauth_req) { 16885b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos, 3); 16895b9c547cSRui Paulo wpabuf_put_u8(sta->hs20_deauth_req, len - 3); 16905b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); 16915b9c547cSRui Paulo } 16925b9c547cSRui Paulo ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); 16935b9c547cSRui Paulo } 16945b9c547cSRui Paulo 16955b9c547cSRui Paulo 16965b9c547cSRui Paulo static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd, 16975b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 16985b9c547cSRui Paulo size_t len, int session_timeout) 16995b9c547cSRui Paulo { 17005b9c547cSRui Paulo unsigned int swt; 17015b9c547cSRui Paulo int warning_time, beacon_int; 17025b9c547cSRui Paulo 17035b9c547cSRui Paulo if (len < 1) 17045b9c547cSRui Paulo return; /* Malformed information */ 17055b9c547cSRui Paulo os_free(sta->hs20_session_info_url); 17065b9c547cSRui Paulo sta->hs20_session_info_url = os_malloc(len); 17075b9c547cSRui Paulo if (sta->hs20_session_info_url == NULL) 17085b9c547cSRui Paulo return; 17095b9c547cSRui Paulo swt = pos[0]; 17105b9c547cSRui Paulo os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1); 17115b9c547cSRui Paulo sta->hs20_session_info_url[len - 1] = '\0'; 17125b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u " 17135b9c547cSRui Paulo "(session_timeout=%d)", 17145b9c547cSRui Paulo sta->hs20_session_info_url, swt, session_timeout); 17155b9c547cSRui Paulo if (session_timeout < 0) { 17165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL"); 17175b9c547cSRui Paulo return; 17185b9c547cSRui Paulo } 17195b9c547cSRui Paulo if (swt == 255) 17205b9c547cSRui Paulo swt = 1; /* Use one minute as the AP selected value */ 17215b9c547cSRui Paulo 17225b9c547cSRui Paulo if ((unsigned int) session_timeout < swt * 60) 17235b9c547cSRui Paulo warning_time = 0; 17245b9c547cSRui Paulo else 17255b9c547cSRui Paulo warning_time = session_timeout - swt * 60; 17265b9c547cSRui Paulo 17275b9c547cSRui Paulo beacon_int = hapd->iconf->beacon_int; 17285b9c547cSRui Paulo if (beacon_int < 1) 17295b9c547cSRui Paulo beacon_int = 100; /* best guess */ 17305b9c547cSRui Paulo sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128; 17315b9c547cSRui Paulo if (sta->hs20_disassoc_timer > 65535) 17325b9c547cSRui Paulo sta->hs20_disassoc_timer = 65535; 17335b9c547cSRui Paulo 17345b9c547cSRui Paulo ap_sta_session_warning_timeout(hapd, sta, warning_time); 17355b9c547cSRui Paulo } 17365b9c547cSRui Paulo 173785732ac8SCy Schubert 173885732ac8SCy Schubert static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd, 173985732ac8SCy Schubert struct sta_info *sta, u8 *pos, 174085732ac8SCy Schubert size_t len) 174185732ac8SCy Schubert { 174285732ac8SCy Schubert if (len < 4) 174385732ac8SCy Schubert return; /* Malformed information */ 174485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 174585732ac8SCy Schubert "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x", 174685732ac8SCy Schubert pos[0], pos[1], pos[2], pos[3]); 174785732ac8SCy Schubert hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0)); 174885732ac8SCy Schubert } 174985732ac8SCy Schubert 175085732ac8SCy Schubert 175185732ac8SCy Schubert static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd, 175285732ac8SCy Schubert struct sta_info *sta, u8 *pos, size_t len) 175385732ac8SCy Schubert { 175485732ac8SCy Schubert os_free(sta->t_c_url); 175585732ac8SCy Schubert sta->t_c_url = os_malloc(len + 1); 175685732ac8SCy Schubert if (!sta->t_c_url) 175785732ac8SCy Schubert return; 175885732ac8SCy Schubert os_memcpy(sta->t_c_url, pos, len); 175985732ac8SCy Schubert sta->t_c_url[len] = '\0'; 176085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 176185732ac8SCy Schubert "HS 2.0: Terms and Conditions URL %s", sta->t_c_url); 176285732ac8SCy Schubert } 176385732ac8SCy Schubert 17645b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 17655b9c547cSRui Paulo 17665b9c547cSRui Paulo 17675b9c547cSRui Paulo static void ieee802_1x_check_hs20(struct hostapd_data *hapd, 17685b9c547cSRui Paulo struct sta_info *sta, 17695b9c547cSRui Paulo struct radius_msg *msg, 17705b9c547cSRui Paulo int session_timeout) 17715b9c547cSRui Paulo { 17725b9c547cSRui Paulo #ifdef CONFIG_HS20 17735b9c547cSRui Paulo u8 *buf, *pos, *end, type, sublen; 17745b9c547cSRui Paulo size_t len; 17755b9c547cSRui Paulo 17765b9c547cSRui Paulo buf = NULL; 17775b9c547cSRui Paulo sta->remediation = 0; 17785b9c547cSRui Paulo sta->hs20_deauth_requested = 0; 17795b9c547cSRui Paulo 17805b9c547cSRui Paulo for (;;) { 17815b9c547cSRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 17825b9c547cSRui Paulo &buf, &len, buf) < 0) 17835b9c547cSRui Paulo break; 17845b9c547cSRui Paulo if (len < 6) 17855b9c547cSRui Paulo continue; 17865b9c547cSRui Paulo pos = buf; 17875b9c547cSRui Paulo end = buf + len; 17885b9c547cSRui Paulo if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 17895b9c547cSRui Paulo continue; 17905b9c547cSRui Paulo pos += 4; 17915b9c547cSRui Paulo 17925b9c547cSRui Paulo type = *pos++; 17935b9c547cSRui Paulo sublen = *pos++; 17945b9c547cSRui Paulo if (sublen < 2) 17955b9c547cSRui Paulo continue; /* invalid length */ 17965b9c547cSRui Paulo sublen -= 2; /* skip header */ 17975b9c547cSRui Paulo if (pos + sublen > end) 17985b9c547cSRui Paulo continue; /* invalid WFA VSA */ 17995b9c547cSRui Paulo 18005b9c547cSRui Paulo switch (type) { 18015b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: 18025b9c547cSRui Paulo ieee802_1x_hs20_sub_rem(sta, pos, sublen); 18035b9c547cSRui Paulo break; 18045b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ: 18055b9c547cSRui Paulo ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen); 18065b9c547cSRui Paulo break; 18075b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL: 18085b9c547cSRui Paulo ieee802_1x_hs20_session_info(hapd, sta, pos, sublen, 18095b9c547cSRui Paulo session_timeout); 18105b9c547cSRui Paulo break; 181185732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING: 181285732ac8SCy Schubert ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen); 181385732ac8SCy Schubert break; 181485732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL: 181585732ac8SCy Schubert ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen); 181685732ac8SCy Schubert break; 18175b9c547cSRui Paulo } 18185b9c547cSRui Paulo } 18195b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 18205b9c547cSRui Paulo } 18215b9c547cSRui Paulo 18225b9c547cSRui Paulo 1823e28a4053SRui Paulo struct sta_id_search { 1824e28a4053SRui Paulo u8 identifier; 1825e28a4053SRui Paulo struct eapol_state_machine *sm; 1826e28a4053SRui Paulo }; 1827e28a4053SRui Paulo 1828e28a4053SRui Paulo 1829e28a4053SRui Paulo static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1830e28a4053SRui Paulo struct sta_info *sta, 1831e28a4053SRui Paulo void *ctx) 1832e28a4053SRui Paulo { 1833e28a4053SRui Paulo struct sta_id_search *id_search = ctx; 1834e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1835e28a4053SRui Paulo 1836e28a4053SRui Paulo if (sm && sm->radius_identifier >= 0 && 1837e28a4053SRui Paulo sm->radius_identifier == id_search->identifier) { 1838e28a4053SRui Paulo id_search->sm = sm; 1839e28a4053SRui Paulo return 1; 1840e28a4053SRui Paulo } 1841e28a4053SRui Paulo return 0; 1842e28a4053SRui Paulo } 1843e28a4053SRui Paulo 1844e28a4053SRui Paulo 1845e28a4053SRui Paulo static struct eapol_state_machine * 1846e28a4053SRui Paulo ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1847e28a4053SRui Paulo { 1848e28a4053SRui Paulo struct sta_id_search id_search; 1849e28a4053SRui Paulo id_search.identifier = identifier; 1850e28a4053SRui Paulo id_search.sm = NULL; 1851e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1852e28a4053SRui Paulo return id_search.sm; 1853e28a4053SRui Paulo } 1854e28a4053SRui Paulo 1855e28a4053SRui Paulo 18564bc52338SCy Schubert #ifndef CONFIG_NO_VLAN 18574bc52338SCy Schubert static int ieee802_1x_update_vlan(struct radius_msg *msg, 18584bc52338SCy Schubert struct hostapd_data *hapd, 18594bc52338SCy Schubert struct sta_info *sta) 18604bc52338SCy Schubert { 18614bc52338SCy Schubert struct vlan_description vlan_desc; 18624bc52338SCy Schubert 18634bc52338SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 18644bc52338SCy Schubert vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged, 18654bc52338SCy Schubert MAX_NUM_TAGGED_VLAN, 18664bc52338SCy Schubert vlan_desc.tagged); 18674bc52338SCy Schubert 18684bc52338SCy Schubert if (vlan_desc.notempty && 18694bc52338SCy Schubert !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 18704bc52338SCy Schubert sta->eapol_sm->authFail = TRUE; 18714bc52338SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 18724bc52338SCy Schubert HOSTAPD_LEVEL_INFO, 18734bc52338SCy Schubert "Invalid VLAN %d%s received from RADIUS server", 18744bc52338SCy Schubert vlan_desc.untagged, 18754bc52338SCy Schubert vlan_desc.tagged[0] ? "+" : ""); 18764bc52338SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 18774bc52338SCy Schubert ap_sta_set_vlan(hapd, sta, &vlan_desc); 18784bc52338SCy Schubert return -1; 18794bc52338SCy Schubert } 18804bc52338SCy Schubert 18814bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 18824bc52338SCy Schubert !vlan_desc.notempty) { 18834bc52338SCy Schubert sta->eapol_sm->authFail = TRUE; 18844bc52338SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 18854bc52338SCy Schubert HOSTAPD_LEVEL_INFO, 18864bc52338SCy Schubert "authentication server did not include required VLAN ID in Access-Accept"); 18874bc52338SCy Schubert return -1; 18884bc52338SCy Schubert } 18894bc52338SCy Schubert 18904bc52338SCy Schubert return ap_sta_set_vlan(hapd, sta, &vlan_desc); 18914bc52338SCy Schubert } 18924bc52338SCy Schubert #endif /* CONFIG_NO_VLAN */ 18934bc52338SCy Schubert 18944bc52338SCy Schubert 1895e28a4053SRui Paulo /** 1896e28a4053SRui Paulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1897e28a4053SRui Paulo * @msg: RADIUS response message 1898e28a4053SRui Paulo * @req: RADIUS request message 1899e28a4053SRui Paulo * @shared_secret: RADIUS shared secret 1900e28a4053SRui Paulo * @shared_secret_len: Length of shared_secret in octets 1901e28a4053SRui Paulo * @data: Context data (struct hostapd_data *) 1902e28a4053SRui Paulo * Returns: Processing status 1903e28a4053SRui Paulo */ 1904e28a4053SRui Paulo static RadiusRxResult 1905e28a4053SRui Paulo ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1906e28a4053SRui Paulo const u8 *shared_secret, size_t shared_secret_len, 1907e28a4053SRui Paulo void *data) 1908e28a4053SRui Paulo { 1909e28a4053SRui Paulo struct hostapd_data *hapd = data; 1910e28a4053SRui Paulo struct sta_info *sta; 1911e28a4053SRui Paulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1912780fb4a2SCy Schubert int session_timeout_set; 191385732ac8SCy Schubert u32 reason_code; 1914e28a4053SRui Paulo struct eapol_state_machine *sm; 1915e28a4053SRui Paulo int override_eapReq = 0; 1916e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1917e28a4053SRui Paulo 1918e28a4053SRui Paulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1919e28a4053SRui Paulo if (sm == NULL) { 1920e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1921e28a4053SRui Paulo "station for this RADIUS message"); 1922e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1923e28a4053SRui Paulo } 1924e28a4053SRui Paulo sta = sm->sta; 1925e28a4053SRui Paulo 1926e28a4053SRui Paulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1927e28a4053SRui Paulo * present when packet contains an EAP-Message attribute */ 1928e28a4053SRui Paulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1929e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1930e28a4053SRui Paulo 0) < 0 && 1931e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1932e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1933e28a4053SRui Paulo "Message-Authenticator since it does not include " 1934e28a4053SRui Paulo "EAP-Message"); 1935e28a4053SRui Paulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1936e28a4053SRui Paulo req, 1)) { 19375b9c547cSRui Paulo wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1938e28a4053SRui Paulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1939e28a4053SRui Paulo } 1940e28a4053SRui Paulo 1941e28a4053SRui Paulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1942e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1943e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 19445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1945e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1946e28a4053SRui Paulo } 1947e28a4053SRui Paulo 1948e28a4053SRui Paulo sm->radius_identifier = -1; 1949e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1950e28a4053SRui Paulo MAC2STR(sta->addr)); 1951e28a4053SRui Paulo 1952e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1953e28a4053SRui Paulo sm->last_recv_radius = msg; 1954e28a4053SRui Paulo 1955e28a4053SRui Paulo session_timeout_set = 1956e28a4053SRui Paulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1957e28a4053SRui Paulo &session_timeout); 1958e28a4053SRui Paulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1959e28a4053SRui Paulo &termination_action)) 1960e28a4053SRui Paulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1961e28a4053SRui Paulo 1962e28a4053SRui Paulo if (hapd->conf->acct_interim_interval == 0 && 1963e28a4053SRui Paulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1964e28a4053SRui Paulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1965e28a4053SRui Paulo &acct_interim_interval) == 0) { 1966e28a4053SRui Paulo if (acct_interim_interval < 60) { 1967e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1968e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1969e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1970e28a4053SRui Paulo "ignored too small " 1971e28a4053SRui Paulo "Acct-Interim-Interval %d", 1972e28a4053SRui Paulo acct_interim_interval); 1973e28a4053SRui Paulo } else 1974e28a4053SRui Paulo sta->acct_interim_interval = acct_interim_interval; 1975e28a4053SRui Paulo } 1976e28a4053SRui Paulo 1977e28a4053SRui Paulo 1978e28a4053SRui Paulo switch (hdr->code) { 1979e28a4053SRui Paulo case RADIUS_CODE_ACCESS_ACCEPT: 1980e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 19814bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED && 19824bc52338SCy Schubert ieee802_1x_update_vlan(msg, hapd, sta) < 0) 1983780fb4a2SCy Schubert break; 1984780fb4a2SCy Schubert 1985780fb4a2SCy Schubert if (sta->vlan_id > 0) { 1986780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1987780fb4a2SCy Schubert HOSTAPD_MODULE_RADIUS, 1988780fb4a2SCy Schubert HOSTAPD_LEVEL_INFO, 1989780fb4a2SCy Schubert "VLAN ID %d", sta->vlan_id); 1990780fb4a2SCy Schubert } 1991780fb4a2SCy Schubert 1992325151a3SRui Paulo if ((sta->flags & WLAN_STA_ASSOC) && 1993325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta) < 0) 1994e28a4053SRui Paulo break; 19954bc52338SCy Schubert #endif /* CONFIG_NO_VLAN */ 1996e28a4053SRui Paulo 19975b9c547cSRui Paulo sta->session_timeout_set = !!session_timeout_set; 199885732ac8SCy Schubert os_get_reltime(&sta->session_timeout); 199985732ac8SCy Schubert sta->session_timeout.sec += session_timeout; 20005b9c547cSRui Paulo 2001e28a4053SRui Paulo /* RFC 3580, Ch. 3.17 */ 2002e28a4053SRui Paulo if (session_timeout_set && termination_action == 200385732ac8SCy Schubert RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) 2004e28a4053SRui Paulo sm->reAuthPeriod = session_timeout; 200585732ac8SCy Schubert else if (session_timeout_set) 2006e28a4053SRui Paulo ap_sta_session_timeout(hapd, sta, session_timeout); 200785732ac8SCy Schubert else 200885732ac8SCy Schubert ap_sta_no_session_timeout(hapd, sta); 2009e28a4053SRui Paulo 2010e28a4053SRui Paulo sm->eap_if->aaaSuccess = TRUE; 2011e28a4053SRui Paulo override_eapReq = 1; 2012e28a4053SRui Paulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 2013e28a4053SRui Paulo shared_secret_len); 2014e28a4053SRui Paulo ieee802_1x_store_radius_class(hapd, sta, msg); 2015e28a4053SRui Paulo ieee802_1x_update_sta_identity(hapd, sta, msg); 2016f05cddf9SRui Paulo ieee802_1x_update_sta_cui(hapd, sta, msg); 20175b9c547cSRui Paulo ieee802_1x_check_hs20(hapd, sta, msg, 20185b9c547cSRui Paulo session_timeout_set ? 20195b9c547cSRui Paulo (int) session_timeout : -1); 2020e28a4053SRui Paulo break; 2021e28a4053SRui Paulo case RADIUS_CODE_ACCESS_REJECT: 2022e28a4053SRui Paulo sm->eap_if->aaaFail = TRUE; 2023e28a4053SRui Paulo override_eapReq = 1; 202485732ac8SCy Schubert if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 202585732ac8SCy Schubert &reason_code) == 0) { 202685732ac8SCy Schubert wpa_printf(MSG_DEBUG, 202785732ac8SCy Schubert "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for " 202885732ac8SCy Schubert MACSTR, reason_code, MAC2STR(sta->addr)); 202985732ac8SCy Schubert sta->disconnect_reason_code = reason_code; 203085732ac8SCy Schubert } 2031e28a4053SRui Paulo break; 2032e28a4053SRui Paulo case RADIUS_CODE_ACCESS_CHALLENGE: 2033e28a4053SRui Paulo sm->eap_if->aaaEapReq = TRUE; 2034e28a4053SRui Paulo if (session_timeout_set) { 2035e28a4053SRui Paulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 2036e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = session_timeout; 2037e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, 2038e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 2039e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 2040e28a4053SRui Paulo "using EAP timeout of %d seconds (from " 2041e28a4053SRui Paulo "RADIUS)", 2042e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout); 2043e28a4053SRui Paulo } else { 2044e28a4053SRui Paulo /* 2045e28a4053SRui Paulo * Use dynamic retransmission behavior per EAP 2046e28a4053SRui Paulo * specification. 2047e28a4053SRui Paulo */ 2048e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = 0; 2049e28a4053SRui Paulo } 2050e28a4053SRui Paulo break; 2051e28a4053SRui Paulo } 2052e28a4053SRui Paulo 2053e28a4053SRui Paulo ieee802_1x_decapsulate_radius(hapd, sta); 2054e28a4053SRui Paulo if (override_eapReq) 2055e28a4053SRui Paulo sm->eap_if->aaaEapReq = FALSE; 2056e28a4053SRui Paulo 205785732ac8SCy Schubert #ifdef CONFIG_FILS 205885732ac8SCy Schubert #ifdef NEED_AP_MLME 205985732ac8SCy Schubert if (sta->flags & WLAN_STA_PENDING_FILS_ERP) { 206085732ac8SCy Schubert /* TODO: Add a PMKSA entry on success? */ 206185732ac8SCy Schubert ieee802_11_finish_fils_auth( 206285732ac8SCy Schubert hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT, 206385732ac8SCy Schubert sm->eap_if->aaaEapReqData, 206485732ac8SCy Schubert sm->eap_if->aaaEapKeyData, 206585732ac8SCy Schubert sm->eap_if->aaaEapKeyDataLen); 206685732ac8SCy Schubert } 206785732ac8SCy Schubert #endif /* NEED_AP_MLME */ 206885732ac8SCy Schubert #endif /* CONFIG_FILS */ 206985732ac8SCy Schubert 2070e28a4053SRui Paulo eapol_auth_step(sm); 2071e28a4053SRui Paulo 2072e28a4053SRui Paulo return RADIUS_RX_QUEUED; 2073e28a4053SRui Paulo } 2074e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2075e28a4053SRui Paulo 2076e28a4053SRui Paulo 2077e28a4053SRui Paulo void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 2078e28a4053SRui Paulo { 2079e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 2080e28a4053SRui Paulo if (sm == NULL) 2081e28a4053SRui Paulo return; 2082e28a4053SRui Paulo 2083e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2084e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 2085e28a4053SRui Paulo 2086e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2087e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 2088e28a4053SRui Paulo sm->last_recv_radius = NULL; 2089e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2090e28a4053SRui Paulo 2091e28a4053SRui Paulo if (sm->eap_if->eapTimeout) { 2092e28a4053SRui Paulo /* 2093e28a4053SRui Paulo * Disconnect the STA since it did not reply to the last EAP 2094e28a4053SRui Paulo * request and we cannot continue EAP processing (EAP-Failure 2095e28a4053SRui Paulo * could only be sent if the EAP peer actually replied). 2096e28a4053SRui Paulo */ 2097f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 2098f05cddf9SRui Paulo MAC2STR(sta->addr)); 2099f05cddf9SRui Paulo 2100e28a4053SRui Paulo sm->eap_if->portEnabled = FALSE; 2101e28a4053SRui Paulo ap_sta_disconnect(hapd, sta, sta->addr, 2102e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 2103e28a4053SRui Paulo } 2104e28a4053SRui Paulo } 2105e28a4053SRui Paulo 2106e28a4053SRui Paulo 2107e28a4053SRui Paulo static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 2108e28a4053SRui Paulo { 2109e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2110e28a4053SRui Paulo 2111e28a4053SRui Paulo if (hapd->conf->default_wep_key_len < 1) 2112e28a4053SRui Paulo return 0; 2113e28a4053SRui Paulo 2114e28a4053SRui Paulo os_free(eapol->default_wep_key); 2115e28a4053SRui Paulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 2116e28a4053SRui Paulo if (eapol->default_wep_key == NULL || 2117f05cddf9SRui Paulo random_get_bytes(eapol->default_wep_key, 2118e28a4053SRui Paulo hapd->conf->default_wep_key_len)) { 21195b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not generate random WEP key"); 2120e28a4053SRui Paulo os_free(eapol->default_wep_key); 2121e28a4053SRui Paulo eapol->default_wep_key = NULL; 2122e28a4053SRui Paulo return -1; 2123e28a4053SRui Paulo } 2124e28a4053SRui Paulo 2125e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 2126e28a4053SRui Paulo eapol->default_wep_key, 2127e28a4053SRui Paulo hapd->conf->default_wep_key_len); 2128e28a4053SRui Paulo 2129e28a4053SRui Paulo return 0; 2130e28a4053SRui Paulo } 2131e28a4053SRui Paulo 2132e28a4053SRui Paulo 2133e28a4053SRui Paulo static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 2134e28a4053SRui Paulo struct sta_info *sta, void *ctx) 2135e28a4053SRui Paulo { 2136e28a4053SRui Paulo if (sta->eapol_sm) { 2137e28a4053SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 2138e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 2139e28a4053SRui Paulo } 2140e28a4053SRui Paulo return 0; 2141e28a4053SRui Paulo } 2142e28a4053SRui Paulo 2143e28a4053SRui Paulo 2144e28a4053SRui Paulo static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 2145e28a4053SRui Paulo { 2146e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 2147e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2148e28a4053SRui Paulo 2149e28a4053SRui Paulo if (eapol->default_wep_key_idx >= 3) 2150e28a4053SRui Paulo eapol->default_wep_key_idx = 2151e28a4053SRui Paulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 2152e28a4053SRui Paulo else 2153e28a4053SRui Paulo eapol->default_wep_key_idx++; 2154e28a4053SRui Paulo 2155e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 2156e28a4053SRui Paulo eapol->default_wep_key_idx); 2157e28a4053SRui Paulo 2158e28a4053SRui Paulo if (ieee802_1x_rekey_broadcast(hapd)) { 2159e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2160e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "failed to generate a " 2161e28a4053SRui Paulo "new broadcast key"); 2162e28a4053SRui Paulo os_free(eapol->default_wep_key); 2163e28a4053SRui Paulo eapol->default_wep_key = NULL; 2164e28a4053SRui Paulo return; 2165e28a4053SRui Paulo } 2166e28a4053SRui Paulo 2167e28a4053SRui Paulo /* TODO: Could setup key for RX here, but change default TX keyid only 2168e28a4053SRui Paulo * after new broadcast key has been sent to all stations. */ 2169f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 2170f05cddf9SRui Paulo broadcast_ether_addr, 2171e28a4053SRui Paulo eapol->default_wep_key_idx, 1, NULL, 0, 2172e28a4053SRui Paulo eapol->default_wep_key, 2173e28a4053SRui Paulo hapd->conf->default_wep_key_len)) { 2174e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2175e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "failed to configure a " 2176e28a4053SRui Paulo "new broadcast key"); 2177e28a4053SRui Paulo os_free(eapol->default_wep_key); 2178e28a4053SRui Paulo eapol->default_wep_key = NULL; 2179e28a4053SRui Paulo return; 2180e28a4053SRui Paulo } 2181e28a4053SRui Paulo 2182e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 2183e28a4053SRui Paulo 2184e28a4053SRui Paulo if (hapd->conf->wep_rekeying_period > 0) { 2185e28a4053SRui Paulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 2186e28a4053SRui Paulo ieee802_1x_rekey, hapd, NULL); 2187e28a4053SRui Paulo } 2188e28a4053SRui Paulo } 2189e28a4053SRui Paulo 2190e28a4053SRui Paulo 2191e28a4053SRui Paulo static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 2192e28a4053SRui Paulo const u8 *data, size_t datalen) 2193e28a4053SRui Paulo { 2194e28a4053SRui Paulo #ifdef CONFIG_WPS 2195e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2196e28a4053SRui Paulo 2197e28a4053SRui Paulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 2198e28a4053SRui Paulo WLAN_STA_MAYBE_WPS) { 2199e28a4053SRui Paulo const u8 *identity; 2200e28a4053SRui Paulo size_t identity_len; 2201e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 2202e28a4053SRui Paulo 2203e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 2204e28a4053SRui Paulo if (identity && 2205e28a4053SRui Paulo ((identity_len == WSC_ID_ENROLLEE_LEN && 2206e28a4053SRui Paulo os_memcmp(identity, WSC_ID_ENROLLEE, 2207e28a4053SRui Paulo WSC_ID_ENROLLEE_LEN) == 0) || 2208e28a4053SRui Paulo (identity_len == WSC_ID_REGISTRAR_LEN && 2209e28a4053SRui Paulo os_memcmp(identity, WSC_ID_REGISTRAR, 2210e28a4053SRui Paulo WSC_ID_REGISTRAR_LEN) == 0))) { 2211e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 2212e28a4053SRui Paulo "WLAN_STA_WPS"); 2213e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 2214e28a4053SRui Paulo } 2215e28a4053SRui Paulo } 2216e28a4053SRui Paulo #endif /* CONFIG_WPS */ 2217e28a4053SRui Paulo 2218e28a4053SRui Paulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 2219e28a4053SRui Paulo } 2220e28a4053SRui Paulo 2221e28a4053SRui Paulo 2222e28a4053SRui Paulo static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 2223e28a4053SRui Paulo const u8 *data, size_t datalen) 2224e28a4053SRui Paulo { 2225e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2226e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2227e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2228e28a4053SRui Paulo 2229e28a4053SRui Paulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 2230e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2231e28a4053SRui Paulo } 2232e28a4053SRui Paulo 2233e28a4053SRui Paulo 2234e28a4053SRui Paulo static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 22355b9c547cSRui Paulo int preauth, int remediation) 2236e28a4053SRui Paulo { 2237e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2238e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2239e28a4053SRui Paulo if (preauth) 2240e28a4053SRui Paulo rsn_preauth_finished(hapd, sta, success); 2241e28a4053SRui Paulo else 22425b9c547cSRui Paulo ieee802_1x_finished(hapd, sta, success, remediation); 2243e28a4053SRui Paulo } 2244e28a4053SRui Paulo 2245e28a4053SRui Paulo 2246e28a4053SRui Paulo static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 2247e28a4053SRui Paulo size_t identity_len, int phase2, 2248e28a4053SRui Paulo struct eap_user *user) 2249e28a4053SRui Paulo { 2250e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2251e28a4053SRui Paulo const struct hostapd_eap_user *eap_user; 2252f05cddf9SRui Paulo int i; 2253325151a3SRui Paulo int rv = -1; 2254e28a4053SRui Paulo 2255f05cddf9SRui Paulo eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 2256e28a4053SRui Paulo if (eap_user == NULL) 2257325151a3SRui Paulo goto out; 2258e28a4053SRui Paulo 2259e28a4053SRui Paulo os_memset(user, 0, sizeof(*user)); 2260e28a4053SRui Paulo user->phase2 = phase2; 2261f05cddf9SRui Paulo for (i = 0; i < EAP_MAX_METHODS; i++) { 2262e28a4053SRui Paulo user->methods[i].vendor = eap_user->methods[i].vendor; 2263e28a4053SRui Paulo user->methods[i].method = eap_user->methods[i].method; 2264e28a4053SRui Paulo } 2265e28a4053SRui Paulo 2266e28a4053SRui Paulo if (eap_user->password) { 226785732ac8SCy Schubert user->password = os_memdup(eap_user->password, 226885732ac8SCy Schubert eap_user->password_len); 2269e28a4053SRui Paulo if (user->password == NULL) 2270325151a3SRui Paulo goto out; 2271e28a4053SRui Paulo user->password_len = eap_user->password_len; 2272f05cddf9SRui Paulo user->password_hash = eap_user->password_hash; 227385732ac8SCy Schubert if (eap_user->salt && eap_user->salt_len) { 227485732ac8SCy Schubert user->salt = os_memdup(eap_user->salt, 227585732ac8SCy Schubert eap_user->salt_len); 227685732ac8SCy Schubert if (!user->salt) 227785732ac8SCy Schubert goto out; 227885732ac8SCy Schubert user->salt_len = eap_user->salt_len; 227985732ac8SCy Schubert } 2280e28a4053SRui Paulo } 2281e28a4053SRui Paulo user->force_version = eap_user->force_version; 22825b9c547cSRui Paulo user->macacl = eap_user->macacl; 2283e28a4053SRui Paulo user->ttls_auth = eap_user->ttls_auth; 22845b9c547cSRui Paulo user->remediation = eap_user->remediation; 2285325151a3SRui Paulo rv = 0; 2286e28a4053SRui Paulo 2287325151a3SRui Paulo out: 2288325151a3SRui Paulo if (rv) 2289325151a3SRui Paulo wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); 2290325151a3SRui Paulo 2291325151a3SRui Paulo return rv; 2292e28a4053SRui Paulo } 2293e28a4053SRui Paulo 2294e28a4053SRui Paulo 2295e28a4053SRui Paulo static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 2296e28a4053SRui Paulo { 2297e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2298e28a4053SRui Paulo struct sta_info *sta; 2299e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 2300e28a4053SRui Paulo if (sta == NULL || sta->eapol_sm == NULL) 2301e28a4053SRui Paulo return 0; 2302e28a4053SRui Paulo return 1; 2303e28a4053SRui Paulo } 2304e28a4053SRui Paulo 2305e28a4053SRui Paulo 2306e28a4053SRui Paulo static void ieee802_1x_logger(void *ctx, const u8 *addr, 2307e28a4053SRui Paulo eapol_logger_level level, const char *txt) 2308e28a4053SRui Paulo { 2309e28a4053SRui Paulo #ifndef CONFIG_NO_HOSTAPD_LOGGER 2310e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2311e28a4053SRui Paulo int hlevel; 2312e28a4053SRui Paulo 2313e28a4053SRui Paulo switch (level) { 2314e28a4053SRui Paulo case EAPOL_LOGGER_WARNING: 2315e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_WARNING; 2316e28a4053SRui Paulo break; 2317e28a4053SRui Paulo case EAPOL_LOGGER_INFO: 2318e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_INFO; 2319e28a4053SRui Paulo break; 2320e28a4053SRui Paulo case EAPOL_LOGGER_DEBUG: 2321e28a4053SRui Paulo default: 2322e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_DEBUG; 2323e28a4053SRui Paulo break; 2324e28a4053SRui Paulo } 2325e28a4053SRui Paulo 2326e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 2327e28a4053SRui Paulo txt); 2328e28a4053SRui Paulo #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 2329e28a4053SRui Paulo } 2330e28a4053SRui Paulo 2331e28a4053SRui Paulo 2332e28a4053SRui Paulo static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 2333e28a4053SRui Paulo int authorized) 2334e28a4053SRui Paulo { 2335e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2336e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2337e28a4053SRui Paulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 2338e28a4053SRui Paulo } 2339e28a4053SRui Paulo 2340e28a4053SRui Paulo 2341e28a4053SRui Paulo static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 2342e28a4053SRui Paulo { 2343e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2344e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2345e28a4053SRui Paulo ieee802_1x_abort_auth(hapd, sta); 2346e28a4053SRui Paulo } 2347e28a4053SRui Paulo 2348e28a4053SRui Paulo 2349e28a4053SRui Paulo static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 2350e28a4053SRui Paulo { 2351325151a3SRui Paulo #ifndef CONFIG_FIPS 2352325151a3SRui Paulo #ifndef CONFIG_NO_RC4 2353e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2354e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2355e28a4053SRui Paulo ieee802_1x_tx_key(hapd, sta); 2356325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 2357325151a3SRui Paulo #endif /* CONFIG_FIPS */ 2358e28a4053SRui Paulo } 2359e28a4053SRui Paulo 2360e28a4053SRui Paulo 2361e28a4053SRui Paulo static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 2362e28a4053SRui Paulo enum eapol_event type) 2363e28a4053SRui Paulo { 2364e28a4053SRui Paulo /* struct hostapd_data *hapd = ctx; */ 2365e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2366e28a4053SRui Paulo switch (type) { 2367e28a4053SRui Paulo case EAPOL_AUTH_SM_CHANGE: 2368e28a4053SRui Paulo wpa_auth_sm_notify(sta->wpa_sm); 2369e28a4053SRui Paulo break; 2370e28a4053SRui Paulo case EAPOL_AUTH_REAUTHENTICATE: 2371e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 2372e28a4053SRui Paulo break; 2373e28a4053SRui Paulo } 2374e28a4053SRui Paulo } 2375e28a4053SRui Paulo 2376e28a4053SRui Paulo 23775b9c547cSRui Paulo #ifdef CONFIG_ERP 23785b9c547cSRui Paulo 23795b9c547cSRui Paulo static struct eap_server_erp_key * 23805b9c547cSRui Paulo ieee802_1x_erp_get_key(void *ctx, const char *keyname) 23815b9c547cSRui Paulo { 23825b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 23835b9c547cSRui Paulo struct eap_server_erp_key *erp; 23845b9c547cSRui Paulo 23855b9c547cSRui Paulo dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key, 23865b9c547cSRui Paulo list) { 23875b9c547cSRui Paulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 23885b9c547cSRui Paulo return erp; 23895b9c547cSRui Paulo } 23905b9c547cSRui Paulo 23915b9c547cSRui Paulo return NULL; 23925b9c547cSRui Paulo } 23935b9c547cSRui Paulo 23945b9c547cSRui Paulo 23955b9c547cSRui Paulo static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 23965b9c547cSRui Paulo { 23975b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 23985b9c547cSRui Paulo 23995b9c547cSRui Paulo dl_list_add(&hapd->erp_keys, &erp->list); 24005b9c547cSRui Paulo return 0; 24015b9c547cSRui Paulo } 24025b9c547cSRui Paulo 24035b9c547cSRui Paulo #endif /* CONFIG_ERP */ 24045b9c547cSRui Paulo 24055b9c547cSRui Paulo 2406e28a4053SRui Paulo int ieee802_1x_init(struct hostapd_data *hapd) 2407e28a4053SRui Paulo { 2408e28a4053SRui Paulo int i; 2409e28a4053SRui Paulo struct eapol_auth_config conf; 2410e28a4053SRui Paulo struct eapol_auth_cb cb; 2411e28a4053SRui Paulo 24125b9c547cSRui Paulo dl_list_init(&hapd->erp_keys); 24135b9c547cSRui Paulo 2414e28a4053SRui Paulo os_memset(&conf, 0, sizeof(conf)); 2415e28a4053SRui Paulo conf.ctx = hapd; 2416e28a4053SRui Paulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 2417e28a4053SRui Paulo conf.wpa = hapd->conf->wpa; 2418e28a4053SRui Paulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 2419e28a4053SRui Paulo conf.eap_server = hapd->conf->eap_server; 2420e28a4053SRui Paulo conf.ssl_ctx = hapd->ssl_ctx; 2421e28a4053SRui Paulo conf.msg_ctx = hapd->msg_ctx; 2422e28a4053SRui Paulo conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 2423e28a4053SRui Paulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 2424e28a4053SRui Paulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 24255b9c547cSRui Paulo conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 24265b9c547cSRui Paulo conf.erp_domain = hapd->conf->erp_domain; 24275b9c547cSRui Paulo conf.erp = hapd->conf->eap_server_erp; 2428325151a3SRui Paulo conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; 242985732ac8SCy Schubert conf.tls_flags = hapd->conf->tls_flags; 2430e28a4053SRui Paulo conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 2431e28a4053SRui Paulo conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 2432e28a4053SRui Paulo conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 2433e28a4053SRui Paulo conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 2434e28a4053SRui Paulo conf.eap_fast_prov = hapd->conf->eap_fast_prov; 2435e28a4053SRui Paulo conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 2436e28a4053SRui Paulo conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 2437*206b73d0SCy Schubert conf.eap_teap_auth = hapd->conf->eap_teap_auth; 2438*206b73d0SCy Schubert conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; 2439e28a4053SRui Paulo conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 2440*206b73d0SCy Schubert conf.eap_sim_id = hapd->conf->eap_sim_id; 2441e28a4053SRui Paulo conf.tnc = hapd->conf->tnc; 2442e28a4053SRui Paulo conf.wps = hapd->wps; 2443f05cddf9SRui Paulo conf.fragment_size = hapd->conf->fragment_size; 2444f05cddf9SRui Paulo conf.pwd_group = hapd->conf->pwd_group; 2445f05cddf9SRui Paulo conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 24465b9c547cSRui Paulo if (hapd->conf->server_id) { 24475b9c547cSRui Paulo conf.server_id = (const u8 *) hapd->conf->server_id; 24485b9c547cSRui Paulo conf.server_id_len = os_strlen(hapd->conf->server_id); 24495b9c547cSRui Paulo } else { 24505b9c547cSRui Paulo conf.server_id = (const u8 *) "hostapd"; 24515b9c547cSRui Paulo conf.server_id_len = 7; 24525b9c547cSRui Paulo } 2453e28a4053SRui Paulo 2454e28a4053SRui Paulo os_memset(&cb, 0, sizeof(cb)); 2455e28a4053SRui Paulo cb.eapol_send = ieee802_1x_eapol_send; 2456e28a4053SRui Paulo cb.aaa_send = ieee802_1x_aaa_send; 2457e28a4053SRui Paulo cb.finished = _ieee802_1x_finished; 2458e28a4053SRui Paulo cb.get_eap_user = ieee802_1x_get_eap_user; 2459e28a4053SRui Paulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 2460e28a4053SRui Paulo cb.logger = ieee802_1x_logger; 2461e28a4053SRui Paulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 2462e28a4053SRui Paulo cb.abort_auth = _ieee802_1x_abort_auth; 2463e28a4053SRui Paulo cb.tx_key = _ieee802_1x_tx_key; 2464e28a4053SRui Paulo cb.eapol_event = ieee802_1x_eapol_event; 24655b9c547cSRui Paulo #ifdef CONFIG_ERP 24665b9c547cSRui Paulo cb.erp_get_key = ieee802_1x_erp_get_key; 24675b9c547cSRui Paulo cb.erp_add_key = ieee802_1x_erp_add_key; 24685b9c547cSRui Paulo #endif /* CONFIG_ERP */ 2469e28a4053SRui Paulo 2470e28a4053SRui Paulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 2471e28a4053SRui Paulo if (hapd->eapol_auth == NULL) 2472e28a4053SRui Paulo return -1; 2473e28a4053SRui Paulo 2474e28a4053SRui Paulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 2475f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 2476e28a4053SRui Paulo return -1; 2477e28a4053SRui Paulo 2478e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2479e28a4053SRui Paulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 2480e28a4053SRui Paulo ieee802_1x_receive_auth, hapd)) 2481e28a4053SRui Paulo return -1; 2482e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2483e28a4053SRui Paulo 2484e28a4053SRui Paulo if (hapd->conf->default_wep_key_len) { 2485e28a4053SRui Paulo for (i = 0; i < 4; i++) 2486f05cddf9SRui Paulo hostapd_drv_set_key(hapd->conf->iface, hapd, 2487e28a4053SRui Paulo WPA_ALG_NONE, NULL, i, 0, NULL, 0, 2488e28a4053SRui Paulo NULL, 0); 2489e28a4053SRui Paulo 2490e28a4053SRui Paulo ieee802_1x_rekey(hapd, NULL); 2491e28a4053SRui Paulo 2492e28a4053SRui Paulo if (hapd->eapol_auth->default_wep_key == NULL) 2493e28a4053SRui Paulo return -1; 2494e28a4053SRui Paulo } 2495e28a4053SRui Paulo 2496e28a4053SRui Paulo return 0; 2497e28a4053SRui Paulo } 2498e28a4053SRui Paulo 2499e28a4053SRui Paulo 25005b9c547cSRui Paulo void ieee802_1x_erp_flush(struct hostapd_data *hapd) 25015b9c547cSRui Paulo { 25025b9c547cSRui Paulo struct eap_server_erp_key *erp; 25035b9c547cSRui Paulo 25045b9c547cSRui Paulo while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key, 25055b9c547cSRui Paulo list)) != NULL) { 25065b9c547cSRui Paulo dl_list_del(&erp->list); 25075b9c547cSRui Paulo bin_clear_free(erp, sizeof(*erp)); 25085b9c547cSRui Paulo } 25095b9c547cSRui Paulo } 25105b9c547cSRui Paulo 25115b9c547cSRui Paulo 2512e28a4053SRui Paulo void ieee802_1x_deinit(struct hostapd_data *hapd) 2513e28a4053SRui Paulo { 2514e28a4053SRui Paulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 2515e28a4053SRui Paulo 2516780fb4a2SCy Schubert if (hapd->driver && hapd->drv_priv && 2517e28a4053SRui Paulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 2518f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 2519e28a4053SRui Paulo 2520e28a4053SRui Paulo eapol_auth_deinit(hapd->eapol_auth); 2521e28a4053SRui Paulo hapd->eapol_auth = NULL; 25225b9c547cSRui Paulo 25235b9c547cSRui Paulo ieee802_1x_erp_flush(hapd); 2524e28a4053SRui Paulo } 2525e28a4053SRui Paulo 2526e28a4053SRui Paulo 2527e28a4053SRui Paulo int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2528e28a4053SRui Paulo const u8 *buf, size_t len, int ack) 2529e28a4053SRui Paulo { 2530e28a4053SRui Paulo struct ieee80211_hdr *hdr; 2531e28a4053SRui Paulo u8 *pos; 2532e28a4053SRui Paulo const unsigned char rfc1042_hdr[ETH_ALEN] = 2533e28a4053SRui Paulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 2534e28a4053SRui Paulo 2535e28a4053SRui Paulo if (sta == NULL) 2536e28a4053SRui Paulo return -1; 2537f05cddf9SRui Paulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 2538e28a4053SRui Paulo return 0; 2539e28a4053SRui Paulo 2540e28a4053SRui Paulo hdr = (struct ieee80211_hdr *) buf; 2541e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 2542e28a4053SRui Paulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 2543e28a4053SRui Paulo return 0; 2544e28a4053SRui Paulo pos += sizeof(rfc1042_hdr); 2545e28a4053SRui Paulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 2546e28a4053SRui Paulo return 0; 2547e28a4053SRui Paulo pos += 2; 2548e28a4053SRui Paulo 2549f05cddf9SRui Paulo return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 2550f05cddf9SRui Paulo ack); 2551f05cddf9SRui Paulo } 2552e28a4053SRui Paulo 2553f05cddf9SRui Paulo 2554f05cddf9SRui Paulo int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2555f05cddf9SRui Paulo const u8 *buf, int len, int ack) 2556f05cddf9SRui Paulo { 2557f05cddf9SRui Paulo const struct ieee802_1x_hdr *xhdr = 2558f05cddf9SRui Paulo (const struct ieee802_1x_hdr *) buf; 2559f05cddf9SRui Paulo const u8 *pos = buf + sizeof(*xhdr); 2560f05cddf9SRui Paulo struct ieee802_1x_eapol_key *key; 2561f05cddf9SRui Paulo 2562f05cddf9SRui Paulo if (len < (int) sizeof(*xhdr)) 2563f05cddf9SRui Paulo return 0; 2564e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 2565e28a4053SRui Paulo "type=%d length=%d - ack=%d", 2566e28a4053SRui Paulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 2567e28a4053SRui Paulo be_to_host16(xhdr->length), ack); 2568e28a4053SRui Paulo 256985732ac8SCy Schubert #ifdef CONFIG_WPS 257085732ac8SCy Schubert if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack && 257185732ac8SCy Schubert (sta->flags & WLAN_STA_WPS) && 257285732ac8SCy Schubert ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) { 257385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 257485732ac8SCy Schubert "WPS: Indicate EAP completion on ACK for EAP-Failure"); 257585732ac8SCy Schubert hostapd_wps_eap_completed(hapd); 257685732ac8SCy Schubert } 257785732ac8SCy Schubert #endif /* CONFIG_WPS */ 257885732ac8SCy Schubert 2579f05cddf9SRui Paulo if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 2580f05cddf9SRui Paulo return 0; 2581f05cddf9SRui Paulo 2582f05cddf9SRui Paulo if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 2583f05cddf9SRui Paulo const struct wpa_eapol_key *wpa; 2584f05cddf9SRui Paulo wpa = (const struct wpa_eapol_key *) pos; 2585f05cddf9SRui Paulo if (wpa->type == EAPOL_KEY_TYPE_RSN || 2586f05cddf9SRui Paulo wpa->type == EAPOL_KEY_TYPE_WPA) 2587f05cddf9SRui Paulo wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 2588f05cddf9SRui Paulo sta->wpa_sm, ack); 2589f05cddf9SRui Paulo } 2590f05cddf9SRui Paulo 2591e28a4053SRui Paulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 2592e28a4053SRui Paulo * or Authenticator state machines, but EAPOL-Key packets are not 2593f05cddf9SRui Paulo * retransmitted in case of failure. Try to re-send failed EAPOL-Key 2594e28a4053SRui Paulo * packets couple of times because otherwise STA keys become 2595e28a4053SRui Paulo * unsynchronized with AP. */ 2596f05cddf9SRui Paulo if (!ack && pos + sizeof(*key) <= buf + len) { 2597e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) pos; 2598e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2599e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 2600e28a4053SRui Paulo "frame (%scast index=%d)", 2601e28a4053SRui Paulo key->key_index & BIT(7) ? "uni" : "broad", 2602e28a4053SRui Paulo key->key_index & ~BIT(7)); 2603e28a4053SRui Paulo /* TODO: re-send EAPOL-Key couple of times (with short delay 2604e28a4053SRui Paulo * between them?). If all attempt fail, report error and 2605e28a4053SRui Paulo * deauthenticate STA so that it will get new keys when 2606e28a4053SRui Paulo * authenticating again (e.g., after returning in range). 2607e28a4053SRui Paulo * Separate limit/transmit state needed both for unicast and 2608e28a4053SRui Paulo * broadcast keys(?) */ 2609e28a4053SRui Paulo } 2610e28a4053SRui Paulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 2611e28a4053SRui Paulo * to here and change the key only if the EAPOL-Key packet was Acked. 2612e28a4053SRui Paulo */ 2613e28a4053SRui Paulo 2614e28a4053SRui Paulo return 1; 2615e28a4053SRui Paulo } 2616e28a4053SRui Paulo 2617e28a4053SRui Paulo 2618e28a4053SRui Paulo u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 2619e28a4053SRui Paulo { 2620e28a4053SRui Paulo if (sm == NULL || sm->identity == NULL) 2621e28a4053SRui Paulo return NULL; 2622e28a4053SRui Paulo 2623e28a4053SRui Paulo *len = sm->identity_len; 2624e28a4053SRui Paulo return sm->identity; 2625e28a4053SRui Paulo } 2626e28a4053SRui Paulo 2627e28a4053SRui Paulo 2628e28a4053SRui Paulo u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 2629e28a4053SRui Paulo int idx) 2630e28a4053SRui Paulo { 2631e28a4053SRui Paulo if (sm == NULL || sm->radius_class.attr == NULL || 2632e28a4053SRui Paulo idx >= (int) sm->radius_class.count) 2633e28a4053SRui Paulo return NULL; 2634e28a4053SRui Paulo 2635e28a4053SRui Paulo *len = sm->radius_class.attr[idx].len; 2636e28a4053SRui Paulo return sm->radius_class.attr[idx].data; 2637e28a4053SRui Paulo } 2638e28a4053SRui Paulo 2639e28a4053SRui Paulo 2640f05cddf9SRui Paulo struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 2641f05cddf9SRui Paulo { 2642f05cddf9SRui Paulo if (sm == NULL) 2643f05cddf9SRui Paulo return NULL; 2644f05cddf9SRui Paulo return sm->radius_cui; 2645f05cddf9SRui Paulo } 2646f05cddf9SRui Paulo 2647f05cddf9SRui Paulo 2648e28a4053SRui Paulo const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2649e28a4053SRui Paulo { 2650f05cddf9SRui Paulo *len = 0; 2651e28a4053SRui Paulo if (sm == NULL) 2652e28a4053SRui Paulo return NULL; 2653e28a4053SRui Paulo 2654e28a4053SRui Paulo *len = sm->eap_if->eapKeyDataLen; 2655e28a4053SRui Paulo return sm->eap_if->eapKeyData; 2656e28a4053SRui Paulo } 2657e28a4053SRui Paulo 2658e28a4053SRui Paulo 2659*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 2660*206b73d0SCy Schubert const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm, 2661*206b73d0SCy Schubert size_t *len) 2662*206b73d0SCy Schubert { 2663*206b73d0SCy Schubert *len = 0; 2664*206b73d0SCy Schubert if (!sm || !sm->eap_if) 2665*206b73d0SCy Schubert return NULL; 2666*206b73d0SCy Schubert 2667*206b73d0SCy Schubert *len = sm->eap_if->eapSessionIdLen; 2668*206b73d0SCy Schubert return sm->eap_if->eapSessionId; 2669*206b73d0SCy Schubert } 2670*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 2671*206b73d0SCy Schubert 2672*206b73d0SCy Schubert 2673e28a4053SRui Paulo void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2674e28a4053SRui Paulo int enabled) 2675e28a4053SRui Paulo { 2676e28a4053SRui Paulo if (sm == NULL) 2677e28a4053SRui Paulo return; 2678e28a4053SRui Paulo sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 2679e28a4053SRui Paulo eapol_auth_step(sm); 2680e28a4053SRui Paulo } 2681e28a4053SRui Paulo 2682e28a4053SRui Paulo 2683e28a4053SRui Paulo void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 2684e28a4053SRui Paulo int valid) 2685e28a4053SRui Paulo { 2686e28a4053SRui Paulo if (sm == NULL) 2687e28a4053SRui Paulo return; 2688e28a4053SRui Paulo sm->portValid = valid ? TRUE : FALSE; 2689e28a4053SRui Paulo eapol_auth_step(sm); 2690e28a4053SRui Paulo } 2691e28a4053SRui Paulo 2692e28a4053SRui Paulo 2693e28a4053SRui Paulo void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 2694e28a4053SRui Paulo { 2695e28a4053SRui Paulo if (sm == NULL) 2696e28a4053SRui Paulo return; 2697e28a4053SRui Paulo if (pre_auth) 2698e28a4053SRui Paulo sm->flags |= EAPOL_SM_PREAUTH; 2699e28a4053SRui Paulo else 2700e28a4053SRui Paulo sm->flags &= ~EAPOL_SM_PREAUTH; 2701e28a4053SRui Paulo } 2702e28a4053SRui Paulo 2703e28a4053SRui Paulo 2704325151a3SRui Paulo static const char * bool_txt(Boolean val) 2705e28a4053SRui Paulo { 2706325151a3SRui Paulo return val ? "TRUE" : "FALSE"; 2707e28a4053SRui Paulo } 2708e28a4053SRui Paulo 2709e28a4053SRui Paulo 2710e28a4053SRui Paulo int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2711e28a4053SRui Paulo { 2712e28a4053SRui Paulo /* TODO */ 2713e28a4053SRui Paulo return 0; 2714e28a4053SRui Paulo } 2715e28a4053SRui Paulo 2716e28a4053SRui Paulo 2717e28a4053SRui Paulo int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2718e28a4053SRui Paulo char *buf, size_t buflen) 2719e28a4053SRui Paulo { 2720e28a4053SRui Paulo int len = 0, ret; 2721e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 27225b9c547cSRui Paulo struct os_reltime diff; 27235b9c547cSRui Paulo const char *name1; 27245b9c547cSRui Paulo const char *name2; 27254bc52338SCy Schubert char *identity_buf = NULL; 2726e28a4053SRui Paulo 2727e28a4053SRui Paulo if (sm == NULL) 2728e28a4053SRui Paulo return 0; 2729e28a4053SRui Paulo 2730e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2731e28a4053SRui Paulo "dot1xPaePortNumber=%d\n" 2732e28a4053SRui Paulo "dot1xPaePortProtocolVersion=%d\n" 2733e28a4053SRui Paulo "dot1xPaePortCapabilities=1\n" 2734e28a4053SRui Paulo "dot1xPaePortInitialize=%d\n" 2735e28a4053SRui Paulo "dot1xPaePortReauthenticate=FALSE\n", 2736e28a4053SRui Paulo sta->aid, 2737e28a4053SRui Paulo EAPOL_VERSION, 2738e28a4053SRui Paulo sm->initialize); 27395b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2740e28a4053SRui Paulo return len; 2741e28a4053SRui Paulo len += ret; 2742e28a4053SRui Paulo 2743e28a4053SRui Paulo /* dot1xAuthConfigTable */ 2744e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2745e28a4053SRui Paulo "dot1xAuthPaeState=%d\n" 2746e28a4053SRui Paulo "dot1xAuthBackendAuthState=%d\n" 2747e28a4053SRui Paulo "dot1xAuthAdminControlledDirections=%d\n" 2748e28a4053SRui Paulo "dot1xAuthOperControlledDirections=%d\n" 2749e28a4053SRui Paulo "dot1xAuthAuthControlledPortStatus=%d\n" 2750e28a4053SRui Paulo "dot1xAuthAuthControlledPortControl=%d\n" 2751e28a4053SRui Paulo "dot1xAuthQuietPeriod=%u\n" 2752e28a4053SRui Paulo "dot1xAuthServerTimeout=%u\n" 2753e28a4053SRui Paulo "dot1xAuthReAuthPeriod=%u\n" 2754e28a4053SRui Paulo "dot1xAuthReAuthEnabled=%s\n" 2755e28a4053SRui Paulo "dot1xAuthKeyTxEnabled=%s\n", 2756e28a4053SRui Paulo sm->auth_pae_state + 1, 2757e28a4053SRui Paulo sm->be_auth_state + 1, 2758e28a4053SRui Paulo sm->adminControlledDirections, 2759e28a4053SRui Paulo sm->operControlledDirections, 2760e28a4053SRui Paulo sm->authPortStatus, 2761e28a4053SRui Paulo sm->portControl, 2762e28a4053SRui Paulo sm->quietPeriod, 2763e28a4053SRui Paulo sm->serverTimeout, 2764e28a4053SRui Paulo sm->reAuthPeriod, 2765e28a4053SRui Paulo bool_txt(sm->reAuthEnabled), 2766e28a4053SRui Paulo bool_txt(sm->keyTxEnabled)); 27675b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2768e28a4053SRui Paulo return len; 2769e28a4053SRui Paulo len += ret; 2770e28a4053SRui Paulo 2771e28a4053SRui Paulo /* dot1xAuthStatsTable */ 2772e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2773e28a4053SRui Paulo "dot1xAuthEapolFramesRx=%u\n" 2774e28a4053SRui Paulo "dot1xAuthEapolFramesTx=%u\n" 2775e28a4053SRui Paulo "dot1xAuthEapolStartFramesRx=%u\n" 2776e28a4053SRui Paulo "dot1xAuthEapolLogoffFramesRx=%u\n" 2777e28a4053SRui Paulo "dot1xAuthEapolRespIdFramesRx=%u\n" 2778e28a4053SRui Paulo "dot1xAuthEapolRespFramesRx=%u\n" 2779e28a4053SRui Paulo "dot1xAuthEapolReqIdFramesTx=%u\n" 2780e28a4053SRui Paulo "dot1xAuthEapolReqFramesTx=%u\n" 2781e28a4053SRui Paulo "dot1xAuthInvalidEapolFramesRx=%u\n" 2782e28a4053SRui Paulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 2783e28a4053SRui Paulo "dot1xAuthLastEapolFrameVersion=%u\n" 2784e28a4053SRui Paulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2785e28a4053SRui Paulo sm->dot1xAuthEapolFramesRx, 2786e28a4053SRui Paulo sm->dot1xAuthEapolFramesTx, 2787e28a4053SRui Paulo sm->dot1xAuthEapolStartFramesRx, 2788e28a4053SRui Paulo sm->dot1xAuthEapolLogoffFramesRx, 2789e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx, 2790e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx, 2791e28a4053SRui Paulo sm->dot1xAuthEapolReqIdFramesTx, 2792e28a4053SRui Paulo sm->dot1xAuthEapolReqFramesTx, 2793e28a4053SRui Paulo sm->dot1xAuthInvalidEapolFramesRx, 2794e28a4053SRui Paulo sm->dot1xAuthEapLengthErrorFramesRx, 2795e28a4053SRui Paulo sm->dot1xAuthLastEapolFrameVersion, 2796e28a4053SRui Paulo MAC2STR(sm->addr)); 27975b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2798e28a4053SRui Paulo return len; 2799e28a4053SRui Paulo len += ret; 2800e28a4053SRui Paulo 2801e28a4053SRui Paulo /* dot1xAuthDiagTable */ 2802e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2803e28a4053SRui Paulo "dot1xAuthEntersConnecting=%u\n" 2804e28a4053SRui Paulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2805e28a4053SRui Paulo "dot1xAuthEntersAuthenticating=%u\n" 2806e28a4053SRui Paulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2807e28a4053SRui Paulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2808e28a4053SRui Paulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2809e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2810e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2811e28a4053SRui Paulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2812e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2813e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2814e28a4053SRui Paulo "dot1xAuthBackendResponses=%u\n" 2815e28a4053SRui Paulo "dot1xAuthBackendAccessChallenges=%u\n" 2816e28a4053SRui Paulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2817e28a4053SRui Paulo "dot1xAuthBackendAuthSuccesses=%u\n" 2818e28a4053SRui Paulo "dot1xAuthBackendAuthFails=%u\n", 2819e28a4053SRui Paulo sm->authEntersConnecting, 2820e28a4053SRui Paulo sm->authEapLogoffsWhileConnecting, 2821e28a4053SRui Paulo sm->authEntersAuthenticating, 2822e28a4053SRui Paulo sm->authAuthSuccessesWhileAuthenticating, 2823e28a4053SRui Paulo sm->authAuthTimeoutsWhileAuthenticating, 2824e28a4053SRui Paulo sm->authAuthFailWhileAuthenticating, 2825e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticating, 2826e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticating, 2827e28a4053SRui Paulo sm->authAuthReauthsWhileAuthenticated, 2828e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticated, 2829e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticated, 2830e28a4053SRui Paulo sm->backendResponses, 2831e28a4053SRui Paulo sm->backendAccessChallenges, 2832e28a4053SRui Paulo sm->backendOtherRequestsToSupplicant, 2833e28a4053SRui Paulo sm->backendAuthSuccesses, 2834e28a4053SRui Paulo sm->backendAuthFails); 28355b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2836e28a4053SRui Paulo return len; 2837e28a4053SRui Paulo len += ret; 2838e28a4053SRui Paulo 2839e28a4053SRui Paulo /* dot1xAuthSessionStatsTable */ 28405b9c547cSRui Paulo os_reltime_age(&sta->acct_session_start, &diff); 28414bc52338SCy Schubert if (sm->eap && !sm->identity) { 28424bc52338SCy Schubert const u8 *id; 28434bc52338SCy Schubert size_t id_len; 28444bc52338SCy Schubert 28454bc52338SCy Schubert id = eap_get_identity(sm->eap, &id_len); 28464bc52338SCy Schubert if (id) 28474bc52338SCy Schubert identity_buf = dup_binstr(id, id_len); 28484bc52338SCy Schubert } 2849e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2850e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsRx */ 2851e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsTx */ 2852e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesRx */ 2853e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesTx */ 2854780fb4a2SCy Schubert "dot1xAuthSessionId=%016llX\n" 2855e28a4053SRui Paulo "dot1xAuthSessionAuthenticMethod=%d\n" 2856e28a4053SRui Paulo "dot1xAuthSessionTime=%u\n" 2857e28a4053SRui Paulo "dot1xAuthSessionTerminateCause=999\n" 2858e28a4053SRui Paulo "dot1xAuthSessionUserName=%s\n", 2859780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id, 2860e28a4053SRui Paulo (wpa_key_mgmt_wpa_ieee8021x( 2861e28a4053SRui Paulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2862e28a4053SRui Paulo 1 : 2, 28635b9c547cSRui Paulo (unsigned int) diff.sec, 28644bc52338SCy Schubert sm->identity ? (char *) sm->identity : 28654bc52338SCy Schubert (identity_buf ? identity_buf : "N/A")); 28664bc52338SCy Schubert os_free(identity_buf); 28675b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 28685b9c547cSRui Paulo return len; 28695b9c547cSRui Paulo len += ret; 28705b9c547cSRui Paulo 2871780fb4a2SCy Schubert if (sm->acct_multi_session_id) { 28725b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 2873780fb4a2SCy Schubert "authMultiSessionId=%016llX\n", 2874780fb4a2SCy Schubert (unsigned long long) 2875780fb4a2SCy Schubert sm->acct_multi_session_id); 28765b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 28775b9c547cSRui Paulo return len; 28785b9c547cSRui Paulo len += ret; 28795b9c547cSRui Paulo } 28805b9c547cSRui Paulo 28815b9c547cSRui Paulo name1 = eap_server_get_name(0, sm->eap_type_authsrv); 28825b9c547cSRui Paulo name2 = eap_server_get_name(0, sm->eap_type_supp); 28835b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 28845b9c547cSRui Paulo "last_eap_type_as=%d (%s)\n" 28855b9c547cSRui Paulo "last_eap_type_sta=%d (%s)\n", 28865b9c547cSRui Paulo sm->eap_type_authsrv, name1, 28875b9c547cSRui Paulo sm->eap_type_supp, name2); 28885b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2889e28a4053SRui Paulo return len; 2890e28a4053SRui Paulo len += ret; 2891e28a4053SRui Paulo 2892e28a4053SRui Paulo return len; 2893e28a4053SRui Paulo } 2894e28a4053SRui Paulo 2895e28a4053SRui Paulo 2896780fb4a2SCy Schubert #ifdef CONFIG_HS20 2897780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) 2898780fb4a2SCy Schubert { 2899780fb4a2SCy Schubert struct hostapd_data *hapd = eloop_ctx; 2900780fb4a2SCy Schubert struct sta_info *sta = timeout_ctx; 2901780fb4a2SCy Schubert 2902780fb4a2SCy Schubert if (sta->remediation) { 2903780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2904780fb4a2SCy Schubert MACSTR " to indicate Subscription Remediation", 2905780fb4a2SCy Schubert MAC2STR(sta->addr)); 2906780fb4a2SCy Schubert hs20_send_wnm_notification(hapd, sta->addr, 2907780fb4a2SCy Schubert sta->remediation_method, 2908780fb4a2SCy Schubert sta->remediation_url); 2909780fb4a2SCy Schubert os_free(sta->remediation_url); 2910780fb4a2SCy Schubert sta->remediation_url = NULL; 2911780fb4a2SCy Schubert } 2912780fb4a2SCy Schubert 2913780fb4a2SCy Schubert if (sta->hs20_deauth_req) { 2914780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2915780fb4a2SCy Schubert MACSTR " to indicate imminent deauthentication", 2916780fb4a2SCy Schubert MAC2STR(sta->addr)); 2917780fb4a2SCy Schubert hs20_send_wnm_notification_deauth_req(hapd, sta->addr, 2918780fb4a2SCy Schubert sta->hs20_deauth_req); 2919780fb4a2SCy Schubert } 292085732ac8SCy Schubert 292185732ac8SCy Schubert if (sta->hs20_t_c_filtering) { 292285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 292385732ac8SCy Schubert MACSTR " to indicate Terms and Conditions filtering", 292485732ac8SCy Schubert MAC2STR(sta->addr)); 292585732ac8SCy Schubert hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url); 292685732ac8SCy Schubert os_free(sta->t_c_url); 292785732ac8SCy Schubert sta->t_c_url = NULL; 292885732ac8SCy Schubert } 2929780fb4a2SCy Schubert } 2930780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 2931780fb4a2SCy Schubert 2932780fb4a2SCy Schubert 2933e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 29345b9c547cSRui Paulo struct sta_info *sta, int success, 29355b9c547cSRui Paulo int remediation) 2936e28a4053SRui Paulo { 2937e28a4053SRui Paulo const u8 *key; 2938e28a4053SRui Paulo size_t len; 2939e28a4053SRui Paulo /* TODO: get PMKLifetime from WPA parameters */ 2940e28a4053SRui Paulo static const int dot11RSNAConfigPMKLifetime = 43200; 29415b9c547cSRui Paulo unsigned int session_timeout; 294285732ac8SCy Schubert struct os_reltime now, remaining; 29435b9c547cSRui Paulo 29445b9c547cSRui Paulo #ifdef CONFIG_HS20 29455b9c547cSRui Paulo if (remediation && !sta->remediation) { 29465b9c547cSRui Paulo sta->remediation = 1; 29475b9c547cSRui Paulo os_free(sta->remediation_url); 29485b9c547cSRui Paulo sta->remediation_url = 29495b9c547cSRui Paulo os_strdup(hapd->conf->subscr_remediation_url); 29505b9c547cSRui Paulo sta->remediation_method = 1; /* SOAP-XML SPP */ 29515b9c547cSRui Paulo } 29525b9c547cSRui Paulo 295385732ac8SCy Schubert if (success && (sta->remediation || sta->hs20_deauth_req || 295485732ac8SCy Schubert sta->hs20_t_c_filtering)) { 2955780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to " 2956780fb4a2SCy Schubert MACSTR " in 100 ms", MAC2STR(sta->addr)); 2957780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 2958780fb4a2SCy Schubert eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send, 2959780fb4a2SCy Schubert hapd, sta); 29605b9c547cSRui Paulo } 29615b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 2962e28a4053SRui Paulo 2963*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 2964*206b73d0SCy Schubert ieee802_1x_notify_create_actor_hapd(hapd, sta); 2965*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 2966*206b73d0SCy Schubert 2967e28a4053SRui Paulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 296885732ac8SCy Schubert if (sta->session_timeout_set) { 296985732ac8SCy Schubert os_get_reltime(&now); 297085732ac8SCy Schubert os_reltime_sub(&sta->session_timeout, &now, &remaining); 297185732ac8SCy Schubert session_timeout = (remaining.sec > 0) ? remaining.sec : 1; 297285732ac8SCy Schubert } else { 29735b9c547cSRui Paulo session_timeout = dot11RSNAConfigPMKLifetime; 297485732ac8SCy Schubert } 29755b9c547cSRui Paulo if (success && key && len >= PMK_LEN && !sta->remediation && 29765b9c547cSRui Paulo !sta->hs20_deauth_requested && 2977780fb4a2SCy Schubert wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout, 2978e28a4053SRui Paulo sta->eapol_sm) == 0) { 2979e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2980e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 2981e28a4053SRui Paulo "Added PMKSA cache entry (IEEE 802.1X)"); 2982e28a4053SRui Paulo } 2983e28a4053SRui Paulo 2984f05cddf9SRui Paulo if (!success) { 2985e28a4053SRui Paulo /* 2986e28a4053SRui Paulo * Many devices require deauthentication after WPS provisioning 2987e28a4053SRui Paulo * and some may not be be able to do that themselves, so 2988f05cddf9SRui Paulo * disconnect the client here. In addition, this may also 2989f05cddf9SRui Paulo * benefit IEEE 802.1X/EAPOL authentication cases, too since 2990f05cddf9SRui Paulo * the EAPOL PAE state machine would remain in HELD state for 2991f05cddf9SRui Paulo * considerable amount of time and some EAP methods, like 2992f05cddf9SRui Paulo * EAP-FAST with anonymous provisioning, may require another 2993f05cddf9SRui Paulo * EAPOL authentication to be started to complete connection. 2994e28a4053SRui Paulo */ 299585732ac8SCy Schubert ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); 2996e28a4053SRui Paulo } 2997e28a4053SRui Paulo } 2998