📄 ieee802_1x.c
字号:
printf("Could not add Connect-Info\n"); goto fail; } if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (sm->last_recv_radius && sm->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, sm->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); } } radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr); return; fail: radius_msg_free(msg); os_free(msg);}char *eap_type_text(u8 type){ switch (type) { case EAP_TYPE_IDENTITY: return "Identity"; case EAP_TYPE_NOTIFICATION: return "Notification"; case EAP_TYPE_NAK: return "Nak"; case EAP_TYPE_MD5: return "MD5-Challenge"; case EAP_TYPE_OTP: return "One-Time Password"; case EAP_TYPE_GTC: return "Generic Token Card"; case EAP_TYPE_TLS: return "TLS"; case EAP_TYPE_TTLS: return "TTLS"; case EAP_TYPE_PEAP: return "PEAP"; case EAP_TYPE_SIM: return "SIM"; case EAP_TYPE_FAST: return "FAST"; case EAP_TYPE_SAKE: return "SAKE"; case EAP_TYPE_PSK: return "PSK"; case EAP_TYPE_PAX: return "PAX"; default: return "Unknown"; }}static void handle_eap_response(struct hostapd_data *hapd, struct sta_info *sta, struct eap_hdr *eap, size_t len){ u8 type, *data; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; data = (u8 *) (eap + 1); if (len < sizeof(*eap) + 1) { printf("handle_eap_response: too short response data\n"); return; } sm->eap_type_supp = type = data[0]; hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " "id=%d len=%d) from STA: EAP Response-%s (%d)", eap->code, eap->identifier, be_to_host16(eap->length), eap_type_text(type), type); sm->dot1xAuthEapolRespFramesRx++; wpabuf_free(sm->eap_if->eapRespData); sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); sm->eapolEap = TRUE;}/* Process incoming EAP packet from Supplicant */static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, u8 *buf, size_t len){ struct eap_hdr *eap; u16 eap_len; if (len < sizeof(*eap)) { printf(" too short EAP packet\n"); return; } eap = (struct eap_hdr *) buf; eap_len = be_to_host16(eap->length); wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", eap->code, eap->identifier, eap_len); if (eap_len < sizeof(*eap)) { wpa_printf(MSG_DEBUG, " Invalid EAP length"); return; } else if (eap_len > len) { wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " "packet"); return; } else if (eap_len < len) { wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " "packet", (unsigned long) len - eap_len); } switch (eap->code) { case EAP_CODE_REQUEST: wpa_printf(MSG_DEBUG, " (request)"); return; case EAP_CODE_RESPONSE: wpa_printf(MSG_DEBUG, " (response)"); handle_eap_response(hapd, sta, eap, eap_len); break; case EAP_CODE_SUCCESS: wpa_printf(MSG_DEBUG, " (success)"); return; case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, " (failure)"); return; default: wpa_printf(MSG_DEBUG, " (unknown code)"); return; }}/** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant * @hapd: hostapd BSS data * @sa: Source address (sender of the EAPOL frame) * @buf: EAPOL frame * @len: Length of buf in octets * * This function is called for each incoming EAPOL frame from the interface */void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, size_t len){ struct sta_info *sta; struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; u16 datalen; struct rsn_pmksa_cache_entry *pmksa; if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->wps_state) return; wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, (unsigned long) len, MAC2STR(sa)); sta = ap_get_sta(hapd, sa); if (!sta) { printf(" no station information available\n"); return; } if (len < sizeof(*hdr)) { printf(" too short IEEE 802.1X packet\n"); return; } hdr = (struct ieee802_1x_hdr *) buf; datalen = be_to_host16(hdr->length); wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", hdr->version, hdr->type, datalen); if (len - sizeof(*hdr) < datalen) { printf(" frame too short for this IEEE 802.1X packet\n"); if (sta->eapol_sm) sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; return; } if (len - sizeof(*hdr) > datalen) { wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " "IEEE 802.1X packet", (unsigned long) len - sizeof(*hdr) - datalen); } if (sta->eapol_sm) { sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; sta->eapol_sm->dot1xAuthEapolFramesRx++; } key = (struct ieee802_1x_eapol_key *) (hdr + 1); if (datalen >= sizeof(struct ieee802_1x_eapol_key) && hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && (key->type == EAPOL_KEY_TYPE_WPA || key->type == EAPOL_KEY_TYPE_RSN)) { wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, sizeof(*hdr) + datalen); return; } if ((!hapd->conf->ieee802_1x && !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) || wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) return; if (!sta->eapol_sm) { sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr, sta->flags & WLAN_STA_PREAUTH, sta); if (!sta->eapol_sm) return;#ifdef CONFIG_WPS if (!hapd->conf->ieee802_1x && ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == WLAN_STA_MAYBE_WPS)) { /* * Delay EAPOL frame transmission until a possible WPS * STA initiates the handshake with EAPOL-Start. */ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; }#endif /* CONFIG_WPS */ sta->eapol_sm->eap_if->portEnabled = TRUE; } /* since we support version 1, we can ignore version field and proceed * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ /* TODO: actually, we are not version 1 anymore.. However, Version 2 * does not change frame contents, so should be ok to process frames * more or less identically. Some changes might be needed for * verification of fields. */ switch (hdr->type) { case IEEE802_1X_TYPE_EAP_PACKET: handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); break; case IEEE802_1X_TYPE_EAPOL_START: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " "from STA"); sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); if (pmksa) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "cached PMKSA " "available - ignore it since " "STA sent EAPOL-Start"); wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); } sta->eapol_sm->eapolStart = TRUE; sta->eapol_sm->dot1xAuthEapolStartFramesRx++; wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); break; case IEEE802_1X_TYPE_EAPOL_LOGOFF: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " "from STA"); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; accounting_sta_stop(hapd, sta); sta->eapol_sm->eapolLogoff = TRUE; sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; break; case IEEE802_1X_TYPE_EAPOL_KEY: wpa_printf(MSG_DEBUG, " EAPOL-Key"); if (!(sta->flags & WLAN_STA_AUTHORIZED)) { wpa_printf(MSG_DEBUG, " Dropped key data from " "unauthorized Supplicant"); break; } break; case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); /* TODO: implement support for this; show data */ break; default: wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; break; } eapol_auth_step(sta->eapol_sm);}/** * ieee802_1x_new_station - Start IEEE 802.1X authentication * @hapd: hostapd BSS data * @sta: The station * * This function is called to start IEEE 802.1X authentication when a new * station completes IEEE 802.11 association. */void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta){ struct rsn_pmksa_cache_entry *pmksa; int reassoc = 1; int force_1x = 0;#ifdef CONFIG_WPS if (hapd->conf->wps_state && hapd->conf->wpa && (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { /* * Need to enable IEEE 802.1X/EAPOL state machines for possible * WPS handshake even if IEEE 802.1X/EAPOL is not used for * authentication in this BSS. */ force_1x = 1; }#endif /* CONFIG_WPS */ if ((!force_1x && !hapd->conf->ieee802_1x) || wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) return; if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "start authentication"); sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr, sta->flags & WLAN_STA_PREAUTH, sta); if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_INFO, "failed to allocate state machine"); return; } reassoc = 0; }#ifdef CONFIG_WPS sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { /* * Delay EAPOL frame transmission until a possible WPS * initiates the handshake with EAPOL-Start. */ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; }#endif /* CONFIG_WPS */ sta->eapol_sm->eap_if->portEnabled = TRUE; pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); if (pmksa) { int old_vlanid; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); /* Setup EAPOL state machines to already authenticated state * because of existing PMKSA information in the cache. */ sta->eapol_sm->keyRun = TRUE; sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; sta->eapol_sm->authSuccess = TRUE; if (sta->eapol_sm->eap) eap_sm_notify_cached(sta->eapol_sm->eap); old_vlanid = sta->vlan_id; pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) sta->vlan_id = 0; ap_sta_bind_vlan(hapd, sta, old_vlanid); } else { if (reassoc) { /* * Force EAPOL state machines to start * re-authentication without having to wait for the * Supplicant to send EAPOL-Start. */ sta->eapol_sm->reAuthenticate = TRUE; } eapol_auth_step(sta->eapol_sm); }}void ieee802_1x_free_radius_class(struct radius_class_data *class){ size_t i; if (class == NULL) return; for (i = 0; i < class->count; i++) os_free(class->attr[i].data); os_free(class->attr); class->attr = NULL; class->count = 0;}int ieee802_1x_copy_radius_class(struct radius_class_data *dst, const struct radius_class_data *src){ size_t i; if (src->attr == NULL) return 0; dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data)); if (dst->attr == NULL) return -1; dst->count = 0; for (i = 0; i < src->count; i++) { dst->attr[i].data = os_malloc(src->attr[i].len); if (dst->attr[i].data == NULL) break; dst->count++; os_memcpy(dst->attr[i].data, src->attr[i].data, src->attr[i].len); dst->attr[i].len = src->attr[i].len; } return 0;}void ieee802_1x_free_station(struct sta_info *sta){ struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; sta->eapol_sm = NULL; if (sm->last_recv_radius) { radius_msg_free(sm->last_recv_radius); os_free(sm->last_recv_radius); } os_free(sm->identity); ieee802_1x_free_radius_class(&sm->radius_class); eapol_auth_free(sm);}static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, struct sta_info *sta){ u8 *eap; size_t len; struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL || sm->last_recv_radius == NULL) { if (sm) sm->eap_if->aaaEapNoReq = TRUE; return; } msg = sm->last_recv_radius; eap = radius_msg_get_eap(msg, &len); if (eap == NULL) { /* RFC 3579, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_WARNING, "could not extract " "EAP-Message from RADIUS message"); sm->eap_if->aaaEapNoReq = TRUE; return; } if (len < sizeof(*hdr)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_WARNING, "too short EAP packet " "received from authentication server"); os_free(eap); sm->eap_if->aaaEapNoReq = TRUE; return; } if (len > sizeof(*hdr)) eap_type = eap[sizeof(*hdr)]; hdr = (struct eap_hdr *) eap; switch (hdr->code) { case EAP_CODE_REQUEST: if (eap_type >= 0) sm->eap_type_authsrv = eap_type; os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_RESPONSE: os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_SUCCESS: os_strlcpy(buf, "EAP Success", sizeof(buf));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -