diff --git a/src/libcharon/plugins/tnc_ifmap2/Makefile.am b/src/libcharon/plugins/tnc_ifmap2/Makefile.am index 11524795c..217d8972f 100644 --- a/src/libcharon/plugins/tnc_ifmap2/Makefile.am +++ b/src/libcharon/plugins/tnc_ifmap2/Makefile.am @@ -20,7 +20,8 @@ libstrongswan_tnc_ifmap2_la_LIBADD = \ libstrongswan_tnc_ifmap2_la_SOURCES = \ tnc_ifmap2_plugin.h tnc_ifmap2_plugin.c \ tnc_ifmap2_listener.h tnc_ifmap2_listener.c \ - tnc_ifmap2_soap.h tnc_ifmap2_soap.c + tnc_ifmap2_soap.h tnc_ifmap2_soap.c \ + tnc_ifmap2_soap_msg.h tnc_ifmap2_soap_msg.c libstrongswan_tnc_ifmap2_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c index 65f92653b..4c9334dbd 100644 --- a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c +++ b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c @@ -13,28 +13,20 @@ * for more details. */ -#define _GNU_SOURCE /* for asprintf() */ - #include "tnc_ifmap2_soap.h" +#include "tnc_ifmap2_soap_msg.h" #include -#include #include #include #include -#include - -#define _GNU_SOURCE - -#include #include #include #include #include -#define SOAP_NS "http://www.w3.org/2003/05/soap-envelope" #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2" #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2" #define IFMAP_LOGFILE "strongswan_ifmap.log" @@ -90,206 +82,11 @@ struct private_tnc_ifmap2_soap_t { }; -/** - * Send HTTP POST request and receive HTTP response - */ -static bool http_send_receive(private_tnc_ifmap2_soap_t *this, chunk_t out, - chunk_t *in) -{ - char header[] = - "POST /ifmap HTTP/1.1\r\n" - "Content-Type: application/soap+xml;charset=utf-8\r\n" - "Content-Length: "; - char *request, response[2048]; - chunk_t line, http, parameter; - int len, code, content_len = 0; - - /* Write HTTP POST request */ - len = asprintf(&request, "%s%d\r\n\r\n%.*s", header, out.len, - out.len, out.ptr); - if (len == -1) - { - return FALSE; - } - this->tls->write(this->tls, request, len); - free(request); - - /* Read HTTP response */ - len = this->tls->read(this->tls, response, sizeof(response), TRUE); - if (len == -1) - { - return FALSE; - } - *in = chunk_create(response, len); - - /* Process HTTP protocol version */ - if (!fetchline(in, &line) || !extract_token(&http, ' ', &line) || - !match("HTTP/1.1", &http) || sscanf(line.ptr, "%d", &code) != 1) - { - DBG1(DBG_TNC, "malformed http response header"); - return FALSE; - } - if (code != 200) - { - DBG1(DBG_TNC, "http response returns error code %d", code); - return FALSE; - } - - /* Process HTTP header line by line until the HTTP body is reached */ - while (fetchline(in, &line)) - { - if (line.len == 0) - { - break; - } - - if (extract_token(¶meter, ':', &line) && - match("Content-Length", ¶meter) && - sscanf(line.ptr, "%d", &len) == 1) - { - content_len = len; - } - } - - /* Found Content-Length parameter and check size of HTTP body */ - if (content_len) - { - if (content_len > in->len) - { - DBG1(DBG_TNC, "http body is smaller than content length"); - return FALSE; - } - in->len = content_len; - } - *in = chunk_clone(*in); - - return TRUE; -} - -/** - * Find a child node with a given name - */ -static xmlNodePtr find_child(xmlNodePtr parent, const xmlChar* name) -{ - xmlNodePtr child; - - child = parent->xmlChildrenNode; - while (child) - { - if (xmlStrcmp(child->name, name) == 0) - { - return child; - } - child = child->next; - } - - DBG1(DBG_TNC, "child node \"%s\" not found", name); - return NULL; -} - -/** - * Send request and receive result via SOAP - */ -static bool soap_send_receive(private_tnc_ifmap2_soap_t *this, - char *request_name, xmlNodePtr request, - char *result_name, xmlNodePtr *result, - xmlDocPtr *result_doc) -{ - xmlDocPtr doc; - xmlNodePtr env, body, cur; - xmlNsPtr ns; - xmlChar *xml; - int len; - chunk_t in, out; - - *result_doc = NULL; - DBG2(DBG_TNC, "sending ifmap %s", request_name); - - /* Generate XML Document containing SOAP Envelope */ - doc = xmlNewDoc("1.0"); - env =xmlNewNode(NULL, "Envelope"); - ns = xmlNewNs(env, SOAP_NS, "env"); - xmlSetNs(env, ns); - xmlDocSetRootElement(doc, env); - - /* Add SOAP Body containing IF-MAP request */ - body = xmlNewNode(ns, "Body"); - xmlAddChild(body, request); - xmlAddChild(env, body); - - /* Convert XML Document into a character string */ - xmlDocDumpFormatMemory(doc, &xml, &len, 1); - xmlFreeDoc(doc); - DBG3(DBG_TNC, "%.*s", len, xml); - out = chunk_create(xml, len); - - /* Send SOAP-XML request via HTTP */ - if (!http_send_receive(this, out, &in)) - { - xmlFree(xml); - return FALSE; - } - xmlFree(xml); - - DBG3(DBG_TNC, "%B", &in); - doc = xmlParseMemory(in.ptr, in.len); - free(in.ptr); - - if (!doc) - { - DBG1(DBG_TNC, "failed to parse XML message"); - return FALSE; - } - *result_doc = doc; - - /* check out XML document */ - cur = xmlDocGetRootElement(doc); - if (!cur) - { - DBG1(DBG_TNC, "empty XML message"); - return FALSE; - } - - /* get XML Document type is a SOAP Envelope */ - if (xmlStrcmp(cur->name, "Envelope")) - { - DBG1(DBG_TNC, "XML message does not contain a SOAP Envelope"); - return FALSE; - } - - /* get SOAP Body */ - cur = find_child(cur, "Body"); - if (!cur) - { - return FALSE; - } - - /* get IF-MAP response */ - cur = find_child(cur, "response"); - if (!cur) - { - return FALSE; - } - - /* get IF-MAP result */ - cur = find_child(cur, result_name); - if (!cur) - { - return FALSE; - } - - if (result) - { - *result = cur; - } - return TRUE; -} - METHOD(tnc_ifmap2_soap_t, newSession, bool, private_tnc_ifmap2_soap_t *this) { + tnc_ifmap2_soap_msg_t *soap_msg; xmlNodePtr request, result; - xmlDocPtr result_doc; xmlNsPtr ns; /*build newSession request */ @@ -297,20 +94,18 @@ METHOD(tnc_ifmap2_soap_t, newSession, bool, ns = xmlNewNs(request, IFMAP_NS, "ifmap"); xmlSetNs(request, ns); - if (!soap_send_receive(this, "newSession", request, "newSessionResult", - &result, &result_doc)) + soap_msg = tnc_ifmap2_soap_msg_create(this->tls); + if (!soap_msg->post(soap_msg, "newSession", request, + "newSessionResult", &result)) { - if (result_doc) - { - xmlFreeDoc(result_doc); - } + soap_msg->destroy(soap_msg); return FALSE; } /* get session-id and ifmap-publisher-id properties */ this->session_id = xmlGetProp(result, "session-id"); this->ifmap_publisher_id = xmlGetProp(result, "ifmap-publisher-id"); - xmlFreeDoc(result_doc); + soap_msg->destroy(soap_msg); DBG1(DBG_TNC, "session-id: %s, ifmap-publisher-id: %s", this->session_id, this->ifmap_publisher_id); @@ -327,8 +122,8 @@ METHOD(tnc_ifmap2_soap_t, newSession, bool, METHOD(tnc_ifmap2_soap_t, purgePublisher, bool, private_tnc_ifmap2_soap_t *this) { + tnc_ifmap2_soap_msg_t *soap_msg; xmlNodePtr request; - xmlDocPtr result_doc; xmlNsPtr ns; bool success; @@ -339,12 +134,11 @@ METHOD(tnc_ifmap2_soap_t, purgePublisher, bool, xmlNewProp(request, "session-id", this->session_id); xmlNewProp(request, "ifmap-publisher-id", this->ifmap_publisher_id); - success = soap_send_receive(this, "purgePublisher", request, - "purgePublisherReceived", NULL, &result_doc); - if (result_doc) - { - xmlFreeDoc(result_doc); - } + soap_msg = tnc_ifmap2_soap_msg_create(this->tls); + success = soap_msg->post(soap_msg, "purgePublisher", request, + "purgePublisherReceived", NULL); + soap_msg->destroy(soap_msg); + return success; } diff --git a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.c b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.c new file mode 100644 index 000000000..7bea62d83 --- /dev/null +++ b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE /* for asprintf() */ + +#include "tnc_ifmap2_soap_msg.h" + +#include +#include + +#include + +#define SOAP_NS "http://www.w3.org/2003/05/soap-envelope" + +typedef struct private_tnc_ifmap2_soap_msg_t private_tnc_ifmap2_soap_msg_t; + +/** + * Private data of an tnc_ifmap2_soap_msg_t object. + */ +struct private_tnc_ifmap2_soap_msg_t { + + /** + * Public tnc_ifmap2_soap_msg_t interface. + */ + tnc_ifmap2_soap_msg_t public; + + /** + * TLS Socket + */ + tls_socket_t *tls; + + /** + * XML Document + */ + xmlDocPtr doc; + +}; + +/** + * Send HTTP POST request and receive HTTP response + */ +static bool http_send_receive(private_tnc_ifmap2_soap_msg_t *this, + chunk_t out, chunk_t *in) +{ + char header[] = + "POST /ifmap HTTP/1.1\r\n" + "Content-Type: application/soap+xml;charset=utf-8\r\n" + "Content-Length: "; + char *request, response[2048]; + chunk_t line, http, parameter; + int len, code, content_len = 0; + + /* Write HTTP POST request */ + len = asprintf(&request, "%s%d\r\n\r\n%.*s", header, out.len, + out.len, out.ptr); + if (len == -1) + { + return FALSE; + } + this->tls->write(this->tls, request, len); + free(request); + + /* Read HTTP response */ + len = this->tls->read(this->tls, response, sizeof(response), TRUE); + if (len == -1) + { + return FALSE; + } + *in = chunk_create(response, len); + + /* Process HTTP protocol version */ + if (!fetchline(in, &line) || !extract_token(&http, ' ', &line) || + !match("HTTP/1.1", &http) || sscanf(line.ptr, "%d", &code) != 1) + { + DBG1(DBG_TNC, "malformed http response header"); + return FALSE; + } + if (code != 200) + { + DBG1(DBG_TNC, "http response returns error code %d", code); + return FALSE; + } + + /* Process HTTP header line by line until the HTTP body is reached */ + while (fetchline(in, &line)) + { + if (line.len == 0) + { + break; + } + + if (extract_token(¶meter, ':', &line) && + match("Content-Length", ¶meter) && + sscanf(line.ptr, "%d", &len) == 1) + { + content_len = len; + } + } + + /* Found Content-Length parameter and check size of HTTP body */ + if (content_len) + { + if (content_len > in->len) + { + DBG1(DBG_TNC, "http body is smaller than content length"); + return FALSE; + } + in->len = content_len; + } + *in = chunk_clone(*in); + + return TRUE; +} + +/** + * Find a child node with a given name + */ +static xmlNodePtr find_child(xmlNodePtr parent, const xmlChar* name) +{ + xmlNodePtr child; + + child = parent->xmlChildrenNode; + while (child) + { + if (xmlStrcmp(child->name, name) == 0) + { + return child; + } + child = child->next; + } + + DBG1(DBG_TNC, "child node \"%s\" not found", name); + return NULL; +} + +METHOD(tnc_ifmap2_soap_msg_t, post, bool, + private_tnc_ifmap2_soap_msg_t *this, char *request_name, xmlNodePtr request, + char *result_name, xmlNodePtr *result) +{ + xmlDocPtr doc; + xmlNodePtr env, body, cur; + xmlNsPtr ns; + xmlChar *xml; + int len; + chunk_t in, out; + + DBG2(DBG_TNC, "sending ifmap %s", request_name); + + /* Generate XML Document containing SOAP Envelope */ + doc = xmlNewDoc("1.0"); + env =xmlNewNode(NULL, "Envelope"); + ns = xmlNewNs(env, SOAP_NS, "env"); + xmlSetNs(env, ns); + xmlDocSetRootElement(doc, env); + + /* Add SOAP Body containing IF-MAP request */ + body = xmlNewNode(ns, "Body"); + xmlAddChild(body, request); + xmlAddChild(env, body); + + /* Convert XML Document into a character string */ + xmlDocDumpFormatMemory(doc, &xml, &len, 1); + xmlFreeDoc(doc); + DBG3(DBG_TNC, "%.*s", len, xml); + out = chunk_create(xml, len); + + /* Send SOAP-XML request via HTTP */ + if (!http_send_receive(this, out, &in)) + { + xmlFree(xml); + return FALSE; + } + xmlFree(xml); + + DBG3(DBG_TNC, "%B", &in); + this->doc = xmlParseMemory(in.ptr, in.len); + free(in.ptr); + + if (!this->doc) + { + DBG1(DBG_TNC, "failed to parse XML message"); + return FALSE; + } + + /* check out XML document */ + cur = xmlDocGetRootElement(this->doc); + if (!cur) + { + DBG1(DBG_TNC, "empty XML message"); + return FALSE; + } + + /* get XML Document type is a SOAP Envelope */ + if (xmlStrcmp(cur->name, "Envelope")) + { + DBG1(DBG_TNC, "XML message does not contain a SOAP Envelope"); + return FALSE; + } + + /* get SOAP Body */ + cur = find_child(cur, "Body"); + if (!cur) + { + return FALSE; + } + + /* get IF-MAP response */ + cur = find_child(cur, "response"); + if (!cur) + { + return FALSE; + } + + /* get IF-MAP result */ + cur = find_child(cur, result_name); + if (!cur) + { + return FALSE; + } + + if (result) + { + *result = cur; + } + return TRUE; +} + +METHOD(tnc_ifmap2_soap_msg_t, destroy, void, + private_tnc_ifmap2_soap_msg_t *this) +{ + if (this->doc) + { + xmlFreeDoc(this->doc); + } + free(this); +} + +/** + * See header + */ +tnc_ifmap2_soap_msg_t *tnc_ifmap2_soap_msg_create(tls_socket_t *tls) +{ + private_tnc_ifmap2_soap_msg_t *this; + + INIT(this, + .public = { + .post = _post, + .destroy = _destroy, + }, + .tls = tls, + ); + + return &this->public; +} + diff --git a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.h b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.h new file mode 100644 index 000000000..21ab5eecd --- /dev/null +++ b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap_msg.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 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 . + * + * 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_ifmap2_soap_msg tnc_ifmap2_soap_msg + * @{ @ingroup tnc_ifmap2 + */ + +#ifndef TNC_IFMAP2_SOAP_MSG_H_ +#define TNC_IFMAP2_SOAP_MSG_H_ + +#include +#include + +#include + +typedef struct tnc_ifmap2_soap_msg_t tnc_ifmap2_soap_msg_t; + +/** + * Interface for sending and receiving SOAP-XML messages + */ +struct tnc_ifmap2_soap_msg_t { + + /** + * Post an IF-MAP request in a SOAP-XML message and return a result + * + * @param request_name name of the IF-MAP request + * @param request XML-encoded IF-MAP request + * @param result_name name of the IF-MAP result + * @param result XML-encoded IF-MAP result + */ + bool (*post)(tnc_ifmap2_soap_msg_t *this, + char *request_name, xmlNodePtr request, + char *result_name, xmlNodePtr* result); + + /** + * Destroy a tnc_ifmap2_soap_msg_t object. + */ + void (*destroy)(tnc_ifmap2_soap_msg_t *this); +}; + +/** + * Create a tnc_ifmap2_soap_msg instance. + * + * @param tls TLS socket protecting the SOAP message + */ +tnc_ifmap2_soap_msg_t *tnc_ifmap2_soap_msg_create(tls_socket_t *tls); + +#endif /** TNC_IFMAP2_SOAP_MSG_H_ @}*/