aboutsummaryrefslogtreecommitdiffstats
path: root/src/libtnccs/plugins
diff options
context:
space:
mode:
authorAndreas Steffen <andreas.steffen@strongswan.org>2013-08-08 11:02:17 +0200
committerAndreas Steffen <andreas.steffen@strongswan.org>2013-08-15 23:34:22 +0200
commite8f65c5cdee4e04bf898f49e07d783ae6b3441aa (patch)
tree84b9797fdf106fa9520d3f1fb032a8c37d8a255a /src/libtnccs/plugins
parent180a2f2642fc55c9d0836449e55bf76a52391c31 (diff)
downloadstrongswan-e8f65c5cdee4e04bf898f49e07d783ae6b3441aa.tar.bz2
strongswan-e8f65c5cdee4e04bf898f49e07d783ae6b3441aa.tar.xz
Moved tnc-tnccs, tnc-imc, tnccs-11, tnccs-20 and tnccs-dynamic libcharon plugins to libtnccs
Diffstat (limited to 'src/libtnccs/plugins')
-rw-r--r--src/libtnccs/plugins/tnc_imc/Makefile.am23
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc.c428
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc.h60
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc_bind_function.c222
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c441
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc_manager.h32
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c79
-rw-r--r--src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h42
-rw-r--r--src/libtnccs/plugins/tnc_tnccs/Makefile.am23
-rw-r--r--src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c866
-rw-r--r--src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.h31
-rw-r--r--src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.c98
-rw-r--r--src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h42
-rw-r--r--src/libtnccs/plugins/tnccs_11/Makefile.am33
-rw-r--r--src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.c325
-rw-r--r--src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.h100
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.c243
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.h71
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.c190
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.h80
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.c140
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.h102
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.c137
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.h64
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.c196
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.h64
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.c186
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.h64
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.c118
-rw-r--r--src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.h54
-rw-r--r--src/libtnccs/plugins/tnccs_11/tnccs_11.c631
-rw-r--r--src/libtnccs/plugins/tnccs_11/tnccs_11.h42
-rw-r--r--src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c61
-rw-r--r--src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h42
-rw-r--r--src/libtnccs/plugins/tnccs_20/Makefile.am33
-rw-r--r--src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c577
-rw-r--r--src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h130
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.c181
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.h76
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.c174
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.h60
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.c352
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.h127
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.c102
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.h53
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.c179
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.h60
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.c274
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.h98
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.c217
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.h69
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c311
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h118
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c75
-rw-r--r--src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h128
-rw-r--r--src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c316
-rw-r--r--src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h102
-rw-r--r--src/libtnccs/plugins/tnccs_20/tnccs_20.c941
-rw-r--r--src/libtnccs/plugins/tnccs_20/tnccs_20.h42
-rw-r--r--src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.c61
-rw-r--r--src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h42
-rw-r--r--src/libtnccs/plugins/tnccs_dynamic/Makefile.am22
-rw-r--r--src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c223
-rw-r--r--src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h42
-rw-r--r--src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c62
-rw-r--r--src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h42
66 files changed, 10619 insertions, 0 deletions
diff --git a/src/libtnccs/plugins/tnc_imc/Makefile.am b/src/libtnccs/plugins/tnc_imc/Makefile.am
new file mode 100644
index 000000000..b2c26cbff
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/Makefile.am
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtnccs \
+ -I$(top_srcdir)/src/libtls
+
+AM_CFLAGS = \
+ -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnc-imc.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnc-imc.la
+libstrongswan_tnc_imc_la_LIBADD = \
+ $(top_builddir)/src/libtncif/libtncif.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnc_imc_la_SOURCES = \
+ tnc_imc_plugin.h tnc_imc_plugin.c tnc_imc.h tnc_imc.c \
+ tnc_imc_manager.h tnc_imc_manager.c tnc_imc_bind_function.c
+
+libstrongswan_tnc_imc_la_LDFLAGS = -module -avoid-version
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc.c b/src/libtnccs/plugins/tnc_imc/tnc_imc.c
new file mode 100644
index 000000000..cbecf14c7
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2006 Mike McCauley
+ * Copyright (C) 2010-2011 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 "tnc_imc.h"
+
+#include <dlfcn.h>
+
+#include <tncif_pa_subtypes.h>
+
+#include <utils/debug.h>
+#include <library.h>
+#include <collections/linked_list.h>
+#include <threading/mutex.h>
+
+typedef struct private_tnc_imc_t private_tnc_imc_t;
+
+/**
+ * Private data of an imc_t object.
+ */
+struct private_tnc_imc_t {
+
+ /**
+ * Public members of imc_t.
+ */
+ imc_t public;
+
+ /**
+ * Name of loaded IMC
+ */
+ char *name;
+
+ /**
+ * Handle of loaded IMC
+ */
+ void *handle;
+
+ /**
+ * ID of loaded IMC
+ */
+ TNC_IMCID id;
+
+ /**
+ * list of additional IMC IDs
+ */
+ linked_list_t *additional_ids;
+
+ /**
+ * List of message types supported by IMC - Vendor ID part
+ */
+ TNC_VendorIDList supported_vids;
+
+ /**
+ * List of message types supported by IMC - Subtype part
+ */
+ TNC_MessageSubtypeList supported_subtypes;
+
+ /**
+ * Number of supported message types
+ */
+ TNC_UInt32 type_count;
+
+ /**
+ * mutex to lock the imc_t object
+ */
+ mutex_t *mutex;
+};
+
+METHOD(imc_t, set_id, void,
+ private_tnc_imc_t *this, TNC_IMCID id)
+{
+ this->id = id;
+}
+
+METHOD(imc_t, get_id, TNC_IMCID,
+ private_tnc_imc_t *this)
+{
+ return this->id;
+}
+
+METHOD(imc_t, add_id, void,
+ private_tnc_imc_t *this, TNC_IMCID id)
+{
+ void *pointer;
+
+ /* store the scalar value in the pointer */
+ pointer = (void*)id;
+ this->additional_ids->insert_last(this->additional_ids, pointer);
+}
+
+METHOD(imc_t, has_id, bool,
+ private_tnc_imc_t *this, TNC_IMCID id)
+{
+ enumerator_t *enumerator;
+ TNC_IMCID additional_id;
+ void *pointer;
+ bool found = FALSE;
+
+ /* check primary IMC ID */
+ if (id == this->id)
+ {
+ return TRUE;
+ }
+
+ /* return if there are no additional IMC IDs */
+ if (this->additional_ids->get_count(this->additional_ids) == 0)
+ {
+ return FALSE;
+ }
+
+ /* check additional IMC IDs */
+ enumerator = this->additional_ids->create_enumerator(this->additional_ids);
+ while (enumerator->enumerate(enumerator, &pointer))
+ {
+ /* interpret pointer as scalar value */
+ additional_id = (TNC_UInt32)pointer;
+
+ if (id == additional_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+METHOD(imc_t, get_name, char*,
+ private_tnc_imc_t *this)
+{
+ return this->name;
+}
+
+METHOD(imc_t, set_message_types, void,
+ private_tnc_imc_t *this, TNC_MessageTypeList supported_types,
+ TNC_UInt32 type_count)
+{
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = sizeof(buf);
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
+
+ /* lock the imc_t instance */
+ this->mutex->lock(this->mutex);
+
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
+
+ /* Store the new MessageType list */
+ this->type_count = type_count;
+ if (type_count && supported_types)
+ {
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
+
+ for (i = 0; i < type_count; i++)
+ {
+ vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
+ subtype = supported_types[i] & TNC_SUBTYPE_ANY;
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
+ pen_names, vid, vid, subtype);
+ }
+ if (written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+
+ this->supported_vids[i] = vid;
+ this->supported_subtypes[i] = subtype;
+ }
+ }
+ *pos = '\0';
+ DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s",
+ this->id, type_count, (type_count == 1) ? "":"s", buf);
+
+ /* unlock the imc_t instance */
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(imc_t, set_message_types_long, void,
+ private_tnc_imc_t *this, TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
+{
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = sizeof(buf);
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
+
+ /* lock the imc_t instance */
+ this->mutex->lock(this->mutex);
+
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
+
+ /* Store the new MessageType list */
+ this->type_count = type_count;
+ if (type_count && supported_vids && supported_subtypes)
+ {
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ memcpy(this->supported_vids, supported_vids, size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
+ memcpy(this->supported_subtypes, supported_subtypes, size);
+
+ for (i = 0; i < type_count; i++)
+ {
+ vid = supported_vids[i];
+ subtype = supported_subtypes[i];
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
+ pen_names, vid, vid, subtype);
+ }
+ if (written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ }
+ *pos = '\0';
+ DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s",
+ this->id, type_count, (type_count == 1) ? "":"s", buf);
+
+ /* unlock the imc_t instance */
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(imc_t, type_supported, bool,
+ private_tnc_imc_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
+{
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ int i;
+
+ for (i = 0; i < this->type_count; i++)
+ {
+ vid = this->supported_vids[i];
+ subtype = this->supported_subtypes[i];
+
+ if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
+ (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
+ subtype == msg_subtype)))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(imc_t, destroy, void,
+ private_tnc_imc_t *this)
+{
+ if (this->handle && lib->settings->get_bool(lib->settings,
+ "libtnccs.plugins.tnc-imc.dlclose", TRUE))
+ {
+ dlclose(this->handle);
+ }
+ this->mutex->destroy(this->mutex);
+ this->additional_ids->destroy(this->additional_ids);
+ free(this->supported_vids);
+ free(this->supported_subtypes);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Generic constructor
+ */
+static private_tnc_imc_t* tnc_imc_create_empty(char *name)
+{
+ private_tnc_imc_t *this;
+
+ INIT(this,
+ .public = {
+ .set_id = _set_id,
+ .get_id = _get_id,
+ .add_id = _add_id,
+ .has_id = _has_id,
+ .get_name = _get_name,
+ .set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
+ .type_supported = _type_supported,
+ .destroy = _destroy,
+ },
+ .name = strdup(name),
+ .additional_ids = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ return this;
+}
+
+/**
+ * See header
+ */
+imc_t* tnc_imc_create(char *name, char *path)
+{
+ private_tnc_imc_t *this;
+
+ this = tnc_imc_create_empty(name);
+
+ this->handle = dlopen(path, RTLD_LAZY);
+ if (!this->handle)
+ {
+ DBG1(DBG_TNC, "IMC \"%s\" failed to load: %s", name, dlerror());
+ destroy(this);
+ return NULL;
+ }
+
+ this->public.initialize = dlsym(this->handle, "TNC_IMC_Initialize");
+ if (!this->public.initialize)
+ {
+ DBG1(DBG_TNC, "could not resolve TNC_IMC_Initialize in %s: %s\n",
+ path, dlerror());
+ destroy(this);
+ return NULL;
+ }
+ this->public.notify_connection_change =
+ dlsym(this->handle, "TNC_IMC_NotifyConnectionChange");
+ this->public.begin_handshake = dlsym(this->handle, "TNC_IMC_BeginHandshake");
+ if (!this->public.begin_handshake)
+ {
+ DBG1(DBG_TNC, "could not resolve TNC_IMC_BeginHandshake in %s: %s\n",
+ path, dlerror());
+ destroy(this);
+ return NULL;
+ }
+ this->public.receive_message =
+ dlsym(this->handle, "TNC_IMC_ReceiveMessage");
+ this->public.receive_message_long =
+ dlsym(this->handle, "TNC_IMC_ReceiveMessageLong");
+ this->public.batch_ending =
+ dlsym(this->handle, "TNC_IMC_BatchEnding");
+ this->public.terminate =
+ dlsym(this->handle, "TNC_IMC_Terminate");
+ this->public.provide_bind_function =
+ dlsym(this->handle, "TNC_IMC_ProvideBindFunction");
+ if (!this->public.provide_bind_function)
+ {
+ DBG1(DBG_TNC, "could not resolve TNC_IMC_ProvideBindFunction in %s: %s\n",
+ path, dlerror());
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+imc_t* tnc_imc_create_from_functions(char *name,
+ TNC_IMC_InitializePointer initialize,
+ TNC_IMC_NotifyConnectionChangePointer notify_connection_change,
+ TNC_IMC_BeginHandshakePointer begin_handshake,
+ TNC_IMC_ReceiveMessagePointer receive_message,
+ TNC_IMC_ReceiveMessageLongPointer receive_message_long,
+ TNC_IMC_BatchEndingPointer batch_ending,
+ TNC_IMC_TerminatePointer terminate,
+ TNC_IMC_ProvideBindFunctionPointer provide_bind_function)
+{
+ private_tnc_imc_t *this;
+
+ this = tnc_imc_create_empty(name);
+
+ this->public.initialize = initialize;
+ this->public.notify_connection_change = notify_connection_change;
+ this->public.begin_handshake = begin_handshake;
+ this->public.receive_message = receive_message;
+ this->public.receive_message_long = receive_message_long;
+ this->public.batch_ending = batch_ending;
+ this->public.terminate = terminate;
+ this->public.provide_bind_function = provide_bind_function;
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc.h b/src/libtnccs/plugins/tnc_imc/tnc_imc.h
new file mode 100644
index 000000000..2d4607e77
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * @defgroup tnc_imc_t tnc_imc
+ * @{ @ingroup tnc_imc
+ */
+
+#ifndef TNC_IMC_H_
+#define TNC_IMC_H_
+
+#include <tnc/imc/imc.h>
+
+/**
+ * Create an Integrity Measurement Collector loaded from a library.
+ *
+ * @param name name of the IMC
+ * @param filename path to the dynamic IMC library
+ * @return instance of the imc_t interface
+ */
+imc_t* tnc_imc_create(char *name, char *filename);
+
+/**
+ * Create an Integrity Measurement Collector from a set of IMC functions.
+ *
+ * @param name name of the IMC
+ * @param initialize TNC_IMC_InitializePointer
+ * @param notify_connection_change TNC_IMC_NotifyConnectionChangePointer
+ * @param begin_handshake TNC_IMC_BeginHandshakePointer
+ * @param receive_message TNC_IMC_ReceiveMessagePointer
+ * @param receive_message_long TNC_IMC_ReceiveMessageLongPointer
+ * @param batch_ending TNC_IMC_BatchEndingPointer
+ * @param terminate TNC_IMC_TerminatePointer
+ * @param provide_bind_function TNC_IMC_ProvideBindFunctionPointer
+ * @return instance of the imc_t interface
+ */
+imc_t* tnc_imc_create_from_functions(char *name,
+ TNC_IMC_InitializePointer initialize,
+ TNC_IMC_NotifyConnectionChangePointer notify_connection_change,
+ TNC_IMC_BeginHandshakePointer begin_handshake,
+ TNC_IMC_ReceiveMessagePointer receive_message,
+ TNC_IMC_ReceiveMessageLongPointer receive_message_long,
+ TNC_IMC_BatchEndingPointer batch_ending,
+ TNC_IMC_TerminatePointer terminate,
+ TNC_IMC_ProvideBindFunctionPointer provide_bind_function);
+
+#endif /** TNC_IMC_H_ @}*/
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_bind_function.c b/src/libtnccs/plugins/tnc_imc/tnc_imc_bind_function.c
new file mode 100644
index 000000000..26a5ed2b4
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_bind_function.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006 Mike McCauley
+ * 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 <tnc/tnc.h>
+#include <tnc/imc/imc_manager.h>
+#include <tnc/tnccs/tnccs_manager.h>
+
+#include <utils/debug.h>
+
+/**
+ * Called by the IMC to inform a TNCC about the set of message types the IMC
+ * is able to receive
+ */
+TNC_Result TNC_TNCC_ReportMessageTypes(TNC_IMCID imc_id,
+ TNC_MessageTypeList supported_types,
+ TNC_UInt32 type_count)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring ReportMessageTypes() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->imcs->set_message_types(tnc->imcs, imc_id, supported_types,
+ type_count);
+}
+
+/**
+ * Called by the IMC to inform a TNCC about the set of message types the IMC
+ * is able to receive. This function supports long message types.
+ */
+TNC_Result TNC_TNCC_ReportMessageTypesLong(TNC_IMCID imc_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring ReportMessageTypesLong() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->imcs->set_message_types_long(tnc->imcs, imc_id, supported_vids,
+ supported_subtypes, type_count);
+}
+
+/**
+ * Called by the IMC to ask a TNCC to retry an Integrity Check Handshake
+ */
+TNC_Result TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_RetryReason reason)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring RequestHandshakeRetry() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->request_handshake_retry(tnc->tnccs, TRUE, imc_id,
+ connection_id, reason);
+}
+
+/**
+ * Called by the IMC when an IMC-IMV message is to be sent
+ */
+TNC_Result TNC_TNCC_SendMessage(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return tnc->tnccs->send_message(tnc->tnccs, imc_id, TNC_IMVID_ANY,
+ connection_id, 0, msg, msg_len, msg_vid, msg_subtype);
+}
+
+/**
+ * Called by the IMC when an IMC-IMV message is to be sent over IF-TNCCS 2.0
+ */
+TNC_Result TNC_TNCC_SendMessageLong(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 imv_id)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->send_message(tnc->tnccs, imc_id, imv_id, connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype);
+}
+
+/**
+ * Called by the IMC to get the value of an attribute associated with a
+ * connection or with the TNCC as a whole.
+ */
+TNC_Result TNC_TNCC_GetAttribute(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *out_value_len)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring GetAttribute() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->get_attribute(tnc->tnccs, TRUE, imc_id, connection_id,
+ attribute_id, buffer_len, buffer, out_value_len);
+}
+
+/**
+ * Called by the IMC to set the value of an attribute associated with a
+ * connection or with the TNCC as a whole.
+ */
+TNC_Result TNC_TNCC_SetAttribute(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring SetAttribute() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->set_attribute(tnc->tnccs, TRUE, imc_id, connection_id,
+ attribute_id, buffer_len, buffer);
+}
+
+/**
+ * Called by the IMC when it wants to reserve an additional IMC ID for itself
+ */
+TNC_Result TNC_TNCC_ReserveAdditionalIMCID(TNC_IMCID imc_id, TNC_UInt32 *new_id)
+{
+ if (tnc->imcs->reserve_id(tnc->imcs, imc_id, new_id))
+ {
+ return TNC_RESULT_SUCCESS;
+ }
+ DBG1(DBG_TNC, "ignoring ReserveAdditionalIMCID() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+}
+
+/**
+ * Called by the IMC when it needs a function pointer
+ */
+TNC_Result TNC_TNCC_BindFunction(TNC_IMCID id,
+ char *function_name,
+ void **function_pointer)
+{
+ if (streq(function_name, "TNC_TNCC_ReportMessageTypes"))
+ {
+ *function_pointer = (void*)TNC_TNCC_ReportMessageTypes;
+ }
+ else if (streq(function_name, "TNC_TNCC_ReportMessageTypesLong"))
+ {
+ *function_pointer = (void*)TNC_TNCC_ReportMessageTypesLong;
+ }
+ else if (streq(function_name, "TNC_TNCC_RequestHandshakeRetry"))
+ {
+ *function_pointer = (void*)TNC_TNCC_RequestHandshakeRetry;
+ }
+ else if (streq(function_name, "TNC_TNCC_SendMessage"))
+ {
+ *function_pointer = (void*)TNC_TNCC_SendMessage;
+ }
+ else if (streq(function_name, "TNC_TNCC_SendMessageLong"))
+ {
+ *function_pointer = (void*)TNC_TNCC_SendMessageLong;
+ }
+ else if (streq(function_name, "TNC_TNCC_GetAttribute"))
+ {
+ *function_pointer = (void*)TNC_TNCC_GetAttribute;
+ }
+ else if (streq(function_name, "TNC_TNCC_SetAttribute"))
+ {
+ *function_pointer = (void*)TNC_TNCC_SetAttribute;
+ }
+ else if (streq(function_name, "TNC_TNCC_ReserveAdditionalIMCID"))
+ {
+ *function_pointer = (void*)TNC_TNCC_ReserveAdditionalIMCID;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return TNC_RESULT_SUCCESS;
+}
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c
new file mode 100644
index 000000000..311598fa9
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2006 Mike McCauley
+ * Copyright (C) 2010-2011 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 "tnc_imc_manager.h"
+#include "tnc_imc.h"
+
+#include <tncifimc.h>
+
+#include <utils/debug.h>
+#include <threading/rwlock.h>
+#include <threading/mutex.h>
+#include <collections/linked_list.h>
+
+typedef struct private_tnc_imc_manager_t private_tnc_imc_manager_t;
+
+/**
+ * Private data of an imc_manager_t object.
+ */
+struct private_tnc_imc_manager_t {
+
+ /**
+ * Public members of imc_manager_t.
+ */
+ imc_manager_t public;
+
+ /**
+ * Linked list of IMCs
+ */
+ linked_list_t *imcs;
+
+ /**
+ * Lock to access IMC list
+ */
+ rwlock_t *lock;
+
+ /**
+ * Next IMC ID to be assigned
+ */
+ TNC_IMCID next_imc_id;
+
+ /**
+ * Mutex to access next IMC ID
+ */
+ mutex_t *id_mutex;
+};
+
+METHOD(imc_manager_t, add, bool,
+ private_tnc_imc_manager_t *this, imc_t *imc)
+{
+ TNC_Version version;
+ TNC_IMCID imc_id;
+
+ this->id_mutex->lock(this->id_mutex);
+ imc_id = this->next_imc_id++;
+ this->id_mutex->unlock(this->id_mutex);
+
+ imc->set_id(imc, imc_id);
+ if (imc->initialize(imc_id, TNC_IFIMC_VERSION_1,
+ TNC_IFIMC_VERSION_1, &version) != TNC_RESULT_SUCCESS)
+ {
+ DBG1(DBG_TNC, "IMC \"%s\" failed to initialize", imc->get_name(imc));
+ return FALSE;
+ }
+ this->lock->write_lock(this->lock);
+ this->imcs->insert_last(this->imcs, imc);
+ this->lock->unlock(this->lock);
+
+ if (imc->provide_bind_function(imc->get_id(imc),
+ TNC_TNCC_BindFunction) != TNC_RESULT_SUCCESS)
+ {
+ if (imc->terminate)
+ {
+ imc->terminate(imc->get_id(imc));
+ }
+ DBG1(DBG_TNC, "IMC \"%s\" failed to obtain bind function",
+ imc->get_name(imc));
+ this->lock->write_lock(this->lock);
+ this->imcs->remove_last(this->imcs, (void**)&imc);
+ this->lock->unlock(this->lock);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(imc_manager_t, remove_, imc_t*,
+ private_tnc_imc_manager_t *this, TNC_IMCID id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc, *removed_imc = NULL;
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (id == imc->get_id(imc))
+ {
+ this->imcs->remove_at(this->imcs, enumerator);
+ removed_imc = imc;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return removed_imc;
+}
+
+METHOD(imc_manager_t, load, bool,
+ private_tnc_imc_manager_t *this, char *name, char *path)
+{
+ imc_t *imc;
+
+ imc = tnc_imc_create(name, path);
+ if (!imc)
+ {
+ return FALSE;
+ }
+ if (!add(this, imc))
+ {
+ imc->destroy(imc);
+ return FALSE;
+ }
+ DBG1(DBG_TNC, "IMC %u \"%s\" loaded from '%s'", imc->get_id(imc), name, path);
+ return TRUE;
+}
+
+METHOD(imc_manager_t, load_from_functions, bool,
+ private_tnc_imc_manager_t *this, char *name,
+ TNC_IMC_InitializePointer initialize,
+ TNC_IMC_NotifyConnectionChangePointer notify_connection_change,
+ TNC_IMC_BeginHandshakePointer begin_handshake,
+ TNC_IMC_ReceiveMessagePointer receive_message,
+ TNC_IMC_ReceiveMessageLongPointer receive_message_long,
+ TNC_IMC_BatchEndingPointer batch_ending,
+ TNC_IMC_TerminatePointer terminate,
+ TNC_IMC_ProvideBindFunctionPointer provide_bind_function)
+{
+ imc_t *imc;
+
+ imc = tnc_imc_create_from_functions(name,
+ initialize, notify_connection_change,
+ begin_handshake, receive_message,
+ receive_message_long, batch_ending,
+ terminate, provide_bind_function);
+ if (!imc)
+ {
+ return FALSE;
+ }
+ if (!add(this, imc))
+ {
+ imc->destroy(imc);
+ return FALSE;
+ }
+ DBG1(DBG_TNC, "IMC %u \"%s\" loaded", imc->get_id(imc), name);
+ return TRUE;
+}
+
+METHOD(imc_manager_t, is_registered, bool,
+ private_tnc_imc_manager_t *this, TNC_IMCID id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ bool found = FALSE;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (imc->has_id(imc, id))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return found;
+}
+
+METHOD(imc_manager_t, reserve_id, bool,
+ private_tnc_imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ bool found = FALSE;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (id == imc->get_id(imc))
+ {
+ found = TRUE;
+ this->id_mutex->lock(this->id_mutex);
+ *new_id = this->next_imc_id++;
+ this->id_mutex->unlock(this->id_mutex);
+ imc->add_id(imc, *new_id);
+ DBG2(DBG_TNC, "additional ID %u reserved for IMC with primary ID %u",
+ *new_id, id);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return found;
+}
+
+METHOD(imc_manager_t, get_preferred_language, char*,
+ private_tnc_imc_manager_t *this)
+{
+ return lib->settings->get_str(lib->settings,
+ "libtnccs.plugins.tnc-imc.preferred_language", "en");
+}
+
+METHOD(imc_manager_t, notify_connection_change, void,
+ private_tnc_imc_manager_t *this, TNC_ConnectionID id,
+ TNC_ConnectionState state)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (imc->notify_connection_change)
+ {
+ imc->notify_connection_change(imc->get_id(imc), id, state);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(imc_manager_t, begin_handshake, void,
+ private_tnc_imc_manager_t *this, TNC_ConnectionID id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ imc->begin_handshake(imc->get_id(imc), id);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(imc_manager_t, set_message_types, TNC_Result,
+ private_tnc_imc_manager_t *this, TNC_IMCID id,
+ TNC_MessageTypeList supported_types,
+ TNC_UInt32 type_count)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ TNC_Result result = TNC_RESULT_FATAL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (id == imc->get_id(imc))
+ {
+ imc->set_message_types(imc, supported_types, type_count);
+ result = TNC_RESULT_SUCCESS;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return result;
+}
+
+METHOD(imc_manager_t, set_message_types_long, TNC_Result,
+ private_tnc_imc_manager_t *this, TNC_IMCID id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ TNC_Result result = TNC_RESULT_FATAL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (id == imc->get_id(imc))
+ {
+ imc->set_message_types_long(imc, supported_vids, supported_subtypes,
+ type_count);
+ result = TNC_RESULT_SUCCESS;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return result;
+}
+
+METHOD(imc_manager_t, receive_message, void,
+ private_tnc_imc_manager_t *this, TNC_ConnectionID connection_id,
+ bool excl,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id,
+ TNC_UInt32 dst_imc_id)
+{
+ bool type_supported = FALSE;
+ TNC_MessageType msg_type;
+ TNC_UInt32 msg_flags;
+ enumerator_t *enumerator;
+ imc_t *imc;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (imc->type_supported(imc, msg_vid, msg_subtype) &&
+ (!excl || (excl && imc->has_id(imc, dst_imc_id))))
+ {
+ if (imc->receive_message_long && src_imv_id)
+ {
+ type_supported = TRUE;
+ msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
+ imc->receive_message_long(imc->get_id(imc), connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype,
+ src_imv_id, dst_imc_id);
+
+ }
+ else if (imc->receive_message && msg_vid <= TNC_VENDORID_ANY &&
+ msg_subtype <= TNC_SUBTYPE_ANY)
+ {
+ type_supported = TRUE;
+ msg_type = (msg_vid << 8) | msg_subtype;
+ imc->receive_message(imc->get_id(imc), connection_id,
+ msg, msg_len, msg_type);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ if (!type_supported)
+ {
+ DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMC",
+ msg_vid, msg_subtype);
+ }
+}
+
+METHOD(imc_manager_t, batch_ending, void,
+ private_tnc_imc_manager_t *this, TNC_ConnectionID id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (imc->batch_ending)
+ {
+ imc->batch_ending(imc->get_id(imc), id);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(imc_manager_t, destroy, void,
+ private_tnc_imc_manager_t *this)
+{
+ imc_t *imc;
+
+ while (this->imcs->remove_last(this->imcs, (void**)&imc) == SUCCESS)
+ {
+ if (imc->terminate &&
+ imc->terminate(imc->get_id(imc)) != TNC_RESULT_SUCCESS)
+ {
+ DBG1(DBG_TNC, "IMC \"%s\" not terminated successfully",
+ imc->get_name(imc));
+ }
+ imc->destroy(imc);
+ }
+ this->imcs->destroy(this->imcs);
+ this->lock->destroy(this->lock);
+ this->id_mutex->destroy(this->id_mutex);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+imc_manager_t* tnc_imc_manager_create(void)
+{
+ private_tnc_imc_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .remove = _remove_, /* avoid name conflict with stdio.h */
+ .load = _load,
+ .load_from_functions = _load_from_functions,
+ .is_registered = _is_registered,
+ .reserve_id = _reserve_id,
+ .get_preferred_language = _get_preferred_language,
+ .notify_connection_change = _notify_connection_change,
+ .begin_handshake = _begin_handshake,
+ .set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
+ .receive_message = _receive_message,
+ .batch_ending = _batch_ending,
+ .destroy = _destroy,
+ },
+ .imcs = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .id_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .next_imc_id = 1,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.h b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.h
new file mode 100644
index 000000000..ed490293b
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * @defgroup tnc_imc_manager tnc_imc_manager
+ * @{ @ingroup tnc_imc
+ */
+
+#ifndef TNC_IMC_MANAGER_H_
+#define TNC_IMC_MANAGER_H_
+
+#include <tnc/imc/imc_manager.h>
+
+/**
+ * Create an IMC manager instance.
+ */
+imc_manager_t *tnc_imc_manager_create();
+
+#endif /** TNC_IMC_MANAGER_H_ @}*/
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c
new file mode 100644
index 000000000..859dded79
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010-2011 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 "tnc_imc_plugin.h"
+#include "tnc_imc_manager.h"
+
+#include <tnc/tnc.h>
+
+typedef struct private_tnc_imc_plugin_t private_tnc_imc_plugin_t;
+
+/**
+ * Private data of a tnc_imc_plugin_t object.
+ */
+struct private_tnc_imc_plugin_t {
+
+ /**
+ * Public interface.
+ */
+ tnc_imc_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_tnc_imc_plugin_t *this)
+{
+ return "tnc-imc";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_tnc_imc_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(tnc_manager_register, tnc_imc_manager_create),
+ PLUGIN_PROVIDE(CUSTOM, "imc-manager"),
+ PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_X509),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_tnc_imc_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnc_imc_plugin_create(void)
+{
+ private_tnc_imc_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
+
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h
new file mode 100644
index 000000000..8c5521cb2
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnc_imc tnc_imc
+ * @ingroup cplugins
+ *
+ * @defgroup tnc_imc_plugin tnc_imc_plugin
+ * @{ @ingroup tnc_imc
+ */
+
+#ifndef TNC_IMC_PLUGIN_H_
+#define TNC_IMC_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnc_imc_plugin_t tnc_imc_plugin_t;
+
+/**
+ * TNC IMC plugin
+ */
+struct tnc_imc_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNC_IMC_PLUGIN_H_ @}*/
diff --git a/src/libtnccs/plugins/tnc_tnccs/Makefile.am b/src/libtnccs/plugins/tnc_tnccs/Makefile.am
new file mode 100644
index 000000000..f16bf8e1b
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_tnccs/Makefile.am
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtls \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtnccs
+
+AM_CFLAGS = \
+ -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnc-tnccs.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnc-tnccs.la
+libstrongswan_tnc_tnccs_la_LIBADD = \
+ $(top_builddir)/src/libtncif/libtncif.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnc_tnccs_la_SOURCES = \
+ tnc_tnccs_plugin.h tnc_tnccs_plugin.c \
+ tnc_tnccs_manager.h tnc_tnccs_manager.c
+
+libstrongswan_tnc_tnccs_la_LDFLAGS = -module -avoid-version
diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c
new file mode 100644
index 000000000..60f6bc3c1
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c
@@ -0,0 +1,866 @@
+/*
+ * Copyright (C) 2010-2013 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.
+ */
+
+#define _GNU_SOURCE /* for asprintf() */
+
+#include "tnc_tnccs_manager.h"
+
+#include <tnc/tnc.h>
+#include <tnc/imv/imv_manager.h>
+#include <tnc/imc/imc_manager.h>
+#include <tnc/imv/imv_manager.h>
+
+#include <tncif_identity.h>
+
+#include <tls.h>
+
+#include <utils/debug.h>
+#include <pen/pen.h>
+#include <bio/bio_writer.h>
+#include <collections/linked_list.h>
+#include <threading/rwlock.h>
+
+#include <stdio.h>
+
+typedef struct private_tnc_tnccs_manager_t private_tnc_tnccs_manager_t;
+typedef struct tnccs_entry_t tnccs_entry_t;
+typedef struct tnccs_connection_entry_t tnccs_connection_entry_t;
+
+/**
+ * TNCCS constructor entry
+ */
+struct tnccs_entry_t {
+
+ /**
+ * TNCCS protocol type
+ */
+ tnccs_type_t type;
+
+ /**
+ * constructor function to create instance
+ */
+ tnccs_constructor_t constructor;
+};
+
+/**
+ * TNCCS connection entry
+ */
+struct tnccs_connection_entry_t {
+
+ /**
+ * TNCCS connection ID
+ */
+ TNC_ConnectionID id;
+
+ /**
+ * TNCCS protocol type
+ */
+ tnccs_type_t type;
+
+ /**
+ * TNCCS instance
+ */
+ tnccs_t *tnccs;
+
+ /**
+ * TNCCS send message function
+ */
+ tnccs_send_message_t send_message;
+
+ /**
+ * TNCCS request handshake retry flag
+ */
+ bool *request_handshake_retry;
+
+ /**
+ * Maximum size of a PA-TNC message
+ */
+ u_int32_t max_msg_len;
+
+ /**
+ * collection of IMV recommendations
+ */
+ recommendations_t *recs;
+};
+
+/**
+ * private data of tnc_tnccs_manager
+ */
+struct private_tnc_tnccs_manager_t {
+
+ /**
+ * public functions
+ */
+ tnccs_manager_t public;
+
+ /**
+ * list of TNCCS protocol entries
+ */
+ linked_list_t *protocols;
+
+ /**
+ * rwlock to lock the TNCCS protocol entries
+ */
+ rwlock_t *protocol_lock;
+
+ /**
+ * connection ID counter
+ */
+ TNC_ConnectionID connection_id;
+
+ /**
+ * list of TNCCS connection entries
+ */
+ linked_list_t *connections;
+
+ /**
+ * rwlock to lock TNCCS connection entries
+ */
+ rwlock_t *connection_lock;
+
+};
+
+METHOD(tnccs_manager_t, add_method, void,
+ private_tnc_tnccs_manager_t *this, tnccs_type_t type,
+ tnccs_constructor_t constructor)
+{
+ tnccs_entry_t *entry;
+
+ entry = malloc_thing(tnccs_entry_t);
+ entry->type = type;
+ entry->constructor = constructor;
+
+ this->protocol_lock->write_lock(this->protocol_lock);
+ this->protocols->insert_last(this->protocols, entry);
+ this->protocol_lock->unlock(this->protocol_lock);
+}
+
+METHOD(tnccs_manager_t, remove_method, void,
+ private_tnc_tnccs_manager_t *this, tnccs_constructor_t constructor)
+{
+ enumerator_t *enumerator;
+ tnccs_entry_t *entry;
+
+ this->protocol_lock->write_lock(this->protocol_lock);
+ enumerator = this->protocols->create_enumerator(this->protocols);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (constructor == entry->constructor)
+ {
+ this->protocols->remove_at(this->protocols, enumerator);
+ free(entry);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->protocol_lock->unlock(this->protocol_lock);
+}
+
+METHOD(tnccs_manager_t, create_instance, tnccs_t*,
+ private_tnc_tnccs_manager_t *this, tnccs_type_t type, bool is_server,
+ identification_t *server, identification_t *peer,
+ tnc_ift_type_t transport)
+{
+ enumerator_t *enumerator;
+ tnccs_entry_t *entry;
+ tnccs_t *protocol = NULL;
+
+ this->protocol_lock->read_lock(this->protocol_lock);
+ enumerator = this->protocols->create_enumerator(this->protocols);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (type == entry->type)
+ {
+ protocol = entry->constructor(is_server, server, peer, transport);
+ if (protocol)
+ {
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->protocol_lock->unlock(this->protocol_lock);
+
+ return protocol;
+}
+
+METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
+ private_tnc_tnccs_manager_t *this, tnccs_type_t type, tnccs_t *tnccs,
+ tnccs_send_message_t send_message, bool* request_handshake_retry,
+ u_int32_t max_msg_len, recommendations_t **recs)
+{
+ tnccs_connection_entry_t *entry;
+
+ entry = malloc_thing(tnccs_connection_entry_t);
+ entry->type = type;
+ entry->tnccs = tnccs;
+ entry->send_message = send_message;
+ entry->request_handshake_retry = request_handshake_retry;
+ entry->max_msg_len = max_msg_len;
+ if (recs)
+ {
+ /* we assume a TNC Server needing recommendations from IMVs */
+ if (!tnc->imvs)
+ {
+ DBG1(DBG_TNC, "no IMV manager available!");
+ free(entry);
+ return 0;
+ }
+ entry->recs = tnc->imvs->create_recommendations(tnc->imvs);
+ *recs = entry->recs;
+ }
+ else
+ {
+ /* we assume a TNC Client */
+ if (!tnc->imcs)
+ {
+ DBG1(DBG_TNC, "no IMC manager available!");
+ free(entry);
+ return 0;
+ }
+ entry->recs = NULL;
+ }
+ this->connection_lock->write_lock(this->connection_lock);
+ entry->id = ++this->connection_id;
+ this->connections->insert_last(this->connections, entry);
+ this->connection_lock->unlock(this->connection_lock);
+
+ DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
+ return entry->id;
+}
+
+METHOD(tnccs_manager_t, remove_connection, void,
+ private_tnc_tnccs_manager_t *this, TNC_ConnectionID id, bool is_server)
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+
+ if (is_server)
+ {
+ if (tnc->imvs)
+ {
+ tnc->imvs->notify_connection_change(tnc->imvs, id,
+ TNC_CONNECTION_STATE_DELETE);
+ }
+ }
+ else
+ {
+ if (tnc->imcs)
+ {
+ tnc->imcs->notify_connection_change(tnc->imcs, id,
+ TNC_CONNECTION_STATE_DELETE);
+ }
+ }
+
+ this->connection_lock->write_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == entry->id)
+ {
+ this->connections->remove_at(this->connections, enumerator);
+ if (entry->recs)
+ {
+ entry->recs->destroy(entry->recs);
+ }
+ free(entry);
+ DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+}
+
+METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result,
+ private_tnc_tnccs_manager_t *this, bool is_imc, TNC_UInt32 imcv_id,
+ TNC_ConnectionID id,
+ TNC_RetryReason reason)
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+
+ if (id == TNC_CONNECTIONID_ANY)
+ {
+ DBG2(DBG_TNC, "%s %u requests handshake retry for all connections "
+ "(reason: %u)", is_imc ? "IMC":"IMV", reason);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "%s %u requests handshake retry for Connection ID %u "
+ "(reason: %u)", is_imc ? "IMC":"IMV", imcv_id, id, reason);
+ }
+ this->connection_lock->read_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == TNC_CONNECTIONID_ANY || id == entry->id)
+ {
+ *entry->request_handshake_retry = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+
+ return TNC_RESULT_SUCCESS;
+}
+
+METHOD(tnccs_manager_t, send_message, TNC_Result,
+ private_tnc_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
+ TNC_ConnectionID id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
+
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+ tnccs_send_message_t send_message = NULL;
+ tnccs_t *tnccs = NULL;
+
+ if (msg_vid == TNC_VENDORID_ANY || msg_subtype == TNC_SUBTYPE_ANY)
+ {
+ DBG1(DBG_TNC, "not sending message of invalid type 0x%02x/0x%08x",
+ msg_vid, msg_subtype);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+
+ this->connection_lock->read_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == entry->id)
+ {
+ tnccs = entry->tnccs;
+ send_message = entry->send_message;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+
+ if (tnccs && send_message)
+ {
+ return send_message(tnccs, imc_id, imv_id, msg_flags, msg, msg_len,
+ msg_vid, msg_subtype);
+ }
+ return TNC_RESULT_FATAL;
+}
+
+METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
+ private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id,
+ TNC_ConnectionID id,
+ TNC_IMV_Action_Recommendation rec,
+ TNC_IMV_Evaluation_Result eval)
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+ recommendations_t *recs = NULL;
+
+ this->connection_lock->read_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == entry->id)
+ {
+ recs = entry->recs;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+
+ if (recs)
+ {
+ recs->provide_recommendation(recs, imv_id, rec, eval);
+ return TNC_RESULT_SUCCESS;
+ }
+ return TNC_RESULT_FATAL;
+}
+
+/**
+ * Write the value of a boolean attribute into the buffer
+ */
+static TNC_Result bool_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ bool value)
+{
+ *value_len = 1;
+
+ if (buffer && buffer_len > 0)
+ {
+ *buffer = value ? 0x01 : 0x00;
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+/**
+ * Write the value of an u_int32_t attribute into the buffer
+ */
+static TNC_Result uint_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ u_int32_t value)
+{
+ *value_len = sizeof(u_int32_t);
+
+ if (buffer && buffer_len >= *value_len)
+ {
+ htoun32(buffer, value);
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+/**
+ * Write the value of string attribute into the buffer
+ */
+static TNC_Result str_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ char *value)
+{
+ *value_len = 1 + strlen(value);
+
+ if (buffer && buffer_len >= *value_len)
+ {
+ snprintf(buffer, buffer_len, "%s", value);
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+/**
+ * Write the value of a TNC identity list into the buffer
+ */
+static TNC_Result identity_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ linked_list_t *list)
+{
+ bio_writer_t *writer;
+ enumerator_t *enumerator;
+ u_int32_t count;
+ chunk_t value;
+ tncif_identity_t *tnc_id;
+ TNC_Result result = TNC_RESULT_INVALID_PARAMETER;
+
+ count = list->get_count(list);
+ writer = bio_writer_create(4 + TNCIF_IDENTITY_MIN_SIZE * count);
+ writer->write_uint32(writer, count);
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &tnc_id))
+ {
+ tnc_id->build(tnc_id, writer);
+ }
+ enumerator->destroy(enumerator);
+
+ value = writer->get_buf(writer);
+ *value_len = value.len;
+ if (buffer && buffer_len >= value.len)
+ {
+ memcpy(buffer, value.ptr, value.len);
+ result = TNC_RESULT_SUCCESS;
+ }
+ writer->destroy(writer);
+
+ return result;
+}
+
+METHOD(tnccs_manager_t, get_attribute, TNC_Result,
+ private_tnc_tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
+ TNC_ConnectionID id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len)
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+ bool attribute_match = FALSE, entry_found = FALSE;
+
+ if (is_imc)
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are unsupported */
+ case TNC_ATTRIBUTEID_SOHR:
+ case TNC_ATTRIBUTEID_SSOHR:
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PRIMARY_IMC_ID:
+ attribute_match = TRUE;
+ break;
+
+ /* these attributes are yet to be matched */
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are unsupported or invalid */
+ case TNC_ATTRIBUTEID_REASON_STRING:
+ case TNC_ATTRIBUTEID_REASON_LANGUAGE:
+ case TNC_ATTRIBUTEID_SOH:
+ case TNC_ATTRIBUTEID_SSOH:
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PRIMARY_IMV_ID:
+ case TNC_ATTRIBUTEID_AR_IDENTITIES:
+ attribute_match = TRUE;
+ break;
+
+ /* these attributes are yet to be matched */
+ default:
+ break;
+ }
+ }
+
+ if (!attribute_match)
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
+ case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
+ case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
+ case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
+ case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
+ case TNC_ATTRIBUTEID_HAS_SOH:
+ case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
+ case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
+ case TNC_ATTRIBUTEID_IFT_PROTOCOL:
+ case TNC_ATTRIBUTEID_IFT_VERSION:
+ break;
+
+ /* these attributes are unsupported or unknown */
+ case TNC_ATTRIBUTEID_DHPN:
+ case TNC_ATTRIBUTEID_TLS_UNIQUE:
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ }
+
+ /* attributes specific to the TNCC or TNCS are unsupported */
+ if (id == TNC_CONNECTIONID_ANY)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+
+ this->connection_lock->read_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == entry->id)
+ {
+ entry_found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+
+ if (!entry_found)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+
+ switch (attribute_id)
+ {
+ case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
+ {
+ recommendations_t *recs;
+ chunk_t pref_lang;
+
+ recs = entry->recs;
+ if (!recs)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ pref_lang = recs->get_preferred_language(recs);
+ if (pref_lang.len == 0)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ *value_len = pref_lang.len;
+ if (buffer && buffer_len >= pref_lang.len)
+ {
+ memcpy(buffer, pref_lang.ptr, pref_lang.len);
+ }
+ return TNC_RESULT_SUCCESS;
+ }
+ case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
+ return uint_attribute(buffer_len, buffer, value_len,
+ 0xffffffff);
+ case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
+ return uint_attribute(buffer_len, buffer, value_len,
+ entry->max_msg_len);
+ case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
+ case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
+ return bool_attribute(buffer_len, buffer, value_len,
+ entry->type == TNCCS_2_0);
+ case TNC_ATTRIBUTEID_HAS_SOH:
+ return bool_attribute(buffer_len, buffer, value_len,
+ entry->type == TNCCS_SOH);
+ case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
+ {
+ char *protocol;
+
+ switch (entry->type)
+ {
+ case TNCCS_1_1:
+ case TNCCS_2_0:
+ protocol = "IF-TNCCS";
+ break;
+ case TNCCS_SOH:
+ protocol = "IF-TNCCS-SOH";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, protocol);
+ }
+ case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
+ {
+ char *version;
+
+ switch (entry->type)
+ {
+ case TNCCS_1_1:
+ version = "1.1";
+ break;
+ case TNCCS_2_0:
+ version = "2.0";
+ break;
+ case TNCCS_SOH:
+ version = "1.0";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, version);
+ }
+ case TNC_ATTRIBUTEID_IFT_PROTOCOL:
+ {
+ char *protocol;
+
+ switch (entry->tnccs->get_transport(entry->tnccs))
+ {
+ case TNC_IFT_EAP_1_0:
+ case TNC_IFT_EAP_1_1:
+ case TNC_IFT_EAP_2_0:
+ protocol = "IF-T for Tunneled EAP";
+ break;
+ case TNC_IFT_TLS_1_0:
+ case TNC_IFT_TLS_2_0:
+ protocol = "IF-T for TLS";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, protocol);
+ }
+ case TNC_ATTRIBUTEID_IFT_VERSION:
+ {
+ char *version;
+
+ switch (entry->tnccs->get_transport(entry->tnccs))
+ {
+ case TNC_IFT_EAP_1_0:
+ case TNC_IFT_TLS_1_0:
+ version = "1.0";
+ break;
+ case TNC_IFT_EAP_1_1:
+ version = "1.1";
+ break;
+ case TNC_IFT_EAP_2_0:
+ case TNC_IFT_TLS_2_0:
+ version = "2.0";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, version);
+ }
+ case TNC_ATTRIBUTEID_AR_IDENTITIES:
+ {
+ linked_list_t *list;
+ identification_t *peer;
+ tnccs_t *tnccs;
+ tncif_identity_t *tnc_id;
+ u_int32_t id_type, subject_type;
+ chunk_t id_value;
+ char *id_str;
+ TNC_Result result;
+
+ list = linked_list_create();
+ tnccs = entry->tnccs;
+ peer = tnccs->tls.get_peer_id(&tnccs->tls);
+ if (peer)
+ {
+ switch (peer->get_type(peer))
+ {
+ case ID_IPV4_ADDR:
+ id_type = TNC_ID_IPV4_ADDR;
+ subject_type = TNC_SUBJECT_MACHINE;
+ break;
+ case ID_IPV6_ADDR:
+ id_type = TNC_ID_IPV6_ADDR;
+ subject_type = TNC_SUBJECT_MACHINE;
+ break;
+ case ID_FQDN:
+ id_type = TNC_ID_USERNAME;
+ subject_type = TNC_SUBJECT_USER;
+ break;
+ case ID_RFC822_ADDR:
+ id_type = TNC_ID_EMAIL_ADDR;
+ subject_type = TNC_SUBJECT_USER;
+ break;
+ case ID_DER_ASN1_DN:
+ id_type = TNC_ID_X500_DN;
+ subject_type = TNC_SUBJECT_USER;
+ break;
+ default:
+ id_type = TNC_ID_UNKNOWN;
+ subject_type = TNC_SUBJECT_UNKNOWN;
+ }
+ if (id_type != TNC_ID_UNKNOWN &&
+ asprintf(&id_str, "%Y", peer) >= 0)
+ {
+ id_value = chunk_from_str(id_str);
+ tnc_id = tncif_identity_create(
+ pen_type_create(PEN_TCG, id_type), id_value,
+ pen_type_create(PEN_TCG, subject_type),
+ pen_type_create(PEN_TCG,
+ tnccs->get_auth_type(tnccs)));
+ list->insert_last(list, tnc_id);
+ }
+ }
+ result = identity_attribute(buffer_len, buffer, value_len, list);
+ list->destroy_offset(list, offsetof(tncif_identity_t, destroy));
+ return result;
+ }
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+METHOD(tnccs_manager_t, set_attribute, TNC_Result,
+ private_tnc_tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
+ TNC_ConnectionID id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer)
+{
+ enumerator_t *enumerator;
+ tnccs_connection_entry_t *entry;
+ recommendations_t *recs = NULL;
+
+ if (is_imc || id == TNC_CONNECTIONID_ANY ||
+ (attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
+ attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+
+ this->connection_lock->read_lock(this->connection_lock);
+ enumerator = this->connections->create_enumerator(this->connections);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (id == entry->id)
+ {
+ recs = entry->recs;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->connection_lock->unlock(this->connection_lock);
+
+ if (recs)
+ {
+ chunk_t attribute = { buffer, buffer_len };
+
+ if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
+ {
+ return recs->set_reason_string(recs, imcv_id, attribute);
+ }
+ else
+ {
+ return recs->set_reason_language(recs, imcv_id, attribute);
+ }
+ }
+ return TNC_RESULT_INVALID_PARAMETER;
+}
+
+METHOD(tnccs_manager_t, destroy, void,
+ private_tnc_tnccs_manager_t *this)
+{
+ this->protocols->destroy_function(this->protocols, free);
+ this->protocol_lock->destroy(this->protocol_lock);
+ this->connections->destroy_function(this->connections, free);
+ this->connection_lock->destroy(this->connection_lock);
+ free(this);
+}
+
+/*
+ * See header
+ */
+tnccs_manager_t *tnc_tnccs_manager_create()
+{
+ private_tnc_tnccs_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add_method = _add_method,
+ .remove_method = _remove_method,
+ .create_instance = _create_instance,
+ .create_connection = _create_connection,
+ .remove_connection = _remove_connection,
+ .request_handshake_retry = _request_handshake_retry,
+ .send_message = _send_message,
+ .provide_recommendation = _provide_recommendation,
+ .get_attribute = _get_attribute,
+ .set_attribute = _set_attribute,
+ .destroy = _destroy,
+ },
+ .protocols = linked_list_create(),
+ .connections = linked_list_create(),
+ .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.h b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.h
new file mode 100644
index 000000000..dd5149846
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnc_tnccs_manager tnc_tnccs_manager
+ * @{ @ingroup tnc_tnccs
+ */
+
+#ifndef TNC_TNCCS_MANAGER_H_
+#define TNC_TNCCS_MANAGER_H_
+
+#include <tnc/tnccs/tnccs_manager.h>
+
+/**
+ * Create a TNCCS manager instance.
+ */
+tnccs_manager_t *tnc_tnccs_manager_create();
+
+#endif /** TNC_TNCCS_MANAGER_H_ @}*/
diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.c b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.c
new file mode 100644
index 000000000..1e4ddc195
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.c
@@ -0,0 +1,98 @@
+/*
+ * 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 "tnc_tnccs_plugin.h"
+#include "tnc_tnccs_manager.h"
+
+#include <tnc/tnc.h>
+
+#include <utils/debug.h>
+
+typedef struct private_tnc_tnccs_plugin_t private_tnc_tnccs_plugin_t;
+
+/**
+ * Private data of a tnc_tnccs_plugin_t object.
+ */
+struct private_tnc_tnccs_plugin_t {
+
+ /**
+ * Public interface.
+ */
+ tnc_tnccs_plugin_t public;
+
+};
+
+
+METHOD(plugin_t, get_name, char*,
+ private_tnc_tnccs_plugin_t *this)
+{
+ return "tnc-tnccs";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_tnc_tnccs_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(tnc_manager_register, tnc_tnccs_manager_create),
+ PLUGIN_PROVIDE(CUSTOM, "tnccs-manager"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_tnc_tnccs_plugin_t *this)
+{
+ libtnccs_deinit();
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnc_tnccs_plugin_create(void)
+{
+ private_tnc_tnccs_plugin_t *this;
+
+ if (lib->integrity)
+ {
+ if (lib->integrity->check(lib->integrity, "libtnccs", libtnccs_init))
+ {
+ DBG1(DBG_LIB,
+ "lib 'libtnccs': passed file and segment integrity tests");
+ }
+ else
+ {
+ DBG1(DBG_LIB,
+ "lib 'libtnccs': failed integrity tests");
+ return NULL;
+ }
+ }
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ libtnccs_init();
+
+ return &this->public.plugin;
+}
+
diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h
new file mode 100644
index 000000000..f935fa462
--- /dev/null
+++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnc_tnccs tnc_tnccs
+ * @ingroup cplugins
+ *
+ * @defgroup tnc_tnccs_plugin tnc_tnccs_plugin
+ * @{ @ingroup tnc_tnccs
+ */
+
+#ifndef TNC_TNCCS_PLUGIN_H_
+#define TNC_TNCCS_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnc_tnccs_plugin_t tnc_tnccs_plugin_t;
+
+/**
+ * TNCCS manager plugin
+ */
+struct tnc_tnccs_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNC_TNCCS_PLUGIN_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/Makefile.am b/src/libtnccs/plugins/tnccs_11/Makefile.am
new file mode 100644
index 000000000..cbe0b8e19
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/Makefile.am
@@ -0,0 +1,33 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtls \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtnccs
+
+AM_CFLAGS = \
+ ${xml_CFLAGS} \
+ -rdynamic
+
+libstrongswan_tnccs_11_la_LIBADD = ${xml_LIBS}
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnccs-11.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnccs-11.la
+libstrongswan_tnccs_11_la_LIBADD += \
+ $(top_builddir)/src/libtncif/libtncif.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnccs_11_la_SOURCES = \
+ tnccs_11_plugin.h tnccs_11_plugin.c tnccs_11.h tnccs_11.c \
+ batch/tnccs_batch.h batch/tnccs_batch.c \
+ messages/tnccs_msg.h messages/tnccs_msg.c \
+ messages/imc_imv_msg.h messages/imc_imv_msg.c \
+ messages/tnccs_error_msg.h messages/tnccs_error_msg.c \
+ messages/tnccs_preferred_language_msg.h messages/tnccs_preferred_language_msg.c \
+ messages/tnccs_reason_strings_msg.h messages/tnccs_reason_strings_msg.c \
+ messages/tnccs_recommendation_msg.h messages/tnccs_recommendation_msg.c \
+ messages/tnccs_tncs_contact_info_msg.h messages/tnccs_tncs_contact_info_msg.c
+
+libstrongswan_tnccs_11_la_LDFLAGS = -module -avoid-version
diff --git a/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.c b/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.c
new file mode 100644
index 000000000..660ba179d
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_batch.h"
+#include "messages/tnccs_error_msg.h"
+
+#include <tnc/tnccs/tnccs.h>
+
+#include <collections/linked_list.h>
+#include <utils/debug.h>
+
+#include <libxml/parser.h>
+
+#define TNCCS_NS "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#"
+#define SCHEMA_NS "http://www.w3.org/2001/XMLSchema-instance"
+#define TNCCS_XSD "https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd"
+
+typedef struct private_tnccs_batch_t private_tnccs_batch_t;
+
+/**
+ * Private data of a tnccs_batch_t object.
+ *
+ */
+struct private_tnccs_batch_t {
+ /**
+ * Public tnccs_batch_t interface.
+ */
+ tnccs_batch_t public;
+
+ /**
+ * Batch ID
+ */
+ int batch_id;
+
+ /**
+ * TNCC if TRUE, TNCS if FALSE
+ */
+ bool is_server;
+
+ /**
+ * linked list of TNCCS messages
+ */
+ linked_list_t *messages;
+
+ /**
+ * linked list of TNCCS error messages
+ */
+ linked_list_t *errors;
+
+ /**
+ * XML document
+ */
+ xmlDocPtr doc;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(tnccs_batch_t, get_encoding, chunk_t,
+ private_tnccs_batch_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(tnccs_batch_t, add_msg, void,
+ private_tnccs_batch_t *this, tnccs_msg_t* msg)
+{
+ xmlNodePtr root;
+
+ DBG2(DBG_TNC, "adding %N message", tnccs_msg_type_names,
+ msg->get_type(msg));
+ this->messages->insert_last(this->messages, msg);
+ root = xmlDocGetRootElement(this->doc);
+ xmlAddChild(root, msg->get_node(msg));
+}
+
+METHOD(tnccs_batch_t, build, void,
+ private_tnccs_batch_t *this)
+{
+ xmlChar *xmlbuf;
+ int buf_size;
+
+ xmlDocDumpFormatMemory(this->doc, &xmlbuf, &buf_size, 1);
+ this->encoding = chunk_create(xmlbuf, buf_size);
+ this->encoding = chunk_clone(this->encoding);
+ xmlFree(xmlbuf);
+}
+
+METHOD(tnccs_batch_t, process, status_t,
+ private_tnccs_batch_t *this)
+{
+ tnccs_msg_t *tnccs_msg, *msg;
+ tnccs_error_type_t error_type = TNCCS_ERROR_OTHER;
+ char *error_msg, buf[BUF_LEN];
+ xmlNodePtr cur;
+ xmlNsPtr ns;
+ xmlChar *batchid, *recipient;
+ int batch_id;
+
+ this->doc = xmlParseMemory(this->encoding.ptr, this->encoding.len);
+ if (!this->doc)
+ {
+ error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ error_msg = "failed to parse XML message";
+ goto fatal;
+ }
+
+ /* check out the XML document */
+ cur = xmlDocGetRootElement(this->doc);
+ if (!cur)
+ {
+ error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ error_msg = "empty XML document";
+ goto fatal;
+ }
+
+ /* check TNCCS namespace */
+ ns = xmlSearchNsByHref(this->doc, cur, TNCCS_NS);
+ if (!ns)
+ {
+ error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ error_msg = "TNCCS namespace not found";
+ goto fatal;
+ }
+
+ /* check XML document type */
+ if (xmlStrcmp(cur->name, "TNCCS-Batch"))
+ {
+ error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ error_msg = buf;
+ snprintf(buf, BUF_LEN, "wrong XML document type '%s', expected TNCCS-Batch",
+ cur->name);
+ goto fatal;
+ }
+
+ /* check presence of BatchID property */
+ batchid = xmlGetProp(cur, "BatchId");
+ if (!batchid)
+ {
+ error_type = TNCCS_ERROR_INVALID_BATCH_ID;
+ error_msg = "BatchId is missing";
+ goto fatal;
+ }
+
+ /* check BatchID */
+ batch_id = atoi((char*)batchid);
+ xmlFree(batchid);
+ if (batch_id != this->batch_id)
+ {
+ error_type = TNCCS_ERROR_INVALID_BATCH_ID;
+ error_msg = buf;
+ snprintf(buf, BUF_LEN, "BatchId %d expected, got %d", this->batch_id,
+ batch_id);
+ goto fatal;
+ }
+
+ /* check presence of Recipient property */
+ recipient = xmlGetProp(cur, "Recipient");
+ if (!recipient)
+ {
+ error_type = TNCCS_ERROR_INVALID_RECIPIENT_TYPE;
+ error_msg = "Recipient is missing";
+ goto fatal;
+ }
+
+ /* check recipient */
+ if (!streq(recipient, this->is_server ? "TNCS" : "TNCC"))
+ {
+ error_type = TNCCS_ERROR_INVALID_RECIPIENT_TYPE;
+ error_msg = buf;
+ snprintf(buf, BUF_LEN, "message recipient expected '%s', got '%s'",
+ this->is_server ? "TNCS" : "TNCC", recipient);
+ xmlFree(recipient);
+ goto fatal;
+ }
+ xmlFree(recipient);
+
+ DBG2(DBG_TNC, "processing TNCCS Batch #%d", batch_id);
+
+ /* Now walk the tree, handling message nodes as we go */
+ for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
+ {
+ /* ignore empty or blank nodes */
+ if (xmlIsBlankNode(cur))
+ {
+ continue;
+ }
+
+ /* ignore nodes with wrong namespace */
+ if (cur->ns != ns)
+ {
+ DBG1(DBG_TNC, "ignoring message node '%s' having wrong namespace",
+ cur->name);
+ continue;
+ }
+
+ tnccs_msg = tnccs_msg_create_from_node(cur, this->errors);
+
+ /* exit if a message parsing error occurred */
+ if (this->errors->get_count(this->errors) > 0)
+ {
+ return FAILED;
+ }
+
+ /* ignore unrecognized messages */
+ if (!tnccs_msg)
+ {
+ continue;
+ }
+
+ this->messages->insert_last(this->messages, tnccs_msg);
+ }
+ return SUCCESS;
+
+fatal:
+ msg = tnccs_error_msg_create(error_type, error_msg);
+ this->errors->insert_last(this->errors, msg);
+ return FAILED;
+}
+
+METHOD(tnccs_batch_t, create_msg_enumerator, enumerator_t*,
+ private_tnccs_batch_t *this)
+{
+ return this->messages->create_enumerator(this->messages);
+}
+
+METHOD(tnccs_batch_t, create_error_enumerator, enumerator_t*,
+ private_tnccs_batch_t *this)
+{
+ return this->errors->create_enumerator(this->errors);
+}
+
+METHOD(tnccs_batch_t, destroy, void,
+ private_tnccs_batch_t *this)
+{
+ this->messages->destroy_offset(this->messages,
+ offsetof(tnccs_msg_t, destroy));
+ this->errors->destroy_offset(this->errors,
+ offsetof(tnccs_msg_t, destroy));
+ xmlFreeDoc(this->doc);
+ free(this->encoding.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+tnccs_batch_t* tnccs_batch_create(bool is_server, int batch_id)
+{
+ private_tnccs_batch_t *this;
+ xmlNodePtr n;
+ xmlNsPtr ns_xsi;
+ char buf[12];
+
+ INIT(this,
+ .public = {
+ .get_encoding = _get_encoding,
+ .add_msg = _add_msg,
+ .build = _build,
+ .process = _process,
+ .create_msg_enumerator = _create_msg_enumerator,
+ .create_error_enumerator = _create_error_enumerator,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ .messages = linked_list_create(),
+ .errors = linked_list_create(),
+ .batch_id = batch_id,
+ .doc = xmlNewDoc("1.0"),
+ );
+
+ DBG2(DBG_TNC, "creating TNCCS Batch #%d", this->batch_id);
+ n = xmlNewNode(NULL, "TNCCS-Batch");
+ xmlNewNs(n, TNCCS_NS, NULL);
+ ns_xsi = xmlNewNs(n, SCHEMA_NS, "xsi");
+ snprintf(buf, sizeof(buf), "%d", batch_id);
+ xmlNewProp(n, "BatchId", buf);
+ xmlNewProp(n, "Recipient", this->is_server ? "TNCC" : "TNCS");
+ xmlNewNsProp(n, ns_xsi, "schemaLocation", TNCCS_NS " " TNCCS_XSD);
+ xmlDocSetRootElement(this->doc, n);
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+tnccs_batch_t* tnccs_batch_create_from_data(bool is_server, int batch_id, chunk_t data)
+{
+ private_tnccs_batch_t *this;
+
+ INIT(this,
+ .public = {
+ .get_encoding = _get_encoding,
+ .add_msg = _add_msg,
+ .build = _build,
+ .process = _process,
+ .create_msg_enumerator = _create_msg_enumerator,
+ .create_error_enumerator = _create_error_enumerator,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ .batch_id = batch_id,
+ .messages = linked_list_create(),
+ .errors = linked_list_create(),
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.h b/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.h
new file mode 100644
index 000000000..25301f763
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/batch/tnccs_batch.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_batch tnccs_batch
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_BATCH_H_
+#define TNCCS_BATCH_H_
+
+typedef enum tnccs_batch_type_t tnccs_batch_type_t;
+typedef struct tnccs_batch_t tnccs_batch_t;
+
+#include "messages/tnccs_msg.h"
+
+#include <library.h>
+
+/**
+ * Interface for a TNCCS 1.x Batch.
+ */
+struct tnccs_batch_t {
+
+ /**
+ * Get the encoding of the TNCCS 1.x Batch
+ *
+ * @return encoded TNCCS 1.x batch
+ */
+ chunk_t (*get_encoding)(tnccs_batch_t *this);
+
+ /**
+ * Add TNCCS message
+ *
+ * @param msg TNCCS message to be addedd
+ */
+ void (*add_msg)(tnccs_batch_t *this, tnccs_msg_t* msg);
+
+ /**
+ * Build the TNCCS 1.x Batch
+ */
+ void (*build)(tnccs_batch_t *this);
+
+ /**
+ * Process the TNCCS 1.x Batch
+ *
+ * @return return processing status
+ */
+ status_t (*process)(tnccs_batch_t *this);
+
+ /**
+ * Enumerates over all TNCCS Messages
+ *
+ * @return return message enumerator
+ */
+ enumerator_t* (*create_msg_enumerator)(tnccs_batch_t *this);
+
+ /**
+ * Enumerates over all parsing errors
+ *
+ * @return return error enumerator
+ */
+ enumerator_t* (*create_error_enumerator)(tnccs_batch_t *this);
+
+ /**
+ * Destroys a tnccs_batch_t object.
+ */
+ void (*destroy)(tnccs_batch_t *this);
+};
+
+/**
+ * Create an empty TNCCS 1.x Batch
+ *
+ * @param is_server TRUE if server, FALSE if client
+ * @param batch_id number of the batch to be sent
+ */
+tnccs_batch_t* tnccs_batch_create(bool is_server, int batch_id);
+
+/**
+ * Create an unprocessed TNCCS 1.x Batch from data
+ *
+ * @param is_server TRUE if server, FALSE if client
+ * @param batch_id current Batch ID
+ * @param data encoded PB-TNC batch
+ */
+tnccs_batch_t* tnccs_batch_create_from_data(bool is_server, int batch_id,
+ chunk_t data);
+
+#endif /** TNCCS_BATCH_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.c b/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.c
new file mode 100644
index 000000000..f0e821c8c
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "imc_imv_msg.h"
+
+#include <tnc/tnccs/tnccs.h>
+
+#include <utils/lexparser.h>
+#include <utils/debug.h>
+
+typedef struct private_imc_imv_msg_t private_imc_imv_msg_t;
+
+#define BYTES_PER_LINE 57
+
+/**
+ * Private data of a imc_imv_msg_t object.
+ *
+ */
+struct private_imc_imv_msg_t {
+ /**
+ * Public imc_imv_msg_t interface.
+ */
+ imc_imv_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+
+ /**
+ * IMC-IMV message type
+ */
+ TNC_MessageType msg_type;
+
+ /**
+ * IMC-IMV message body
+ */
+ chunk_t msg_body;
+
+};
+
+/**
+ * Encodes message data into multiple base64-encoded lines
+ */
+static chunk_t encode_base64(chunk_t data)
+{
+ chunk_t encoding;
+ u_char *pos;
+ size_t b64_chars, b64_lines;
+
+ /* handle empty message data object */
+ if (data.len == 0)
+ {
+ encoding = chunk_alloc(1);
+ *encoding.ptr = '\0';
+ return encoding;
+ }
+
+ /* compute and allocate maximum size of base64 object */
+ b64_chars = 4 * ((data.len + 2) / 3);
+ b64_lines = (data.len + BYTES_PER_LINE - 1) / BYTES_PER_LINE;
+ encoding = chunk_alloc(b64_chars + b64_lines);
+ pos = encoding.ptr;
+
+ /* encode lines */
+ while (b64_lines--)
+ {
+ chunk_t data_line, b64_line;
+
+ data_line = chunk_create(data.ptr, min(data.len, BYTES_PER_LINE));
+ data.ptr += data_line.len;
+ data.len -= data_line.len;
+ b64_line = chunk_to_base64(data_line, pos);
+ pos += b64_line.len;
+ *pos = '\n';
+ pos++;
+ }
+ /* terminate last line with NULL character instead of newline */
+ *(pos-1) = '\0';
+
+ return encoding;
+}
+
+/**
+ * Decodes message data from multiple base64-encoded lines
+ */
+static chunk_t decode_base64(chunk_t data)
+{
+ chunk_t decoding, data_line, b64_line;
+ u_char *pos;
+
+ /* compute and allocate maximum size of decoded message data */
+ decoding = chunk_alloc(3 * ((data.len + 3) / 4));
+ pos = decoding.ptr;
+ decoding.len = 0;
+
+ while (fetchline(&data, &b64_line))
+ {
+ data_line = chunk_from_base64(b64_line, pos);
+ pos += data_line.len;
+ decoding.len += data_line.len;
+ }
+
+ return decoding;
+}
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_imc_imv_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_imc_imv_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_imc_imv_msg_t *this)
+{
+ free(this->msg_body.ptr);
+ free(this);
+}
+
+METHOD(imc_imv_msg_t, get_msg_type, TNC_MessageType,
+ private_imc_imv_msg_t *this)
+{
+ return this->msg_type;
+}
+
+METHOD(imc_imv_msg_t, get_msg_body, chunk_t,
+ private_imc_imv_msg_t *this)
+{
+ return this->msg_body;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *imc_imv_msg_create_from_node(xmlNodePtr node, linked_list_t *errors)
+{
+ private_imc_imv_msg_t *this;
+ xmlNsPtr ns;
+ xmlNodePtr cur;
+ xmlChar *content;
+ chunk_t b64_body;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_msg_type = _get_msg_type,
+ .get_msg_body = _get_msg_body,
+ },
+ .type = IMC_IMV_MSG,
+ .node = node,
+ );
+
+ ns = node->ns;
+ cur = node->xmlChildrenNode;
+ while (cur)
+ {
+ if (streq(cur->name, "Type") && cur->ns == ns)
+ {
+ content = xmlNodeGetContent(cur);
+ this->msg_type = strtoul(content, NULL, 16);
+ xmlFree(content);
+ }
+ else if (streq(cur->name, "Base64") && cur->ns == ns)
+ {
+ content = xmlNodeGetContent(cur);
+ b64_body = chunk_create(content, strlen(content));
+ this->msg_body = decode_base64(b64_body);
+ xmlFree(content);
+ }
+ cur = cur->next;
+ }
+
+ return &this->public.tnccs_msg_interface;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *imc_imv_msg_create(TNC_MessageType msg_type, chunk_t msg_body)
+{
+ private_imc_imv_msg_t *this;
+ chunk_t b64_body;
+ char buf[10]; /* big enough for hex-encoded message type */
+ xmlNodePtr n;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_msg_type = _get_msg_type,
+ .get_msg_body = _get_msg_body,
+ },
+ .type = IMC_IMV_MSG,
+ .node = xmlNewNode(NULL, "IMC-IMV-Message"),
+ .msg_type = msg_type,
+ .msg_body = chunk_clone(msg_body),
+ );
+
+ /* add the message type number in hex */
+ n = xmlNewNode(NULL, "Type");
+ snprintf(buf, 10, "%08x", this->msg_type);
+ xmlNodeSetContent(n, buf);
+ xmlAddChild(this->node, n);
+
+ /* encode the message as a Base64 node */
+ n = xmlNewNode(NULL, "Base64");
+ b64_body = encode_base64(this->msg_body);
+ xmlNodeSetContent(n, b64_body.ptr);
+ xmlAddChild(this->node, n);
+ free(b64_body.ptr);
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.h b/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.h
new file mode 100644
index 000000000..3477fa74e
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/imc_imv_msg.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup imc_imv_msg imc_imv_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef IMC_IMV_MSG_H_
+#define IMC_IMV_MSG_H_
+
+typedef struct imc_imv_msg_t imc_imv_msg_t;
+
+#include "tnccs_msg.h"
+
+#include <tncif.h>
+
+/**
+ * Classs representing the PB-PA message type.
+ */
+struct imc_imv_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+
+ /**
+ * Get IMC-IMV message type
+ *
+ * @return IMC-IMV message type
+ */
+ TNC_MessageType (*get_msg_type)(imc_imv_msg_t *this);
+
+ /**
+ * Get IMC-IMV message body
+ *
+ * @return IMC-IMV message body
+ */
+ chunk_t (*get_msg_body)(imc_imv_msg_t *this);
+};
+
+/**
+ * Create an IMC-IMV message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ * @param errors linked list of TNCCS error messages
+*/
+tnccs_msg_t *imc_imv_msg_create_from_node(xmlNodePtr node, linked_list_t *errors);
+
+/**
+ * Create an IMC-IMV message from parameters
+ *
+ * @param msg_type IMC-IMV message type
+ * @param msg_body IMC-IMV message body
+ */
+tnccs_msg_t *imc_imv_msg_create(TNC_MessageType msg_type, chunk_t msg_body);
+
+#endif /** IMC_IMV_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.c
new file mode 100644
index 000000000..86b7c6aa5
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_error_msg.h"
+
+#include <utils/debug.h>
+
+ENUM(tnccs_error_type_names, TNCCS_ERROR_BATCH_TOO_LONG, TNCCS_ERROR_OTHER,
+ "batch-too-long",
+ "malformed-batch",
+ "invalid-batch-id",
+ "invalid-recipient-type",
+ "internal-error",
+ "other"
+);
+
+typedef struct private_tnccs_error_msg_t private_tnccs_error_msg_t;
+
+/**
+ * Private data of a tnccs_error_msg_t object.
+ *
+ */
+struct private_tnccs_error_msg_t {
+ /**
+ * Public tnccs_error_msg_t interface.
+ */
+ tnccs_error_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+
+ /**
+ * Error type
+ */
+ tnccs_error_type_t error_type;
+
+ /**
+ * Error message
+ */
+ char *error_msg;
+
+ /**
+ * reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_tnccs_error_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_tnccs_error_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, get_ref, tnccs_msg_t*,
+ private_tnccs_error_msg_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.tnccs_msg_interface;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_tnccs_error_msg_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->error_msg);
+ free(this);
+ }
+}
+
+METHOD(tnccs_error_msg_t, get_message, char*,
+ private_tnccs_error_msg_t *this, tnccs_error_type_t *type)
+{
+ *type = this->error_type;
+
+ return this->error_msg;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_error_msg_create_from_node(xmlNodePtr node)
+{
+ private_tnccs_error_msg_t *this;
+ xmlChar *error_type_name, *error_msg;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_message = _get_message,
+ },
+ .type = TNCCS_MSG_ERROR,
+ .ref = 1,
+ .node = node,
+ .error_type = TNCCS_ERROR_OTHER,
+ );
+
+ error_type_name = xmlGetProp(node, "type");
+ if (error_type_name)
+ {
+ this->error_type = enum_from_name(tnccs_error_type_names,
+ error_type_name);
+ if (this->error_type == -1)
+ {
+ this->error_type = TNCCS_ERROR_OTHER;
+ }
+ xmlFree(error_type_name);
+ }
+
+ error_msg = xmlNodeGetContent(node);
+ if (error_msg)
+ {
+ this->error_msg = strdup(error_msg);
+ xmlFree(error_msg);
+ }
+
+ return &this->public.tnccs_msg_interface;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_error_msg_create(tnccs_error_type_t type, char *msg)
+{
+ private_tnccs_error_msg_t *this;
+ xmlNodePtr n, n2;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_message = _get_message,
+ },
+ .type = TNCCS_MSG_ERROR,
+ .ref = 1,
+ .node = xmlNewNode(NULL, "TNCC-TNCS-Message"),
+ .error_type = type,
+ .error_msg = strdup(msg),
+ );
+
+ DBG1(DBG_TNC, "%s", msg);
+
+ n = xmlNewNode(NULL, "Type");
+ xmlNodeSetContent(n, "00000002");
+ xmlAddChild(this->node, n);
+
+ n = xmlNewNode(NULL, "XML");
+ xmlAddChild(this->node, n);
+
+ n2 = xmlNewNode(NULL, enum_to_name(tnccs_msg_type_names, this->type));
+ xmlNewProp(n2, "type", enum_to_name(tnccs_error_type_names, type));
+ xmlNodeSetContent(n2, msg);
+ xmlAddChild(n, n2);
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.h
new file mode 100644
index 000000000..ce2ce9755
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_error_msg.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_error_msg tnccs_error_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_ERROR_MSG_H_
+#define TNCCS_ERROR_MSG_H_
+
+typedef enum tnccs_error_type_t tnccs_error_type_t;
+typedef struct tnccs_error_msg_t tnccs_error_msg_t;
+
+#include "tnccs_msg.h"
+
+/**
+ * TNCCS error types as defined in section 8.1.4 of TCG TNC IF-TNCCS v1.2
+ */
+enum tnccs_error_type_t {
+ TNCCS_ERROR_BATCH_TOO_LONG,
+ TNCCS_ERROR_MALFORMED_BATCH,
+ TNCCS_ERROR_INVALID_BATCH_ID,
+ TNCCS_ERROR_INVALID_RECIPIENT_TYPE,
+ TNCCS_ERROR_INTERNAL_ERROR,
+ TNCCS_ERROR_OTHER
+};
+
+/**
+ * enum name for tnccs_error_type_t.
+ */
+extern enum_name_t *tnccs_error_type_names;
+
+/**
+ * Class representing the TNCCS-Error message type
+ */
+struct tnccs_error_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+
+ /**
+ * Get error message and type
+ *
+ * @param type TNCCS error type
+ * @return arbitrary error message
+ */
+ char* (*get_message)(tnccs_error_msg_t *this, tnccs_error_type_t *type);
+};
+
+/**
+ * Create a TNCCS-Error message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ */
+tnccs_msg_t *tnccs_error_msg_create_from_node(xmlNodePtr node);
+
+/**
+ * Create a TNCCS-Error message from parameters
+ *
+ * @param type TNCCS error type
+ * @param msg arbitrary error message
+ */
+tnccs_msg_t *tnccs_error_msg_create(tnccs_error_type_t type, char *msg);
+
+#endif /** TNCCS_ERROR_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.c
new file mode 100644
index 000000000..fa5ce8239
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_msg.h"
+#include "imc_imv_msg.h"
+#include "tnccs_error_msg.h"
+#include "tnccs_preferred_language_msg.h"
+#include "tnccs_reason_strings_msg.h"
+#include "tnccs_recommendation_msg.h"
+#include "tnccs_tncs_contact_info_msg.h"
+
+#include <library.h>
+#include <utils/debug.h>
+
+ENUM(tnccs_msg_type_names, IMC_IMV_MSG, TNCCS_MSG_ROOF,
+ "IMC-IMV",
+ "TNCCS-Recommendation",
+ "TNCCS-Error",
+ "TNCCS-PreferredLanguage",
+ "TNCCS-ReasonStrings",
+ "TNCCS-TNCSContactInfo"
+);
+
+/**
+ * See header
+ */
+tnccs_msg_t* tnccs_msg_create_from_node(xmlNodePtr node, linked_list_t *errors)
+{
+ char *error_msg, buf[BUF_LEN];
+ tnccs_error_type_t error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ tnccs_msg_t *msg;
+ tnccs_msg_type_t type = IMC_IMV_MSG;
+
+ if (streq((char*)node->name, "IMC-IMV-Message"))
+ {
+ DBG2(DBG_TNC, "processing %N message", tnccs_msg_type_names, type);
+ return imc_imv_msg_create_from_node(node, errors);
+ }
+ else if (streq((char*)node->name, "TNCC-TNCS-Message"))
+ {
+ bool found = FALSE;
+ xmlNsPtr ns = node->ns;
+ xmlNodePtr cur = node->xmlChildrenNode;
+ xmlNodePtr xml_msg_node = NULL;
+
+ while (cur)
+ {
+ if (streq(cur->name, "Type") && cur->ns == ns)
+ {
+ xmlChar *content = xmlNodeGetContent(cur);
+
+ type = strtol(content, NULL, 16);
+ xmlFree(content);
+ found = TRUE;
+ }
+ else if (streq(cur->name, "XML") && cur->ns == ns)
+ {
+ xml_msg_node = cur->xmlChildrenNode;
+ }
+ cur = cur->next;
+ }
+ if (!found)
+ {
+ error_msg = "Type is missing in TNCC-TNCS-Message";
+ goto fatal;
+ }
+ if (!xml_msg_node)
+ {
+ error_msg = "XML node is missing in TNCC-TNCS-Message";
+ goto fatal;
+ }
+ cur = xml_msg_node;
+
+ /* skip empty and blank nodes */
+ while (cur && xmlIsBlankNode(cur))
+ {
+ cur = cur->next;
+ }
+ if (!cur)
+ {
+ error_msg = "XML node is empty";
+ goto fatal;
+ }
+
+ /* check if TNCCS message type and node name agree */
+ if (type >= TNCCS_MSG_RECOMMENDATION && type <= TNCCS_MSG_ROOF)
+ {
+ DBG2(DBG_TNC, "processing %N message", tnccs_msg_type_names, type);
+ if (cur->ns != ns)
+ {
+ error_msg = "node is not in the TNCCS message namespace";
+ goto fatal;
+ }
+ if (type != enum_from_name(tnccs_msg_type_names, (char*)cur->name))
+ {
+ error_msg = buf;
+ snprintf(buf, BUF_LEN, "expected '%N' node but was '%s'",
+ tnccs_msg_type_names, type, (char*)cur->name);
+ goto fatal;
+ }
+ }
+
+ switch (type)
+ {
+ case TNCCS_MSG_RECOMMENDATION:
+ return tnccs_recommendation_msg_create_from_node(cur, errors);
+ case TNCCS_MSG_ERROR:
+ return tnccs_error_msg_create_from_node(cur);
+ case TNCCS_MSG_PREFERRED_LANGUAGE:
+ return tnccs_preferred_language_msg_create_from_node(cur, errors);
+ case TNCCS_MSG_REASON_STRINGS:
+ return tnccs_reason_strings_msg_create_from_node(cur, errors);
+ case TNCCS_MSG_TNCS_CONTACT_INFO:
+ return tnccs_tncs_contact_info_msg_create_from_node(cur, errors);
+ default:
+ DBG1(DBG_TNC, "ignoring TNCC-TNCS-Message with type %d", type);
+ return NULL;
+ }
+ }
+ DBG1(DBG_TNC, "ignoring unknown message node '%s'", (char*)node->name);
+ return NULL;
+
+fatal:
+ msg = tnccs_error_msg_create(error_type, error_msg);
+ errors->insert_last(errors, msg);
+ return NULL;
+}
+
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.h
new file mode 100644
index 000000000..88d6f07aa
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_msg.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_msg tnccs_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_MSG_H_
+#define TNCCS_MSG_H_
+
+typedef enum tnccs_msg_type_t tnccs_msg_type_t;
+typedef struct tnccs_msg_t tnccs_msg_t;
+
+#include <library.h>
+#include <collections/linked_list.h>
+#include <libxml/parser.h>
+
+/**
+ * TNCC-TNCS messages as defined in section 2.8.5 of TCG TNC IF-TNCCS v1.2
+ */
+enum tnccs_msg_type_t {
+ IMC_IMV_MSG = 0,
+ TNCCS_MSG_RECOMMENDATION = 1,
+ TNCCS_MSG_ERROR = 2,
+ TNCCS_MSG_PREFERRED_LANGUAGE = 3,
+ TNCCS_MSG_REASON_STRINGS = 4,
+ TNCCS_MSG_TNCS_CONTACT_INFO = 5,
+ TNCCS_MSG_ROOF = 5
+};
+
+/**
+ * enum name for tnccs_msg_type_t.
+ */
+extern enum_name_t *tnccs_msg_type_names;
+
+/**
+ * Generic interface for all TNCCS message types.
+ *
+ * To handle all messages in a generic way, this interface
+ * must be implemented by each message type.
+ */
+struct tnccs_msg_t {
+
+ /**
+ * Get the TNCCS Message Type
+ *
+ * @return TNCCS Message Type
+ */
+ tnccs_msg_type_t (*get_type)(tnccs_msg_t *this);
+
+ /**
+ * Get the XML-encoded Message Node
+ *
+ * @return Message Node
+ */
+ xmlNodePtr (*get_node)(tnccs_msg_t *this);
+
+ /**
+ * Process the TNCCS Message
+ *
+ * @return return processing status
+ */
+ status_t (*process)(tnccs_msg_t *this);
+
+ /**
+ * Get a new reference to the message.
+ *
+ * @return this, with an increased refcount
+ */
+ tnccs_msg_t* (*get_ref)(tnccs_msg_t *this);
+
+ /**
+ * Destroys a tnccs_msg_t object.
+ */
+ void (*destroy)(tnccs_msg_t *this);
+};
+
+/**
+ * Create a pre-processed TNCCS message
+ *
+ * Useful for the parser which wants a generic constructor for all
+ * tnccs_msg_t types.
+ *
+ * @param node TNCCS message node
+ * @param errors linked list of TNCCS error messages
+ */
+tnccs_msg_t* tnccs_msg_create_from_node(xmlNodePtr node, linked_list_t *errors);
+
+#endif /** TNCCS_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.c
new file mode 100644
index 000000000..710269ba9
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_preferred_language_msg.h"
+
+#include <utils/debug.h>
+
+typedef struct private_tnccs_preferred_language_msg_t private_tnccs_preferred_language_msg_t;
+
+/**
+ * Private data of a tnccs_preferred_language_msg_t object.
+ *
+ */
+struct private_tnccs_preferred_language_msg_t {
+ /**
+ * Public tnccs_preferred_language_msg_t interface.
+ */
+ tnccs_preferred_language_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+
+ /**
+ * Preferred language
+ */
+ char *preferred_language;
+};
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_tnccs_preferred_language_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_tnccs_preferred_language_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_tnccs_preferred_language_msg_t *this)
+{
+ free(this->preferred_language);
+ free(this);
+}
+
+METHOD(tnccs_preferred_language_msg_t, get_preferred_language, char*,
+ private_tnccs_preferred_language_msg_t *this)
+{
+ return this->preferred_language;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_preferred_language_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors)
+{
+ private_tnccs_preferred_language_msg_t *this;
+ xmlChar *language;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_preferred_language = _get_preferred_language,
+ },
+ .type = TNCCS_MSG_PREFERRED_LANGUAGE,
+ .node = node,
+ );
+
+ language = xmlNodeGetContent(node);
+ this->preferred_language = strdup(language);
+ xmlFree(language);
+
+ return &this->public.tnccs_msg_interface;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_preferred_language_msg_create(char *language)
+{
+ private_tnccs_preferred_language_msg_t *this;
+ xmlNodePtr n, n2;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_preferred_language = _get_preferred_language,
+ },
+ .type = TNCCS_MSG_PREFERRED_LANGUAGE,
+ .node = xmlNewNode(NULL, "TNCC-TNCS-Message"),
+ .preferred_language = strdup(language),
+ );
+
+ /* add the message type number in hex */
+ n = xmlNewNode(NULL, "Type");
+ xmlNodeSetContent(n, "00000003");
+ xmlAddChild(this->node, n);
+
+ n = xmlNewNode(NULL, "XML");
+ xmlAddChild(this->node, n);
+
+ n2 = xmlNewNode(NULL, enum_to_name(tnccs_msg_type_names, this->type));
+ xmlNodeSetContent(n2, language);
+ xmlAddChild(n, n2);
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.h
new file mode 100644
index 000000000..c2de7fe4d
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_preferred_language_msg.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_preferred_language_msg tnccs_preferred_language_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_PREFERRED_LANGUAGE_MSG_H_
+#define TNCCS_PREFERRED_LANGUAGE_MSG_H_
+
+typedef struct tnccs_preferred_language_msg_t tnccs_preferred_language_msg_t;
+
+#include "tnccs_msg.h"
+
+#include <tncif.h>
+
+/**
+ * Class representing the TNCCS-PreferredLanguage message type
+ */
+struct tnccs_preferred_language_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+
+ /**
+ * Get preferred language string
+ *
+ * @return preferred language string
+ */
+ char* (*get_preferred_language)(tnccs_preferred_language_msg_t *this);
+};
+
+/**
+ * Create a TNCCS-PreferredLanguage message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ * @param errors linked list of TNCCS error messages
+ */
+tnccs_msg_t *tnccs_preferred_language_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors);
+
+/**
+ * Create a TNCCS-PreferredLanguage message from parameters
+ *
+ * @param language preferred language string
+ */
+tnccs_msg_t *tnccs_preferred_language_msg_create(char *language);
+
+#endif /** TNCCS_PREFERRED_LANGUAGE_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.c
new file mode 100644
index 000000000..7c2f9b3f9
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_reason_strings_msg.h"
+#include "tnccs_error_msg.h"
+
+#include <utils/debug.h>
+
+typedef struct private_tnccs_reason_strings_msg_t private_tnccs_reason_strings_msg_t;
+
+/**
+ * Private data of a tnccs_reason_strings_msg_t object.
+ *
+ */
+struct private_tnccs_reason_strings_msg_t {
+ /**
+ * Public tnccs_reason_strings_msg_t interface.
+ */
+ tnccs_reason_strings_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+
+ /**
+ * Reason String
+ */
+ chunk_t reason;
+
+ /**
+ * Reason Language
+ */
+ chunk_t language;
+};
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_tnccs_reason_strings_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_tnccs_reason_strings_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_tnccs_reason_strings_msg_t *this)
+{
+ free(this->reason.ptr);
+ free(this->language.ptr);
+ free(this);
+}
+
+METHOD(tnccs_reason_strings_msg_t, get_reason, chunk_t,
+ private_tnccs_reason_strings_msg_t *this, chunk_t *language)
+{
+ *language = this->language;
+
+ return this->reason;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_reason_strings_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors)
+{
+ private_tnccs_reason_strings_msg_t *this;
+ char *error_msg, *lang_string, *reason_string;
+ tnccs_error_type_t error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ tnccs_msg_t *msg;
+ xmlNodePtr child;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_reason = _get_reason,
+ },
+ .type = TNCCS_MSG_REASON_STRINGS,
+ .node = node,
+ );
+
+ if (xmlStrcmp(node->name, "TNCCS-ReasonStrings"))
+ {
+ error_msg = "TNCCS-ReasonStrings tag expected";
+ goto fatal;
+ }
+
+ child = node->xmlChildrenNode;
+ while (child)
+ {
+ if (xmlIsBlankNode(child))
+ {
+ child = child->next;
+ continue;
+ }
+ if (xmlStrcmp(child->name, "ReasonString"))
+ {
+ error_msg = "ReasonString tag expected";
+ goto fatal;
+ }
+ break;
+ }
+
+ lang_string = xmlGetProp(child, "lang");
+ if (!lang_string)
+ {
+ lang_string = strdup("");
+ }
+ this->language = chunk_clone(chunk_from_str(lang_string));
+ xmlFree(lang_string);
+
+ reason_string = xmlNodeGetContent(child);
+ this->reason = chunk_clone(chunk_from_str(reason_string));
+ xmlFree(reason_string);
+
+ return &this->public.tnccs_msg_interface;
+
+fatal:
+ msg = tnccs_error_msg_create(error_type, error_msg);
+ errors->insert_last(errors, msg);
+ destroy(this);
+ return NULL;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_reason_strings_msg_create(chunk_t reason, chunk_t language)
+{
+ private_tnccs_reason_strings_msg_t *this;
+ xmlNodePtr n, n2, n3;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_reason = _get_reason,
+ },
+ .type = TNCCS_MSG_REASON_STRINGS,
+ .node = xmlNewNode(NULL, "TNCC-TNCS-Message"),
+ .reason = chunk_create_clone(malloc(reason.len + 1), reason),
+ .language = chunk_create_clone(malloc(language.len + 1), language),
+ );
+
+ /* add NULL termination for XML string representation */
+ this->reason.ptr[this->reason.len] = '\0';
+ this->language.ptr[this->language.len] = '\0';
+
+ /* add the message type number in hex */
+ n = xmlNewNode(NULL, "Type");
+ xmlNodeSetContent(n, "00000004");
+ xmlAddChild(this->node, n);
+
+ n = xmlNewNode(NULL, "XML");
+ xmlAddChild(this->node, n);
+
+ n2 = xmlNewNode(NULL, enum_to_name(tnccs_msg_type_names, this->type));
+
+ /* could add multiple reasons here, if we had them */
+
+ n3 = xmlNewNode(NULL, "ReasonString");
+ xmlNewProp(n3, "xml:lang", this->language.ptr);
+ xmlNodeSetContent(n3, this->reason.ptr);
+ xmlAddChild(n2, n3);
+ xmlAddChild(n, n2);
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.h
new file mode 100644
index 000000000..0046a5789
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_reason_strings_msg.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_reason_strings_msg tnccs_reason_strings_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_REASON_STRINGS_MSG_H_
+#define TNCCS_REASON_STRINGS_MSG_H_
+
+typedef struct tnccs_reason_strings_msg_t tnccs_reason_strings_msg_t;
+
+#include "tnccs_msg.h"
+
+/**
+ * Class representing the TNCCS-ReasonStrings message type
+ */
+struct tnccs_reason_strings_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+
+ /**
+ * Get reason string and language
+ *
+ * @param language reason language
+ * @return reason string
+ */
+ chunk_t (*get_reason)(tnccs_reason_strings_msg_t *this, chunk_t *language);
+};
+
+/**
+ * Create a TNCCS-ReasonStrings message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ * @param errors linked list of TNCCS error messages
+ */
+tnccs_msg_t *tnccs_reason_strings_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors);
+
+/**
+ * Create a TNCCS-ReasonStrings message from parameters
+ *
+ * @param reason reason string
+ * @param language reason language
+ */
+tnccs_msg_t *tnccs_reason_strings_msg_create(chunk_t reason, chunk_t language);
+
+#endif /** TNCCS_REASON_STRINGS_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.c
new file mode 100644
index 000000000..013e0c7ed
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
+ * 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 "tnccs_recommendation_msg.h"
+#include "tnccs_error_msg.h"
+
+#include <utils/debug.h>
+
+typedef struct private_tnccs_recommendation_msg_t private_tnccs_recommendation_msg_t;
+
+/**
+ * Private data of a tnccs_recommendation_msg_t object.
+ *
+ */
+struct private_tnccs_recommendation_msg_t {
+ /**
+ * Public tnccs_recommendation_msg_t interface.
+ */
+ tnccs_recommendation_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+
+ /**
+ * Action Recommendation
+ */
+ TNC_IMV_Action_Recommendation rec;
+};
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_tnccs_recommendation_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_tnccs_recommendation_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_tnccs_recommendation_msg_t *this)
+{
+ free(this);
+}
+
+METHOD(tnccs_recommendation_msg_t, get_recommendation, TNC_IMV_Action_Recommendation,
+ private_tnccs_recommendation_msg_t *this)
+{
+ return this->rec;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_recommendation_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors)
+{
+ private_tnccs_recommendation_msg_t *this;
+ xmlChar *rec_string;
+ char *error_msg, buf[BUF_LEN];
+ tnccs_error_type_t error_type = TNCCS_ERROR_MALFORMED_BATCH;
+ tnccs_msg_t *msg;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_recommendation = _get_recommendation,
+ },
+ .type = TNCCS_MSG_RECOMMENDATION,
+ .node = node,
+ );
+
+ rec_string = xmlGetProp(node, "type");
+ if (!rec_string)
+ {
+ error_msg = "type property in TNCCS-Recommendation is missing";
+ goto fatal;
+ }
+ else if (streq(rec_string, "allow"))
+ {
+ this->rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
+ }
+ else if (streq(rec_string, "isolate"))
+ {
+ this->rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
+ }
+ else if (streq(rec_string, "none"))
+ {
+ this->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
+ }
+ else
+ {
+ error_msg = buf;
+ snprintf(buf, BUF_LEN, "unsupported type property value '%s' "
+ "in TNCCS-Recommendation", rec_string);
+ xmlFree(rec_string);
+ goto fatal;
+ }
+ xmlFree(rec_string);
+
+ return &this->public.tnccs_msg_interface;
+
+fatal:
+ msg = tnccs_error_msg_create(error_type, error_msg);
+ errors->insert_last(errors, msg);
+ destroy(this);
+ return NULL;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_recommendation_msg_create(TNC_IMV_Action_Recommendation rec)
+{
+ private_tnccs_recommendation_msg_t *this;
+ xmlNodePtr n, n2;
+ char *rec_string;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ .get_recommendation = _get_recommendation,
+ },
+ .type = TNCCS_MSG_RECOMMENDATION,
+ .node = xmlNewNode(NULL, "TNCC-TNCS-Message"),
+ .rec = rec,
+ );
+
+ /* add the message type number in hex */
+ n = xmlNewNode(NULL, "Type");
+ xmlNodeSetContent(n, "00000001");
+ xmlAddChild(this->node, n);
+
+ n = xmlNewNode(NULL, "XML");
+ xmlAddChild(this->node, n);
+
+ switch (rec)
+ {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ rec_string = "allow";
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ rec_string = "isolate";
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ default:
+ rec_string = "none";
+ }
+
+ n2 = xmlNewNode(NULL, enum_to_name(tnccs_msg_type_names, this->type));
+ xmlNewProp(n2, BAD_CAST "type", rec_string);
+ xmlNodeSetContent(n2, "");
+ xmlAddChild(n, n2);
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.h
new file mode 100644
index 000000000..3a67a3b32
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_recommendation_msg.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_recommendation_msg tnccs_recommendation_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_RECOMMENDATION_MSG_H_
+#define TNCCS_RECOMMENDATION_MSG_H_
+
+typedef struct tnccs_recommendation_msg_t tnccs_recommendation_msg_t;
+
+#include "tnccs_msg.h"
+
+#include <tncifimv.h>
+
+/**
+ * Class representing the TNCCS-Recommendation message type
+ */
+struct tnccs_recommendation_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+
+ /**
+ * Get Action Recommendation
+ *
+ * @return Action Recommendation
+ */
+ TNC_IMV_Action_Recommendation (*get_recommendation)(tnccs_recommendation_msg_t *this);
+};
+
+/**
+ * Create a TNCCS-Recommendation message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ * @param errors linked list of TNCCS error messages
+ */
+tnccs_msg_t *tnccs_recommendation_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors);
+
+/**
+ * Create a TNCCS-Recommendation message from parameters
+ *
+ * @param rec Action Recommendation
+ */
+tnccs_msg_t *tnccs_recommendation_msg_create(TNC_IMV_Action_Recommendation rec);
+
+#endif /** TNCCS_RECOMMENDATION_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.c b/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.c
new file mode 100644
index 000000000..0d3e1c2a0
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.c
@@ -0,0 +1,118 @@
+/*
+ * 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 "tnccs_tncs_contact_info_msg.h"
+
+#include <utils/debug.h>
+
+typedef struct private_tnccs_tncs_contact_info_msg_t private_tnccs_tncs_contact_info_msg_t;
+
+/**
+ * Private data of a tnccs_tncs_contact_info_msg_t object.
+ *
+ */
+struct private_tnccs_tncs_contact_info_msg_t {
+ /**
+ * Public tnccs_tncs_contact_info_msg_t interface.
+ */
+ tnccs_tncs_contact_info_msg_t public;
+
+ /**
+ * TNCCS message type
+ */
+ tnccs_msg_type_t type;
+
+ /**
+ * XML-encoded message node
+ */
+ xmlNodePtr node;
+};
+
+METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
+ private_tnccs_tncs_contact_info_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(tnccs_msg_t, get_node, xmlNodePtr,
+ private_tnccs_tncs_contact_info_msg_t *this)
+{
+ return this->node;
+}
+
+METHOD(tnccs_msg_t, destroy, void,
+ private_tnccs_tncs_contact_info_msg_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_tncs_contact_info_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors)
+{
+ private_tnccs_tncs_contact_info_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ },
+ .type = TNCCS_MSG_TNCS_CONTACT_INFO,
+ .node = node,
+ );
+
+ return &this->public.tnccs_msg_interface;
+}
+
+/**
+ * See header
+ */
+tnccs_msg_t *tnccs_tncs_contact_info_msg_create(void)
+{
+ private_tnccs_tncs_contact_info_msg_t *this;
+ xmlNodePtr n /*, n2 */;
+
+ INIT(this,
+ .public = {
+ .tnccs_msg_interface = {
+ .get_type = _get_type,
+ .get_node = _get_node,
+ .destroy = _destroy,
+ },
+ },
+ .type = TNCCS_MSG_TNCS_CONTACT_INFO,
+ .node = xmlNewNode(NULL, "TNCC-TNCS-Message"),
+ );
+
+ /* add the message type number in hex */
+ n = xmlNewNode(NULL, "Type");
+ xmlNodeSetContent(n, "00000005");
+ xmlAddChild(this->node, n);
+
+ n = xmlNewNode(NULL, "XML");
+ xmlAddChild(this->node, n);
+
+/* TODO
+ n2 = xmlNewNode(NULL, enum_to_name(tnccs_msg_type_names, this->type));
+ xmlNodeSetContent(n2, language);
+ xmlAddChild(n, n2);
+*/
+
+ return &this->public.tnccs_msg_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.h b/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.h
new file mode 100644
index 000000000..8ed210a57
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/messages/tnccs_tncs_contact_info_msg.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_tncs_contact_info_msg tnccs_tncs_contact_info_msg
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_TNCS_CONTACT_INFO_MSG_H_
+#define TNCCS_TNCS_CONTACT_INFO_MSG_H_
+
+typedef struct tnccs_tncs_contact_info_msg_t tnccs_tncs_contact_info_msg_t;
+
+#include "tnccs_msg.h"
+
+/**
+ * Class representing the TNCCS-TNCSContactInfo message type
+ */
+struct tnccs_tncs_contact_info_msg_t {
+
+ /**
+ * TNCCS Message interface
+ */
+ tnccs_msg_t tnccs_msg_interface;
+};
+
+/**
+ * Create a TNCCS-TNCSContactInfo message from XML-encoded message node
+ *
+ * @param node XML-encoded message node
+ * @param errors linked list of TNCCS error messages
+ */
+tnccs_msg_t *tnccs_tncs_contact_info_msg_create_from_node(xmlNodePtr node,
+ linked_list_t *errors);
+
+/**
+ * Create a TNCCS-TNCSContactInfo message from parameters
+ *
+ */
+tnccs_msg_t *tnccs_tncs_contact_info_msg_create(void);
+
+#endif /** TNCCS_TNCS_CONTACT_INFO_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11.c b/src/libtnccs/plugins/tnccs_11/tnccs_11.c
new file mode 100644
index 000000000..b19a048fe
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/tnccs_11.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2010-2013 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 "tnccs_11.h"
+#include "batch/tnccs_batch.h"
+#include "messages/tnccs_msg.h"
+#include "messages/imc_imv_msg.h"
+#include "messages/tnccs_error_msg.h"
+#include "messages/tnccs_preferred_language_msg.h"
+#include "messages/tnccs_reason_strings_msg.h"
+#include "messages/tnccs_recommendation_msg.h"
+
+#include <tncif_names.h>
+#include <tncif_pa_subtypes.h>
+
+#include <tnc/tnc.h>
+#include <tnc/imc/imc_manager.h>
+#include <tnc/imv/imv_manager.h>
+#include <tnc/tnccs/tnccs.h>
+#include <tnc/tnccs/tnccs_manager.h>
+
+#include <utils/debug.h>
+#include <threading/mutex.h>
+
+typedef struct private_tnccs_11_t private_tnccs_11_t;
+
+/**
+ * Private data of a tnccs_11_t object.
+ */
+struct private_tnccs_11_t {
+
+ /**
+ * Public tnccs_t interface.
+ */
+ tnccs_t public;
+
+ /**
+ * TNCC if TRUE, TNCS if FALSE
+ */
+ bool is_server;
+
+ /**
+ * Server identity
+ */
+ identification_t *server;
+
+ /**
+ * Client identity
+ */
+ identification_t *peer;
+
+ /**
+ * Underlying TNC IF-T transport protocol
+ */
+ tnc_ift_type_t transport;
+
+ /**
+ * Type of TNC client authentication
+ */
+ u_int32_t auth_type;
+
+ /**
+ * Connection ID assigned to this TNCCS connection
+ */
+ TNC_ConnectionID connection_id;
+
+ /**
+ * Last TNCCS batch ID
+ */
+ int batch_id;
+
+ /**
+ * TNCCS batch being constructed
+ */
+ tnccs_batch_t *batch;
+
+ /**
+ * Maximum PA-TNC message size
+ */
+ size_t max_msg_len;
+
+ /**
+ * Mutex locking the batch in construction
+ */
+ mutex_t *mutex;
+
+ /**
+ * Flag set while processing
+ */
+ bool fatal_error;
+
+ /**
+ * Flag set by TNCCS-Recommendation message
+ */
+ bool delete_state;
+
+ /**
+ * SendMessage() by IMC/IMV only allowed if flag is set
+ */
+ bool send_msg;
+
+ /**
+ * Flag set by IMC/IMV RequestHandshakeRetry() function
+ */
+ bool request_handshake_retry;
+
+ /**
+ * Set of IMV recommendations (TNC Server only)
+ */
+ recommendations_t *recs;
+
+};
+
+METHOD(tnccs_t, send_msg, TNC_Result,
+ private_tnccs_11_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
+{
+ tnccs_msg_t *tnccs_msg;
+ TNC_MessageType msg_type;
+ enum_name_t *pa_subtype_names;
+
+ if (!this->send_msg)
+ {
+ DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
+ this->is_server ? "IMV" : "IMC",
+ this->is_server ? imv_id : imc_id);
+ return TNC_RESULT_ILLEGAL_OPERATION;
+ }
+ if (msg_vid > TNC_VENDORID_ANY || msg_subtype > TNC_SUBTYPE_ANY)
+ {
+ return TNC_RESULT_NO_LONG_MESSAGE_TYPES;
+ }
+ msg_type = (msg_vid << 8) | msg_subtype;
+
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
+ if (pa_subtype_names)
+ {
+ DBG2(DBG_TNC, "creating IMC-IMV message type '%N/%N' 0x%06x/0x%02x",
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "creating IMC-IMV message type '%N' 0x%06x/0x%02x",
+ pen_names, msg_vid, msg_vid, msg_subtype);
+ }
+ tnccs_msg = imc_imv_msg_create(msg_type, chunk_create(msg, msg_len));
+
+ /* adding an IMC-IMV Message to TNCCS batch */
+ this->mutex->lock(this->mutex);
+ if (!this->batch)
+ {
+ this->batch = tnccs_batch_create(this->is_server, ++this->batch_id);
+ }
+ this->batch->add_msg(this->batch, tnccs_msg);
+ this->mutex->unlock(this->mutex);
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * Handle a single TNCCS message according to its type
+ */
+static void handle_message(private_tnccs_11_t *this, tnccs_msg_t *msg)
+{
+ switch (msg->get_type(msg))
+ {
+ case IMC_IMV_MSG:
+ {
+ imc_imv_msg_t *imc_imv_msg;
+ TNC_MessageType msg_type;
+ chunk_t msg_body;
+ u_int32_t msg_vid, msg_subtype;
+ enum_name_t *pa_subtype_names;
+
+ imc_imv_msg = (imc_imv_msg_t*)msg;
+ msg_type = imc_imv_msg->get_msg_type(imc_imv_msg);
+ msg_body = imc_imv_msg->get_msg_body(imc_imv_msg);
+ msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
+ if (pa_subtype_names)
+ {
+ DBG2(DBG_TNC, "handling IMC-IMV message type '%N/%N' 0x%06x/0x%02x",
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "handling IMC-IMV message type '%N' 0x%06x/0x%02x",
+ pen_names, msg_vid, msg_vid, msg_subtype);
+ }
+
+ this->send_msg = TRUE;
+ if (this->is_server)
+ {
+ tnc->imvs->receive_message(tnc->imvs, this->connection_id,
+ FALSE, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
+ }
+ else
+ {
+ tnc->imcs->receive_message(tnc->imcs, this->connection_id,
+ FALSE, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, 0, TNC_IMCID_ANY);
+ }
+ this->send_msg = FALSE;
+ break;
+ }
+ case TNCCS_MSG_RECOMMENDATION:
+ {
+ tnccs_recommendation_msg_t *rec_msg;
+ TNC_IMV_Action_Recommendation rec;
+ TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE;
+
+ rec_msg = (tnccs_recommendation_msg_t*)msg;
+ rec = rec_msg->get_recommendation(rec_msg);
+ if (this->is_server)
+ {
+ DBG1(DBG_TNC, "ignoring NCCS-Recommendation message from "
+ " TNC client");
+ break;
+ }
+ DBG1(DBG_TNC, "TNC recommendation is '%N'",
+ TNC_IMV_Action_Recommendation_names, rec);
+ switch (rec)
+ {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ default:
+ state = TNC_CONNECTION_STATE_ACCESS_NONE;
+ }
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ state);
+ this->delete_state = TRUE;
+ break;
+ }
+ case TNCCS_MSG_ERROR:
+ {
+ tnccs_error_msg_t *err_msg;
+ tnccs_error_type_t error_type;
+ char *error_msg;
+
+ err_msg = (tnccs_error_msg_t*)msg;
+ error_msg = err_msg->get_message(err_msg, &error_type);
+ DBG1(DBG_TNC, "received '%N' TNCCS-Error: %s",
+ tnccs_error_type_names, error_type, error_msg);
+
+ /* we assume that all errors are fatal */
+ this->fatal_error = TRUE;
+ break;
+ }
+ case TNCCS_MSG_PREFERRED_LANGUAGE:
+ {
+ tnccs_preferred_language_msg_t *lang_msg;
+ char *lang;
+
+ lang_msg = (tnccs_preferred_language_msg_t*)msg;
+ lang = lang_msg->get_preferred_language(lang_msg);
+
+ DBG2(DBG_TNC, "setting preferred language to '%s'", lang);
+ this->recs->set_preferred_language(this->recs,
+ chunk_create(lang, strlen(lang)));
+ break;
+ }
+ case TNCCS_MSG_REASON_STRINGS:
+ {
+ tnccs_reason_strings_msg_t *reason_msg;
+ chunk_t reason_string, reason_lang;
+
+ reason_msg = (tnccs_reason_strings_msg_t*)msg;
+ reason_string = reason_msg->get_reason(reason_msg, &reason_lang);
+ DBG2(DBG_TNC, "reason string is '%.*s'", (int)reason_string.len,
+ reason_string.ptr);
+ DBG2(DBG_TNC, "language code is '%.*s'", (int)reason_lang.len,
+ reason_lang.ptr);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+METHOD(tls_t, process, status_t,
+ private_tnccs_11_t *this, void *buf, size_t buflen)
+{
+ chunk_t data;
+ tnccs_batch_t *batch;
+ tnccs_msg_t *msg;
+ enumerator_t *enumerator;
+ status_t status;
+
+ if (this->is_server && !this->connection_id)
+ {
+ this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
+ TNCCS_1_1, (tnccs_t*)this, _send_msg,
+ &this->request_handshake_retry,
+ this->max_msg_len, &this->recs);
+ if (!this->connection_id)
+ {
+ return FAILED;
+ }
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ TNC_CONNECTION_STATE_CREATE);
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ }
+
+ data = chunk_create(buf, buflen);
+ DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u",
+ data.len, this->connection_id);
+ DBG3(DBG_TNC, "%.*s", (int)data.len, data.ptr);
+ batch = tnccs_batch_create_from_data(this->is_server, ++this->batch_id, data);
+ status = batch->process(batch);
+
+ if (status == FAILED)
+ {
+ this->fatal_error = TRUE;
+ this->mutex->lock(this->mutex);
+ if (this->batch)
+ {
+ DBG1(DBG_TNC, "cancelling TNCCS batch");
+ this->batch->destroy(this->batch);
+ this->batch_id--;
+ }
+ this->batch = tnccs_batch_create(this->is_server, ++this->batch_id);
+
+ /* add error messages to outbound batch */
+ enumerator = batch->create_error_enumerator(batch);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ this->batch->add_msg(this->batch, msg->get_ref(msg));
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+ }
+ else
+ {
+ enumerator = batch->create_msg_enumerator(batch);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ handle_message(this, msg);
+ }
+ enumerator->destroy(enumerator);
+
+ /* received any TNCCS-Error messages */
+ if (this->fatal_error)
+ {
+ DBG1(DBG_TNC, "a fatal TNCCS-Error occurred, terminating connection");
+ batch->destroy(batch);
+ return FAILED;
+ }
+
+ this->send_msg = TRUE;
+ if (this->is_server)
+ {
+ tnc->imvs->batch_ending(tnc->imvs, this->connection_id);
+ }
+ else
+ {
+ tnc->imcs->batch_ending(tnc->imcs, this->connection_id);
+ }
+ this->send_msg = FALSE;
+ }
+ batch->destroy(batch);
+
+ return NEED_MORE;
+}
+
+/**
+ * Add a recommendation message if a final recommendation is available
+ */
+static void check_and_build_recommendation(private_tnccs_11_t *this)
+{
+ TNC_IMV_Action_Recommendation rec;
+ TNC_IMV_Evaluation_Result eval;
+ TNC_IMVID id;
+ chunk_t reason, language;
+ enumerator_t *enumerator;
+ tnccs_msg_t *msg;
+
+ if (!this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id);
+ }
+ if (this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ if (!this->batch)
+ {
+ this->batch = tnccs_batch_create(this->is_server, ++this->batch_id);
+ }
+
+ msg = tnccs_recommendation_msg_create(rec);
+ this->batch->add_msg(this->batch, msg);
+
+ /* currently we just send the first Reason String */
+ enumerator = this->recs->create_reason_enumerator(this->recs);
+ if (enumerator->enumerate(enumerator, &id, &reason, &language))
+ {
+ msg = tnccs_reason_strings_msg_create(reason, language);
+ this->batch->add_msg(this->batch, msg);
+ }
+ enumerator->destroy(enumerator);
+
+ /* we have reache the final state */
+ this->delete_state = TRUE;
+ }
+}
+
+METHOD(tls_t, build, status_t,
+ private_tnccs_11_t *this, void *buf, size_t *buflen, size_t *msglen)
+{
+ status_t status;
+
+ /* Initialize the connection */
+ if (!this->is_server && !this->connection_id)
+ {
+ tnccs_msg_t *msg;
+ char *pref_lang;
+
+ this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
+ TNCCS_1_1, (tnccs_t*)this, _send_msg,
+ &this->request_handshake_retry,
+ this->max_msg_len, NULL);
+ if (!this->connection_id)
+ {
+ return FAILED;
+ }
+
+ /* Create TNCCS-PreferredLanguage message */
+ pref_lang = tnc->imcs->get_preferred_language(tnc->imcs);
+ msg = tnccs_preferred_language_msg_create(pref_lang);
+ this->mutex->lock(this->mutex);
+ this->batch = tnccs_batch_create(this->is_server, ++this->batch_id);
+ this->batch->add_msg(this->batch, msg);
+ this->mutex->unlock(this->mutex);
+
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ TNC_CONNECTION_STATE_CREATE);
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ this->send_msg = TRUE;
+ tnc->imcs->begin_handshake(tnc->imcs, this->connection_id);
+ this->send_msg = FALSE;
+ }
+
+ /* Do not allow any asynchronous IMCs or IMVs to add additional messages */
+ this->mutex->lock(this->mutex);
+
+ if (this->recs && !this->delete_state &&
+ (!this->batch || this->fatal_error))
+ {
+ check_and_build_recommendation(this);
+ }
+
+ if (this->batch)
+ {
+ chunk_t data;
+
+ this->batch->build(this->batch);
+ data = this->batch->get_encoding(this->batch);
+ DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u",
+ data.len, this->connection_id);
+ DBG3(DBG_TNC, "%.*s", (int)data.len, data.ptr);
+ *msglen = 0;
+
+ if (data.len > *buflen)
+ {
+ DBG1(DBG_TNC, "fragmentation of TNCCS batch not supported yet");
+ }
+ else
+ {
+ *buflen = data.len;
+ }
+ memcpy(buf, data.ptr, *buflen);
+ this->batch->destroy(this->batch);
+ this->batch = NULL;
+ status = ALREADY_DONE;
+ }
+ else
+ {
+ DBG1(DBG_TNC, "no TNCCS Batch to send");
+ status = INVALID_STATE;
+ }
+ this->mutex->unlock(this->mutex);
+
+ return status;
+}
+
+METHOD(tls_t, is_server, bool,
+ private_tnccs_11_t *this)
+{
+ return this->is_server;
+}
+
+METHOD(tls_t, get_server_id, identification_t*,
+ private_tnccs_11_t *this)
+{
+ return this->server;
+}
+
+METHOD(tls_t, get_peer_id, identification_t*,
+ private_tnccs_11_t *this)
+{
+ return this->peer;
+}
+
+METHOD(tls_t, get_purpose, tls_purpose_t,
+ private_tnccs_11_t *this)
+{
+ return TLS_PURPOSE_EAP_TNC;
+}
+
+METHOD(tls_t, is_complete, bool,
+ private_tnccs_11_t *this)
+{
+ TNC_IMV_Action_Recommendation rec;
+ TNC_IMV_Evaluation_Result eval;
+
+ if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ return tnc->imvs->enforce_recommendation(tnc->imvs, rec, eval);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+METHOD(tls_t, get_eap_msk, chunk_t,
+ private_tnccs_11_t *this)
+{
+ return chunk_empty;
+}
+
+METHOD(tls_t, destroy, void,
+ private_tnccs_11_t *this)
+{
+ tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id,
+ this->is_server);
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ this->mutex->destroy(this->mutex);
+ DESTROY_IF(this->batch);
+ free(this);
+}
+
+METHOD(tnccs_t, get_transport, tnc_ift_type_t,
+ private_tnccs_11_t *this)
+{
+ return this->transport;
+}
+
+METHOD(tnccs_t, set_transport, void,
+ private_tnccs_11_t *this, tnc_ift_type_t transport)
+{
+ this->transport = transport;
+}
+
+METHOD(tnccs_t, get_auth_type, u_int32_t,
+ private_tnccs_11_t *this)
+{
+ return this->auth_type;
+}
+
+METHOD(tnccs_t, set_auth_type, void,
+ private_tnccs_11_t *this, u_int32_t auth_type)
+{
+ this->auth_type = auth_type;
+}
+
+/**
+ * See header
+ */
+tnccs_t* tnccs_11_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport)
+{
+ private_tnccs_11_t *this;
+
+ INIT(this,
+ .public = {
+ .tls = {
+ .process = _process,
+ .build = _build,
+ .is_server = _is_server,
+ .get_server_id = _get_server_id,
+ .get_peer_id = _get_peer_id,
+ .get_purpose = _get_purpose,
+ .is_complete = _is_complete,
+ .get_eap_msk = _get_eap_msk,
+ .destroy = _destroy,
+ },
+ .get_transport = _get_transport,
+ .set_transport = _set_transport,
+ .get_auth_type = _get_auth_type,
+ .set_auth_type = _set_auth_type,
+ },
+ .is_server = is_server,
+ .server = server->clone(server),
+ .peer = peer->clone(peer),
+ .transport = transport,
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .max_msg_len = lib->settings->get_int(lib->settings,
+ "libtnccs.plugins.tnccs-11.max_message_size", 45000),
+ );
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11.h b/src/libtnccs/plugins/tnccs_11/tnccs_11.h
new file mode 100644
index 000000000..531ebb611
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/tnccs_11.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010-2013 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.
+ */
+
+/**
+ * @defgroup tnccs_11_h tnccs_11
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_11_H_
+#define TNCCS_11_H_
+
+#include <library.h>
+
+#include <tnc/tnccs/tnccs.h>
+
+/**
+ * Create an instance of the TNC IF-TNCCS 1.1 protocol handler.
+ *
+ * @param is_server TRUE to act as TNC Server, FALSE for TNC Client
+ * @param server Server identity
+ * @param peer Client identity
+ * @param transport Underlying IF-T transport protocol
+ * @return TNC_IF_TNCCS 1.1 protocol stack
+ */
+tnccs_t* tnccs_11_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport);
+
+#endif /** TNCCS_11_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c
new file mode 100644
index 000000000..f534af008
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "tnccs_11_plugin.h"
+#include "tnccs_11.h"
+
+#include <tnc/tnccs/tnccs_manager.h>
+
+METHOD(plugin_t, get_name, char*,
+ tnccs_11_plugin_t *this)
+{
+ return "tnccs-11";
+}
+
+METHOD(plugin_t, get_features, int,
+ tnccs_11_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(tnccs_method_register, tnccs_11_create),
+ PLUGIN_PROVIDE(CUSTOM, "tnccs-1.1"),
+ PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ tnccs_11_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnccs_11_plugin_create()
+{
+ tnccs_11_plugin_t *this;
+
+ INIT(this,
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->plugin;
+}
diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h
new file mode 100644
index 000000000..619a073ad
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_11 tnccs_11
+ * @ingroup cplugins
+ *
+ * @defgroup tnccs_11_plugin tnccs_11_plugin
+ * @{ @ingroup tnccs_11
+ */
+
+#ifndef TNCCS_11_PLUGIN_H_
+#define TNCCS_11_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnccs_11_plugin_t tnccs_11_plugin_t;
+
+/**
+ * EAP-TNC plugin
+ */
+struct tnccs_11_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNCCS_11_PLUGIN_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/Makefile.am b/src/libtnccs/plugins/tnccs_20/Makefile.am
new file mode 100644
index 000000000..c268f5971
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/Makefile.am
@@ -0,0 +1,33 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtls \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtnccs
+
+AM_CFLAGS = \
+ -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnccs-20.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnccs-20.la
+libstrongswan_tnccs_20_la_LIBADD = \
+ $(top_builddir)/src/libtncif/libtncif.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnccs_20_la_SOURCES = \
+ tnccs_20_plugin.h tnccs_20_plugin.c tnccs_20.h tnccs_20.c \
+ batch/pb_tnc_batch.h batch/pb_tnc_batch.c \
+ messages/pb_tnc_msg.h messages/pb_tnc_msg.c \
+ messages/pb_experimental_msg.h messages/pb_experimental_msg.c \
+ messages/pb_pa_msg.h messages/pb_pa_msg.c \
+ messages/pb_assessment_result_msg.h messages/pb_assessment_result_msg.c \
+ messages/pb_access_recommendation_msg.h messages/pb_access_recommendation_msg.c \
+ messages/pb_error_msg.h messages/pb_error_msg.c \
+ messages/pb_language_preference_msg.h messages/pb_language_preference_msg.c \
+ messages/pb_reason_string_msg.h messages/pb_reason_string_msg.c \
+ messages/pb_remediation_parameters_msg.h messages/pb_remediation_parameters_msg.c \
+ state_machine/pb_tnc_state_machine.h state_machine/pb_tnc_state_machine.c
+
+libstrongswan_tnccs_20_la_LDFLAGS = -module -avoid-version
diff --git a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c
new file mode 100644
index 000000000..d87e0ccea
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyanbuu
+ * Copyright (C) 2010-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
+ * 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 "pb_tnc_batch.h"
+#include "messages/pb_error_msg.h"
+#include "state_machine/pb_tnc_state_machine.h"
+
+#include <tnc/tnccs/tnccs.h>
+
+#include <collections/linked_list.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <pen/pen.h>
+#include <utils/debug.h>
+
+ENUM(pb_tnc_batch_type_names, PB_BATCH_CDATA, PB_BATCH_CLOSE,
+ "CDATA",
+ "SDATA",
+ "RESULT",
+ "CRETRY",
+ "SRETRY",
+ "CLOSE"
+);
+
+typedef struct private_pb_tnc_batch_t private_pb_tnc_batch_t;
+
+/**
+ * PB-Batch Header (see section 4.1 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Version |D| Reserved | B-Type|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Batch Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define PB_TNC_BATCH_FLAG_NONE 0x00
+#define PB_TNC_BATCH_FLAG_D (1<<7)
+#define PB_TNC_BATCH_HEADER_SIZE 8
+
+/**
+ * PB-TNC Message (see section 4.2 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | PB-TNC Vendor ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PB-TNC Message Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PB-TNC Message Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PB-TNC Message Value (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define PB_TNC_FLAG_NONE 0x00
+#define PB_TNC_FLAG_NOSKIP (1<<7)
+#define PB_TNC_HEADER_SIZE 12
+
+#define PB_TNC_RESERVED_MSG_TYPE 0xffffffff
+
+/**
+ * Private data of a pb_tnc_batch_t object.
+ *
+ */
+struct private_pb_tnc_batch_t {
+ /**
+ * Public pb_pa_msg_t interface.
+ */
+ pb_tnc_batch_t public;
+
+ /**
+ * TNCC if TRUE, TNCS if FALSE
+ */
+ bool is_server;
+
+ /**
+ * PB-TNC Batch type
+ */
+ pb_tnc_batch_type_t type;
+
+ /**
+ * Current PB-TNC Batch size
+ */
+ size_t batch_len;
+
+ /**
+ * Maximum PB-TNC Batch size
+ */
+ size_t max_batch_len;
+
+ /**
+ * linked list of PB-TNC messages
+ */
+ linked_list_t *messages;
+
+ /**
+ * linked list of PB-TNC error messages
+ */
+ linked_list_t *errors;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+
+ /**
+ * Offset into encoding (used for error reporting)
+ */
+ u_int32_t offset;
+};
+
+METHOD(pb_tnc_batch_t, get_type, pb_tnc_batch_type_t,
+ private_pb_tnc_batch_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_batch_t, get_encoding, chunk_t,
+ private_pb_tnc_batch_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_batch_t, add_msg, bool,
+ private_pb_tnc_batch_t *this, pb_tnc_msg_t* msg)
+{
+ chunk_t msg_value;
+ size_t msg_len;
+
+ msg->build(msg);
+ msg_value = msg->get_encoding(msg);
+ msg_len = PB_TNC_HEADER_SIZE + msg_value.len;
+
+ if (this->batch_len + msg_len > this->max_batch_len)
+ {
+ /* message just does not fit into this batch */
+ return FALSE;
+ }
+ this->batch_len += msg_len;
+
+ DBG2(DBG_TNC, "adding %N message", pb_tnc_msg_type_names,
+ msg->get_type(msg));
+ this->messages->insert_last(this->messages, msg);
+ return TRUE;
+}
+
+METHOD(pb_tnc_batch_t, build, void,
+ private_pb_tnc_batch_t *this)
+{
+ u_int32_t msg_len;
+ chunk_t msg_value;
+ enumerator_t *enumerator;
+ pb_tnc_msg_type_t msg_type;
+ pb_tnc_msg_t *msg;
+ bio_writer_t *writer;
+
+ /* build PB-TNC batch header */
+ writer = bio_writer_create(this->batch_len);
+ writer->write_uint8 (writer, PB_TNC_VERSION);
+ writer->write_uint8 (writer, this->is_server ?
+ PB_TNC_BATCH_FLAG_D : PB_TNC_BATCH_FLAG_NONE);
+ writer->write_uint16(writer, this->type);
+ writer->write_uint32(writer, this->batch_len);
+
+ /* build PB-TNC messages */
+ enumerator = this->messages->create_enumerator(this->messages);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ u_int8_t flags = PB_TNC_FLAG_NONE;
+
+ /* build PB-TNC message */
+ msg_value = msg->get_encoding(msg);
+ msg_len = PB_TNC_HEADER_SIZE + msg_value.len;
+ msg_type = msg->get_type(msg);
+ if (pb_tnc_msg_infos[msg_type].has_noskip_flag)
+ {
+ flags |= PB_TNC_FLAG_NOSKIP;
+ }
+ writer->write_uint8 (writer, flags);
+ writer->write_uint24(writer, PEN_IETF);
+ writer->write_uint32(writer, msg_type);
+ writer->write_uint32(writer, msg_len);
+ writer->write_data (writer, msg_value);
+ }
+ enumerator->destroy(enumerator);
+
+ this->encoding = writer->extract_buf(writer);
+ writer->destroy(writer);
+}
+
+static status_t process_batch_header(private_pb_tnc_batch_t *this,
+ pb_tnc_state_machine_t *state_machine)
+{
+ bio_reader_t *reader;
+ pb_tnc_msg_t *msg;
+ pb_error_msg_t *err_msg;
+ u_int8_t version, flags, reserved, type;
+ u_int32_t batch_len;
+ bool directionality;
+
+ if (this->encoding.len < PB_TNC_BATCH_HEADER_SIZE)
+ {
+ DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC batch header",
+ this->encoding.len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, 0);
+ goto fatal;
+ }
+
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint8 (reader, &version);
+ reader->read_uint8 (reader, &flags);
+ reader->read_uint8 (reader, &reserved);
+ reader->read_uint8 (reader, &type);
+ reader->read_uint32(reader, &batch_len);
+ reader->destroy(reader);
+
+ /* Version */
+ if (version != PB_TNC_VERSION)
+ {
+ DBG1(DBG_TNC, "unsupported TNCCS batch version 0x%02x", version);
+ msg = pb_error_msg_create(TRUE, PEN_IETF,
+ PB_ERROR_VERSION_NOT_SUPPORTED);
+ err_msg = (pb_error_msg_t*)msg;
+ err_msg->set_bad_version(err_msg, version);
+ goto fatal;
+ }
+
+ /* Directionality */
+ directionality = (flags & PB_TNC_BATCH_FLAG_D) != PB_TNC_BATCH_FLAG_NONE;
+ if (directionality == this->is_server)
+ {
+ DBG1(DBG_TNC, "wrong Directionality: batch is from a PB %s",
+ directionality ? "server" : "client");
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, 1);
+ goto fatal;
+ }
+
+ /* Batch Type */
+ this->type = type & 0x0F;
+ if (this->type > PB_BATCH_ROOF)
+ {
+ DBG1(DBG_TNC, "unknown PB-TNC batch type: %d", this->type);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, 3);
+ goto fatal;
+ }
+
+ if (!state_machine->receive_batch(state_machine, this->type))
+ {
+ DBG1(DBG_TNC, "unexpected PB-TNC batch type: %N",
+ pb_tnc_batch_type_names, this->type);
+ msg = pb_error_msg_create(TRUE, PEN_IETF,
+ PB_ERROR_UNEXPECTED_BATCH_TYPE);
+ goto fatal;
+ }
+ DBG1(DBG_TNC, "processing PB-TNC %N batch", pb_tnc_batch_type_names,
+ this->type);
+
+ /* Batch Length */
+ if (this->encoding.len != batch_len)
+ {
+ DBG1(DBG_TNC, "%u bytes of data is not equal to batch length of %u bytes",
+ this->encoding.len, batch_len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, 4);
+ goto fatal;
+ }
+
+ this->offset = PB_TNC_BATCH_HEADER_SIZE;
+
+ /* Register an empty CDATA batch with the state machine */
+ if (this->type == PB_BATCH_CDATA)
+ {
+ state_machine->set_empty_cdata(state_machine,
+ this->offset == this->encoding.len);
+ }
+ return SUCCESS;
+
+fatal:
+ this->errors->insert_last(this->errors, msg);
+ return FAILED;
+}
+
+static status_t process_tnc_msg(private_pb_tnc_batch_t *this)
+{
+ bio_reader_t *reader;
+ pb_tnc_msg_t *pb_tnc_msg, *msg;
+ u_int8_t flags;
+ u_int32_t vendor_id, msg_type, msg_len, offset;
+ chunk_t data, msg_value;
+ bool noskip_flag;
+ status_t status;
+
+ data = chunk_skip(this->encoding, this->offset);
+
+ if (data.len < PB_TNC_HEADER_SIZE)
+ {
+ DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message header",
+ data.len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset);
+ goto fatal;
+ }
+
+ reader = bio_reader_create(data);
+ reader->read_uint8 (reader, &flags);
+ reader->read_uint24(reader, &vendor_id);
+ reader->read_uint32(reader, &msg_type);
+ reader->read_uint32(reader, &msg_len);
+ reader->destroy(reader);
+
+ noskip_flag = (flags & PB_TNC_FLAG_NOSKIP) != PB_TNC_FLAG_NONE;
+
+ if (msg_len > data.len)
+ {
+ DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message", data.len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset + 8);
+ goto fatal;
+ }
+
+ if (vendor_id == PEN_RESERVED)
+ {
+ DBG1(DBG_TNC, "Vendor ID 0x%06x is reserved", PEN_RESERVED);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset + 1);
+ goto fatal;
+
+ }
+
+ if (msg_type == PB_TNC_RESERVED_MSG_TYPE)
+ {
+ DBG1(DBG_TNC, "PB-TNC message Type 0x%08x is reserved",
+ PB_TNC_RESERVED_MSG_TYPE);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset + 4);
+ goto fatal;
+ }
+
+
+ if (vendor_id != PEN_IETF || msg_type > PB_MSG_ROOF)
+ {
+ if (msg_len < PB_TNC_HEADER_SIZE)
+ {
+ DBG1(DBG_TNC, "%u bytes too small for PB-TNC message length",
+ msg_len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset + 8);
+ goto fatal;
+ }
+
+ if (noskip_flag)
+ {
+ DBG1(DBG_TNC, "reject PB-TNC message (Vendor ID 0x%06x / "
+ "Type 0x%08x)", vendor_id, msg_type);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset);
+ goto fatal;
+ }
+ else
+ {
+ DBG1(DBG_TNC, "ignore PB-TNC message (Vendor ID 0x%06x / "
+ "Type 0x%08x)", vendor_id, msg_type);
+ this->offset += msg_len;
+ return SUCCESS;
+ }
+ }
+ else
+ {
+ if (msg_type == PB_MSG_EXPERIMENTAL && noskip_flag)
+ {
+ DBG1(DBG_TNC, "reject PB-Experimental message with NOSKIP flag set");
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset);
+ goto fatal;
+ }
+ if (pb_tnc_msg_infos[msg_type].has_noskip_flag != TRUE_OR_FALSE &&
+ pb_tnc_msg_infos[msg_type].has_noskip_flag != noskip_flag)
+ {
+ DBG1(DBG_TNC, "%N message must%s have NOSKIP flag set",
+ pb_tnc_msg_type_names, msg_type,
+ pb_tnc_msg_infos[msg_type].has_noskip_flag ? "" : " not");
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset);
+ goto fatal;
+ }
+
+ if (msg_len < pb_tnc_msg_infos[msg_type].min_size ||
+ (pb_tnc_msg_infos[msg_type].exact_size &&
+ msg_len != pb_tnc_msg_infos[msg_type].min_size))
+ {
+ DBG1(DBG_TNC, "%N message length must be %s %u bytes but is %u bytes",
+ pb_tnc_msg_type_names, msg_type,
+ pb_tnc_msg_infos[msg_type].exact_size ? "exactly" : "at least",
+ pb_tnc_msg_infos[msg_type].min_size, msg_len);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset);
+ goto fatal;
+ }
+ }
+
+ if (pb_tnc_msg_infos[msg_type].in_result_batch &&
+ this->type != PB_BATCH_RESULT)
+ {
+ if (this->is_server)
+ {
+ DBG1(DBG_TNC,"reject %N message received from a PB-TNC client",
+ pb_tnc_msg_type_names, msg_type);
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset);
+ goto fatal;
+ }
+ else
+ {
+ DBG1(DBG_TNC,"ignore %N message not received within RESULT batch",
+ pb_tnc_msg_type_names, msg_type);
+ this->offset += msg_len;
+ return SUCCESS;
+ }
+ }
+
+ DBG2(DBG_TNC, "processing %N message (%u bytes)", pb_tnc_msg_type_names,
+ msg_type, msg_len);
+ data.len = msg_len;
+ msg_value = chunk_skip(data, PB_TNC_HEADER_SIZE);
+ pb_tnc_msg = pb_tnc_msg_create_from_data(msg_type, msg_value);
+
+ status = pb_tnc_msg->process(pb_tnc_msg, &offset);
+ if (status == FAILED || status == VERIFY_ERROR)
+ {
+ msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF,
+ PB_ERROR_INVALID_PARAMETER, this->offset + offset);
+ this->errors->insert_last(this->errors, msg);
+ }
+ if (status == FAILED)
+ {
+ pb_tnc_msg->destroy(pb_tnc_msg);
+ return FAILED;
+ }
+ this->messages->insert_last(this->messages, pb_tnc_msg);
+ this->offset += msg_len;
+ return status;
+
+fatal:
+ this->errors->insert_last(this->errors, msg);
+ return FAILED;
+}
+
+METHOD(pb_tnc_batch_t, process, status_t,
+ private_pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine)
+{
+ status_t status;
+
+ status = process_batch_header(this, state_machine);
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ while (this->offset < this->encoding.len)
+ {
+ switch (process_tnc_msg(this))
+ {
+ case FAILED:
+ return FAILED;
+ case VERIFY_ERROR:
+ status = VERIFY_ERROR;
+ break;
+ case SUCCESS:
+ default:
+ break;
+ }
+ }
+ return status;
+}
+
+METHOD(pb_tnc_batch_t, create_msg_enumerator, enumerator_t*,
+ private_pb_tnc_batch_t *this)
+{
+ return this->messages->create_enumerator(this->messages);
+}
+
+METHOD(pb_tnc_batch_t, create_error_enumerator, enumerator_t*,
+ private_pb_tnc_batch_t *this)
+{
+ return this->errors->create_enumerator(this->errors);
+}
+
+METHOD(pb_tnc_batch_t, destroy, void,
+ private_pb_tnc_batch_t *this)
+{
+ this->messages->destroy_offset(this->messages,
+ offsetof(pb_tnc_msg_t, destroy));
+ this->errors->destroy_offset(this->errors,
+ offsetof(pb_tnc_msg_t, destroy));
+ free(this->encoding.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type,
+ size_t max_batch_len)
+{
+ private_pb_tnc_batch_t *this;
+
+ INIT(this,
+ .public = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .add_msg = _add_msg,
+ .build = _build,
+ .process = _process,
+ .create_msg_enumerator = _create_msg_enumerator,
+ .create_error_enumerator = _create_error_enumerator,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ .type = type,
+ .max_batch_len = max_batch_len,
+ .batch_len = PB_TNC_BATCH_HEADER_SIZE,
+ .messages = linked_list_create(),
+ .errors = linked_list_create(),
+ );
+
+ DBG2(DBG_TNC, "creating PB-TNC %N batch", pb_tnc_batch_type_names, type);
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data)
+{
+ private_pb_tnc_batch_t *this;
+
+ INIT(this,
+ .public = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .add_msg = _add_msg,
+ .build = _build,
+ .process = _process,
+ .create_msg_enumerator = _create_msg_enumerator,
+ .create_error_enumerator = _create_error_enumerator,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ .messages = linked_list_create(),
+ .errors = linked_list_create(),
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h
new file mode 100644
index 000000000..60cef7735
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010-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
+ * 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.
+ */
+
+/**
+ * @defgroup pb_tnc_batch pb_tnc_batch
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_TNC_BATCH_H_
+#define PB_TNC_BATCH_H_
+
+typedef enum pb_tnc_batch_type_t pb_tnc_batch_type_t;
+typedef struct pb_tnc_batch_t pb_tnc_batch_t;
+
+#include "messages/pb_tnc_msg.h"
+#include "state_machine/pb_tnc_state_machine.h"
+
+#include <library.h>
+
+/**
+ * PB-TNC Batch Types as defined in section 4.1 of RFC 5793
+ */
+enum pb_tnc_batch_type_t {
+ PB_BATCH_NONE = 0, /* for internal use only */
+ PB_BATCH_CDATA = 1,
+ PB_BATCH_SDATA = 2,
+ PB_BATCH_RESULT = 3,
+ PB_BATCH_CRETRY = 4,
+ PB_BATCH_SRETRY = 5,
+ PB_BATCH_CLOSE = 6,
+ PB_BATCH_ROOF = 6
+};
+
+/**
+ * enum name for pb_tnc_batch_type_t.
+ */
+extern enum_name_t *pb_tnc_batch_type_names;
+
+/**
+ * Interface for all PB-TNC Batch Types.
+ */
+struct pb_tnc_batch_t {
+
+ /**
+ * Get the PB-TNC Message Type
+ *
+ * @return PB-TNC batch type
+ */
+ pb_tnc_batch_type_t (*get_type)(pb_tnc_batch_t *this);
+
+ /**
+ * Get the encoding of the PB-TNC Batch
+ *
+ * @return encoded PB-TNC batch
+ */
+ chunk_t (*get_encoding)(pb_tnc_batch_t *this);
+
+ /**
+ * Add a PB-TNC Message
+ *
+ * @param msg PB-TNC message to be addedd
+ * @return TRUE if message fit into batch and was added
+ */
+ bool (*add_msg)(pb_tnc_batch_t *this, pb_tnc_msg_t* msg);
+
+ /**
+ * Build the PB-TNC Batch
+ */
+ void (*build)(pb_tnc_batch_t *this);
+
+ /**
+ * Process the PB-TNC Batch
+ *
+ * @param PB-TNC state machine
+ * @return return processing status
+ */
+ status_t (*process)(pb_tnc_batch_t *this,
+ pb_tnc_state_machine_t *state_machine);
+
+ /**
+ * Enumerates over all PB-TNC Messages
+ *
+ * @return return message enumerator
+ */
+ enumerator_t* (*create_msg_enumerator)(pb_tnc_batch_t *this);
+
+ /**
+ * Enumerates over all parsing errors
+ *
+ * @return return error enumerator
+ */
+ enumerator_t* (*create_error_enumerator)(pb_tnc_batch_t *this);
+
+ /**
+ * Destroys a pb_tnc_batch_t object.
+ */
+ void (*destroy)(pb_tnc_batch_t *this);
+};
+
+/**
+ * Create an empty PB-TNC Batch of a given type
+ *
+ * @param is_server TRUE if server, FALSE if client
+ * @param type PB-TNC batch type
+ * @param max_batch_len maximum size the PB-TNC batch
+ */
+pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type,
+ size_t max_batch_len);
+
+/**
+ * Create an unprocessed PB-TNC Batch from data
+ *
+ * @param is_server TRUE if server, FALSE if client
+ * @param data encoded PB-TNC batch
+ */
+pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data);
+
+#endif /** PB_TNC_BATCH_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.c
new file mode 100644
index 000000000..cdd0d0d0d
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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 "pb_access_recommendation_msg.h"
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/debug.h>
+
+ENUM(pb_access_recommendation_code_names, PB_REC_ACCESS_ALLOWED, PB_REC_QUARANTINED,
+ "Access Allowed",
+ "Access Denied",
+ "Quarantined"
+);
+
+typedef struct private_pb_access_recommendation_msg_t private_pb_access_recommendation_msg_t;
+
+/**
+ * PB-Access-Recommendation message (see section 4.7 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Access Recommendation Code |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define ACCESS_RECOMMENDATION_RESERVED 0x0000
+#define ACCESS_RECOMMENDATION_MSG_SIZE 4
+/**
+ * Private data of a pb_access_recommendation_msg_t object.
+ *
+ */
+struct private_pb_access_recommendation_msg_t {
+ /**
+ * Public pb_access_recommendation_msg_t interface.
+ */
+ pb_access_recommendation_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Access recommendation code
+ */
+ u_int16_t recommendation;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_access_recommendation_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_access_recommendation_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_access_recommendation_msg_t *this)
+{
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+ writer = bio_writer_create(ACCESS_RECOMMENDATION_MSG_SIZE);
+ writer->write_uint16(writer, ACCESS_RECOMMENDATION_RESERVED);
+ writer->write_uint16(writer, this->recommendation);
+ this->encoding = writer->get_buf(writer);
+ this->encoding = chunk_clone(this->encoding);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_access_recommendation_msg_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int16_t reserved;
+
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint16(reader, &reserved);
+ reader->read_uint16(reader, &this->recommendation);
+ reader->destroy(reader);
+
+ if (this->recommendation < PB_REC_ACCESS_ALLOWED ||
+ this->recommendation > PB_REC_QUARANTINED)
+ {
+ DBG1(DBG_TNC, "invalid access recommendation code (%u)",
+ this->recommendation);
+ *offset = 2;
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_access_recommendation_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this);
+}
+
+METHOD(pb_access_recommendation_msg_t, get_access_recommendation, u_int16_t,
+ private_pb_access_recommendation_msg_t *this)
+{
+ return this->recommendation;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_access_recommendation_msg_create_from_data(chunk_t data)
+{
+ private_pb_access_recommendation_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_access_recommendation = _get_access_recommendation,
+ },
+ .type = PB_MSG_ACCESS_RECOMMENDATION,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_access_recommendation_msg_create(u_int16_t recommendation)
+{
+ private_pb_access_recommendation_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_access_recommendation = _get_access_recommendation,
+ },
+ .type = PB_MSG_ACCESS_RECOMMENDATION,
+ .recommendation = recommendation,
+ );
+
+ return &this->public.pb_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.h
new file mode 100644
index 000000000..01b83cfd7
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_access_recommendation_msg.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_access_recommendation_msg pb_access_recommendation_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_ACCESS_RECOMMENDATION_MSG_H_
+#define PB_ACCESS_RECOMMENDATION_MSG_H_
+
+typedef enum pb_access_recommendation_code_t pb_access_recommendation_code_t;
+typedef struct pb_access_recommendation_msg_t pb_access_recommendation_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * PB Access Recommendation Codes as defined in section 4.7 of RFC 5793
+ */
+enum pb_access_recommendation_code_t {
+ PB_REC_ACCESS_ALLOWED = 1,
+ PB_REC_ACCESS_DENIED = 2,
+ PB_REC_QUARANTINED = 3,
+};
+
+/**
+ * enum name for pb_access_recommendation_code_t.
+ */
+extern enum_name_t *pb_access_recommendation_code_names;
+
+
+/**
+ * Class representing the PB-Access-Recommendation message type.
+ */
+struct pb_access_recommendation_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get PB Access Recommendation
+ *
+ * @return PB Access Recommendation
+ */
+ u_int16_t (*get_access_recommendation)(pb_access_recommendation_msg_t *this);
+};
+
+/**
+ * Create a PB-Access-Recommendation message from parameters
+ *
+ * @param recommendation Access Recommendation code
+ */
+pb_tnc_msg_t* pb_access_recommendation_msg_create(u_int16_t recommendation);
+
+/**
+ * Create an unprocessed PB-Access-Recommendation message from raw data
+ *
+ * @param data PB-Access-Recommendation message data
+ */
+pb_tnc_msg_t* pb_access_recommendation_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.c
new file mode 100644
index 000000000..4e50446be
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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 "pb_assessment_result_msg.h"
+
+#include <tncifimv.h>
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/debug.h>
+
+typedef struct private_pb_assessment_result_msg_t private_pb_assessment_result_msg_t;
+
+/**
+ * PB-Assessment-Result message (see section 4.6 of RFC 5793)
+ *
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Assessment Result |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define ASSESSMENT_RESULT_MSG_SIZE 4
+
+/**
+ * Private data of a pb_assessment_result_msg_t object.
+ *
+ */
+struct private_pb_assessment_result_msg_t {
+ /**
+ * Public pb_assessment_result_msg_t interface.
+ */
+ pb_assessment_result_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Assessment result code
+ */
+ u_int32_t assessment_result;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_assessment_result_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_assessment_result_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_assessment_result_msg_t *this)
+{
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+ writer = bio_writer_create(ASSESSMENT_RESULT_MSG_SIZE);
+ writer->write_uint32(writer, this->assessment_result);
+ this->encoding = writer->get_buf(writer);
+ this->encoding = chunk_clone(this->encoding);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_assessment_result_msg_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint32(reader, &this->assessment_result);
+ reader->destroy(reader);
+
+ if (this->assessment_result < TNC_IMV_EVALUATION_RESULT_COMPLIANT ||
+ this->assessment_result > TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
+ {
+ DBG1(DBG_TNC, "invalid assessment result (%u)",
+ this->assessment_result);
+ *offset = 0;
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_assessment_result_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this);
+}
+
+METHOD(pb_assessment_result_msg_t, get_assessment_result, u_int32_t,
+ private_pb_assessment_result_msg_t *this)
+{
+ return this->assessment_result;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_assessment_result_msg_create_from_data(chunk_t data)
+{
+ private_pb_assessment_result_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_assessment_result = _get_assessment_result,
+ },
+ .type = PB_MSG_ASSESSMENT_RESULT,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_assessment_result_msg_create(u_int32_t assessment_result)
+{
+ private_pb_assessment_result_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_assessment_result = _get_assessment_result,
+ },
+ .type = PB_MSG_ASSESSMENT_RESULT,
+ .assessment_result = assessment_result,
+ );
+
+ return &this->public.pb_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.h
new file mode 100644
index 000000000..d2b005114
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_assessment_result_msg.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_assessment_result_msg pb_assessment_result_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_ASSESSMENT_RESULT_MSG_H_
+#define PB_ASSESSMENT_RESULT_MSG_H_
+
+typedef struct pb_assessment_result_msg_t pb_assessment_result_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * Class representing the PB-Assessment-Result message type.
+ */
+struct pb_assessment_result_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get PB Assessment result
+ *
+ * @return PB Assessment result
+ */
+ u_int32_t (*get_assessment_result)(pb_assessment_result_msg_t *this);
+};
+
+/**
+ * Create a PB-Assessment-Result message from parameters
+ *
+ * @param assessment_result Assessment result code
+ */
+pb_tnc_msg_t* pb_assessment_result_msg_create(u_int32_t assessment_result);
+
+/**
+ * Create an unprocessed PB-Assessment-Result message from raw data
+ *
+ * @param data PB-Assessment-Result message data
+ */
+pb_tnc_msg_t* pb_assessment_result_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.c
new file mode 100644
index 000000000..d048f437c
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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 "pb_error_msg.h"
+
+#include <tnc/tnccs/tnccs.h>
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <pen/pen.h>
+#include <utils/debug.h>
+
+ENUM(pb_tnc_error_code_names, PB_ERROR_UNEXPECTED_BATCH_TYPE,
+ PB_ERROR_VERSION_NOT_SUPPORTED,
+ "Unexpected Batch Type",
+ "Invalid Parameter",
+ "Local Error",
+ "Unsupported Mandatory Message",
+ "Version Not Supported"
+);
+
+typedef struct private_pb_error_msg_t private_pb_error_msg_t;
+
+/**
+ * PB-Error message (see section 4.9 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | Error Code Vendor ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Parameters (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define ERROR_FLAG_NONE 0x00
+#define ERROR_FLAG_FATAL (1<<7)
+#define ERROR_RESERVED 0x0000
+#define ERROR_HEADER_SIZE 8
+
+/**
+ * Private data of a pb_error_msg_t object.
+ *
+ */
+struct private_pb_error_msg_t {
+ /**
+ * Public pb_error_msg_t interface.
+ */
+ pb_error_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Fatal flag
+ */
+ bool fatal;
+
+ /**
+ * PB Error Code Vendor ID
+ */
+ u_int32_t vendor_id;
+
+ /**
+ * PB Error Code
+ */
+ u_int16_t error_code;
+
+ /**
+ * PB Error Offset
+ */
+ u_int32_t error_offset;
+
+ /**
+ * Bad PB-TNC version received
+ */
+ u_int8_t bad_version;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+
+ /**
+ * reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_error_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_error_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_error_msg_t *this)
+{
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+
+ /* build message header */
+ writer = bio_writer_create(ERROR_HEADER_SIZE);
+ writer->write_uint8 (writer, this->fatal ?
+ ERROR_FLAG_FATAL : ERROR_FLAG_NONE);
+ writer->write_uint24(writer, this->vendor_id);
+ writer->write_uint16(writer, this->error_code);
+ writer->write_uint16(writer, ERROR_RESERVED);
+
+ /* build message body */
+ if (this->error_code == PB_ERROR_VERSION_NOT_SUPPORTED)
+ {
+ /* Bad version */
+ writer->write_uint8(writer, this->bad_version);
+ writer->write_uint8(writer, PB_TNC_VERSION); /* Max version */
+ writer->write_uint8(writer, PB_TNC_VERSION); /* Min version */
+ writer->write_uint8(writer, 0x00); /* Reserved */
+ }
+ else
+ {
+ /* Error Offset */
+ writer->write_uint32(writer, this->error_offset);
+ }
+ this->encoding = writer->get_buf(writer);
+ this->encoding = chunk_clone(this->encoding);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_error_msg_t *this, u_int32_t *offset)
+{
+ u_int8_t flags, max_version, min_version;
+ u_int16_t reserved;
+ bio_reader_t *reader;
+
+ if (this->encoding.len < ERROR_HEADER_SIZE)
+ {
+ DBG1(DBG_TNC,"%N message is shorter than header size of %u bytes",
+ pb_tnc_msg_type_names, PB_MSG_ERROR, ERROR_HEADER_SIZE);
+ *offset = 0;
+ return FAILED;
+ }
+
+ /* process message header */
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint8 (reader, &flags);
+ reader->read_uint24(reader, &this->vendor_id);
+ reader->read_uint16(reader, &this->error_code);
+ reader->read_uint16(reader, &reserved);
+ this->fatal = (flags & ERROR_FLAG_FATAL) != ERROR_FLAG_NONE;
+
+ if (this->vendor_id == PEN_IETF && reader->remaining(reader) == 4)
+ {
+ if (this->error_code == PB_ERROR_VERSION_NOT_SUPPORTED)
+ {
+ reader->read_uint8(reader, &this->bad_version);
+ reader->read_uint8(reader, &max_version);
+ reader->read_uint8(reader, &min_version);
+ }
+ else
+ {
+ reader->read_uint32(reader, &this->error_offset);
+ }
+ }
+ reader->destroy(reader);
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, get_ref, pb_tnc_msg_t*,
+ private_pb_error_msg_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pb_interface;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_error_msg_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->encoding.ptr);
+ free(this);
+ }
+}
+
+METHOD(pb_error_msg_t, get_fatal_flag, bool,
+ private_pb_error_msg_t *this)
+{
+ return this->fatal;
+}
+
+METHOD(pb_error_msg_t, get_vendor_id, u_int32_t,
+ private_pb_error_msg_t *this)
+{
+ return this->vendor_id;
+}
+
+METHOD(pb_error_msg_t, get_error_code, u_int16_t,
+ private_pb_error_msg_t *this)
+{
+ return this->error_code;
+}
+
+METHOD(pb_error_msg_t, get_offset, u_int32_t,
+ private_pb_error_msg_t *this)
+{
+ return this->error_offset;
+}
+
+METHOD(pb_error_msg_t, get_bad_version, u_int8_t,
+ private_pb_error_msg_t *this)
+{
+ return this->bad_version;
+}
+
+METHOD(pb_error_msg_t, set_bad_version, void,
+ private_pb_error_msg_t *this, u_int8_t version)
+{
+ this->bad_version = version;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t* pb_error_msg_create(bool fatal, u_int32_t vendor_id,
+ pb_tnc_error_code_t error_code)
+{
+ private_pb_error_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_fatal_flag = _get_fatal_flag,
+ .get_vendor_id = _get_vendor_id,
+ .get_error_code = _get_error_code,
+ .get_offset = _get_offset,
+ .get_bad_version = _get_bad_version,
+ .set_bad_version = _set_bad_version,
+ },
+ .type = PB_MSG_ERROR,
+ .ref = 1,
+ .fatal = fatal,
+ .vendor_id = vendor_id,
+ .error_code = error_code,
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t* pb_error_msg_create_with_offset(bool fatal, u_int32_t vendor_id,
+ pb_tnc_error_code_t error_code,
+ u_int32_t error_offset)
+{
+ private_pb_error_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_fatal_flag = _get_fatal_flag,
+ .get_vendor_id = _get_vendor_id,
+ .get_error_code = _get_error_code,
+ .get_offset = _get_offset,
+ .get_bad_version = _get_bad_version,
+ .set_bad_version = _set_bad_version,
+ },
+ .type = PB_MSG_ERROR,
+ .ref = 1,
+ .fatal = fatal,
+ .vendor_id = vendor_id,
+ .error_code = error_code,
+ .error_offset = error_offset,
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_error_msg_create_from_data(chunk_t data)
+{
+ private_pb_error_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_fatal_flag = _get_fatal_flag,
+ .get_vendor_id = _get_vendor_id,
+ .get_error_code = _get_error_code,
+ .get_offset = _get_offset,
+ .get_bad_version = _get_bad_version,
+ .set_bad_version = _set_bad_version,
+ },
+ .type = PB_MSG_ERROR,
+ .ref = 1,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.h
new file mode 100644
index 000000000..8b92742b5
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_error_msg.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_error_msg pb_error_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_ERROR_MSG_H_
+#define PB_ERROR_MSG_H_
+
+typedef enum pb_tnc_error_code_t pb_tnc_error_code_t;
+typedef struct pb_error_msg_t pb_error_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * PB-TNC Error Codes as defined in section 4.9.1 of RFC 5793
+ */
+enum pb_tnc_error_code_t {
+ PB_ERROR_UNEXPECTED_BATCH_TYPE = 0,
+ PB_ERROR_INVALID_PARAMETER = 1,
+ PB_ERROR_LOCAL_ERROR = 2,
+ PB_ERROR_UNSUPPORTED_MANDATORY_MSG = 3,
+ PB_ERROR_VERSION_NOT_SUPPORTED = 4
+};
+
+/**
+ * enum name for pb_tnc_error_code_t.
+ */
+extern enum_name_t *pb_tnc_error_code_names;
+
+/**
+ * Class representing the PB-Error message type.
+ */
+struct pb_error_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get the fatal flag
+ *
+ * @return fatal flag
+ */
+ bool (*get_fatal_flag)(pb_error_msg_t *this);
+
+ /**
+ * Get PB Error code Vendor ID
+ *
+ * @return PB Error Code Vendor ID
+ */
+ u_int32_t (*get_vendor_id)(pb_error_msg_t *this);
+
+ /**
+ * Get PB Error Code
+ *
+ * @return PB Error Code
+ */
+ u_int16_t (*get_error_code)(pb_error_msg_t *this);
+
+ /**
+ * Get the PB Error Offset
+ *
+ * @return PB Error Offset
+ */
+ u_int32_t (*get_offset)(pb_error_msg_t *this);
+
+ /**
+ * Get the PB Bad Version
+ *
+ * @return PB Bad Version
+ */
+ u_int8_t (*get_bad_version)(pb_error_msg_t *this);
+
+ /**
+ * Set the PB Bad Version
+ *
+ * @param version PB Bad Version
+ */
+ void (*set_bad_version)(pb_error_msg_t *this, u_int8_t version);
+};
+
+/**
+ * Create a PB-Error message from parameters
+ *
+ * @param fatal fatal flag
+ * @param vendor_id Error Code Vendor ID
+ * @param error_code Error Code
+ */
+pb_tnc_msg_t* pb_error_msg_create(bool fatal, u_int32_t vendor_id,
+ pb_tnc_error_code_t error_code);
+
+/**
+ * Create a PB-Error message from parameters with offset field
+ *
+ * @param fatal fatal flag
+ * @param vendor_id Error Code Vendor ID
+ * @param error_code Error Code
+ * @param error_offset Error Offset
+ */
+pb_tnc_msg_t* pb_error_msg_create_with_offset(bool fatal, u_int32_t vendor_id,
+ pb_tnc_error_code_t error_code,
+ u_int32_t error_offset);
+
+/**
+ * Create an unprocessed PB-Error message from raw data
+ *
+ * @param data PB-Error message data
+ */
+pb_tnc_msg_t* pb_error_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.c
new file mode 100644
index 000000000..7dfba136f
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.c
@@ -0,0 +1,102 @@
+/*
+ * 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 "pb_experimental_msg.h"
+
+typedef struct private_pb_experimental_msg_t private_pb_experimental_msg_t;
+
+/**
+ * Private data of a pb_experimental_msg_t object.
+ *
+ */
+struct private_pb_experimental_msg_t {
+ /**
+ * Public pb_experimental_msg_t interface.
+ */
+ pb_experimental_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_experimental_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_experimental_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_experimental_msg_t *this)
+{
+ /* nothing to do since message contents equal encoding */
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_experimental_msg_t *this, u_int32_t *offset)
+{
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_experimental_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_experimental_msg_create_from_data(chunk_t data)
+{
+ private_pb_experimental_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ },
+ .type = PB_MSG_EXPERIMENTAL,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_experimental_msg_create(chunk_t body)
+{
+ return pb_experimental_msg_create_from_data(body);
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.h
new file mode 100644
index 000000000..b1cc4f46e
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_experimental_msg.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_experimental_msg pb_experimental_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_EXPERIMENTAL_MSG_H_
+#define PB_EXPERIMENTAL_MSG_H_
+
+typedef struct pb_experimental_msg_t pb_experimental_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * Class representing the PB-Experimental message type.
+ */
+struct pb_experimental_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+};
+
+/**
+ * Create a PB-Experimental message from parameters
+ *
+ * @param body message body
+ */
+pb_tnc_msg_t* pb_experimental_msg_create(chunk_t body);
+
+/**
+ * Create an unprocessed PB-Experimental message from raw data
+ *
+ * @param data PB-Experimental message data
+ */
+pb_tnc_msg_t* pb_experimental_msg_create_from_data(chunk_t data);
+
+#endif /** PB_EXPERIMENTAL_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.c
new file mode 100644
index 000000000..70a03cdc5
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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 "pb_language_preference_msg.h"
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/debug.h>
+
+typedef struct private_pb_language_preference_msg_t private_pb_language_preference_msg_t;
+
+/**
+ * PB-Language-Preference message (see section 4.10 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Language Preference (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define PB_LANG_PREFIX "Accept-Language: "
+#define PB_LANG_PREFIX_LEN strlen(PB_LANG_PREFIX)
+
+/**
+ * Private data of a pb_language_preference_msg_t object.
+ *
+ */
+struct private_pb_language_preference_msg_t {
+ /**
+ * Public pb_access_recommendation_msg_t interface.
+ */
+ pb_language_preference_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Language preference
+ */
+ chunk_t language_preference;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_language_preference_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_language_preference_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_language_preference_msg_t *this)
+{
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+ this->encoding = chunk_cat("cc",
+ chunk_create(PB_LANG_PREFIX, PB_LANG_PREFIX_LEN),
+ this->language_preference);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_language_preference_msg_t *this, u_int32_t *offset)
+{
+ chunk_t lang;
+
+ if (this->encoding.len >= PB_LANG_PREFIX_LEN &&
+ memeq(this->encoding.ptr, PB_LANG_PREFIX, PB_LANG_PREFIX_LEN))
+ {
+ lang = chunk_skip(this->encoding, PB_LANG_PREFIX_LEN);
+ this->language_preference = lang.len ? chunk_clone(lang) : chunk_empty;
+ }
+ else
+ {
+ DBG1(DBG_TNC, "language preference must be preceded by '%s'",
+ PB_LANG_PREFIX);
+ *offset = 0;
+ return FAILED;
+ }
+
+ if (this->language_preference.len &&
+ this->language_preference.ptr[this->language_preference.len-1] == '\0')
+ {
+ DBG1(DBG_TNC, "language preference must not be null terminated");
+ *offset = PB_LANG_PREFIX_LEN + this->language_preference.len - 1;
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_language_preference_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this->language_preference.ptr);
+ free(this);
+}
+
+METHOD(pb_language_preference_msg_t, get_language_preference, chunk_t,
+ private_pb_language_preference_msg_t *this)
+{
+ return this->language_preference;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_language_preference_msg_create_from_data(chunk_t data)
+{
+ private_pb_language_preference_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_language_preference = _get_language_preference,
+ },
+ .type = PB_MSG_LANGUAGE_PREFERENCE,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_language_preference_msg_create(chunk_t language_preference)
+{
+ private_pb_language_preference_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_language_preference = _get_language_preference,
+ },
+ .type = PB_MSG_LANGUAGE_PREFERENCE,
+ .language_preference = chunk_clone(language_preference),
+ );
+
+ return &this->public.pb_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.h
new file mode 100644
index 000000000..17106f6fa
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_language_preference_msg.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_language_preference_msg pb_language_preference_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_LANGUAGE_PREFERENCE_MSG_H_
+#define PB_LANGUAGE_PREFERENCE_MSG_H_
+
+typedef struct pb_language_preference_msg_t pb_language_preference_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * Class representing the PB-Language-Preference message type.
+ */
+struct pb_language_preference_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get PB Language Preference
+ *
+ * @return Language preference
+ */
+ chunk_t (*get_language_preference)(pb_language_preference_msg_t *this);
+};
+
+/**
+ * Create a PB-Language-Preference message from parameters
+ *
+ * @param language_preference Preferred language(s)
+ */
+pb_tnc_msg_t* pb_language_preference_msg_create(chunk_t language_preference);
+
+/**
+ * Create an unprocessed PB-Language-Preference message from raw data
+ *
+ * @param data PB-Language-Preference message data
+ */
+pb_tnc_msg_t* pb_language_preference_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.c
new file mode 100644
index 000000000..aa5e9c723
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyanbuu
+ * 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 "pb_pa_msg.h"
+
+#include <tnc/tnccs/tnccs.h>
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <pen/pen.h>
+#include <utils/debug.h>
+
+typedef struct private_pb_pa_msg_t private_pb_pa_msg_t;
+
+/**
+ * PB-PA message
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | PA Message Vendor ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PA Subtype |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Posture Collector Identifier | Posture Validator Identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | PA Message Body (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define PA_FLAG_NONE 0x00
+#define PA_FLAG_EXCL (1<<7)
+#define PA_RESERVED_SUBTYPE 0xffffffff
+
+
+/**
+ * Private data of a pb_pa_msg_t object.
+ *
+ */
+struct private_pb_pa_msg_t {
+ /**
+ * Public pb_pa_msg_t interface.
+ */
+ pb_pa_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Exclusive flag
+ */
+ bool excl;
+
+ /**
+ * Vendor-specific PA Subtype
+ */
+ pen_type_t subtype;
+
+ /**
+ * Posture Validator Identifier
+ */
+ u_int16_t collector_id;
+
+ /**
+ * Posture Validator Identifier
+ */
+ u_int16_t validator_id;
+
+ /**
+ * PA Message Body
+ */
+ chunk_t msg_body;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_pa_msg_t *this)
+{
+ chunk_t msg_header;
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+
+ /* build message header */
+ writer = bio_writer_create(64);
+ writer->write_uint8 (writer, this->excl ? PA_FLAG_EXCL : PA_FLAG_NONE);
+ writer->write_uint24(writer, this->subtype.vendor_id);
+ writer->write_uint32(writer, this->subtype.type);
+ writer->write_uint16(writer, this->collector_id);
+ writer->write_uint16(writer, this->validator_id);
+ msg_header = writer->get_buf(writer);
+
+ /* create encoding by concatenating message header and message body */
+ this->encoding = chunk_cat("cc", msg_header, this->msg_body);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_pa_msg_t *this, u_int32_t *offset)
+{
+ u_int8_t flags;
+ size_t msg_body_len;
+ bio_reader_t *reader;
+
+ /* process message header */
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint8 (reader, &flags);
+ reader->read_uint24(reader, &this->subtype.vendor_id);
+ reader->read_uint32(reader, &this->subtype.type);
+ reader->read_uint16(reader, &this->collector_id);
+ reader->read_uint16(reader, &this->validator_id);
+ this->excl = ((flags & PA_FLAG_EXCL) != PA_FLAG_NONE);
+
+ /* process message body */
+ msg_body_len = reader->remaining(reader);
+ if (msg_body_len)
+ {
+ reader->read_data(reader, msg_body_len, &this->msg_body);
+ this->msg_body = chunk_clone(this->msg_body);
+ }
+ reader->destroy(reader);
+
+ if (this->subtype.vendor_id == PEN_RESERVED)
+ {
+ DBG1(DBG_TNC, "Vendor ID 0x%06x is reserved", PEN_RESERVED);
+ *offset = 1;
+ return FAILED;
+ }
+
+ if (this->subtype.type == PA_RESERVED_SUBTYPE)
+ {
+ DBG1(DBG_TNC, "PA Subtype 0x%08x is reserved", PA_RESERVED_SUBTYPE);
+ *offset = 4;
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_pa_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this->msg_body.ptr);
+ free(this);
+}
+
+METHOD(pb_pa_msg_t, get_subtype, pen_type_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->subtype;
+}
+
+METHOD(pb_pa_msg_t, get_collector_id, u_int16_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->collector_id;
+}
+
+METHOD(pb_pa_msg_t, get_validator_id, u_int16_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->validator_id;
+}
+
+METHOD(pb_pa_msg_t, get_body, chunk_t,
+ private_pb_pa_msg_t *this)
+{
+ return this->msg_body;
+}
+
+METHOD(pb_pa_msg_t, get_exclusive_flag, bool,
+ private_pb_pa_msg_t *this)
+{
+ return this->excl;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data)
+{
+ private_pb_pa_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_subtype = _get_subtype,
+ .get_collector_id = _get_collector_id,
+ .get_validator_id = _get_validator_id,
+ .get_body = _get_body,
+ .get_exclusive_flag = _get_exclusive_flag,
+ },
+ .type = PB_MSG_PA,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype,
+ u_int16_t collector_id, u_int16_t validator_id,
+ bool excl, chunk_t msg_body)
+{
+ private_pb_pa_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_subtype= _get_subtype,
+ .get_collector_id = _get_collector_id,
+ .get_validator_id = _get_validator_id,
+ .get_body = _get_body,
+ .get_exclusive_flag = _get_exclusive_flag,
+ },
+ .type = PB_MSG_PA,
+ .subtype = { vendor_id, subtype },
+ .collector_id = collector_id,
+ .validator_id = validator_id,
+ .excl = excl,
+ .msg_body = chunk_clone(msg_body),
+ );
+
+ return &this->public.pb_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.h
new file mode 100644
index 000000000..5c9b7c0bf
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_pa_msg.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup pb_pa_msg pb_pa_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_PA_MSG_H_
+#define PB_PA_MSG_H_
+
+typedef struct pb_pa_msg_t pb_pa_msg_t;
+
+#include "pb_tnc_msg.h"
+
+#include <pen/pen.h>
+
+/**
+ * Class representing the PB-PA message type.
+ */
+struct pb_pa_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get PA Message Vendor ID and Subtype
+ *
+ * @return Vendor-specific PA Subtype
+ */
+ pen_type_t (*get_subtype)(pb_pa_msg_t *this);
+
+ /**
+ * Get Posture Collector ID
+ *
+ * @return Posture Collector ID
+ */
+ u_int16_t (*get_collector_id)(pb_pa_msg_t *this);
+
+ /**
+ * Get Posture Validator ID
+ *
+ * @return Posture Validator ID
+ */
+ u_int16_t (*get_validator_id)(pb_pa_msg_t *this);
+
+ /**
+ * Get the PA Message Body
+ *
+ * @return PA Message Body
+ */
+ chunk_t (*get_body)(pb_pa_msg_t *this);
+
+ /**
+ * Get the exclusive flag
+ *
+ * @return exclusive flag
+ */
+ bool (*get_exclusive_flag)(pb_pa_msg_t *this);
+
+};
+
+/**
+ * Create a PB-PA message from parameters
+ *
+ * @param vendor_id PA Message Vendor ID
+ * @param subtype PA Subtype
+ * @param collector_id Posture Collector ID
+ * @param validator_id Posture Validator ID
+ * @param excl Exclusive Flag
+ * @param msg_body PA Message Body
+ */
+pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype,
+ u_int16_t collector_id, u_int16_t validator_id,
+ bool excl, chunk_t msg_body);
+
+/**
+ * Create an unprocessed PB-PA message from raw data
+ *
+ * @param data PB-PA message data
+ */
+pb_tnc_msg_t* pb_pa_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.c
new file mode 100644
index 000000000..935c52d7b
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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 "pb_reason_string_msg.h"
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/debug.h>
+
+typedef struct private_pb_reason_string_msg_t private_pb_reason_string_msg_t;
+
+/**
+ * PB-Language-Preference message (see section 4.11 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reason String Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reason String (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Lang Code Len | Reason String Language Code (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/**
+ * Private data of a pb_reason_string_msg_t object.
+ *
+ */
+struct private_pb_reason_string_msg_t {
+ /**
+ * Public pb_reason_string_msg_t interface.
+ */
+ pb_reason_string_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Reason string
+ */
+ chunk_t reason_string;
+
+ /**
+ * Language code
+ */
+ chunk_t language_code;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_reason_string_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_reason_string_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_reason_string_msg_t *this)
+{
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+ writer = bio_writer_create(64);
+ writer->write_data32(writer, this->reason_string);
+ writer->write_data8 (writer, this->language_code);
+
+ this->encoding = writer->get_buf(writer);
+ this->encoding = chunk_clone(this->encoding);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_reason_string_msg_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+
+ reader = bio_reader_create(this->encoding);
+ if (!reader->read_data32(reader, &this->reason_string))
+ {
+ DBG1(DBG_TNC, "could not parse reason string");
+ reader->destroy(reader);
+ *offset = 0;
+ return FAILED;
+ };
+ this->reason_string = chunk_clone(this->reason_string);
+
+ if (this->reason_string.len &&
+ this->reason_string.ptr[this->reason_string.len-1] == '\0')
+ {
+ DBG1(DBG_TNC, "reason string must not be null terminated");
+ reader->destroy(reader);
+ *offset = 3 + this->reason_string.len;
+ return FAILED;
+ }
+
+ if (!reader->read_data8(reader, &this->language_code))
+ {
+ DBG1(DBG_TNC, "could not parse language code");
+ reader->destroy(reader);
+ *offset = 4 + this->reason_string.len;
+ return FAILED;
+ };
+ this->language_code = chunk_clone(this->language_code);
+ reader->destroy(reader);
+
+ if (this->language_code.len &&
+ this->language_code.ptr[this->language_code.len-1] == '\0')
+ {
+ DBG1(DBG_TNC, "language code must not be null terminated");
+ *offset = 4 + this->reason_string.len + this->language_code.len;
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_reason_string_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this->reason_string.ptr);
+ free(this->language_code.ptr);
+ free(this);
+}
+
+METHOD(pb_reason_string_msg_t, get_reason_string, chunk_t,
+ private_pb_reason_string_msg_t *this)
+{
+ return this->reason_string;
+}
+
+METHOD(pb_reason_string_msg_t, get_language_code, chunk_t,
+ private_pb_reason_string_msg_t *this)
+{
+ return this->language_code;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_reason_string_msg_create_from_data(chunk_t data)
+{
+ private_pb_reason_string_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_reason_string = _get_reason_string,
+ .get_language_code = _get_language_code,
+ },
+ .type = PB_MSG_REASON_STRING,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_reason_string_msg_create(chunk_t reason_string,
+ chunk_t language_code)
+{
+ private_pb_reason_string_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_reason_string = _get_reason_string,
+ .get_language_code = _get_language_code,
+ },
+ .type = PB_MSG_REASON_STRING,
+ .reason_string = chunk_clone(reason_string),
+ .language_code = chunk_clone(language_code),
+ );
+
+ return &this->public.pb_interface;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.h
new file mode 100644
index 000000000..bb296a90c
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_reason_string_msg.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyambuu
+ * 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.
+ */
+
+/**
+ * @defgroup pb_reason_string_msg pb_reason_string_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_REASON_STRING_MSG_H_
+#define PB_REASON_STRING_MSG_H_
+
+typedef struct pb_reason_string_msg_t pb_reason_string_msg_t;
+
+#include "pb_tnc_msg.h"
+
+/**
+ * Class representing the PB-Reason-String message type.
+ */
+struct pb_reason_string_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get Reason String
+ *
+ * @return Reason string
+ */
+ chunk_t (*get_reason_string)(pb_reason_string_msg_t *this);
+
+ /**
+ * Get Reason String Language Code
+ *
+ * @return Language code
+ */
+ chunk_t (*get_language_code)(pb_reason_string_msg_t *this);
+};
+
+/**
+ * Create a PB-Reason-String message from parameters
+ *
+ * @param reason_string Reason string
+ * @param language_code Language code
+ */
+pb_tnc_msg_t* pb_reason_string_msg_create(chunk_t reason_string,
+ chunk_t language_code);
+
+/**
+ * Create an unprocessed PB-Reason-String message from raw data
+ *
+ * @param data PB-Reason-String message data
+ */
+pb_tnc_msg_t* pb_reason_string_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c
new file mode 100644
index 000000000..2ef8dd6cd
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c
@@ -0,0 +1,311 @@
+/*
+ * 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 "pb_remediation_parameters_msg.h"
+
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/debug.h>
+
+ENUM(pb_tnc_remed_param_type_names, PB_REMEDIATION_URI, PB_REMEDIATION_STRING,
+ "Remediation-URI",
+ "Remediation-String"
+);
+
+typedef struct private_pb_remediation_parameters_msg_t private_pb_remediation_parameters_msg_t;
+
+/**
+ * PB-Remediation-Parameters message (see section 4.8 of RFC 5793)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Remediation Parameters Vendor ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Remediation Parameters Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Remediation Parameters (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Remediation String Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Remediation String (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Lang Code Len | Remediation String Lang Code (Variable Len) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/**
+ * Private data of a pb_remediation_parameters_msg_t object.
+ *
+ */
+struct private_pb_remediation_parameters_msg_t {
+ /**
+ * Public pb_remediation_parameters_msg_t interface.
+ */
+ pb_remediation_parameters_msg_t public;
+
+ /**
+ * PB-TNC message type
+ */
+ pb_tnc_msg_type_t type;
+
+ /**
+ * Remediation Parameters Type
+ */
+ pen_type_t parameters_type;
+
+ /**
+ * Remediation Parameters
+ */
+ chunk_t parameters;
+
+ /**
+ * Remediation String
+ */
+ chunk_t string;
+
+ /**
+ * Remediation Language Code
+ */
+ chunk_t lang_code;
+
+ /**
+ * Encoded message
+ */
+ chunk_t encoding;
+};
+
+METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ return this->type;
+}
+
+METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ return this->encoding;
+}
+
+METHOD(pb_tnc_msg_t, build, void,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ bio_writer_t *writer;
+
+ if (this->encoding.ptr)
+ {
+ return;
+ }
+ writer = bio_writer_create(64);
+ writer->write_uint32(writer, this->parameters_type.vendor_id);
+ writer->write_uint32(writer, this->parameters_type.type);
+ writer->write_data32(writer, this->parameters);
+
+ this->encoding = writer->get_buf(writer);
+ this->encoding = chunk_clone(this->encoding);
+ writer->destroy(writer);
+}
+
+METHOD(pb_tnc_msg_t, process, status_t,
+ private_pb_remediation_parameters_msg_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int8_t reserved;
+ status_t status = SUCCESS;
+ u_char *pos;
+
+ *offset = 0;
+
+ /* process message */
+ reader = bio_reader_create(this->encoding);
+ reader->read_uint8 (reader, &reserved);
+ reader->read_uint24(reader, &this->parameters_type.vendor_id);
+ reader->read_uint32(reader, &this->parameters_type.type);
+ reader->read_data (reader, reader->remaining(reader), &this->parameters);
+
+ this->parameters = chunk_clone(this->parameters);
+ reader->destroy(reader);
+
+ if (this->parameters_type.vendor_id == PEN_IETF &&
+ this->parameters_type.type == PB_REMEDIATION_STRING)
+ {
+ reader = bio_reader_create(this->parameters);
+ status = FAILED;
+ *offset = 8;
+
+ if (!reader->read_data32(reader, &this->string))
+ {
+ DBG1(DBG_TNC, "insufficient data for remediation string");
+ goto end;
+ };
+ *offset += 4;
+
+ pos = memchr(this->string.ptr, '\0', this->string.len);
+ if (pos)
+ {
+ DBG1(DBG_TNC, "nul termination in remediation string");
+ *offset += (pos - this->string.ptr);
+ goto end;
+ }
+ *offset += this->string.len;
+
+ if (!reader->read_data8(reader, &this->lang_code))
+ {
+ DBG1(DBG_TNC, "insufficient data for remediation string lang code");
+ goto end;
+ };
+ *offset += 1;
+
+ pos = memchr(this->lang_code.ptr, '\0', this->lang_code.len);
+
+ if (pos)
+ {
+ DBG1(DBG_TNC, "nul termination in remediation string lang code");
+ *offset += (pos - this->lang_code.ptr);
+ goto end;
+ }
+ status = SUCCESS;
+
+end:
+ reader->destroy(reader);
+ }
+ return status;
+}
+
+METHOD(pb_tnc_msg_t, destroy, void,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ free(this->encoding.ptr);
+ free(this->parameters.ptr);
+ free(this);
+}
+
+METHOD(pb_remediation_parameters_msg_t, get_parameters_type, pen_type_t,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ return this->parameters_type;
+}
+
+METHOD(pb_remediation_parameters_msg_t, get_parameters, chunk_t,
+ private_pb_remediation_parameters_msg_t *this)
+{
+ return this->parameters;
+}
+
+METHOD(pb_remediation_parameters_msg_t, get_string, chunk_t,
+ private_pb_remediation_parameters_msg_t *this, chunk_t *lang_code)
+{
+ if (lang_code)
+ {
+ *lang_code = this->lang_code;
+ }
+ return this->string;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create(pen_type_t parameters_type,
+ chunk_t parameters)
+{
+ private_pb_remediation_parameters_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_parameters_type = _get_parameters_type,
+ .get_parameters = _get_parameters,
+ .get_uri = _get_parameters,
+ .get_string = _get_string,
+ },
+ .type = PB_MSG_REMEDIATION_PARAMETERS,
+ .parameters_type = parameters_type,
+ .parameters = chunk_clone(parameters),
+ );
+
+ return &this->public.pb_interface;
+}
+
+/**
+ * Described in header.
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_uri(chunk_t uri)
+{
+ pen_type_t type = { PEN_IETF, PB_REMEDIATION_URI };
+
+ return pb_remediation_parameters_msg_create(type, uri);
+}
+
+/**
+ * Described in header.
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_string(chunk_t string,
+ chunk_t lang_code)
+{
+ pb_tnc_msg_t *msg;
+ bio_writer_t *writer;
+ pen_type_t type = { PEN_IETF, PB_REMEDIATION_STRING };
+
+ /* limit language code to 255 octets */
+ lang_code.len = min(255, lang_code.len);
+
+ writer = bio_writer_create(4 + string.len + 1 + lang_code.len);
+ writer->write_data32(writer, string);
+ writer->write_data8 (writer, lang_code);
+
+ msg = pb_remediation_parameters_msg_create(type, writer->get_buf(writer));
+ writer->destroy(writer);
+
+ return msg;
+}
+
+/**
+ * See header
+ */
+pb_tnc_msg_t *pb_remediation_parameters_msg_create_from_data(chunk_t data)
+{
+ private_pb_remediation_parameters_msg_t *this;
+
+ INIT(this,
+ .public = {
+ .pb_interface = {
+ .get_type = _get_type,
+ .get_encoding = _get_encoding,
+ .build = _build,
+ .process = _process,
+ .destroy = _destroy,
+ },
+ .get_parameters_type = _get_parameters_type,
+ .get_parameters = _get_parameters,
+ .get_uri = _get_parameters,
+ .get_string = _get_string,
+ },
+ .type = PB_MSG_REMEDIATION_PARAMETERS,
+ .encoding = chunk_clone(data),
+ );
+
+ return &this->public.pb_interface;
+}
+
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h
new file mode 100644
index 000000000..f3a1c1009
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011-2013 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.
+ */
+
+/**
+ * @defgroup pb_remediation_parameters_msg pb_remediation_parameters_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_REMEDIATION_PARAMETERS_MSG_H_
+#define PB_REMEDIATION_PARAMETERS_MSG_H_
+
+typedef enum pb_tnc_remed_param_type_t pb_tnc_remed_param_type_t;
+typedef struct pb_remediation_parameters_msg_t pb_remediation_parameters_msg_t;
+
+#include "pb_tnc_msg.h"
+
+#include <pen/pen.h>
+
+/**
+ * PB-TNC Remediation Parameter Types as defined in section 4.8.1 of RFC 5793
+ */
+enum pb_tnc_remed_param_type_t {
+ PB_REMEDIATION_URI = 1,
+ PB_REMEDIATION_STRING = 2,
+};
+
+/**
+ * enum name for pb_tnc_remed_param_type_t.
+ */
+extern enum_name_t *pb_tnc_remed_param_type_names;
+
+/**
+ * Class representing the PB-Remediation-Parameters message type.
+ */
+struct pb_remediation_parameters_msg_t {
+
+ /**
+ * PB-TNC Message interface
+ */
+ pb_tnc_msg_t pb_interface;
+
+ /**
+ * Get the Remediation Parameters Type (Vendor ID and Type)
+ *
+ * @return Remediation Parameters Type
+ */
+ pen_type_t (*get_parameters_type)(pb_remediation_parameters_msg_t *this);
+
+ /**
+ * Get the Remediation Parameters
+ *
+ * @return Remediation Parameters
+ */
+ chunk_t (*get_parameters)(pb_remediation_parameters_msg_t *this);
+
+ /**
+ * Get the Remediation URI
+ *
+ * @return Remediation URI
+ */
+ chunk_t (*get_uri)(pb_remediation_parameters_msg_t *this);
+
+ /**
+ * Get the Remediation String
+ *
+ * @param lang_code Optional Language Code
+ * @return Remediation String
+ */
+ chunk_t (*get_string)(pb_remediation_parameters_msg_t *this,
+ chunk_t *lang_code);
+
+};
+
+/**
+ * Create a general PB-Remediation-Parameters message
+ *
+ * @param parameters_type Remediation Parameters Type
+ * @param parameters Remediation Parameters
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create(pen_type_t parameters_type,
+ chunk_t parameters);
+
+/**
+ * Create a PB-Remediation-Parameters message of IETF Type Remediation URI
+ *
+ * @param uri Remediation URI
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_uri(chunk_t uri);
+
+/**
+ * Create a PB-Remediation-Parameters message of IETF Type Remediation String
+ *
+ * @param string Remediation String
+ * @param lang_code Remediation String Language Code
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_string(chunk_t string,
+ chunk_t lang_code);
+
+/**
+ * Create an unprocessed PB-Remediation-Parameters message from raw data
+ *
+ * @param data PB-Remediation-Parameters message data
+ */
+pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_data(chunk_t data);
+
+#endif /** PB_PA_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c
new file mode 100644
index 000000000..3565c2d84
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c
@@ -0,0 +1,75 @@
+/*
+ * 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 "pb_tnc_msg.h"
+#include "pb_experimental_msg.h"
+#include "pb_pa_msg.h"
+#include "pb_error_msg.h"
+#include "pb_language_preference_msg.h"
+#include "pb_assessment_result_msg.h"
+#include "pb_access_recommendation_msg.h"
+#include "pb_remediation_parameters_msg.h"
+#include "pb_reason_string_msg.h"
+
+#include <library.h>
+
+ENUM(pb_tnc_msg_type_names, PB_MSG_EXPERIMENTAL, PB_MSG_REASON_STRING,
+ "PB-Experimental",
+ "PB-PA",
+ "PB-Assessment-Result",
+ "PB-Access-Recommendation",
+ "PB-Remediation-Parameters",
+ "PB-Error",
+ "PB-Language-Preference",
+ "PB-Reason-String"
+);
+
+pb_tnc_msg_info_t pb_tnc_msg_infos[] = {
+ { 12, FALSE, FALSE, TRUE_OR_FALSE },
+ { 24, FALSE, FALSE, TRUE },
+ { 16, TRUE, TRUE, TRUE },
+ { 16, TRUE, TRUE, FALSE },
+ { 20, FALSE, TRUE, FALSE },
+ { 20, FALSE, FALSE, TRUE },
+ { 12, FALSE, FALSE, FALSE },
+ { 17, FALSE, TRUE, FALSE },
+};
+
+/**
+ * See header
+ */
+pb_tnc_msg_t* pb_tnc_msg_create_from_data(pb_tnc_msg_type_t type, chunk_t value)
+{
+ switch (type)
+ {
+ case PB_MSG_PA:
+ return pb_pa_msg_create_from_data(value);
+ case PB_MSG_ERROR:
+ return pb_error_msg_create_from_data(value);
+ case PB_MSG_EXPERIMENTAL:
+ return pb_experimental_msg_create_from_data(value);
+ case PB_MSG_LANGUAGE_PREFERENCE:
+ return pb_language_preference_msg_create_from_data(value);
+ case PB_MSG_ASSESSMENT_RESULT:
+ return pb_assessment_result_msg_create_from_data(value);
+ case PB_MSG_ACCESS_RECOMMENDATION:
+ return pb_access_recommendation_msg_create_from_data(value);
+ case PB_MSG_REMEDIATION_PARAMETERS:
+ return pb_remediation_parameters_msg_create_from_data(value);
+ case PB_MSG_REASON_STRING:
+ return pb_reason_string_msg_create_from_data(value);
+ }
+ return NULL;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h
new file mode 100644
index 000000000..97ebed27f
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup pb_tnc_msg pb_tnc_msg
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_TNC_MSG_H_
+#define PB_TNC_MSG_H_
+
+typedef enum pb_tnc_msg_type_t pb_tnc_msg_type_t;
+typedef struct pb_tnc_msg_info_t pb_tnc_msg_info_t;
+typedef struct pb_tnc_msg_t pb_tnc_msg_t;
+
+#include <library.h>
+
+#define PB_TNC_VERSION 2
+
+/**
+ * PB-TNC Message Types as defined in section 4.3 of RFC 5793
+ */
+enum pb_tnc_msg_type_t {
+ PB_MSG_EXPERIMENTAL = 0,
+ PB_MSG_PA = 1,
+ PB_MSG_ASSESSMENT_RESULT = 2,
+ PB_MSG_ACCESS_RECOMMENDATION = 3,
+ PB_MSG_REMEDIATION_PARAMETERS = 4,
+ PB_MSG_ERROR = 5,
+ PB_MSG_LANGUAGE_PREFERENCE = 6,
+ PB_MSG_REASON_STRING = 7,
+ PB_MSG_ROOF = 7
+};
+
+/**
+ * enum name for pb_tnc_msg_type_t.
+ */
+extern enum_name_t *pb_tnc_msg_type_names;
+
+/**
+ * Information entry describing a PB-TNC Message Type
+ */
+struct pb_tnc_msg_info_t {
+ u_int32_t min_size;
+ bool exact_size;
+ bool in_result_batch;
+ signed char has_noskip_flag;
+};
+
+#define TRUE_OR_FALSE 2
+
+/**
+ * Information on PB-TNC Message Types
+ */
+extern pb_tnc_msg_info_t pb_tnc_msg_infos[];
+
+/**
+ * Generic interface for all PB-TNC message types.
+ *
+ * To handle all messages in a generic way, this interface
+ * must be implemented by each message type.
+ */
+struct pb_tnc_msg_t {
+
+ /**
+ * Get the PB-TNC Message Type
+ *
+ * @return PB-TNC Message Type
+ */
+ pb_tnc_msg_type_t (*get_type)(pb_tnc_msg_t *this);
+
+ /**
+ * Get the encoding of the PB-TNC Message Value
+ *
+ * @return encoded PB-TNC Message Value
+ */
+ chunk_t (*get_encoding)(pb_tnc_msg_t *this);
+
+ /**
+ * Build the PB-TNC Message Value
+ */
+ void (*build)(pb_tnc_msg_t *this);
+
+ /**
+ * Process the PB-TNC Message Value
+ *
+ * @param relative offset where an error occurred
+ * @return return processing status
+ */
+ status_t (*process)(pb_tnc_msg_t *this, u_int32_t *offset);
+
+ /**
+ * Get a new reference to the message.
+ *
+ * @return this, with an increased refcount
+ */
+ pb_tnc_msg_t* (*get_ref)(pb_tnc_msg_t *this);
+
+ /**
+ * Destroys a pb_tnc_msg_t object.
+ */
+ void (*destroy)(pb_tnc_msg_t *this);
+};
+
+/**
+ * Create an unprocessed PB-TNC message
+ *
+ * Useful for the parser which wants a generic constructor for all
+ * pb_tnc_message_t types.
+ *
+ * @param type PB-TNC message type
+ * @param value PB-TNC message value
+ */
+pb_tnc_msg_t* pb_tnc_msg_create_from_data(pb_tnc_msg_type_t type, chunk_t value);
+
+#endif /** PB_TNC_MSG_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c b/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c
new file mode 100644
index 000000000..43f185440
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c
@@ -0,0 +1,316 @@
+/*
+ * 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 "pb_tnc_state_machine.h"
+
+#include <utils/debug.h>
+
+ENUM(pb_tnc_state_names, PB_STATE_INIT, PB_STATE_END,
+ "Init",
+ "Server Working",
+ "Client Working",
+ "Decided",
+ "End"
+);
+
+/**
+ * PB-TNC State Machine (see section 3.2 of RFC 5793)
+ *
+ * Receive CRETRY SRETRY
+ * or SRETRY +----------------+
+ * +--+ | |
+ * v | v |
+ * +---------+ CRETRY +---------+
+ * CDATA | Server |<---------| Decided | CLOSE
+ * +----------->| Working |--------->| |-------+
+ * | +---------+ RESULT +---------+ |
+ * | ^ | | v
+ * | | | +---------------------->=======
+ * ======== | | CLOSE " End "
+ * " Init " CDATA| |SDATA =======
+ * ======== | | ^ ^
+ * | | | v | |
+ * | | SDATA +---------+ CLOSE | |
+ * | +-------->| Client |----------------------+ |
+ * | | Working | |
+ * | +---------+ |
+ * | | ^ |
+ * | +--+ |
+ * | Receive CRETRY |
+ * | CLOSE |
+ * +--------------------------------------------------+
+ */
+
+typedef struct private_pb_tnc_state_machine_t private_pb_tnc_state_machine_t;
+
+/**
+ * Private data of a pb_tnc_state_machine_t object.
+ *
+ */
+struct private_pb_tnc_state_machine_t {
+ /**
+ * Public pb_pa_message_t interface.
+ */
+ pb_tnc_state_machine_t public;
+
+ /**
+ * PB-TNC Server if TRUE, PB-TNC Client if FALSE
+ */
+ bool is_server;
+
+ /**
+ * Informs whether last received PB-TNC CDATA Batch was empty
+ */
+ bool empty_cdata;
+
+ /**
+ * Current PB-TNC state
+ */
+ pb_tnc_state_t state;
+};
+
+METHOD(pb_tnc_state_machine_t, get_state, pb_tnc_state_t,
+ private_pb_tnc_state_machine_t *this)
+{
+ return this->state;
+}
+
+METHOD(pb_tnc_state_machine_t, receive_batch, bool,
+ private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
+{
+ pb_tnc_state_t old_state = this->state;
+
+ switch (this->state)
+ {
+ case PB_STATE_INIT:
+ if (this->is_server && type == PB_BATCH_CDATA)
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (!this->is_server && type == PB_BATCH_SDATA)
+ {
+ this->state = PB_STATE_CLIENT_WORKING;
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_SERVER_WORKING:
+ if (!this->is_server && (type == PB_BATCH_SDATA ||
+ type == PB_BATCH_SRETRY))
+ {
+ this->state = PB_STATE_CLIENT_WORKING;
+ break;
+ }
+ if (!this->is_server && type == PB_BATCH_RESULT)
+ {
+ this->state = PB_STATE_DECIDED;
+ break;
+ }
+ if (this->is_server && type == PB_BATCH_CRETRY)
+ {
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_CLIENT_WORKING:
+ if (this->is_server && type == PB_BATCH_CDATA)
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (this->is_server && type == PB_BATCH_CRETRY)
+ {
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_DECIDED:
+ if ((this->is_server && type == PB_BATCH_CRETRY) ||
+ (!this->is_server && type == PB_BATCH_SRETRY))
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_END:
+ if (type == PB_BATCH_CLOSE)
+ {
+ break;
+ }
+ return FALSE;
+ }
+
+ if (this->state != old_state)
+ {
+ DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
+ pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
+ }
+ return TRUE;
+}
+
+METHOD(pb_tnc_state_machine_t, send_batch, bool,
+ private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
+{
+ pb_tnc_state_t old_state = this->state;
+
+ switch (this->state)
+ {
+ case PB_STATE_INIT:
+ if (!this->is_server && type == PB_BATCH_CDATA)
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (this->is_server && type == PB_BATCH_SDATA)
+ {
+ this->state = PB_STATE_CLIENT_WORKING;
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_SERVER_WORKING:
+ if (this->is_server && (type == PB_BATCH_SDATA ||
+ type == PB_BATCH_SRETRY))
+ {
+ this->state = PB_STATE_CLIENT_WORKING;
+ break;
+ }
+ if (this->is_server && type == PB_BATCH_RESULT)
+ {
+ this->state = PB_STATE_DECIDED;
+ break;
+ }
+ if (!this->is_server && type == PB_BATCH_CRETRY)
+ {
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_CLIENT_WORKING:
+ if (!this->is_server && (type == PB_BATCH_CDATA ||
+ type == PB_BATCH_CRETRY))
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (this->is_server && type == PB_BATCH_SRETRY)
+ {
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_DECIDED:
+ if ((this->is_server && type == PB_BATCH_SRETRY) ||
+ (!this->is_server && type == PB_BATCH_CRETRY))
+ {
+ this->state = PB_STATE_SERVER_WORKING;
+ break;
+ }
+ if (type == PB_BATCH_CLOSE)
+ {
+ this->state = PB_STATE_END;
+ break;
+ }
+ return FALSE;
+ case PB_STATE_END:
+ if (type == PB_BATCH_CLOSE)
+ {
+ break;
+ }
+ return FALSE;
+ }
+
+ if (this->state != old_state)
+ {
+ DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
+ pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
+ }
+ return TRUE;
+}
+
+METHOD(pb_tnc_state_machine_t, get_empty_cdata, bool,
+ private_pb_tnc_state_machine_t *this)
+{
+ return this->empty_cdata;
+}
+
+METHOD(pb_tnc_state_machine_t, set_empty_cdata, void,
+ private_pb_tnc_state_machine_t *this, bool empty)
+{
+ if (empty)
+ {
+ DBG2(DBG_TNC, "received empty PB-TNC CDATA batch");
+ }
+ this->empty_cdata = empty;
+}
+
+METHOD(pb_tnc_state_machine_t, destroy, void,
+ private_pb_tnc_state_machine_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server)
+{
+ private_pb_tnc_state_machine_t *this;
+
+ INIT(this,
+ .public = {
+ .get_state = _get_state,
+ .receive_batch = _receive_batch,
+ .send_batch = _send_batch,
+ .get_empty_cdata = _get_empty_cdata,
+ .set_empty_cdata = _set_empty_cdata,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ .state = PB_STATE_INIT,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h b/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h
new file mode 100644
index 000000000..aa317041e
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup pb_tnc_state_machine pb_tnc_state_machine
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_TNC_STATE_MACHINE_H_
+#define PB_TNC_STATE_MACHINE_H_
+
+typedef struct pb_tnc_state_machine_t pb_tnc_state_machine_t;
+typedef enum pb_tnc_state_t pb_tnc_state_t;
+
+#include "batch/pb_tnc_batch.h"
+
+#include <library.h>
+
+/**
+ * PB-TNC States (state machine) as defined in section 3.2 of RFC 5793
+ */
+enum pb_tnc_state_t {
+ PB_STATE_INIT,
+ PB_STATE_SERVER_WORKING,
+ PB_STATE_CLIENT_WORKING,
+ PB_STATE_DECIDED,
+ PB_STATE_END,
+};
+
+/**
+ * enum name for pb_tnc_state_t.
+ */
+extern enum_name_t *pb_tnc_state_names;
+
+/**
+ * Interface for the PB-TNC state machine.
+ */
+struct pb_tnc_state_machine_t {
+
+ /**
+ * Get the current PB-TNC STATE
+ *
+ * @return current state
+ */
+ pb_tnc_state_t (*get_state)(pb_tnc_state_machine_t *this);
+
+ /**
+ * Compute state transition due to received PB-TNC Batch
+ *
+ * @param type type of received batch
+ * @result TRUE if a valid transition was found, FALSE otherwise
+ */
+ bool (*receive_batch)(pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type);
+
+ /**
+ * Compute state transition due to sent PB-TNC Batch
+ *
+ * @param type type of sent batch
+ * @result TRUE if a valid transition was found, FALSE otherwise
+ */
+ bool (*send_batch)(pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type);
+
+ /**
+ * Informs whether the last received PB-TNC CDATA Batch was empty
+ *
+ * @result TRUE if last received PB-TNC CDATA Batch was empty
+ */
+ bool (*get_empty_cdata)(pb_tnc_state_machine_t *this);
+
+ /**
+ * Store information whether the received PB-TNC CDATA Batch was empty
+ *
+ * @param empty set to TRUE if received PB-TNC CDATA Batch was empty
+ */
+ void (*set_empty_cdata)(pb_tnc_state_machine_t *this, bool empty);
+
+ /**
+ * Destroys a pb_tnc_state_machine_t object.
+ */
+ void (*destroy)(pb_tnc_state_machine_t *this);
+};
+
+/**
+ * Create and initialize a PB-TNC state machine
+ *
+ * @param is_server TRUE if PB-TNC server, FALSE if PB-TNC client
+ */
+pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server);
+
+#endif /** PB_TNC_STATE_MACHINE_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.c b/src/libtnccs/plugins/tnccs_20/tnccs_20.c
new file mode 100644
index 000000000..09900ade9
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.c
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2010 Sansar Choinyanbuu
+ * Copyright (C) 2010-2013 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 "tnccs_20.h"
+#include "batch/pb_tnc_batch.h"
+#include "messages/pb_tnc_msg.h"
+#include "messages/pb_pa_msg.h"
+#include "messages/pb_error_msg.h"
+#include "messages/pb_assessment_result_msg.h"
+#include "messages/pb_access_recommendation_msg.h"
+#include "messages/pb_remediation_parameters_msg.h"
+#include "messages/pb_reason_string_msg.h"
+#include "messages/pb_language_preference_msg.h"
+#include "state_machine/pb_tnc_state_machine.h"
+
+#include <tncif_names.h>
+#include <tncif_pa_subtypes.h>
+
+#include <tnc/tnc.h>
+#include <tnc/tnccs/tnccs_manager.h>
+#include <tnc/imc/imc_manager.h>
+#include <tnc/imv/imv_manager.h>
+
+#include <threading/mutex.h>
+#include <utils/debug.h>
+#include <collections/linked_list.h>
+#include <pen/pen.h>
+
+typedef struct private_tnccs_20_t private_tnccs_20_t;
+
+/**
+ * Private data of a tnccs_20_t object.
+ */
+struct private_tnccs_20_t {
+
+ /**
+ * Public tnccs_t interface.
+ */
+ tnccs_t public;
+
+ /**
+ * TNCC if TRUE, TNCS if FALSE
+ */
+ bool is_server;
+
+ /**
+ * Server identity
+ */
+ identification_t *server;
+
+ /**
+ * Client identity
+ */
+ identification_t *peer;
+
+ /**
+ * Underlying TNC IF-T transport protocol
+ */
+ tnc_ift_type_t transport;
+
+ /**
+ * Type of TNC client authentication
+ */
+ u_int32_t auth_type;
+
+ /**
+ * PB-TNC State Machine
+ */
+ pb_tnc_state_machine_t *state_machine;
+
+ /**
+ * Connection ID assigned to this TNCCS connection
+ */
+ TNC_ConnectionID connection_id;
+
+ /**
+ * PB-TNC messages to be sent
+ */
+ linked_list_t *messages;
+
+ /**
+ * Type of PB-TNC batch being constructed
+ */
+ pb_tnc_batch_type_t batch_type;
+
+ /**
+ * Maximum PB-TNC batch size
+ */
+ size_t max_batch_len;
+
+ /**
+ * Maximum PA-TNC message size
+ */
+ size_t max_msg_len;
+
+ /**
+ * Mutex locking the batch in construction
+ */
+ mutex_t *mutex;
+
+ /**
+ * Flag set while processing
+ */
+ bool fatal_error;
+
+ /**
+ * Flag set by IMC/IMV RequestHandshakeRetry() function
+ */
+ bool request_handshake_retry;
+
+ /**
+ * SendMessage() by IMC/IMV only allowed if flag is set
+ */
+ bool send_msg;
+
+ /**
+ * Set of IMV recommendations (TNC Server only)
+ */
+ recommendations_t *recs;
+
+};
+
+/**
+ * If the batch type changes then delete all accumulated PB-TNC messages
+ */
+void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type)
+{
+ pb_tnc_msg_t *msg;
+
+ if (batch_type != this->batch_type)
+ {
+ if (this->batch_type != PB_BATCH_NONE)
+ {
+ DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
+ pb_tnc_batch_type_names, this->batch_type);
+
+ while (this->messages->remove_last(this->messages,
+ (void**)&msg) == SUCCESS)
+ {
+ msg->destroy(msg);
+ }
+ }
+ this->batch_type = batch_type;
+ }
+}
+
+METHOD(tnccs_t, send_msg, TNC_Result,
+ private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
+{
+ pb_tnc_msg_t *pb_tnc_msg;
+ pb_tnc_batch_type_t batch_type;
+ enum_name_t *pa_subtype_names;
+ bool excl;
+
+ if (!this->send_msg)
+ {
+ DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
+ this->is_server ? "IMV" : "IMC",
+ this->is_server ? imv_id : imc_id);
+ return TNC_RESULT_ILLEGAL_OPERATION;
+ }
+ excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
+
+ pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
+ excl, chunk_create(msg, msg_len));
+
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
+ if (pa_subtype_names)
+ {
+ DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, msg_vid, msg_subtype);
+ }
+
+ /* adding PA message to SDATA or CDATA batch only */
+ batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA;
+ this->mutex->lock(this->mutex);
+ if (this->batch_type == PB_BATCH_NONE)
+ {
+ this->batch_type = batch_type;
+ }
+ if (this->batch_type == batch_type)
+ {
+ this->messages->insert_last(this->messages, pb_tnc_msg);
+ }
+ else
+ {
+ pb_tnc_msg->destroy(pb_tnc_msg);
+ }
+ this->mutex->unlock(this->mutex);
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * Handle a single PB-TNC message according to its type
+ */
+static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
+{
+ switch (msg->get_type(msg))
+ {
+ case PB_MSG_EXPERIMENTAL:
+ /* nothing to do */
+ break;
+ case PB_MSG_PA:
+ {
+ pb_pa_msg_t *pa_msg;
+ pen_type_t msg_subtype;
+ u_int16_t imc_id, imv_id;
+ chunk_t msg_body;
+ bool excl;
+ enum_name_t *pa_subtype_names;
+
+ pa_msg = (pb_pa_msg_t*)msg;
+ msg_subtype = pa_msg->get_subtype(pa_msg);
+ msg_body = pa_msg->get_body(pa_msg);
+ imc_id = pa_msg->get_collector_id(pa_msg);
+ imv_id = pa_msg->get_validator_id(pa_msg);
+ excl = pa_msg->get_exclusive_flag(pa_msg);
+
+ pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id);
+ if (pa_subtype_names)
+ {
+ DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
+ pen_names, msg_subtype.vendor_id, pa_subtype_names,
+ msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x",
+ pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id,
+ msg_subtype.type);
+ }
+
+ this->send_msg = TRUE;
+ if (this->is_server)
+ {
+ tnc->imvs->receive_message(tnc->imvs, this->connection_id,
+ excl, msg_body.ptr, msg_body.len,
+ msg_subtype.vendor_id,
+ msg_subtype.type, imc_id, imv_id);
+ }
+ else
+ {
+ tnc->imcs->receive_message(tnc->imcs, this->connection_id,
+ excl, msg_body.ptr, msg_body.len,
+ msg_subtype.vendor_id,
+ msg_subtype.type, imv_id, imc_id);
+ }
+ this->send_msg = FALSE;
+ break;
+ }
+ case PB_MSG_ASSESSMENT_RESULT:
+ {
+ pb_assessment_result_msg_t *assess_msg;
+ u_int32_t result;
+
+ assess_msg = (pb_assessment_result_msg_t*)msg;
+ result = assess_msg->get_assessment_result(assess_msg);
+ DBG1(DBG_TNC, "PB-TNC assessment result is '%N'",
+ TNC_IMV_Evaluation_Result_names, result);
+ break;
+ }
+ case PB_MSG_ACCESS_RECOMMENDATION:
+ {
+ pb_access_recommendation_msg_t *rec_msg;
+ pb_access_recommendation_code_t rec;
+ TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE;
+
+ rec_msg = (pb_access_recommendation_msg_t*)msg;
+ rec = rec_msg->get_access_recommendation(rec_msg);
+ DBG1(DBG_TNC, "PB-TNC access recommendation is '%N'",
+ pb_access_recommendation_code_names, rec);
+ switch (rec)
+ {
+ case PB_REC_ACCESS_ALLOWED:
+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+ break;
+ case PB_REC_ACCESS_DENIED:
+ state = TNC_CONNECTION_STATE_ACCESS_NONE;
+ break;
+ case PB_REC_QUARANTINED:
+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+ }
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ state);
+ break;
+ }
+ case PB_MSG_REMEDIATION_PARAMETERS:
+ {
+ pb_remediation_parameters_msg_t *rem_msg;
+ pen_type_t parameters_type;
+ chunk_t parameters, string, lang_code;
+
+ rem_msg = (pb_remediation_parameters_msg_t*)msg;
+ parameters_type = rem_msg->get_parameters_type(rem_msg);
+ parameters = rem_msg->get_parameters(rem_msg);
+
+ if (parameters_type.vendor_id == PEN_IETF)
+ {
+ switch (parameters_type.type)
+ {
+ case PB_REMEDIATION_URI:
+ DBG1(DBG_TNC, "remediation uri: %.*s",
+ parameters.len, parameters.ptr);
+ break;
+ case PB_REMEDIATION_STRING:
+ string = rem_msg->get_string(rem_msg, &lang_code);
+ DBG1(DBG_TNC, "remediation string: [%.*s]\n%.*s",
+ lang_code.len, lang_code.ptr,
+ string.len, string.ptr);
+ break;
+ default:
+ DBG1(DBG_TNC, "remediation parameters: %B", &parameters);
+ }
+ }
+ else
+ {
+ DBG1(DBG_TNC, "remediation parameters: %B", &parameters);
+ }
+ break;
+ }
+ case PB_MSG_ERROR:
+ {
+ pb_error_msg_t *err_msg;
+ bool fatal;
+ u_int32_t vendor_id;
+ u_int16_t error_code;
+
+ err_msg = (pb_error_msg_t*)msg;
+ fatal = err_msg->get_fatal_flag(err_msg);
+ vendor_id = err_msg->get_vendor_id(err_msg);
+ error_code = err_msg->get_error_code(err_msg);
+
+ if (fatal)
+ {
+ this->fatal_error = TRUE;
+ }
+
+ if (vendor_id == PEN_IETF)
+ {
+ switch (error_code)
+ {
+ case PB_ERROR_INVALID_PARAMETER:
+ case PB_ERROR_UNSUPPORTED_MANDATORY_MSG:
+ DBG1(DBG_TNC, "received %s PB-TNC error '%N' "
+ "(offset %u bytes)",
+ fatal ? "fatal" : "non-fatal",
+ pb_tnc_error_code_names, error_code,
+ err_msg->get_offset(err_msg));
+ break;
+ case PB_ERROR_VERSION_NOT_SUPPORTED:
+ DBG1(DBG_TNC, "received %s PB-TNC error '%N' "
+ "caused by bad version 0x%02x",
+ fatal ? "fatal" : "non-fatal",
+ pb_tnc_error_code_names, error_code,
+ err_msg->get_bad_version(err_msg));
+ break;
+ case PB_ERROR_UNEXPECTED_BATCH_TYPE:
+ case PB_ERROR_LOCAL_ERROR:
+ default:
+ DBG1(DBG_TNC, "received %s PB-TNC error '%N'",
+ fatal ? "fatal" : "non-fatal",
+ pb_tnc_error_code_names, error_code);
+ break;
+ }
+ }
+ else
+ {
+ DBG1(DBG_TNC, "received %s PB-TNC error (%u) "
+ "with Vendor ID 0x%06x",
+ fatal ? "fatal" : "non-fatal",
+ error_code, vendor_id);
+ }
+ break;
+ }
+ case PB_MSG_LANGUAGE_PREFERENCE:
+ {
+ pb_language_preference_msg_t *lang_msg;
+ chunk_t lang;
+
+ lang_msg = (pb_language_preference_msg_t*)msg;
+ lang = lang_msg->get_language_preference(lang_msg);
+
+ if (this->recs)
+ {
+ DBG2(DBG_TNC, "setting language preference to '%.*s'",
+ (int)lang.len, lang.ptr);
+ this->recs->set_preferred_language(this->recs, lang);
+ }
+ break;
+ }
+ case PB_MSG_REASON_STRING:
+ {
+ pb_reason_string_msg_t *reason_msg;
+ chunk_t reason_string, language_code;
+
+ reason_msg = (pb_reason_string_msg_t*)msg;
+ reason_string = reason_msg->get_reason_string(reason_msg);
+ language_code = reason_msg->get_language_code(reason_msg);
+ DBG1(DBG_TNC, "reason string is '%.*s' [%.*s]",
+ (int)reason_string.len, reason_string.ptr,
+ (int)language_code.len, language_code.ptr);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/**
+ * Build a CRETRY or SRETRY batch
+ */
+static void build_retry_batch(private_tnccs_20_t *this)
+{
+ pb_tnc_batch_type_t batch_retry_type;
+
+ batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY;
+ if (this->batch_type == batch_retry_type)
+ {
+ /* retry batch has already been selected */
+ return;
+ }
+
+ change_batch_type(this, batch_retry_type);
+
+ if (this->is_server)
+ {
+ this->recs->clear_recommendation(this->recs);
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ }
+}
+
+METHOD(tls_t, process, status_t,
+ private_tnccs_20_t *this, void *buf, size_t buflen)
+{
+ chunk_t data;
+ pb_tnc_batch_t *batch;
+ pb_tnc_msg_t *msg;
+ enumerator_t *enumerator;
+ status_t status;
+
+ if (this->is_server && !this->connection_id)
+ {
+ this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
+ TNCCS_2_0, (tnccs_t*)this, _send_msg,
+ &this->request_handshake_retry,
+ this->max_msg_len, &this->recs);
+ if (!this->connection_id)
+ {
+ return FAILED;
+ }
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ TNC_CONNECTION_STATE_CREATE);
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ }
+
+ data = chunk_create(buf, buflen);
+ DBG1(DBG_TNC, "received TNCCS batch (%u bytes) for Connection ID %u",
+ data.len, this->connection_id);
+ DBG3(DBG_TNC, "%B", &data);
+ batch = pb_tnc_batch_create_from_data(this->is_server, data);
+ status = batch->process(batch, this->state_machine);
+
+ if (status != FAILED)
+ {
+ enumerator_t *enumerator;
+ pb_tnc_msg_t *msg;
+ pb_tnc_batch_type_t batch_type;
+ bool empty = TRUE;
+
+ batch_type = batch->get_type(batch);
+
+ if (batch_type == PB_BATCH_CRETRY)
+ {
+ /* Send an SRETRY batch in response */
+ this->mutex->lock(this->mutex);
+ build_retry_batch(this);
+ this->mutex->unlock(this->mutex);
+ }
+ else if (batch_type == PB_BATCH_SRETRY)
+ {
+ /* Restart the measurements */
+ tnc->imcs->notify_connection_change(tnc->imcs,
+ this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
+ this->send_msg = TRUE;
+ tnc->imcs->begin_handshake(tnc->imcs, this->connection_id);
+ this->send_msg = FALSE;
+ }
+
+ enumerator = batch->create_msg_enumerator(batch);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ handle_message(this, msg);
+ empty = FALSE;
+ }
+ enumerator->destroy(enumerator);
+
+ /* received an empty CLOSE batch from PB-TNC client */
+ if (this->is_server && batch_type == PB_BATCH_CLOSE && empty)
+ {
+ batch->destroy(batch);
+ if (this->fatal_error)
+ {
+ DBG1(DBG_TNC, "a fatal PB-TNC error occurred, "
+ "terminating connection");
+ return FAILED;
+ }
+ else
+ {
+ return SUCCESS;
+ }
+ }
+
+ this->send_msg = TRUE;
+ if (this->is_server)
+ {
+ tnc->imvs->batch_ending(tnc->imvs, this->connection_id);
+ }
+ else
+ {
+ tnc->imcs->batch_ending(tnc->imcs, this->connection_id);
+ }
+ this->send_msg = FALSE;
+ }
+
+ switch (status)
+ {
+ case FAILED:
+ this->fatal_error = TRUE;
+ this->mutex->lock(this->mutex);
+ change_batch_type(this, PB_BATCH_CLOSE);
+ this->mutex->unlock(this->mutex);
+ /* fall through to add error messages to outbound batch */
+ case VERIFY_ERROR:
+ enumerator = batch->create_error_enumerator(batch);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ this->mutex->lock(this->mutex);
+ this->messages->insert_last(this->messages, msg->get_ref(msg));
+ this->mutex->unlock(this->mutex);
+ }
+ enumerator->destroy(enumerator);
+ break;
+ case SUCCESS:
+ default:
+ break;
+ }
+ batch->destroy(batch);
+
+ return NEED_MORE;
+}
+
+/**
+ * Build a RESULT batch if a final recommendation is available
+ */
+static void check_and_build_recommendation(private_tnccs_20_t *this)
+{
+ TNC_IMV_Action_Recommendation rec;
+ TNC_IMV_Evaluation_Result eval;
+ TNC_ConnectionState state;
+ TNC_IMVID id;
+ chunk_t reason, language;
+ enumerator_t *enumerator;
+ pb_tnc_msg_t *msg;
+ pb_access_recommendation_code_t pb_rec;
+
+ if (!this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id);
+ }
+ if (this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ this->batch_type = PB_BATCH_RESULT;
+
+ msg = pb_assessment_result_msg_create(eval);
+ this->messages->insert_last(this->messages, msg);
+
+ /**
+ * Map IMV Action Recommendation codes to PB Access Recommendation codes
+ * and communicate Access Recommendation to IMVs
+ */
+ switch (rec)
+ {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+ pb_rec = PB_REC_ACCESS_ALLOWED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+ pb_rec = PB_REC_QUARANTINED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ default:
+ state = TNC_CONNECTION_STATE_ACCESS_NONE;
+ pb_rec = PB_REC_ACCESS_DENIED;
+ }
+ tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
+ state);
+
+ msg = pb_access_recommendation_msg_create(pb_rec);
+ this->messages->insert_last(this->messages, msg);
+
+ enumerator = this->recs->create_reason_enumerator(this->recs);
+ while (enumerator->enumerate(enumerator, &id, &reason, &language))
+ {
+ msg = pb_reason_string_msg_create(reason, language);
+ this->messages->insert_last(this->messages, msg);
+ }
+ enumerator->destroy(enumerator);
+ }
+}
+
+METHOD(tls_t, build, status_t,
+ private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
+{
+ status_t status;
+ pb_tnc_state_t state;
+
+ /* Initialize the connection */
+ if (!this->is_server && !this->connection_id)
+ {
+ pb_tnc_msg_t *msg;
+ char *pref_lang;
+
+ this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
+ TNCCS_2_0, (tnccs_t*)this, _send_msg,
+ &this->request_handshake_retry,
+ this->max_msg_len, NULL);
+ if (!this->connection_id)
+ {
+ return FAILED;
+ }
+
+ /* Create PB-TNC Language Preference message */
+ pref_lang = tnc->imcs->get_preferred_language(tnc->imcs);
+ msg = pb_language_preference_msg_create(chunk_create(pref_lang,
+ strlen(pref_lang)));
+ this->mutex->lock(this->mutex);
+ this->batch_type = PB_BATCH_CDATA;
+ this->messages->insert_last(this->messages, msg);
+ this->mutex->unlock(this->mutex);
+
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ TNC_CONNECTION_STATE_CREATE);
+ tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ this->send_msg = TRUE;
+ tnc->imcs->begin_handshake(tnc->imcs, this->connection_id);
+ this->send_msg = FALSE;
+ }
+
+ state = this->state_machine->get_state(this->state_machine);
+
+ if (this->fatal_error && state == PB_STATE_END)
+ {
+ DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection");
+ return FAILED;
+ }
+
+ /* Do not allow any asynchronous IMCs or IMVs to add additional messages */
+ this->mutex->lock(this->mutex);
+
+ if (this->request_handshake_retry)
+ {
+ if (state != PB_STATE_INIT)
+ {
+ build_retry_batch(this);
+ }
+
+ /* Reset the flag for the next handshake retry request */
+ this->request_handshake_retry = FALSE;
+ }
+
+ if (this->is_server && state == PB_STATE_SERVER_WORKING &&
+ this->recs->have_recommendation(this->recs, NULL, NULL))
+ {
+ check_and_build_recommendation(this);
+ }
+
+ if (this->batch_type == PB_BATCH_NONE)
+ {
+ if (this->is_server)
+ {
+ if (state == PB_STATE_SERVER_WORKING)
+ {
+ if (this->state_machine->get_empty_cdata(this->state_machine))
+ {
+ check_and_build_recommendation(this);
+ }
+ else
+ {
+ DBG2(DBG_TNC, "no recommendation available yet, "
+ "sending empty PB-TNC SDATA batch");
+ this->batch_type = PB_BATCH_SDATA;
+ }
+ }
+ }
+ else
+ {
+ switch (state)
+ {
+ case PB_STATE_CLIENT_WORKING:
+ DBG2(DBG_TNC, "no client data to send, "
+ "sending empty PB-TNC CDATA batch");
+ this->batch_type = PB_BATCH_CDATA;
+ break;
+ case PB_STATE_DECIDED:
+ /**
+ * In the DECIDED state and if no CRETRY is under way,
+ * a PB-TNC client replies with an empty CLOSE batch.
+ */
+ this->batch_type = PB_BATCH_CLOSE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (this->batch_type != PB_BATCH_NONE)
+ {
+ pb_tnc_batch_t *batch;
+ pb_tnc_msg_t *msg;
+ chunk_t data;
+ int msg_count;
+ enumerator_t *enumerator;
+
+ if (this->state_machine->send_batch(this->state_machine, this->batch_type))
+ {
+ batch = pb_tnc_batch_create(this->is_server, this->batch_type,
+ min(this->max_batch_len, *buflen));
+
+ enumerator = this->messages->create_enumerator(this->messages);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ if (batch->add_msg(batch, msg))
+ {
+ this->messages->remove_at(this->messages, enumerator);
+ }
+ else
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ batch->build(batch);
+ data = batch->get_encoding(batch);
+ DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
+ pb_tnc_batch_type_names, this->batch_type, data.len,
+ this->connection_id);
+ DBG3(DBG_TNC, "%B", &data);
+
+ *buflen = data.len;
+ *msglen = 0;
+ memcpy(buf, data.ptr, *buflen);
+ batch->destroy(batch);
+
+ msg_count = this->messages->get_count(this->messages);
+ if (msg_count)
+ {
+ DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch",
+ msg_count, (msg_count == 1) ? "" : "s",
+ pb_tnc_batch_type_names, this->batch_type);
+ }
+ else
+ {
+ this->batch_type = PB_BATCH_NONE;
+ }
+
+ status = ALREADY_DONE;
+ }
+ else
+ {
+ change_batch_type(this, PB_BATCH_NONE);
+ status = INVALID_STATE;
+ }
+ }
+ else
+ {
+ DBG1(DBG_TNC, "no PB-TNC batch to send");
+ status = INVALID_STATE;
+ }
+ this->mutex->unlock(this->mutex);
+
+ return status;
+}
+
+METHOD(tls_t, is_server, bool,
+ private_tnccs_20_t *this)
+{
+ return this->is_server;
+}
+
+METHOD(tls_t, get_server_id, identification_t*,
+ private_tnccs_20_t *this)
+{
+ return this->server;
+}
+
+METHOD(tls_t, get_peer_id, identification_t*,
+ private_tnccs_20_t *this)
+{
+ return this->peer;
+}
+
+METHOD(tls_t, get_purpose, tls_purpose_t,
+ private_tnccs_20_t *this)
+{
+ return TLS_PURPOSE_EAP_TNC;
+}
+
+METHOD(tls_t, is_complete, bool,
+ private_tnccs_20_t *this)
+{
+ TNC_IMV_Action_Recommendation rec;
+ TNC_IMV_Evaluation_Result eval;
+
+ if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval))
+ {
+ return tnc->imvs->enforce_recommendation(tnc->imvs, rec, eval);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+METHOD(tls_t, get_eap_msk, chunk_t,
+ private_tnccs_20_t *this)
+{
+ return chunk_empty;
+}
+
+METHOD(tls_t, destroy, void,
+ private_tnccs_20_t *this)
+{
+ tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id,
+ this->is_server);
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ this->state_machine->destroy(this->state_machine);
+ this->mutex->destroy(this->mutex);
+ this->messages->destroy_offset(this->messages,
+ offsetof(pb_tnc_msg_t, destroy));
+ free(this);
+}
+
+METHOD(tnccs_t, get_transport, tnc_ift_type_t,
+ private_tnccs_20_t *this)
+{
+ return this->transport;
+}
+
+METHOD(tnccs_t, set_transport, void,
+ private_tnccs_20_t *this, tnc_ift_type_t transport)
+{
+ this->transport = transport;
+}
+
+METHOD(tnccs_t, get_auth_type, u_int32_t,
+ private_tnccs_20_t *this)
+{
+ return this->auth_type;
+}
+
+METHOD(tnccs_t, set_auth_type, void,
+ private_tnccs_20_t *this, u_int32_t auth_type)
+{
+ this->auth_type = auth_type;
+}
+
+/**
+ * See header
+ */
+tnccs_t* tnccs_20_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport)
+{
+ private_tnccs_20_t *this;
+
+ INIT(this,
+ .public = {
+ .tls = {
+ .process = _process,
+ .build = _build,
+ .is_server = _is_server,
+ .get_server_id = _get_server_id,
+ .get_peer_id = _get_peer_id,
+ .get_purpose = _get_purpose,
+ .is_complete = _is_complete,
+ .get_eap_msk = _get_eap_msk,
+ .destroy = _destroy,
+ },
+ .get_transport = _get_transport,
+ .set_transport = _set_transport,
+ .get_auth_type = _get_auth_type,
+ .set_auth_type = _set_auth_type,
+ },
+ .is_server = is_server,
+ .server = server->clone(server),
+ .peer = peer->clone(peer),
+ .transport = transport,
+ .state_machine = pb_tnc_state_machine_create(is_server),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .messages = linked_list_create(),
+ .max_batch_len = lib->settings->get_int(lib->settings,
+ "libtnccs.plugins.tnccs-20.max_batch_size", 65522),
+ .max_msg_len = lib->settings->get_int(lib->settings,
+ "libtnccs.plugins.tnccs-20.max_message_size", 65490),
+ );
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.h b/src/libtnccs/plugins/tnccs_20/tnccs_20.h
new file mode 100644
index 000000000..314935069
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010-2013 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.
+ */
+
+/**
+ * @defgroup tnccs_20_h tnccs_20
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef TNCCS_20_H_
+#define TNCCS_20_H_
+
+#include <library.h>
+
+#include <tnc/tnccs/tnccs.h>
+
+/**
+ * Create an instance of the TNC IF-TNCCS 2.0 protocol handler.
+ *
+ * @param is_server TRUE to act as TNC Server, FALSE for TNC Client
+ * @param server Server identity
+ * @param peer Client identity
+ * @param transport Underlying IF-T transport protocol
+ * @return TNC_IF_TNCCS 2.0 protocol stack
+ */
+tnccs_t* tnccs_20_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport);
+
+#endif /** TNCCS_20_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.c b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.c
new file mode 100644
index 000000000..f74306c8c
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "tnccs_20_plugin.h"
+#include "tnccs_20.h"
+
+#include <tnc/tnccs/tnccs_manager.h>
+
+METHOD(plugin_t, get_name, char*,
+ tnccs_20_plugin_t *this)
+{
+ return "tnccs-20";
+}
+
+METHOD(plugin_t, get_features, int,
+ tnccs_20_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(tnccs_method_register, tnccs_20_create),
+ PLUGIN_PROVIDE(CUSTOM, "tnccs-2.0"),
+ PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ tnccs_20_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnccs_20_plugin_create()
+{
+ tnccs_20_plugin_t *this;
+
+ INIT(this,
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->plugin;
+}
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h
new file mode 100644
index 000000000..1c4ecf4c9
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup tnccs_20 tnccs_20
+ * @ingroup cplugins
+ *
+ * @defgroup tnccs_20_plugin tnccs_20_plugin
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef TNCCS_20_PLUGIN_H_
+#define TNCCS_20_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnccs_20_plugin_t tnccs_20_plugin_t;
+
+/**
+ * EAP-TNC plugin
+ */
+struct tnccs_20_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNCCS_20_PLUGIN_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_dynamic/Makefile.am b/src/libtnccs/plugins/tnccs_dynamic/Makefile.am
new file mode 100644
index 000000000..1a2887816
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_dynamic/Makefile.am
@@ -0,0 +1,22 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtls \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtnccs
+
+AM_CFLAGS = \
+ -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnccs-dynamic.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnccs-dynamic.la
+libstrongswan_tnccs_dynamic_la_LIBADD = \
+ $(top_builddir)/src/libtncif/libtncif.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnccs_dynamic_la_SOURCES = \
+ tnccs_dynamic_plugin.h tnccs_dynamic_plugin.c tnccs_dynamic.h tnccs_dynamic.c
+
+libstrongswan_tnccs_dynamic_la_LDFLAGS = -module -avoid-version
diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c
new file mode 100644
index 000000000..d4fc6a6f7
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2011-2013 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 "tnccs_dynamic.h"
+
+#include <tnc/tnc.h>
+
+#include <utils/debug.h>
+
+typedef struct private_tnccs_dynamic_t private_tnccs_dynamic_t;
+
+/**
+ * Private data of a tnccs_dynamic_t object.
+ */
+struct private_tnccs_dynamic_t {
+
+ /**
+ * Public tnccs_t interface.
+ */
+ tnccs_t public;
+
+ /**
+ * Server identity
+ */
+ identification_t *server;
+
+ /**
+ * Client identity
+ */
+ identification_t *peer;
+
+ /**
+ * Detected TNC IF-TNCCS stack
+ */
+ tls_t *tls;
+
+ /**
+ * Underlying TNC IF-T transport protocol
+ */
+ tnc_ift_type_t transport;
+
+ /**
+ * Type of TNC client authentication
+ */
+ u_int32_t auth_type;
+
+};
+
+/**
+ * Determine the version of the IF-TNCCS protocol used by analyzing the first
+ * byte of the TNCCS batch received from a TNC Client according to the rules
+ * defined by section 3.5 "Interoperability with older IF-TNCCS versions" of
+ * the TCG TNC IF-TNCCS TLV Bindings Version 2.0 standard.
+ */
+tnccs_type_t determine_tnccs_protocol(char version)
+{
+ switch (version)
+ {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ':
+ case '<':
+ return TNCCS_1_1;
+ case 0x00:
+ return TNCCS_SOH;
+ case 0x02:
+ return TNCCS_2_0;
+ default:
+ return TNCCS_UNKNOWN;
+ }
+}
+
+METHOD(tls_t, process, status_t,
+ private_tnccs_dynamic_t *this, void *buf, size_t buflen)
+{
+ tnccs_type_t type;
+ tnccs_t *tnccs;
+
+ if (!this->tls)
+ {
+ if (buflen == 0)
+ {
+ return FAILED;
+ }
+ type = determine_tnccs_protocol(*(char*)buf);
+ DBG1(DBG_TNC, "%N protocol detected dynamically",
+ tnccs_type_names, type);
+ tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, TRUE,
+ this->server, this->peer, this->transport);
+ if (!tnccs)
+ {
+ DBG1(DBG_TNC, "N% protocol not supported", tnccs_type_names, type);
+ return FAILED;
+ }
+ tnccs->set_auth_type(tnccs, this->auth_type);
+ this->tls = &tnccs->tls;
+ }
+ return this->tls->process(this->tls, buf, buflen);
+}
+
+METHOD(tls_t, build, status_t,
+ private_tnccs_dynamic_t *this, void *buf, size_t *buflen, size_t *msglen)
+{
+ return this->tls->build(this->tls, buf, buflen, msglen);
+}
+
+METHOD(tls_t, is_server, bool,
+ private_tnccs_dynamic_t *this)
+{
+ return TRUE;
+}
+
+METHOD(tls_t, get_server_id, identification_t*,
+ private_tnccs_dynamic_t *this)
+{
+ return this->server;
+}
+
+METHOD(tls_t, get_peer_id, identification_t*,
+ private_tnccs_dynamic_t *this)
+{
+ return this->peer;
+}
+
+METHOD(tls_t, get_purpose, tls_purpose_t,
+ private_tnccs_dynamic_t *this)
+{
+ return TLS_PURPOSE_EAP_TNC;
+}
+
+METHOD(tls_t, is_complete, bool,
+ private_tnccs_dynamic_t *this)
+{
+ return this->tls ? this->tls->is_complete(this->tls) : FALSE;
+}
+
+METHOD(tls_t, get_eap_msk, chunk_t,
+ private_tnccs_dynamic_t *this)
+{
+ return chunk_empty;
+}
+
+METHOD(tls_t, destroy, void,
+ private_tnccs_dynamic_t *this)
+{
+ DESTROY_IF(this->tls);
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ free(this);
+}
+
+METHOD(tnccs_t, get_transport, tnc_ift_type_t,
+ private_tnccs_dynamic_t *this)
+{
+ return this->transport;
+}
+
+METHOD(tnccs_t, set_transport, void,
+ private_tnccs_dynamic_t *this, tnc_ift_type_t transport)
+{
+ this->transport = transport;
+}
+
+METHOD(tnccs_t, get_auth_type, u_int32_t,
+ private_tnccs_dynamic_t *this)
+{
+ return this->auth_type;
+}
+
+METHOD(tnccs_t, set_auth_type, void,
+ private_tnccs_dynamic_t *this, u_int32_t auth_type)
+{
+ this->auth_type = auth_type;
+}
+
+/**
+ * See header
+ */
+tnccs_t* tnccs_dynamic_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport)
+{
+ private_tnccs_dynamic_t *this;
+
+ INIT(this,
+ .public = {
+ .tls = {
+ .process = _process,
+ .build = _build,
+ .is_server = _is_server,
+ .get_server_id = _get_server_id,
+ .get_peer_id = _get_peer_id,
+ .get_purpose = _get_purpose,
+ .is_complete = _is_complete,
+ .get_eap_msk = _get_eap_msk,
+ .destroy = _destroy,
+ },
+ .get_transport = _get_transport,
+ .set_transport = _set_transport,
+ .get_auth_type = _get_auth_type,
+ .set_auth_type = _set_auth_type,
+ },
+ .server = server->clone(server),
+ .peer = peer->clone(peer),
+ .transport = transport,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h
new file mode 100644
index 000000000..e4cff74b8
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011-2013 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.
+ */
+
+/**
+ * @defgroup tnccs_dynamic_h tnccs_dynamic
+ * @{ @ingroup tnccs_dynamic
+ */
+
+#ifndef TNCCS_DYNAMIC_H_
+#define TNCCS_DYNAMIC_H_
+
+#include <library.h>
+
+#include <tnc/tnccs/tnccs.h>
+
+/**
+ * Create an instance of a dynamic TNC IF-TNCCS protocol handler.
+ *
+ * @param is_server TRUE to act as TNC Server, FALSE for TNC Client
+ * @param server Server identity
+ * @param peer Client identity
+ * @param transport Underlying IF-T transport protocol
+ * @return dynamic TNC IF-TNCCS protocol stack
+ */
+tnccs_t* tnccs_dynamic_create(bool is_server,
+ identification_t *server,
+ identification_t *peer,
+ tnc_ift_type_t transport);
+
+#endif /** TNCCS_DYNAMIC_H_ @}*/
diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c
new file mode 100644
index 000000000..aac57813a
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 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 "tnccs_dynamic_plugin.h"
+#include "tnccs_dynamic.h"
+
+#include <tnc/tnccs/tnccs_manager.h>
+
+METHOD(plugin_t, get_name, char*,
+ tnccs_dynamic_plugin_t *this)
+{
+ return "tnccs-dynamic";
+}
+
+METHOD(plugin_t, get_features, int,
+ tnccs_dynamic_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(tnccs_method_register, tnccs_dynamic_create),
+ PLUGIN_PROVIDE(CUSTOM, "tnccs-dynamic"),
+ PLUGIN_DEPENDS(CUSTOM, "tnccs-1.1"),
+ PLUGIN_DEPENDS(CUSTOM, "tnccs-2.0"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ tnccs_dynamic_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnccs_dynamic_plugin_create()
+{
+ tnccs_dynamic_plugin_t *this;
+
+ INIT(this,
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->plugin;
+}
diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h
new file mode 100644
index 000000000..b518e1278
--- /dev/null
+++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/**
+ * @defgroup tnccs_dynamic tnccs_dynamic
+ * @ingroup cplugins
+ *
+ * @defgroup tnccs_dynamic_plugin tnccs_dynamic_plugin
+ * @{ @ingroup tnccs_dynamic
+ */
+
+#ifndef TNCCS_DYNAMIC_PLUGIN_H_
+#define TNCCS_DYNAMIC_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnccs_dynamic_plugin_t tnccs_dynamic_plugin_t;
+
+/**
+ * EAP-TNC plugin
+ */
+struct tnccs_dynamic_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNCCS_DYNAMIC_PLUGIN_H_ @}*/