static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id) { struct eap_tnc_data *data = priv; switch (data->state) { case START: tncs_init_connection(data->tncs); return eap_tnc_build_start(sm, data, id); case CONTINUE: if (data->out_buf == NULL) { data->out_buf = eap_tnc_build(sm, data); if (data->out_buf == NULL) { wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " "generate message"); return NULL; } data->out_used = 0; } return eap_tnc_build_msg(data, id); case RECOMMENDATION: if (data->out_buf == NULL) { data->out_buf = eap_tnc_build_recommendation(sm, data); if (data->out_buf == NULL) { wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " "generate recommendation message"); return NULL; } data->out_used = 0; } return eap_tnc_build_msg(data, id); case WAIT_FRAG_ACK: return eap_tnc_build_msg(data, id); case FRAG_ACK: return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST); case DONE: case FAIL: return NULL; } return NULL; }
static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_tnc_data *data = priv; struct wpabuf *resp; const u8 *pos, *end; u8 *rpos, *rpos1; size_t len, rlen; size_t imc_len; char *start_buf, *end_buf; size_t start_len, end_len; int tncs_done = 0; u8 flags, id; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len); if (pos == NULL) { wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)", pos, (unsigned long) len); ret->ignore = TRUE; return NULL; } id = eap_get_id(reqData); end = pos + len; if (len == 0) flags = 0; /* fragment ack */ else flags = *pos++; if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", flags & EAP_TNC_VERSION_MASK); ret->ignore = TRUE; return NULL; } if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); ret->ignore = TRUE; return NULL; } message_length = WPA_GET_BE32(pos); pos += 4; if (message_length < (u32) (end - pos)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); ret->ignore = TRUE; return NULL; } } wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " "WAIT_FRAG_ACK state"); ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); } if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { ret->ignore = TRUE; return NULL; } if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { return eap_tnc_process_fragment(data, ret, id, flags, message_length, pos, end - pos); } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } if (data->state == WAIT_START) { if (!(flags & EAP_TNC_FLAGS_START)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use " "start flag in the first message"); ret->ignore = TRUE; goto fail; } tncc_init_connection(data->tncc); data->state = PROC_MSG; } else { enum tncc_process_res res; if (flags & EAP_TNC_FLAGS_START) { wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start " "flag again"); ret->ignore = TRUE; goto fail; } res = tncc_process_if_tnccs(data->tncc, wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); switch (res) { case TNCCS_PROCESS_ERROR: ret->ignore = TRUE; goto fail; case TNCCS_PROCESS_OK_NO_RECOMMENDATION: case TNCCS_RECOMMENDATION_ERROR: wpa_printf(MSG_DEBUG, "EAP-TNC: No " "TNCCS-Recommendation received"); break; case TNCCS_RECOMMENDATION_ALLOW: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = allow"); tncs_done = 1; break; case TNCCS_RECOMMENDATION_NONE: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = none"); tncs_done = 1; break; case TNCCS_RECOMMENDATION_ISOLATE: wpa_msg(sm->msg_ctx, MSG_INFO, "TNC: Recommendation = isolate"); tncs_done = 1; break; } } if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_UNCOND_SUCC; ret->allowNotifications = TRUE; if (data->out_buf) { data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); } if (tncs_done) { resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) return NULL; wpabuf_put_u8(resp, EAP_TNC_VERSION); wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an " "empty ACK message"); return resp; } imc_len = tncc_total_send_len(data->tncc); start_buf = tncc_if_tnccs_start(data->tncc); if (start_buf == NULL) return NULL; start_len = os_strlen(start_buf); end_buf = tncc_if_tnccs_end(); if (end_buf == NULL) { os_free(start_buf); return NULL; } end_len = os_strlen(end_buf); rlen = start_len + imc_len + end_len; resp = wpabuf_alloc(rlen); if (resp == NULL) { os_free(start_buf); os_free(end_buf); return NULL; } wpabuf_put_data(resp, start_buf, start_len); os_free(start_buf); rpos1 = wpabuf_put(resp, 0); rpos = tncc_copy_send_buf(data->tncc, rpos1); wpabuf_put(resp, rpos - rpos1); wpabuf_put_data(resp, end_buf, end_len); os_free(end_buf); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", wpabuf_head(resp), wpabuf_len(resp)); data->out_buf = resp; data->state = PROC_MSG; return eap_tnc_build_msg(data, ret, id); fail: if (data->in_buf == &tmpbuf) data->in_buf = NULL; return NULL; }