📄 eap.c
字号:
/* * hostapd / EAP Standalone Authenticator state machine * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>#include <stdio.h>#include <unistd.h>#include <netinet/in.h>#include <string.h>#include <sys/socket.h>#include "hostapd.h"#include "eloop.h"#include "sta_info.h"#include "eap_i.h"#define EAP_MAX_AUTH_ROUNDS 50extern const struct eap_method eap_method_identity;#ifdef EAP_MD5extern const struct eap_method eap_method_md5;#endif /* EAP_MD5 */#ifdef EAP_TLSextern const struct eap_method eap_method_tls;#endif /* EAP_TLS */#ifdef EAP_MSCHAPv2extern const struct eap_method eap_method_mschapv2;#endif /* EAP_MSCHAPv2 */#ifdef EAP_PEAPextern const struct eap_method eap_method_peap;#endif /* EAP_PEAP */#ifdef EAP_TLVextern const struct eap_method eap_method_tlv;#endif /* EAP_TLV */#ifdef EAP_GTCextern const struct eap_method eap_method_gtc;#endif /* EAP_GTC */#ifdef EAP_TTLSextern const struct eap_method eap_method_ttls;#endif /* EAP_TTLS */#ifdef EAP_SIMextern const struct eap_method eap_method_sim;#endif /* EAP_SIM */#ifdef EAP_PAXextern const struct eap_method eap_method_pax;#endif /* EAP_PAX */static const struct eap_method *eap_methods[] ={ &eap_method_identity,#ifdef EAP_MD5 &eap_method_md5,#endif /* EAP_MD5 */#ifdef EAP_TLS &eap_method_tls,#endif /* EAP_TLS */#ifdef EAP_MSCHAPv2 &eap_method_mschapv2,#endif /* EAP_MSCHAPv2 */#ifdef EAP_PEAP &eap_method_peap,#endif /* EAP_PEAP */#ifdef EAP_TTLS &eap_method_ttls,#endif /* EAP_TTLS */#ifdef EAP_TLV &eap_method_tlv,#endif /* EAP_TLV */#ifdef EAP_GTC &eap_method_gtc,#endif /* EAP_GTC */#ifdef EAP_SIM &eap_method_sim,#endif /* EAP_SIM */#ifdef EAP_PAX &eap_method_pax,#endif /* EAP_PAX */};#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))const struct eap_method * eap_sm_get_eap_methods(int method){ int i; for (i = 0; i < NUM_EAP_METHODS; i++) { if (eap_methods[i]->method == method) return eap_methods[i]; } return NULL;}static void eap_user_free(struct eap_user *user);/* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */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, u8 *resp, size_t len);static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);static int eap_sm_nextId(struct eap_sm *sm, int id);static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);static int eap_sm_Policy_getDecision(struct eap_sm *sm);static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);/* Definitions for clarifying state machine implementation */#define SM_STATE(machine, state) \static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \ int global)#define SM_ENTRY(machine, state) \if (!global || sm->machine ## _state != machine ## _ ## state) { \ sm->changed = TRUE; \ wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \} \sm->machine ## _state = machine ## _ ## state;#define SM_ENTER(machine, state) \sm_ ## machine ## _ ## state ## _Enter(sm, 0)#define SM_ENTER_GLOBAL(machine, state) \sm_ ## machine ## _ ## state ## _Enter(sm, 1)#define SM_STEP(machine) \static void sm_ ## machine ## _Step(struct eap_sm *sm)#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var){ return sm->eapol_cb->get_bool(sm->eapol_ctx, var);}static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var, Boolean value){ sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);}static void eapol_set_eapReqData(struct eap_sm *sm, const u8 *eapReqData, size_t eapReqDataLen){ wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL", sm->eapReqData, sm->eapReqDataLen); sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);}static void eapol_set_eapKeyData(struct eap_sm *sm, const u8 *eapKeyData, size_t eapKeyDataLen){ wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL", sm->eapKeyData, sm->eapKeyDataLen); sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);}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 = malloc(sizeof(*user)); if (user == NULL) return -1; memset(user, 0, sizeof(*user)); 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; eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); eapol_set_bool(sm, EAPOL_eapFail, FALSE); eapol_set_bool(sm, EAPOL_eapTimeout, FALSE); free(sm->eapKeyData); sm->eapKeyData = NULL; sm->eapKeyDataLen = 0; /* eapKeyAvailable = FALSE */ eapol_set_bool(sm, EAPOL_eapRestart, FALSE); /* This is not defined in draft-ietf-eap-statemachine-05.txt, 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->eapRespData, sm->eapRespDataLen); if (sm->rxResp) { sm->currentId = sm->respId; } } sm->num_rounds = 0;}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_sm_get_eap_methods(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->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount, sm->eapSRTT, sm->eapRTTVAR, sm->methodTimeout);}SM_STATE(EAP, RETRANSMIT){ SM_ENTRY(EAP, RETRANSMIT); /* TODO: Is this needed since EAPOL state machines take care of * retransmit? */}SM_STATE(EAP, RECEIVED){ SM_ENTRY(EAP, RECEIVED); /* parse rxResp, respId, respMethod */ eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen); sm->num_rounds++;}SM_STATE(EAP, DISCARD){ SM_ENTRY(EAP, DISCARD); eapol_set_bool(sm, EAPOL_eapResp, FALSE); eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);}SM_STATE(EAP, SEND_REQUEST){ SM_ENTRY(EAP, SEND_REQUEST); sm->retransCount = 0; if (sm->eapReqData) { eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen); free(sm->lastReqData); sm->lastReqData = sm->eapReqData; sm->lastReqDataLen = sm->eapReqDataLen; sm->eapReqData = NULL; sm->eapReqDataLen = 0; eapol_set_bool(sm, EAPOL_eapResp, FALSE); eapol_set_bool(sm, EAPOL_eapReq, TRUE); } else { wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); eapol_set_bool(sm, EAPOL_eapResp, FALSE); eapol_set_bool(sm, EAPOL_eapReq, FALSE); eapol_set_bool(sm, EAPOL_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->eapRespData, sm->eapRespDataLen); }}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; free(sm->eapReqData); sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, sm->currentId, &sm->eapReqDataLen); 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->eapRespData, sm->eapRespDataLen); if (sm->m->isDone(sm, sm->eap_method_priv)) { eap_sm_Policy_update(sm, NULL, 0); free(sm->eapKeyData); if (sm->m->getKey) { sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, &sm->eapKeyDataLen); } else { sm->eapKeyData = NULL; sm->eapKeyDataLen = 0; } sm->methodState = METHOD_END; } else { sm->methodState = METHOD_CONTINUE; }}SM_STATE(EAP, PROPOSE_METHOD){ SM_ENTRY(EAP, PROPOSE_METHOD); sm->currentMethod = eap_sm_Policy_getNextMethod(sm); if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_sm_get_eap_methods(sm->currentMethod); 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){ struct eap_hdr *nak; size_t len = 0; u8 *pos, *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 = (struct eap_hdr *) sm->eapRespData; if (nak && sm->eapRespDataLen > sizeof(*nak)) { len = ntohs(nak->length); if (len > sm->eapRespDataLen) len = sm->eapRespDataLen; pos = (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); eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);}SM_STATE(EAP, FAILURE){ SM_ENTRY(EAP, FAILURE); free(sm->eapReqData);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -