diff options
Diffstat (limited to 'src/libtnccs/plugins/tnccs_11')
21 files changed, 2943 insertions, 0 deletions
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_ @}*/ |