📄 eapol_sm.c
字号:
/* * hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine * Copyright (c) 2002-2008, 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. */#include "includes.h"#include "hostapd.h"#include "ieee802_1x.h"#include "eapol_sm.h"#include "eloop.h"#include "wpa.h"#include "preauth.h"#include "sta_info.h"#include "eap_server/eap.h"#include "state_machine.h"#include "eap_common/eap_common.h"#define STATE_MACHINE_DATA struct eapol_state_machine#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"#define STATE_MACHINE_ADDR sm->addrstatic struct eapol_callbacks eapol_cb;/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */#define setPortAuthorized() \sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 1)#define setPortUnauthorized() \sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 0)/* procedures */#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)#define txReq() eapol_auth_tx_req(sm)#define abortAuth() sm->eapol->cb.abort_auth(sm->hapd, sm->sta)#define txKey() sm->eapol->cb.tx_key(sm->hapd, sm->sta)#define processKey() do { } while (0)static void eapol_sm_step_run(struct eapol_state_machine *sm);static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);static void eapol_auth_logger(struct eapol_authenticator *eapol, const u8 *addr, logger_level level, const char *txt){ if (eapol->cb.logger == NULL) return; eapol->cb.logger(eapol->conf.hapd, addr, level, txt);}static void eapol_auth_vlogger(struct eapol_authenticator *eapol, const u8 *addr, logger_level level, const char *fmt, ...){ char *format; int maxlen; va_list ap; if (eapol->cb.logger == NULL) return; maxlen = os_strlen(fmt) + 100; format = os_malloc(maxlen); if (!format) return; va_start(ap, fmt); vsnprintf(format, maxlen, fmt, ap); va_end(ap); eapol_auth_logger(eapol, addr, level, format); os_free(format);}static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm, int success){ struct eap_hdr eap; os_memset(&eap, 0, sizeof(eap)); eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; eap.identifier = ++sm->last_eap_id; eap.length = host_to_be16(sizeof(eap)); eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, "Sending canned EAP packet %s (identifier %d)", success ? "SUCCESS" : "FAILURE", eap.identifier); sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap)); sm->dot1xAuthEapolFramesTx++;}static void eapol_auth_tx_req(struct eapol_state_machine *sm){ if (sm->eap_if->eapReqData == NULL || wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) { eapol_auth_logger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, "TxReq called, but there is no EAP request " "from authentication server"); return; } if (sm->flags & EAPOL_SM_WAIT_START) { wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR " while waiting for EAPOL-Start", MAC2STR(sm->addr)); return; } sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData); eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, "Sending EAP Packet (identifier %d)", sm->last_eap_id); sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(sm->eap_if->eapReqData), wpabuf_len(sm->eap_if->eapReqData)); sm->dot1xAuthEapolFramesTx++; if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY) sm->dot1xAuthEapolReqIdFramesTx++; else sm->dot1xAuthEapolReqFramesTx++;}/** * eapol_port_timers_tick - Port Timers state machine * @eloop_ctx: struct eapol_state_machine * * @timeout_ctx: Not used * * This statemachine is implemented as a function that will be called * once a second as a registered event loop timeout. */static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx){ struct eapol_state_machine *state = timeout_ctx; if (state->aWhile > 0) { state->aWhile--; if (state->aWhile == 0) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " - aWhile --> 0", MAC2STR(state->addr)); } } if (state->quietWhile > 0) { state->quietWhile--; if (state->quietWhile == 0) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " - quietWhile --> 0", MAC2STR(state->addr)); } } if (state->reAuthWhen > 0) { state->reAuthWhen--; if (state->reAuthWhen == 0) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " - reAuthWhen --> 0", MAC2STR(state->addr)); } } if (state->eap_if->retransWhile > 0) { state->eap_if->retransWhile--; if (state->eap_if->retransWhile == 0) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " - (EAP) retransWhile --> 0", MAC2STR(state->addr)); } } eapol_sm_step_run(state); eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);}/* Authenticator PAE state machine */SM_STATE(AUTH_PAE, INITIALIZE){ SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae); sm->portMode = Auto;}SM_STATE(AUTH_PAE, DISCONNECTED){ int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE; if (sm->eapolLogoff) { if (sm->auth_pae_state == AUTH_PAE_CONNECTING) sm->authEapLogoffsWhileConnecting++; else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) sm->authAuthEapLogoffWhileAuthenticated++; } SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae); sm->authPortStatus = Unauthorized; setPortUnauthorized(); sm->reAuthCount = 0; sm->eapolLogoff = FALSE; if (!from_initialize) { sm->eapol->cb.finished(sm->hapd, sm->sta, 0, sm->flags & EAPOL_SM_PREAUTH); }}SM_STATE(AUTH_PAE, RESTART){ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) { if (sm->reAuthenticate) sm->authAuthReauthsWhileAuthenticated++; if (sm->eapolStart) sm->authAuthEapStartsWhileAuthenticated++; if (sm->eapolLogoff) sm->authAuthEapLogoffWhileAuthenticated++; } SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae); sm->eap_if->eapRestart = TRUE;}SM_STATE(AUTH_PAE, CONNECTING){ if (sm->auth_pae_state != AUTH_PAE_CONNECTING) sm->authEntersConnecting++; SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae); sm->reAuthenticate = FALSE; sm->reAuthCount++;}SM_STATE(AUTH_PAE, HELD){ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail) sm->authAuthFailWhileAuthenticating++; SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae); sm->authPortStatus = Unauthorized; setPortUnauthorized(); sm->quietWhile = sm->quietPeriod; sm->eapolLogoff = FALSE; eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING, "authentication failed - EAP type: %d (%s)", sm->eap_type_authsrv, eap_type_text(sm->eap_type_authsrv)); if (sm->eap_type_authsrv != sm->eap_type_supp) { eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, "Supplicant used different EAP type: " "%d (%s)", sm->eap_type_supp, eap_type_text(sm->eap_type_supp)); } sm->eapol->cb.finished(sm->hapd, sm->sta, 0, sm->flags & EAPOL_SM_PREAUTH);}SM_STATE(AUTH_PAE, AUTHENTICATED){ char *extra = ""; if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess) sm->authAuthSuccessesWhileAuthenticating++; SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae); sm->authPortStatus = Authorized; setPortAuthorized(); sm->reAuthCount = 0; if (sm->flags & EAPOL_SM_PREAUTH) extra = " (pre-authentication)"; else if (wpa_auth_sta_get_pmksa(sm->sta->wpa_sm)) extra = " (PMKSA cache)"; eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, "authenticated - EAP type: %d (%s)%s", sm->eap_type_authsrv, eap_type_text(sm->eap_type_authsrv), extra); sm->eapol->cb.finished(sm->hapd, sm->sta, 1, sm->flags & EAPOL_SM_PREAUTH);}SM_STATE(AUTH_PAE, AUTHENTICATING){ SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae); sm->eapolStart = FALSE; sm->authSuccess = FALSE; sm->authFail = FALSE; sm->authTimeout = FALSE; sm->authStart = TRUE; sm->keyRun = FALSE; sm->keyDone = FALSE;}SM_STATE(AUTH_PAE, ABORTING){ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) { if (sm->authTimeout) sm->authAuthTimeoutsWhileAuthenticating++; if (sm->eapolStart) sm->authAuthEapStartsWhileAuthenticating++; if (sm->eapolLogoff) sm->authAuthEapLogoffWhileAuthenticating++; } SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae); sm->authAbort = TRUE; sm->keyRun = FALSE; sm->keyDone = FALSE;}SM_STATE(AUTH_PAE, FORCE_AUTH){ SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae); sm->authPortStatus = Authorized; setPortAuthorized(); sm->portMode = ForceAuthorized; sm->eapolStart = FALSE; txCannedSuccess();}SM_STATE(AUTH_PAE, FORCE_UNAUTH){ SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae); sm->authPortStatus = Unauthorized; setPortUnauthorized(); sm->portMode = ForceUnauthorized; sm->eapolStart = FALSE; txCannedFail();}SM_STEP(AUTH_PAE){ if ((sm->portControl == Auto && sm->portMode != sm->portControl) || sm->initialize || !sm->eap_if->portEnabled) SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE); else if (sm->portControl == ForceAuthorized && sm->portMode != sm->portControl && !(sm->initialize || !sm->eap_if->portEnabled)) SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH); else if (sm->portControl == ForceUnauthorized && sm->portMode != sm->portControl && !(sm->initialize || !sm->eap_if->portEnabled)) SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH); else { switch (sm->auth_pae_state) { case AUTH_PAE_INITIALIZE: SM_ENTER(AUTH_PAE, DISCONNECTED); break; case AUTH_PAE_DISCONNECTED: SM_ENTER(AUTH_PAE, RESTART); break; case AUTH_PAE_RESTART: if (!sm->eap_if->eapRestart) SM_ENTER(AUTH_PAE, CONNECTING); break; case AUTH_PAE_HELD: if (sm->quietWhile == 0) SM_ENTER(AUTH_PAE, RESTART); break; case AUTH_PAE_CONNECTING: if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax) SM_ENTER(AUTH_PAE, DISCONNECTED); else if ((sm->eap_if->eapReq && sm->reAuthCount <= sm->reAuthMax) || sm->eap_if->eapSuccess || sm->eap_if->eapFail) SM_ENTER(AUTH_PAE, AUTHENTICATING); break; case AUTH_PAE_AUTHENTICATED: if (sm->eapolStart || sm->reAuthenticate) SM_ENTER(AUTH_PAE, RESTART); else if (sm->eapolLogoff || !sm->portValid) SM_ENTER(AUTH_PAE, DISCONNECTED); break; case AUTH_PAE_AUTHENTICATING: if (sm->authSuccess && sm->portValid) SM_ENTER(AUTH_PAE, AUTHENTICATED); else if (sm->authFail || (sm->keyDone && !sm->portValid)) SM_ENTER(AUTH_PAE, HELD); else if (sm->eapolStart || sm->eapolLogoff || sm->authTimeout) SM_ENTER(AUTH_PAE, ABORTING); break; case AUTH_PAE_ABORTING: if (sm->eapolLogoff && !sm->authAbort) SM_ENTER(AUTH_PAE, DISCONNECTED); else if (!sm->eapolLogoff && !sm->authAbort) SM_ENTER(AUTH_PAE, RESTART); break; case AUTH_PAE_FORCE_AUTH: if (sm->eapolStart) SM_ENTER(AUTH_PAE, FORCE_AUTH); break; case AUTH_PAE_FORCE_UNAUTH: if (sm->eapolStart) SM_ENTER(AUTH_PAE, FORCE_UNAUTH); break; } }}/* Backend Authentication state machine */SM_STATE(BE_AUTH, INITIALIZE){ SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth); abortAuth();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -