1*3ff40c12SJohn Marino /* 2*3ff40c12SJohn Marino * hostapd / IEEE 802.1X-2004 Authenticator 3*3ff40c12SJohn Marino * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 4*3ff40c12SJohn Marino * 5*3ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license. 6*3ff40c12SJohn Marino * See README for more details. 7*3ff40c12SJohn Marino */ 8*3ff40c12SJohn Marino 9*3ff40c12SJohn Marino #include "utils/includes.h" 10*3ff40c12SJohn Marino 11*3ff40c12SJohn Marino #include "utils/common.h" 12*3ff40c12SJohn Marino #include "utils/eloop.h" 13*3ff40c12SJohn Marino #include "crypto/md5.h" 14*3ff40c12SJohn Marino #include "crypto/crypto.h" 15*3ff40c12SJohn Marino #include "crypto/random.h" 16*3ff40c12SJohn Marino #include "common/ieee802_11_defs.h" 17*3ff40c12SJohn Marino #include "radius/radius.h" 18*3ff40c12SJohn Marino #include "radius/radius_client.h" 19*3ff40c12SJohn Marino #include "eap_server/eap.h" 20*3ff40c12SJohn Marino #include "eap_common/eap_wsc_common.h" 21*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm.h" 22*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm_i.h" 23*3ff40c12SJohn Marino #include "p2p/p2p.h" 24*3ff40c12SJohn Marino #include "hostapd.h" 25*3ff40c12SJohn Marino #include "accounting.h" 26*3ff40c12SJohn Marino #include "sta_info.h" 27*3ff40c12SJohn Marino #include "wpa_auth.h" 28*3ff40c12SJohn Marino #include "preauth_auth.h" 29*3ff40c12SJohn Marino #include "pmksa_cache_auth.h" 30*3ff40c12SJohn Marino #include "ap_config.h" 31*3ff40c12SJohn Marino #include "ap_drv_ops.h" 32*3ff40c12SJohn Marino #include "wps_hostapd.h" 33*3ff40c12SJohn Marino #include "ieee802_1x.h" 34*3ff40c12SJohn Marino 35*3ff40c12SJohn Marino 36*3ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd, 37*3ff40c12SJohn Marino struct sta_info *sta, int success); 38*3ff40c12SJohn Marino 39*3ff40c12SJohn Marino 40*3ff40c12SJohn Marino static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 41*3ff40c12SJohn Marino u8 type, const u8 *data, size_t datalen) 42*3ff40c12SJohn Marino { 43*3ff40c12SJohn Marino u8 *buf; 44*3ff40c12SJohn Marino struct ieee802_1x_hdr *xhdr; 45*3ff40c12SJohn Marino size_t len; 46*3ff40c12SJohn Marino int encrypt = 0; 47*3ff40c12SJohn Marino 48*3ff40c12SJohn Marino len = sizeof(*xhdr) + datalen; 49*3ff40c12SJohn Marino buf = os_zalloc(len); 50*3ff40c12SJohn Marino if (buf == NULL) { 51*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "malloc() failed for " 52*3ff40c12SJohn Marino "ieee802_1x_send(len=%lu)", 53*3ff40c12SJohn Marino (unsigned long) len); 54*3ff40c12SJohn Marino return; 55*3ff40c12SJohn Marino } 56*3ff40c12SJohn Marino 57*3ff40c12SJohn Marino xhdr = (struct ieee802_1x_hdr *) buf; 58*3ff40c12SJohn Marino xhdr->version = hapd->conf->eapol_version; 59*3ff40c12SJohn Marino xhdr->type = type; 60*3ff40c12SJohn Marino xhdr->length = host_to_be16(datalen); 61*3ff40c12SJohn Marino 62*3ff40c12SJohn Marino if (datalen > 0 && data != NULL) 63*3ff40c12SJohn Marino os_memcpy(xhdr + 1, data, datalen); 64*3ff40c12SJohn Marino 65*3ff40c12SJohn Marino if (wpa_auth_pairwise_set(sta->wpa_sm)) 66*3ff40c12SJohn Marino encrypt = 1; 67*3ff40c12SJohn Marino if (sta->flags & WLAN_STA_PREAUTH) { 68*3ff40c12SJohn Marino rsn_preauth_send(hapd, sta, buf, len); 69*3ff40c12SJohn Marino } else { 70*3ff40c12SJohn Marino hostapd_drv_hapd_send_eapol( 71*3ff40c12SJohn Marino hapd, sta->addr, buf, len, 72*3ff40c12SJohn Marino encrypt, hostapd_sta_flags_to_drv(sta->flags)); 73*3ff40c12SJohn Marino } 74*3ff40c12SJohn Marino 75*3ff40c12SJohn Marino os_free(buf); 76*3ff40c12SJohn Marino } 77*3ff40c12SJohn Marino 78*3ff40c12SJohn Marino 79*3ff40c12SJohn Marino void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 80*3ff40c12SJohn Marino struct sta_info *sta, int authorized) 81*3ff40c12SJohn Marino { 82*3ff40c12SJohn Marino int res; 83*3ff40c12SJohn Marino 84*3ff40c12SJohn Marino if (sta->flags & WLAN_STA_PREAUTH) 85*3ff40c12SJohn Marino return; 86*3ff40c12SJohn Marino 87*3ff40c12SJohn Marino if (authorized) { 88*3ff40c12SJohn Marino ap_sta_set_authorized(hapd, sta, 1); 89*3ff40c12SJohn Marino res = hostapd_set_authorized(hapd, sta, 1); 90*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 91*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "authorizing port"); 92*3ff40c12SJohn Marino } else { 93*3ff40c12SJohn Marino ap_sta_set_authorized(hapd, sta, 0); 94*3ff40c12SJohn Marino res = hostapd_set_authorized(hapd, sta, 0); 95*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 96*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 97*3ff40c12SJohn Marino } 98*3ff40c12SJohn Marino 99*3ff40c12SJohn Marino if (res && errno != ENOENT) { 100*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 101*3ff40c12SJohn Marino " flags for kernel driver (errno=%d).", 102*3ff40c12SJohn Marino MAC2STR(sta->addr), errno); 103*3ff40c12SJohn Marino } 104*3ff40c12SJohn Marino 105*3ff40c12SJohn Marino if (authorized) { 106*3ff40c12SJohn Marino os_get_reltime(&sta->connected_time); 107*3ff40c12SJohn Marino accounting_sta_start(hapd, sta); 108*3ff40c12SJohn Marino } 109*3ff40c12SJohn Marino } 110*3ff40c12SJohn Marino 111*3ff40c12SJohn Marino 112*3ff40c12SJohn Marino static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 113*3ff40c12SJohn Marino struct sta_info *sta, 114*3ff40c12SJohn Marino int idx, int broadcast, 115*3ff40c12SJohn Marino u8 *key_data, size_t key_len) 116*3ff40c12SJohn Marino { 117*3ff40c12SJohn Marino u8 *buf, *ekey; 118*3ff40c12SJohn Marino struct ieee802_1x_hdr *hdr; 119*3ff40c12SJohn Marino struct ieee802_1x_eapol_key *key; 120*3ff40c12SJohn Marino size_t len, ekey_len; 121*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 122*3ff40c12SJohn Marino 123*3ff40c12SJohn Marino if (sm == NULL) 124*3ff40c12SJohn Marino return; 125*3ff40c12SJohn Marino 126*3ff40c12SJohn Marino len = sizeof(*key) + key_len; 127*3ff40c12SJohn Marino buf = os_zalloc(sizeof(*hdr) + len); 128*3ff40c12SJohn Marino if (buf == NULL) 129*3ff40c12SJohn Marino return; 130*3ff40c12SJohn Marino 131*3ff40c12SJohn Marino hdr = (struct ieee802_1x_hdr *) buf; 132*3ff40c12SJohn Marino key = (struct ieee802_1x_eapol_key *) (hdr + 1); 133*3ff40c12SJohn Marino key->type = EAPOL_KEY_TYPE_RC4; 134*3ff40c12SJohn Marino WPA_PUT_BE16(key->key_length, key_len); 135*3ff40c12SJohn Marino wpa_get_ntp_timestamp(key->replay_counter); 136*3ff40c12SJohn Marino 137*3ff40c12SJohn Marino if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 138*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not get random numbers"); 139*3ff40c12SJohn Marino os_free(buf); 140*3ff40c12SJohn Marino return; 141*3ff40c12SJohn Marino } 142*3ff40c12SJohn Marino 143*3ff40c12SJohn Marino key->key_index = idx | (broadcast ? 0 : BIT(7)); 144*3ff40c12SJohn Marino if (hapd->conf->eapol_key_index_workaround) { 145*3ff40c12SJohn Marino /* According to some information, WinXP Supplicant seems to 146*3ff40c12SJohn Marino * interpret bit7 as an indication whether the key is to be 147*3ff40c12SJohn Marino * activated, so make it possible to enable workaround that 148*3ff40c12SJohn Marino * sets this bit for all keys. */ 149*3ff40c12SJohn Marino key->key_index |= BIT(7); 150*3ff40c12SJohn Marino } 151*3ff40c12SJohn Marino 152*3ff40c12SJohn Marino /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 153*3ff40c12SJohn Marino * MSK[32..63] is used to sign the message. */ 154*3ff40c12SJohn Marino if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 155*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 156*3ff40c12SJohn Marino "and signing EAPOL-Key"); 157*3ff40c12SJohn Marino os_free(buf); 158*3ff40c12SJohn Marino return; 159*3ff40c12SJohn Marino } 160*3ff40c12SJohn Marino os_memcpy((u8 *) (key + 1), key_data, key_len); 161*3ff40c12SJohn Marino ekey_len = sizeof(key->key_iv) + 32; 162*3ff40c12SJohn Marino ekey = os_malloc(ekey_len); 163*3ff40c12SJohn Marino if (ekey == NULL) { 164*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not encrypt key"); 165*3ff40c12SJohn Marino os_free(buf); 166*3ff40c12SJohn Marino return; 167*3ff40c12SJohn Marino } 168*3ff40c12SJohn Marino os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 169*3ff40c12SJohn Marino os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 170*3ff40c12SJohn Marino rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 171*3ff40c12SJohn Marino os_free(ekey); 172*3ff40c12SJohn Marino 173*3ff40c12SJohn Marino /* This header is needed here for HMAC-MD5, but it will be regenerated 174*3ff40c12SJohn Marino * in ieee802_1x_send() */ 175*3ff40c12SJohn Marino hdr->version = hapd->conf->eapol_version; 176*3ff40c12SJohn Marino hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 177*3ff40c12SJohn Marino hdr->length = host_to_be16(len); 178*3ff40c12SJohn Marino hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 179*3ff40c12SJohn Marino key->key_signature); 180*3ff40c12SJohn Marino 181*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 182*3ff40c12SJohn Marino " (%s index=%d)", MAC2STR(sm->addr), 183*3ff40c12SJohn Marino broadcast ? "broadcast" : "unicast", idx); 184*3ff40c12SJohn Marino ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 185*3ff40c12SJohn Marino if (sta->eapol_sm) 186*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthEapolFramesTx++; 187*3ff40c12SJohn Marino os_free(buf); 188*3ff40c12SJohn Marino } 189*3ff40c12SJohn Marino 190*3ff40c12SJohn Marino 191*3ff40c12SJohn Marino void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 192*3ff40c12SJohn Marino { 193*3ff40c12SJohn Marino struct eapol_authenticator *eapol = hapd->eapol_auth; 194*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 195*3ff40c12SJohn Marino 196*3ff40c12SJohn Marino if (sm == NULL || !sm->eap_if->eapKeyData) 197*3ff40c12SJohn Marino return; 198*3ff40c12SJohn Marino 199*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 200*3ff40c12SJohn Marino MAC2STR(sta->addr)); 201*3ff40c12SJohn Marino 202*3ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN 203*3ff40c12SJohn Marino if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) { 204*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 205*3ff40c12SJohn Marino return; 206*3ff40c12SJohn Marino } 207*3ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */ 208*3ff40c12SJohn Marino 209*3ff40c12SJohn Marino if (eapol->default_wep_key) { 210*3ff40c12SJohn Marino ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 211*3ff40c12SJohn Marino eapol->default_wep_key, 212*3ff40c12SJohn Marino hapd->conf->default_wep_key_len); 213*3ff40c12SJohn Marino } 214*3ff40c12SJohn Marino 215*3ff40c12SJohn Marino if (hapd->conf->individual_wep_key_len > 0) { 216*3ff40c12SJohn Marino u8 *ikey; 217*3ff40c12SJohn Marino ikey = os_malloc(hapd->conf->individual_wep_key_len); 218*3ff40c12SJohn Marino if (ikey == NULL || 219*3ff40c12SJohn Marino random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 220*3ff40c12SJohn Marino { 221*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not generate random " 222*3ff40c12SJohn Marino "individual WEP key."); 223*3ff40c12SJohn Marino os_free(ikey); 224*3ff40c12SJohn Marino return; 225*3ff40c12SJohn Marino } 226*3ff40c12SJohn Marino 227*3ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 228*3ff40c12SJohn Marino ikey, hapd->conf->individual_wep_key_len); 229*3ff40c12SJohn Marino 230*3ff40c12SJohn Marino ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 231*3ff40c12SJohn Marino hapd->conf->individual_wep_key_len); 232*3ff40c12SJohn Marino 233*3ff40c12SJohn Marino /* TODO: set encryption in TX callback, i.e., only after STA 234*3ff40c12SJohn Marino * has ACKed EAPOL-Key frame */ 235*3ff40c12SJohn Marino if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 236*3ff40c12SJohn Marino sta->addr, 0, 1, NULL, 0, ikey, 237*3ff40c12SJohn Marino hapd->conf->individual_wep_key_len)) { 238*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set individual WEP " 239*3ff40c12SJohn Marino "encryption."); 240*3ff40c12SJohn Marino } 241*3ff40c12SJohn Marino 242*3ff40c12SJohn Marino os_free(ikey); 243*3ff40c12SJohn Marino } 244*3ff40c12SJohn Marino } 245*3ff40c12SJohn Marino 246*3ff40c12SJohn Marino 247*3ff40c12SJohn Marino const char *radius_mode_txt(struct hostapd_data *hapd) 248*3ff40c12SJohn Marino { 249*3ff40c12SJohn Marino switch (hapd->iface->conf->hw_mode) { 250*3ff40c12SJohn Marino case HOSTAPD_MODE_IEEE80211AD: 251*3ff40c12SJohn Marino return "802.11ad"; 252*3ff40c12SJohn Marino case HOSTAPD_MODE_IEEE80211A: 253*3ff40c12SJohn Marino return "802.11a"; 254*3ff40c12SJohn Marino case HOSTAPD_MODE_IEEE80211G: 255*3ff40c12SJohn Marino return "802.11g"; 256*3ff40c12SJohn Marino case HOSTAPD_MODE_IEEE80211B: 257*3ff40c12SJohn Marino default: 258*3ff40c12SJohn Marino return "802.11b"; 259*3ff40c12SJohn Marino } 260*3ff40c12SJohn Marino } 261*3ff40c12SJohn Marino 262*3ff40c12SJohn Marino 263*3ff40c12SJohn Marino int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 264*3ff40c12SJohn Marino { 265*3ff40c12SJohn Marino int i; 266*3ff40c12SJohn Marino u8 rate = 0; 267*3ff40c12SJohn Marino 268*3ff40c12SJohn Marino for (i = 0; i < sta->supported_rates_len; i++) 269*3ff40c12SJohn Marino if ((sta->supported_rates[i] & 0x7f) > rate) 270*3ff40c12SJohn Marino rate = sta->supported_rates[i] & 0x7f; 271*3ff40c12SJohn Marino 272*3ff40c12SJohn Marino return rate; 273*3ff40c12SJohn Marino } 274*3ff40c12SJohn Marino 275*3ff40c12SJohn Marino 276*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 277*3ff40c12SJohn Marino static void ieee802_1x_learn_identity(struct hostapd_data *hapd, 278*3ff40c12SJohn Marino struct eapol_state_machine *sm, 279*3ff40c12SJohn Marino const u8 *eap, size_t len) 280*3ff40c12SJohn Marino { 281*3ff40c12SJohn Marino const u8 *identity; 282*3ff40c12SJohn Marino size_t identity_len; 283*3ff40c12SJohn Marino 284*3ff40c12SJohn Marino if (len <= sizeof(struct eap_hdr) || 285*3ff40c12SJohn Marino eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) 286*3ff40c12SJohn Marino return; 287*3ff40c12SJohn Marino 288*3ff40c12SJohn Marino identity = eap_get_identity(sm->eap, &identity_len); 289*3ff40c12SJohn Marino if (identity == NULL) 290*3ff40c12SJohn Marino return; 291*3ff40c12SJohn Marino 292*3ff40c12SJohn Marino /* Save station identity for future RADIUS packets */ 293*3ff40c12SJohn Marino os_free(sm->identity); 294*3ff40c12SJohn Marino sm->identity = (u8 *) dup_binstr(identity, identity_len); 295*3ff40c12SJohn Marino if (sm->identity == NULL) { 296*3ff40c12SJohn Marino sm->identity_len = 0; 297*3ff40c12SJohn Marino return; 298*3ff40c12SJohn Marino } 299*3ff40c12SJohn Marino 300*3ff40c12SJohn Marino sm->identity_len = identity_len; 301*3ff40c12SJohn Marino hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 302*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 303*3ff40c12SJohn Marino sm->dot1xAuthEapolRespIdFramesRx++; 304*3ff40c12SJohn Marino } 305*3ff40c12SJohn Marino 306*3ff40c12SJohn Marino 307*3ff40c12SJohn Marino static int add_common_radius_sta_attr(struct hostapd_data *hapd, 308*3ff40c12SJohn Marino struct hostapd_radius_attr *req_attr, 309*3ff40c12SJohn Marino struct sta_info *sta, 310*3ff40c12SJohn Marino struct radius_msg *msg) 311*3ff40c12SJohn Marino { 312*3ff40c12SJohn Marino char buf[128]; 313*3ff40c12SJohn Marino 314*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 315*3ff40c12SJohn Marino RADIUS_ATTR_NAS_PORT) && 316*3ff40c12SJohn Marino !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 317*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 318*3ff40c12SJohn Marino return -1; 319*3ff40c12SJohn Marino } 320*3ff40c12SJohn Marino 321*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 322*3ff40c12SJohn Marino MAC2STR(sta->addr)); 323*3ff40c12SJohn Marino buf[sizeof(buf) - 1] = '\0'; 324*3ff40c12SJohn Marino if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 325*3ff40c12SJohn Marino (u8 *) buf, os_strlen(buf))) { 326*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 327*3ff40c12SJohn Marino return -1; 328*3ff40c12SJohn Marino } 329*3ff40c12SJohn Marino 330*3ff40c12SJohn Marino if (sta->flags & WLAN_STA_PREAUTH) { 331*3ff40c12SJohn Marino os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 332*3ff40c12SJohn Marino sizeof(buf)); 333*3ff40c12SJohn Marino } else { 334*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 335*3ff40c12SJohn Marino radius_sta_rate(hapd, sta) / 2, 336*3ff40c12SJohn Marino (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 337*3ff40c12SJohn Marino radius_mode_txt(hapd)); 338*3ff40c12SJohn Marino buf[sizeof(buf) - 1] = '\0'; 339*3ff40c12SJohn Marino } 340*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 341*3ff40c12SJohn Marino RADIUS_ATTR_CONNECT_INFO) && 342*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 343*3ff40c12SJohn Marino (u8 *) buf, os_strlen(buf))) { 344*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 345*3ff40c12SJohn Marino return -1; 346*3ff40c12SJohn Marino } 347*3ff40c12SJohn Marino 348*3ff40c12SJohn Marino if (sta->acct_session_id_hi || sta->acct_session_id_lo) { 349*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), "%08X-%08X", 350*3ff40c12SJohn Marino sta->acct_session_id_hi, sta->acct_session_id_lo); 351*3ff40c12SJohn Marino if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 352*3ff40c12SJohn Marino (u8 *) buf, os_strlen(buf))) { 353*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 354*3ff40c12SJohn Marino return -1; 355*3ff40c12SJohn Marino } 356*3ff40c12SJohn Marino } 357*3ff40c12SJohn Marino 358*3ff40c12SJohn Marino return 0; 359*3ff40c12SJohn Marino } 360*3ff40c12SJohn Marino 361*3ff40c12SJohn Marino 362*3ff40c12SJohn Marino int add_common_radius_attr(struct hostapd_data *hapd, 363*3ff40c12SJohn Marino struct hostapd_radius_attr *req_attr, 364*3ff40c12SJohn Marino struct sta_info *sta, 365*3ff40c12SJohn Marino struct radius_msg *msg) 366*3ff40c12SJohn Marino { 367*3ff40c12SJohn Marino char buf[128]; 368*3ff40c12SJohn Marino struct hostapd_radius_attr *attr; 369*3ff40c12SJohn Marino 370*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 371*3ff40c12SJohn Marino RADIUS_ATTR_NAS_IP_ADDRESS) && 372*3ff40c12SJohn Marino hapd->conf->own_ip_addr.af == AF_INET && 373*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 374*3ff40c12SJohn Marino (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 375*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 376*3ff40c12SJohn Marino return -1; 377*3ff40c12SJohn Marino } 378*3ff40c12SJohn Marino 379*3ff40c12SJohn Marino #ifdef CONFIG_IPV6 380*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 381*3ff40c12SJohn Marino RADIUS_ATTR_NAS_IPV6_ADDRESS) && 382*3ff40c12SJohn Marino hapd->conf->own_ip_addr.af == AF_INET6 && 383*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 384*3ff40c12SJohn Marino (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 385*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 386*3ff40c12SJohn Marino return -1; 387*3ff40c12SJohn Marino } 388*3ff40c12SJohn Marino #endif /* CONFIG_IPV6 */ 389*3ff40c12SJohn Marino 390*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 391*3ff40c12SJohn Marino RADIUS_ATTR_NAS_IDENTIFIER) && 392*3ff40c12SJohn Marino hapd->conf->nas_identifier && 393*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 394*3ff40c12SJohn Marino (u8 *) hapd->conf->nas_identifier, 395*3ff40c12SJohn Marino os_strlen(hapd->conf->nas_identifier))) { 396*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 397*3ff40c12SJohn Marino return -1; 398*3ff40c12SJohn Marino } 399*3ff40c12SJohn Marino 400*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", 401*3ff40c12SJohn Marino MAC2STR(hapd->own_addr), 402*3ff40c12SJohn Marino wpa_ssid_txt(hapd->conf->ssid.ssid, 403*3ff40c12SJohn Marino hapd->conf->ssid.ssid_len)); 404*3ff40c12SJohn Marino buf[sizeof(buf) - 1] = '\0'; 405*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 406*3ff40c12SJohn Marino RADIUS_ATTR_CALLED_STATION_ID) && 407*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 408*3ff40c12SJohn Marino (u8 *) buf, os_strlen(buf))) { 409*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 410*3ff40c12SJohn Marino return -1; 411*3ff40c12SJohn Marino } 412*3ff40c12SJohn Marino 413*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(req_attr, 414*3ff40c12SJohn Marino RADIUS_ATTR_NAS_PORT_TYPE) && 415*3ff40c12SJohn Marino !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 416*3ff40c12SJohn Marino RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 417*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 418*3ff40c12SJohn Marino return -1; 419*3ff40c12SJohn Marino } 420*3ff40c12SJohn Marino 421*3ff40c12SJohn Marino if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 422*3ff40c12SJohn Marino return -1; 423*3ff40c12SJohn Marino 424*3ff40c12SJohn Marino for (attr = req_attr; attr; attr = attr->next) { 425*3ff40c12SJohn Marino if (!radius_msg_add_attr(msg, attr->type, 426*3ff40c12SJohn Marino wpabuf_head(attr->val), 427*3ff40c12SJohn Marino wpabuf_len(attr->val))) { 428*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add RADIUS " 429*3ff40c12SJohn Marino "attribute"); 430*3ff40c12SJohn Marino return -1; 431*3ff40c12SJohn Marino } 432*3ff40c12SJohn Marino } 433*3ff40c12SJohn Marino 434*3ff40c12SJohn Marino return 0; 435*3ff40c12SJohn Marino } 436*3ff40c12SJohn Marino 437*3ff40c12SJohn Marino 438*3ff40c12SJohn Marino static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 439*3ff40c12SJohn Marino struct sta_info *sta, 440*3ff40c12SJohn Marino const u8 *eap, size_t len) 441*3ff40c12SJohn Marino { 442*3ff40c12SJohn Marino struct radius_msg *msg; 443*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 444*3ff40c12SJohn Marino 445*3ff40c12SJohn Marino if (sm == NULL) 446*3ff40c12SJohn Marino return; 447*3ff40c12SJohn Marino 448*3ff40c12SJohn Marino ieee802_1x_learn_identity(hapd, sm, eap, len); 449*3ff40c12SJohn Marino 450*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 451*3ff40c12SJohn Marino "packet"); 452*3ff40c12SJohn Marino 453*3ff40c12SJohn Marino sm->radius_identifier = radius_client_get_id(hapd->radius); 454*3ff40c12SJohn Marino msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 455*3ff40c12SJohn Marino sm->radius_identifier); 456*3ff40c12SJohn Marino if (msg == NULL) { 457*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 458*3ff40c12SJohn Marino return; 459*3ff40c12SJohn Marino } 460*3ff40c12SJohn Marino 461*3ff40c12SJohn Marino radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); 462*3ff40c12SJohn Marino 463*3ff40c12SJohn Marino if (sm->identity && 464*3ff40c12SJohn Marino !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 465*3ff40c12SJohn Marino sm->identity, sm->identity_len)) { 466*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not add User-Name"); 467*3ff40c12SJohn Marino goto fail; 468*3ff40c12SJohn Marino } 469*3ff40c12SJohn Marino 470*3ff40c12SJohn Marino if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 471*3ff40c12SJohn Marino msg) < 0) 472*3ff40c12SJohn Marino goto fail; 473*3ff40c12SJohn Marino 474*3ff40c12SJohn Marino /* TODO: should probably check MTU from driver config; 2304 is max for 475*3ff40c12SJohn Marino * IEEE 802.11, but use 1400 to avoid problems with too large packets 476*3ff40c12SJohn Marino */ 477*3ff40c12SJohn Marino if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 478*3ff40c12SJohn Marino RADIUS_ATTR_FRAMED_MTU) && 479*3ff40c12SJohn Marino !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 480*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 481*3ff40c12SJohn Marino goto fail; 482*3ff40c12SJohn Marino } 483*3ff40c12SJohn Marino 484*3ff40c12SJohn Marino if (eap && !radius_msg_add_eap(msg, eap, len)) { 485*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not add EAP-Message"); 486*3ff40c12SJohn Marino goto fail; 487*3ff40c12SJohn Marino } 488*3ff40c12SJohn Marino 489*3ff40c12SJohn Marino /* State attribute must be copied if and only if this packet is 490*3ff40c12SJohn Marino * Access-Request reply to the previous Access-Challenge */ 491*3ff40c12SJohn Marino if (sm->last_recv_radius && 492*3ff40c12SJohn Marino radius_msg_get_hdr(sm->last_recv_radius)->code == 493*3ff40c12SJohn Marino RADIUS_CODE_ACCESS_CHALLENGE) { 494*3ff40c12SJohn Marino int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 495*3ff40c12SJohn Marino RADIUS_ATTR_STATE); 496*3ff40c12SJohn Marino if (res < 0) { 497*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); 498*3ff40c12SJohn Marino goto fail; 499*3ff40c12SJohn Marino } 500*3ff40c12SJohn Marino if (res > 0) { 501*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 502*3ff40c12SJohn Marino } 503*3ff40c12SJohn Marino } 504*3ff40c12SJohn Marino 505*3ff40c12SJohn Marino if (hapd->conf->radius_request_cui) { 506*3ff40c12SJohn Marino const u8 *cui; 507*3ff40c12SJohn Marino size_t cui_len; 508*3ff40c12SJohn Marino /* Add previously learned CUI or nul CUI to request CUI */ 509*3ff40c12SJohn Marino if (sm->radius_cui) { 510*3ff40c12SJohn Marino cui = wpabuf_head(sm->radius_cui); 511*3ff40c12SJohn Marino cui_len = wpabuf_len(sm->radius_cui); 512*3ff40c12SJohn Marino } else { 513*3ff40c12SJohn Marino cui = (const u8 *) "\0"; 514*3ff40c12SJohn Marino cui_len = 1; 515*3ff40c12SJohn Marino } 516*3ff40c12SJohn Marino if (!radius_msg_add_attr(msg, 517*3ff40c12SJohn Marino RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 518*3ff40c12SJohn Marino cui, cui_len)) { 519*3ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not add CUI"); 520*3ff40c12SJohn Marino goto fail; 521*3ff40c12SJohn Marino } 522*3ff40c12SJohn Marino } 523*3ff40c12SJohn Marino 524*3ff40c12SJohn Marino if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 525*3ff40c12SJohn Marino goto fail; 526*3ff40c12SJohn Marino 527*3ff40c12SJohn Marino return; 528*3ff40c12SJohn Marino 529*3ff40c12SJohn Marino fail: 530*3ff40c12SJohn Marino radius_msg_free(msg); 531*3ff40c12SJohn Marino } 532*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 533*3ff40c12SJohn Marino 534*3ff40c12SJohn Marino 535*3ff40c12SJohn Marino static void handle_eap_response(struct hostapd_data *hapd, 536*3ff40c12SJohn Marino struct sta_info *sta, struct eap_hdr *eap, 537*3ff40c12SJohn Marino size_t len) 538*3ff40c12SJohn Marino { 539*3ff40c12SJohn Marino u8 type, *data; 540*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 541*3ff40c12SJohn Marino if (sm == NULL) 542*3ff40c12SJohn Marino return; 543*3ff40c12SJohn Marino 544*3ff40c12SJohn Marino data = (u8 *) (eap + 1); 545*3ff40c12SJohn Marino 546*3ff40c12SJohn Marino if (len < sizeof(*eap) + 1) { 547*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); 548*3ff40c12SJohn Marino return; 549*3ff40c12SJohn Marino } 550*3ff40c12SJohn Marino 551*3ff40c12SJohn Marino sm->eap_type_supp = type = data[0]; 552*3ff40c12SJohn Marino 553*3ff40c12SJohn Marino hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 554*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 555*3ff40c12SJohn Marino "id=%d len=%d) from STA: EAP Response-%s (%d)", 556*3ff40c12SJohn Marino eap->code, eap->identifier, be_to_host16(eap->length), 557*3ff40c12SJohn Marino eap_server_get_name(0, type), type); 558*3ff40c12SJohn Marino 559*3ff40c12SJohn Marino sm->dot1xAuthEapolRespFramesRx++; 560*3ff40c12SJohn Marino 561*3ff40c12SJohn Marino wpabuf_free(sm->eap_if->eapRespData); 562*3ff40c12SJohn Marino sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 563*3ff40c12SJohn Marino sm->eapolEap = TRUE; 564*3ff40c12SJohn Marino } 565*3ff40c12SJohn Marino 566*3ff40c12SJohn Marino 567*3ff40c12SJohn Marino /* Process incoming EAP packet from Supplicant */ 568*3ff40c12SJohn Marino static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 569*3ff40c12SJohn Marino u8 *buf, size_t len) 570*3ff40c12SJohn Marino { 571*3ff40c12SJohn Marino struct eap_hdr *eap; 572*3ff40c12SJohn Marino u16 eap_len; 573*3ff40c12SJohn Marino 574*3ff40c12SJohn Marino if (len < sizeof(*eap)) { 575*3ff40c12SJohn Marino wpa_printf(MSG_INFO, " too short EAP packet"); 576*3ff40c12SJohn Marino return; 577*3ff40c12SJohn Marino } 578*3ff40c12SJohn Marino 579*3ff40c12SJohn Marino eap = (struct eap_hdr *) buf; 580*3ff40c12SJohn Marino 581*3ff40c12SJohn Marino eap_len = be_to_host16(eap->length); 582*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 583*3ff40c12SJohn Marino eap->code, eap->identifier, eap_len); 584*3ff40c12SJohn Marino if (eap_len < sizeof(*eap)) { 585*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " Invalid EAP length"); 586*3ff40c12SJohn Marino return; 587*3ff40c12SJohn Marino } else if (eap_len > len) { 588*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 589*3ff40c12SJohn Marino "packet"); 590*3ff40c12SJohn Marino return; 591*3ff40c12SJohn Marino } else if (eap_len < len) { 592*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 593*3ff40c12SJohn Marino "packet", (unsigned long) len - eap_len); 594*3ff40c12SJohn Marino } 595*3ff40c12SJohn Marino 596*3ff40c12SJohn Marino switch (eap->code) { 597*3ff40c12SJohn Marino case EAP_CODE_REQUEST: 598*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " (request)"); 599*3ff40c12SJohn Marino return; 600*3ff40c12SJohn Marino case EAP_CODE_RESPONSE: 601*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " (response)"); 602*3ff40c12SJohn Marino handle_eap_response(hapd, sta, eap, eap_len); 603*3ff40c12SJohn Marino break; 604*3ff40c12SJohn Marino case EAP_CODE_SUCCESS: 605*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " (success)"); 606*3ff40c12SJohn Marino return; 607*3ff40c12SJohn Marino case EAP_CODE_FAILURE: 608*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " (failure)"); 609*3ff40c12SJohn Marino return; 610*3ff40c12SJohn Marino default: 611*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " (unknown code)"); 612*3ff40c12SJohn Marino return; 613*3ff40c12SJohn Marino } 614*3ff40c12SJohn Marino } 615*3ff40c12SJohn Marino 616*3ff40c12SJohn Marino 617*3ff40c12SJohn Marino static struct eapol_state_machine * 618*3ff40c12SJohn Marino ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 619*3ff40c12SJohn Marino { 620*3ff40c12SJohn Marino int flags = 0; 621*3ff40c12SJohn Marino if (sta->flags & WLAN_STA_PREAUTH) 622*3ff40c12SJohn Marino flags |= EAPOL_SM_PREAUTH; 623*3ff40c12SJohn Marino if (sta->wpa_sm) { 624*3ff40c12SJohn Marino flags |= EAPOL_SM_USES_WPA; 625*3ff40c12SJohn Marino if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 626*3ff40c12SJohn Marino flags |= EAPOL_SM_FROM_PMKSA_CACHE; 627*3ff40c12SJohn Marino } 628*3ff40c12SJohn Marino return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 629*3ff40c12SJohn Marino sta->wps_ie, sta->p2p_ie, sta, 630*3ff40c12SJohn Marino sta->identity, sta->radius_cui); 631*3ff40c12SJohn Marino } 632*3ff40c12SJohn Marino 633*3ff40c12SJohn Marino 634*3ff40c12SJohn Marino /** 635*3ff40c12SJohn Marino * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 636*3ff40c12SJohn Marino * @hapd: hostapd BSS data 637*3ff40c12SJohn Marino * @sa: Source address (sender of the EAPOL frame) 638*3ff40c12SJohn Marino * @buf: EAPOL frame 639*3ff40c12SJohn Marino * @len: Length of buf in octets 640*3ff40c12SJohn Marino * 641*3ff40c12SJohn Marino * This function is called for each incoming EAPOL frame from the interface 642*3ff40c12SJohn Marino */ 643*3ff40c12SJohn Marino void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 644*3ff40c12SJohn Marino size_t len) 645*3ff40c12SJohn Marino { 646*3ff40c12SJohn Marino struct sta_info *sta; 647*3ff40c12SJohn Marino struct ieee802_1x_hdr *hdr; 648*3ff40c12SJohn Marino struct ieee802_1x_eapol_key *key; 649*3ff40c12SJohn Marino u16 datalen; 650*3ff40c12SJohn Marino struct rsn_pmksa_cache_entry *pmksa; 651*3ff40c12SJohn Marino int key_mgmt; 652*3ff40c12SJohn Marino 653*3ff40c12SJohn Marino if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && 654*3ff40c12SJohn Marino !hapd->conf->wps_state) 655*3ff40c12SJohn Marino return; 656*3ff40c12SJohn Marino 657*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 658*3ff40c12SJohn Marino (unsigned long) len, MAC2STR(sa)); 659*3ff40c12SJohn Marino sta = ap_get_sta(hapd, sa); 660*3ff40c12SJohn Marino if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 661*3ff40c12SJohn Marino !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 662*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 663*3ff40c12SJohn Marino "associated/Pre-authenticating STA"); 664*3ff40c12SJohn Marino return; 665*3ff40c12SJohn Marino } 666*3ff40c12SJohn Marino 667*3ff40c12SJohn Marino if (len < sizeof(*hdr)) { 668*3ff40c12SJohn Marino wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 669*3ff40c12SJohn Marino return; 670*3ff40c12SJohn Marino } 671*3ff40c12SJohn Marino 672*3ff40c12SJohn Marino hdr = (struct ieee802_1x_hdr *) buf; 673*3ff40c12SJohn Marino datalen = be_to_host16(hdr->length); 674*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 675*3ff40c12SJohn Marino hdr->version, hdr->type, datalen); 676*3ff40c12SJohn Marino 677*3ff40c12SJohn Marino if (len - sizeof(*hdr) < datalen) { 678*3ff40c12SJohn Marino wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); 679*3ff40c12SJohn Marino if (sta->eapol_sm) 680*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 681*3ff40c12SJohn Marino return; 682*3ff40c12SJohn Marino } 683*3ff40c12SJohn Marino if (len - sizeof(*hdr) > datalen) { 684*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 685*3ff40c12SJohn Marino "IEEE 802.1X packet", 686*3ff40c12SJohn Marino (unsigned long) len - sizeof(*hdr) - datalen); 687*3ff40c12SJohn Marino } 688*3ff40c12SJohn Marino 689*3ff40c12SJohn Marino if (sta->eapol_sm) { 690*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 691*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthEapolFramesRx++; 692*3ff40c12SJohn Marino } 693*3ff40c12SJohn Marino 694*3ff40c12SJohn Marino key = (struct ieee802_1x_eapol_key *) (hdr + 1); 695*3ff40c12SJohn Marino if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 696*3ff40c12SJohn Marino hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 697*3ff40c12SJohn Marino (key->type == EAPOL_KEY_TYPE_WPA || 698*3ff40c12SJohn Marino key->type == EAPOL_KEY_TYPE_RSN)) { 699*3ff40c12SJohn Marino wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 700*3ff40c12SJohn Marino sizeof(*hdr) + datalen); 701*3ff40c12SJohn Marino return; 702*3ff40c12SJohn Marino } 703*3ff40c12SJohn Marino 704*3ff40c12SJohn Marino if (!hapd->conf->ieee802_1x && 705*3ff40c12SJohn Marino !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 706*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 707*3ff40c12SJohn Marino "802.1X not enabled and WPS not used"); 708*3ff40c12SJohn Marino return; 709*3ff40c12SJohn Marino } 710*3ff40c12SJohn Marino 711*3ff40c12SJohn Marino key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 712*3ff40c12SJohn Marino if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { 713*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 714*3ff40c12SJohn Marino "STA is using PSK"); 715*3ff40c12SJohn Marino return; 716*3ff40c12SJohn Marino } 717*3ff40c12SJohn Marino 718*3ff40c12SJohn Marino if (!sta->eapol_sm) { 719*3ff40c12SJohn Marino sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 720*3ff40c12SJohn Marino if (!sta->eapol_sm) 721*3ff40c12SJohn Marino return; 722*3ff40c12SJohn Marino 723*3ff40c12SJohn Marino #ifdef CONFIG_WPS 724*3ff40c12SJohn Marino if (!hapd->conf->ieee802_1x) { 725*3ff40c12SJohn Marino u32 wflags = sta->flags & (WLAN_STA_WPS | 726*3ff40c12SJohn Marino WLAN_STA_WPS2 | 727*3ff40c12SJohn Marino WLAN_STA_MAYBE_WPS); 728*3ff40c12SJohn Marino if (wflags == WLAN_STA_MAYBE_WPS || 729*3ff40c12SJohn Marino wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 730*3ff40c12SJohn Marino /* 731*3ff40c12SJohn Marino * Delay EAPOL frame transmission until a 732*3ff40c12SJohn Marino * possible WPS STA initiates the handshake 733*3ff40c12SJohn Marino * with EAPOL-Start. Only allow the wait to be 734*3ff40c12SJohn Marino * skipped if the STA is known to support WPS 735*3ff40c12SJohn Marino * 2.0. 736*3ff40c12SJohn Marino */ 737*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "WPS: Do not start " 738*3ff40c12SJohn Marino "EAPOL until EAPOL-Start is " 739*3ff40c12SJohn Marino "received"); 740*3ff40c12SJohn Marino sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 741*3ff40c12SJohn Marino } 742*3ff40c12SJohn Marino } 743*3ff40c12SJohn Marino #endif /* CONFIG_WPS */ 744*3ff40c12SJohn Marino 745*3ff40c12SJohn Marino sta->eapol_sm->eap_if->portEnabled = TRUE; 746*3ff40c12SJohn Marino } 747*3ff40c12SJohn Marino 748*3ff40c12SJohn Marino /* since we support version 1, we can ignore version field and proceed 749*3ff40c12SJohn Marino * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 750*3ff40c12SJohn Marino /* TODO: actually, we are not version 1 anymore.. However, Version 2 751*3ff40c12SJohn Marino * does not change frame contents, so should be ok to process frames 752*3ff40c12SJohn Marino * more or less identically. Some changes might be needed for 753*3ff40c12SJohn Marino * verification of fields. */ 754*3ff40c12SJohn Marino 755*3ff40c12SJohn Marino switch (hdr->type) { 756*3ff40c12SJohn Marino case IEEE802_1X_TYPE_EAP_PACKET: 757*3ff40c12SJohn Marino handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 758*3ff40c12SJohn Marino break; 759*3ff40c12SJohn Marino 760*3ff40c12SJohn Marino case IEEE802_1X_TYPE_EAPOL_START: 761*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 762*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 763*3ff40c12SJohn Marino "from STA"); 764*3ff40c12SJohn Marino sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 765*3ff40c12SJohn Marino pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 766*3ff40c12SJohn Marino if (pmksa) { 767*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 768*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 769*3ff40c12SJohn Marino "available - ignore it since " 770*3ff40c12SJohn Marino "STA sent EAPOL-Start"); 771*3ff40c12SJohn Marino wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 772*3ff40c12SJohn Marino } 773*3ff40c12SJohn Marino sta->eapol_sm->eapolStart = TRUE; 774*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 775*3ff40c12SJohn Marino eap_server_clear_identity(sta->eapol_sm->eap); 776*3ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 777*3ff40c12SJohn Marino break; 778*3ff40c12SJohn Marino 779*3ff40c12SJohn Marino case IEEE802_1X_TYPE_EAPOL_LOGOFF: 780*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 781*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 782*3ff40c12SJohn Marino "from STA"); 783*3ff40c12SJohn Marino sta->acct_terminate_cause = 784*3ff40c12SJohn Marino RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 785*3ff40c12SJohn Marino accounting_sta_stop(hapd, sta); 786*3ff40c12SJohn Marino sta->eapol_sm->eapolLogoff = TRUE; 787*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 788*3ff40c12SJohn Marino eap_server_clear_identity(sta->eapol_sm->eap); 789*3ff40c12SJohn Marino break; 790*3ff40c12SJohn Marino 791*3ff40c12SJohn Marino case IEEE802_1X_TYPE_EAPOL_KEY: 792*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " EAPOL-Key"); 793*3ff40c12SJohn Marino if (!ap_sta_is_authorized(sta)) { 794*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " Dropped key data from " 795*3ff40c12SJohn Marino "unauthorized Supplicant"); 796*3ff40c12SJohn Marino break; 797*3ff40c12SJohn Marino } 798*3ff40c12SJohn Marino break; 799*3ff40c12SJohn Marino 800*3ff40c12SJohn Marino case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 801*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 802*3ff40c12SJohn Marino /* TODO: implement support for this; show data */ 803*3ff40c12SJohn Marino break; 804*3ff40c12SJohn Marino 805*3ff40c12SJohn Marino default: 806*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 807*3ff40c12SJohn Marino sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 808*3ff40c12SJohn Marino break; 809*3ff40c12SJohn Marino } 810*3ff40c12SJohn Marino 811*3ff40c12SJohn Marino eapol_auth_step(sta->eapol_sm); 812*3ff40c12SJohn Marino } 813*3ff40c12SJohn Marino 814*3ff40c12SJohn Marino 815*3ff40c12SJohn Marino /** 816*3ff40c12SJohn Marino * ieee802_1x_new_station - Start IEEE 802.1X authentication 817*3ff40c12SJohn Marino * @hapd: hostapd BSS data 818*3ff40c12SJohn Marino * @sta: The station 819*3ff40c12SJohn Marino * 820*3ff40c12SJohn Marino * This function is called to start IEEE 802.1X authentication when a new 821*3ff40c12SJohn Marino * station completes IEEE 802.11 association. 822*3ff40c12SJohn Marino */ 823*3ff40c12SJohn Marino void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 824*3ff40c12SJohn Marino { 825*3ff40c12SJohn Marino struct rsn_pmksa_cache_entry *pmksa; 826*3ff40c12SJohn Marino int reassoc = 1; 827*3ff40c12SJohn Marino int force_1x = 0; 828*3ff40c12SJohn Marino int key_mgmt; 829*3ff40c12SJohn Marino 830*3ff40c12SJohn Marino #ifdef CONFIG_WPS 831*3ff40c12SJohn Marino if (hapd->conf->wps_state && hapd->conf->wpa && 832*3ff40c12SJohn Marino (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 833*3ff40c12SJohn Marino /* 834*3ff40c12SJohn Marino * Need to enable IEEE 802.1X/EAPOL state machines for possible 835*3ff40c12SJohn Marino * WPS handshake even if IEEE 802.1X/EAPOL is not used for 836*3ff40c12SJohn Marino * authentication in this BSS. 837*3ff40c12SJohn Marino */ 838*3ff40c12SJohn Marino force_1x = 1; 839*3ff40c12SJohn Marino } 840*3ff40c12SJohn Marino #endif /* CONFIG_WPS */ 841*3ff40c12SJohn Marino 842*3ff40c12SJohn Marino if (!force_1x && !hapd->conf->ieee802_1x) { 843*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 844*3ff40c12SJohn Marino "802.1X not enabled or forced for WPS"); 845*3ff40c12SJohn Marino /* 846*3ff40c12SJohn Marino * Clear any possible EAPOL authenticator state to support 847*3ff40c12SJohn Marino * reassociation change from WPS to PSK. 848*3ff40c12SJohn Marino */ 849*3ff40c12SJohn Marino ieee802_1x_free_station(sta); 850*3ff40c12SJohn Marino return; 851*3ff40c12SJohn Marino } 852*3ff40c12SJohn Marino 853*3ff40c12SJohn Marino key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 854*3ff40c12SJohn Marino if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { 855*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 856*3ff40c12SJohn Marino /* 857*3ff40c12SJohn Marino * Clear any possible EAPOL authenticator state to support 858*3ff40c12SJohn Marino * reassociation change from WPA-EAP to PSK. 859*3ff40c12SJohn Marino */ 860*3ff40c12SJohn Marino ieee802_1x_free_station(sta); 861*3ff40c12SJohn Marino return; 862*3ff40c12SJohn Marino } 863*3ff40c12SJohn Marino 864*3ff40c12SJohn Marino if (sta->eapol_sm == NULL) { 865*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 866*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "start authentication"); 867*3ff40c12SJohn Marino sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 868*3ff40c12SJohn Marino if (sta->eapol_sm == NULL) { 869*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, 870*3ff40c12SJohn Marino HOSTAPD_MODULE_IEEE8021X, 871*3ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, 872*3ff40c12SJohn Marino "failed to allocate state machine"); 873*3ff40c12SJohn Marino return; 874*3ff40c12SJohn Marino } 875*3ff40c12SJohn Marino reassoc = 0; 876*3ff40c12SJohn Marino } 877*3ff40c12SJohn Marino 878*3ff40c12SJohn Marino #ifdef CONFIG_WPS 879*3ff40c12SJohn Marino sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 880*3ff40c12SJohn Marino if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { 881*3ff40c12SJohn Marino /* 882*3ff40c12SJohn Marino * Delay EAPOL frame transmission until a possible WPS STA 883*3ff40c12SJohn Marino * initiates the handshake with EAPOL-Start. Only allow the 884*3ff40c12SJohn Marino * wait to be skipped if the STA is known to support WPS 2.0. 885*3ff40c12SJohn Marino */ 886*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 887*3ff40c12SJohn Marino "EAPOL-Start is received"); 888*3ff40c12SJohn Marino sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 889*3ff40c12SJohn Marino } 890*3ff40c12SJohn Marino #endif /* CONFIG_WPS */ 891*3ff40c12SJohn Marino 892*3ff40c12SJohn Marino sta->eapol_sm->eap_if->portEnabled = TRUE; 893*3ff40c12SJohn Marino 894*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211R 895*3ff40c12SJohn Marino if (sta->auth_alg == WLAN_AUTH_FT) { 896*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 897*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, 898*3ff40c12SJohn Marino "PMK from FT - skip IEEE 802.1X/EAP"); 899*3ff40c12SJohn Marino /* Setup EAPOL state machines to already authenticated state 900*3ff40c12SJohn Marino * because of existing FT information from R0KH. */ 901*3ff40c12SJohn Marino sta->eapol_sm->keyRun = TRUE; 902*3ff40c12SJohn Marino sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 903*3ff40c12SJohn Marino sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 904*3ff40c12SJohn Marino sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 905*3ff40c12SJohn Marino sta->eapol_sm->authSuccess = TRUE; 906*3ff40c12SJohn Marino sta->eapol_sm->authFail = FALSE; 907*3ff40c12SJohn Marino if (sta->eapol_sm->eap) 908*3ff40c12SJohn Marino eap_sm_notify_cached(sta->eapol_sm->eap); 909*3ff40c12SJohn Marino /* TODO: get vlan_id from R0KH using RRB message */ 910*3ff40c12SJohn Marino return; 911*3ff40c12SJohn Marino } 912*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211R */ 913*3ff40c12SJohn Marino 914*3ff40c12SJohn Marino pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 915*3ff40c12SJohn Marino if (pmksa) { 916*3ff40c12SJohn Marino int old_vlanid; 917*3ff40c12SJohn Marino 918*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 919*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, 920*3ff40c12SJohn Marino "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 921*3ff40c12SJohn Marino /* Setup EAPOL state machines to already authenticated state 922*3ff40c12SJohn Marino * because of existing PMKSA information in the cache. */ 923*3ff40c12SJohn Marino sta->eapol_sm->keyRun = TRUE; 924*3ff40c12SJohn Marino sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 925*3ff40c12SJohn Marino sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 926*3ff40c12SJohn Marino sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 927*3ff40c12SJohn Marino sta->eapol_sm->authSuccess = TRUE; 928*3ff40c12SJohn Marino sta->eapol_sm->authFail = FALSE; 929*3ff40c12SJohn Marino if (sta->eapol_sm->eap) 930*3ff40c12SJohn Marino eap_sm_notify_cached(sta->eapol_sm->eap); 931*3ff40c12SJohn Marino old_vlanid = sta->vlan_id; 932*3ff40c12SJohn Marino pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); 933*3ff40c12SJohn Marino if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 934*3ff40c12SJohn Marino sta->vlan_id = 0; 935*3ff40c12SJohn Marino ap_sta_bind_vlan(hapd, sta, old_vlanid); 936*3ff40c12SJohn Marino } else { 937*3ff40c12SJohn Marino if (reassoc) { 938*3ff40c12SJohn Marino /* 939*3ff40c12SJohn Marino * Force EAPOL state machines to start 940*3ff40c12SJohn Marino * re-authentication without having to wait for the 941*3ff40c12SJohn Marino * Supplicant to send EAPOL-Start. 942*3ff40c12SJohn Marino */ 943*3ff40c12SJohn Marino sta->eapol_sm->reAuthenticate = TRUE; 944*3ff40c12SJohn Marino } 945*3ff40c12SJohn Marino eapol_auth_step(sta->eapol_sm); 946*3ff40c12SJohn Marino } 947*3ff40c12SJohn Marino } 948*3ff40c12SJohn Marino 949*3ff40c12SJohn Marino 950*3ff40c12SJohn Marino void ieee802_1x_free_station(struct sta_info *sta) 951*3ff40c12SJohn Marino { 952*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 953*3ff40c12SJohn Marino 954*3ff40c12SJohn Marino if (sm == NULL) 955*3ff40c12SJohn Marino return; 956*3ff40c12SJohn Marino 957*3ff40c12SJohn Marino sta->eapol_sm = NULL; 958*3ff40c12SJohn Marino 959*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 960*3ff40c12SJohn Marino radius_msg_free(sm->last_recv_radius); 961*3ff40c12SJohn Marino radius_free_class(&sm->radius_class); 962*3ff40c12SJohn Marino wpabuf_free(sm->radius_cui); 963*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 964*3ff40c12SJohn Marino 965*3ff40c12SJohn Marino os_free(sm->identity); 966*3ff40c12SJohn Marino eapol_auth_free(sm); 967*3ff40c12SJohn Marino } 968*3ff40c12SJohn Marino 969*3ff40c12SJohn Marino 970*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 971*3ff40c12SJohn Marino static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 972*3ff40c12SJohn Marino struct sta_info *sta) 973*3ff40c12SJohn Marino { 974*3ff40c12SJohn Marino struct wpabuf *eap; 975*3ff40c12SJohn Marino const struct eap_hdr *hdr; 976*3ff40c12SJohn Marino int eap_type = -1; 977*3ff40c12SJohn Marino char buf[64]; 978*3ff40c12SJohn Marino struct radius_msg *msg; 979*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 980*3ff40c12SJohn Marino 981*3ff40c12SJohn Marino if (sm == NULL || sm->last_recv_radius == NULL) { 982*3ff40c12SJohn Marino if (sm) 983*3ff40c12SJohn Marino sm->eap_if->aaaEapNoReq = TRUE; 984*3ff40c12SJohn Marino return; 985*3ff40c12SJohn Marino } 986*3ff40c12SJohn Marino 987*3ff40c12SJohn Marino msg = sm->last_recv_radius; 988*3ff40c12SJohn Marino 989*3ff40c12SJohn Marino eap = radius_msg_get_eap(msg); 990*3ff40c12SJohn Marino if (eap == NULL) { 991*3ff40c12SJohn Marino /* RFC 3579, Chap. 2.6.3: 992*3ff40c12SJohn Marino * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 993*3ff40c12SJohn Marino * attribute */ 994*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 995*3ff40c12SJohn Marino HOSTAPD_LEVEL_WARNING, "could not extract " 996*3ff40c12SJohn Marino "EAP-Message from RADIUS message"); 997*3ff40c12SJohn Marino sm->eap_if->aaaEapNoReq = TRUE; 998*3ff40c12SJohn Marino return; 999*3ff40c12SJohn Marino } 1000*3ff40c12SJohn Marino 1001*3ff40c12SJohn Marino if (wpabuf_len(eap) < sizeof(*hdr)) { 1002*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1003*3ff40c12SJohn Marino HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1004*3ff40c12SJohn Marino "received from authentication server"); 1005*3ff40c12SJohn Marino wpabuf_free(eap); 1006*3ff40c12SJohn Marino sm->eap_if->aaaEapNoReq = TRUE; 1007*3ff40c12SJohn Marino return; 1008*3ff40c12SJohn Marino } 1009*3ff40c12SJohn Marino 1010*3ff40c12SJohn Marino if (wpabuf_len(eap) > sizeof(*hdr)) 1011*3ff40c12SJohn Marino eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1012*3ff40c12SJohn Marino 1013*3ff40c12SJohn Marino hdr = wpabuf_head(eap); 1014*3ff40c12SJohn Marino switch (hdr->code) { 1015*3ff40c12SJohn Marino case EAP_CODE_REQUEST: 1016*3ff40c12SJohn Marino if (eap_type >= 0) 1017*3ff40c12SJohn Marino sm->eap_type_authsrv = eap_type; 1018*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 1019*3ff40c12SJohn Marino eap_type >= 0 ? eap_server_get_name(0, eap_type) : 1020*3ff40c12SJohn Marino "??", 1021*3ff40c12SJohn Marino eap_type); 1022*3ff40c12SJohn Marino break; 1023*3ff40c12SJohn Marino case EAP_CODE_RESPONSE: 1024*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 1025*3ff40c12SJohn Marino eap_type >= 0 ? eap_server_get_name(0, eap_type) : 1026*3ff40c12SJohn Marino "??", 1027*3ff40c12SJohn Marino eap_type); 1028*3ff40c12SJohn Marino break; 1029*3ff40c12SJohn Marino case EAP_CODE_SUCCESS: 1030*3ff40c12SJohn Marino os_strlcpy(buf, "EAP Success", sizeof(buf)); 1031*3ff40c12SJohn Marino break; 1032*3ff40c12SJohn Marino case EAP_CODE_FAILURE: 1033*3ff40c12SJohn Marino os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1034*3ff40c12SJohn Marino break; 1035*3ff40c12SJohn Marino default: 1036*3ff40c12SJohn Marino os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1037*3ff40c12SJohn Marino break; 1038*3ff40c12SJohn Marino } 1039*3ff40c12SJohn Marino buf[sizeof(buf) - 1] = '\0'; 1040*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1041*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1042*3ff40c12SJohn Marino "id=%d len=%d) from RADIUS server: %s", 1043*3ff40c12SJohn Marino hdr->code, hdr->identifier, be_to_host16(hdr->length), 1044*3ff40c12SJohn Marino buf); 1045*3ff40c12SJohn Marino sm->eap_if->aaaEapReq = TRUE; 1046*3ff40c12SJohn Marino 1047*3ff40c12SJohn Marino wpabuf_free(sm->eap_if->aaaEapReqData); 1048*3ff40c12SJohn Marino sm->eap_if->aaaEapReqData = eap; 1049*3ff40c12SJohn Marino } 1050*3ff40c12SJohn Marino 1051*3ff40c12SJohn Marino 1052*3ff40c12SJohn Marino static void ieee802_1x_get_keys(struct hostapd_data *hapd, 1053*3ff40c12SJohn Marino struct sta_info *sta, struct radius_msg *msg, 1054*3ff40c12SJohn Marino struct radius_msg *req, 1055*3ff40c12SJohn Marino const u8 *shared_secret, 1056*3ff40c12SJohn Marino size_t shared_secret_len) 1057*3ff40c12SJohn Marino { 1058*3ff40c12SJohn Marino struct radius_ms_mppe_keys *keys; 1059*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1060*3ff40c12SJohn Marino if (sm == NULL) 1061*3ff40c12SJohn Marino return; 1062*3ff40c12SJohn Marino 1063*3ff40c12SJohn Marino keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1064*3ff40c12SJohn Marino shared_secret_len); 1065*3ff40c12SJohn Marino 1066*3ff40c12SJohn Marino if (keys && keys->send && keys->recv) { 1067*3ff40c12SJohn Marino size_t len = keys->send_len + keys->recv_len; 1068*3ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1069*3ff40c12SJohn Marino keys->send, keys->send_len); 1070*3ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1071*3ff40c12SJohn Marino keys->recv, keys->recv_len); 1072*3ff40c12SJohn Marino 1073*3ff40c12SJohn Marino os_free(sm->eap_if->aaaEapKeyData); 1074*3ff40c12SJohn Marino sm->eap_if->aaaEapKeyData = os_malloc(len); 1075*3ff40c12SJohn Marino if (sm->eap_if->aaaEapKeyData) { 1076*3ff40c12SJohn Marino os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1077*3ff40c12SJohn Marino keys->recv_len); 1078*3ff40c12SJohn Marino os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1079*3ff40c12SJohn Marino keys->send, keys->send_len); 1080*3ff40c12SJohn Marino sm->eap_if->aaaEapKeyDataLen = len; 1081*3ff40c12SJohn Marino sm->eap_if->aaaEapKeyAvailable = TRUE; 1082*3ff40c12SJohn Marino } 1083*3ff40c12SJohn Marino } 1084*3ff40c12SJohn Marino 1085*3ff40c12SJohn Marino if (keys) { 1086*3ff40c12SJohn Marino os_free(keys->send); 1087*3ff40c12SJohn Marino os_free(keys->recv); 1088*3ff40c12SJohn Marino os_free(keys); 1089*3ff40c12SJohn Marino } 1090*3ff40c12SJohn Marino } 1091*3ff40c12SJohn Marino 1092*3ff40c12SJohn Marino 1093*3ff40c12SJohn Marino static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1094*3ff40c12SJohn Marino struct sta_info *sta, 1095*3ff40c12SJohn Marino struct radius_msg *msg) 1096*3ff40c12SJohn Marino { 1097*3ff40c12SJohn Marino u8 *class; 1098*3ff40c12SJohn Marino size_t class_len; 1099*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1100*3ff40c12SJohn Marino int count, i; 1101*3ff40c12SJohn Marino struct radius_attr_data *nclass; 1102*3ff40c12SJohn Marino size_t nclass_count; 1103*3ff40c12SJohn Marino 1104*3ff40c12SJohn Marino if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1105*3ff40c12SJohn Marino sm == NULL) 1106*3ff40c12SJohn Marino return; 1107*3ff40c12SJohn Marino 1108*3ff40c12SJohn Marino radius_free_class(&sm->radius_class); 1109*3ff40c12SJohn Marino count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1110*3ff40c12SJohn Marino if (count <= 0) 1111*3ff40c12SJohn Marino return; 1112*3ff40c12SJohn Marino 1113*3ff40c12SJohn Marino nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1114*3ff40c12SJohn Marino if (nclass == NULL) 1115*3ff40c12SJohn Marino return; 1116*3ff40c12SJohn Marino 1117*3ff40c12SJohn Marino nclass_count = 0; 1118*3ff40c12SJohn Marino 1119*3ff40c12SJohn Marino class = NULL; 1120*3ff40c12SJohn Marino for (i = 0; i < count; i++) { 1121*3ff40c12SJohn Marino do { 1122*3ff40c12SJohn Marino if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1123*3ff40c12SJohn Marino &class, &class_len, 1124*3ff40c12SJohn Marino class) < 0) { 1125*3ff40c12SJohn Marino i = count; 1126*3ff40c12SJohn Marino break; 1127*3ff40c12SJohn Marino } 1128*3ff40c12SJohn Marino } while (class_len < 1); 1129*3ff40c12SJohn Marino 1130*3ff40c12SJohn Marino nclass[nclass_count].data = os_malloc(class_len); 1131*3ff40c12SJohn Marino if (nclass[nclass_count].data == NULL) 1132*3ff40c12SJohn Marino break; 1133*3ff40c12SJohn Marino 1134*3ff40c12SJohn Marino os_memcpy(nclass[nclass_count].data, class, class_len); 1135*3ff40c12SJohn Marino nclass[nclass_count].len = class_len; 1136*3ff40c12SJohn Marino nclass_count++; 1137*3ff40c12SJohn Marino } 1138*3ff40c12SJohn Marino 1139*3ff40c12SJohn Marino sm->radius_class.attr = nclass; 1140*3ff40c12SJohn Marino sm->radius_class.count = nclass_count; 1141*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1142*3ff40c12SJohn Marino "attributes for " MACSTR, 1143*3ff40c12SJohn Marino (unsigned long) sm->radius_class.count, 1144*3ff40c12SJohn Marino MAC2STR(sta->addr)); 1145*3ff40c12SJohn Marino } 1146*3ff40c12SJohn Marino 1147*3ff40c12SJohn Marino 1148*3ff40c12SJohn Marino /* Update sta->identity based on User-Name attribute in Access-Accept */ 1149*3ff40c12SJohn Marino static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1150*3ff40c12SJohn Marino struct sta_info *sta, 1151*3ff40c12SJohn Marino struct radius_msg *msg) 1152*3ff40c12SJohn Marino { 1153*3ff40c12SJohn Marino u8 *buf, *identity; 1154*3ff40c12SJohn Marino size_t len; 1155*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1156*3ff40c12SJohn Marino 1157*3ff40c12SJohn Marino if (sm == NULL) 1158*3ff40c12SJohn Marino return; 1159*3ff40c12SJohn Marino 1160*3ff40c12SJohn Marino if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1161*3ff40c12SJohn Marino NULL) < 0) 1162*3ff40c12SJohn Marino return; 1163*3ff40c12SJohn Marino 1164*3ff40c12SJohn Marino identity = (u8 *) dup_binstr(buf, len); 1165*3ff40c12SJohn Marino if (identity == NULL) 1166*3ff40c12SJohn Marino return; 1167*3ff40c12SJohn Marino 1168*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1169*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1170*3ff40c12SJohn Marino "User-Name from Access-Accept '%s'", 1171*3ff40c12SJohn Marino sm->identity ? (char *) sm->identity : "N/A", 1172*3ff40c12SJohn Marino (char *) identity); 1173*3ff40c12SJohn Marino 1174*3ff40c12SJohn Marino os_free(sm->identity); 1175*3ff40c12SJohn Marino sm->identity = identity; 1176*3ff40c12SJohn Marino sm->identity_len = len; 1177*3ff40c12SJohn Marino } 1178*3ff40c12SJohn Marino 1179*3ff40c12SJohn Marino 1180*3ff40c12SJohn Marino /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1181*3ff40c12SJohn Marino static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1182*3ff40c12SJohn Marino struct sta_info *sta, 1183*3ff40c12SJohn Marino struct radius_msg *msg) 1184*3ff40c12SJohn Marino { 1185*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1186*3ff40c12SJohn Marino struct wpabuf *cui; 1187*3ff40c12SJohn Marino u8 *buf; 1188*3ff40c12SJohn Marino size_t len; 1189*3ff40c12SJohn Marino 1190*3ff40c12SJohn Marino if (sm == NULL) 1191*3ff40c12SJohn Marino return; 1192*3ff40c12SJohn Marino 1193*3ff40c12SJohn Marino if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1194*3ff40c12SJohn Marino &buf, &len, NULL) < 0) 1195*3ff40c12SJohn Marino return; 1196*3ff40c12SJohn Marino 1197*3ff40c12SJohn Marino cui = wpabuf_alloc_copy(buf, len); 1198*3ff40c12SJohn Marino if (cui == NULL) 1199*3ff40c12SJohn Marino return; 1200*3ff40c12SJohn Marino 1201*3ff40c12SJohn Marino wpabuf_free(sm->radius_cui); 1202*3ff40c12SJohn Marino sm->radius_cui = cui; 1203*3ff40c12SJohn Marino } 1204*3ff40c12SJohn Marino 1205*3ff40c12SJohn Marino 1206*3ff40c12SJohn Marino struct sta_id_search { 1207*3ff40c12SJohn Marino u8 identifier; 1208*3ff40c12SJohn Marino struct eapol_state_machine *sm; 1209*3ff40c12SJohn Marino }; 1210*3ff40c12SJohn Marino 1211*3ff40c12SJohn Marino 1212*3ff40c12SJohn Marino static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1213*3ff40c12SJohn Marino struct sta_info *sta, 1214*3ff40c12SJohn Marino void *ctx) 1215*3ff40c12SJohn Marino { 1216*3ff40c12SJohn Marino struct sta_id_search *id_search = ctx; 1217*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1218*3ff40c12SJohn Marino 1219*3ff40c12SJohn Marino if (sm && sm->radius_identifier >= 0 && 1220*3ff40c12SJohn Marino sm->radius_identifier == id_search->identifier) { 1221*3ff40c12SJohn Marino id_search->sm = sm; 1222*3ff40c12SJohn Marino return 1; 1223*3ff40c12SJohn Marino } 1224*3ff40c12SJohn Marino return 0; 1225*3ff40c12SJohn Marino } 1226*3ff40c12SJohn Marino 1227*3ff40c12SJohn Marino 1228*3ff40c12SJohn Marino static struct eapol_state_machine * 1229*3ff40c12SJohn Marino ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1230*3ff40c12SJohn Marino { 1231*3ff40c12SJohn Marino struct sta_id_search id_search; 1232*3ff40c12SJohn Marino id_search.identifier = identifier; 1233*3ff40c12SJohn Marino id_search.sm = NULL; 1234*3ff40c12SJohn Marino ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1235*3ff40c12SJohn Marino return id_search.sm; 1236*3ff40c12SJohn Marino } 1237*3ff40c12SJohn Marino 1238*3ff40c12SJohn Marino 1239*3ff40c12SJohn Marino /** 1240*3ff40c12SJohn Marino * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1241*3ff40c12SJohn Marino * @msg: RADIUS response message 1242*3ff40c12SJohn Marino * @req: RADIUS request message 1243*3ff40c12SJohn Marino * @shared_secret: RADIUS shared secret 1244*3ff40c12SJohn Marino * @shared_secret_len: Length of shared_secret in octets 1245*3ff40c12SJohn Marino * @data: Context data (struct hostapd_data *) 1246*3ff40c12SJohn Marino * Returns: Processing status 1247*3ff40c12SJohn Marino */ 1248*3ff40c12SJohn Marino static RadiusRxResult 1249*3ff40c12SJohn Marino ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1250*3ff40c12SJohn Marino const u8 *shared_secret, size_t shared_secret_len, 1251*3ff40c12SJohn Marino void *data) 1252*3ff40c12SJohn Marino { 1253*3ff40c12SJohn Marino struct hostapd_data *hapd = data; 1254*3ff40c12SJohn Marino struct sta_info *sta; 1255*3ff40c12SJohn Marino u32 session_timeout = 0, termination_action, acct_interim_interval; 1256*3ff40c12SJohn Marino int session_timeout_set, old_vlanid = 0; 1257*3ff40c12SJohn Marino struct eapol_state_machine *sm; 1258*3ff40c12SJohn Marino int override_eapReq = 0; 1259*3ff40c12SJohn Marino struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1260*3ff40c12SJohn Marino 1261*3ff40c12SJohn Marino sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1262*3ff40c12SJohn Marino if (sm == NULL) { 1263*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1264*3ff40c12SJohn Marino "station for this RADIUS message"); 1265*3ff40c12SJohn Marino return RADIUS_RX_UNKNOWN; 1266*3ff40c12SJohn Marino } 1267*3ff40c12SJohn Marino sta = sm->sta; 1268*3ff40c12SJohn Marino 1269*3ff40c12SJohn Marino /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1270*3ff40c12SJohn Marino * present when packet contains an EAP-Message attribute */ 1271*3ff40c12SJohn Marino if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1272*3ff40c12SJohn Marino radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1273*3ff40c12SJohn Marino 0) < 0 && 1274*3ff40c12SJohn Marino radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1275*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1276*3ff40c12SJohn Marino "Message-Authenticator since it does not include " 1277*3ff40c12SJohn Marino "EAP-Message"); 1278*3ff40c12SJohn Marino } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1279*3ff40c12SJohn Marino req, 1)) { 1280*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1281*3ff40c12SJohn Marino return RADIUS_RX_INVALID_AUTHENTICATOR; 1282*3ff40c12SJohn Marino } 1283*3ff40c12SJohn Marino 1284*3ff40c12SJohn Marino if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1285*3ff40c12SJohn Marino hdr->code != RADIUS_CODE_ACCESS_REJECT && 1286*3ff40c12SJohn Marino hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 1287*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1288*3ff40c12SJohn Marino return RADIUS_RX_UNKNOWN; 1289*3ff40c12SJohn Marino } 1290*3ff40c12SJohn Marino 1291*3ff40c12SJohn Marino sm->radius_identifier = -1; 1292*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1293*3ff40c12SJohn Marino MAC2STR(sta->addr)); 1294*3ff40c12SJohn Marino 1295*3ff40c12SJohn Marino radius_msg_free(sm->last_recv_radius); 1296*3ff40c12SJohn Marino sm->last_recv_radius = msg; 1297*3ff40c12SJohn Marino 1298*3ff40c12SJohn Marino session_timeout_set = 1299*3ff40c12SJohn Marino !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1300*3ff40c12SJohn Marino &session_timeout); 1301*3ff40c12SJohn Marino if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1302*3ff40c12SJohn Marino &termination_action)) 1303*3ff40c12SJohn Marino termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1304*3ff40c12SJohn Marino 1305*3ff40c12SJohn Marino if (hapd->conf->acct_interim_interval == 0 && 1306*3ff40c12SJohn Marino hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1307*3ff40c12SJohn Marino radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1308*3ff40c12SJohn Marino &acct_interim_interval) == 0) { 1309*3ff40c12SJohn Marino if (acct_interim_interval < 60) { 1310*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, 1311*3ff40c12SJohn Marino HOSTAPD_MODULE_IEEE8021X, 1312*3ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, 1313*3ff40c12SJohn Marino "ignored too small " 1314*3ff40c12SJohn Marino "Acct-Interim-Interval %d", 1315*3ff40c12SJohn Marino acct_interim_interval); 1316*3ff40c12SJohn Marino } else 1317*3ff40c12SJohn Marino sta->acct_interim_interval = acct_interim_interval; 1318*3ff40c12SJohn Marino } 1319*3ff40c12SJohn Marino 1320*3ff40c12SJohn Marino 1321*3ff40c12SJohn Marino switch (hdr->code) { 1322*3ff40c12SJohn Marino case RADIUS_CODE_ACCESS_ACCEPT: 1323*3ff40c12SJohn Marino if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 1324*3ff40c12SJohn Marino sta->vlan_id = 0; 1325*3ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN 1326*3ff40c12SJohn Marino else { 1327*3ff40c12SJohn Marino old_vlanid = sta->vlan_id; 1328*3ff40c12SJohn Marino sta->vlan_id = radius_msg_get_vlanid(msg); 1329*3ff40c12SJohn Marino } 1330*3ff40c12SJohn Marino if (sta->vlan_id > 0 && 1331*3ff40c12SJohn Marino hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) { 1332*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, 1333*3ff40c12SJohn Marino HOSTAPD_MODULE_RADIUS, 1334*3ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, 1335*3ff40c12SJohn Marino "VLAN ID %d", sta->vlan_id); 1336*3ff40c12SJohn Marino } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { 1337*3ff40c12SJohn Marino sta->eapol_sm->authFail = TRUE; 1338*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, 1339*3ff40c12SJohn Marino HOSTAPD_MODULE_IEEE8021X, 1340*3ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, "authentication " 1341*3ff40c12SJohn Marino "server did not include required VLAN " 1342*3ff40c12SJohn Marino "ID in Access-Accept"); 1343*3ff40c12SJohn Marino break; 1344*3ff40c12SJohn Marino } 1345*3ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */ 1346*3ff40c12SJohn Marino 1347*3ff40c12SJohn Marino if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) 1348*3ff40c12SJohn Marino break; 1349*3ff40c12SJohn Marino 1350*3ff40c12SJohn Marino /* RFC 3580, Ch. 3.17 */ 1351*3ff40c12SJohn Marino if (session_timeout_set && termination_action == 1352*3ff40c12SJohn Marino RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { 1353*3ff40c12SJohn Marino sm->reAuthPeriod = session_timeout; 1354*3ff40c12SJohn Marino } else if (session_timeout_set) 1355*3ff40c12SJohn Marino ap_sta_session_timeout(hapd, sta, session_timeout); 1356*3ff40c12SJohn Marino 1357*3ff40c12SJohn Marino sm->eap_if->aaaSuccess = TRUE; 1358*3ff40c12SJohn Marino override_eapReq = 1; 1359*3ff40c12SJohn Marino ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 1360*3ff40c12SJohn Marino shared_secret_len); 1361*3ff40c12SJohn Marino ieee802_1x_store_radius_class(hapd, sta, msg); 1362*3ff40c12SJohn Marino ieee802_1x_update_sta_identity(hapd, sta, msg); 1363*3ff40c12SJohn Marino ieee802_1x_update_sta_cui(hapd, sta, msg); 1364*3ff40c12SJohn Marino if (sm->eap_if->eapKeyAvailable && 1365*3ff40c12SJohn Marino wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, 1366*3ff40c12SJohn Marino session_timeout_set ? 1367*3ff40c12SJohn Marino (int) session_timeout : -1, sm) == 0) { 1368*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1369*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, 1370*3ff40c12SJohn Marino "Added PMKSA cache entry"); 1371*3ff40c12SJohn Marino } 1372*3ff40c12SJohn Marino break; 1373*3ff40c12SJohn Marino case RADIUS_CODE_ACCESS_REJECT: 1374*3ff40c12SJohn Marino sm->eap_if->aaaFail = TRUE; 1375*3ff40c12SJohn Marino override_eapReq = 1; 1376*3ff40c12SJohn Marino break; 1377*3ff40c12SJohn Marino case RADIUS_CODE_ACCESS_CHALLENGE: 1378*3ff40c12SJohn Marino sm->eap_if->aaaEapReq = TRUE; 1379*3ff40c12SJohn Marino if (session_timeout_set) { 1380*3ff40c12SJohn Marino /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 1381*3ff40c12SJohn Marino sm->eap_if->aaaMethodTimeout = session_timeout; 1382*3ff40c12SJohn Marino hostapd_logger(hapd, sm->addr, 1383*3ff40c12SJohn Marino HOSTAPD_MODULE_IEEE8021X, 1384*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, 1385*3ff40c12SJohn Marino "using EAP timeout of %d seconds (from " 1386*3ff40c12SJohn Marino "RADIUS)", 1387*3ff40c12SJohn Marino sm->eap_if->aaaMethodTimeout); 1388*3ff40c12SJohn Marino } else { 1389*3ff40c12SJohn Marino /* 1390*3ff40c12SJohn Marino * Use dynamic retransmission behavior per EAP 1391*3ff40c12SJohn Marino * specification. 1392*3ff40c12SJohn Marino */ 1393*3ff40c12SJohn Marino sm->eap_if->aaaMethodTimeout = 0; 1394*3ff40c12SJohn Marino } 1395*3ff40c12SJohn Marino break; 1396*3ff40c12SJohn Marino } 1397*3ff40c12SJohn Marino 1398*3ff40c12SJohn Marino ieee802_1x_decapsulate_radius(hapd, sta); 1399*3ff40c12SJohn Marino if (override_eapReq) 1400*3ff40c12SJohn Marino sm->eap_if->aaaEapReq = FALSE; 1401*3ff40c12SJohn Marino 1402*3ff40c12SJohn Marino eapol_auth_step(sm); 1403*3ff40c12SJohn Marino 1404*3ff40c12SJohn Marino return RADIUS_RX_QUEUED; 1405*3ff40c12SJohn Marino } 1406*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 1407*3ff40c12SJohn Marino 1408*3ff40c12SJohn Marino 1409*3ff40c12SJohn Marino void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 1410*3ff40c12SJohn Marino { 1411*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1412*3ff40c12SJohn Marino if (sm == NULL) 1413*3ff40c12SJohn Marino return; 1414*3ff40c12SJohn Marino 1415*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1416*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 1417*3ff40c12SJohn Marino 1418*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 1419*3ff40c12SJohn Marino radius_msg_free(sm->last_recv_radius); 1420*3ff40c12SJohn Marino sm->last_recv_radius = NULL; 1421*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 1422*3ff40c12SJohn Marino 1423*3ff40c12SJohn Marino if (sm->eap_if->eapTimeout) { 1424*3ff40c12SJohn Marino /* 1425*3ff40c12SJohn Marino * Disconnect the STA since it did not reply to the last EAP 1426*3ff40c12SJohn Marino * request and we cannot continue EAP processing (EAP-Failure 1427*3ff40c12SJohn Marino * could only be sent if the EAP peer actually replied). 1428*3ff40c12SJohn Marino */ 1429*3ff40c12SJohn Marino wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 1430*3ff40c12SJohn Marino MAC2STR(sta->addr)); 1431*3ff40c12SJohn Marino 1432*3ff40c12SJohn Marino sm->eap_if->portEnabled = FALSE; 1433*3ff40c12SJohn Marino ap_sta_disconnect(hapd, sta, sta->addr, 1434*3ff40c12SJohn Marino WLAN_REASON_PREV_AUTH_NOT_VALID); 1435*3ff40c12SJohn Marino } 1436*3ff40c12SJohn Marino } 1437*3ff40c12SJohn Marino 1438*3ff40c12SJohn Marino 1439*3ff40c12SJohn Marino static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 1440*3ff40c12SJohn Marino { 1441*3ff40c12SJohn Marino struct eapol_authenticator *eapol = hapd->eapol_auth; 1442*3ff40c12SJohn Marino 1443*3ff40c12SJohn Marino if (hapd->conf->default_wep_key_len < 1) 1444*3ff40c12SJohn Marino return 0; 1445*3ff40c12SJohn Marino 1446*3ff40c12SJohn Marino os_free(eapol->default_wep_key); 1447*3ff40c12SJohn Marino eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 1448*3ff40c12SJohn Marino if (eapol->default_wep_key == NULL || 1449*3ff40c12SJohn Marino random_get_bytes(eapol->default_wep_key, 1450*3ff40c12SJohn Marino hapd->conf->default_wep_key_len)) { 1451*3ff40c12SJohn Marino wpa_printf(MSG_INFO, "Could not generate random WEP key"); 1452*3ff40c12SJohn Marino os_free(eapol->default_wep_key); 1453*3ff40c12SJohn Marino eapol->default_wep_key = NULL; 1454*3ff40c12SJohn Marino return -1; 1455*3ff40c12SJohn Marino } 1456*3ff40c12SJohn Marino 1457*3ff40c12SJohn Marino wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 1458*3ff40c12SJohn Marino eapol->default_wep_key, 1459*3ff40c12SJohn Marino hapd->conf->default_wep_key_len); 1460*3ff40c12SJohn Marino 1461*3ff40c12SJohn Marino return 0; 1462*3ff40c12SJohn Marino } 1463*3ff40c12SJohn Marino 1464*3ff40c12SJohn Marino 1465*3ff40c12SJohn Marino static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 1466*3ff40c12SJohn Marino struct sta_info *sta, void *ctx) 1467*3ff40c12SJohn Marino { 1468*3ff40c12SJohn Marino if (sta->eapol_sm) { 1469*3ff40c12SJohn Marino sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1470*3ff40c12SJohn Marino eapol_auth_step(sta->eapol_sm); 1471*3ff40c12SJohn Marino } 1472*3ff40c12SJohn Marino return 0; 1473*3ff40c12SJohn Marino } 1474*3ff40c12SJohn Marino 1475*3ff40c12SJohn Marino 1476*3ff40c12SJohn Marino static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 1477*3ff40c12SJohn Marino { 1478*3ff40c12SJohn Marino struct hostapd_data *hapd = eloop_ctx; 1479*3ff40c12SJohn Marino struct eapol_authenticator *eapol = hapd->eapol_auth; 1480*3ff40c12SJohn Marino 1481*3ff40c12SJohn Marino if (eapol->default_wep_key_idx >= 3) 1482*3ff40c12SJohn Marino eapol->default_wep_key_idx = 1483*3ff40c12SJohn Marino hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 1484*3ff40c12SJohn Marino else 1485*3ff40c12SJohn Marino eapol->default_wep_key_idx++; 1486*3ff40c12SJohn Marino 1487*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 1488*3ff40c12SJohn Marino eapol->default_wep_key_idx); 1489*3ff40c12SJohn Marino 1490*3ff40c12SJohn Marino if (ieee802_1x_rekey_broadcast(hapd)) { 1491*3ff40c12SJohn Marino hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1492*3ff40c12SJohn Marino HOSTAPD_LEVEL_WARNING, "failed to generate a " 1493*3ff40c12SJohn Marino "new broadcast key"); 1494*3ff40c12SJohn Marino os_free(eapol->default_wep_key); 1495*3ff40c12SJohn Marino eapol->default_wep_key = NULL; 1496*3ff40c12SJohn Marino return; 1497*3ff40c12SJohn Marino } 1498*3ff40c12SJohn Marino 1499*3ff40c12SJohn Marino /* TODO: Could setup key for RX here, but change default TX keyid only 1500*3ff40c12SJohn Marino * after new broadcast key has been sent to all stations. */ 1501*3ff40c12SJohn Marino if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 1502*3ff40c12SJohn Marino broadcast_ether_addr, 1503*3ff40c12SJohn Marino eapol->default_wep_key_idx, 1, NULL, 0, 1504*3ff40c12SJohn Marino eapol->default_wep_key, 1505*3ff40c12SJohn Marino hapd->conf->default_wep_key_len)) { 1506*3ff40c12SJohn Marino hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1507*3ff40c12SJohn Marino HOSTAPD_LEVEL_WARNING, "failed to configure a " 1508*3ff40c12SJohn Marino "new broadcast key"); 1509*3ff40c12SJohn Marino os_free(eapol->default_wep_key); 1510*3ff40c12SJohn Marino eapol->default_wep_key = NULL; 1511*3ff40c12SJohn Marino return; 1512*3ff40c12SJohn Marino } 1513*3ff40c12SJohn Marino 1514*3ff40c12SJohn Marino ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 1515*3ff40c12SJohn Marino 1516*3ff40c12SJohn Marino if (hapd->conf->wep_rekeying_period > 0) { 1517*3ff40c12SJohn Marino eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 1518*3ff40c12SJohn Marino ieee802_1x_rekey, hapd, NULL); 1519*3ff40c12SJohn Marino } 1520*3ff40c12SJohn Marino } 1521*3ff40c12SJohn Marino 1522*3ff40c12SJohn Marino 1523*3ff40c12SJohn Marino static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 1524*3ff40c12SJohn Marino const u8 *data, size_t datalen) 1525*3ff40c12SJohn Marino { 1526*3ff40c12SJohn Marino #ifdef CONFIG_WPS 1527*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1528*3ff40c12SJohn Marino 1529*3ff40c12SJohn Marino if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 1530*3ff40c12SJohn Marino WLAN_STA_MAYBE_WPS) { 1531*3ff40c12SJohn Marino const u8 *identity; 1532*3ff40c12SJohn Marino size_t identity_len; 1533*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1534*3ff40c12SJohn Marino 1535*3ff40c12SJohn Marino identity = eap_get_identity(sm->eap, &identity_len); 1536*3ff40c12SJohn Marino if (identity && 1537*3ff40c12SJohn Marino ((identity_len == WSC_ID_ENROLLEE_LEN && 1538*3ff40c12SJohn Marino os_memcmp(identity, WSC_ID_ENROLLEE, 1539*3ff40c12SJohn Marino WSC_ID_ENROLLEE_LEN) == 0) || 1540*3ff40c12SJohn Marino (identity_len == WSC_ID_REGISTRAR_LEN && 1541*3ff40c12SJohn Marino os_memcmp(identity, WSC_ID_REGISTRAR, 1542*3ff40c12SJohn Marino WSC_ID_REGISTRAR_LEN) == 0))) { 1543*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 1544*3ff40c12SJohn Marino "WLAN_STA_WPS"); 1545*3ff40c12SJohn Marino sta->flags |= WLAN_STA_WPS; 1546*3ff40c12SJohn Marino } 1547*3ff40c12SJohn Marino } 1548*3ff40c12SJohn Marino #endif /* CONFIG_WPS */ 1549*3ff40c12SJohn Marino 1550*3ff40c12SJohn Marino ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 1551*3ff40c12SJohn Marino } 1552*3ff40c12SJohn Marino 1553*3ff40c12SJohn Marino 1554*3ff40c12SJohn Marino static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 1555*3ff40c12SJohn Marino const u8 *data, size_t datalen) 1556*3ff40c12SJohn Marino { 1557*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 1558*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1559*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1560*3ff40c12SJohn Marino 1561*3ff40c12SJohn Marino ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 1562*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 1563*3ff40c12SJohn Marino } 1564*3ff40c12SJohn Marino 1565*3ff40c12SJohn Marino 1566*3ff40c12SJohn Marino static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 1567*3ff40c12SJohn Marino int preauth) 1568*3ff40c12SJohn Marino { 1569*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1570*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1571*3ff40c12SJohn Marino if (preauth) 1572*3ff40c12SJohn Marino rsn_preauth_finished(hapd, sta, success); 1573*3ff40c12SJohn Marino else 1574*3ff40c12SJohn Marino ieee802_1x_finished(hapd, sta, success); 1575*3ff40c12SJohn Marino } 1576*3ff40c12SJohn Marino 1577*3ff40c12SJohn Marino 1578*3ff40c12SJohn Marino static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 1579*3ff40c12SJohn Marino size_t identity_len, int phase2, 1580*3ff40c12SJohn Marino struct eap_user *user) 1581*3ff40c12SJohn Marino { 1582*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1583*3ff40c12SJohn Marino const struct hostapd_eap_user *eap_user; 1584*3ff40c12SJohn Marino int i; 1585*3ff40c12SJohn Marino 1586*3ff40c12SJohn Marino eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 1587*3ff40c12SJohn Marino if (eap_user == NULL) 1588*3ff40c12SJohn Marino return -1; 1589*3ff40c12SJohn Marino 1590*3ff40c12SJohn Marino os_memset(user, 0, sizeof(*user)); 1591*3ff40c12SJohn Marino user->phase2 = phase2; 1592*3ff40c12SJohn Marino for (i = 0; i < EAP_MAX_METHODS; i++) { 1593*3ff40c12SJohn Marino user->methods[i].vendor = eap_user->methods[i].vendor; 1594*3ff40c12SJohn Marino user->methods[i].method = eap_user->methods[i].method; 1595*3ff40c12SJohn Marino } 1596*3ff40c12SJohn Marino 1597*3ff40c12SJohn Marino if (eap_user->password) { 1598*3ff40c12SJohn Marino user->password = os_malloc(eap_user->password_len); 1599*3ff40c12SJohn Marino if (user->password == NULL) 1600*3ff40c12SJohn Marino return -1; 1601*3ff40c12SJohn Marino os_memcpy(user->password, eap_user->password, 1602*3ff40c12SJohn Marino eap_user->password_len); 1603*3ff40c12SJohn Marino user->password_len = eap_user->password_len; 1604*3ff40c12SJohn Marino user->password_hash = eap_user->password_hash; 1605*3ff40c12SJohn Marino } 1606*3ff40c12SJohn Marino user->force_version = eap_user->force_version; 1607*3ff40c12SJohn Marino user->ttls_auth = eap_user->ttls_auth; 1608*3ff40c12SJohn Marino 1609*3ff40c12SJohn Marino return 0; 1610*3ff40c12SJohn Marino } 1611*3ff40c12SJohn Marino 1612*3ff40c12SJohn Marino 1613*3ff40c12SJohn Marino static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 1614*3ff40c12SJohn Marino { 1615*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1616*3ff40c12SJohn Marino struct sta_info *sta; 1617*3ff40c12SJohn Marino sta = ap_get_sta(hapd, addr); 1618*3ff40c12SJohn Marino if (sta == NULL || sta->eapol_sm == NULL) 1619*3ff40c12SJohn Marino return 0; 1620*3ff40c12SJohn Marino return 1; 1621*3ff40c12SJohn Marino } 1622*3ff40c12SJohn Marino 1623*3ff40c12SJohn Marino 1624*3ff40c12SJohn Marino static void ieee802_1x_logger(void *ctx, const u8 *addr, 1625*3ff40c12SJohn Marino eapol_logger_level level, const char *txt) 1626*3ff40c12SJohn Marino { 1627*3ff40c12SJohn Marino #ifndef CONFIG_NO_HOSTAPD_LOGGER 1628*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1629*3ff40c12SJohn Marino int hlevel; 1630*3ff40c12SJohn Marino 1631*3ff40c12SJohn Marino switch (level) { 1632*3ff40c12SJohn Marino case EAPOL_LOGGER_WARNING: 1633*3ff40c12SJohn Marino hlevel = HOSTAPD_LEVEL_WARNING; 1634*3ff40c12SJohn Marino break; 1635*3ff40c12SJohn Marino case EAPOL_LOGGER_INFO: 1636*3ff40c12SJohn Marino hlevel = HOSTAPD_LEVEL_INFO; 1637*3ff40c12SJohn Marino break; 1638*3ff40c12SJohn Marino case EAPOL_LOGGER_DEBUG: 1639*3ff40c12SJohn Marino default: 1640*3ff40c12SJohn Marino hlevel = HOSTAPD_LEVEL_DEBUG; 1641*3ff40c12SJohn Marino break; 1642*3ff40c12SJohn Marino } 1643*3ff40c12SJohn Marino 1644*3ff40c12SJohn Marino hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 1645*3ff40c12SJohn Marino txt); 1646*3ff40c12SJohn Marino #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 1647*3ff40c12SJohn Marino } 1648*3ff40c12SJohn Marino 1649*3ff40c12SJohn Marino 1650*3ff40c12SJohn Marino static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 1651*3ff40c12SJohn Marino int authorized) 1652*3ff40c12SJohn Marino { 1653*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1654*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1655*3ff40c12SJohn Marino ieee802_1x_set_sta_authorized(hapd, sta, authorized); 1656*3ff40c12SJohn Marino } 1657*3ff40c12SJohn Marino 1658*3ff40c12SJohn Marino 1659*3ff40c12SJohn Marino static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 1660*3ff40c12SJohn Marino { 1661*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1662*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1663*3ff40c12SJohn Marino ieee802_1x_abort_auth(hapd, sta); 1664*3ff40c12SJohn Marino } 1665*3ff40c12SJohn Marino 1666*3ff40c12SJohn Marino 1667*3ff40c12SJohn Marino static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 1668*3ff40c12SJohn Marino { 1669*3ff40c12SJohn Marino struct hostapd_data *hapd = ctx; 1670*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1671*3ff40c12SJohn Marino ieee802_1x_tx_key(hapd, sta); 1672*3ff40c12SJohn Marino } 1673*3ff40c12SJohn Marino 1674*3ff40c12SJohn Marino 1675*3ff40c12SJohn Marino static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 1676*3ff40c12SJohn Marino enum eapol_event type) 1677*3ff40c12SJohn Marino { 1678*3ff40c12SJohn Marino /* struct hostapd_data *hapd = ctx; */ 1679*3ff40c12SJohn Marino struct sta_info *sta = sta_ctx; 1680*3ff40c12SJohn Marino switch (type) { 1681*3ff40c12SJohn Marino case EAPOL_AUTH_SM_CHANGE: 1682*3ff40c12SJohn Marino wpa_auth_sm_notify(sta->wpa_sm); 1683*3ff40c12SJohn Marino break; 1684*3ff40c12SJohn Marino case EAPOL_AUTH_REAUTHENTICATE: 1685*3ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1686*3ff40c12SJohn Marino break; 1687*3ff40c12SJohn Marino } 1688*3ff40c12SJohn Marino } 1689*3ff40c12SJohn Marino 1690*3ff40c12SJohn Marino 1691*3ff40c12SJohn Marino int ieee802_1x_init(struct hostapd_data *hapd) 1692*3ff40c12SJohn Marino { 1693*3ff40c12SJohn Marino int i; 1694*3ff40c12SJohn Marino struct eapol_auth_config conf; 1695*3ff40c12SJohn Marino struct eapol_auth_cb cb; 1696*3ff40c12SJohn Marino 1697*3ff40c12SJohn Marino os_memset(&conf, 0, sizeof(conf)); 1698*3ff40c12SJohn Marino conf.ctx = hapd; 1699*3ff40c12SJohn Marino conf.eap_reauth_period = hapd->conf->eap_reauth_period; 1700*3ff40c12SJohn Marino conf.wpa = hapd->conf->wpa; 1701*3ff40c12SJohn Marino conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 1702*3ff40c12SJohn Marino conf.eap_server = hapd->conf->eap_server; 1703*3ff40c12SJohn Marino conf.ssl_ctx = hapd->ssl_ctx; 1704*3ff40c12SJohn Marino conf.msg_ctx = hapd->msg_ctx; 1705*3ff40c12SJohn Marino conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 1706*3ff40c12SJohn Marino conf.eap_req_id_text = hapd->conf->eap_req_id_text; 1707*3ff40c12SJohn Marino conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 1708*3ff40c12SJohn Marino conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 1709*3ff40c12SJohn Marino conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 1710*3ff40c12SJohn Marino conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 1711*3ff40c12SJohn Marino conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 1712*3ff40c12SJohn Marino conf.eap_fast_prov = hapd->conf->eap_fast_prov; 1713*3ff40c12SJohn Marino conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 1714*3ff40c12SJohn Marino conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 1715*3ff40c12SJohn Marino conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 1716*3ff40c12SJohn Marino conf.tnc = hapd->conf->tnc; 1717*3ff40c12SJohn Marino conf.wps = hapd->wps; 1718*3ff40c12SJohn Marino conf.fragment_size = hapd->conf->fragment_size; 1719*3ff40c12SJohn Marino conf.pwd_group = hapd->conf->pwd_group; 1720*3ff40c12SJohn Marino conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 1721*3ff40c12SJohn Marino if (hapd->conf->server_id) { 1722*3ff40c12SJohn Marino conf.server_id = (const u8 *) hapd->conf->server_id; 1723*3ff40c12SJohn Marino conf.server_id_len = os_strlen(hapd->conf->server_id); 1724*3ff40c12SJohn Marino } else { 1725*3ff40c12SJohn Marino conf.server_id = (const u8 *) "hostapd"; 1726*3ff40c12SJohn Marino conf.server_id_len = 7; 1727*3ff40c12SJohn Marino } 1728*3ff40c12SJohn Marino 1729*3ff40c12SJohn Marino os_memset(&cb, 0, sizeof(cb)); 1730*3ff40c12SJohn Marino cb.eapol_send = ieee802_1x_eapol_send; 1731*3ff40c12SJohn Marino cb.aaa_send = ieee802_1x_aaa_send; 1732*3ff40c12SJohn Marino cb.finished = _ieee802_1x_finished; 1733*3ff40c12SJohn Marino cb.get_eap_user = ieee802_1x_get_eap_user; 1734*3ff40c12SJohn Marino cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 1735*3ff40c12SJohn Marino cb.logger = ieee802_1x_logger; 1736*3ff40c12SJohn Marino cb.set_port_authorized = ieee802_1x_set_port_authorized; 1737*3ff40c12SJohn Marino cb.abort_auth = _ieee802_1x_abort_auth; 1738*3ff40c12SJohn Marino cb.tx_key = _ieee802_1x_tx_key; 1739*3ff40c12SJohn Marino cb.eapol_event = ieee802_1x_eapol_event; 1740*3ff40c12SJohn Marino 1741*3ff40c12SJohn Marino hapd->eapol_auth = eapol_auth_init(&conf, &cb); 1742*3ff40c12SJohn Marino if (hapd->eapol_auth == NULL) 1743*3ff40c12SJohn Marino return -1; 1744*3ff40c12SJohn Marino 1745*3ff40c12SJohn Marino if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 1746*3ff40c12SJohn Marino hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 1747*3ff40c12SJohn Marino return -1; 1748*3ff40c12SJohn Marino 1749*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS 1750*3ff40c12SJohn Marino if (radius_client_register(hapd->radius, RADIUS_AUTH, 1751*3ff40c12SJohn Marino ieee802_1x_receive_auth, hapd)) 1752*3ff40c12SJohn Marino return -1; 1753*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */ 1754*3ff40c12SJohn Marino 1755*3ff40c12SJohn Marino if (hapd->conf->default_wep_key_len) { 1756*3ff40c12SJohn Marino for (i = 0; i < 4; i++) 1757*3ff40c12SJohn Marino hostapd_drv_set_key(hapd->conf->iface, hapd, 1758*3ff40c12SJohn Marino WPA_ALG_NONE, NULL, i, 0, NULL, 0, 1759*3ff40c12SJohn Marino NULL, 0); 1760*3ff40c12SJohn Marino 1761*3ff40c12SJohn Marino ieee802_1x_rekey(hapd, NULL); 1762*3ff40c12SJohn Marino 1763*3ff40c12SJohn Marino if (hapd->eapol_auth->default_wep_key == NULL) 1764*3ff40c12SJohn Marino return -1; 1765*3ff40c12SJohn Marino } 1766*3ff40c12SJohn Marino 1767*3ff40c12SJohn Marino return 0; 1768*3ff40c12SJohn Marino } 1769*3ff40c12SJohn Marino 1770*3ff40c12SJohn Marino 1771*3ff40c12SJohn Marino void ieee802_1x_deinit(struct hostapd_data *hapd) 1772*3ff40c12SJohn Marino { 1773*3ff40c12SJohn Marino eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 1774*3ff40c12SJohn Marino 1775*3ff40c12SJohn Marino if (hapd->driver != NULL && 1776*3ff40c12SJohn Marino (hapd->conf->ieee802_1x || hapd->conf->wpa)) 1777*3ff40c12SJohn Marino hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 1778*3ff40c12SJohn Marino 1779*3ff40c12SJohn Marino eapol_auth_deinit(hapd->eapol_auth); 1780*3ff40c12SJohn Marino hapd->eapol_auth = NULL; 1781*3ff40c12SJohn Marino } 1782*3ff40c12SJohn Marino 1783*3ff40c12SJohn Marino 1784*3ff40c12SJohn Marino int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 1785*3ff40c12SJohn Marino const u8 *buf, size_t len, int ack) 1786*3ff40c12SJohn Marino { 1787*3ff40c12SJohn Marino struct ieee80211_hdr *hdr; 1788*3ff40c12SJohn Marino u8 *pos; 1789*3ff40c12SJohn Marino const unsigned char rfc1042_hdr[ETH_ALEN] = 1790*3ff40c12SJohn Marino { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 1791*3ff40c12SJohn Marino 1792*3ff40c12SJohn Marino if (sta == NULL) 1793*3ff40c12SJohn Marino return -1; 1794*3ff40c12SJohn Marino if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 1795*3ff40c12SJohn Marino return 0; 1796*3ff40c12SJohn Marino 1797*3ff40c12SJohn Marino hdr = (struct ieee80211_hdr *) buf; 1798*3ff40c12SJohn Marino pos = (u8 *) (hdr + 1); 1799*3ff40c12SJohn Marino if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 1800*3ff40c12SJohn Marino return 0; 1801*3ff40c12SJohn Marino pos += sizeof(rfc1042_hdr); 1802*3ff40c12SJohn Marino if (WPA_GET_BE16(pos) != ETH_P_PAE) 1803*3ff40c12SJohn Marino return 0; 1804*3ff40c12SJohn Marino pos += 2; 1805*3ff40c12SJohn Marino 1806*3ff40c12SJohn Marino return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 1807*3ff40c12SJohn Marino ack); 1808*3ff40c12SJohn Marino } 1809*3ff40c12SJohn Marino 1810*3ff40c12SJohn Marino 1811*3ff40c12SJohn Marino int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 1812*3ff40c12SJohn Marino const u8 *buf, int len, int ack) 1813*3ff40c12SJohn Marino { 1814*3ff40c12SJohn Marino const struct ieee802_1x_hdr *xhdr = 1815*3ff40c12SJohn Marino (const struct ieee802_1x_hdr *) buf; 1816*3ff40c12SJohn Marino const u8 *pos = buf + sizeof(*xhdr); 1817*3ff40c12SJohn Marino struct ieee802_1x_eapol_key *key; 1818*3ff40c12SJohn Marino 1819*3ff40c12SJohn Marino if (len < (int) sizeof(*xhdr)) 1820*3ff40c12SJohn Marino return 0; 1821*3ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 1822*3ff40c12SJohn Marino "type=%d length=%d - ack=%d", 1823*3ff40c12SJohn Marino MAC2STR(sta->addr), xhdr->version, xhdr->type, 1824*3ff40c12SJohn Marino be_to_host16(xhdr->length), ack); 1825*3ff40c12SJohn Marino 1826*3ff40c12SJohn Marino if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 1827*3ff40c12SJohn Marino return 0; 1828*3ff40c12SJohn Marino 1829*3ff40c12SJohn Marino if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 1830*3ff40c12SJohn Marino const struct wpa_eapol_key *wpa; 1831*3ff40c12SJohn Marino wpa = (const struct wpa_eapol_key *) pos; 1832*3ff40c12SJohn Marino if (wpa->type == EAPOL_KEY_TYPE_RSN || 1833*3ff40c12SJohn Marino wpa->type == EAPOL_KEY_TYPE_WPA) 1834*3ff40c12SJohn Marino wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 1835*3ff40c12SJohn Marino sta->wpa_sm, ack); 1836*3ff40c12SJohn Marino } 1837*3ff40c12SJohn Marino 1838*3ff40c12SJohn Marino /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 1839*3ff40c12SJohn Marino * or Authenticator state machines, but EAPOL-Key packets are not 1840*3ff40c12SJohn Marino * retransmitted in case of failure. Try to re-send failed EAPOL-Key 1841*3ff40c12SJohn Marino * packets couple of times because otherwise STA keys become 1842*3ff40c12SJohn Marino * unsynchronized with AP. */ 1843*3ff40c12SJohn Marino if (!ack && pos + sizeof(*key) <= buf + len) { 1844*3ff40c12SJohn Marino key = (struct ieee802_1x_eapol_key *) pos; 1845*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1846*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 1847*3ff40c12SJohn Marino "frame (%scast index=%d)", 1848*3ff40c12SJohn Marino key->key_index & BIT(7) ? "uni" : "broad", 1849*3ff40c12SJohn Marino key->key_index & ~BIT(7)); 1850*3ff40c12SJohn Marino /* TODO: re-send EAPOL-Key couple of times (with short delay 1851*3ff40c12SJohn Marino * between them?). If all attempt fail, report error and 1852*3ff40c12SJohn Marino * deauthenticate STA so that it will get new keys when 1853*3ff40c12SJohn Marino * authenticating again (e.g., after returning in range). 1854*3ff40c12SJohn Marino * Separate limit/transmit state needed both for unicast and 1855*3ff40c12SJohn Marino * broadcast keys(?) */ 1856*3ff40c12SJohn Marino } 1857*3ff40c12SJohn Marino /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 1858*3ff40c12SJohn Marino * to here and change the key only if the EAPOL-Key packet was Acked. 1859*3ff40c12SJohn Marino */ 1860*3ff40c12SJohn Marino 1861*3ff40c12SJohn Marino return 1; 1862*3ff40c12SJohn Marino } 1863*3ff40c12SJohn Marino 1864*3ff40c12SJohn Marino 1865*3ff40c12SJohn Marino u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 1866*3ff40c12SJohn Marino { 1867*3ff40c12SJohn Marino if (sm == NULL || sm->identity == NULL) 1868*3ff40c12SJohn Marino return NULL; 1869*3ff40c12SJohn Marino 1870*3ff40c12SJohn Marino *len = sm->identity_len; 1871*3ff40c12SJohn Marino return sm->identity; 1872*3ff40c12SJohn Marino } 1873*3ff40c12SJohn Marino 1874*3ff40c12SJohn Marino 1875*3ff40c12SJohn Marino u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 1876*3ff40c12SJohn Marino int idx) 1877*3ff40c12SJohn Marino { 1878*3ff40c12SJohn Marino if (sm == NULL || sm->radius_class.attr == NULL || 1879*3ff40c12SJohn Marino idx >= (int) sm->radius_class.count) 1880*3ff40c12SJohn Marino return NULL; 1881*3ff40c12SJohn Marino 1882*3ff40c12SJohn Marino *len = sm->radius_class.attr[idx].len; 1883*3ff40c12SJohn Marino return sm->radius_class.attr[idx].data; 1884*3ff40c12SJohn Marino } 1885*3ff40c12SJohn Marino 1886*3ff40c12SJohn Marino 1887*3ff40c12SJohn Marino struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 1888*3ff40c12SJohn Marino { 1889*3ff40c12SJohn Marino if (sm == NULL) 1890*3ff40c12SJohn Marino return NULL; 1891*3ff40c12SJohn Marino return sm->radius_cui; 1892*3ff40c12SJohn Marino } 1893*3ff40c12SJohn Marino 1894*3ff40c12SJohn Marino 1895*3ff40c12SJohn Marino const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 1896*3ff40c12SJohn Marino { 1897*3ff40c12SJohn Marino *len = 0; 1898*3ff40c12SJohn Marino if (sm == NULL) 1899*3ff40c12SJohn Marino return NULL; 1900*3ff40c12SJohn Marino 1901*3ff40c12SJohn Marino *len = sm->eap_if->eapKeyDataLen; 1902*3ff40c12SJohn Marino return sm->eap_if->eapKeyData; 1903*3ff40c12SJohn Marino } 1904*3ff40c12SJohn Marino 1905*3ff40c12SJohn Marino 1906*3ff40c12SJohn Marino void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 1907*3ff40c12SJohn Marino int enabled) 1908*3ff40c12SJohn Marino { 1909*3ff40c12SJohn Marino if (sm == NULL) 1910*3ff40c12SJohn Marino return; 1911*3ff40c12SJohn Marino sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 1912*3ff40c12SJohn Marino eapol_auth_step(sm); 1913*3ff40c12SJohn Marino } 1914*3ff40c12SJohn Marino 1915*3ff40c12SJohn Marino 1916*3ff40c12SJohn Marino void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 1917*3ff40c12SJohn Marino int valid) 1918*3ff40c12SJohn Marino { 1919*3ff40c12SJohn Marino if (sm == NULL) 1920*3ff40c12SJohn Marino return; 1921*3ff40c12SJohn Marino sm->portValid = valid ? TRUE : FALSE; 1922*3ff40c12SJohn Marino eapol_auth_step(sm); 1923*3ff40c12SJohn Marino } 1924*3ff40c12SJohn Marino 1925*3ff40c12SJohn Marino 1926*3ff40c12SJohn Marino void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 1927*3ff40c12SJohn Marino { 1928*3ff40c12SJohn Marino if (sm == NULL) 1929*3ff40c12SJohn Marino return; 1930*3ff40c12SJohn Marino if (pre_auth) 1931*3ff40c12SJohn Marino sm->flags |= EAPOL_SM_PREAUTH; 1932*3ff40c12SJohn Marino else 1933*3ff40c12SJohn Marino sm->flags &= ~EAPOL_SM_PREAUTH; 1934*3ff40c12SJohn Marino } 1935*3ff40c12SJohn Marino 1936*3ff40c12SJohn Marino 1937*3ff40c12SJohn Marino static const char * bool_txt(Boolean bool) 1938*3ff40c12SJohn Marino { 1939*3ff40c12SJohn Marino return bool ? "TRUE" : "FALSE"; 1940*3ff40c12SJohn Marino } 1941*3ff40c12SJohn Marino 1942*3ff40c12SJohn Marino 1943*3ff40c12SJohn Marino int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 1944*3ff40c12SJohn Marino { 1945*3ff40c12SJohn Marino /* TODO */ 1946*3ff40c12SJohn Marino return 0; 1947*3ff40c12SJohn Marino } 1948*3ff40c12SJohn Marino 1949*3ff40c12SJohn Marino 1950*3ff40c12SJohn Marino int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 1951*3ff40c12SJohn Marino char *buf, size_t buflen) 1952*3ff40c12SJohn Marino { 1953*3ff40c12SJohn Marino int len = 0, ret; 1954*3ff40c12SJohn Marino struct eapol_state_machine *sm = sta->eapol_sm; 1955*3ff40c12SJohn Marino struct os_reltime diff; 1956*3ff40c12SJohn Marino 1957*3ff40c12SJohn Marino if (sm == NULL) 1958*3ff40c12SJohn Marino return 0; 1959*3ff40c12SJohn Marino 1960*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 1961*3ff40c12SJohn Marino "dot1xPaePortNumber=%d\n" 1962*3ff40c12SJohn Marino "dot1xPaePortProtocolVersion=%d\n" 1963*3ff40c12SJohn Marino "dot1xPaePortCapabilities=1\n" 1964*3ff40c12SJohn Marino "dot1xPaePortInitialize=%d\n" 1965*3ff40c12SJohn Marino "dot1xPaePortReauthenticate=FALSE\n", 1966*3ff40c12SJohn Marino sta->aid, 1967*3ff40c12SJohn Marino EAPOL_VERSION, 1968*3ff40c12SJohn Marino sm->initialize); 1969*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 1970*3ff40c12SJohn Marino return len; 1971*3ff40c12SJohn Marino len += ret; 1972*3ff40c12SJohn Marino 1973*3ff40c12SJohn Marino /* dot1xAuthConfigTable */ 1974*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 1975*3ff40c12SJohn Marino "dot1xAuthPaeState=%d\n" 1976*3ff40c12SJohn Marino "dot1xAuthBackendAuthState=%d\n" 1977*3ff40c12SJohn Marino "dot1xAuthAdminControlledDirections=%d\n" 1978*3ff40c12SJohn Marino "dot1xAuthOperControlledDirections=%d\n" 1979*3ff40c12SJohn Marino "dot1xAuthAuthControlledPortStatus=%d\n" 1980*3ff40c12SJohn Marino "dot1xAuthAuthControlledPortControl=%d\n" 1981*3ff40c12SJohn Marino "dot1xAuthQuietPeriod=%u\n" 1982*3ff40c12SJohn Marino "dot1xAuthServerTimeout=%u\n" 1983*3ff40c12SJohn Marino "dot1xAuthReAuthPeriod=%u\n" 1984*3ff40c12SJohn Marino "dot1xAuthReAuthEnabled=%s\n" 1985*3ff40c12SJohn Marino "dot1xAuthKeyTxEnabled=%s\n", 1986*3ff40c12SJohn Marino sm->auth_pae_state + 1, 1987*3ff40c12SJohn Marino sm->be_auth_state + 1, 1988*3ff40c12SJohn Marino sm->adminControlledDirections, 1989*3ff40c12SJohn Marino sm->operControlledDirections, 1990*3ff40c12SJohn Marino sm->authPortStatus, 1991*3ff40c12SJohn Marino sm->portControl, 1992*3ff40c12SJohn Marino sm->quietPeriod, 1993*3ff40c12SJohn Marino sm->serverTimeout, 1994*3ff40c12SJohn Marino sm->reAuthPeriod, 1995*3ff40c12SJohn Marino bool_txt(sm->reAuthEnabled), 1996*3ff40c12SJohn Marino bool_txt(sm->keyTxEnabled)); 1997*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 1998*3ff40c12SJohn Marino return len; 1999*3ff40c12SJohn Marino len += ret; 2000*3ff40c12SJohn Marino 2001*3ff40c12SJohn Marino /* dot1xAuthStatsTable */ 2002*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 2003*3ff40c12SJohn Marino "dot1xAuthEapolFramesRx=%u\n" 2004*3ff40c12SJohn Marino "dot1xAuthEapolFramesTx=%u\n" 2005*3ff40c12SJohn Marino "dot1xAuthEapolStartFramesRx=%u\n" 2006*3ff40c12SJohn Marino "dot1xAuthEapolLogoffFramesRx=%u\n" 2007*3ff40c12SJohn Marino "dot1xAuthEapolRespIdFramesRx=%u\n" 2008*3ff40c12SJohn Marino "dot1xAuthEapolRespFramesRx=%u\n" 2009*3ff40c12SJohn Marino "dot1xAuthEapolReqIdFramesTx=%u\n" 2010*3ff40c12SJohn Marino "dot1xAuthEapolReqFramesTx=%u\n" 2011*3ff40c12SJohn Marino "dot1xAuthInvalidEapolFramesRx=%u\n" 2012*3ff40c12SJohn Marino "dot1xAuthEapLengthErrorFramesRx=%u\n" 2013*3ff40c12SJohn Marino "dot1xAuthLastEapolFrameVersion=%u\n" 2014*3ff40c12SJohn Marino "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2015*3ff40c12SJohn Marino sm->dot1xAuthEapolFramesRx, 2016*3ff40c12SJohn Marino sm->dot1xAuthEapolFramesTx, 2017*3ff40c12SJohn Marino sm->dot1xAuthEapolStartFramesRx, 2018*3ff40c12SJohn Marino sm->dot1xAuthEapolLogoffFramesRx, 2019*3ff40c12SJohn Marino sm->dot1xAuthEapolRespIdFramesRx, 2020*3ff40c12SJohn Marino sm->dot1xAuthEapolRespFramesRx, 2021*3ff40c12SJohn Marino sm->dot1xAuthEapolReqIdFramesTx, 2022*3ff40c12SJohn Marino sm->dot1xAuthEapolReqFramesTx, 2023*3ff40c12SJohn Marino sm->dot1xAuthInvalidEapolFramesRx, 2024*3ff40c12SJohn Marino sm->dot1xAuthEapLengthErrorFramesRx, 2025*3ff40c12SJohn Marino sm->dot1xAuthLastEapolFrameVersion, 2026*3ff40c12SJohn Marino MAC2STR(sm->addr)); 2027*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 2028*3ff40c12SJohn Marino return len; 2029*3ff40c12SJohn Marino len += ret; 2030*3ff40c12SJohn Marino 2031*3ff40c12SJohn Marino /* dot1xAuthDiagTable */ 2032*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 2033*3ff40c12SJohn Marino "dot1xAuthEntersConnecting=%u\n" 2034*3ff40c12SJohn Marino "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2035*3ff40c12SJohn Marino "dot1xAuthEntersAuthenticating=%u\n" 2036*3ff40c12SJohn Marino "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2037*3ff40c12SJohn Marino "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2038*3ff40c12SJohn Marino "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2039*3ff40c12SJohn Marino "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2040*3ff40c12SJohn Marino "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2041*3ff40c12SJohn Marino "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2042*3ff40c12SJohn Marino "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2043*3ff40c12SJohn Marino "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2044*3ff40c12SJohn Marino "dot1xAuthBackendResponses=%u\n" 2045*3ff40c12SJohn Marino "dot1xAuthBackendAccessChallenges=%u\n" 2046*3ff40c12SJohn Marino "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2047*3ff40c12SJohn Marino "dot1xAuthBackendAuthSuccesses=%u\n" 2048*3ff40c12SJohn Marino "dot1xAuthBackendAuthFails=%u\n", 2049*3ff40c12SJohn Marino sm->authEntersConnecting, 2050*3ff40c12SJohn Marino sm->authEapLogoffsWhileConnecting, 2051*3ff40c12SJohn Marino sm->authEntersAuthenticating, 2052*3ff40c12SJohn Marino sm->authAuthSuccessesWhileAuthenticating, 2053*3ff40c12SJohn Marino sm->authAuthTimeoutsWhileAuthenticating, 2054*3ff40c12SJohn Marino sm->authAuthFailWhileAuthenticating, 2055*3ff40c12SJohn Marino sm->authAuthEapStartsWhileAuthenticating, 2056*3ff40c12SJohn Marino sm->authAuthEapLogoffWhileAuthenticating, 2057*3ff40c12SJohn Marino sm->authAuthReauthsWhileAuthenticated, 2058*3ff40c12SJohn Marino sm->authAuthEapStartsWhileAuthenticated, 2059*3ff40c12SJohn Marino sm->authAuthEapLogoffWhileAuthenticated, 2060*3ff40c12SJohn Marino sm->backendResponses, 2061*3ff40c12SJohn Marino sm->backendAccessChallenges, 2062*3ff40c12SJohn Marino sm->backendOtherRequestsToSupplicant, 2063*3ff40c12SJohn Marino sm->backendAuthSuccesses, 2064*3ff40c12SJohn Marino sm->backendAuthFails); 2065*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 2066*3ff40c12SJohn Marino return len; 2067*3ff40c12SJohn Marino len += ret; 2068*3ff40c12SJohn Marino 2069*3ff40c12SJohn Marino /* dot1xAuthSessionStatsTable */ 2070*3ff40c12SJohn Marino os_reltime_age(&sta->acct_session_start, &diff); 2071*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 2072*3ff40c12SJohn Marino /* TODO: dot1xAuthSessionOctetsRx */ 2073*3ff40c12SJohn Marino /* TODO: dot1xAuthSessionOctetsTx */ 2074*3ff40c12SJohn Marino /* TODO: dot1xAuthSessionFramesRx */ 2075*3ff40c12SJohn Marino /* TODO: dot1xAuthSessionFramesTx */ 2076*3ff40c12SJohn Marino "dot1xAuthSessionId=%08X-%08X\n" 2077*3ff40c12SJohn Marino "dot1xAuthSessionAuthenticMethod=%d\n" 2078*3ff40c12SJohn Marino "dot1xAuthSessionTime=%u\n" 2079*3ff40c12SJohn Marino "dot1xAuthSessionTerminateCause=999\n" 2080*3ff40c12SJohn Marino "dot1xAuthSessionUserName=%s\n", 2081*3ff40c12SJohn Marino sta->acct_session_id_hi, sta->acct_session_id_lo, 2082*3ff40c12SJohn Marino (wpa_key_mgmt_wpa_ieee8021x( 2083*3ff40c12SJohn Marino wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2084*3ff40c12SJohn Marino 1 : 2, 2085*3ff40c12SJohn Marino (unsigned int) diff.sec, 2086*3ff40c12SJohn Marino sm->identity); 2087*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 2088*3ff40c12SJohn Marino return len; 2089*3ff40c12SJohn Marino len += ret; 2090*3ff40c12SJohn Marino 2091*3ff40c12SJohn Marino ret = os_snprintf(buf + len, buflen - len, 2092*3ff40c12SJohn Marino "last_eap_type_as=%d (%s)\n" 2093*3ff40c12SJohn Marino "last_eap_type_sta=%d (%s)\n", 2094*3ff40c12SJohn Marino sm->eap_type_authsrv, 2095*3ff40c12SJohn Marino eap_server_get_name(0, sm->eap_type_authsrv), 2096*3ff40c12SJohn Marino sm->eap_type_supp, 2097*3ff40c12SJohn Marino eap_server_get_name(0, sm->eap_type_supp)); 2098*3ff40c12SJohn Marino if (ret < 0 || (size_t) ret >= buflen - len) 2099*3ff40c12SJohn Marino return len; 2100*3ff40c12SJohn Marino len += ret; 2101*3ff40c12SJohn Marino 2102*3ff40c12SJohn Marino return len; 2103*3ff40c12SJohn Marino } 2104*3ff40c12SJohn Marino 2105*3ff40c12SJohn Marino 2106*3ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd, 2107*3ff40c12SJohn Marino struct sta_info *sta, int success) 2108*3ff40c12SJohn Marino { 2109*3ff40c12SJohn Marino const u8 *key; 2110*3ff40c12SJohn Marino size_t len; 2111*3ff40c12SJohn Marino /* TODO: get PMKLifetime from WPA parameters */ 2112*3ff40c12SJohn Marino static const int dot11RSNAConfigPMKLifetime = 43200; 2113*3ff40c12SJohn Marino 2114*3ff40c12SJohn Marino key = ieee802_1x_get_key(sta->eapol_sm, &len); 2115*3ff40c12SJohn Marino if (success && key && len >= PMK_LEN && 2116*3ff40c12SJohn Marino wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, 2117*3ff40c12SJohn Marino sta->eapol_sm) == 0) { 2118*3ff40c12SJohn Marino hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2119*3ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, 2120*3ff40c12SJohn Marino "Added PMKSA cache entry (IEEE 802.1X)"); 2121*3ff40c12SJohn Marino } 2122*3ff40c12SJohn Marino 2123*3ff40c12SJohn Marino if (!success) { 2124*3ff40c12SJohn Marino /* 2125*3ff40c12SJohn Marino * Many devices require deauthentication after WPS provisioning 2126*3ff40c12SJohn Marino * and some may not be be able to do that themselves, so 2127*3ff40c12SJohn Marino * disconnect the client here. In addition, this may also 2128*3ff40c12SJohn Marino * benefit IEEE 802.1X/EAPOL authentication cases, too since 2129*3ff40c12SJohn Marino * the EAPOL PAE state machine would remain in HELD state for 2130*3ff40c12SJohn Marino * considerable amount of time and some EAP methods, like 2131*3ff40c12SJohn Marino * EAP-FAST with anonymous provisioning, may require another 2132*3ff40c12SJohn Marino * EAPOL authentication to be started to complete connection. 2133*3ff40c12SJohn Marino */ 2134*3ff40c12SJohn Marino wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force " 2135*3ff40c12SJohn Marino "disconnection after EAP-Failure"); 2136*3ff40c12SJohn Marino /* Add a small sleep to increase likelihood of previously 2137*3ff40c12SJohn Marino * requested EAP-Failure TX getting out before this should the 2138*3ff40c12SJohn Marino * driver reorder operations. 2139*3ff40c12SJohn Marino */ 2140*3ff40c12SJohn Marino os_sleep(0, 10000); 2141*3ff40c12SJohn Marino ap_sta_disconnect(hapd, sta, sta->addr, 2142*3ff40c12SJohn Marino WLAN_REASON_IEEE_802_1X_AUTH_FAILED); 2143*3ff40c12SJohn Marino hostapd_wps_eap_completed(hapd); 2144*3ff40c12SJohn Marino } 2145*3ff40c12SJohn Marino } 2146