diff options
Diffstat (limited to 'src/libtnccs/plugins/tnc_imc')
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/Makefile.am | 23 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc.c | 428 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc.h | 60 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_bind_function.c | 222 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c | 441 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_manager.h | 32 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c | 79 | ||||
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h | 42 |
8 files changed, 1327 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_ @}*/ |