📄 eap.c
字号:
for (i = 0; i < msg_len; i++) msg[i] = isprint(pos[i]) ? (char) pos[i] : '_'; msg[msg_len] = '\0'; wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s", WPA_EVENT_EAP_NOTIFICATION, msg); os_free(msg);}static struct wpabuf * eap_sm_buildNotify(int id){ struct wpabuf *resp; wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification"); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; return resp;}static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req){ const struct eap_hdr *hdr; size_t plen; const u8 *pos; sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE; sm->reqId = 0; sm->reqMethod = EAP_TYPE_NONE; sm->reqVendor = EAP_VENDOR_IETF; sm->reqVendorMethod = EAP_TYPE_NONE; if (req == NULL || wpabuf_len(req) < sizeof(*hdr)) return; hdr = wpabuf_head(req); plen = be_to_host16(hdr->length); if (plen > wpabuf_len(req)) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " "(len=%lu plen=%lu)", (unsigned long) wpabuf_len(req), (unsigned long) plen); return; } sm->reqId = hdr->identifier; if (sm->workaround) { const u8 *addr[1]; addr[0] = wpabuf_head(req); md5_vector(1, addr, &plen, sm->req_md5); } switch (hdr->code) { case EAP_CODE_REQUEST: if (plen < sizeof(*hdr) + 1) { wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - " "no Type field"); return; } sm->rxReq = TRUE; pos = (const u8 *) (hdr + 1); sm->reqMethod = *pos++; if (sm->reqMethod == 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->reqVendor = WPA_GET_BE24(pos); pos += 3; sm->reqVendorMethod = WPA_GET_BE32(pos); } wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d " "method=%u vendor=%u vendorMethod=%u", sm->reqId, sm->reqMethod, sm->reqVendor, sm->reqVendorMethod); break; case EAP_CODE_RESPONSE: if (sm->selectedMethod == EAP_TYPE_LEAP) { /* * LEAP differs from RFC 4137 by using reversed roles * for mutual authentication and because of this, we * need to accept EAP-Response frames if LEAP is used. */ if (plen < sizeof(*hdr) + 1) { wpa_printf(MSG_DEBUG, "EAP: Too short " "EAP-Response - no Type field"); return; } sm->rxResp = TRUE; pos = (const u8 *) (hdr + 1); sm->reqMethod = *pos; wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for " "LEAP method=%d id=%d", sm->reqMethod, sm->reqId); break; } wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response"); break; case EAP_CODE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success"); sm->rxSuccess = TRUE; break; case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure"); sm->rxFailure = TRUE; break; default: wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown " "code %d", hdr->code); break; }}/** * eap_peer_sm_init - Allocate and initialize EAP peer state machine * @eapol_ctx: Context data to be used with eapol_cb calls * @eapol_cb: Pointer to EAPOL callback functions * @msg_ctx: Context data for wpa_msg() calls * @conf: EAP configuration * Returns: Pointer to the allocated EAP state machine or %NULL on failure * * This function allocates and initializes an EAP state machine. In addition, * this initializes TLS library for the new EAP state machine. eapol_cb pointer * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP * state machine. Consequently, the caller must make sure that this data * structure remains alive while the EAP state machine is active. */struct eap_sm * eap_peer_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb, void *msg_ctx, struct eap_config *conf){ struct eap_sm *sm; struct tls_config tlsconf; sm = os_zalloc(sizeof(*sm)); if (sm == NULL) return NULL; sm->eapol_ctx = eapol_ctx; sm->eapol_cb = eapol_cb; sm->msg_ctx = msg_ctx; sm->ClientTimeout = 60; if (conf->mac_addr) os_memcpy(sm->mac_addr, conf->mac_addr, ETH_ALEN); os_memset(&tlsconf, 0, sizeof(tlsconf)); tlsconf.opensc_engine_path = conf->opensc_engine_path; tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path; tlsconf.pkcs11_module_path = conf->pkcs11_module_path; sm->ssl_ctx = tls_init(&tlsconf); if (sm->ssl_ctx == NULL) { wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS " "context."); os_free(sm); return NULL; } return sm;}/** * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * This function deinitializes EAP state machine and frees all allocated * resources. */void eap_peer_sm_deinit(struct eap_sm *sm){ if (sm == NULL) return; eap_deinit_prev_method(sm, "EAP deinit"); eap_sm_abort(sm); tls_deinit(sm->ssl_ctx); os_free(sm);}/** * eap_peer_sm_step - Step EAP peer state machine * @sm: Pointer to EAP state machine allocated with eap_peer_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_peer_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_sm_abort - Abort EAP authentication * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * Release system resources that have been allocated for the authentication * session without fully deinitializing the EAP state machine. */void eap_sm_abort(struct eap_sm *sm){ wpabuf_free(sm->lastRespData); sm->lastRespData = NULL; wpabuf_free(sm->eapRespData); sm->eapRespData = NULL; os_free(sm->eapKeyData); sm->eapKeyData = NULL; /* This is not clearly specified in the EAP statemachines draft, but * it seems necessary to make sure that some of the EAPOL variables get * cleared for the next authentication. */ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);}#ifdef CONFIG_CTRL_IFACEstatic const char * eap_sm_state_txt(int state){ switch (state) { case EAP_INITIALIZE: return "INITIALIZE"; case EAP_DISABLED: return "DISABLED"; case EAP_IDLE: return "IDLE"; case EAP_RECEIVED: return "RECEIVED"; case EAP_GET_METHOD: return "GET_METHOD"; case EAP_METHOD: return "METHOD"; case EAP_SEND_RESPONSE: return "SEND_RESPONSE"; case EAP_DISCARD: return "DISCARD"; case EAP_IDENTITY: return "IDENTITY"; case EAP_NOTIFICATION: return "NOTIFICATION"; case EAP_RETRANSMIT: return "RETRANSMIT"; case EAP_SUCCESS: return "SUCCESS"; case EAP_FAILURE: return "FAILURE"; default: return "UNKNOWN"; }}#endif /* CONFIG_CTRL_IFACE */#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)static const char * eap_sm_method_state_txt(EapMethodState state){ switch (state) { case METHOD_NONE: return "NONE"; case METHOD_INIT: return "INIT"; case METHOD_CONT: return "CONT"; case METHOD_MAY_CONT: return "MAY_CONT"; case METHOD_DONE: return "DONE"; default: return "UNKNOWN"; }}static const char * eap_sm_decision_txt(EapDecision decision){ switch (decision) { case DECISION_FAIL: return "FAIL"; case DECISION_COND_SUCC: return "COND_SUCC"; case DECISION_UNCOND_SUCC: return "UNCOND_SUCC"; default: return "UNKNOWN"; }}#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */#ifdef CONFIG_CTRL_IFACE/** * eap_sm_get_status - Get EAP state machine status * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @buf: Buffer for status information * @buflen: Maximum buffer length * @verbose: Whether to include verbose status information * Returns: Number of bytes written to buf. * * Query EAP state machine for status information. This function fills in a * text area with current status information from the EAPOL state machine. If * the buffer (buf) is not large enough, status information will be truncated * to fit the buffer. */int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose){ int len, ret; if (sm == NULL) return 0; len = os_snprintf(buf, buflen, "EAP state=%s\n", eap_sm_state_txt(sm->EAP_state)); if (len < 0 || (size_t) len >= buflen) return 0; if (sm->selectedMethod != EAP_TYPE_NONE) { const char *name; if (sm->m) { name = sm->m->name; } else { const struct eap_method *m = eap_peer_get_eap_method(EAP_VENDOR_IETF, sm->selectedMethod); if (m) name = m->name; else name = "?"; } ret = os_snprintf(buf + len, buflen - len, "selectedMethod=%d (EAP-%s)\n", sm->selectedMethod, name); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; if (sm->m && sm->m->get_status) { len += sm->m->get_status(sm, sm->eap_method_priv, buf + len, buflen - len, verbose); } } if (verbose) { ret = os_snprintf(buf + len, buflen - len, "reqMethod=%d\n" "methodState=%s\n" "decision=%s\n" "ClientTimeout=%d\n", sm->reqMethod, eap_sm_method_state_txt(sm->methodState), eap_sm_decision_txt(sm->decision), sm->ClientTimeout); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; } return len;}#endif /* CONFIG_CTRL_IFACE */#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD, TYPE_PASSPHRASE} eap_ctrl_req_type;static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type, const char *msg, size_t msglen){ struct eap_peer_config *config; char *field, *txt, *tmp; if (sm == NULL) return; config = eap_get_config(sm); if (config == NULL) return; switch (type) { case TYPE_IDENTITY: field = "IDENTITY"; txt = "Identity"; config->pending_req_identity++; break; case TYPE_PASSWORD: field = "PASSWORD"; txt = "Password"; config->pending_req_password++; break; case TYPE_NEW_PASSWORD: field = "NEW_PASSWORD"; txt = "New Password"; config->pending_req_new_password++; break; case TYPE_PIN: field = "PIN"; txt = "PIN"; config->pending_req_pin++; break; case TYPE_OTP: field = "OTP"; if (msg) { tmp = os_malloc(msglen + 3); if (tmp == NULL) return; tmp[0] = '['; os_memcpy(tmp + 1, msg, msglen); tmp[msglen + 1] = ']'; tmp[msglen + 2] = '\0'; txt = tmp; os_free(config->pending_req_otp); config->pending_req_otp = tmp; config->pending_req_otp_len = msglen + 3; } else { if (config->pending_req_otp == NULL) return; txt = config->pending_req_otp; } break; case TYPE_PASSPHRASE: field = "PASSPHRASE"; txt = "Private key passphrase"; config->pending_req_passphrase++; break; default: return; } if (sm->eapol_cb->eap_param_needed) sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);}#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */#define eap_sm_request(sm, type, msg, msglen) do { } while (0)#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG *//** * eap_sm_request_identity - Request identity from user (ctrl_iface) * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * EAP methods can call this function to request identity information for the * current network. This is normally called when the identity is not included * in the network configuration. The request will be sent to monitor programs * through the control interface. */void eap_sm_request_identity(struct eap_sm *sm){ eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);}/** * eap_sm_request_password - Request password from user (ctrl_iface) * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * EAP methods can call this function to request password information for the * current network. This is normally called when the password is not included * in the network configuration. The request will be sent to monitor programs * through the control interface. */void eap_sm_request_password(struct eap_sm *sm){ eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);}/** * eap_sm_request_new_password - Request new password from user (ctrl_iface) * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * EAP methods can call this function to request new password information for * the current network. This is normally called when the EAP method indicates * that the current password has expired and password change is required. The * request will be sent to monitor programs through the control interface. */void eap_sm_request_new_password(struct eap_sm *sm){ eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);}/** * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface) * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * * EAP methods can call this function to request SIM or smart card PIN * information for the current network. This is normally called when the PIN is * not included in the network configuration. The request will be sent to * monitor programs through the control interface. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -