diff options
Diffstat (limited to 'src/libimcv/imv/imv_agent.c')
-rw-r--r-- | src/libimcv/imv/imv_agent.c | 210 |
1 files changed, 139 insertions, 71 deletions
diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index 56131c547..fa04e0237 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,11 +15,11 @@ #include "imcv.h" #include "imv_agent.h" +#include "ietf/ietf_attr_assess_result.h" #include <tncif_names.h> #include <debug.h> -#include <utils/linked_list.h> #include <threading/rwlock.h> typedef struct private_imv_agent_t private_imv_agent_t; @@ -49,6 +50,11 @@ struct private_imv_agent_t { TNC_MessageSubtype subtype; /** + * Maximum PA-TNC Message size + */ + size_t max_msg_len; + + /** * ID of IMV as assigned by TNCS */ TNC_IMVID id; @@ -351,12 +357,31 @@ static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id, return NULL; } +/** + * Read an UInt32 attribute + */ +static u_int32_t get_uint_attribute(private_imv_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[4]; + + if (this->get_attribute && + this->get_attribute(this->id, id, attribute_id, 4, buf, &len) == + TNC_RESULT_SUCCESS && len == 4) + { + return untoh32(buf); + } + return 0; + } + METHOD(imv_agent_t, create_state, TNC_Result, private_imv_agent_t *this, imv_state_t *state) { TNC_ConnectionID conn_id; char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; + u_int32_t max_msg_len; conn_id = state->get_connection_id(state); if (find_connection(this, conn_id)) @@ -371,18 +396,22 @@ METHOD(imv_agent_t, create_state, TNC_Result, has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES); has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE); has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH); - tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); + tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION); t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL); t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION); + max_msg_len = get_uint_attribute(this, conn_id, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE); state->set_flags(state, has_long, has_excl); + state->set_max_msg_len(state, max_msg_len); + + DBG2(DBG_IMV, "IMV %u \"%s\" created a state for %s %s Connection ID %u: " + "%slong %sexcl %ssoh", this->id, this->name, + tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id, + has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-"); + DBG2(DBG_IMV, " over %s %s with maximum PA-TNC message size of %u bytes", + t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len); - DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u: " - "%s %s with %slong %sexcl %ssoh over %s %s", - this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?", - tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-", - has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?"); free(tnccs_p); free(tnccs_v); free(t_p); @@ -449,7 +478,7 @@ METHOD(imv_agent_t, change_state, TNC_Result, DBG1(DBG_IMV, "IMV %u \"%s\" was notified of unknown state %u " "for Connection ID %u", this->id, this->name, new_state, connection_id); - return TNC_RESULT_INVALID_PARAMETER; + return TNC_RESULT_INVALID_PARAMETER; } return TNC_RESULT_SUCCESS; } @@ -470,11 +499,17 @@ METHOD(imv_agent_t, get_state, bool, METHOD(imv_agent_t, send_message, TNC_Result, private_imv_agent_t *this, TNC_ConnectionID connection_id, bool excl, - TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, chunk_t msg) + TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, linked_list_t *attr_list) { TNC_MessageType type; TNC_UInt32 msg_flags; + TNC_Result result = TNC_RESULT_FATAL; imv_state_t *state; + pa_tnc_attr_t *attr; + pa_tnc_msg_t *pa_tnc_msg; + chunk_t msg; + enumerator_t *enumerator; + bool attr_added; state = find_connection(this, connection_id); if (!state) @@ -484,26 +519,70 @@ METHOD(imv_agent_t, send_message, TNC_Result, return TNC_RESULT_FATAL; } - if (state->has_long(state) && this->send_message_long) + while (attr_list->get_count(attr_list)) { - if (!src_imv_id) + pa_tnc_msg = pa_tnc_msg_create(this->max_msg_len); + attr_added = FALSE; + + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) + { + if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr)) + { + attr_added = TRUE; + } + else + { + if (attr_added) + { + break; + } + else + { + DBG1(DBG_IMV, "PA-TNC attribute too large to send, deleted"); + attr->destroy(attr); + } + } + attr_list->remove_at(attr_list, enumerator); + } + enumerator->destroy(enumerator); + + /* build and send the PA-TNC message via the IF-IMV interface */ + if (!pa_tnc_msg->build(pa_tnc_msg)) { - src_imv_id = this->id; + pa_tnc_msg->destroy(pa_tnc_msg); + return TNC_RESULT_FATAL; } - msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + msg = pa_tnc_msg->get_encoding(pa_tnc_msg); - return this->send_message_long(src_imv_id, connection_id, msg_flags, - msg.ptr, msg.len, this->vendor_id, - this->subtype, dst_imc_id); - } - if (this->send_message) - { - type = (this->vendor_id << 8) | this->subtype; + if (state->has_long(state) && this->send_message_long) + { + if (!src_imv_id) + { + src_imv_id = this->id; + } + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; - return this->send_message(this->id, connection_id, msg.ptr, msg.len, - type); + result = this->send_message_long(src_imv_id, connection_id, + msg_flags, msg.ptr, msg.len, this->vendor_id, + this->subtype, dst_imc_id); + } + else if (this->send_message) + { + type = (this->vendor_id << 8) | this->subtype; + + result = this->send_message(this->id, connection_id, msg.ptr, + msg.len, type); + } + + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result != TNC_RESULT_SUCCESS) + { + break; + } } - return TNC_RESULT_FATAL; + return result; } METHOD(imv_agent_t, set_recommendation, TNC_Result, @@ -530,11 +609,11 @@ METHOD(imv_agent_t, receive_message, TNC_Result, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, pa_tnc_msg_t **pa_tnc_msg) { - pa_tnc_msg_t *pa_msg, *error_msg; + pa_tnc_msg_t *pa_msg; pa_tnc_attr_t *error_attr; + linked_list_t *error_attr_list; enumerator_t *enumerator; - TNC_MessageType msg_type; - TNC_UInt32 msg_flags, src_imv_id, dst_imc_id; + TNC_UInt32 src_imv_id, dst_imc_id; TNC_ConnectionID connection_id; TNC_Result result; @@ -570,53 +649,24 @@ METHOD(imv_agent_t, receive_message, TNC_Result, *pa_tnc_msg = pa_msg; break; case VERIFY_ERROR: - /* build error message */ - error_msg = pa_tnc_msg_create(); + /* extract and copy by refence all error attributes */ + error_attr_list = linked_list_create(); + enumerator = pa_msg->create_error_enumerator(pa_msg); while (enumerator->enumerate(enumerator, &error_attr)) { - error_msg->add_attribute(error_msg, - error_attr->get_ref(error_attr)); + error_attr_list->insert_last(error_attr_list, + error_attr->get_ref(error_attr)); } enumerator->destroy(enumerator); - error_msg->build(error_msg); - /* send error message */ - msg = error_msg->get_encoding(error_msg); + src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id : dst_imv_id; + dst_imc_id = state->has_excl(state) ? src_imc_id : TNC_IMCID_ANY; - if (state->has_long(state) && this->send_message_long) - { - if (state->has_excl(state)) - { - msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE; - dst_imc_id = src_imc_id; - } - else - { - msg_flags = 0; - dst_imc_id = TNC_IMCID_ANY; - } - src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id - : dst_imv_id; - - result = this->send_message_long(src_imv_id, connection_id, - msg_flags, msg.ptr, msg.len, msg_vid, - msg_subtype, dst_imc_id); - } - else if (this->send_message) - { - msg_type = (msg_vid << 8) | msg_subtype; + result = send_message(this, connection_id, state->has_excl(state), + src_imv_id, dst_imc_id, error_attr_list); - result = this->send_message(this->id, connection_id, - msg.ptr, msg.len, msg_type); - } - else - { - result = TNC_RESULT_FATAL; - } - - /* clean up */ - error_msg->destroy(error_msg); + error_attr_list->destroy(error_attr_list); pa_msg->destroy(pa_msg); return result; case FAILED: @@ -633,9 +683,13 @@ METHOD(imv_agent_t, receive_message, TNC_Result, } METHOD(imv_agent_t, provide_recommendation, TNC_Result, - private_imv_agent_t *this, TNC_ConnectionID connection_id) + private_imv_agent_t *this, TNC_ConnectionID connection_id, + TNC_UInt32 dst_imc_id) { imv_state_t *state; + linked_list_t *attr_list; + pa_tnc_attr_t *attr; + TNC_Result result; TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; TNC_UInt32 lang_len; @@ -651,7 +705,6 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, } state->get_recommendation(state, &rec, &eval); - /* send a reason string if action recommendation is not allow */ if (rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW) { @@ -663,8 +716,8 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, lang_len <= BUF_LEN) { pref_lang.len = lang_len; - DBG2(DBG_IMV, "preferred language is '%.*s'", - pref_lang.len, pref_lang.ptr); + DBG2(DBG_IMV, "preferred language is '%.*s'", (int)pref_lang.len, + pref_lang.ptr); } /* find a reason string for the preferred or default language and set it */ @@ -680,7 +733,21 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, reason_lang.len, reason_lang.ptr); } } - + + /* Send an IETF Assessment Result attribute if enabled */ + if (lib->settings->get_bool(lib->settings, "libimcv.assessment_result", TRUE)) + { + attr = ietf_attr_assess_result_create(eval); + attr_list = linked_list_create(); + attr_list->insert_last(attr_list, attr); + result = send_message(this, connection_id, FALSE, this->id, dst_imc_id, + attr_list); + attr_list->destroy(attr_list); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + } return this->provide_recommendation(this->id, connection_id, rec, eval); } @@ -777,6 +844,7 @@ imv_agent_t *imv_agent_create(const char *name, .name = name, .vendor_id = vendor_id, .subtype = subtype, + .max_msg_len = 65490, .id = id, .additional_ids = linked_list_create(), .connections = linked_list_create(), |