ieee802_1x.c revision 252726
1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.1X-2004 Authenticator 3252726Srpaulo * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "crypto/md5.h" 14214501Srpaulo#include "crypto/crypto.h" 15252726Srpaulo#include "crypto/random.h" 16214501Srpaulo#include "common/ieee802_11_defs.h" 17214501Srpaulo#include "radius/radius.h" 18214501Srpaulo#include "radius/radius_client.h" 19214501Srpaulo#include "eap_server/eap.h" 20214501Srpaulo#include "eap_common/eap_wsc_common.h" 21214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 22214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 23252726Srpaulo#include "p2p/p2p.h" 24214501Srpaulo#include "hostapd.h" 25214501Srpaulo#include "accounting.h" 26214501Srpaulo#include "sta_info.h" 27214501Srpaulo#include "wpa_auth.h" 28214501Srpaulo#include "preauth_auth.h" 29214501Srpaulo#include "pmksa_cache_auth.h" 30214501Srpaulo#include "ap_config.h" 31252726Srpaulo#include "ap_drv_ops.h" 32214501Srpaulo#include "ieee802_1x.h" 33214501Srpaulo 34214501Srpaulo 35214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 36214501Srpaulo struct sta_info *sta, int success); 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostatic void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 40214501Srpaulo u8 type, const u8 *data, size_t datalen) 41214501Srpaulo{ 42214501Srpaulo u8 *buf; 43214501Srpaulo struct ieee802_1x_hdr *xhdr; 44214501Srpaulo size_t len; 45214501Srpaulo int encrypt = 0; 46214501Srpaulo 47214501Srpaulo len = sizeof(*xhdr) + datalen; 48214501Srpaulo buf = os_zalloc(len); 49214501Srpaulo if (buf == NULL) { 50214501Srpaulo wpa_printf(MSG_ERROR, "malloc() failed for " 51214501Srpaulo "ieee802_1x_send(len=%lu)", 52214501Srpaulo (unsigned long) len); 53214501Srpaulo return; 54214501Srpaulo } 55214501Srpaulo 56214501Srpaulo xhdr = (struct ieee802_1x_hdr *) buf; 57214501Srpaulo xhdr->version = hapd->conf->eapol_version; 58214501Srpaulo xhdr->type = type; 59214501Srpaulo xhdr->length = host_to_be16(datalen); 60214501Srpaulo 61214501Srpaulo if (datalen > 0 && data != NULL) 62214501Srpaulo os_memcpy(xhdr + 1, data, datalen); 63214501Srpaulo 64214501Srpaulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 65214501Srpaulo encrypt = 1; 66214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 67214501Srpaulo rsn_preauth_send(hapd, sta, buf, len); 68214501Srpaulo } else { 69252726Srpaulo hostapd_drv_hapd_send_eapol( 70252726Srpaulo hapd, sta->addr, buf, len, 71252726Srpaulo encrypt, hostapd_sta_flags_to_drv(sta->flags)); 72214501Srpaulo } 73214501Srpaulo 74214501Srpaulo os_free(buf); 75214501Srpaulo} 76214501Srpaulo 77214501Srpaulo 78214501Srpaulovoid ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 79214501Srpaulo struct sta_info *sta, int authorized) 80214501Srpaulo{ 81214501Srpaulo int res; 82214501Srpaulo 83214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 84214501Srpaulo return; 85214501Srpaulo 86214501Srpaulo if (authorized) { 87252726Srpaulo ap_sta_set_authorized(hapd, sta, 1); 88252726Srpaulo res = hostapd_set_authorized(hapd, sta, 1); 89214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 90214501Srpaulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 91214501Srpaulo } else { 92252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 93252726Srpaulo res = hostapd_set_authorized(hapd, sta, 0); 94214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 95214501Srpaulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 96214501Srpaulo } 97214501Srpaulo 98214501Srpaulo if (res && errno != ENOENT) { 99214501Srpaulo printf("Could not set station " MACSTR " flags for kernel " 100214501Srpaulo "driver (errno=%d).\n", MAC2STR(sta->addr), errno); 101214501Srpaulo } 102214501Srpaulo 103252726Srpaulo if (authorized) { 104252726Srpaulo os_get_time(&sta->connected_time); 105214501Srpaulo accounting_sta_start(hapd, sta); 106252726Srpaulo } 107214501Srpaulo} 108214501Srpaulo 109214501Srpaulo 110214501Srpaulostatic void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 111214501Srpaulo struct sta_info *sta, 112214501Srpaulo int idx, int broadcast, 113214501Srpaulo u8 *key_data, size_t key_len) 114214501Srpaulo{ 115214501Srpaulo u8 *buf, *ekey; 116214501Srpaulo struct ieee802_1x_hdr *hdr; 117214501Srpaulo struct ieee802_1x_eapol_key *key; 118214501Srpaulo size_t len, ekey_len; 119214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 120214501Srpaulo 121214501Srpaulo if (sm == NULL) 122214501Srpaulo return; 123214501Srpaulo 124214501Srpaulo len = sizeof(*key) + key_len; 125214501Srpaulo buf = os_zalloc(sizeof(*hdr) + len); 126214501Srpaulo if (buf == NULL) 127214501Srpaulo return; 128214501Srpaulo 129214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 130214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 131214501Srpaulo key->type = EAPOL_KEY_TYPE_RC4; 132252726Srpaulo WPA_PUT_BE16(key->key_length, key_len); 133214501Srpaulo wpa_get_ntp_timestamp(key->replay_counter); 134214501Srpaulo 135252726Srpaulo if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 136214501Srpaulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 137214501Srpaulo os_free(buf); 138214501Srpaulo return; 139214501Srpaulo } 140214501Srpaulo 141214501Srpaulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 142214501Srpaulo if (hapd->conf->eapol_key_index_workaround) { 143214501Srpaulo /* According to some information, WinXP Supplicant seems to 144214501Srpaulo * interpret bit7 as an indication whether the key is to be 145214501Srpaulo * activated, so make it possible to enable workaround that 146214501Srpaulo * sets this bit for all keys. */ 147214501Srpaulo key->key_index |= BIT(7); 148214501Srpaulo } 149214501Srpaulo 150214501Srpaulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 151214501Srpaulo * MSK[32..63] is used to sign the message. */ 152214501Srpaulo if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 153214501Srpaulo wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 154214501Srpaulo "and signing EAPOL-Key"); 155214501Srpaulo os_free(buf); 156214501Srpaulo return; 157214501Srpaulo } 158214501Srpaulo os_memcpy((u8 *) (key + 1), key_data, key_len); 159214501Srpaulo ekey_len = sizeof(key->key_iv) + 32; 160214501Srpaulo ekey = os_malloc(ekey_len); 161214501Srpaulo if (ekey == NULL) { 162214501Srpaulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 163214501Srpaulo os_free(buf); 164214501Srpaulo return; 165214501Srpaulo } 166214501Srpaulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 167214501Srpaulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 168214501Srpaulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 169214501Srpaulo os_free(ekey); 170214501Srpaulo 171214501Srpaulo /* This header is needed here for HMAC-MD5, but it will be regenerated 172214501Srpaulo * in ieee802_1x_send() */ 173214501Srpaulo hdr->version = hapd->conf->eapol_version; 174214501Srpaulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 175214501Srpaulo hdr->length = host_to_be16(len); 176214501Srpaulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 177214501Srpaulo key->key_signature); 178214501Srpaulo 179214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 180214501Srpaulo " (%s index=%d)", MAC2STR(sm->addr), 181214501Srpaulo broadcast ? "broadcast" : "unicast", idx); 182214501Srpaulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 183214501Srpaulo if (sta->eapol_sm) 184214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 185214501Srpaulo os_free(buf); 186214501Srpaulo} 187214501Srpaulo 188214501Srpaulo 189214501Srpaulo#ifndef CONFIG_NO_VLAN 190214501Srpaulostatic struct hostapd_wep_keys * 191214501Srpauloieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) 192214501Srpaulo{ 193214501Srpaulo struct hostapd_wep_keys *key; 194214501Srpaulo 195214501Srpaulo key = os_zalloc(sizeof(*key)); 196214501Srpaulo if (key == NULL) 197214501Srpaulo return NULL; 198214501Srpaulo 199214501Srpaulo key->default_len = hapd->conf->default_wep_key_len; 200214501Srpaulo 201214501Srpaulo if (key->idx >= hapd->conf->broadcast_key_idx_max || 202214501Srpaulo key->idx < hapd->conf->broadcast_key_idx_min) 203214501Srpaulo key->idx = hapd->conf->broadcast_key_idx_min; 204214501Srpaulo else 205214501Srpaulo key->idx++; 206214501Srpaulo 207214501Srpaulo if (!key->key[key->idx]) 208214501Srpaulo key->key[key->idx] = os_malloc(key->default_len); 209214501Srpaulo if (key->key[key->idx] == NULL || 210252726Srpaulo random_get_bytes(key->key[key->idx], key->default_len)) { 211214501Srpaulo printf("Could not generate random WEP key (dynamic VLAN).\n"); 212214501Srpaulo os_free(key->key[key->idx]); 213214501Srpaulo key->key[key->idx] = NULL; 214214501Srpaulo os_free(key); 215214501Srpaulo return NULL; 216214501Srpaulo } 217214501Srpaulo key->len[key->idx] = key->default_len; 218214501Srpaulo 219214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n", 220214501Srpaulo ifname, key->idx); 221214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)", 222214501Srpaulo key->key[key->idx], key->len[key->idx]); 223214501Srpaulo 224252726Srpaulo if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP, 225252726Srpaulo broadcast_ether_addr, key->idx, 1, 226252726Srpaulo NULL, 0, key->key[key->idx], 227252726Srpaulo key->len[key->idx])) 228214501Srpaulo printf("Could not set dynamic VLAN WEP encryption key.\n"); 229214501Srpaulo 230252726Srpaulo hostapd_set_drv_ieee8021x(hapd, ifname, 1); 231214501Srpaulo 232214501Srpaulo return key; 233214501Srpaulo} 234214501Srpaulo 235214501Srpaulo 236214501Srpaulostatic struct hostapd_wep_keys * 237214501Srpauloieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid, 238214501Srpaulo size_t vlan_id) 239214501Srpaulo{ 240214501Srpaulo const char *ifname; 241214501Srpaulo 242214501Srpaulo if (vlan_id == 0) 243214501Srpaulo return &ssid->wep; 244214501Srpaulo 245214501Srpaulo if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys && 246214501Srpaulo ssid->dyn_vlan_keys[vlan_id]) 247214501Srpaulo return ssid->dyn_vlan_keys[vlan_id]; 248214501Srpaulo 249214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group " 250214501Srpaulo "state machine for VLAN ID %lu", 251214501Srpaulo (unsigned long) vlan_id); 252214501Srpaulo 253214501Srpaulo ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); 254214501Srpaulo if (ifname == NULL) { 255214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - " 256214501Srpaulo "cannot create group key state machine", 257214501Srpaulo (unsigned long) vlan_id); 258214501Srpaulo return NULL; 259214501Srpaulo } 260214501Srpaulo 261214501Srpaulo if (ssid->dyn_vlan_keys == NULL) { 262214501Srpaulo int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); 263214501Srpaulo ssid->dyn_vlan_keys = os_zalloc(size); 264214501Srpaulo if (ssid->dyn_vlan_keys == NULL) 265214501Srpaulo return NULL; 266214501Srpaulo ssid->max_dyn_vlan_keys = vlan_id; 267214501Srpaulo } 268214501Srpaulo 269214501Srpaulo if (ssid->max_dyn_vlan_keys < vlan_id) { 270214501Srpaulo struct hostapd_wep_keys **na; 271214501Srpaulo int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); 272214501Srpaulo na = os_realloc(ssid->dyn_vlan_keys, size); 273214501Srpaulo if (na == NULL) 274214501Srpaulo return NULL; 275214501Srpaulo ssid->dyn_vlan_keys = na; 276214501Srpaulo os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0, 277214501Srpaulo (vlan_id - ssid->max_dyn_vlan_keys) * 278214501Srpaulo sizeof(ssid->dyn_vlan_keys[0])); 279214501Srpaulo ssid->max_dyn_vlan_keys = vlan_id; 280214501Srpaulo } 281214501Srpaulo 282214501Srpaulo ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname); 283214501Srpaulo 284214501Srpaulo return ssid->dyn_vlan_keys[vlan_id]; 285214501Srpaulo} 286214501Srpaulo#endif /* CONFIG_NO_VLAN */ 287214501Srpaulo 288214501Srpaulo 289214501Srpaulovoid ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 290214501Srpaulo{ 291214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 292214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 293214501Srpaulo#ifndef CONFIG_NO_VLAN 294214501Srpaulo struct hostapd_wep_keys *key = NULL; 295214501Srpaulo int vlan_id; 296214501Srpaulo#endif /* CONFIG_NO_VLAN */ 297214501Srpaulo 298214501Srpaulo if (sm == NULL || !sm->eap_if->eapKeyData) 299214501Srpaulo return; 300214501Srpaulo 301214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 302214501Srpaulo MAC2STR(sta->addr)); 303214501Srpaulo 304214501Srpaulo#ifndef CONFIG_NO_VLAN 305214501Srpaulo vlan_id = sta->vlan_id; 306214501Srpaulo if (vlan_id < 0 || vlan_id > MAX_VLAN_ID) 307214501Srpaulo vlan_id = 0; 308214501Srpaulo 309214501Srpaulo if (vlan_id) { 310214501Srpaulo key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id); 311214501Srpaulo if (key && key->key[key->idx]) 312214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, key->idx, 1, 313214501Srpaulo key->key[key->idx], 314214501Srpaulo key->len[key->idx]); 315214501Srpaulo } else 316214501Srpaulo#endif /* CONFIG_NO_VLAN */ 317214501Srpaulo if (eapol->default_wep_key) { 318214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 319214501Srpaulo eapol->default_wep_key, 320214501Srpaulo hapd->conf->default_wep_key_len); 321214501Srpaulo } 322214501Srpaulo 323214501Srpaulo if (hapd->conf->individual_wep_key_len > 0) { 324214501Srpaulo u8 *ikey; 325214501Srpaulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 326214501Srpaulo if (ikey == NULL || 327252726Srpaulo random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 328252726Srpaulo { 329214501Srpaulo wpa_printf(MSG_ERROR, "Could not generate random " 330214501Srpaulo "individual WEP key."); 331214501Srpaulo os_free(ikey); 332214501Srpaulo return; 333214501Srpaulo } 334214501Srpaulo 335214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 336214501Srpaulo ikey, hapd->conf->individual_wep_key_len); 337214501Srpaulo 338214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 339214501Srpaulo hapd->conf->individual_wep_key_len); 340214501Srpaulo 341214501Srpaulo /* TODO: set encryption in TX callback, i.e., only after STA 342214501Srpaulo * has ACKed EAPOL-Key frame */ 343252726Srpaulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 344252726Srpaulo sta->addr, 0, 1, NULL, 0, ikey, 345252726Srpaulo hapd->conf->individual_wep_key_len)) { 346214501Srpaulo wpa_printf(MSG_ERROR, "Could not set individual WEP " 347214501Srpaulo "encryption."); 348214501Srpaulo } 349214501Srpaulo 350214501Srpaulo os_free(ikey); 351214501Srpaulo } 352214501Srpaulo} 353214501Srpaulo 354214501Srpaulo 355214501Srpauloconst char *radius_mode_txt(struct hostapd_data *hapd) 356214501Srpaulo{ 357214501Srpaulo switch (hapd->iface->conf->hw_mode) { 358252726Srpaulo case HOSTAPD_MODE_IEEE80211AD: 359252726Srpaulo return "802.11ad"; 360214501Srpaulo case HOSTAPD_MODE_IEEE80211A: 361214501Srpaulo return "802.11a"; 362214501Srpaulo case HOSTAPD_MODE_IEEE80211G: 363214501Srpaulo return "802.11g"; 364214501Srpaulo case HOSTAPD_MODE_IEEE80211B: 365214501Srpaulo default: 366214501Srpaulo return "802.11b"; 367214501Srpaulo } 368214501Srpaulo} 369214501Srpaulo 370214501Srpaulo 371214501Srpauloint radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 372214501Srpaulo{ 373214501Srpaulo int i; 374214501Srpaulo u8 rate = 0; 375214501Srpaulo 376214501Srpaulo for (i = 0; i < sta->supported_rates_len; i++) 377214501Srpaulo if ((sta->supported_rates[i] & 0x7f) > rate) 378214501Srpaulo rate = sta->supported_rates[i] & 0x7f; 379214501Srpaulo 380214501Srpaulo return rate; 381214501Srpaulo} 382214501Srpaulo 383214501Srpaulo 384214501Srpaulo#ifndef CONFIG_NO_RADIUS 385214501Srpaulostatic void ieee802_1x_learn_identity(struct hostapd_data *hapd, 386214501Srpaulo struct eapol_state_machine *sm, 387214501Srpaulo const u8 *eap, size_t len) 388214501Srpaulo{ 389214501Srpaulo const u8 *identity; 390214501Srpaulo size_t identity_len; 391214501Srpaulo 392214501Srpaulo if (len <= sizeof(struct eap_hdr) || 393214501Srpaulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) 394214501Srpaulo return; 395214501Srpaulo 396214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 397214501Srpaulo if (identity == NULL) 398214501Srpaulo return; 399214501Srpaulo 400214501Srpaulo /* Save station identity for future RADIUS packets */ 401214501Srpaulo os_free(sm->identity); 402214501Srpaulo sm->identity = os_malloc(identity_len + 1); 403214501Srpaulo if (sm->identity == NULL) { 404214501Srpaulo sm->identity_len = 0; 405214501Srpaulo return; 406214501Srpaulo } 407214501Srpaulo 408214501Srpaulo os_memcpy(sm->identity, identity, identity_len); 409214501Srpaulo sm->identity_len = identity_len; 410214501Srpaulo sm->identity[identity_len] = '\0'; 411214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 412214501Srpaulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 413214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx++; 414214501Srpaulo} 415214501Srpaulo 416214501Srpaulo 417252726Srpaulostatic int add_common_radius_sta_attr(struct hostapd_data *hapd, 418252726Srpaulo struct hostapd_radius_attr *req_attr, 419252726Srpaulo struct sta_info *sta, 420252726Srpaulo struct radius_msg *msg) 421252726Srpaulo{ 422252726Srpaulo char buf[128]; 423252726Srpaulo 424252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 425252726Srpaulo RADIUS_ATTR_NAS_PORT) && 426252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 427252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 428252726Srpaulo return -1; 429252726Srpaulo } 430252726Srpaulo 431252726Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 432252726Srpaulo MAC2STR(sta->addr)); 433252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 434252726Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 435252726Srpaulo (u8 *) buf, os_strlen(buf))) { 436252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 437252726Srpaulo return -1; 438252726Srpaulo } 439252726Srpaulo 440252726Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 441252726Srpaulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 442252726Srpaulo sizeof(buf)); 443252726Srpaulo } else { 444252726Srpaulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 445252726Srpaulo radius_sta_rate(hapd, sta) / 2, 446252726Srpaulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 447252726Srpaulo radius_mode_txt(hapd)); 448252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 449252726Srpaulo } 450252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 451252726Srpaulo RADIUS_ATTR_CONNECT_INFO) && 452252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 453252726Srpaulo (u8 *) buf, os_strlen(buf))) { 454252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 455252726Srpaulo return -1; 456252726Srpaulo } 457252726Srpaulo 458252726Srpaulo if (sta->acct_session_id_hi || sta->acct_session_id_lo) { 459252726Srpaulo os_snprintf(buf, sizeof(buf), "%08X-%08X", 460252726Srpaulo sta->acct_session_id_hi, sta->acct_session_id_lo); 461252726Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 462252726Srpaulo (u8 *) buf, os_strlen(buf))) { 463252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 464252726Srpaulo return -1; 465252726Srpaulo } 466252726Srpaulo } 467252726Srpaulo 468252726Srpaulo return 0; 469252726Srpaulo} 470252726Srpaulo 471252726Srpaulo 472252726Srpauloint add_common_radius_attr(struct hostapd_data *hapd, 473252726Srpaulo struct hostapd_radius_attr *req_attr, 474252726Srpaulo struct sta_info *sta, 475252726Srpaulo struct radius_msg *msg) 476252726Srpaulo{ 477252726Srpaulo char buf[128]; 478252726Srpaulo struct hostapd_radius_attr *attr; 479252726Srpaulo 480252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 481252726Srpaulo RADIUS_ATTR_NAS_IP_ADDRESS) && 482252726Srpaulo hapd->conf->own_ip_addr.af == AF_INET && 483252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 484252726Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 485252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 486252726Srpaulo return -1; 487252726Srpaulo } 488252726Srpaulo 489252726Srpaulo#ifdef CONFIG_IPV6 490252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 491252726Srpaulo RADIUS_ATTR_NAS_IPV6_ADDRESS) && 492252726Srpaulo hapd->conf->own_ip_addr.af == AF_INET6 && 493252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 494252726Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 495252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 496252726Srpaulo return -1; 497252726Srpaulo } 498252726Srpaulo#endif /* CONFIG_IPV6 */ 499252726Srpaulo 500252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 501252726Srpaulo RADIUS_ATTR_NAS_IDENTIFIER) && 502252726Srpaulo hapd->conf->nas_identifier && 503252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 504252726Srpaulo (u8 *) hapd->conf->nas_identifier, 505252726Srpaulo os_strlen(hapd->conf->nas_identifier))) { 506252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 507252726Srpaulo return -1; 508252726Srpaulo } 509252726Srpaulo 510252726Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", 511252726Srpaulo MAC2STR(hapd->own_addr), 512252726Srpaulo wpa_ssid_txt(hapd->conf->ssid.ssid, 513252726Srpaulo hapd->conf->ssid.ssid_len)); 514252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 515252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 516252726Srpaulo RADIUS_ATTR_CALLED_STATION_ID) && 517252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 518252726Srpaulo (u8 *) buf, os_strlen(buf))) { 519252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 520252726Srpaulo return -1; 521252726Srpaulo } 522252726Srpaulo 523252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 524252726Srpaulo RADIUS_ATTR_NAS_PORT_TYPE) && 525252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 526252726Srpaulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 527252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 528252726Srpaulo return -1; 529252726Srpaulo } 530252726Srpaulo 531252726Srpaulo if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 532252726Srpaulo return -1; 533252726Srpaulo 534252726Srpaulo for (attr = req_attr; attr; attr = attr->next) { 535252726Srpaulo if (!radius_msg_add_attr(msg, attr->type, 536252726Srpaulo wpabuf_head(attr->val), 537252726Srpaulo wpabuf_len(attr->val))) { 538252726Srpaulo wpa_printf(MSG_ERROR, "Could not add RADIUS " 539252726Srpaulo "attribute"); 540252726Srpaulo return -1; 541252726Srpaulo } 542252726Srpaulo } 543252726Srpaulo 544252726Srpaulo return 0; 545252726Srpaulo} 546252726Srpaulo 547252726Srpaulo 548214501Srpaulostatic void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 549214501Srpaulo struct sta_info *sta, 550214501Srpaulo const u8 *eap, size_t len) 551214501Srpaulo{ 552214501Srpaulo struct radius_msg *msg; 553214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 554214501Srpaulo 555214501Srpaulo if (sm == NULL) 556214501Srpaulo return; 557214501Srpaulo 558214501Srpaulo ieee802_1x_learn_identity(hapd, sm, eap, len); 559214501Srpaulo 560214501Srpaulo wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 561214501Srpaulo "packet"); 562214501Srpaulo 563214501Srpaulo sm->radius_identifier = radius_client_get_id(hapd->radius); 564214501Srpaulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 565214501Srpaulo sm->radius_identifier); 566214501Srpaulo if (msg == NULL) { 567214501Srpaulo printf("Could not create net RADIUS packet\n"); 568214501Srpaulo return; 569214501Srpaulo } 570214501Srpaulo 571214501Srpaulo radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); 572214501Srpaulo 573214501Srpaulo if (sm->identity && 574214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 575214501Srpaulo sm->identity, sm->identity_len)) { 576214501Srpaulo printf("Could not add User-Name\n"); 577214501Srpaulo goto fail; 578214501Srpaulo } 579214501Srpaulo 580252726Srpaulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 581252726Srpaulo msg) < 0) 582214501Srpaulo goto fail; 583214501Srpaulo 584214501Srpaulo /* TODO: should probably check MTU from driver config; 2304 is max for 585214501Srpaulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 586214501Srpaulo */ 587252726Srpaulo if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 588252726Srpaulo RADIUS_ATTR_FRAMED_MTU) && 589252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 590214501Srpaulo printf("Could not add Framed-MTU\n"); 591214501Srpaulo goto fail; 592214501Srpaulo } 593214501Srpaulo 594214501Srpaulo if (eap && !radius_msg_add_eap(msg, eap, len)) { 595214501Srpaulo printf("Could not add EAP-Message\n"); 596214501Srpaulo goto fail; 597214501Srpaulo } 598214501Srpaulo 599214501Srpaulo /* State attribute must be copied if and only if this packet is 600214501Srpaulo * Access-Request reply to the previous Access-Challenge */ 601214501Srpaulo if (sm->last_recv_radius && 602214501Srpaulo radius_msg_get_hdr(sm->last_recv_radius)->code == 603214501Srpaulo RADIUS_CODE_ACCESS_CHALLENGE) { 604214501Srpaulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 605214501Srpaulo RADIUS_ATTR_STATE); 606214501Srpaulo if (res < 0) { 607214501Srpaulo printf("Could not copy State attribute from previous " 608214501Srpaulo "Access-Challenge\n"); 609214501Srpaulo goto fail; 610214501Srpaulo } 611214501Srpaulo if (res > 0) { 612214501Srpaulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 613214501Srpaulo } 614214501Srpaulo } 615214501Srpaulo 616252726Srpaulo if (hapd->conf->radius_request_cui) { 617252726Srpaulo const u8 *cui; 618252726Srpaulo size_t cui_len; 619252726Srpaulo /* Add previously learned CUI or nul CUI to request CUI */ 620252726Srpaulo if (sm->radius_cui) { 621252726Srpaulo cui = wpabuf_head(sm->radius_cui); 622252726Srpaulo cui_len = wpabuf_len(sm->radius_cui); 623252726Srpaulo } else { 624252726Srpaulo cui = (const u8 *) "\0"; 625252726Srpaulo cui_len = 1; 626252726Srpaulo } 627252726Srpaulo if (!radius_msg_add_attr(msg, 628252726Srpaulo RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 629252726Srpaulo cui, cui_len)) { 630252726Srpaulo wpa_printf(MSG_ERROR, "Could not add CUI"); 631252726Srpaulo goto fail; 632252726Srpaulo } 633252726Srpaulo } 634252726Srpaulo 635252726Srpaulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 636252726Srpaulo goto fail; 637252726Srpaulo 638214501Srpaulo return; 639214501Srpaulo 640214501Srpaulo fail: 641214501Srpaulo radius_msg_free(msg); 642214501Srpaulo} 643214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 644214501Srpaulo 645214501Srpaulo 646214501Srpaulostatic void handle_eap_response(struct hostapd_data *hapd, 647214501Srpaulo struct sta_info *sta, struct eap_hdr *eap, 648214501Srpaulo size_t len) 649214501Srpaulo{ 650214501Srpaulo u8 type, *data; 651214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 652214501Srpaulo if (sm == NULL) 653214501Srpaulo return; 654214501Srpaulo 655214501Srpaulo data = (u8 *) (eap + 1); 656214501Srpaulo 657214501Srpaulo if (len < sizeof(*eap) + 1) { 658214501Srpaulo printf("handle_eap_response: too short response data\n"); 659214501Srpaulo return; 660214501Srpaulo } 661214501Srpaulo 662214501Srpaulo sm->eap_type_supp = type = data[0]; 663214501Srpaulo 664214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 665214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 666214501Srpaulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 667214501Srpaulo eap->code, eap->identifier, be_to_host16(eap->length), 668214501Srpaulo eap_server_get_name(0, type), type); 669214501Srpaulo 670214501Srpaulo sm->dot1xAuthEapolRespFramesRx++; 671214501Srpaulo 672214501Srpaulo wpabuf_free(sm->eap_if->eapRespData); 673214501Srpaulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 674214501Srpaulo sm->eapolEap = TRUE; 675214501Srpaulo} 676214501Srpaulo 677214501Srpaulo 678214501Srpaulo/* Process incoming EAP packet from Supplicant */ 679214501Srpaulostatic void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 680214501Srpaulo u8 *buf, size_t len) 681214501Srpaulo{ 682214501Srpaulo struct eap_hdr *eap; 683214501Srpaulo u16 eap_len; 684214501Srpaulo 685214501Srpaulo if (len < sizeof(*eap)) { 686214501Srpaulo printf(" too short EAP packet\n"); 687214501Srpaulo return; 688214501Srpaulo } 689214501Srpaulo 690214501Srpaulo eap = (struct eap_hdr *) buf; 691214501Srpaulo 692214501Srpaulo eap_len = be_to_host16(eap->length); 693214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 694214501Srpaulo eap->code, eap->identifier, eap_len); 695214501Srpaulo if (eap_len < sizeof(*eap)) { 696214501Srpaulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 697214501Srpaulo return; 698214501Srpaulo } else if (eap_len > len) { 699214501Srpaulo wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 700214501Srpaulo "packet"); 701214501Srpaulo return; 702214501Srpaulo } else if (eap_len < len) { 703214501Srpaulo wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 704214501Srpaulo "packet", (unsigned long) len - eap_len); 705214501Srpaulo } 706214501Srpaulo 707214501Srpaulo switch (eap->code) { 708214501Srpaulo case EAP_CODE_REQUEST: 709214501Srpaulo wpa_printf(MSG_DEBUG, " (request)"); 710214501Srpaulo return; 711214501Srpaulo case EAP_CODE_RESPONSE: 712214501Srpaulo wpa_printf(MSG_DEBUG, " (response)"); 713214501Srpaulo handle_eap_response(hapd, sta, eap, eap_len); 714214501Srpaulo break; 715214501Srpaulo case EAP_CODE_SUCCESS: 716214501Srpaulo wpa_printf(MSG_DEBUG, " (success)"); 717214501Srpaulo return; 718214501Srpaulo case EAP_CODE_FAILURE: 719214501Srpaulo wpa_printf(MSG_DEBUG, " (failure)"); 720214501Srpaulo return; 721214501Srpaulo default: 722214501Srpaulo wpa_printf(MSG_DEBUG, " (unknown code)"); 723214501Srpaulo return; 724214501Srpaulo } 725214501Srpaulo} 726214501Srpaulo 727214501Srpaulo 728214501Srpaulostatic struct eapol_state_machine * 729214501Srpauloieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 730214501Srpaulo{ 731214501Srpaulo int flags = 0; 732214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 733214501Srpaulo flags |= EAPOL_SM_PREAUTH; 734214501Srpaulo if (sta->wpa_sm) { 735214501Srpaulo flags |= EAPOL_SM_USES_WPA; 736214501Srpaulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 737214501Srpaulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 738214501Srpaulo } 739214501Srpaulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 740252726Srpaulo sta->wps_ie, sta->p2p_ie, sta, 741252726Srpaulo sta->identity, sta->radius_cui); 742214501Srpaulo} 743214501Srpaulo 744214501Srpaulo 745214501Srpaulo/** 746214501Srpaulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 747214501Srpaulo * @hapd: hostapd BSS data 748214501Srpaulo * @sa: Source address (sender of the EAPOL frame) 749214501Srpaulo * @buf: EAPOL frame 750214501Srpaulo * @len: Length of buf in octets 751214501Srpaulo * 752214501Srpaulo * This function is called for each incoming EAPOL frame from the interface 753214501Srpaulo */ 754214501Srpaulovoid ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 755214501Srpaulo size_t len) 756214501Srpaulo{ 757214501Srpaulo struct sta_info *sta; 758214501Srpaulo struct ieee802_1x_hdr *hdr; 759214501Srpaulo struct ieee802_1x_eapol_key *key; 760214501Srpaulo u16 datalen; 761214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 762252726Srpaulo int key_mgmt; 763214501Srpaulo 764214501Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && 765214501Srpaulo !hapd->conf->wps_state) 766214501Srpaulo return; 767214501Srpaulo 768214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 769214501Srpaulo (unsigned long) len, MAC2STR(sa)); 770214501Srpaulo sta = ap_get_sta(hapd, sa); 771252726Srpaulo if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 772252726Srpaulo !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 773214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 774252726Srpaulo "associated/Pre-authenticating STA"); 775214501Srpaulo return; 776214501Srpaulo } 777214501Srpaulo 778214501Srpaulo if (len < sizeof(*hdr)) { 779214501Srpaulo printf(" too short IEEE 802.1X packet\n"); 780214501Srpaulo return; 781214501Srpaulo } 782214501Srpaulo 783214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 784214501Srpaulo datalen = be_to_host16(hdr->length); 785214501Srpaulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 786214501Srpaulo hdr->version, hdr->type, datalen); 787214501Srpaulo 788214501Srpaulo if (len - sizeof(*hdr) < datalen) { 789214501Srpaulo printf(" frame too short for this IEEE 802.1X packet\n"); 790214501Srpaulo if (sta->eapol_sm) 791214501Srpaulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 792214501Srpaulo return; 793214501Srpaulo } 794214501Srpaulo if (len - sizeof(*hdr) > datalen) { 795214501Srpaulo wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 796214501Srpaulo "IEEE 802.1X packet", 797214501Srpaulo (unsigned long) len - sizeof(*hdr) - datalen); 798214501Srpaulo } 799214501Srpaulo 800214501Srpaulo if (sta->eapol_sm) { 801214501Srpaulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 802214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 803214501Srpaulo } 804214501Srpaulo 805214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 806214501Srpaulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 807214501Srpaulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 808214501Srpaulo (key->type == EAPOL_KEY_TYPE_WPA || 809214501Srpaulo key->type == EAPOL_KEY_TYPE_RSN)) { 810214501Srpaulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 811214501Srpaulo sizeof(*hdr) + datalen); 812214501Srpaulo return; 813214501Srpaulo } 814214501Srpaulo 815252726Srpaulo if (!hapd->conf->ieee802_1x && 816252726Srpaulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 817252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 818252726Srpaulo "802.1X not enabled and WPS not used"); 819214501Srpaulo return; 820252726Srpaulo } 821214501Srpaulo 822252726Srpaulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 823252726Srpaulo if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { 824252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 825252726Srpaulo "STA is using PSK"); 826252726Srpaulo return; 827252726Srpaulo } 828252726Srpaulo 829214501Srpaulo if (!sta->eapol_sm) { 830214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 831214501Srpaulo if (!sta->eapol_sm) 832214501Srpaulo return; 833214501Srpaulo 834214501Srpaulo#ifdef CONFIG_WPS 835252726Srpaulo if (!hapd->conf->ieee802_1x) { 836252726Srpaulo u32 wflags = sta->flags & (WLAN_STA_WPS | 837252726Srpaulo WLAN_STA_WPS2 | 838252726Srpaulo WLAN_STA_MAYBE_WPS); 839252726Srpaulo if (wflags == WLAN_STA_MAYBE_WPS || 840252726Srpaulo wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 841252726Srpaulo /* 842252726Srpaulo * Delay EAPOL frame transmission until a 843252726Srpaulo * possible WPS STA initiates the handshake 844252726Srpaulo * with EAPOL-Start. Only allow the wait to be 845252726Srpaulo * skipped if the STA is known to support WPS 846252726Srpaulo * 2.0. 847252726Srpaulo */ 848252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Do not start " 849252726Srpaulo "EAPOL until EAPOL-Start is " 850252726Srpaulo "received"); 851252726Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 852252726Srpaulo } 853214501Srpaulo } 854214501Srpaulo#endif /* CONFIG_WPS */ 855214501Srpaulo 856214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 857214501Srpaulo } 858214501Srpaulo 859214501Srpaulo /* since we support version 1, we can ignore version field and proceed 860214501Srpaulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 861214501Srpaulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 862214501Srpaulo * does not change frame contents, so should be ok to process frames 863214501Srpaulo * more or less identically. Some changes might be needed for 864214501Srpaulo * verification of fields. */ 865214501Srpaulo 866214501Srpaulo switch (hdr->type) { 867214501Srpaulo case IEEE802_1X_TYPE_EAP_PACKET: 868214501Srpaulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 869214501Srpaulo break; 870214501Srpaulo 871214501Srpaulo case IEEE802_1X_TYPE_EAPOL_START: 872214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 873214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 874214501Srpaulo "from STA"); 875214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 876214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 877214501Srpaulo if (pmksa) { 878214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 879214501Srpaulo HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 880214501Srpaulo "available - ignore it since " 881214501Srpaulo "STA sent EAPOL-Start"); 882214501Srpaulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 883214501Srpaulo } 884214501Srpaulo sta->eapol_sm->eapolStart = TRUE; 885214501Srpaulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 886252726Srpaulo eap_server_clear_identity(sta->eapol_sm->eap); 887214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 888214501Srpaulo break; 889214501Srpaulo 890214501Srpaulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 891214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 892214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 893214501Srpaulo "from STA"); 894214501Srpaulo sta->acct_terminate_cause = 895214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 896214501Srpaulo accounting_sta_stop(hapd, sta); 897214501Srpaulo sta->eapol_sm->eapolLogoff = TRUE; 898214501Srpaulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 899252726Srpaulo eap_server_clear_identity(sta->eapol_sm->eap); 900214501Srpaulo break; 901214501Srpaulo 902214501Srpaulo case IEEE802_1X_TYPE_EAPOL_KEY: 903214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 904252726Srpaulo if (!ap_sta_is_authorized(sta)) { 905214501Srpaulo wpa_printf(MSG_DEBUG, " Dropped key data from " 906214501Srpaulo "unauthorized Supplicant"); 907214501Srpaulo break; 908214501Srpaulo } 909214501Srpaulo break; 910214501Srpaulo 911214501Srpaulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 912214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 913214501Srpaulo /* TODO: implement support for this; show data */ 914214501Srpaulo break; 915214501Srpaulo 916214501Srpaulo default: 917214501Srpaulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 918214501Srpaulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 919214501Srpaulo break; 920214501Srpaulo } 921214501Srpaulo 922214501Srpaulo eapol_auth_step(sta->eapol_sm); 923214501Srpaulo} 924214501Srpaulo 925214501Srpaulo 926214501Srpaulo/** 927214501Srpaulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 928214501Srpaulo * @hapd: hostapd BSS data 929214501Srpaulo * @sta: The station 930214501Srpaulo * 931214501Srpaulo * This function is called to start IEEE 802.1X authentication when a new 932214501Srpaulo * station completes IEEE 802.11 association. 933214501Srpaulo */ 934214501Srpaulovoid ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 935214501Srpaulo{ 936214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 937214501Srpaulo int reassoc = 1; 938214501Srpaulo int force_1x = 0; 939252726Srpaulo int key_mgmt; 940214501Srpaulo 941214501Srpaulo#ifdef CONFIG_WPS 942214501Srpaulo if (hapd->conf->wps_state && hapd->conf->wpa && 943214501Srpaulo (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 944214501Srpaulo /* 945214501Srpaulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 946214501Srpaulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 947214501Srpaulo * authentication in this BSS. 948214501Srpaulo */ 949214501Srpaulo force_1x = 1; 950214501Srpaulo } 951214501Srpaulo#endif /* CONFIG_WPS */ 952214501Srpaulo 953252726Srpaulo if (!force_1x && !hapd->conf->ieee802_1x) { 954252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 955252726Srpaulo "802.1X not enabled or forced for WPS"); 956252726Srpaulo /* 957252726Srpaulo * Clear any possible EAPOL authenticator state to support 958252726Srpaulo * reassociation change from WPS to PSK. 959252726Srpaulo */ 960252726Srpaulo ieee802_1x_free_station(sta); 961214501Srpaulo return; 962252726Srpaulo } 963214501Srpaulo 964252726Srpaulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 965252726Srpaulo if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { 966252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 967252726Srpaulo /* 968252726Srpaulo * Clear any possible EAPOL authenticator state to support 969252726Srpaulo * reassociation change from WPA-EAP to PSK. 970252726Srpaulo */ 971252726Srpaulo ieee802_1x_free_station(sta); 972252726Srpaulo return; 973252726Srpaulo } 974252726Srpaulo 975214501Srpaulo if (sta->eapol_sm == NULL) { 976214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 977214501Srpaulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 978214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 979214501Srpaulo if (sta->eapol_sm == NULL) { 980214501Srpaulo hostapd_logger(hapd, sta->addr, 981214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 982214501Srpaulo HOSTAPD_LEVEL_INFO, 983214501Srpaulo "failed to allocate state machine"); 984214501Srpaulo return; 985214501Srpaulo } 986214501Srpaulo reassoc = 0; 987214501Srpaulo } 988214501Srpaulo 989214501Srpaulo#ifdef CONFIG_WPS 990214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 991252726Srpaulo if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { 992214501Srpaulo /* 993252726Srpaulo * Delay EAPOL frame transmission until a possible WPS STA 994252726Srpaulo * initiates the handshake with EAPOL-Start. Only allow the 995252726Srpaulo * wait to be skipped if the STA is known to support WPS 2.0. 996214501Srpaulo */ 997252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 998252726Srpaulo "EAPOL-Start is received"); 999214501Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1000214501Srpaulo } 1001214501Srpaulo#endif /* CONFIG_WPS */ 1002214501Srpaulo 1003214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1004214501Srpaulo 1005252726Srpaulo#ifdef CONFIG_IEEE80211R 1006252726Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 1007252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1008252726Srpaulo HOSTAPD_LEVEL_DEBUG, 1009252726Srpaulo "PMK from FT - skip IEEE 802.1X/EAP"); 1010252726Srpaulo /* Setup EAPOL state machines to already authenticated state 1011252726Srpaulo * because of existing FT information from R0KH. */ 1012252726Srpaulo sta->eapol_sm->keyRun = TRUE; 1013252726Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1014252726Srpaulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1015252726Srpaulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1016252726Srpaulo sta->eapol_sm->authSuccess = TRUE; 1017252726Srpaulo sta->eapol_sm->authFail = FALSE; 1018252726Srpaulo if (sta->eapol_sm->eap) 1019252726Srpaulo eap_sm_notify_cached(sta->eapol_sm->eap); 1020252726Srpaulo /* TODO: get vlan_id from R0KH using RRB message */ 1021252726Srpaulo return; 1022252726Srpaulo } 1023252726Srpaulo#endif /* CONFIG_IEEE80211R */ 1024252726Srpaulo 1025214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1026214501Srpaulo if (pmksa) { 1027214501Srpaulo int old_vlanid; 1028214501Srpaulo 1029214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1030214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1031214501Srpaulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1032214501Srpaulo /* Setup EAPOL state machines to already authenticated state 1033214501Srpaulo * because of existing PMKSA information in the cache. */ 1034214501Srpaulo sta->eapol_sm->keyRun = TRUE; 1035214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1036214501Srpaulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1037214501Srpaulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1038214501Srpaulo sta->eapol_sm->authSuccess = TRUE; 1039252726Srpaulo sta->eapol_sm->authFail = FALSE; 1040214501Srpaulo if (sta->eapol_sm->eap) 1041214501Srpaulo eap_sm_notify_cached(sta->eapol_sm->eap); 1042214501Srpaulo old_vlanid = sta->vlan_id; 1043214501Srpaulo pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); 1044214501Srpaulo if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 1045214501Srpaulo sta->vlan_id = 0; 1046214501Srpaulo ap_sta_bind_vlan(hapd, sta, old_vlanid); 1047214501Srpaulo } else { 1048214501Srpaulo if (reassoc) { 1049214501Srpaulo /* 1050214501Srpaulo * Force EAPOL state machines to start 1051214501Srpaulo * re-authentication without having to wait for the 1052214501Srpaulo * Supplicant to send EAPOL-Start. 1053214501Srpaulo */ 1054214501Srpaulo sta->eapol_sm->reAuthenticate = TRUE; 1055214501Srpaulo } 1056214501Srpaulo eapol_auth_step(sta->eapol_sm); 1057214501Srpaulo } 1058214501Srpaulo} 1059214501Srpaulo 1060214501Srpaulo 1061214501Srpaulovoid ieee802_1x_free_station(struct sta_info *sta) 1062214501Srpaulo{ 1063214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1064214501Srpaulo 1065214501Srpaulo if (sm == NULL) 1066214501Srpaulo return; 1067214501Srpaulo 1068214501Srpaulo sta->eapol_sm = NULL; 1069214501Srpaulo 1070214501Srpaulo#ifndef CONFIG_NO_RADIUS 1071214501Srpaulo radius_msg_free(sm->last_recv_radius); 1072214501Srpaulo radius_free_class(&sm->radius_class); 1073252726Srpaulo wpabuf_free(sm->radius_cui); 1074214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1075214501Srpaulo 1076214501Srpaulo os_free(sm->identity); 1077214501Srpaulo eapol_auth_free(sm); 1078214501Srpaulo} 1079214501Srpaulo 1080214501Srpaulo 1081214501Srpaulo#ifndef CONFIG_NO_RADIUS 1082214501Srpaulostatic void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1083214501Srpaulo struct sta_info *sta) 1084214501Srpaulo{ 1085252726Srpaulo struct wpabuf *eap; 1086252726Srpaulo const struct eap_hdr *hdr; 1087214501Srpaulo int eap_type = -1; 1088214501Srpaulo char buf[64]; 1089214501Srpaulo struct radius_msg *msg; 1090214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1091214501Srpaulo 1092214501Srpaulo if (sm == NULL || sm->last_recv_radius == NULL) { 1093214501Srpaulo if (sm) 1094214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1095214501Srpaulo return; 1096214501Srpaulo } 1097214501Srpaulo 1098214501Srpaulo msg = sm->last_recv_radius; 1099214501Srpaulo 1100252726Srpaulo eap = radius_msg_get_eap(msg); 1101214501Srpaulo if (eap == NULL) { 1102214501Srpaulo /* RFC 3579, Chap. 2.6.3: 1103214501Srpaulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1104214501Srpaulo * attribute */ 1105214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1106214501Srpaulo HOSTAPD_LEVEL_WARNING, "could not extract " 1107214501Srpaulo "EAP-Message from RADIUS message"); 1108214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1109214501Srpaulo return; 1110214501Srpaulo } 1111214501Srpaulo 1112252726Srpaulo if (wpabuf_len(eap) < sizeof(*hdr)) { 1113214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1114214501Srpaulo HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1115214501Srpaulo "received from authentication server"); 1116252726Srpaulo wpabuf_free(eap); 1117214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1118214501Srpaulo return; 1119214501Srpaulo } 1120214501Srpaulo 1121252726Srpaulo if (wpabuf_len(eap) > sizeof(*hdr)) 1122252726Srpaulo eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1123214501Srpaulo 1124252726Srpaulo hdr = wpabuf_head(eap); 1125214501Srpaulo switch (hdr->code) { 1126214501Srpaulo case EAP_CODE_REQUEST: 1127214501Srpaulo if (eap_type >= 0) 1128214501Srpaulo sm->eap_type_authsrv = eap_type; 1129214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 1130214501Srpaulo eap_type >= 0 ? eap_server_get_name(0, eap_type) : 1131214501Srpaulo "??", 1132214501Srpaulo eap_type); 1133214501Srpaulo break; 1134214501Srpaulo case EAP_CODE_RESPONSE: 1135214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 1136214501Srpaulo eap_type >= 0 ? eap_server_get_name(0, eap_type) : 1137214501Srpaulo "??", 1138214501Srpaulo eap_type); 1139214501Srpaulo break; 1140214501Srpaulo case EAP_CODE_SUCCESS: 1141214501Srpaulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 1142214501Srpaulo break; 1143214501Srpaulo case EAP_CODE_FAILURE: 1144214501Srpaulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1145214501Srpaulo break; 1146214501Srpaulo default: 1147214501Srpaulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1148214501Srpaulo break; 1149214501Srpaulo } 1150214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 1151214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1152214501Srpaulo HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1153214501Srpaulo "id=%d len=%d) from RADIUS server: %s", 1154214501Srpaulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1155214501Srpaulo buf); 1156214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 1157214501Srpaulo 1158214501Srpaulo wpabuf_free(sm->eap_if->aaaEapReqData); 1159252726Srpaulo sm->eap_if->aaaEapReqData = eap; 1160214501Srpaulo} 1161214501Srpaulo 1162214501Srpaulo 1163214501Srpaulostatic void ieee802_1x_get_keys(struct hostapd_data *hapd, 1164214501Srpaulo struct sta_info *sta, struct radius_msg *msg, 1165214501Srpaulo struct radius_msg *req, 1166214501Srpaulo const u8 *shared_secret, 1167214501Srpaulo size_t shared_secret_len) 1168214501Srpaulo{ 1169214501Srpaulo struct radius_ms_mppe_keys *keys; 1170214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1171214501Srpaulo if (sm == NULL) 1172214501Srpaulo return; 1173214501Srpaulo 1174214501Srpaulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1175214501Srpaulo shared_secret_len); 1176214501Srpaulo 1177214501Srpaulo if (keys && keys->send && keys->recv) { 1178214501Srpaulo size_t len = keys->send_len + keys->recv_len; 1179214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1180214501Srpaulo keys->send, keys->send_len); 1181214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1182214501Srpaulo keys->recv, keys->recv_len); 1183214501Srpaulo 1184214501Srpaulo os_free(sm->eap_if->aaaEapKeyData); 1185214501Srpaulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1186214501Srpaulo if (sm->eap_if->aaaEapKeyData) { 1187214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1188214501Srpaulo keys->recv_len); 1189214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1190214501Srpaulo keys->send, keys->send_len); 1191214501Srpaulo sm->eap_if->aaaEapKeyDataLen = len; 1192214501Srpaulo sm->eap_if->aaaEapKeyAvailable = TRUE; 1193214501Srpaulo } 1194214501Srpaulo } 1195214501Srpaulo 1196214501Srpaulo if (keys) { 1197214501Srpaulo os_free(keys->send); 1198214501Srpaulo os_free(keys->recv); 1199214501Srpaulo os_free(keys); 1200214501Srpaulo } 1201214501Srpaulo} 1202214501Srpaulo 1203214501Srpaulo 1204214501Srpaulostatic void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1205214501Srpaulo struct sta_info *sta, 1206214501Srpaulo struct radius_msg *msg) 1207214501Srpaulo{ 1208214501Srpaulo u8 *class; 1209214501Srpaulo size_t class_len; 1210214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1211214501Srpaulo int count, i; 1212214501Srpaulo struct radius_attr_data *nclass; 1213214501Srpaulo size_t nclass_count; 1214214501Srpaulo 1215214501Srpaulo if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1216214501Srpaulo sm == NULL) 1217214501Srpaulo return; 1218214501Srpaulo 1219214501Srpaulo radius_free_class(&sm->radius_class); 1220214501Srpaulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1221214501Srpaulo if (count <= 0) 1222214501Srpaulo return; 1223214501Srpaulo 1224252726Srpaulo nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1225214501Srpaulo if (nclass == NULL) 1226214501Srpaulo return; 1227214501Srpaulo 1228214501Srpaulo nclass_count = 0; 1229214501Srpaulo 1230214501Srpaulo class = NULL; 1231214501Srpaulo for (i = 0; i < count; i++) { 1232214501Srpaulo do { 1233214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1234214501Srpaulo &class, &class_len, 1235214501Srpaulo class) < 0) { 1236214501Srpaulo i = count; 1237214501Srpaulo break; 1238214501Srpaulo } 1239214501Srpaulo } while (class_len < 1); 1240214501Srpaulo 1241214501Srpaulo nclass[nclass_count].data = os_malloc(class_len); 1242214501Srpaulo if (nclass[nclass_count].data == NULL) 1243214501Srpaulo break; 1244214501Srpaulo 1245214501Srpaulo os_memcpy(nclass[nclass_count].data, class, class_len); 1246214501Srpaulo nclass[nclass_count].len = class_len; 1247214501Srpaulo nclass_count++; 1248214501Srpaulo } 1249214501Srpaulo 1250214501Srpaulo sm->radius_class.attr = nclass; 1251214501Srpaulo sm->radius_class.count = nclass_count; 1252214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1253214501Srpaulo "attributes for " MACSTR, 1254214501Srpaulo (unsigned long) sm->radius_class.count, 1255214501Srpaulo MAC2STR(sta->addr)); 1256214501Srpaulo} 1257214501Srpaulo 1258214501Srpaulo 1259214501Srpaulo/* Update sta->identity based on User-Name attribute in Access-Accept */ 1260214501Srpaulostatic void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1261214501Srpaulo struct sta_info *sta, 1262214501Srpaulo struct radius_msg *msg) 1263214501Srpaulo{ 1264214501Srpaulo u8 *buf, *identity; 1265214501Srpaulo size_t len; 1266214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1267214501Srpaulo 1268214501Srpaulo if (sm == NULL) 1269214501Srpaulo return; 1270214501Srpaulo 1271214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1272214501Srpaulo NULL) < 0) 1273214501Srpaulo return; 1274214501Srpaulo 1275214501Srpaulo identity = os_malloc(len + 1); 1276214501Srpaulo if (identity == NULL) 1277214501Srpaulo return; 1278214501Srpaulo 1279214501Srpaulo os_memcpy(identity, buf, len); 1280214501Srpaulo identity[len] = '\0'; 1281214501Srpaulo 1282214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1283214501Srpaulo HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1284214501Srpaulo "User-Name from Access-Accept '%s'", 1285214501Srpaulo sm->identity ? (char *) sm->identity : "N/A", 1286214501Srpaulo (char *) identity); 1287214501Srpaulo 1288214501Srpaulo os_free(sm->identity); 1289214501Srpaulo sm->identity = identity; 1290214501Srpaulo sm->identity_len = len; 1291214501Srpaulo} 1292214501Srpaulo 1293214501Srpaulo 1294252726Srpaulo/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1295252726Srpaulostatic void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1296252726Srpaulo struct sta_info *sta, 1297252726Srpaulo struct radius_msg *msg) 1298252726Srpaulo{ 1299252726Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1300252726Srpaulo struct wpabuf *cui; 1301252726Srpaulo u8 *buf; 1302252726Srpaulo size_t len; 1303252726Srpaulo 1304252726Srpaulo if (sm == NULL) 1305252726Srpaulo return; 1306252726Srpaulo 1307252726Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1308252726Srpaulo &buf, &len, NULL) < 0) 1309252726Srpaulo return; 1310252726Srpaulo 1311252726Srpaulo cui = wpabuf_alloc_copy(buf, len); 1312252726Srpaulo if (cui == NULL) 1313252726Srpaulo return; 1314252726Srpaulo 1315252726Srpaulo wpabuf_free(sm->radius_cui); 1316252726Srpaulo sm->radius_cui = cui; 1317252726Srpaulo} 1318252726Srpaulo 1319252726Srpaulo 1320214501Srpaulostruct sta_id_search { 1321214501Srpaulo u8 identifier; 1322214501Srpaulo struct eapol_state_machine *sm; 1323214501Srpaulo}; 1324214501Srpaulo 1325214501Srpaulo 1326214501Srpaulostatic int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1327214501Srpaulo struct sta_info *sta, 1328214501Srpaulo void *ctx) 1329214501Srpaulo{ 1330214501Srpaulo struct sta_id_search *id_search = ctx; 1331214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1332214501Srpaulo 1333214501Srpaulo if (sm && sm->radius_identifier >= 0 && 1334214501Srpaulo sm->radius_identifier == id_search->identifier) { 1335214501Srpaulo id_search->sm = sm; 1336214501Srpaulo return 1; 1337214501Srpaulo } 1338214501Srpaulo return 0; 1339214501Srpaulo} 1340214501Srpaulo 1341214501Srpaulo 1342214501Srpaulostatic struct eapol_state_machine * 1343214501Srpauloieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1344214501Srpaulo{ 1345214501Srpaulo struct sta_id_search id_search; 1346214501Srpaulo id_search.identifier = identifier; 1347214501Srpaulo id_search.sm = NULL; 1348214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1349214501Srpaulo return id_search.sm; 1350214501Srpaulo} 1351214501Srpaulo 1352214501Srpaulo 1353214501Srpaulo/** 1354214501Srpaulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1355214501Srpaulo * @msg: RADIUS response message 1356214501Srpaulo * @req: RADIUS request message 1357214501Srpaulo * @shared_secret: RADIUS shared secret 1358214501Srpaulo * @shared_secret_len: Length of shared_secret in octets 1359214501Srpaulo * @data: Context data (struct hostapd_data *) 1360214501Srpaulo * Returns: Processing status 1361214501Srpaulo */ 1362214501Srpaulostatic RadiusRxResult 1363214501Srpauloieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1364214501Srpaulo const u8 *shared_secret, size_t shared_secret_len, 1365214501Srpaulo void *data) 1366214501Srpaulo{ 1367214501Srpaulo struct hostapd_data *hapd = data; 1368214501Srpaulo struct sta_info *sta; 1369214501Srpaulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1370214501Srpaulo int session_timeout_set, old_vlanid = 0; 1371214501Srpaulo struct eapol_state_machine *sm; 1372214501Srpaulo int override_eapReq = 0; 1373214501Srpaulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1374214501Srpaulo 1375214501Srpaulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1376214501Srpaulo if (sm == NULL) { 1377214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1378214501Srpaulo "station for this RADIUS message"); 1379214501Srpaulo return RADIUS_RX_UNKNOWN; 1380214501Srpaulo } 1381214501Srpaulo sta = sm->sta; 1382214501Srpaulo 1383214501Srpaulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1384214501Srpaulo * present when packet contains an EAP-Message attribute */ 1385214501Srpaulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1386214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1387214501Srpaulo 0) < 0 && 1388214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1389214501Srpaulo wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1390214501Srpaulo "Message-Authenticator since it does not include " 1391214501Srpaulo "EAP-Message"); 1392214501Srpaulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1393214501Srpaulo req, 1)) { 1394214501Srpaulo printf("Incoming RADIUS packet did not have correct " 1395214501Srpaulo "Message-Authenticator - dropped\n"); 1396214501Srpaulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1397214501Srpaulo } 1398214501Srpaulo 1399214501Srpaulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1400214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1401214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 1402214501Srpaulo printf("Unknown RADIUS message code\n"); 1403214501Srpaulo return RADIUS_RX_UNKNOWN; 1404214501Srpaulo } 1405214501Srpaulo 1406214501Srpaulo sm->radius_identifier = -1; 1407214501Srpaulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1408214501Srpaulo MAC2STR(sta->addr)); 1409214501Srpaulo 1410214501Srpaulo radius_msg_free(sm->last_recv_radius); 1411214501Srpaulo sm->last_recv_radius = msg; 1412214501Srpaulo 1413214501Srpaulo session_timeout_set = 1414214501Srpaulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1415214501Srpaulo &session_timeout); 1416214501Srpaulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1417214501Srpaulo &termination_action)) 1418214501Srpaulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1419214501Srpaulo 1420214501Srpaulo if (hapd->conf->acct_interim_interval == 0 && 1421214501Srpaulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1422214501Srpaulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1423214501Srpaulo &acct_interim_interval) == 0) { 1424214501Srpaulo if (acct_interim_interval < 60) { 1425214501Srpaulo hostapd_logger(hapd, sta->addr, 1426214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1427214501Srpaulo HOSTAPD_LEVEL_INFO, 1428214501Srpaulo "ignored too small " 1429214501Srpaulo "Acct-Interim-Interval %d", 1430214501Srpaulo acct_interim_interval); 1431214501Srpaulo } else 1432214501Srpaulo sta->acct_interim_interval = acct_interim_interval; 1433214501Srpaulo } 1434214501Srpaulo 1435214501Srpaulo 1436214501Srpaulo switch (hdr->code) { 1437214501Srpaulo case RADIUS_CODE_ACCESS_ACCEPT: 1438214501Srpaulo if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 1439214501Srpaulo sta->vlan_id = 0; 1440214501Srpaulo#ifndef CONFIG_NO_VLAN 1441214501Srpaulo else { 1442214501Srpaulo old_vlanid = sta->vlan_id; 1443214501Srpaulo sta->vlan_id = radius_msg_get_vlanid(msg); 1444214501Srpaulo } 1445214501Srpaulo if (sta->vlan_id > 0 && 1446214501Srpaulo hostapd_get_vlan_id_ifname(hapd->conf->vlan, 1447214501Srpaulo sta->vlan_id)) { 1448214501Srpaulo hostapd_logger(hapd, sta->addr, 1449214501Srpaulo HOSTAPD_MODULE_RADIUS, 1450214501Srpaulo HOSTAPD_LEVEL_INFO, 1451214501Srpaulo "VLAN ID %d", sta->vlan_id); 1452214501Srpaulo } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { 1453214501Srpaulo sta->eapol_sm->authFail = TRUE; 1454214501Srpaulo hostapd_logger(hapd, sta->addr, 1455214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1456214501Srpaulo HOSTAPD_LEVEL_INFO, "authentication " 1457214501Srpaulo "server did not include required VLAN " 1458214501Srpaulo "ID in Access-Accept"); 1459214501Srpaulo break; 1460214501Srpaulo } 1461214501Srpaulo#endif /* CONFIG_NO_VLAN */ 1462214501Srpaulo 1463214501Srpaulo if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) 1464214501Srpaulo break; 1465214501Srpaulo 1466214501Srpaulo /* RFC 3580, Ch. 3.17 */ 1467214501Srpaulo if (session_timeout_set && termination_action == 1468214501Srpaulo RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { 1469214501Srpaulo sm->reAuthPeriod = session_timeout; 1470214501Srpaulo } else if (session_timeout_set) 1471214501Srpaulo ap_sta_session_timeout(hapd, sta, session_timeout); 1472214501Srpaulo 1473214501Srpaulo sm->eap_if->aaaSuccess = TRUE; 1474214501Srpaulo override_eapReq = 1; 1475214501Srpaulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 1476214501Srpaulo shared_secret_len); 1477214501Srpaulo ieee802_1x_store_radius_class(hapd, sta, msg); 1478214501Srpaulo ieee802_1x_update_sta_identity(hapd, sta, msg); 1479252726Srpaulo ieee802_1x_update_sta_cui(hapd, sta, msg); 1480214501Srpaulo if (sm->eap_if->eapKeyAvailable && 1481214501Srpaulo wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, 1482214501Srpaulo session_timeout_set ? 1483214501Srpaulo (int) session_timeout : -1, sm) == 0) { 1484214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1485214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1486214501Srpaulo "Added PMKSA cache entry"); 1487214501Srpaulo } 1488214501Srpaulo break; 1489214501Srpaulo case RADIUS_CODE_ACCESS_REJECT: 1490214501Srpaulo sm->eap_if->aaaFail = TRUE; 1491214501Srpaulo override_eapReq = 1; 1492214501Srpaulo break; 1493214501Srpaulo case RADIUS_CODE_ACCESS_CHALLENGE: 1494214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 1495214501Srpaulo if (session_timeout_set) { 1496214501Srpaulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 1497214501Srpaulo sm->eap_if->aaaMethodTimeout = session_timeout; 1498214501Srpaulo hostapd_logger(hapd, sm->addr, 1499214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1500214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1501214501Srpaulo "using EAP timeout of %d seconds (from " 1502214501Srpaulo "RADIUS)", 1503214501Srpaulo sm->eap_if->aaaMethodTimeout); 1504214501Srpaulo } else { 1505214501Srpaulo /* 1506214501Srpaulo * Use dynamic retransmission behavior per EAP 1507214501Srpaulo * specification. 1508214501Srpaulo */ 1509214501Srpaulo sm->eap_if->aaaMethodTimeout = 0; 1510214501Srpaulo } 1511214501Srpaulo break; 1512214501Srpaulo } 1513214501Srpaulo 1514214501Srpaulo ieee802_1x_decapsulate_radius(hapd, sta); 1515214501Srpaulo if (override_eapReq) 1516214501Srpaulo sm->eap_if->aaaEapReq = FALSE; 1517214501Srpaulo 1518214501Srpaulo eapol_auth_step(sm); 1519214501Srpaulo 1520214501Srpaulo return RADIUS_RX_QUEUED; 1521214501Srpaulo} 1522214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1523214501Srpaulo 1524214501Srpaulo 1525214501Srpaulovoid ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 1526214501Srpaulo{ 1527214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1528214501Srpaulo if (sm == NULL) 1529214501Srpaulo return; 1530214501Srpaulo 1531214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1532214501Srpaulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 1533214501Srpaulo 1534214501Srpaulo#ifndef CONFIG_NO_RADIUS 1535214501Srpaulo radius_msg_free(sm->last_recv_radius); 1536214501Srpaulo sm->last_recv_radius = NULL; 1537214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1538214501Srpaulo 1539214501Srpaulo if (sm->eap_if->eapTimeout) { 1540214501Srpaulo /* 1541214501Srpaulo * Disconnect the STA since it did not reply to the last EAP 1542214501Srpaulo * request and we cannot continue EAP processing (EAP-Failure 1543214501Srpaulo * could only be sent if the EAP peer actually replied). 1544214501Srpaulo */ 1545252726Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 1546252726Srpaulo MAC2STR(sta->addr)); 1547252726Srpaulo 1548214501Srpaulo sm->eap_if->portEnabled = FALSE; 1549214501Srpaulo ap_sta_disconnect(hapd, sta, sta->addr, 1550214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 1551214501Srpaulo } 1552214501Srpaulo} 1553214501Srpaulo 1554214501Srpaulo 1555214501Srpaulostatic int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 1556214501Srpaulo{ 1557214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 1558214501Srpaulo 1559214501Srpaulo if (hapd->conf->default_wep_key_len < 1) 1560214501Srpaulo return 0; 1561214501Srpaulo 1562214501Srpaulo os_free(eapol->default_wep_key); 1563214501Srpaulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 1564214501Srpaulo if (eapol->default_wep_key == NULL || 1565252726Srpaulo random_get_bytes(eapol->default_wep_key, 1566252726Srpaulo hapd->conf->default_wep_key_len)) { 1567214501Srpaulo printf("Could not generate random WEP key.\n"); 1568214501Srpaulo os_free(eapol->default_wep_key); 1569214501Srpaulo eapol->default_wep_key = NULL; 1570214501Srpaulo return -1; 1571214501Srpaulo } 1572214501Srpaulo 1573214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 1574214501Srpaulo eapol->default_wep_key, 1575214501Srpaulo hapd->conf->default_wep_key_len); 1576214501Srpaulo 1577214501Srpaulo return 0; 1578214501Srpaulo} 1579214501Srpaulo 1580214501Srpaulo 1581214501Srpaulostatic int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 1582214501Srpaulo struct sta_info *sta, void *ctx) 1583214501Srpaulo{ 1584214501Srpaulo if (sta->eapol_sm) { 1585214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1586214501Srpaulo eapol_auth_step(sta->eapol_sm); 1587214501Srpaulo } 1588214501Srpaulo return 0; 1589214501Srpaulo} 1590214501Srpaulo 1591214501Srpaulo 1592214501Srpaulostatic void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 1593214501Srpaulo{ 1594214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 1595214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 1596214501Srpaulo 1597214501Srpaulo if (eapol->default_wep_key_idx >= 3) 1598214501Srpaulo eapol->default_wep_key_idx = 1599214501Srpaulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 1600214501Srpaulo else 1601214501Srpaulo eapol->default_wep_key_idx++; 1602214501Srpaulo 1603214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 1604214501Srpaulo eapol->default_wep_key_idx); 1605214501Srpaulo 1606214501Srpaulo if (ieee802_1x_rekey_broadcast(hapd)) { 1607214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1608214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to generate a " 1609214501Srpaulo "new broadcast key"); 1610214501Srpaulo os_free(eapol->default_wep_key); 1611214501Srpaulo eapol->default_wep_key = NULL; 1612214501Srpaulo return; 1613214501Srpaulo } 1614214501Srpaulo 1615214501Srpaulo /* TODO: Could setup key for RX here, but change default TX keyid only 1616214501Srpaulo * after new broadcast key has been sent to all stations. */ 1617252726Srpaulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 1618252726Srpaulo broadcast_ether_addr, 1619252726Srpaulo eapol->default_wep_key_idx, 1, NULL, 0, 1620252726Srpaulo eapol->default_wep_key, 1621252726Srpaulo hapd->conf->default_wep_key_len)) { 1622214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1623214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to configure a " 1624214501Srpaulo "new broadcast key"); 1625214501Srpaulo os_free(eapol->default_wep_key); 1626214501Srpaulo eapol->default_wep_key = NULL; 1627214501Srpaulo return; 1628214501Srpaulo } 1629214501Srpaulo 1630214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 1631214501Srpaulo 1632214501Srpaulo if (hapd->conf->wep_rekeying_period > 0) { 1633214501Srpaulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 1634214501Srpaulo ieee802_1x_rekey, hapd, NULL); 1635214501Srpaulo } 1636214501Srpaulo} 1637214501Srpaulo 1638214501Srpaulo 1639214501Srpaulostatic void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 1640214501Srpaulo const u8 *data, size_t datalen) 1641214501Srpaulo{ 1642214501Srpaulo#ifdef CONFIG_WPS 1643214501Srpaulo struct sta_info *sta = sta_ctx; 1644214501Srpaulo 1645214501Srpaulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 1646214501Srpaulo WLAN_STA_MAYBE_WPS) { 1647214501Srpaulo const u8 *identity; 1648214501Srpaulo size_t identity_len; 1649214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1650214501Srpaulo 1651214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 1652214501Srpaulo if (identity && 1653214501Srpaulo ((identity_len == WSC_ID_ENROLLEE_LEN && 1654214501Srpaulo os_memcmp(identity, WSC_ID_ENROLLEE, 1655214501Srpaulo WSC_ID_ENROLLEE_LEN) == 0) || 1656214501Srpaulo (identity_len == WSC_ID_REGISTRAR_LEN && 1657214501Srpaulo os_memcmp(identity, WSC_ID_REGISTRAR, 1658214501Srpaulo WSC_ID_REGISTRAR_LEN) == 0))) { 1659214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 1660214501Srpaulo "WLAN_STA_WPS"); 1661214501Srpaulo sta->flags |= WLAN_STA_WPS; 1662214501Srpaulo } 1663214501Srpaulo } 1664214501Srpaulo#endif /* CONFIG_WPS */ 1665214501Srpaulo 1666214501Srpaulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 1667214501Srpaulo} 1668214501Srpaulo 1669214501Srpaulo 1670214501Srpaulostatic void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 1671214501Srpaulo const u8 *data, size_t datalen) 1672214501Srpaulo{ 1673214501Srpaulo#ifndef CONFIG_NO_RADIUS 1674214501Srpaulo struct hostapd_data *hapd = ctx; 1675214501Srpaulo struct sta_info *sta = sta_ctx; 1676214501Srpaulo 1677214501Srpaulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 1678214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1679214501Srpaulo} 1680214501Srpaulo 1681214501Srpaulo 1682214501Srpaulostatic void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 1683214501Srpaulo int preauth) 1684214501Srpaulo{ 1685214501Srpaulo struct hostapd_data *hapd = ctx; 1686214501Srpaulo struct sta_info *sta = sta_ctx; 1687214501Srpaulo if (preauth) 1688214501Srpaulo rsn_preauth_finished(hapd, sta, success); 1689214501Srpaulo else 1690214501Srpaulo ieee802_1x_finished(hapd, sta, success); 1691214501Srpaulo} 1692214501Srpaulo 1693214501Srpaulo 1694214501Srpaulostatic int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 1695214501Srpaulo size_t identity_len, int phase2, 1696214501Srpaulo struct eap_user *user) 1697214501Srpaulo{ 1698214501Srpaulo struct hostapd_data *hapd = ctx; 1699214501Srpaulo const struct hostapd_eap_user *eap_user; 1700252726Srpaulo int i; 1701214501Srpaulo 1702252726Srpaulo eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 1703214501Srpaulo if (eap_user == NULL) 1704214501Srpaulo return -1; 1705214501Srpaulo 1706214501Srpaulo os_memset(user, 0, sizeof(*user)); 1707214501Srpaulo user->phase2 = phase2; 1708252726Srpaulo for (i = 0; i < EAP_MAX_METHODS; i++) { 1709214501Srpaulo user->methods[i].vendor = eap_user->methods[i].vendor; 1710214501Srpaulo user->methods[i].method = eap_user->methods[i].method; 1711214501Srpaulo } 1712214501Srpaulo 1713214501Srpaulo if (eap_user->password) { 1714214501Srpaulo user->password = os_malloc(eap_user->password_len); 1715214501Srpaulo if (user->password == NULL) 1716214501Srpaulo return -1; 1717214501Srpaulo os_memcpy(user->password, eap_user->password, 1718214501Srpaulo eap_user->password_len); 1719214501Srpaulo user->password_len = eap_user->password_len; 1720252726Srpaulo user->password_hash = eap_user->password_hash; 1721214501Srpaulo } 1722214501Srpaulo user->force_version = eap_user->force_version; 1723214501Srpaulo user->ttls_auth = eap_user->ttls_auth; 1724214501Srpaulo 1725214501Srpaulo return 0; 1726214501Srpaulo} 1727214501Srpaulo 1728214501Srpaulo 1729214501Srpaulostatic int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 1730214501Srpaulo{ 1731214501Srpaulo struct hostapd_data *hapd = ctx; 1732214501Srpaulo struct sta_info *sta; 1733214501Srpaulo sta = ap_get_sta(hapd, addr); 1734214501Srpaulo if (sta == NULL || sta->eapol_sm == NULL) 1735214501Srpaulo return 0; 1736214501Srpaulo return 1; 1737214501Srpaulo} 1738214501Srpaulo 1739214501Srpaulo 1740214501Srpaulostatic void ieee802_1x_logger(void *ctx, const u8 *addr, 1741214501Srpaulo eapol_logger_level level, const char *txt) 1742214501Srpaulo{ 1743214501Srpaulo#ifndef CONFIG_NO_HOSTAPD_LOGGER 1744214501Srpaulo struct hostapd_data *hapd = ctx; 1745214501Srpaulo int hlevel; 1746214501Srpaulo 1747214501Srpaulo switch (level) { 1748214501Srpaulo case EAPOL_LOGGER_WARNING: 1749214501Srpaulo hlevel = HOSTAPD_LEVEL_WARNING; 1750214501Srpaulo break; 1751214501Srpaulo case EAPOL_LOGGER_INFO: 1752214501Srpaulo hlevel = HOSTAPD_LEVEL_INFO; 1753214501Srpaulo break; 1754214501Srpaulo case EAPOL_LOGGER_DEBUG: 1755214501Srpaulo default: 1756214501Srpaulo hlevel = HOSTAPD_LEVEL_DEBUG; 1757214501Srpaulo break; 1758214501Srpaulo } 1759214501Srpaulo 1760214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 1761214501Srpaulo txt); 1762214501Srpaulo#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 1763214501Srpaulo} 1764214501Srpaulo 1765214501Srpaulo 1766214501Srpaulostatic void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 1767214501Srpaulo int authorized) 1768214501Srpaulo{ 1769214501Srpaulo struct hostapd_data *hapd = ctx; 1770214501Srpaulo struct sta_info *sta = sta_ctx; 1771214501Srpaulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 1772214501Srpaulo} 1773214501Srpaulo 1774214501Srpaulo 1775214501Srpaulostatic void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 1776214501Srpaulo{ 1777214501Srpaulo struct hostapd_data *hapd = ctx; 1778214501Srpaulo struct sta_info *sta = sta_ctx; 1779214501Srpaulo ieee802_1x_abort_auth(hapd, sta); 1780214501Srpaulo} 1781214501Srpaulo 1782214501Srpaulo 1783214501Srpaulostatic void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 1784214501Srpaulo{ 1785214501Srpaulo struct hostapd_data *hapd = ctx; 1786214501Srpaulo struct sta_info *sta = sta_ctx; 1787214501Srpaulo ieee802_1x_tx_key(hapd, sta); 1788214501Srpaulo} 1789214501Srpaulo 1790214501Srpaulo 1791214501Srpaulostatic void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 1792214501Srpaulo enum eapol_event type) 1793214501Srpaulo{ 1794214501Srpaulo /* struct hostapd_data *hapd = ctx; */ 1795214501Srpaulo struct sta_info *sta = sta_ctx; 1796214501Srpaulo switch (type) { 1797214501Srpaulo case EAPOL_AUTH_SM_CHANGE: 1798214501Srpaulo wpa_auth_sm_notify(sta->wpa_sm); 1799214501Srpaulo break; 1800214501Srpaulo case EAPOL_AUTH_REAUTHENTICATE: 1801214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1802214501Srpaulo break; 1803214501Srpaulo } 1804214501Srpaulo} 1805214501Srpaulo 1806214501Srpaulo 1807214501Srpauloint ieee802_1x_init(struct hostapd_data *hapd) 1808214501Srpaulo{ 1809214501Srpaulo int i; 1810214501Srpaulo struct eapol_auth_config conf; 1811214501Srpaulo struct eapol_auth_cb cb; 1812214501Srpaulo 1813214501Srpaulo os_memset(&conf, 0, sizeof(conf)); 1814214501Srpaulo conf.ctx = hapd; 1815214501Srpaulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 1816214501Srpaulo conf.wpa = hapd->conf->wpa; 1817214501Srpaulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 1818214501Srpaulo conf.eap_server = hapd->conf->eap_server; 1819214501Srpaulo conf.ssl_ctx = hapd->ssl_ctx; 1820214501Srpaulo conf.msg_ctx = hapd->msg_ctx; 1821214501Srpaulo conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 1822214501Srpaulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 1823214501Srpaulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 1824214501Srpaulo conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 1825214501Srpaulo conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 1826214501Srpaulo conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 1827214501Srpaulo conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 1828214501Srpaulo conf.eap_fast_prov = hapd->conf->eap_fast_prov; 1829214501Srpaulo conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 1830214501Srpaulo conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 1831214501Srpaulo conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 1832214501Srpaulo conf.tnc = hapd->conf->tnc; 1833214501Srpaulo conf.wps = hapd->wps; 1834252726Srpaulo conf.fragment_size = hapd->conf->fragment_size; 1835252726Srpaulo conf.pwd_group = hapd->conf->pwd_group; 1836252726Srpaulo conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 1837214501Srpaulo 1838214501Srpaulo os_memset(&cb, 0, sizeof(cb)); 1839214501Srpaulo cb.eapol_send = ieee802_1x_eapol_send; 1840214501Srpaulo cb.aaa_send = ieee802_1x_aaa_send; 1841214501Srpaulo cb.finished = _ieee802_1x_finished; 1842214501Srpaulo cb.get_eap_user = ieee802_1x_get_eap_user; 1843214501Srpaulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 1844214501Srpaulo cb.logger = ieee802_1x_logger; 1845214501Srpaulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 1846214501Srpaulo cb.abort_auth = _ieee802_1x_abort_auth; 1847214501Srpaulo cb.tx_key = _ieee802_1x_tx_key; 1848214501Srpaulo cb.eapol_event = ieee802_1x_eapol_event; 1849214501Srpaulo 1850214501Srpaulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 1851214501Srpaulo if (hapd->eapol_auth == NULL) 1852214501Srpaulo return -1; 1853214501Srpaulo 1854214501Srpaulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 1855252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 1856214501Srpaulo return -1; 1857214501Srpaulo 1858214501Srpaulo#ifndef CONFIG_NO_RADIUS 1859214501Srpaulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 1860214501Srpaulo ieee802_1x_receive_auth, hapd)) 1861214501Srpaulo return -1; 1862214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1863214501Srpaulo 1864214501Srpaulo if (hapd->conf->default_wep_key_len) { 1865214501Srpaulo for (i = 0; i < 4; i++) 1866252726Srpaulo hostapd_drv_set_key(hapd->conf->iface, hapd, 1867252726Srpaulo WPA_ALG_NONE, NULL, i, 0, NULL, 0, 1868252726Srpaulo NULL, 0); 1869214501Srpaulo 1870214501Srpaulo ieee802_1x_rekey(hapd, NULL); 1871214501Srpaulo 1872214501Srpaulo if (hapd->eapol_auth->default_wep_key == NULL) 1873214501Srpaulo return -1; 1874214501Srpaulo } 1875214501Srpaulo 1876214501Srpaulo return 0; 1877214501Srpaulo} 1878214501Srpaulo 1879214501Srpaulo 1880214501Srpaulovoid ieee802_1x_deinit(struct hostapd_data *hapd) 1881214501Srpaulo{ 1882214501Srpaulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 1883214501Srpaulo 1884214501Srpaulo if (hapd->driver != NULL && 1885214501Srpaulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 1886252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 1887214501Srpaulo 1888214501Srpaulo eapol_auth_deinit(hapd->eapol_auth); 1889214501Srpaulo hapd->eapol_auth = NULL; 1890214501Srpaulo} 1891214501Srpaulo 1892214501Srpaulo 1893214501Srpauloint ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 1894214501Srpaulo const u8 *buf, size_t len, int ack) 1895214501Srpaulo{ 1896214501Srpaulo struct ieee80211_hdr *hdr; 1897214501Srpaulo u8 *pos; 1898214501Srpaulo const unsigned char rfc1042_hdr[ETH_ALEN] = 1899214501Srpaulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 1900214501Srpaulo 1901214501Srpaulo if (sta == NULL) 1902214501Srpaulo return -1; 1903252726Srpaulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 1904214501Srpaulo return 0; 1905214501Srpaulo 1906214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 1907214501Srpaulo pos = (u8 *) (hdr + 1); 1908214501Srpaulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 1909214501Srpaulo return 0; 1910214501Srpaulo pos += sizeof(rfc1042_hdr); 1911214501Srpaulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 1912214501Srpaulo return 0; 1913214501Srpaulo pos += 2; 1914214501Srpaulo 1915252726Srpaulo return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 1916252726Srpaulo ack); 1917252726Srpaulo} 1918214501Srpaulo 1919252726Srpaulo 1920252726Srpauloint ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 1921252726Srpaulo const u8 *buf, int len, int ack) 1922252726Srpaulo{ 1923252726Srpaulo const struct ieee802_1x_hdr *xhdr = 1924252726Srpaulo (const struct ieee802_1x_hdr *) buf; 1925252726Srpaulo const u8 *pos = buf + sizeof(*xhdr); 1926252726Srpaulo struct ieee802_1x_eapol_key *key; 1927252726Srpaulo 1928252726Srpaulo if (len < (int) sizeof(*xhdr)) 1929252726Srpaulo return 0; 1930214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 1931214501Srpaulo "type=%d length=%d - ack=%d", 1932214501Srpaulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 1933214501Srpaulo be_to_host16(xhdr->length), ack); 1934214501Srpaulo 1935252726Srpaulo if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 1936252726Srpaulo return 0; 1937252726Srpaulo 1938252726Srpaulo if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 1939252726Srpaulo const struct wpa_eapol_key *wpa; 1940252726Srpaulo wpa = (const struct wpa_eapol_key *) pos; 1941252726Srpaulo if (wpa->type == EAPOL_KEY_TYPE_RSN || 1942252726Srpaulo wpa->type == EAPOL_KEY_TYPE_WPA) 1943252726Srpaulo wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 1944252726Srpaulo sta->wpa_sm, ack); 1945252726Srpaulo } 1946252726Srpaulo 1947214501Srpaulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 1948214501Srpaulo * or Authenticator state machines, but EAPOL-Key packets are not 1949252726Srpaulo * retransmitted in case of failure. Try to re-send failed EAPOL-Key 1950214501Srpaulo * packets couple of times because otherwise STA keys become 1951214501Srpaulo * unsynchronized with AP. */ 1952252726Srpaulo if (!ack && pos + sizeof(*key) <= buf + len) { 1953214501Srpaulo key = (struct ieee802_1x_eapol_key *) pos; 1954214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1955214501Srpaulo HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 1956214501Srpaulo "frame (%scast index=%d)", 1957214501Srpaulo key->key_index & BIT(7) ? "uni" : "broad", 1958214501Srpaulo key->key_index & ~BIT(7)); 1959214501Srpaulo /* TODO: re-send EAPOL-Key couple of times (with short delay 1960214501Srpaulo * between them?). If all attempt fail, report error and 1961214501Srpaulo * deauthenticate STA so that it will get new keys when 1962214501Srpaulo * authenticating again (e.g., after returning in range). 1963214501Srpaulo * Separate limit/transmit state needed both for unicast and 1964214501Srpaulo * broadcast keys(?) */ 1965214501Srpaulo } 1966214501Srpaulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 1967214501Srpaulo * to here and change the key only if the EAPOL-Key packet was Acked. 1968214501Srpaulo */ 1969214501Srpaulo 1970214501Srpaulo return 1; 1971214501Srpaulo} 1972214501Srpaulo 1973214501Srpaulo 1974214501Srpaulou8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 1975214501Srpaulo{ 1976214501Srpaulo if (sm == NULL || sm->identity == NULL) 1977214501Srpaulo return NULL; 1978214501Srpaulo 1979214501Srpaulo *len = sm->identity_len; 1980214501Srpaulo return sm->identity; 1981214501Srpaulo} 1982214501Srpaulo 1983214501Srpaulo 1984214501Srpaulou8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 1985214501Srpaulo int idx) 1986214501Srpaulo{ 1987214501Srpaulo if (sm == NULL || sm->radius_class.attr == NULL || 1988214501Srpaulo idx >= (int) sm->radius_class.count) 1989214501Srpaulo return NULL; 1990214501Srpaulo 1991214501Srpaulo *len = sm->radius_class.attr[idx].len; 1992214501Srpaulo return sm->radius_class.attr[idx].data; 1993214501Srpaulo} 1994214501Srpaulo 1995214501Srpaulo 1996252726Srpaulostruct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 1997252726Srpaulo{ 1998252726Srpaulo if (sm == NULL) 1999252726Srpaulo return NULL; 2000252726Srpaulo return sm->radius_cui; 2001252726Srpaulo} 2002252726Srpaulo 2003252726Srpaulo 2004214501Srpauloconst u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2005214501Srpaulo{ 2006252726Srpaulo *len = 0; 2007214501Srpaulo if (sm == NULL) 2008214501Srpaulo return NULL; 2009214501Srpaulo 2010214501Srpaulo *len = sm->eap_if->eapKeyDataLen; 2011214501Srpaulo return sm->eap_if->eapKeyData; 2012214501Srpaulo} 2013214501Srpaulo 2014214501Srpaulo 2015214501Srpaulovoid ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2016214501Srpaulo int enabled) 2017214501Srpaulo{ 2018214501Srpaulo if (sm == NULL) 2019214501Srpaulo return; 2020214501Srpaulo sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 2021214501Srpaulo eapol_auth_step(sm); 2022214501Srpaulo} 2023214501Srpaulo 2024214501Srpaulo 2025214501Srpaulovoid ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 2026214501Srpaulo int valid) 2027214501Srpaulo{ 2028214501Srpaulo if (sm == NULL) 2029214501Srpaulo return; 2030214501Srpaulo sm->portValid = valid ? TRUE : FALSE; 2031214501Srpaulo eapol_auth_step(sm); 2032214501Srpaulo} 2033214501Srpaulo 2034214501Srpaulo 2035214501Srpaulovoid ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 2036214501Srpaulo{ 2037214501Srpaulo if (sm == NULL) 2038214501Srpaulo return; 2039214501Srpaulo if (pre_auth) 2040214501Srpaulo sm->flags |= EAPOL_SM_PREAUTH; 2041214501Srpaulo else 2042214501Srpaulo sm->flags &= ~EAPOL_SM_PREAUTH; 2043214501Srpaulo} 2044214501Srpaulo 2045214501Srpaulo 2046214501Srpaulostatic const char * bool_txt(Boolean bool) 2047214501Srpaulo{ 2048214501Srpaulo return bool ? "TRUE" : "FALSE"; 2049214501Srpaulo} 2050214501Srpaulo 2051214501Srpaulo 2052214501Srpauloint ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2053214501Srpaulo{ 2054214501Srpaulo /* TODO */ 2055214501Srpaulo return 0; 2056214501Srpaulo} 2057214501Srpaulo 2058214501Srpaulo 2059214501Srpauloint ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2060214501Srpaulo char *buf, size_t buflen) 2061214501Srpaulo{ 2062214501Srpaulo int len = 0, ret; 2063214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 2064252726Srpaulo struct os_time t; 2065214501Srpaulo 2066214501Srpaulo if (sm == NULL) 2067214501Srpaulo return 0; 2068214501Srpaulo 2069214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2070214501Srpaulo "dot1xPaePortNumber=%d\n" 2071214501Srpaulo "dot1xPaePortProtocolVersion=%d\n" 2072214501Srpaulo "dot1xPaePortCapabilities=1\n" 2073214501Srpaulo "dot1xPaePortInitialize=%d\n" 2074214501Srpaulo "dot1xPaePortReauthenticate=FALSE\n", 2075214501Srpaulo sta->aid, 2076214501Srpaulo EAPOL_VERSION, 2077214501Srpaulo sm->initialize); 2078214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 2079214501Srpaulo return len; 2080214501Srpaulo len += ret; 2081214501Srpaulo 2082214501Srpaulo /* dot1xAuthConfigTable */ 2083214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2084214501Srpaulo "dot1xAuthPaeState=%d\n" 2085214501Srpaulo "dot1xAuthBackendAuthState=%d\n" 2086214501Srpaulo "dot1xAuthAdminControlledDirections=%d\n" 2087214501Srpaulo "dot1xAuthOperControlledDirections=%d\n" 2088214501Srpaulo "dot1xAuthAuthControlledPortStatus=%d\n" 2089214501Srpaulo "dot1xAuthAuthControlledPortControl=%d\n" 2090214501Srpaulo "dot1xAuthQuietPeriod=%u\n" 2091214501Srpaulo "dot1xAuthServerTimeout=%u\n" 2092214501Srpaulo "dot1xAuthReAuthPeriod=%u\n" 2093214501Srpaulo "dot1xAuthReAuthEnabled=%s\n" 2094214501Srpaulo "dot1xAuthKeyTxEnabled=%s\n", 2095214501Srpaulo sm->auth_pae_state + 1, 2096214501Srpaulo sm->be_auth_state + 1, 2097214501Srpaulo sm->adminControlledDirections, 2098214501Srpaulo sm->operControlledDirections, 2099214501Srpaulo sm->authPortStatus, 2100214501Srpaulo sm->portControl, 2101214501Srpaulo sm->quietPeriod, 2102214501Srpaulo sm->serverTimeout, 2103214501Srpaulo sm->reAuthPeriod, 2104214501Srpaulo bool_txt(sm->reAuthEnabled), 2105214501Srpaulo bool_txt(sm->keyTxEnabled)); 2106214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 2107214501Srpaulo return len; 2108214501Srpaulo len += ret; 2109214501Srpaulo 2110214501Srpaulo /* dot1xAuthStatsTable */ 2111214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2112214501Srpaulo "dot1xAuthEapolFramesRx=%u\n" 2113214501Srpaulo "dot1xAuthEapolFramesTx=%u\n" 2114214501Srpaulo "dot1xAuthEapolStartFramesRx=%u\n" 2115214501Srpaulo "dot1xAuthEapolLogoffFramesRx=%u\n" 2116214501Srpaulo "dot1xAuthEapolRespIdFramesRx=%u\n" 2117214501Srpaulo "dot1xAuthEapolRespFramesRx=%u\n" 2118214501Srpaulo "dot1xAuthEapolReqIdFramesTx=%u\n" 2119214501Srpaulo "dot1xAuthEapolReqFramesTx=%u\n" 2120214501Srpaulo "dot1xAuthInvalidEapolFramesRx=%u\n" 2121214501Srpaulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 2122214501Srpaulo "dot1xAuthLastEapolFrameVersion=%u\n" 2123214501Srpaulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2124214501Srpaulo sm->dot1xAuthEapolFramesRx, 2125214501Srpaulo sm->dot1xAuthEapolFramesTx, 2126214501Srpaulo sm->dot1xAuthEapolStartFramesRx, 2127214501Srpaulo sm->dot1xAuthEapolLogoffFramesRx, 2128214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx, 2129214501Srpaulo sm->dot1xAuthEapolRespFramesRx, 2130214501Srpaulo sm->dot1xAuthEapolReqIdFramesTx, 2131214501Srpaulo sm->dot1xAuthEapolReqFramesTx, 2132214501Srpaulo sm->dot1xAuthInvalidEapolFramesRx, 2133214501Srpaulo sm->dot1xAuthEapLengthErrorFramesRx, 2134214501Srpaulo sm->dot1xAuthLastEapolFrameVersion, 2135214501Srpaulo MAC2STR(sm->addr)); 2136214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 2137214501Srpaulo return len; 2138214501Srpaulo len += ret; 2139214501Srpaulo 2140214501Srpaulo /* dot1xAuthDiagTable */ 2141214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2142214501Srpaulo "dot1xAuthEntersConnecting=%u\n" 2143214501Srpaulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2144214501Srpaulo "dot1xAuthEntersAuthenticating=%u\n" 2145214501Srpaulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2146214501Srpaulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2147214501Srpaulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2148214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2149214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2150214501Srpaulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2151214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2152214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2153214501Srpaulo "dot1xAuthBackendResponses=%u\n" 2154214501Srpaulo "dot1xAuthBackendAccessChallenges=%u\n" 2155214501Srpaulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2156214501Srpaulo "dot1xAuthBackendAuthSuccesses=%u\n" 2157214501Srpaulo "dot1xAuthBackendAuthFails=%u\n", 2158214501Srpaulo sm->authEntersConnecting, 2159214501Srpaulo sm->authEapLogoffsWhileConnecting, 2160214501Srpaulo sm->authEntersAuthenticating, 2161214501Srpaulo sm->authAuthSuccessesWhileAuthenticating, 2162214501Srpaulo sm->authAuthTimeoutsWhileAuthenticating, 2163214501Srpaulo sm->authAuthFailWhileAuthenticating, 2164214501Srpaulo sm->authAuthEapStartsWhileAuthenticating, 2165214501Srpaulo sm->authAuthEapLogoffWhileAuthenticating, 2166214501Srpaulo sm->authAuthReauthsWhileAuthenticated, 2167214501Srpaulo sm->authAuthEapStartsWhileAuthenticated, 2168214501Srpaulo sm->authAuthEapLogoffWhileAuthenticated, 2169214501Srpaulo sm->backendResponses, 2170214501Srpaulo sm->backendAccessChallenges, 2171214501Srpaulo sm->backendOtherRequestsToSupplicant, 2172214501Srpaulo sm->backendAuthSuccesses, 2173214501Srpaulo sm->backendAuthFails); 2174214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 2175214501Srpaulo return len; 2176214501Srpaulo len += ret; 2177214501Srpaulo 2178214501Srpaulo /* dot1xAuthSessionStatsTable */ 2179252726Srpaulo os_get_time(&t); 2180214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2181214501Srpaulo /* TODO: dot1xAuthSessionOctetsRx */ 2182214501Srpaulo /* TODO: dot1xAuthSessionOctetsTx */ 2183214501Srpaulo /* TODO: dot1xAuthSessionFramesRx */ 2184214501Srpaulo /* TODO: dot1xAuthSessionFramesTx */ 2185214501Srpaulo "dot1xAuthSessionId=%08X-%08X\n" 2186214501Srpaulo "dot1xAuthSessionAuthenticMethod=%d\n" 2187214501Srpaulo "dot1xAuthSessionTime=%u\n" 2188214501Srpaulo "dot1xAuthSessionTerminateCause=999\n" 2189214501Srpaulo "dot1xAuthSessionUserName=%s\n", 2190214501Srpaulo sta->acct_session_id_hi, sta->acct_session_id_lo, 2191214501Srpaulo (wpa_key_mgmt_wpa_ieee8021x( 2192214501Srpaulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2193214501Srpaulo 1 : 2, 2194252726Srpaulo (unsigned int) (t.sec - sta->acct_session_start), 2195214501Srpaulo sm->identity); 2196214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 2197214501Srpaulo return len; 2198214501Srpaulo len += ret; 2199214501Srpaulo 2200214501Srpaulo return len; 2201214501Srpaulo} 2202214501Srpaulo 2203214501Srpaulo 2204214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 2205214501Srpaulo struct sta_info *sta, int success) 2206214501Srpaulo{ 2207214501Srpaulo const u8 *key; 2208214501Srpaulo size_t len; 2209214501Srpaulo /* TODO: get PMKLifetime from WPA parameters */ 2210214501Srpaulo static const int dot11RSNAConfigPMKLifetime = 43200; 2211214501Srpaulo 2212214501Srpaulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 2213214501Srpaulo if (success && key && len >= PMK_LEN && 2214214501Srpaulo wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, 2215214501Srpaulo sta->eapol_sm) == 0) { 2216214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2217214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2218214501Srpaulo "Added PMKSA cache entry (IEEE 802.1X)"); 2219214501Srpaulo } 2220214501Srpaulo 2221252726Srpaulo if (!success) { 2222214501Srpaulo /* 2223214501Srpaulo * Many devices require deauthentication after WPS provisioning 2224214501Srpaulo * and some may not be be able to do that themselves, so 2225252726Srpaulo * disconnect the client here. In addition, this may also 2226252726Srpaulo * benefit IEEE 802.1X/EAPOL authentication cases, too since 2227252726Srpaulo * the EAPOL PAE state machine would remain in HELD state for 2228252726Srpaulo * considerable amount of time and some EAP methods, like 2229252726Srpaulo * EAP-FAST with anonymous provisioning, may require another 2230252726Srpaulo * EAPOL authentication to be started to complete connection. 2231214501Srpaulo */ 2232252726Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force " 2233252726Srpaulo "disconnection after EAP-Failure"); 2234214501Srpaulo /* Add a small sleep to increase likelihood of previously 2235214501Srpaulo * requested EAP-Failure TX getting out before this should the 2236214501Srpaulo * driver reorder operations. 2237214501Srpaulo */ 2238214501Srpaulo os_sleep(0, 10000); 2239214501Srpaulo ap_sta_disconnect(hapd, sta, sta->addr, 2240252726Srpaulo WLAN_REASON_IEEE_802_1X_AUTH_FAILED); 2241214501Srpaulo } 2242214501Srpaulo} 2243