📄 ieee802_1x.c
字号:
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->eapNoReq = TRUE; return; } msg = sm->last_recv_radius; eap = radius_msg_get_eap(msg, &len); if (eap == NULL) { /* draft-aboba-radius-rfc2869bis-20.txt, 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"); free(sm->last_eap_radius); sm->last_eap_radius = NULL; sm->last_eap_radius_len = 0; sm->eapNoReq = 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"); free(eap); sm->eapNoReq = TRUE; return; } if (len > sizeof(*hdr)) eap_type = eap[sizeof(*hdr)]; hdr = (struct eap_hdr *) eap; switch (hdr->code) { case EAP_CODE_REQUEST: snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_RESPONSE: snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_SUCCESS: snprintf(buf, sizeof(buf), "EAP Success"); break; case EAP_CODE_FAILURE: snprintf(buf, sizeof(buf), "EAP Failure"); break; default: snprintf(buf, sizeof(buf), "unknown EAP code"); break; } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " "id=%d len=%d) from RADIUS server: %s", hdr->code, hdr->identifier, ntohs(hdr->length), buf); sm->eapReq = TRUE; free(sm->last_eap_radius); sm->last_eap_radius = eap; sm->last_eap_radius_len = len;}static void ieee802_1x_get_keys(struct hostapd_data *hapd, struct sta_info *sta, struct radius_msg *msg, struct radius_msg *req, u8 *shared_secret, size_t shared_secret_len){ struct radius_ms_mppe_keys *keys; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; keys = radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len); if (keys) { if (keys->send) { wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", keys->send, keys->send_len); } if (keys->recv) { wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", keys->recv, keys->recv_len); } if (keys->send && keys->recv) { free(sm->eapol_key_sign); free(sm->eapol_key_crypt); sm->eapol_key_sign = keys->send; sm->eapol_key_sign_len = keys->send_len; sm->eapol_key_crypt = keys->recv; sm->eapol_key_crypt_len = keys->recv_len; if (hapd->default_wep_key || hapd->conf->individual_wep_key_len > 0 || hapd->conf->wpa) sta->eapol_sm->keyAvailable = TRUE; } else { free(keys->send); free(keys->recv); } free(keys); }}static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, struct sta_info *sta, struct radius_msg *msg){ u8 *class; size_t class_len; struct eapol_state_machine *sm = sta->eapol_sm; int count, i; struct radius_attr_data *nclass; size_t nclass_count; if (!hapd->conf->radius->acct_server || hapd->radius == NULL || sm == NULL) return; ieee802_1x_free_radius_class(&sm->radius_class); count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); if (count <= 0) return; nclass = wpa_zalloc(count * sizeof(struct radius_attr_data)); if (nclass == NULL) return; nclass_count = 0; class = NULL; for (i = 0; i < count; i++) { do { if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, &class, &class_len, class) < 0) { i = count; break; } } while (class_len < 1); nclass[nclass_count].data = malloc(class_len); if (nclass[nclass_count].data == NULL) break; memcpy(nclass[nclass_count].data, class, class_len); nclass[nclass_count].len = class_len; nclass_count++; } sm->radius_class.attr = nclass; sm->radius_class.count = nclass_count; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Stored %lu RADIUS " "Class attributes for " MACSTR "\n", (unsigned long) sm->radius_class.count, MAC2STR(sta->addr));}/* Update sta->identity based on User-Name attribute in Access-Accept */static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, struct sta_info *sta, struct radius_msg *msg){ u8 *buf, *identity; size_t len; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, NULL) < 0) return; identity = malloc(len + 1); if (identity == NULL) return; memcpy(identity, buf, len); identity[len] = '\0'; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " "User-Name from Access-Accept '%s'", sm->identity ? (char *) sm->identity : "N/A", (char *) identity); free(sm->identity); sm->identity = identity; sm->identity_len = len;}struct sta_id_search { u8 identifier; struct eapol_state_machine *sm;};static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, struct sta_info *sta, void *ctx){ struct sta_id_search *id_search = ctx; struct eapol_state_machine *sm = sta->eapol_sm; if (sm && sm->radius_identifier >= 0 && sm->radius_identifier == id_search->identifier) { id_search->sm = sm; return 1; } return 0;}static struct eapol_state_machine *ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier){ struct sta_id_search id_search; id_search.identifier = identifier; id_search.sm = NULL; ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); return id_search.sm;}/* Process the RADIUS frames from Authentication Server */static RadiusRxResultieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, u8 *shared_secret, size_t shared_secret_len, void *data){ struct hostapd_data *hapd = data; struct sta_info *sta; u32 session_timeout = 0, termination_action, acct_interim_interval; int session_timeout_set; int eap_timeout; struct eapol_state_machine *sm; int override_eapReq = 0; sm = ieee802_1x_search_radius_identifier(hapd, msg->hdr->identifier); if (sm == NULL) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Could not " "find matching station for this RADIUS " "message\n"); return RADIUS_RX_UNKNOWN; } sta = sm->sta; /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be * present when packet contains an EAP-Message attribute */ if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT && radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 0) < 0 && radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Allowing RADIUS " "Access-Reject without Message-Authenticator " "since it does not include EAP-Message\n"); } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) { printf("Incoming RADIUS packet did not have correct " "Message-Authenticator - dropped\n"); return RADIUS_RX_INVALID_AUTHENTICATOR; } if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT && msg->hdr->code != RADIUS_CODE_ACCESS_REJECT && msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { printf("Unknown RADIUS message code\n"); return RADIUS_RX_UNKNOWN; } sm->radius_identifier = -1; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RADIUS packet matching with station " MACSTR "\n", MAC2STR(sta->addr)); if (sm->last_recv_radius) { radius_msg_free(sm->last_recv_radius); free(sm->last_recv_radius); } sm->last_recv_radius = msg; session_timeout_set = !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &session_timeout); if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, &termination_action)) termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; if (hapd->conf->radius->acct_interim_interval == 0 && msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT && radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, &acct_interim_interval) == 0) { if (acct_interim_interval < 60) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_INFO, "ignored too small " "Acct-Interim-Interval %d", acct_interim_interval); } else sta->acct_interim_interval = acct_interim_interval; } switch (msg->hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) sta->vlan_id = 0; else sta->vlan_id = radius_msg_get_vlanid(msg); if (sta->vlan_id > 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { sta->eapol_sm->authFail = TRUE; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_INFO, "authentication " "server did not include required VLAN " "ID in Access-Accept"); break; } /* RFC 3580, Ch. 3.17 */ if (session_timeout_set && termination_action == RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { sm->reAuthPeriod = session_timeout; } else if (session_timeout_set) ap_sta_session_timeout(hapd, sta, session_timeout); sm->eapSuccess = TRUE; override_eapReq = 1; ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, shared_secret_len); ieee802_1x_store_radius_class(hapd, sta, msg); ieee802_1x_update_sta_identity(hapd, sta, msg); if (sm->keyAvailable && wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, session_timeout_set ? session_timeout : -1, sm) == 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "Added PMKSA cache entry"); } break; case RADIUS_CODE_ACCESS_REJECT: sm->eapFail = TRUE; override_eapReq = 1; break; case RADIUS_CODE_ACCESS_CHALLENGE: if (session_timeout_set) { /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ eap_timeout = session_timeout; } else eap_timeout = 30; hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "using EAP timeout of %d seconds%s", eap_timeout, session_timeout_set ? " (from RADIUS)" : ""); eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL); eloop_register_timeout(eap_timeout, 0, ieee802_1x_eap_timeout, sta, NULL); sm->eapTimeout = FALSE; break; } ieee802_1x_decapsulate_radius(hapd, sta); if (override_eapReq) sm->eapReq = FALSE; eapol_sm_step(sm); return RADIUS_RX_QUEUED;}/* Handler for EAPOL Backend Authentication state machine sendRespToServer. * Forward the EAP Response from Supplicant to Authentication Server. */void ieee802_1x_send_resp_to_server(struct hostapd_data *hapd, struct sta_info *sta){ struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; if (hapd->conf->eap_server) { eap_set_eapRespData(sm->eap, sm->last_eap_supp, sm->last_eap_supp_len); } else { ieee802_1x_encapsulate_radius(hapd, sta, sm->last_eap_supp, sm->last_eap_supp_len); }}void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta){ struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "aborting authentication"); if (sm->last_recv_radius) { radius_msg_free(sm->last_recv_radius); free(sm->last_recv_radius); sm->last_recv_radius = NULL; } free(sm->last_eap_supp); sm->last_eap_supp = NULL; sm->last_eap_supp_len = 0; free(sm->last_eap_radius); sm->last_eap_radius = NULL; sm->last_eap_radius_len = 0;}#ifdef HOSTAPD_DUMP_STATEstatic void fprint_char(FILE *f, char c){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -