summaryrefslogtreecommitdiff
path: root/src/libimcv/imv/imv_agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libimcv/imv/imv_agent.c')
-rw-r--r--src/libimcv/imv/imv_agent.c210
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(),