ECB mode added to the DES plugin
[strongswan.git] / src / manager / gateway.c
index b918da2..6d5f6f7 100644 (file)
@@ -1,10 +1,3 @@
-/**
- * @file gateway.c
- *
- * @brief Implementation of gateway_t.
- *
- */
-
 /*
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
  * 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.
+ *
+ * $Id$
  */
 
 #include "gateway.h"
 #include <sys/socket.h>
 #include <unistd.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <xml.h>
 
 typedef struct private_gateway_t private_gateway_t;
 
@@ -45,7 +44,7 @@ struct private_gateway_t {
        char *name;
        
        /**
-        * connection information
+        * host to connect using tcp
         */
        host_t *host;
        
@@ -53,24 +52,46 @@ struct private_gateway_t {
         * socket file descriptor, > 0 if connected
         */
        int fd;
+       
+       /**
+        * unique id assigned to each xml message
+        */
+       int xmlid;
 };
 
+struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
+
 /**
  * establish connection to gateway
  */
 static bool connect_(private_gateway_t *this)
 {
+       int family, len;
+       struct sockaddr *addr;
+
        if (this->fd >= 0)
        {
                close(this->fd);
        }
-       this->fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (this->host)
+       {
+               family = AF_INET;
+               addr = this->host->get_sockaddr(this->host);
+               len = *this->host->get_sockaddr_len(this->host);
+       }
+       else
+       {
+               family = AF_UNIX;
+               addr = (struct sockaddr*)&unix_addr;
+               len = sizeof(unix_addr);
+       }
+       
+       this->fd = socket(family, SOCK_STREAM, 0);
        if (this->fd < 0)
        {
                return FALSE;
        }
-       if (connect(this->fd, this->host->get_sockaddr(this->host),
-                               *this->host->get_sockaddr_len(this->host)) != 0)
+       if (connect(this->fd, addr, len) != 0)
        {
                close(this->fd);
                this->fd = -1;
@@ -79,11 +100,10 @@ static bool connect_(private_gateway_t *this)
        return TRUE;
 }
 
-
 /**
  * Implementation of gateway_t.request.
  */
-static char* request(private_gateway_t *this, char *xml)
+static char* request(private_gateway_t *this, char *xml, ...)
 {
        if (this->fd < 0)
        {
@@ -96,18 +116,25 @@ static char* request(private_gateway_t *this, char *xml)
        {
                char buf[8096];
                ssize_t len;
+               va_list args;
                
-               len = strlen(xml);
-               if (send(this->fd, xml, len, 0) != len)
+               va_start(args, xml);
+               len = vsnprintf(buf, sizeof(buf), xml, args);
+               va_end(args);
+               if (len < 0 || len >= sizeof(buf))
                {
                        return NULL;
                }
-               len = recv(this->fd, buf, sizeof(buf) - 1, 0);
-               if (len < 0)
+               if (send(this->fd, buf, len, 0) != len)
                {
-                       return NULL;
+                       if (!connect_(this))
+                       {
+                               return NULL;
+                       }
+                       continue;
                }
-               if (len == 0)
+               len = recv(this->fd, buf, sizeof(buf) - 1, 0);
+               if (len <= 0)
                {
                        if (!connect_(this))
                        {
@@ -119,7 +146,210 @@ static char* request(private_gateway_t *this, char *xml)
                return strdup(buf);
        }
 }
+
+/**
+ * Implementation of gateway_t.query_ikesalist.
+ */
+static enumerator_t* query_ikesalist(private_gateway_t *this)
+{
+       char *str, *name, *value;
+       xml_t *xml;
+       enumerator_t *e1, *e2, *e3, *e4 = NULL;
+       
+       str = request(this,     "<message type=\"request\" id=\"%d\">"
+                                                       "<query>"
+                                                               "<ikesalist/>"
+                                                       "</query>"
+                                               "</message>", this->xmlid++);
+       if (str == NULL)
+       {
+               return NULL;
+       }
+       xml = xml_create(str);
+       if (xml == NULL)
+       {
+               return NULL;
+       }
+       
+       e1 = xml->children(xml);
+       free(str);
+       while (e1->enumerate(e1, &xml, &name, &value))
+       {
+               if (streq(name, "message"))
+               {
+                       e2 = xml->children(xml);
+                       while (e2->enumerate(e2, &xml, &name, &value))
+                       {
+                               if (streq(name, "query"))
+                               {
+                                       e3 = xml->children(xml);
+                                       while (e3->enumerate(e3, &xml, &name, &value))
+                                       {
+                                               if (streq(name, "ikesalist"))
+                                               {
+                                                       e4 = xml->children(xml);
+                                                       e1->destroy(e1);
+                                                       e2->destroy(e2);
+                                                       e3->destroy(e3);
+                                                       return e4;
+                                               }
+                                       }
+                                       e3->destroy(e3);
+                               }
+                       }
+                       e2->destroy(e2);
+               }
+       }
+       e1->destroy(e1);
+       return NULL;
+}
+
+       
+/**
+ * Implementation of gateway_t.query_configlist.
+ */
+static enumerator_t* query_configlist(private_gateway_t *this)
+{
+       char *str, *name, *value;
+       xml_t *xml;
+       enumerator_t *e1, *e2, *e3, *e4 = NULL;
+       
+       str = request(this,     "<message type=\"request\" id=\"%d\">"
+                                                       "<query>"
+                                                               "<configlist/>"
+                                                       "</query>"
+                                               "</message>", this->xmlid++);
+       if (str == NULL)
+       {
+               return NULL;
+       }
+       xml = xml_create(str);
+       if (xml == NULL)
+       {
+               return NULL;
+       }
+       
+       e1 = xml->children(xml);
+       free(str);
+       while (e1->enumerate(e1, &xml, &name, &value))
+       {
+               if (streq(name, "message"))
+               {
+                       e2 = xml->children(xml);
+                       while (e2->enumerate(e2, &xml, &name, &value))
+                       {
+                               if (streq(name, "query"))
+                               {
+                                       e3 = xml->children(xml);
+                                       while (e3->enumerate(e3, &xml, &name, &value))
+                                       {
+                                               if (streq(name, "configlist"))
+                                               {
+                                                       e4 = xml->children(xml);
+                                                       e1->destroy(e1);
+                                                       e2->destroy(e2);
+                                                       e3->destroy(e3);
+                                                       return e4;
+                                               }
+                                       }
+                                       e3->destroy(e3);
+                               }
+                       }
+                       e2->destroy(e2);
+               }
+       }
+       e1->destroy(e1);
+       return NULL;
+}
+
+/**
+ * create enumerator over control elements children of a control response
+ */
+static enumerator_t* read_result(private_gateway_t *this, char *res)
+{
+       char *name, *value;
+       xml_t *xml;
+       enumerator_t *e1, *e2, *e3;
+
+       if (res == NULL)
+       {
+               return NULL;
+       }
+       xml = xml_create(res);
+       if (xml == NULL)
+       {
+               return NULL;
+       }
+       e1 = xml->children(xml);
+       free(res);
+       while (e1->enumerate(e1, &xml, &name, &value))
+       {
+               if (streq(name, "message"))
+               {
+                       e2 = xml->children(xml);
+                       while (e2->enumerate(e2, &xml, &name, &value))
+                       {
+                               if (streq(name, "control"))
+                               {
+                                       e3 = xml->children(xml);
+                                       e1->destroy(e1);
+                                       e2->destroy(e2);
+                                       return e3;
+                               }
+                       }
+                       e2->destroy(e2);
+               }
+       }
+       e1->destroy(e1);
+       return NULL;
+}
+
+/**
+ * Implementation of gateway_t.initiate.
+ */
+static enumerator_t* initiate(private_gateway_t *this, bool ike, char *name)
+{
+       char *str, *kind;
+       
+       if (ike)
+       {
+               kind = "ike";
+       }
+       else
+       {
+               kind = "child";
+       }
+       str = request(this,     "<message type=\"request\" id=\"%d\">"
+                                                       "<control>"
+                                                               "<%ssainitiate>%s</%ssainitiate>"
+                                                       "</control>"
+                                               "</message>", this->xmlid++, kind, name, kind);
+       return read_result(this, str);
+}
+
+/**
+ * Implementation of gateway_t.terminate.
+ */
+static enumerator_t* terminate(private_gateway_t *this, bool ike, u_int32_t id)
+{
+       char *str, *kind;
        
+       if (ike)
+       {
+               kind = "ike";
+       }
+       else
+       {
+               kind = "child";
+       }
+       str = request(this,     "<message type=\"request\" id=\"%d\">"
+                                                       "<control>"
+                                                               "<%ssaterminate>%d</%ssaterminate>"
+                                                       "</control>"
+                                               "</message>", this->xmlid++, kind, id, kind);
+       return read_result(this, str);
+}
+
 /**
  * Implementation of gateway_t.destroy
  */
@@ -129,24 +359,51 @@ static void destroy(private_gateway_t *this)
        {
                close(this->fd);
        }
-       this->host->destroy(this->host);
+       if (this->host) this->host->destroy(this->host);
        free(this->name);
        free(this);
 }
 
-/*
- * see header file
+/**
+ * generic constructor
  */
-gateway_t *gateway_create(char *name, host_t *host)
+static private_gateway_t *gateway_create(char *name)
 {
        private_gateway_t *this = malloc_thing(private_gateway_t);
        
        this->public.request = (char*(*)(gateway_t*, char *xml))request;
+       this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist;
+       this->public.query_configlist = (enumerator_t*(*)(gateway_t*))query_configlist;
+       this->public.initiate = (enumerator_t*(*)(gateway_t*, bool ike, char *name))initiate;
+       this->public.terminate = (enumerator_t*(*)(gateway_t*, bool ike, u_int32_t id))terminate;
        this->public.destroy = (void(*)(gateway_t*))destroy;
        
        this->name = strdup(name);
-       this->host = host;
+       this->host = NULL;
        this->fd = -1;
+       this->xmlid = 1;
+       
+       return this;
+}
+
+/**
+ * see header
+ */
+gateway_t *gateway_create_tcp(char *name, host_t *host)
+{
+       private_gateway_t *this = gateway_create(name);
+       
+       this->host = host;
+       
+       return &this->public;
+}
+
+/**
+ * see header
+ */
+gateway_t *gateway_create_unix(char *name)
+{
+       private_gateway_t *this = gateway_create(name);
        
        return &this->public;
 }