summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c')
-rw-r--r--src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c415
1 files changed, 415 insertions, 0 deletions
diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c b/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c
new file mode 100644
index 000000000..5cc6b0ced
--- /dev/null
+++ b/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2010 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <debug.h>
+#include <daemon.h>
+#include <tnc/tncifimv.h>
+#include <tnc/imv/imv.h>
+#include <tnc/imv/imv_recommendations.h>
+
+typedef struct private_tnc_imv_recommendations_t private_tnc_imv_recommendations_t;
+typedef struct recommendation_entry_t recommendation_entry_t;
+
+/**
+ * Recommendation entry
+ */
+struct recommendation_entry_t {
+
+ /**
+ * IMV ID
+ */
+ TNC_IMVID id;
+
+ /**
+ * Received a recommendation message from this IMV?
+ */
+ bool have_recommendation;
+
+ /**
+ * Action Recommendation provided by IMV instance
+ */
+ TNC_IMV_Action_Recommendation rec;
+
+ /**
+ * Evaluation Result provided by IMV instance
+ */
+ TNC_IMV_Evaluation_Result eval;
+
+ /**
+ * Reason string provided by IMV instance
+ */
+ chunk_t reason;
+
+ /**
+ * Reason language provided by IMV instance
+ */
+ chunk_t reason_language;
+};
+
+/**
+ * Private data of a recommendations_t object.
+ */
+struct private_tnc_imv_recommendations_t {
+
+ /**
+ * Public members of recommendations_t.
+ */
+ recommendations_t public;
+
+ /**
+ * list of recommendations and evaluations provided by IMVs
+ */
+ linked_list_t *recs;
+
+ /**
+ * Preferred language for remediation messages
+ */
+ chunk_t preferred_language;
+};
+
+METHOD(recommendations_t, provide_recommendation, TNC_Result,
+ private_tnc_imv_recommendations_t* this, TNC_IMVID id,
+ TNC_IMV_Action_Recommendation rec,
+ TNC_IMV_Evaluation_Result eval)
+{
+ enumerator_t *enumerator;
+ recommendation_entry_t *entry;
+ bool found = FALSE;
+
+ DBG2(DBG_TNC, "IMV %u provides recommendation '%N' and evaluation '%N'", id,
+ TNC_IMV_Action_Recommendation_names, rec,
+ TNC_IMV_Evaluation_Result_names, eval);
+
+ enumerator = this->recs->create_enumerator(this->recs);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->id == id)
+ {
+ found = TRUE;
+ entry->have_recommendation = TRUE;
+ entry->rec = rec;
+ entry->eval = eval;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found ? TNC_RESULT_SUCCESS : TNC_RESULT_FATAL;
+}
+
+METHOD(recommendations_t, have_recommendation, bool,
+ private_tnc_imv_recommendations_t *this, TNC_IMV_Action_Recommendation *rec,
+ TNC_IMV_Evaluation_Result *eval)
+{
+ enumerator_t *enumerator;
+ recommendation_entry_t *entry;
+ recommendation_policy_t policy;
+ TNC_IMV_Action_Recommendation final_rec;
+ TNC_IMV_Evaluation_Result final_eval;
+ bool first = TRUE, incomplete = FALSE;
+
+ *rec = final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+ *eval = final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
+
+ if (this->recs->get_count(this->recs) == 0)
+ {
+ DBG1(DBG_TNC, "there are no IMVs to make a recommendation");
+ return TRUE;
+ }
+ policy = charon->imvs->get_recommendation_policy(charon->imvs);
+
+ enumerator = this->recs->create_enumerator(this->recs);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (!entry->have_recommendation)
+ {
+ incomplete = TRUE;
+ break;
+ }
+ if (first)
+ {
+ final_rec = entry->rec;
+ final_eval = entry->eval;
+ first = FALSE;
+ continue;
+ }
+ switch (policy)
+ {
+ case RECOMMENDATION_POLICY_DEFAULT:
+ switch (entry->rec)
+ {
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ final_rec = entry->rec;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+ {
+ final_rec = entry->rec;
+ };
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+ {
+ final_rec = entry->rec;
+ };
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ break;
+ }
+ switch (entry->eval)
+ {
+ case TNC_IMV_EVALUATION_RESULT_ERROR:
+ final_eval = entry->eval;
+ break;
+ case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
+ if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
+ if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR &&
+ final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
+ if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
+ break;
+ }
+ break;
+
+ case RECOMMENDATION_POLICY_ALL:
+ if (entry->rec != final_rec)
+ {
+ final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+ }
+ if (entry->eval != final_eval)
+ {
+ final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
+ }
+ break;
+
+ case RECOMMENDATION_POLICY_ANY:
+ switch (entry->rec)
+ {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ final_rec = entry->rec;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
+ {
+ final_rec = entry->rec;
+ };
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+ {
+ final_rec = entry->rec;
+ };
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ break;
+ }
+ switch (entry->eval)
+ {
+ case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
+ final_eval = entry->eval;
+ break;
+ case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
+ if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
+ if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT &&
+ final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_ERROR:
+ if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
+ {
+ final_eval = entry->eval;
+ }
+ break;
+ case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (incomplete)
+ {
+ return FALSE;
+ }
+ *rec = final_rec;
+ *eval = final_eval;
+ return TRUE;
+}
+
+METHOD(recommendations_t, get_preferred_language, chunk_t,
+ private_tnc_imv_recommendations_t *this)
+{
+ return this->preferred_language;
+}
+
+METHOD(recommendations_t, set_preferred_language, void,
+ private_tnc_imv_recommendations_t *this, chunk_t pref_lang)
+{
+ free(this->preferred_language.ptr);
+ this->preferred_language = chunk_clone(pref_lang);
+}
+
+METHOD(recommendations_t, set_reason_string, TNC_Result,
+ private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason)
+{
+ enumerator_t *enumerator;
+ recommendation_entry_t *entry;
+ bool found = FALSE;
+
+ DBG2(DBG_TNC, "IMV %u is setting reason string to '%.*s'",
+ id, reason.len, reason.ptr);
+
+ enumerator = this->recs->create_enumerator(this->recs);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->id == id)
+ {
+ found = TRUE;
+ free(entry->reason.ptr);
+ entry->reason = chunk_clone(reason);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
+}
+
+METHOD(recommendations_t, set_reason_language, TNC_Result,
+ private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason_lang)
+{
+ enumerator_t *enumerator;
+ recommendation_entry_t *entry;
+ bool found = FALSE;
+
+ DBG2(DBG_TNC, "IMV %u is setting reason language to '%.*s'",
+ id, reason_lang.len, reason_lang.ptr);
+
+ enumerator = this->recs->create_enumerator(this->recs);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->id == id)
+ {
+ found = TRUE;
+ free(entry->reason_language.ptr);
+ entry->reason_language = chunk_clone(reason_lang);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
+}
+
+/**
+ * Enumerate reason and reason_language, not recommendation entries
+ */
+static bool reason_filter(void *null, recommendation_entry_t **entry,
+ TNC_IMVID *id, void *i2, chunk_t *reason, void *i3,
+ chunk_t *reason_language)
+{
+ if ((*entry)->reason.len)
+ {
+ *id = (*entry)->id;
+ *reason = (*entry)->reason;
+ *reason_language = (*entry)->reason_language;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+METHOD(recommendations_t, create_reason_enumerator, enumerator_t*,
+ private_tnc_imv_recommendations_t *this)
+{
+ return enumerator_create_filter(this->recs->create_enumerator(this->recs),
+ (void*)reason_filter, NULL, NULL);
+}
+
+METHOD(recommendations_t, destroy, void,
+ private_tnc_imv_recommendations_t *this)
+{
+ recommendation_entry_t *entry;
+
+ while (this->recs->remove_last(this->recs, (void**)&entry) == SUCCESS)
+ {
+ free(entry->reason.ptr);
+ free(entry->reason_language.ptr);
+ free(entry);
+ }
+ this->recs->destroy(this->recs);
+ free(this->preferred_language.ptr);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+recommendations_t* tnc_imv_recommendations_create(linked_list_t *imv_list)
+{
+ private_tnc_imv_recommendations_t *this;
+ recommendation_entry_t *entry;
+ enumerator_t *enumerator;
+ imv_t *imv;
+
+ INIT(this,
+ .public = {
+ .provide_recommendation = _provide_recommendation,
+ .have_recommendation = _have_recommendation,
+ .get_preferred_language = _get_preferred_language,
+ .set_preferred_language = _set_preferred_language,
+ .set_reason_string = _set_reason_string,
+ .set_reason_language = _set_reason_language,
+ .create_reason_enumerator = _create_reason_enumerator,
+ .destroy = _destroy,
+ },
+ .recs = linked_list_create(),
+ );
+
+ enumerator = imv_list->create_enumerator(imv_list);
+ while (enumerator->enumerate(enumerator, &imv))
+ {
+ entry = malloc_thing(recommendation_entry_t);
+ entry->id = imv->get_id(imv);
+ entry->have_recommendation = FALSE;
+ entry->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+ entry->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
+ entry->reason = chunk_empty;
+ entry->reason_language = chunk_empty;
+ this->recs->insert_last(this->recs, entry);
+ }
+ enumerator->destroy(enumerator);
+
+ return &this->public;
+}