]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
implement NewSession and PurgePublisher messages using the libxml2 library
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 29 Mar 2013 21:29:12 +0000 (22:29 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 29 Mar 2013 21:29:12 +0000 (22:29 +0100)
configure.in
src/libcharon/plugins/tnc_ifmap2/Makefile.am
src/libcharon/plugins/tnc_ifmap2/gaga.txt [deleted file]
src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c

index 659d4e9bae3d387f94c40884477769d072e85668..5ad0f7e75d2025f447b7db1a2fb0b1dc65e9f98c 100644 (file)
@@ -169,11 +169,11 @@ ARG_ENABL_SET([xauth-eap],      [enable XAuth backend using EAP methods to verif
 ARG_ENABL_SET([xauth-pam],      [enable XAuth backend using PAM to verify passwords.])
 ARG_ENABL_SET([xauth-noauth],   [enable XAuth pseudo-backend that does not actually verify or even request any credentials.])
 ARG_ENABL_SET([tnc-ifmap],      [enable TNC IF-MAP module.])
-ARG_ENABL_SET([tnc-ifmap2],     [enable TNC IF-MAP v2 module.])
+ARG_ENABL_SET([tnc-ifmap2],     [enable TNC IF-MAP v2 module. Requires libxml])
 ARG_ENABL_SET([tnc-pdp],        [enable TNC policy decision point module.])
 ARG_ENABL_SET([tnc-imc],        [enable TNC IMC module.])
 ARG_ENABL_SET([tnc-imv],        [enable TNC IMV module.])
-ARG_ENABL_SET([tnccs-11],       [enable TNCCS 1.1 protocol module.])
+ARG_ENABL_SET([tnccs-11],       [enable TNCCS 1.1 protocol module. Requires libxml])
 ARG_ENABL_SET([tnccs-20],       [enable TNCCS 2.0 protocol module.])
 ARG_ENABL_SET([tnccs-dynamic],  [enable dynamic TNCCS protocol discovery module.])
 ARG_ENABL_SET([imc-test],       [enable IMC test module.])
@@ -339,7 +339,7 @@ if test x$fips_prf = xtrue; then
        fi
 fi
 
-if test x$smp = xtrue -o x$tnccs_11 = xtrue; then
+if test x$smp = xtrue -o x$tnccs_11 = xtrue -o x$tnc_ifmap2 = xtrue; then
        xml=true
 fi
 
index 20bb3ca0ec7c0090ccab0ea9adb207198964c87f..11524795ca3b99579130d0de5cf1b36bfe13bb50 100644 (file)
@@ -3,7 +3,8 @@ INCLUDES = \
        -I$(top_srcdir)/src/libstrongswan \
        -I$(top_srcdir)/src/libtls \
        -I$(top_srcdir)/src/libhydra \
-       -I$(top_srcdir)/src/libcharon
+       -I$(top_srcdir)/src/libcharon \
+       ${xml_CFLAGS}
 
 AM_CFLAGS = -rdynamic
 
@@ -13,7 +14,8 @@ else
 plugin_LTLIBRARIES = libstrongswan-tnc-ifmap2.la
 endif
 
-libstrongswan_tnc_ifmap2_la_LIBADD = $(top_builddir)/src/libtls/libtls.la
+libstrongswan_tnc_ifmap2_la_LIBADD = \
+       $(top_builddir)/src/libtls/libtls.la ${xml_LIBS}
 
 libstrongswan_tnc_ifmap2_la_SOURCES = \
        tnc_ifmap2_plugin.h tnc_ifmap2_plugin.c \
diff --git a/src/libcharon/plugins/tnc_ifmap2/gaga.txt b/src/libcharon/plugins/tnc_ifmap2/gaga.txt
deleted file mode 100644 (file)
index c93a50a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-POST /ifmap HTTP/1.1
-Content-Type: application/soap+xml; charset=utf-8
-Content-Length: 236
-
-<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
-  <soapenv:Body>
-    <ifmap:newSession xmlns:ifmap="http://www.trustedcomputinggroup.org/2010/IFMAP/2"></ifmap:newSession>
-  </soapenv:Body>
-</soapenv:Envelope>
-
-2013-03-27 20:29:56,704 [pool-5-thread-2] DEBUG  - ChannelAcceptor: New connection from 127.0.0.1:44019 on port 8444
-2013-03-27 20:29:56,887 [pool-6-thread-1] DEBUG  - ChannelThread: Client koala.strongsec.com authenticated successfully on channel 127.0.0.1:44019:0
-2013-03-27 20:29:56,891 [pool-1-thread-1] TRACE  - EventProcessor: RequestChannelEvent on channel 127.0.0.1:44019:0
-2013-03-27 20:29:57,057 [pool-1-thread-1] DEBUG  - EventProcessor: newSession for koala.strongsec.com on 127.0.0.1:44019:0
-2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE  - ClientService: newSession for koala.strongsec.com--515754026-1 and maxPollResultSize=5000000 bytes
-2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE  - Adding new Publisher: sessionid=1890214968-1490695359-237418166-218822252 publisherid=koala.strongsec.com--515754026-1
-2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE  - Creating new Publisher...
-2013-03-27 20:29:57,064 [pool-3-thread-1] TRACE  - ActionProcessor: Forward response to channel 127.0.0.1:44019:0
-2013-03-27 20:29:57,065 [pool-3-thread-1] DEBUG  - ChannelThread: Sending reply to koala.strongsec.com
-2013-03-27 20:29:57,066 [pool-3-thread-1] TRACE  - ChannelThread: Length of reply on wire=376
-2013-03-27 20:29:57,091 [pool-5-thread-2] DEBUG  - ChannelAcceptor: New connection from 127.0.0.1:44020 on port 8444
-2013-03-27 20:29:57,103 [pool-6-thread-1] DEBUG  - ChannelThread: 127.0.0.1:44019:0 closed
-2013-03-27 20:29:57,104 [pool-1-thread-2] DEBUG  - EventProcessor: Got ClosedChannelEvent for 127.0.0.1:44019:0
-2013-03-27 20:29:57,104 [pool-1-thread-2] DEBUG  - EventProcessor: Creating Timer for koala.strongsec.com
-
-2013-03-27 20:29:57,120 [pool-6-thread-2] DEBUG  - ChannelThread: Client koala.strongsec.com authenticated successfully on channel 127.0.0.1:44020:1
-2013-03-27 20:29:57,122 [pool-1-thread-3] TRACE  - EventProcessor: RequestChannelEvent on channel 127.0.0.1:44020:1
-2013-03-27 20:29:57,129 [pool-1-thread-3] DEBUG  - EventProcessor: purgePublisher for koala.strongsec.com on 127.0.0.1:44020:1
-2013-03-27 20:29:57,129 [pool-1-thread-3] TRACE  - EventProcessor: koala.strongsec.com uses 127.0.0.1:44020:1 as new SSRC
-2013-03-27 20:29:57,130 [pool-1-thread-3] TRACE  - EventProcessor: Cancel timer for koala.strongsec.com
-2013-03-27 20:29:57,130 [pool-1-thread-3] DEBUG  - ClientService: publisher{koala.strongsec.com--515754026-1} is purging 0 metadata objects of publisher{koala.strongsec.com--515754026-1}
-
index 994b36c0cc240d5963c157669442792565062b4c..65f92653b3e9c23a015696ca42fe1ac9606592e5 100644 (file)
  * for more details.
  */
 
+#define _GNU_SOURCE /* for asprintf() */
+
 #include "tnc_ifmap2_soap.h"
 
 #include <utils/debug.h>
+#include <utils/lexparser.h>
 #include <credentials/sets/mem_cred.h>
 #include <daemon.h>
 
 #include <tls_socket.h>
 
+#include <libxml/parser.h>
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
-#define IFMAP_NO_FD            -1
-#define IFMAP_SERVER_ID        "C=DE, ST=Niedersachsen, L=Hannover, O=Hochschule Hannover, OU=Trust@FHH, CN=irond.trust.inform.fh-hannover.de"         
+#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"
 #define IFMAP_SERVER   "https://localhost:8443/"
+#define IFMAP_NO_FD            -1
 
 typedef struct private_tnc_ifmap2_soap_t private_tnc_ifmap2_soap_t;
 
@@ -83,52 +91,235 @@ struct private_tnc_ifmap2_soap_t {
 };
 
 /**
- * Send request and receive result via SOAP
+ * Send HTTP POST request and receive HTTP response
  */
-static bool send_receive(private_tnc_ifmap2_soap_t *this,
-                                                                        char *request_qname, chunk_t request,
-                                                                        char *receipt_qname, chunk_t *result)
-
+static bool http_send_receive(private_tnc_ifmap2_soap_t *this, chunk_t out,
+                                                                                                                          chunk_t *in)
 {
-       int written, len;
-       char *pos;
-
-       char soap[] =
-               "<?xml version=\"1.0\"?>"
-               "<env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\">"
-               "  <env:Body>"
-               "    <ifmap:newSession xmlns:ifmap=\"http://www.trustedcomputinggroup.org/2010/IFMAP/2\"></ifmap:newSession>"
-               "  </env:Body>"
-               "</env:Envelope>";
-
-       char http_header[] =
+       char header[] =
                 "POST /ifmap HTTP/1.1\r\n"
-                "Content-Type: application/soap+xml; charset=utf-8\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(&parameter, ':', &line) &&
+                       match("Content-Length", &parameter) &&
+                       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);
 
-       char buf[2048];
-
-       pos = buf;
-       len = sizeof(buf);
-       written = snprintf(pos, len, "%s", http_header);
-       pos += written;
-       len -= written;
-       written = snprintf(pos, len, "%d\r\n\r\n%s", strlen(soap), soap);
-       this->tls->write(this->tls, buf, strlen(buf));
-       len = this->tls->read(this->tls, buf, sizeof(buf), TRUE);
-       *result = chunk_create(buf, len);
-       DBG2(DBG_TNC, "%B", result);
+       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)
 {
-       chunk_t request, result;
+       xmlNodePtr request, result;
+       xmlDocPtr result_doc;
+       xmlNsPtr ns;
+
+       /*build newSession request */
+       request = xmlNewNode(NULL, "newSession");
+       ns = xmlNewNs(request, IFMAP_NS, "ifmap");
+       xmlSetNs(request, ns);
 
-       send_receive(this, "newSession", request, "newSessionResult", &result);
+       if (!soap_send_receive(this, "newSession", request, "newSessionResult",
+                                                  &result, &result_doc))
+       {
+               if (result_doc)
+               {
+                       xmlFreeDoc(result_doc);
+               }
+               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);
+
+       DBG1(DBG_TNC, "session-id: %s, ifmap-publisher-id: %s",
+                                  this->session_id, this->ifmap_publisher_id);
+
+       /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
+       this->device_name = lib->settings->get_str(lib->settings,
+                                                                       "%s.plugins.tnc-ifmap2.device_name",
+                                                                        this->ifmap_publisher_id, charon->name);
+       this->device_name = strdup(this->device_name);
 
     return this->session_id && this->ifmap_publisher_id;
 }
@@ -136,10 +327,25 @@ METHOD(tnc_ifmap2_soap_t, newSession, bool,
 METHOD(tnc_ifmap2_soap_t, purgePublisher, bool,
        private_tnc_ifmap2_soap_t *this)
 {
-       /* send purgePublisher request and receive purgePublisherReceived */
-       /* return send_receive(this, "purgePublisher", request,
-                                                         "purgePublisherReceived", NULL); */
-       return FALSE;
+       xmlNodePtr request;
+       xmlDocPtr result_doc;
+       xmlNsPtr ns;
+       bool success;
+
+       /* build purgePublisher request */
+       request = xmlNewNode(NULL, "purgePublisher");
+       ns = xmlNewNs(request, IFMAP_NS, "ifmap");
+       xmlSetNs(request, ns);
+       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);
+       }
+       return success;
 }
 
 METHOD(tnc_ifmap2_soap_t, publish_ike_sa, bool,
@@ -203,7 +409,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this)
        private_key_t *key;
        identification_t *server_id, *client_id;
 
-       /** Load [self-signed] MAP server certificate */
+       /**
+        * Load [self-signed] MAP server certificate
+        */
        server_cert = lib->settings->get_str(lib->settings,
                                        "%s.plugins.tnc-ifmap2.server_cert", NULL, charon->name);
        if (!server_cert)
@@ -223,7 +431,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this)
        server_id = cert->get_subject(cert);
        this->creds->add_cert(this->creds, TRUE, cert);
 
-       /* Load MAP client certificate */
+       /**
+        * Load MAP client certificate
+        */
        client_cert = lib->settings->get_str(lib->settings,
                                        "%s.plugins.tnc-ifmap2.client_cert", NULL, charon->name);
        if (!client_cert)
@@ -243,7 +453,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this)
        client_id = cert->get_subject(cert);
        this->creds->add_cert(this->creds, TRUE, cert);
 
-       /* Load MAP client private key */
+       /**
+        * Load MAP client private key
+        */
        client_key = lib->settings->get_str(lib->settings,
                                        "%s.plugins.tnc-ifmap2.client_key", NULL, charon->name);
        if (!client_key)
@@ -262,7 +474,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this)
        DBG1(DBG_TNC, "loaded MAP client RSA private key from '%s'", client_key);
        this->creds->add_key(this->creds, key);
 
-       /* Open TCP socket and connect to MAP server */
+       /**
+        * Open TCP socket and connect to MAP server
+        */
        server = "127.0.0.1";
        this->host = host_create_from_dns(server, 0, 8444);
        if (!this->host)
@@ -286,7 +500,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this)
                return FALSE;
        }
 
-       /* Open TLS socket */
+       /**
+        * Open TLS socket
+        */
        this->tls = tls_socket_create(FALSE, server_id, client_id, this->fd, NULL);
        if (!this->tls)
        {