📄 eap.c
字号:
SM_ENTER(EAP, METHOD_REQUEST); break; case EAP_NAK: SM_ENTER(EAP, SELECT_ACTION); break; case EAP_SELECT_ACTION: if (sm->decision == DECISION_FAILURE) SM_ENTER(EAP, FAILURE); else if (sm->decision == DECISION_SUCCESS) SM_ENTER(EAP, SUCCESS); else SM_ENTER(EAP, PROPOSE_METHOD); break; case EAP_TIMEOUT_FAILURE: break; case EAP_FAILURE: break; case EAP_SUCCESS: break; }}static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, int eapSRTT, int eapRTTVAR, int methodTimeout){ /* For now, retransmission is done in EAPOL state machines, so make * sure EAP state machine does not end up trying to retransmit packets. */ return 1;}static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len){ struct eap_hdr *hdr; size_t plen; /* parse rxResp, respId, respMethod */ sm->rxResp = FALSE; sm->respId = -1; sm->respMethod = EAP_TYPE_NONE; sm->respVendor = EAP_VENDOR_IETF; sm->respVendorMethod = EAP_TYPE_NONE; if (resp == NULL || len < sizeof(*hdr)) return; hdr = (struct eap_hdr *) resp; plen = ntohs(hdr->length); if (plen > len) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " "(len=%lu plen=%lu)", (unsigned long) len, (unsigned long) plen); return; } sm->respId = hdr->identifier; if (hdr->code == EAP_CODE_RESPONSE) sm->rxResp = TRUE; if (plen > sizeof(*hdr)) { u8 *pos = (u8 *) (hdr + 1); sm->respMethod = *pos++; if (sm->respMethod == EAP_TYPE_EXPANDED) { if (plen < sizeof(*hdr) + 8) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " "expanded EAP-Packet (plen=%lu)", (unsigned long) plen); return; } sm->respVendor = WPA_GET_BE24(pos); pos += 3; sm->respVendorMethod = WPA_GET_BE32(pos); } } wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " "respMethod=%u respVendor=%u respVendorMethod=%u", sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, sm->respVendorMethod);}static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len){ struct eap_hdr *resp; wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); *len = sizeof(*resp); resp = malloc(*len); if (resp == NULL) return NULL; resp->code = EAP_CODE_SUCCESS; resp->identifier = id; resp->length = htons(*len); return (u8 *) resp;}static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len){ struct eap_hdr *resp; wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); *len = sizeof(*resp); resp = malloc(*len); if (resp == NULL) return NULL; resp->code = EAP_CODE_FAILURE; resp->identifier = id; resp->length = htons(*len); return (u8 *) resp;}static int eap_sm_nextId(struct eap_sm *sm, int id){ if (id < 0) { /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a * random number */ id = rand() & 0xff; if (id != sm->lastId) return id; } return (id + 1) & 0xff;}/** * eap_sm_process_nak - Process EAP-Response/Nak * @sm: Pointer to EAP state machine allocated with eap_sm_init() * @nak_list: Nak list (allowed methods) from the supplicant * @len: Length of nak_list in bytes * * This function is called when EAP-Response/Nak is received from the * supplicant. This can happen for both phase 1 and phase 2 authentications. */void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len){ int i, j; wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " "index %d)", sm->user_eap_method_index); wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", (u8 *) sm->user->methods, EAP_MAX_METHODS * sizeof(sm->user->methods[0])); wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", nak_list, len); i = sm->user_eap_method_index; while (i < EAP_MAX_METHODS && (sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_NONE)) { if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) goto not_found; for (j = 0; j < len; j++) { if (nak_list[j] == sm->user->methods[i].method) { break; } } if (j < len) { /* found */ i++; continue; } not_found: /* not found - remove from the list */ memmove(&sm->user->methods[i], &sm->user->methods[i + 1], (EAP_MAX_METHODS - i - 1) * sizeof(sm->user->methods[0])); sm->user->methods[EAP_MAX_METHODS - 1].vendor = EAP_VENDOR_IETF; sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; } wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", (u8 *) sm->user->methods, EAP_MAX_METHODS * sizeof(sm->user->methods[0]));}static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len){ if (nak_list == NULL || sm == NULL || sm->user == NULL) return; if (sm->user->phase2) { wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" " info was selected - reject"); sm->decision = DECISION_FAILURE; return; } eap_sm_process_nak(sm, nak_list, len);}static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor){ EapType next; int idx = sm->user_eap_method_index; /* In theory, there should be no problems with starting * re-authentication with something else than EAP-Request/Identity and * this does indeed work with wpa_supplicant. However, at least Funk * Supplicant seemed to ignore re-auth if it skipped * EAP-Request/Identity. * Re-auth sets currentId == -1, so that can be used here to select * whether Identity needs to be requested again. */ if (sm->identity == NULL || sm->currentId == -1) { *vendor = EAP_VENDOR_IETF; next = EAP_TYPE_IDENTITY; sm->update_user = TRUE; } else if (sm->user && idx < EAP_MAX_METHODS && (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || sm->user->methods[idx].method != EAP_TYPE_NONE)) { *vendor = sm->user->methods[idx].vendor; next = sm->user->methods[idx].method; sm->user_eap_method_index++; } else { *vendor = EAP_VENDOR_IETF; next = EAP_TYPE_NONE; } wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", *vendor, next); return next;}static int eap_sm_Policy_getDecision(struct eap_sm *sm){ if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && sm->m->isSuccess(sm, sm->eap_method_priv)) { wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " "SUCCESS"); sm->update_user = TRUE; return DECISION_SUCCESS; } if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && !sm->m->isSuccess(sm, sm->eap_method_priv)) { wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " "FAILURE"); sm->update_user = TRUE; return DECISION_FAILURE; } if ((sm->user == NULL || sm->update_user) && sm->identity) { if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " "found from database -> FAILURE"); return DECISION_FAILURE; } sm->update_user = FALSE; } if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && (sm->user->methods[sm->user_eap_method_index].vendor != EAP_VENDOR_IETF || sm->user->methods[sm->user_eap_method_index].method != EAP_TYPE_NONE)) { wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " "available -> CONTINUE"); return DECISION_CONTINUE; } if (sm->identity == NULL || sm->currentId == -1) { wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " "yet -> CONTINUE"); return DECISION_CONTINUE; } wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " "FAILURE"); return DECISION_FAILURE;}static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method){ return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;}/** * eap_sm_step - Step EAP state machine * @sm: Pointer to EAP state machine allocated with eap_sm_init() * Returns: 1 if EAP state was changed or 0 if not * * This function advances EAP state machine to a new state to match with the * current variables. This should be called whenever variables used by the EAP * state machine have changed. */int eap_sm_step(struct eap_sm *sm){ int res = 0; do { sm->changed = FALSE; SM_STEP_RUN(EAP); if (sm->changed) res = 1; } while (sm->changed); return res;}/** * eap_set_eapRespData - Set EAP response (eapRespData) * @sm: Pointer to EAP state machine allocated with eap_sm_init() * @eapRespData: EAP-Response payload from the supplicant * @eapRespDataLen: Length of eapRespData in bytes * * This function is called when an EAP-Response is received from a supplicant. */void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData, size_t eapRespDataLen){ if (sm == NULL) return; free(sm->eapRespData); sm->eapRespData = malloc(eapRespDataLen); if (sm->eapRespData == NULL) return; memcpy(sm->eapRespData, eapRespData, eapRespDataLen); sm->eapRespDataLen = eapRespDataLen; wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received", eapRespData, eapRespDataLen);}static void eap_user_free(struct eap_user *user){ if (user == NULL) return; free(user->password); user->password = NULL; free(user);}/** * eap_sm_init - Allocate and initialize EAP state machine * @eapol_ctx: Context data to be used with eapol_cb calls * @eapol_cb: Pointer to EAPOL callback functions * @conf: EAP configuration * Returns: Pointer to the allocated EAP state machine or %NULL on failure * * This function allocates and initializes an EAP state machine. */struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb, struct eap_config *conf){ struct eap_sm *sm; sm = wpa_zalloc(sizeof(*sm)); if (sm == NULL) return NULL; sm->eapol_ctx = eapol_ctx; sm->eapol_cb = eapol_cb; sm->MaxRetrans = 10; sm->ssl_ctx = conf->ssl_ctx; sm->eap_sim_db_priv = conf->eap_sim_db_priv; sm->backend_auth = conf->backend_auth; wpa_printf(MSG_DEBUG, "EAP: State machine created"); return sm;}/** * eap_sm_deinit - Deinitialize and free an EAP state machine * @sm: Pointer to EAP state machine allocated with eap_sm_init() * * This function deinitializes EAP state machine and frees all allocated * resources. */void eap_sm_deinit(struct eap_sm *sm){ if (sm == NULL) return; wpa_printf(MSG_DEBUG, "EAP: State machine removed"); if (sm->m && sm->eap_method_priv) sm->m->reset(sm, sm->eap_method_priv); free(sm->eapReqData); free(sm->eapKeyData); free(sm->lastReqData); free(sm->eapRespData); free(sm->identity); eap_user_free(sm->user); free(sm);}/** * eap_sm_notify_cached - Notify EAP state machine of cached PMK * @sm: Pointer to EAP state machine allocated with eap_sm_init() * * This function is called when PMKSA caching is used to skip EAP * authentication. */void eap_sm_notify_cached(struct eap_sm *sm){ if (sm == NULL) return; sm->EAP_state = EAP_SUCCESS;}/** * eap_sm_pending_cb - EAP state machine callback for a pending EAP request * @sm: Pointer to EAP state machine allocated with eap_sm_init() * * This function is called when data for a pending EAP-Request is received. */void eap_sm_pending_cb(struct eap_sm *sm){ if (sm == NULL) return; wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); if (sm->method_pending == METHOD_PENDING_WAIT) sm->method_pending = METHOD_PENDING_CONT;}/** * eap_sm_method_pending - Query whether EAP method is waiting for pending data * @sm: Pointer to EAP state machine allocated with eap_sm_init() * Returns: 1 if method is waiting for pending data or 0 if not */int eap_sm_method_pending(struct eap_sm *sm){ if (sm == NULL) return 0; return sm->method_pending == METHOD_PENDING_WAIT;}/** * eap_hdr_validate - Validate EAP header * @vendor: Expected EAP Vendor-Id (0 = IETF) * @eap_type: Expected EAP type number * @msg: EAP frame (starting with EAP header) * @msglen: Length of msg * @plen: Pointer to variable to contain the returned payload length * Returns: Pointer to EAP payload (after type field), or %NULL on failure * * This is a helper function for EAP method implementations. This is usually * called in the beginning of struct eap_method::process() function to verify * that the received EAP request packet has a valid header. This function is * able to process both legacy and expanded EAP headers and in most cases, the * caller can just use the returned payload pointer (into *plen) for processing * the payload regardless of whether the packet used the expanded EAP header or * not. */const u8 * eap_hdr_validate(int vendor, EapType eap_type, const u8 *msg, size_t msglen, size_t *plen){ const struct eap_hdr *hdr; const u8 *pos; size_t len; hdr = (const struct eap_hdr *) msg; if (msglen < sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); return NULL; } len = be_to_host16(hdr->length); if (len < sizeof(*hdr) + 1 || len > msglen) { wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); return NULL; } pos = (const u8 *) (hdr + 1); if (*pos == EAP_TYPE_EXPANDED) { int exp_vendor; u32 exp_type; if (len < sizeof(*hdr) + 8) { wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " "length"); return NULL; } pos++; exp_vendor = WPA_GET_BE24(pos); pos += 3; exp_type = WPA_GET_BE32(pos); pos += 4; if (exp_vendor != vendor || exp_type != (u32) eap_type) { wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " "type"); return NULL; } *plen = len - sizeof(*hdr) - 8; return pos; } else { if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { wpa_printf(MSG_INFO, "EAP: Invalid frame type"); return NULL; } *plen = len - sizeof(*hdr) - 1; return pos + 1; }}/** * eap_msg_alloc - Allocate a buffer for an EAP message * @vendor: Vendor-Id (0 = IETF) * @type: EAP type * @len: Buffer for returning message length * @payload_len: Payload length in bytes (data after Type) * @code: Message Code (EAP_CODE_*) * @identifier: Identifier * @payload: Pointer to payload pointer that will be set to point to the * beginning of the payload or %NULL if payload pointer is not needed * Returns: Pointer to the allocated message buffer or %NULL on error * * This function can be used to allocate a buffer for an EAP message and fill * in the EAP header. This function is automatically using expanded EAP header * if the selected Vendor-Id is not IETF. In other words, most EAP methods do * not need to separately select which header type to use when using this * function to allocate the message buffers. */struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len, size_t payload_len, u8 code, u8 identifier, u8 **payload){ struct eap_hdr *hdr; u8 *pos; *len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + payload_len; hdr = malloc(*len); if (hdr) { hdr->code = code; hdr->identifier = identifier; hdr->length = host_to_be16(*len); pos = (u8 *) (hdr + 1); if (vendor == EAP_VENDOR_IETF) { *pos++ = type; } else { *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, vendor); pos += 3; WPA_PUT_BE32(pos, type); pos += 4; } if (payload) *payload = pos; } return hdr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -