⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eap.c

📁 hostapd源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * hostapd / EAP Standalone Authenticator state machine (RFC 4137) * Copyright (c) 2004-2006, 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 "includes.h"#include "hostapd.h"#include "sta_info.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, 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, 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 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);}/** * eap_user_get - Fetch user information from the database * @sm: Pointer to EAP state machine allocated with eap_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 = wpa_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;	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 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->eapRespData, sm->eapRespDataLen);		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_sm_get_eap_methods(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->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){	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_sm_get_eap_methods(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){	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);	sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,					     &sm->eapReqDataLen);	if (sm->eapReqData) {		eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);		free(sm->eapReqData);		sm->eapReqData = NULL;		sm->eapReqDataLen = 0;	}	free(sm->lastReqData);	sm->lastReqData = NULL;	sm->lastReqDataLen = 0;	eapol_set_bool(sm, EAPOL_eapFail, TRUE);}SM_STATE(EAP, SUCCESS){	SM_ENTRY(EAP, SUCCESS);	free(sm->eapReqData);	sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,					     &sm->eapReqDataLen);	if (sm->eapReqData) {		eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);		free(sm->eapReqData);		sm->eapReqData = NULL;		sm->eapReqDataLen = 0;	}	free(sm->lastReqData);	sm->lastReqData = NULL;	sm->lastReqDataLen = 0;	if (sm->eapKeyData) {		eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);	}	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);}SM_STEP(EAP){	if (eapol_get_bool(sm, EAPOL_eapRestart) &&	    eapol_get_bool(sm, EAPOL_portEnabled))		SM_ENTER_GLOBAL(EAP, INITIALIZE);	else if (!eapol_get_bool(sm, EAPOL_portEnabled))		SM_ENTER_GLOBAL(EAP, DISABLED);	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {			wpa_printf(MSG_DEBUG, "EAP: more than %d "				   "authentication rounds - abort",				   EAP_MAX_AUTH_ROUNDS);			sm->num_rounds++;			SM_ENTER_GLOBAL(EAP, FAILURE);		}	} else switch (sm->EAP_state) {	case EAP_INITIALIZE:		if (sm->backend_auth) {			if (!sm->rxResp)				SM_ENTER(EAP, SELECT_ACTION);			else if (sm->rxResp &&				 (sm->respMethod == EAP_TYPE_NAK ||				  (sm->respMethod == EAP_TYPE_EXPANDED &&				   sm->respVendor == EAP_VENDOR_IETF &&				   sm->respVendorMethod == EAP_TYPE_NAK)))				SM_ENTER(EAP, NAK);			else				SM_ENTER(EAP, PICK_UP_METHOD);		} else {			SM_ENTER(EAP, SELECT_ACTION);		}		break;	case EAP_PICK_UP_METHOD:		if (sm->currentMethod == EAP_TYPE_NONE) {			SM_ENTER(EAP, SELECT_ACTION);		} else {			SM_ENTER(EAP, METHOD_RESPONSE);		}		break;	case EAP_DISABLED:		if (eapol_get_bool(sm, EAPOL_portEnabled))			SM_ENTER(EAP, INITIALIZE);		break;	case EAP_IDLE:		if (sm->retransWhile == 0)			SM_ENTER(EAP, RETRANSMIT);		else if (eapol_get_bool(sm, EAPOL_eapResp))			SM_ENTER(EAP, RECEIVED);		break;	case EAP_RETRANSMIT:		if (sm->retransCount > sm->MaxRetrans)			SM_ENTER(EAP, TIMEOUT_FAILURE);		else			SM_ENTER(EAP, IDLE);		break;	case EAP_RECEIVED:		if (sm->rxResp && (sm->respId == sm->currentId) &&		    (sm->respMethod == EAP_TYPE_NAK ||		     (sm->respMethod == EAP_TYPE_EXPANDED &&		      sm->respVendor == EAP_VENDOR_IETF &&		      sm->respVendorMethod == EAP_TYPE_NAK))		    && (sm->methodState == METHOD_PROPOSED))			SM_ENTER(EAP, NAK);		else if (sm->rxResp && (sm->respId == sm->currentId) &&			 ((sm->respMethod == sm->currentMethod) ||			  (sm->respMethod == EAP_TYPE_EXPANDED &&			   sm->respVendor == EAP_VENDOR_IETF &&			   sm->respVendorMethod == sm->currentMethod)))			SM_ENTER(EAP, INTEGRITY_CHECK);		else {			wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "				   "rxResp=%d respId=%d currentId=%d "				   "respMethod=%d currentMethod=%d",				   sm->rxResp, sm->respId, sm->currentId,				   sm->respMethod, sm->currentMethod);			SM_ENTER(EAP, DISCARD);		}		break;	case EAP_DISCARD:		SM_ENTER(EAP, IDLE);		break;	case EAP_SEND_REQUEST:		SM_ENTER(EAP, IDLE);		break;	case EAP_INTEGRITY_CHECK:		if (sm->ignore)			SM_ENTER(EAP, DISCARD);		else			SM_ENTER(EAP, METHOD_RESPONSE);		break;	case EAP_METHOD_REQUEST:		SM_ENTER(EAP, SEND_REQUEST);		break;	case EAP_METHOD_RESPONSE:		/*		 * Note: Mechanism to allow EAP methods to wait while going		 * through pending processing is an extension to RFC 4137		 * which only defines the transits to SELECT_ACTION and		 * METHOD_REQUEST from this METHOD_RESPONSE state.		 */		if (sm->methodState == METHOD_END)			SM_ENTER(EAP, SELECT_ACTION);		else if (sm->method_pending == METHOD_PENDING_WAIT) {			wpa_printf(MSG_DEBUG, "EAP: Method has pending "				   "processing - wait before proceeding to "				   "METHOD_REQUEST state");		} else if (sm->method_pending == METHOD_PENDING_CONT) {			wpa_printf(MSG_DEBUG, "EAP: Method has completed "				   "pending processing - reprocess pending "				   "EAP message");			sm->method_pending = METHOD_PENDING_NONE;			SM_ENTER(EAP, METHOD_RESPONSE);		} else			SM_ENTER(EAP, METHOD_REQUEST);		break;	case EAP_PROPOSE_METHOD:		/*		 * Note: Mechanism to allow EAP methods to wait while going		 * through pending processing is an extension to RFC 4137		 * which only defines the transit to METHOD_REQUEST from this		 * PROPOSE_METHOD state.		 */		if (sm->method_pending == METHOD_PENDING_WAIT) {			wpa_printf(MSG_DEBUG, "EAP: Method has pending "				   "processing - wait before proceeding to "				   "METHOD_REQUEST state");			if (sm->user_eap_method_index > 0)				sm->user_eap_method_index--;		} else if (sm->method_pending == METHOD_PENDING_CONT) {			wpa_printf(MSG_DEBUG, "EAP: Method has completed "				   "pending processing - reprocess pending "				   "EAP message");			sm->method_pending = METHOD_PENDING_NONE;			SM_ENTER(EAP, PROPOSE_METHOD);		} else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -