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

📄 eap.c

📁 WPA在Linux下实现的原代码 WPA在Linux下实现的原代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 * Handles requests for Identity method and builds a response. */SM_STATE(EAP, IDENTITY){	const u8 *eapReqData;	size_t eapReqDataLen;	SM_ENTRY(EAP, IDENTITY);	eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);	eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);	free(sm->eapRespData);	sm->eapRespData = NULL;	sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,					       &sm->eapRespDataLen, 0);}/* * Handles requests for Notification method and builds a response. */SM_STATE(EAP, NOTIFICATION){	const u8 *eapReqData;	size_t eapReqDataLen;	SM_ENTRY(EAP, NOTIFICATION);	eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);	eap_sm_processNotify(sm, eapReqData, eapReqDataLen);	free(sm->eapRespData);	sm->eapRespData = NULL;	sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,					     &sm->eapRespDataLen);}/* * This state retransmits the previous response packet. */SM_STATE(EAP, RETRANSMIT){	SM_ENTRY(EAP, RETRANSMIT);	free(sm->eapRespData);	if (sm->lastRespData) {		sm->eapRespData = malloc(sm->lastRespDataLen);		if (sm->eapRespData) {			memcpy(sm->eapRespData, sm->lastRespData,			       sm->lastRespDataLen);			sm->eapRespDataLen = sm->lastRespDataLen;		}	} else		sm->eapRespData = NULL;}/* * This state is entered in case of a successful completion of authentication * and state machine waits here until port is disabled or EAP authentication is * restarted. */SM_STATE(EAP, SUCCESS){	SM_ENTRY(EAP, SUCCESS);	if (sm->eapKeyData != NULL)		sm->eapKeyAvailable = TRUE;	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);	/*	 * RFC 4137 does not clear eapReq here, but this seems to be required	 * to avoid processing the same request twice when state machine is	 * initialized.	 */	eapol_set_bool(sm, EAPOL_eapReq, FALSE);	/*	 * RFC 4137 does not set eapNoResp here, but this seems to be required	 * to get EAPOL Supplicant backend state machine into SUCCESS state. In	 * addition, either eapResp or eapNoResp is required to be set after	 * processing the received EAP frame.	 */	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS		"EAP authentication completed successfully");}/* * This state is entered in case of a failure and state machine waits here * until port is disabled or EAP authentication is restarted. */SM_STATE(EAP, FAILURE){	SM_ENTRY(EAP, FAILURE);	eapol_set_bool(sm, EAPOL_eapFail, TRUE);	/*	 * RFC 4137 does not clear eapReq here, but this seems to be required	 * to avoid processing the same request twice when state machine is	 * initialized.	 */	eapol_set_bool(sm, EAPOL_eapReq, FALSE);	/*	 * RFC 4137 does not set eapNoResp here. However, either eapResp or	 * eapNoResp is required to be set after processing the received EAP	 * frame.	 */	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE		"EAP authentication failed");}static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId){	/*	 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending	 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and	 * RFC 4137 require that reqId == lastId. In addition, it looks like	 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.	 *	 * Accept this kind of Id if EAP workarounds are enabled. These are	 * unauthenticated plaintext messages, so this should have minimal	 * security implications (bit easier to fake EAP-Success/Failure).	 */	if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||			       reqId == ((lastId + 2) & 0xff))) {		wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "			   "identifier field in EAP Success: "			   "reqId=%d lastId=%d (these are supposed to be "			   "same)", reqId, lastId);		return 1;	}	wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "		   "lastId=%d", reqId, lastId);	return 0;}/* * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions */SM_STEP(EAP){	int duplicate;	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->force_disabled)		SM_ENTER_GLOBAL(EAP, DISABLED);	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {		/* RFC 4137 does not place any limit on number of EAP messages		 * in an authentication session. However, some error cases have		 * ended up in a state were EAP messages were sent between the		 * peer and server in a loop (e.g., TLS ACK frame in both		 * direction). Since this is quite undesired outcome, limit the		 * total number of EAP round-trips and abort authentication if		 * this limit is exceeded.		 */		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {			wpa_msg(sm->msg_ctx, MSG_INFO, "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:		SM_ENTER(EAP, IDLE);		break;	case EAP_DISABLED:		if (eapol_get_bool(sm, EAPOL_portEnabled) &&		    !sm->force_disabled)			SM_ENTER(EAP, INITIALIZE);		break;	case EAP_IDLE:		/*		 * The first three transitions are from RFC 4137. The last two		 * are local additions to handle special cases with LEAP and		 * PEAP server not sending EAP-Success in some cases.		 */		if (eapol_get_bool(sm, EAPOL_eapReq))			SM_ENTER(EAP, RECEIVED);		else if ((eapol_get_bool(sm, EAPOL_altAccept) &&			  sm->decision != DECISION_FAIL) ||			 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&			  sm->decision == DECISION_UNCOND_SUCC))			SM_ENTER(EAP, SUCCESS);		else if (eapol_get_bool(sm, EAPOL_altReject) ||			 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&			  sm->decision != DECISION_UNCOND_SUCC) ||			 (eapol_get_bool(sm, EAPOL_altAccept) &&			  sm->methodState != METHOD_CONT &&			  sm->decision == DECISION_FAIL))			SM_ENTER(EAP, FAILURE);		else if (sm->selectedMethod == EAP_TYPE_LEAP &&			 sm->leap_done && sm->decision != DECISION_FAIL &&			 sm->methodState == METHOD_DONE)			SM_ENTER(EAP, SUCCESS);		else if (sm->selectedMethod == EAP_TYPE_PEAP &&			 sm->peap_done && sm->decision != DECISION_FAIL &&			 sm->methodState == METHOD_DONE)			SM_ENTER(EAP, SUCCESS);		break;	case EAP_RECEIVED:		duplicate = (sm->reqId == sm->lastId) && sm->rxReq;		if (sm->workaround && duplicate &&		    memcmp(sm->req_md5, sm->last_md5, 16) != 0) {			/*			 * RFC 4137 uses (reqId == lastId) as the only			 * verification for duplicate EAP requests. However,			 * this misses cases where the AS is incorrectly using			 * the same id again; and unfortunately, such			 * implementations exist. Use MD5 hash as an extra			 * verification for the packets being duplicate to			 * workaround these issues.			 */			wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"				   " but EAP packets were not identical");			wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "				   "is not a duplicate packet");			duplicate = 0;		}		/*		 * Two special cases below for LEAP are local additions to work		 * around odd LEAP behavior (EAP-Success in the middle of		 * authentication and then swapped roles). Other transitions		 * are based on RFC 4137.		 */		if (sm->rxSuccess && sm->decision != DECISION_FAIL &&		    (sm->reqId == sm->lastId ||		     eap_success_workaround(sm, sm->reqId, sm->lastId)))			SM_ENTER(EAP, SUCCESS);		else if (sm->methodState != METHOD_CONT &&			 ((sm->rxFailure &&			   sm->decision != DECISION_UNCOND_SUCC) ||			  (sm->rxSuccess && sm->decision == DECISION_FAIL &&			   (sm->selectedMethod != EAP_TYPE_LEAP ||			    sm->methodState != METHOD_MAY_CONT))) &&			 (sm->reqId == sm->lastId ||			  eap_success_workaround(sm, sm->reqId, sm->lastId)))			SM_ENTER(EAP, FAILURE);		else if (sm->rxReq && duplicate)			SM_ENTER(EAP, RETRANSMIT);		else if (sm->rxReq && !duplicate &&			 sm->reqMethod == EAP_TYPE_NOTIFICATION &&			 sm->allowNotifications)			SM_ENTER(EAP, NOTIFICATION);		else if (sm->rxReq && !duplicate &&			 sm->selectedMethod == EAP_TYPE_NONE &&			 sm->reqMethod == EAP_TYPE_IDENTITY)			SM_ENTER(EAP, IDENTITY);		else if (sm->rxReq && !duplicate &&			 sm->selectedMethod == EAP_TYPE_NONE &&			 sm->reqMethod != EAP_TYPE_IDENTITY &&			 sm->reqMethod != EAP_TYPE_NOTIFICATION)			SM_ENTER(EAP, GET_METHOD);		else if (sm->rxReq && !duplicate &&			 sm->reqMethod == sm->selectedMethod &&			 sm->methodState != METHOD_DONE)			SM_ENTER(EAP, METHOD);		else if (sm->selectedMethod == EAP_TYPE_LEAP &&			 (sm->rxSuccess || sm->rxResp))			SM_ENTER(EAP, METHOD);		else			SM_ENTER(EAP, DISCARD);		break;	case EAP_GET_METHOD:		if (sm->selectedMethod == sm->reqMethod)			SM_ENTER(EAP, METHOD);		else			SM_ENTER(EAP, SEND_RESPONSE);		break;	case EAP_METHOD:		if (sm->ignore)			SM_ENTER(EAP, DISCARD);		else			SM_ENTER(EAP, SEND_RESPONSE);		break;	case EAP_SEND_RESPONSE:		SM_ENTER(EAP, IDLE);		break;	case EAP_DISCARD:		SM_ENTER(EAP, IDLE);		break;	case EAP_IDENTITY:		SM_ENTER(EAP, SEND_RESPONSE);		break;	case EAP_NOTIFICATION:		SM_ENTER(EAP, SEND_RESPONSE);		break;	case EAP_RETRANSMIT:		SM_ENTER(EAP, SEND_RESPONSE);		break;	case EAP_SUCCESS:		break;	case EAP_FAILURE:		break;	}}static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method){	struct wpa_ssid *config = eap_get_config(sm);	int i;	if (!wpa_config_allowed_eap_method(config, method))		return FALSE;	for (i = 0; i < NUM_EAP_METHODS; i++) {		if (eap_methods[i]->method == method)			return TRUE;	}	return FALSE;}static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len){	struct wpa_ssid *config = eap_get_config(sm);	struct eap_hdr *resp;	u8 *pos;	int i, found = 0;	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "		   "allowed)", sm->reqMethod);	*len = sizeof(struct eap_hdr) + 1;	resp = malloc(*len + NUM_EAP_METHODS);	if (resp == NULL)		return NULL;	resp->code = EAP_CODE_RESPONSE;	resp->identifier = id;	pos = (u8 *) (resp + 1);	*pos++ = EAP_TYPE_NAK;	for (i = 0; i < NUM_EAP_METHODS; i++) {		if (eap_methods[i]->method != sm->reqMethod &&		    wpa_config_allowed_eap_method(config,						  eap_methods[i]->method)) {			*pos++ = eap_methods[i]->method;			(*len)++;			found++;		}	}	if (!found) {		*pos = EAP_TYPE_NONE;		(*len)++;	}	wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",		    ((u8 *) (resp + 1)) + 1, found);	resp->length = host_to_be16(*len);	return (u8 *) resp;}static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,				   size_t len){	const struct eap_hdr *hdr = (const struct eap_hdr *) req;	const u8 *pos = (const u8 *) (hdr + 1);	pos++;	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED		"EAP authentication started");	/*	 * RFC 3748 - 5.1: Identity	 * Data field may contain a displayable message in UTF-8. If this	 * includes NUL-character, only the data before that should be	 * displayed. Some EAP implementasitons may piggy-back additional	 * options after the NUL.	 */	/* TODO: could save displayable message so that it can be shown to the	 * user in case of interaction is required */	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",			  pos, be_to_host16(hdr->length) - 5);}#ifdef PCSC_FUNCSstatic int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid){	int aka = 0;	char imsi[100];	size_t imsi_len;	u8 *pos = ssid->eap_methods;	imsi_len = sizeof(imsi);	if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {		wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");		return -1;	}	wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);	while (pos && *pos != EAP_TYPE_NONE) {		if (*pos == EAP_TYPE_AKA) {			aka = 1;			break;		}		pos++;	}	free(ssid->identity);	ssid->identity = malloc(1 + imsi_len);	if (ssid->identity == NULL) {		wpa_printf(MSG_WARNING, "Failed to allocate buffer for "			   "IMSI-based identity");		return -1;	}	ssid->identity[0] = aka ? '0' : '1';	memcpy(ssid->identity + 1, imsi, imsi_len);	ssid->identity_len = 1 + imsi_len;	return 0;}#endif /* PCSC_FUNCS */static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid){#ifdef PCSC_FUNCS	if (scard_set_pin(sm->scard_ctx, ssid->pin)) {		/*		 * Make sure the same PIN is not tried again in order to avoid		 * blocking SIM.		 */		free(ssid->pin);		ssid->pin = NULL;		wpa_printf(MSG_WARNING, "PIN validation failed");		eap_sm_request_pin(sm, ssid);		return -1;	}	return eap_sm_imsi_identity(sm, ssid);#else /* PCSC_FUNCS */	return -1;#endif /* PCSC_FUNCS */}/** * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network * @sm: Pointer to EAP state machine allocated with eap_sm_init() * @id: EAP identifier for the packet * @len: Pointer to a variable that will be set to the length of the response * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2) * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on * failure * * This function allocates and builds an EAP-Identity/Response packet for the * current network. The caller is responsible for freeing the returned data. */u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,			  int encrypted){	struct wpa_ssid *config = eap_get_config(sm);	struct eap_hdr *resp;	u8 *pos;	const u8 *identity;	size_t identity_len;	if (config == NULL) {		wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "			   "was not available");		return NULL;	}	if (sm->m && sm->m->get_identity &&	    (identity = sm->m->get_identity(sm, sm->eap_method_priv,					    &identity_len)) != NULL) {		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "				  "identity", identity, identity_len);	} else if (!encrypted && config->anonymous_identity) {		identity = config->anonymous_identity;		identity_len = config->anonymous_identity_len;		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",				  identity, identity_len);

⌨️ 快捷键说明

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