diff --git a/conf/plugins/imc-swima.opt b/conf/plugins/imc-swima.opt index 099a3c80f..daa4ecadd 100644 --- a/conf/plugins/imc-swima.opt +++ b/conf/plugins/imc-swima.opt @@ -19,3 +19,6 @@ libimcv.plugins.imc-swima.swid_pretty = no libimcv.plugins.imc-swima.swid_full = no Include file information in the XML-encoded SWID tags. + +libimcv.plugins.imc-swima.subscriptions = no + Accept SW Inventory or SW Events subscriptions. diff --git a/src/libimcv/imc/imc_agent.c b/src/libimcv/imc/imc_agent.c index 3a7a16bc2..ec44d587f 100644 --- a/src/libimcv/imc/imc_agent.c +++ b/src/libimcv/imc/imc_agent.c @@ -73,6 +73,11 @@ struct private_imc_agent_t { */ rwlock_t *connection_lock; + /** + * Is the transport protocol PT-TLS? + */ + bool has_pt_tls; + /** * Inform a TNCC about the set of message types the IMC is able to receive * @@ -372,6 +377,8 @@ METHOD(imc_agent_t, create_state, TNC_Result, DBG2(DBG_IMC, " over %s %s with maximum PA-TNC message size of %u bytes", t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len); + this->has_pt_tls = streq(t_p, "IF-T for TLS"); + free(tnccs_p); free(tnccs_v); free(t_p); @@ -403,6 +410,7 @@ METHOD(imc_agent_t, change_state, TNC_Result, imc_state_t **state_p) { imc_state_t *state; + TNC_ConnectionState old_state; switch (new_state) { @@ -418,7 +426,7 @@ METHOD(imc_agent_t, change_state, TNC_Result, this->id, this->name, connection_id); return TNC_RESULT_FATAL; } - state->change_state(state, new_state); + old_state = state->change_state(state, new_state); DBG2(DBG_IMC, "IMC %u \"%s\" changed state of Connection ID %u to '%N'", this->id, this->name, connection_id, TNC_Connection_State_names, new_state); @@ -426,6 +434,13 @@ METHOD(imc_agent_t, change_state, TNC_Result, { *state_p = state; } + if (new_state == TNC_CONNECTION_STATE_HANDSHAKE && + old_state != TNC_CONNECTION_STATE_CREATE) + { + state->reset(state); + DBG2(DBG_IMC, "IMC %u \"%s\" reset state of Connection ID %u", + this->id, this->name, connection_id); + } break; case TNC_CONNECTION_STATE_CREATE: DBG1(DBG_IMC, "state '%N' should be handled by create_state()", @@ -531,6 +546,12 @@ METHOD(imc_agent_t, get_non_fatal_attr_types, linked_list_t*, return this->non_fatal_attr_types; } +METHOD(imc_agent_t, has_pt_tls, bool, + private_imc_agent_t *this) +{ + return this->has_pt_tls; +} + METHOD(imc_agent_t, destroy, void, private_imc_agent_t *this) { @@ -575,6 +596,7 @@ imc_agent_t *imc_agent_create(const char *name, .create_id_enumerator = _create_id_enumerator, .add_non_fatal_attr_type = _add_non_fatal_attr_type, .get_non_fatal_attr_types = _get_non_fatal_attr_types, + .has_pt_tls = _has_pt_tls, .destroy = _destroy, }, .name = name, diff --git a/src/libimcv/imc/imc_agent.h b/src/libimcv/imc/imc_agent.h index bac1b4832..27c749954 100644 --- a/src/libimcv/imc/imc_agent.h +++ b/src/libimcv/imc/imc_agent.h @@ -181,6 +181,13 @@ struct imc_agent_t { */ linked_list_t* (*get_non_fatal_attr_types)(imc_agent_t *this); + /** + * Is the transport protocol PT-TLS? + * + * return TRUE if PT-TLS + */ + bool (*has_pt_tls)(imc_agent_t *this); + /** * Destroys an imc_agent_t object */ diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h index d8aeab996..bd55f7356 100644 --- a/src/libimcv/imc/imc_state.h +++ b/src/libimcv/imc/imc_state.h @@ -92,8 +92,10 @@ struct imc_state_t { * Change the connection state * * @param new_state new connection state + * @return old connection state */ - void (*change_state)(imc_state_t *this, TNC_ConnectionState new_state); + TNC_ConnectionState (*change_state)(imc_state_t *this, + TNC_ConnectionState new_state); /** * Set the Assessment/Evaluation Result @@ -114,6 +116,11 @@ struct imc_state_t { bool (*get_result)(imc_state_t *this, TNC_IMCID id, TNC_IMV_Evaluation_Result *result); + /** + * Resets the state for a new measurement cycle triggered by a SRETRY batch + */ + void (*reset)(imc_state_t *this); + /** * Destroys an imc_state_t object */ diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index bb0b3b75b..f3ccfbf56 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -492,6 +492,7 @@ METHOD(imv_agent_t, change_state, TNC_Result, imv_state_t **state_p) { imv_state_t *state; + TNC_ConnectionState old_state; switch (new_state) { @@ -506,7 +507,7 @@ METHOD(imv_agent_t, change_state, TNC_Result, this->id, this->name, connection_id); return TNC_RESULT_FATAL; } - state->change_state(state, new_state); + old_state = state->change_state(state, new_state); DBG2(DBG_IMV, "IMV %u \"%s\" changed state of Connection ID %u to '%N'", this->id, this->name, connection_id, TNC_Connection_State_names, new_state); @@ -514,6 +515,13 @@ METHOD(imv_agent_t, change_state, TNC_Result, { *state_p = state; } + if (new_state == TNC_CONNECTION_STATE_HANDSHAKE && + old_state != TNC_CONNECTION_STATE_CREATE) + { + state->reset(state); + DBG2(DBG_IMV, "IMV %u \"%s\" reset state of Connection ID %u", + this->id, this->name, connection_id); + } break; case TNC_CONNECTION_STATE_CREATE: DBG1(DBG_IMV, "state '%N' should be handled by create_state()", diff --git a/src/libimcv/imv/imv_database.c b/src/libimcv/imv/imv_database.c index b444abdbb..03f583204 100644 --- a/src/libimcv/imv/imv_database.c +++ b/src/libimcv/imv/imv_database.c @@ -143,7 +143,7 @@ static bool create_session(private_imv_database_t *this, imv_session_t *session) } /* create a new session entry */ - created = session->get_creation_time(session); + created = time(NULL); conn_id = session->get_connection_id(session); this->db->execute(this->db, &session_id, "INSERT INTO sessions (time, connection, product, device) " @@ -161,6 +161,7 @@ static bool create_session(private_imv_database_t *this, imv_session_t *session) return FALSE; } session->set_session_id(session, session_id, pid, did); + session->set_creation_time(session, created); enumerator = session->create_ar_identities_enumerator(session); while (enumerator->enumerate(enumerator, &tnc_id)) diff --git a/src/libimcv/imv/imv_session.c b/src/libimcv/imv/imv_session.c index bc6b5a8d1..830dd48d4 100644 --- a/src/libimcv/imv/imv_session.c +++ b/src/libimcv/imv/imv_session.c @@ -121,6 +121,12 @@ METHOD(imv_session_t, get_connection_id, TNC_ConnectionID, return this->conn_id; } +METHOD(imv_session_t, set_creation_time, void, + private_imv_session_t *this, time_t created) +{ + this->created = created; +} + METHOD(imv_session_t, get_creation_time, time_t, private_imv_session_t *this) { @@ -259,7 +265,7 @@ METHOD(imv_session_t, destroy, void, /** * See header */ -imv_session_t *imv_session_create(TNC_ConnectionID conn_id, time_t created, +imv_session_t *imv_session_create(TNC_ConnectionID conn_id, linked_list_t *ar_identities) { private_imv_session_t *this; @@ -269,6 +275,7 @@ imv_session_t *imv_session_create(TNC_ConnectionID conn_id, time_t created, .set_session_id = _set_session_id, .get_session_id = _get_session_id, .get_connection_id = _get_connection_id, + .set_creation_time = _set_creation_time, .get_creation_time = _get_creation_time, .create_ar_identities_enumerator = _create_ar_identities_enumerator, .get_os_info = _get_os_info, @@ -286,7 +293,6 @@ imv_session_t *imv_session_create(TNC_ConnectionID conn_id, time_t created, .destroy = _destroy, }, .conn_id = conn_id, - .created = created, .ar_identities = ar_identities, .os_info = imv_os_info_create(), .workitems = linked_list_create(), diff --git a/src/libimcv/imv/imv_session.h b/src/libimcv/imv/imv_session.h index 107716f30..a2f6fc2a8 100644 --- a/src/libimcv/imv/imv_session.h +++ b/src/libimcv/imv/imv_session.h @@ -62,6 +62,13 @@ struct imv_session_t { */ TNC_ConnectionID (*get_connection_id)(imv_session_t *this); + /** + * Set session creation time + * + * @param created Session creation time + */ + void (*set_creation_time)(imv_session_t *this, time_t created); + /** * Get session creation time * @@ -170,10 +177,9 @@ struct imv_session_t { * Create an imv_session_t instance * * @param id Associated Connection ID - * @param created Session creation time * @param ar_identities List of Access Requestor identities */ -imv_session_t* imv_session_create(TNC_ConnectionID id, time_t created, - linked_list_t *ar_identities); +imv_session_t* imv_session_create(TNC_ConnectionID id, + linked_list_t *ar_identities); #endif /** IMV_SESSION_H_ @}*/ diff --git a/src/libimcv/imv/imv_session_manager.c b/src/libimcv/imv/imv_session_manager.c index c97602998..2e3cfa466 100644 --- a/src/libimcv/imv/imv_session_manager.c +++ b/src/libimcv/imv/imv_session_manager.c @@ -51,7 +51,6 @@ METHOD(imv_session_manager_t, add_session, imv_session_t*, enumerator_t *enumerator; tncif_identity_t *tnc_id; imv_session_t *current, *session = NULL; - time_t created; this->mutex->lock(this->mutex); @@ -105,8 +104,7 @@ METHOD(imv_session_manager_t, add_session, imv_session_t*, enumerator->destroy(enumerator); /* create a new session entry */ - created = time(NULL); - session = imv_session_create(conn_id, created, ar_identities); + session = imv_session_create(conn_id, ar_identities); this->sessions->insert_last(this->sessions, session); this->mutex->unlock(this->mutex); diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index 30ed612b3..4571da2fa 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -119,8 +119,10 @@ struct imv_state_t { * Change the connection state * * @param new_state new connection state + * @return old connection state */ - void (*change_state)(imv_state_t *this, TNC_ConnectionState new_state); + TNC_ConnectionState (*change_state)(imv_state_t *this, + TNC_ConnectionState new_state); /** * Get IMV action recommendation and evaluation result @@ -181,6 +183,11 @@ struct imv_state_t { chunk_t *string, char **lang_code, char **uri); + /** + * Resets the state for a new measurement cycle triggered by a SRETRY batch + */ + void (*reset)(imv_state_t *this); + /** * Destroys an imv_state_t object */ diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation.c b/src/libimcv/plugins/imc_attestation/imc_attestation.c index 0dd88b6a7..f592a5134 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation.c +++ b/src/libimcv/plugins/imc_attestation/imc_attestation.c @@ -115,19 +115,8 @@ TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_attestation_state_create(connection_id); return imc_attestation->create_state(imc_attestation, state); - case TNC_CONNECTION_STATE_HANDSHAKE: - if (imc_attestation->change_state(imc_attestation, connection_id, - new_state, &state) != TNC_RESULT_SUCCESS) - { - return TNC_RESULT_FATAL; - } - state->set_result(state, imc_id, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW); - return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_attestation->delete_state(imc_attestation, connection_id); - case TNC_CONNECTION_STATE_ACCESS_ISOLATED: - case TNC_CONNECTION_STATE_ACCESS_NONE: default: return imc_attestation->change_state(imc_attestation, connection_id, new_state, NULL); diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c b/src/libimcv/plugins/imc_attestation/imc_attestation_state.c index b789a2104..f8e0b8d2c 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_state.c @@ -131,10 +131,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_attestation_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -155,6 +159,21 @@ METHOD(imc_state_t, get_result, bool, return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_attestation_state_t *this) +{ + this->result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->components->destroy_offset(this->components, + offsetof(pts_component_t, destroy)); + this->components = linked_list_create(); + this->list->destroy_offset(this->list, + offsetof(pts_comp_evidence_t, destroy)); + this->list = linked_list_create(); + this->pts->destroy(this->pts); + this->pts = pts_create(TRUE); +} + METHOD(imc_state_t, destroy, void, private_imc_attestation_state_t *this) { @@ -238,6 +257,7 @@ imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id) .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, .get_pts = _get_pts, diff --git a/src/libimcv/plugins/imc_hcd/imc_hcd.c b/src/libimcv/plugins/imc_hcd/imc_hcd.c index b631683ce..09ba8bc0b 100644 --- a/src/libimcv/plugins/imc_hcd/imc_hcd.c +++ b/src/libimcv/plugins/imc_hcd/imc_hcd.c @@ -141,15 +141,6 @@ TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_hcd_state_create(connection_id); return imc_hcd->create_state(imc_hcd, state); - case TNC_CONNECTION_STATE_HANDSHAKE: - if (imc_hcd->change_state(imc_hcd, connection_id, new_state, - &state) != TNC_RESULT_SUCCESS) - { - return TNC_RESULT_FATAL; - } - state->set_result(state, imc_id, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW); - return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_hcd->delete_state(imc_hcd, connection_id); default: @@ -348,7 +339,7 @@ static void add_certification_state(imc_msg_t *msg) if (hex_string) { blob = chunk_from_hex(chunk_from_str(hex_string), NULL); - + DBG2(DBG_IMC, " %N: %B", pwg_attr_names, PWG_HCD_CERTIFICATION_STATE, &blob); attr = generic_attr_chunk_create(blob, @@ -373,7 +364,7 @@ static void add_configuration_state(imc_msg_t *msg) if (hex_string) { blob = chunk_from_hex(chunk_from_str(hex_string), NULL); - + DBG2(DBG_IMC, " %N: %B", pwg_attr_names, PWG_HCD_CONFIGURATION_STATE, &blob); attr = generic_attr_chunk_create(blob, @@ -412,7 +403,7 @@ static void add_quadruple(imc_msg_t *msg, char *section, quadruple_t *quad) "%s.plugins.imc-hcd.subtypes.%s.%s.%s.string_version", "", lib->ns, section, quad->section, app); hex_version = lib->settings->get_str(lib->settings, - "%s.plugins.imc-hcd.subtypes.%s.%s.%s.version", + "%s.plugins.imc-hcd.subtypes.%s.%s.%s.version", hex_version_default, lib->ns, section, quad->section, app); /* convert hex string into binary chunk */ diff --git a/src/libimcv/plugins/imc_hcd/imc_hcd_state.c b/src/libimcv/plugins/imc_hcd/imc_hcd_state.c index 60ccdce81..b2207f28a 100644 --- a/src/libimcv/plugins/imc_hcd/imc_hcd_state.c +++ b/src/libimcv/plugins/imc_hcd/imc_hcd_state.c @@ -110,10 +110,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_hcd_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -134,6 +138,12 @@ METHOD(imc_state_t, get_result, bool, return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_hcd_state_t *this) +{ + this->result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_hcd_state_t *this) { @@ -161,6 +171,7 @@ imc_state_t *imc_hcd_state_create(TNC_ConnectionID connection_id) .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, }, diff --git a/src/libimcv/plugins/imc_os/imc_os.c b/src/libimcv/plugins/imc_os/imc_os.c index d7b508ab9..a10492e04 100644 --- a/src/libimcv/plugins/imc_os/imc_os.c +++ b/src/libimcv/plugins/imc_os/imc_os.c @@ -103,15 +103,6 @@ TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_os_state_create(connection_id); return imc_os->create_state(imc_os, state); - case TNC_CONNECTION_STATE_HANDSHAKE: - if (imc_os->change_state(imc_os, connection_id, new_state, - &state) != TNC_RESULT_SUCCESS) - { - return TNC_RESULT_FATAL; - } - state->set_result(state, imc_id, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW); - return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_os->delete_state(imc_os, connection_id); default: diff --git a/src/libimcv/plugins/imc_os/imc_os_state.c b/src/libimcv/plugins/imc_os/imc_os_state.c index a38696a81..d26454719 100644 --- a/src/libimcv/plugins/imc_os/imc_os_state.c +++ b/src/libimcv/plugins/imc_os/imc_os_state.c @@ -110,10 +110,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_os_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -134,6 +138,12 @@ METHOD(imc_state_t, get_result, bool, return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_os_state_t *this) +{ + this->result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_os_state_t *this) { @@ -161,6 +171,7 @@ imc_state_t *imc_os_state_create(TNC_ConnectionID connection_id) .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, }, diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c index 93ed4271b..c4fc254cf 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c @@ -85,15 +85,6 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_scanner_state_create(connection_id); return imc_scanner->create_state(imc_scanner, state); - case TNC_CONNECTION_STATE_HANDSHAKE: - if (imc_scanner->change_state(imc_scanner, connection_id, new_state, - &state) != TNC_RESULT_SUCCESS) - { - return TNC_RESULT_FATAL; - } - state->set_result(state, imc_id, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW); - return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_scanner->delete_state(imc_scanner, connection_id); default: diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c index c1b7a50e4..2a2214841 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c @@ -110,10 +110,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_scanner_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -134,6 +138,12 @@ METHOD(imc_state_t, get_result, bool, return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_scanner_state_t *this) +{ + this->result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_scanner_state_t *this) { @@ -161,6 +171,7 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id) .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, }, diff --git a/src/libimcv/plugins/imc_swima/Makefile.am b/src/libimcv/plugins/imc_swima/Makefile.am index 4a29e7949..e31f98d33 100644 --- a/src/libimcv/plugins/imc_swima/Makefile.am +++ b/src/libimcv/plugins/imc_swima/Makefile.am @@ -19,11 +19,13 @@ $(swid_tag) : $(regid)__strongSwan.swidtag.in AM_CPPFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libtncif \ - -I$(top_srcdir)/src/libimcv + -I$(top_srcdir)/src/libimcv \ + -DSW_COLLECTOR=\"${prefix}/sbin/sw-collector\" AM_CFLAGS = \ $(PLUGIN_CFLAGS) $(json_CFLAGS) + imcv_LTLIBRARIES = imc-swima.la imc_swima_la_LIBADD = \ diff --git a/src/libimcv/plugins/imc_swima/imc_swima.c b/src/libimcv/plugins/imc_swima/imc_swima.c index 67080e050..be258d335 100644 --- a/src/libimcv/plugins/imc_swima/imc_swima.c +++ b/src/libimcv/plugins/imc_swima/imc_swima.c @@ -30,6 +30,17 @@ #include #include +#include +#include +#include +#include +#include +#include + +#ifndef SW_COLLECTOR +#define SW_COLLECTOR NULL +#endif + /* IMC definitions */ static const char imc_name[] = "SWIMA"; @@ -67,6 +78,75 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, return TNC_RESULT_SUCCESS; } +/** + * Poll for IN_CLOSE_WRITE event on the apt history.log + */ +static bool poll_history_log(void) +{ + int fd, wd, res; + nfds_t nfds; + struct pollfd fds[1]; + char *history_path; + bool success = FALSE; + + history_path = lib->settings->get_str(lib->settings, "sw-collector.history", + NULL); + if (!history_path) + { + DBG1(DBG_IMC, "sw-collector.history path not set"); + return FALSE; + } + + /* Create the file descriptor for accessing the inotify API */ + fd = inotify_init1(IN_NONBLOCK); + if (fd == -1) + { + DBG1(DBG_IMC, "inotify file descriptor could not be created"); + return FALSE; + } + + /* Watch for CLOSE_WRITE events on history log */ + wd = inotify_add_watch(fd, history_path, IN_CLOSE_WRITE); + if (wd == -1) + { + DBG1(DBG_IMC, "cannot watch '%s'", history_path); + goto end; + } + + /* Prepare for polling */ + nfds = 1; + + /* Inotify input */ + fds[0].fd = fd; + fds[0].events = POLLIN; + + while (1) + { + DBG1(DBG_IMC, " waiting for write event on history.log ..."); + + res = poll(fds, nfds, -1); + if (res == -1) + { + DBG1(DBG_IMC, " poll failed: %s", strerror(errno)); + if (errno == EINTR) + { + continue; + } + goto end; + } + if (res > 0 && fds[0].revents & POLLIN) + { + DBG1(DBG_IMC, " poll successful"); + success = TRUE; + break; + } + } + +end: + close(fd); + return success; +} + /** * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 */ @@ -75,6 +155,11 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, TNC_ConnectionState new_state) { imc_state_t *state; + imc_swima_state_t *swima_state; + imc_swima_subscription_t *subscription; + TNC_IMV_Evaluation_Result res; + TNC_Result result; + uint32_t eid, eid_epoch; if (!imc_swima) { @@ -86,14 +171,42 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_swima_state_create(connection_id); return imc_swima->create_state(imc_swima, state); - case TNC_CONNECTION_STATE_HANDSHAKE: - if (imc_swima->change_state(imc_swima, connection_id, new_state, - &state) != TNC_RESULT_SUCCESS) + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + /* get updated IMC state */ + result = imc_swima->change_state(imc_swima, connection_id, + new_state, &state); + if (result != TNC_RESULT_SUCCESS) { return TNC_RESULT_FATAL; } - state->set_result(state, imc_id, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + swima_state = (imc_swima_state_t*)state; + + /* do a handshake retry? */ + if (swima_state->get_subscription(swima_state, &subscription)) + { + /* update earliest EID in subscription target */ + if (state->get_result(state, imc_id, &res) && + res == TNC_IMV_EVALUATION_RESULT_COMPLIANT) + { + eid = subscription->targets->get_eid(subscription->targets, + &eid_epoch); + if (eid > 0) + { + eid = swima_state->get_earliest_eid(swima_state); + subscription->targets->set_eid(subscription->targets, eid, + eid_epoch); + } + } + DBG1(DBG_IMC, "SWIMA subscription %u:", subscription->request_id); + if (!poll_history_log()) + { + return TNC_RESULT_FATAL; + } + return imc_swima->request_handshake_retry(imc_id, connection_id, + TNC_RETRY_REASON_IMC_PERIODIC); + } return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_swima->delete_state(imc_swima, connection_id); @@ -103,62 +216,12 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, } } -/** - * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 - */ -TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, - TNC_ConnectionID connection_id) -{ - imc_state_t *state; - imc_msg_t *out_msg; - pa_tnc_attr_t *attr; - seg_contract_t *contract; - seg_contract_manager_t *contracts; - size_t max_attr_size = SWIMA_MAX_ATTR_SIZE; - size_t max_seg_size; - char buf[BUF_LEN]; - TNC_Result result = TNC_RESULT_SUCCESS; - - if (!imc_swima) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imc_swima->get_state(imc_swima, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - - /* Determine maximum PA-TNC attribute segment size */ - max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE - - PA_TNC_ATTR_HEADER_SIZE - - TCG_SEG_ATTR_SEG_ENV_HEADER; - - /* Announce support of PA-TNC segmentation to IMV */ - contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size, - TRUE, imc_id, TRUE); - contract->get_info_string(contract, buf, BUF_LEN, TRUE); - DBG2(DBG_IMC, "%s", buf); - contracts = state->get_contracts(state); - contracts->add_contract(contracts, contract); - attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE); - - /* send PA-TNC message with the excl flag not set */ - out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id, - TNC_IMVID_ANY, msg_types[0]); - out_msg->add_attribute(out_msg, attr); - result = out_msg->send(out_msg, FALSE); - out_msg->destroy(out_msg); - - return result; -} - /** * Add SWID Inventory or Event attribute to the send queue */ static void fulfill_request(imc_state_t *state, imc_msg_t *msg, - uint32_t request_id, bool sw_id_only, - swima_inventory_t *targets) + uint32_t request_id, bool sw_id_only, + swima_inventory_t *targets) { pa_tnc_attr_t *attr; swima_collector_t *collector; @@ -174,6 +237,8 @@ static void fulfill_request(imc_state_t *state, imc_msg_t *msg, { swima_events_t *sw_ev; ietf_swima_attr_sw_ev_t *sw_ev_attr; + imc_swima_state_t *swima_state; + uint32_t eid_epoch, last_eid = 0; sw_ev = collector->collect_events(collector, sw_id_only, targets); if (!sw_ev) @@ -185,8 +250,14 @@ static void fulfill_request(imc_state_t *state, imc_msg_t *msg, } else { items = sw_ev->get_count(sw_ev); - DBG1(DBG_IMC, "collected %d SW%s event%s", items, id_str, - items == 1 ? "" : "s"); + last_eid = sw_ev->get_eid(sw_ev, &eid_epoch, NULL); + + DBG1(DBG_IMC, "collected %d SW%s event%s at last eid %d of epoch 0x%08x", + items, id_str, items == 1 ? "" : "s", last_eid, eid_epoch); + + /* Store the earliest EID for the next subscription round */ + swima_state = (imc_swima_state_t*)state; + swima_state->set_earliest_eid(swima_state, last_eid + 1); /* Send an IETF SW [Identity] Events attribute */ attr = ietf_swima_attr_sw_ev_create(IETF_SWIMA_ATTR_SW_INV_FLAG_NONE, @@ -226,9 +297,78 @@ static void fulfill_request(imc_state_t *state, imc_msg_t *msg, collector->destroy(collector); } +/** + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + imc_state_t *state; + imc_swima_state_t *swima_state; + imc_msg_t *out_msg; + pa_tnc_attr_t *attr; + seg_contract_t *contract; + seg_contract_manager_t *contracts; + imc_swima_subscription_t *subscription; + size_t max_attr_size = SWIMA_MAX_ATTR_SIZE; + size_t max_seg_size; + char buf[BUF_LEN]; + TNC_Result result = TNC_RESULT_SUCCESS; + + if (!imc_swima) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_swima->get_state(imc_swima, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + swima_state = (imc_swima_state_t*)state; + + if (swima_state->get_subscription(swima_state, &subscription)) + { + if (system(SW_COLLECTOR) != 0) + { + DBG1(DBG_IMC, "calling %s failed", SW_COLLECTOR); + return TNC_RESULT_FATAL; + } + out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id, + subscription->imv_id, msg_types[0]); + fulfill_request(state, out_msg, subscription->request_id, + subscription->sw_id_only, subscription->targets); + } + else + { + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER; + + /* Announce support of PA-TNC segmentation to IMV */ + contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size, + TRUE, imc_id, TRUE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMC, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE); + + /* send PA-TNC message with the excl flag not set */ + out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id, + TNC_IMVID_ANY, msg_types[0]); + out_msg->add_attribute(out_msg, attr); + } + result = out_msg->send(out_msg, FALSE); + out_msg->destroy(out_msg); + + return result; +} + static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) { imc_msg_t *out_msg; + imc_swima_state_t *swima_state; pa_tnc_attr_t *attr; enumerator_t *enumerator; pen_type_t type; @@ -255,7 +395,6 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) uint32_t request_id; bool sw_id_only; swima_inventory_t *targets; - type = attr->get_type(attr); if (type.vendor_id != PEN_IETF || type.type != IETF_ATTR_SWIMA_REQUEST) @@ -267,15 +406,55 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) flags = attr_req->get_flags(attr_req); request_id = attr_req->get_request_id(attr_req); targets = attr_req->get_targets(attr_req); + sw_id_only = (flags & IETF_SWIMA_ATTR_REQ_FLAG_R); if (flags & (IETF_SWIMA_ATTR_REQ_FLAG_S | IETF_SWIMA_ATTR_REQ_FLAG_C)) { - attr = swima_error_create(PA_ERROR_SWIMA_SUBSCRIPTION_DENIED, - request_id, 0, "no subscription available yet"); - out_msg->add_attribute(out_msg, attr); - break; + if (imc_swima->has_pt_tls(imc_swima) && + lib->settings->get_bool(lib->settings, + "%s.plugins.imc-swima.subscriptions", FALSE, lib->ns)) + { + imc_swima_subscription_t *subscription; + + swima_state = (imc_swima_state_t*)state; + + if (flags & IETF_SWIMA_ATTR_REQ_FLAG_C) + { + if (swima_state->get_subscription(swima_state, &subscription)) + { + DBG1(DBG_IMC, "SWIMA subscription %u cleared", + subscription->request_id); + swima_state->set_subscription(swima_state, NULL, FALSE); + } + } + else + { + INIT(subscription, + .imv_id = in_msg->get_src_id(in_msg), + .request_id = request_id, + .targets = targets->get_ref(targets), + .sw_id_only = sw_id_only, + ); + + swima_state->set_subscription(swima_state, subscription, + TRUE); + DBG1(DBG_IMC, "SWIMA subscription %u established", + subscription->request_id); + if (system(SW_COLLECTOR) != 0) + { + DBG1(DBG_IMC, "calling %s failed", SW_COLLECTOR); + out_msg->destroy(out_msg); + return TNC_RESULT_FATAL; + } + } + } + else + { + attr = swima_error_create(PA_ERROR_SWIMA_SUBSCRIPTION_DENIED, + request_id, 0, "subscriptions not enabled"); + out_msg->add_attribute(out_msg, attr); + } } - sw_id_only = (flags & IETF_SWIMA_ATTR_REQ_FLAG_R); fulfill_request(state, out_msg, request_id, sw_id_only, targets); break; diff --git a/src/libimcv/plugins/imc_swima/imc_swima_state.c b/src/libimcv/plugins/imc_swima/imc_swima_state.c index 70b2434a4..55d887055 100644 --- a/src/libimcv/plugins/imc_swima/imc_swima_state.c +++ b/src/libimcv/plugins/imc_swima/imc_swima_state.c @@ -65,8 +65,33 @@ struct private_imc_swima_state_t { * PA-TNC attribute segmentation contracts associated with TNCCS connection */ seg_contract_manager_t *contracts; + + /** + * Has a subscription been established? + */ + bool has_subscription; + + /** + * State information on subscriptions + */ + imc_swima_subscription_t *subscription; + + /** + * Earliest EID for the next subscription round + */ + uint32_t earliest_eid; + }; +static void free_subscription(imc_swima_subscription_t *this) +{ + if (this) + { + this->targets->destroy(this->targets); + free(this); + } +} + METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, private_imc_swima_state_t *this) { @@ -110,10 +135,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_swima_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -134,13 +163,59 @@ METHOD(imc_state_t, get_result, bool, return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_swima_state_t *this) +{ + this->result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_swima_state_t *this) { + free(this->subscription); this->contracts->destroy(this->contracts); free(this); } +METHOD(imc_swima_state_t, set_subscription, void, + private_imc_swima_state_t *this, imc_swima_subscription_t *subscription, + bool set) +{ + free_subscription(this->subscription); + this->has_subscription = set; + + if (set) + { + this->subscription = subscription; + } + else + { + this->subscription = NULL; + } +} + +METHOD(imc_swima_state_t, get_subscription, bool, + private_imc_swima_state_t *this, imc_swima_subscription_t **subscription) +{ + if (subscription) + { + *subscription = this->subscription; + } + return this->has_subscription; +} + +METHOD(imc_swima_state_t, set_earliest_eid, void, + private_imc_swima_state_t *this, uint32_t eid) +{ + this->earliest_eid = eid; +} + +METHOD(imc_swima_state_t, get_earliest_eid, uint32_t, + private_imc_swima_state_t *this) +{ + return this->earliest_eid; +} + /** * Described in header. */ @@ -161,15 +236,20 @@ imc_state_t *imc_swima_state_create(TNC_ConnectionID connection_id) .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, + .set_subscription = _set_subscription, + .get_subscription = _get_subscription, + .set_earliest_eid = _set_earliest_eid, + .get_earliest_eid = _get_earliest_eid, }, .state = TNC_CONNECTION_STATE_CREATE, .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, .contracts = seg_contract_manager_create(), ); - + return &this->public.interface; } diff --git a/src/libimcv/plugins/imc_swima/imc_swima_state.h b/src/libimcv/plugins/imc_swima/imc_swima_state.h index 4e4e3b1bf..92a674ff8 100644 --- a/src/libimcv/plugins/imc_swima/imc_swima_state.h +++ b/src/libimcv/plugins/imc_swima/imc_swima_state.h @@ -25,9 +25,38 @@ #define IMC_SWIMA_STATE_H_ #include +#include #include typedef struct imc_swima_state_t imc_swima_state_t; +typedef struct imc_swima_subscription_t imc_swima_subscription_t; + +/** + * State information on subscriptions + */ +struct imc_swima_subscription_t { + + /** + * IMV which sent the subscription request + */ + TNC_IMVID imv_id; + + /** + * SWIMA Request ID + */ + uint32_t request_id; + + /** + * SWIMA Request targets + */ + swima_inventory_t *targets; + + /** + * Retrieve SW Identifieres only + */ + bool sw_id_only; + +}; /** * Internal state of an imc_swima_t connection instance @@ -39,6 +68,37 @@ struct imc_swima_state_t { */ imc_state_t interface; + /** + * Set or clear a subscription + * + * @param subscription state information on subscription + * @param set TRUE sets and FALSE clears a subscripton + */ + void (*set_subscription)(imc_swima_state_t *this, + imc_swima_subscription_t *subscription, bool set); + + /** + * Get the subscription status + * + * @param subscription state information on subscription + * @return TRUE if subscription is set + */ + bool (*get_subscription)(imc_swima_state_t *this, + imc_swima_subscription_t**subscription); + + /** + * Set the earliest EID for the next subscription round + * + * @param eid Earliest EID for events or 0 for inventories + */ + void (*set_earliest_eid)(imc_swima_state_t *this, uint32_t eid); + + /** + * Get earliest EID for the next subscription round + * + * @return Earliest EID for events or 0 for inventories + */ + uint32_t (*get_earliest_eid)(imc_swima_state_t *this); }; /** diff --git a/src/libimcv/plugins/imc_test/imc_test_state.c b/src/libimcv/plugins/imc_test/imc_test_state.c index 047c82502..86d59a76a 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.c +++ b/src/libimcv/plugins/imc_test/imc_test_state.c @@ -141,10 +141,14 @@ METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imc_state_t, change_state, void, +METHOD(imc_state_t, change_state, TNC_ConnectionState, private_imc_test_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imc_state_t, set_result, void, @@ -202,6 +206,12 @@ METHOD(imc_state_t, get_result, bool, return eval != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; } +METHOD(imc_state_t, reset, void, + private_imc_test_state_t *this) +{ + /* nothing to reset */ +} + METHOD(imc_state_t, destroy, void, private_imc_test_state_t *this) { @@ -277,6 +287,7 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, + .reset = _reset, .destroy = _destroy, }, .get_command = _get_command, diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c index d63940797..3d9e0ab1f 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c @@ -250,10 +250,14 @@ METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_attestation_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_recommendation, void, @@ -338,6 +342,24 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return FALSE; } +METHOD(imv_state_t, reset, void, + private_imv_attestation_state_t *this) +{ + DESTROY_IF(this->reason_string); + this->reason_string = NULL; + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->action_flags = 0; + + this->handshake_state = IMV_ATTESTATION_STATE_INIT; + this->measurement_error = 0; + this->components->destroy_function(this->components, (void *)free_func_comp); + this->components = linked_list_create(); + this->pts->destroy(this->pts); + this->pts = pts_create(FALSE); +} + METHOD(imv_state_t, destroy, void, private_imv_attestation_state_t *this) { @@ -532,6 +554,7 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .get_handshake_state = _get_handshake_state, diff --git a/src/libimcv/plugins/imv_hcd/imv_hcd_state.c b/src/libimcv/plugins/imv_hcd/imv_hcd_state.c index bfe6dd619..e2b6eaed9 100644 --- a/src/libimcv/plugins/imv_hcd/imv_hcd_state.c +++ b/src/libimcv/plugins/imv_hcd/imv_hcd_state.c @@ -213,10 +213,14 @@ METHOD(imv_state_t, update_recommendation, void, this->eval = tncif_policy_update_evaluation(this->eval, eval); } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_hcd_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_reason_string, bool, @@ -246,6 +250,24 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return FALSE; } +METHOD(imv_state_t, reset, void, + private_imv_hcd_state_t *this) +{ + DESTROY_IF(this->reason_string); + this->reason_string = NULL; + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->handshake_state = IMV_HCD_STATE_INIT; + this->subtype_action_flags[0].action_flags = IMV_HCD_ATTR_NONE; + this->subtype_action_flags[1].action_flags = IMV_HCD_ATTR_SYSTEM_ONLY; + this->subtype_action_flags[2].action_flags = IMV_HCD_ATTR_SYSTEM_ONLY; + this->subtype_action_flags[3].action_flags = IMV_HCD_ATTR_SYSTEM_ONLY; + this->subtype_action_flags[4].action_flags = IMV_HCD_ATTR_SYSTEM_ONLY; + this->subtype_action_flags[5].action_flags = IMV_HCD_ATTR_SYSTEM_ONLY; + this->action_flags = &this->subtype_action_flags[0].action_flags; +} + METHOD(imv_state_t, destroy, void, private_imv_hcd_state_t *this) { @@ -320,6 +342,7 @@ imv_state_t *imv_hcd_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .set_handshake_state = _set_handshake_state, diff --git a/src/libimcv/plugins/imv_os/imv_os_state.c b/src/libimcv/plugins/imv_os/imv_os_state.c index af5daf0fc..dd8fcf594 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.c +++ b/src/libimcv/plugins/imv_os/imv_os_state.c @@ -362,10 +362,14 @@ METHOD(imv_state_t, update_recommendation, void, this->eval = tncif_policy_update_evaluation(this->eval, eval); } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_os_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_reason_string, bool, @@ -466,6 +470,32 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return TRUE; } +METHOD(imv_state_t, reset, void, + private_imv_os_state_t *this) +{ + DESTROY_IF(this->reason_string); + DESTROY_IF(this->remediation_string); + this->reason_string = NULL; + this->remediation_string = NULL; + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->action_flags = 0; + + this->handshake_state = IMV_OS_STATE_INIT; + this->count = 0; + this->count_security = 0; + this->count_blacklist = 0; + this->count_ok = 0; + this->os_settings = 0; + this->missing = 0; + + this->update_packages->destroy_function(this->update_packages, free); + this->remove_packages->destroy_function(this->remove_packages, free); + this->update_packages = linked_list_create(); + this->remove_packages = linked_list_create(); +} + METHOD(imv_state_t, destroy, void, private_imv_os_state_t *this) { @@ -590,6 +620,7 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .set_handshake_state = _set_handshake_state, diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c index 8f9593f17..64ab5c4eb 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c @@ -222,10 +222,14 @@ METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_scanner_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_recommendation, void, @@ -303,6 +307,26 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return TRUE; } +METHOD(imv_state_t, reset, void, + private_imv_scanner_state_t *this) +{ + DESTROY_IF(this->reason_string); + DESTROY_IF(this->remediation_string); + this->reason_string = NULL; + this->remediation_string = NULL; + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->action_flags = 0; + + this->handshake_state = IMV_SCANNER_STATE_INIT; + + DESTROY_IF(&this->port_filter_attr->pa_tnc_attribute); + this->port_filter_attr = NULL; + this->violating_ports->destroy_function(this->violating_ports, free); + this->violating_ports = linked_list_create(); +} + METHOD(imv_state_t, destroy, void, private_imv_scanner_state_t *this) { @@ -373,6 +397,7 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .set_handshake_state = _set_handshake_state, @@ -391,5 +416,3 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) return &this->public.interface; } - - diff --git a/src/libimcv/plugins/imv_swima/imv_swima_agent.c b/src/libimcv/plugins/imv_swima/imv_swima_agent.c index 1d9944200..52f1baf03 100644 --- a/src/libimcv/plugins/imv_swima/imv_swima_agent.c +++ b/src/libimcv/plugins/imv_swima/imv_swima_agent.c @@ -187,11 +187,17 @@ static TNC_Result receive_msg(private_imv_swima_agent_t *this, } description = reader->peek(reader); if (description.len) - { + { DBG1(DBG_IMV, " description: %.*s", description.len, description.ptr); } reader->destroy(reader); + if (error_code.type == PA_ERROR_SWIMA_SUBSCRIPTION_DENIED) + { + swima_state->set_subscription(swima_state, FALSE); + DBG1(DBG_IMV, "SWIMA subscription %u cleared", + swima_state->get_request_id(swima_state)); + } break; } case IETF_ATTR_SW_ID_INVENTORY: @@ -474,7 +480,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, seg_contract_t *contract; seg_contract_manager_t *contracts; swima_inventory_t *targets; - uint32_t earliest_eid = 0; + uint32_t old_request_id = 0, earliest_eid = 0; char buf[BUF_LEN]; enumerator = session->create_workitem_enumerator(session); @@ -487,7 +493,13 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, { continue; } - + + earliest_eid = workitem->get_arg_int(workitem); + request_id = workitem->get_id(workitem); + workitem->set_imv_id(workitem, imv_id); + no_workitems = FALSE; + old_request_id = swima_state->get_request_id(swima_state); + flags = IETF_SWIMA_ATTR_REQ_FLAG_NONE; if (strchr(workitem->get_arg_str(workitem), 'R')) { @@ -496,47 +508,57 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, if (strchr(workitem->get_arg_str(workitem), 'S')) { flags |= IETF_SWIMA_ATTR_REQ_FLAG_S; + swima_state->set_subscription(swima_state, TRUE); + if (!old_request_id) + { + DBG1(DBG_IMV, "SWIMA subscription %u requested", + request_id); + } } if (strchr(workitem->get_arg_str(workitem), 'C')) { flags |= IETF_SWIMA_ATTR_REQ_FLAG_C; + swima_state->set_subscription(swima_state, FALSE); } - earliest_eid = workitem->get_arg_int(workitem); - /* Determine maximum PA-TNC attribute segment size */ - max_seg_size = state->get_max_msg_len(state) - - PA_TNC_HEADER_SIZE - - PA_TNC_ATTR_HEADER_SIZE - - TCG_SEG_ATTR_SEG_ENV_HEADER; + if (!old_request_id) + { + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) + - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER; - /* Announce support of PA-TNC segmentation to IMC */ - contract = seg_contract_create(msg_types[0], max_attr_size, - max_seg_size, TRUE, imv_id, FALSE); - contract->get_info_string(contract, buf, BUF_LEN, TRUE); - DBG2(DBG_IMV, "%s", buf); - contracts = state->get_contracts(state); - contracts->add_contract(contracts, contract); - attr = tcg_seg_attr_max_size_create(max_attr_size, - max_seg_size, TRUE); - out_msg->add_attribute(out_msg, attr); + /* Announce support of PA-TNC segmentation to IMC */ + contract = seg_contract_create(msg_types[0], max_attr_size, + max_seg_size, TRUE, imv_id, FALSE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMV, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, + max_seg_size, TRUE); + out_msg->add_attribute(out_msg, attr); + } - /* Issue a SWID request */ - request_id = workitem->get_id(workitem); - swima_state->set_request_id(swima_state, request_id); - attr = ietf_swima_attr_req_create(flags, request_id); + if (!old_request_id || + !swima_state->get_subscription(swima_state)) + { + /* Issue a SWID request */ + swima_state->set_request_id(swima_state, request_id); + attr = ietf_swima_attr_req_create(flags, request_id); - /* Request software identifier events */ - targets = swima_inventory_create(); - targets->set_eid(targets, earliest_eid, 0); - cast_attr = (ietf_swima_attr_req_t*)attr; - cast_attr->set_targets(cast_attr, targets); - targets->destroy(targets); + /* Request software identifier events */ + targets = swima_inventory_create(); + targets->set_eid(targets, earliest_eid, 0); + cast_attr = (ietf_swima_attr_req_t*)attr; + cast_attr->set_targets(cast_attr, targets); + targets->destroy(targets); - out_msg->add_attribute(out_msg, attr); - workitem->set_imv_id(workitem, imv_id); - no_workitems = FALSE; - DBG2(DBG_IMV, "IMV %d issues sw request %d with earliest eid %d", - imv_id, request_id, earliest_eid); + out_msg->add_attribute(out_msg, attr); + DBG2(DBG_IMV, "IMV %d issues sw request %d with earliest " + "eid %d", imv_id, request_id, earliest_eid); + } break; } enumerator->destroy(enumerator); @@ -565,7 +587,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, TNC_IMV_Action_Recommendation rec; char result_str[BUF_LEN], *format = NULL, *cmd = NULL, *command; char *target_str, *error_str = ""; - int sw_id_count, tag_count, i, res; + int sw_id_count, tag_count, i, res, written; json_object *jrequest, *jresponse, *jvalue; ietf_swima_attr_req_t *cast_attr; swima_inventory_t *targets; @@ -617,16 +639,24 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, &tag_count); if (format) { - snprintf(result_str, BUF_LEN, format, + written = snprintf(result_str, BUF_LEN, format, sw_id_count, (sw_id_count == 1) ? "" : "s", tag_count, (tag_count == 1) ? "" : "s"); } else { - snprintf(result_str, BUF_LEN, "received %d SWID tag" - "%s", tag_count, (tag_count == 1) ? "" : "s"); + written = snprintf(result_str, BUF_LEN, + "received %d SWID tag%s", + tag_count, (tag_count == 1) ? "" : "s"); } + if (swima_state->get_subscription(swima_state) && + written > 0 && written < BUF_LEN) + { + snprintf(result_str + written, BUF_LEN - written, + " from subscription %u", + swima_state->get_request_id(swima_state)); + } session->remove_workitem(session, enumerator); eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; diff --git a/src/libimcv/plugins/imv_swima/imv_swima_state.c b/src/libimcv/plugins/imv_swima/imv_swima_state.c index 03500bc2d..7d9631d3f 100644 --- a/src/libimcv/plugins/imv_swima/imv_swima_state.c +++ b/src/libimcv/plugins/imv_swima/imv_swima_state.c @@ -100,6 +100,11 @@ struct private_imv_swima_state_t { */ imv_remediation_string_t *remediation_string; + /** + * Has a subscription been established? + */ + bool has_subscription; + /** * SWID Tag Request ID */ @@ -204,10 +209,14 @@ METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_swima_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_recommendation, void, @@ -248,13 +257,28 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return FALSE; } +METHOD(imv_state_t, reset, void, + private_imv_swima_state_t *this) +{ + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->action_flags = 0; + + this->handshake_state = IMV_SWIMA_STATE_INIT; + this->sw_id_count = 0; + this->tag_count = 0; + this->missing = 0; + + json_object_put(this->jobj); + this->jobj = json_object_new_object(); +} + METHOD(imv_state_t, destroy, void, private_imv_swima_state_t *this) { json_object_put(this->jobj); DESTROY_IF(this->session); - DESTROY_IF(this->reason_string); - DESTROY_IF(this->remediation_string); this->contracts->destroy(this->contracts); free(this); } @@ -426,6 +450,18 @@ METHOD(imv_swima_state_t, get_imc_id, TNC_UInt32, return this->imc_id; } +METHOD(imv_swima_state_t, set_subscription, void, + private_imv_swima_state_t *this, bool set) +{ + this->has_subscription = set; +} + +METHOD(imv_swima_state_t, get_subscription, bool, + private_imv_swima_state_t *this) +{ + return this->has_subscription; +} + /** * Described in header. */ @@ -453,6 +489,7 @@ imv_state_t *imv_swima_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .set_handshake_state = _set_handshake_state, @@ -467,6 +504,8 @@ imv_state_t *imv_swima_state_create(TNC_ConnectionID connection_id) .set_count = _set_count, .get_count = _get_count, .get_imc_id = _get_imc_id, + .set_subscription = _set_subscription, + .get_subscription = _get_subscription, }, .state = TNC_CONNECTION_STATE_CREATE, .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, diff --git a/src/libimcv/plugins/imv_swima/imv_swima_state.h b/src/libimcv/plugins/imv_swima/imv_swima_state.h index 4fa32daf4..e2f805189 100644 --- a/src/libimcv/plugins/imv_swima/imv_swima_state.h +++ b/src/libimcv/plugins/imv_swima/imv_swima_state.h @@ -141,6 +141,20 @@ struct imv_swima_state_t { * @return SWID IMC ID */ TNC_UInt32 (*get_imc_id)(imv_swima_state_t *this); + + /** + * Set or clear a subscription + * + * @param set TRUE sets and FALSE clears a subscripton + */ + void (*set_subscription)(imv_swima_state_t *this, bool set); + + /** + * Get the subscription status + * + * @return TRUE if subscription is set + */ + bool (*get_subscription)(imv_swima_state_t *this); }; /** diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c index c20d00bd1..fe6bf18b2 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.c +++ b/src/libimcv/plugins/imv_test/imv_test_state.c @@ -173,10 +173,14 @@ METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, return this->contracts; } -METHOD(imv_state_t, change_state, void, +METHOD(imv_state_t, change_state, TNC_ConnectionState, private_imv_test_state_t *this, TNC_ConnectionState new_state) { + TNC_ConnectionState old_state; + + old_state = this->state; this->state = new_state; + return old_state; } METHOD(imv_state_t, get_recommendation, void, @@ -226,6 +230,20 @@ METHOD(imv_state_t, get_remediation_instructions, bool, return FALSE; } +METHOD(imv_state_t, reset, void, + private_imv_test_state_t *this) +{ + DESTROY_IF(this->reason_string); + this->reason_string = NULL; + this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + this->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + this->imcs->destroy_function(this->imcs, free); + this->imcs = linked_list_create(); + +} + + METHOD(imv_state_t, destroy, void, private_imv_test_state_t *this) { @@ -326,6 +344,7 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .update_recommendation = _update_recommendation, .get_reason_string = _get_reason_string, .get_remediation_instructions = _get_remediation_instructions, + .reset = _reset, .destroy = _destroy, }, .add_imc = _add_imc, diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c index 86ae1c099..32d950297 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c @@ -91,6 +91,11 @@ struct private_tnccs_20_server_t { */ bool request_handshake_retry; + /** + * Flag set after sending SRETRY batch + */ + bool retry_handshake; + /** * SendMessage() by IMV only allowed if flag is set */ @@ -279,8 +284,9 @@ static void build_retry_batch(private_tnccs_20_server_t *this) change_batch_type(this, PB_BATCH_SRETRY); this->recs->clear_recommendation(this->recs); - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); + + /* Handshake will be retried with next incoming CDATA batch */ + this->retry_handshake = TRUE; } METHOD(tnccs_20_handler_t, process, status_t, @@ -301,7 +307,17 @@ METHOD(tnccs_20_handler_t, process, status_t, pb_tnc_msg_t *msg; bool empty = TRUE; - if (batch_type == PB_BATCH_CRETRY) + if (batch_type == PB_BATCH_CDATA) + { + /* retry handshake after a previous SRETRY batch */ + if (this->retry_handshake) + { + tnc->imvs->notify_connection_change(tnc->imvs, + this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); + this->retry_handshake = FALSE; + } + } + else if (batch_type == PB_BATCH_CRETRY) { /* Send an SRETRY batch in response */ this->mutex->lock(this->mutex);