📄 eap.c
字号:
/* * hostapd / EAP Full Authenticator state machine (RFC 4137) * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This state machine is based on the full authenticator state machine defined * in RFC 4137. However, to support backend authentication in RADIUS * authentication server functionality, parts of backend authenticator (also * from RFC 4137) are mixed in. This functionality is enabled by setting * backend_auth configuration variable to TRUE. */#include "includes.h"#include "common.h"#include "eap_i.h"#include "state_machine.h"#define STATE_MACHINE_DATA struct eap_sm#define STATE_MACHINE_DEBUG_PREFIX "EAP"#define EAP_MAX_AUTH_ROUNDS 50static void eap_user_free(struct eap_user *user);/* EAP state machines are described in RFC 4137 */static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, int eapSRTT, int eapRTTVAR, int methodTimeout);static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);static int eap_sm_getId(const struct wpabuf *data);static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);static int eap_sm_nextId(struct eap_sm *sm, int id);static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, size_t len);static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);static int eap_sm_Policy_getDecision(struct eap_sm *sm);static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src){ if (src == NULL) return -1; wpabuf_free(*dst); *dst = wpabuf_dup(src); return *dst ? 0 : -1;}static int eap_copy_data(u8 **dst, size_t *dst_len, const u8 *src, size_t src_len){ if (src == NULL) return -1; os_free(*dst); *dst = os_malloc(src_len); if (*dst) { os_memcpy(*dst, src, src_len); *dst_len = src_len; return 0; } else { *dst_len = 0; return -1; }}#define EAP_COPY(dst, src) \ eap_copy_data((dst), (dst ## Len), (src), (src ## Len))/** * eap_user_get - Fetch user information from the database * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() * @identity: Identity (User-Name) of the user * @identity_len: Length of identity in bytes * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user * Returns: 0 on success, or -1 on failure * * This function is used to fetch user information for EAP. The user will be * selected based on the specified identity. sm->user and * sm->user_eap_method_index are updated for the new user when a matching user * is found. sm->user can be used to get user information (e.g., password). */int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, int phase2){ struct eap_user *user; if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->get_eap_user == NULL) return -1; eap_user_free(sm->user); sm->user = NULL; user = os_zalloc(sizeof(*user)); if (user == NULL) return -1; if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, identity_len, phase2, user) != 0) { eap_user_free(user); return -1; } sm->user = user; sm->user_eap_method_index = 0; return 0;}SM_STATE(EAP, DISABLED){ SM_ENTRY(EAP, DISABLED); sm->num_rounds = 0;}SM_STATE(EAP, INITIALIZE){ SM_ENTRY(EAP, INITIALIZE); sm->currentId = -1; sm->eap_if.eapSuccess = FALSE; sm->eap_if.eapFail = FALSE; sm->eap_if.eapTimeout = FALSE; os_free(sm->eap_if.eapKeyData); sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; sm->eap_if.eapKeyAvailable = FALSE; sm->eap_if.eapRestart = FALSE; /* * This is not defined in RFC 4137, but method state needs to be * reseted here so that it does not remain in success state when * re-authentication starts. */ if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = NULL; sm->user_eap_method_index = 0; if (sm->backend_auth) { sm->currentMethod = EAP_TYPE_NONE; /* parse rxResp, respId, respMethod */ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); if (sm->rxResp) { sm->currentId = sm->respId; } } sm->num_rounds = 0; sm->method_pending = METHOD_PENDING_NONE;}SM_STATE(EAP, PICK_UP_METHOD){ SM_ENTRY(EAP, PICK_UP_METHOD); if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { sm->currentMethod = sm->respMethod; if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, sm->currentMethod); if (sm->m && sm->m->initPickUp) { sm->eap_method_priv = sm->m->initPickUp(sm); if (sm->eap_method_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP: Failed to " "initialize EAP method %d", sm->currentMethod); sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } else { sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } }}SM_STATE(EAP, IDLE){ SM_ENTRY(EAP, IDLE); sm->eap_if.retransWhile = eap_sm_calculateTimeout( sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, sm->methodTimeout);}SM_STATE(EAP, RETRANSMIT){ SM_ENTRY(EAP, RETRANSMIT); sm->retransCount++; if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) sm->eap_if.eapReq = TRUE; }}SM_STATE(EAP, RECEIVED){ SM_ENTRY(EAP, RECEIVED); /* parse rxResp, respId, respMethod */ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); sm->num_rounds++;}SM_STATE(EAP, DISCARD){ SM_ENTRY(EAP, DISCARD); sm->eap_if.eapResp = FALSE; sm->eap_if.eapNoReq = TRUE;}SM_STATE(EAP, SEND_REQUEST){ SM_ENTRY(EAP, SEND_REQUEST); sm->retransCount = 0; if (sm->eap_if.eapReqData) { if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) { sm->eap_if.eapResp = FALSE; sm->eap_if.eapReq = TRUE; } else { sm->eap_if.eapResp = FALSE; sm->eap_if.eapReq = FALSE; } } else { wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); sm->eap_if.eapResp = FALSE; sm->eap_if.eapReq = FALSE; sm->eap_if.eapNoReq = TRUE; }}SM_STATE(EAP, INTEGRITY_CHECK){ SM_ENTRY(EAP, INTEGRITY_CHECK); if (sm->m->check) { sm->ignore = sm->m->check(sm, sm->eap_method_priv, sm->eap_if.eapRespData); }}SM_STATE(EAP, METHOD_REQUEST){ SM_ENTRY(EAP, METHOD_REQUEST); if (sm->m == NULL) { wpa_printf(MSG_DEBUG, "EAP: method not initialized"); return; } sm->currentId = eap_sm_nextId(sm, sm->currentId); wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", sm->currentId); sm->lastId = sm->currentId; wpabuf_free(sm->eap_if.eapReqData); sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, sm->currentId); if (sm->m->getTimeout) sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); else sm->methodTimeout = 0;}SM_STATE(EAP, METHOD_RESPONSE){ SM_ENTRY(EAP, METHOD_RESPONSE); sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); if (sm->m->isDone(sm, sm->eap_method_priv)) { eap_sm_Policy_update(sm, NULL, 0); os_free(sm->eap_if.eapKeyData); if (sm->m->getKey) { sm->eap_if.eapKeyData = sm->m->getKey( sm, sm->eap_method_priv, &sm->eap_if.eapKeyDataLen); } else { sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; } sm->methodState = METHOD_END; } else { sm->methodState = METHOD_CONTINUE; }}SM_STATE(EAP, PROPOSE_METHOD){ int vendor; EapType type; SM_ENTRY(EAP, PROPOSE_METHOD); type = eap_sm_Policy_getNextMethod(sm, &vendor); if (vendor == EAP_VENDOR_IETF) sm->currentMethod = type; else sm->currentMethod = EAP_TYPE_EXPANDED; if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_server_get_eap_method(vendor, type); if (sm->m) { sm->eap_method_priv = sm->m->init(sm); if (sm->eap_method_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " "method %d", sm->currentMethod); sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } if (sm->currentMethod == EAP_TYPE_IDENTITY || sm->currentMethod == EAP_TYPE_NOTIFICATION) sm->methodState = METHOD_CONTINUE; else sm->methodState = METHOD_PROPOSED;}SM_STATE(EAP, NAK){ const struct eap_hdr *nak; size_t len = 0; const u8 *pos; const u8 *nak_list = NULL; SM_ENTRY(EAP, NAK); if (sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = NULL; nak = wpabuf_head(sm->eap_if.eapRespData); if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { len = be_to_host16(nak->length); if (len > wpabuf_len(sm->eap_if.eapRespData)) len = wpabuf_len(sm->eap_if.eapRespData); pos = (const u8 *) (nak + 1); len -= sizeof(*nak); if (*pos == EAP_TYPE_NAK) { pos++; len--; nak_list = pos; } } eap_sm_Policy_update(sm, nak_list, len);}SM_STATE(EAP, SELECT_ACTION){ SM_ENTRY(EAP, SELECT_ACTION); sm->decision = eap_sm_Policy_getDecision(sm);}SM_STATE(EAP, TIMEOUT_FAILURE){ SM_ENTRY(EAP, TIMEOUT_FAILURE); sm->eap_if.eapTimeout = TRUE;}SM_STATE(EAP, FAILURE){ SM_ENTRY(EAP, FAILURE); wpabuf_free(sm->eap_if.eapReqData); sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); wpabuf_free(sm->lastReqData); sm->lastReqData = NULL; sm->eap_if.eapFail = TRUE;}SM_STATE(EAP, SUCCESS){ SM_ENTRY(EAP, SUCCESS); wpabuf_free(sm->eap_if.eapReqData); sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); wpabuf_free(sm->lastReqData); sm->lastReqData = NULL; if (sm->eap_if.eapKeyData) sm->eap_if.eapKeyAvailable = TRUE; sm->eap_if.eapSuccess = TRUE;}SM_STATE(EAP, INITIALIZE_PASSTHROUGH){ SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); wpabuf_free(sm->eap_if.aaaEapRespData); sm->eap_if.aaaEapRespData = NULL;}SM_STATE(EAP, IDLE2){ SM_ENTRY(EAP, IDLE2); sm->eap_if.retransWhile = eap_sm_calculateTimeout( sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, sm->methodTimeout);}SM_STATE(EAP, RETRANSMIT2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -