📄 ieee802_1x.c
字号:
/* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, strlen(buf))) { 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) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " Copied RADIUS State Attribute\n"); } } radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr); return; fail: radius_msg_free(msg); free(msg);}static 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"; default: return "Unknown"; }}static void handle_eap_response(struct hostapd_data *hapd, struct sta_info *sta, struct eap_hdr *eap, u8 *data, size_t len){ u8 type; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; if (eap->identifier != sm->currentId) { hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "EAP Identifier of the Response-Identity does " "not match (was %d, expected %d) - ignored", eap->identifier, sm->currentId); return; } if (len < 1) { printf("handle_eap_response: too short response data\n"); return; } eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL); free(sm->last_eap_supp); sm->last_eap_supp_len = sizeof(*eap) + len; sm->last_eap_supp = (u8 *) malloc(sm->last_eap_supp_len); if (sm->last_eap_supp == NULL) { printf("Could not alloc memory for last EAP Response\n"); return; } memcpy(sm->last_eap_supp, eap, sizeof(*eap)); memcpy(sm->last_eap_supp + sizeof(*eap), data, len); type = data[0]; data++; len--; 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, ntohs(eap->length), eap_type_text(type), type); if (type == EAP_TYPE_IDENTITY) { char *buf, *pos; int i; buf = malloc(4 * len + 1); if (buf) { pos = buf; for (i = 0; i < len; i++) { if (data[i] >= 32 && data[i] < 127) *pos++ = data[i]; else { snprintf(pos, 5, "{%02x}", data[i]); pos += 4; } } *pos = '\0'; hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", buf); free(buf); } sm->rx_identity = TRUE; sm->dot1xAuthEapolRespIdFramesRx++; /* Save station identity for future RADIUS packets */ free(sm->identity); sm->identity = malloc(len + 1); if (sm->identity) { memcpy(sm->identity, data, len); sm->identity[len] = '\0'; sm->identity_len = len; } } else sm->dot1xAuthEapolRespFramesRx++; 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 = ntohs(eap->length); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " EAP: code=%d identifier=%d length=%d", eap->code, eap->identifier, eap_len); if (eap_len < sizeof(*eap)) { printf(" Invalid EAP length\n"); return; } else if (eap_len > len) { printf(" Too short frame to contain this EAP packet\n"); return; } else if (eap_len < len) { printf(" Ignoring %lu extra bytes after EAP packet\n", (unsigned long) len - eap_len); } eap_len -= sizeof(*eap); switch (eap->code) { case EAP_CODE_REQUEST: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " (request)\n"); return; case EAP_CODE_RESPONSE: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " (response)\n"); handle_eap_response(hapd, sta, eap, (u8 *) (eap + 1), eap_len); break; case EAP_CODE_SUCCESS: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " (success)\n"); return; case EAP_CODE_FAILURE: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " (failure)\n"); return; default: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " (unknown code)\n"); return; }}/* Process the EAPOL frames from the Supplicant */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) return; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: %lu bytes from " MACSTR "\n", (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 = ntohs(hdr->length); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " IEEE 802.1X: version=%d type=%d length=%d\n", 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) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " ignoring %lu extra octets after IEEE 802.1X " "packet\n", (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 || wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK) return; if (!sta->eapol_sm) { sta->eapol_sm = eapol_sm_alloc(hapd, sta); if (!sta->eapol_sm) return; } /* 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"); 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; sta->eapol_sm->eapolLogoff = TRUE; sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; break; case IEEE802_1X_TYPE_EAPOL_KEY: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " EAPOL-Key\n"); if (!(sta->flags & WLAN_STA_AUTHORIZED)) { printf(" Dropped key data from unauthorized " "Supplicant\n"); break; } break; case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " EAPOL-Encapsulated-ASF-Alert\n"); /* TODO: implement support for this; show data */ break; default: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " unknown IEEE 802.1X packet type\n"); sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; break; } eapol_sm_step(sta->eapol_sm);}void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta){ struct rsn_pmksa_cache_entry *pmksa; if (!hapd->conf->ieee802_1x || wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK) return; if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "start authentication"); sta->eapol_sm = eapol_sm_alloc(hapd, sta); if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_INFO, "failed to allocate state machine"); return; } } sta->eapol_sm->portEnabled = TRUE; pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); if (pmksa) { 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->keyAvailable = 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); pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); } else eapol_sm_step(sta->eapol_sm);}void ieee802_1x_free_radius_class(struct radius_class_data *class){ int i; if (class == NULL) return; for (i = 0; i < class->count; i++) free(class->attr[i].data); free(class->attr); class->attr = NULL; class->count = 0;}int ieee802_1x_copy_radius_class(struct radius_class_data *dst, struct radius_class_data *src){ size_t i; if (src->attr == NULL) return 0; dst->attr = wpa_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 = malloc(src->attr[i].len); if (dst->attr[i].data == NULL) break; dst->count++; 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; eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL); if (sm == NULL) return; sta->eapol_sm = NULL; if (sm->last_recv_radius) { radius_msg_free(sm->last_recv_radius); free(sm->last_recv_radius); } free(sm->last_eap_supp); free(sm->last_eap_radius); free(sm->identity); ieee802_1x_free_radius_class(&sm->radius_class); free(sm->eapol_key_sign); free(sm->eapol_key_crypt); eapol_sm_free(sm);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -