restructuring of configuration backends
authorMartin Willi <martin@strongswan.org>
Fri, 27 Apr 2007 14:25:08 +0000 (14:25 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 27 Apr 2007 14:25:08 +0000 (14:25 -0000)
added propotypes of new control interfaces (xml & dbus)
introduced loadable:
  configuration backends
  control interfaces
using pluggable modules as in EAP

27 files changed:
configure.in
src/charon/Makefile.am
src/charon/config/backend_manager.c [new file with mode: 0644]
src/charon/config/backend_manager.h [new file with mode: 0644]
src/charon/config/backends/backend.h
src/charon/config/backends/local_backend.c
src/charon/config/backends/local_backend.h
src/charon/config/backends/writeable_backend.h [new file with mode: 0644]
src/charon/config/cfg_store.c [deleted file]
src/charon/config/cfg_store.h [deleted file]
src/charon/control/controller.c [deleted file]
src/charon/control/controller.h [deleted file]
src/charon/control/interface_manager.c [new file with mode: 0644]
src/charon/control/interface_manager.h [new file with mode: 0644]
src/charon/control/interfaces/dbus_interface.c [new file with mode: 0644]
src/charon/control/interfaces/dbus_interface.h [new file with mode: 0644]
src/charon/control/interfaces/interface.h [new file with mode: 0644]
src/charon/control/interfaces/stroke_interface.c [new file with mode: 0755]
src/charon/control/interfaces/stroke_interface.h [new file with mode: 0644]
src/charon/control/interfaces/xml_interface.c [new file with mode: 0644]
src/charon/control/interfaces/xml_interface.h [new file with mode: 0644]
src/charon/control/stroke_interface.c [deleted file]
src/charon/control/stroke_interface.h [deleted file]
src/charon/daemon.c
src/charon/daemon.h
src/charon/sa/ike_sa.c
src/charon/sa/tasks/ike_auth.c

index 3748756..8b54b42 100644 (file)
@@ -75,9 +75,23 @@ AC_ARG_WITH(
 
 AC_ARG_WITH(
     [eapdir],
-    AS_HELP_STRING([--with-eapdir=dir],[path for pluggable EAP modules other than "ipsecdir/eap"]),
+    AS_HELP_STRING([--with-eapdir=dir],[path for pluggable EAP modules other than "ipsecdir/plugins/eap"]),
     [AC_SUBST(eapdir, "$withval")],
-    [AC_SUBST(eapdir, "${ipsecdir}/eap")]
+    [AC_SUBST(eapdir, "${ipsecdir}/plugins/eap")]
+)
+
+AC_ARG_WITH(
+    [backenddir],
+    AS_HELP_STRING([--with-backenddir=dir],[path for pluggable configuration backend modules other than "ipsecdir/plugins/backends"]),
+    [AC_SUBST(backenddir, "$withval")],
+    [AC_SUBST(backenddir, "${ipsecdir}/plugins/backends")]
+)
+
+AC_ARG_WITH(
+    [interfacedir],
+    AS_HELP_STRING([--with-interfacedir=dir],[path for pluggable control interface modules other than "ipsecdir/plugins/interfaces"]),
+    [AC_SUBST(interfacedir, "$withval")],
+    [AC_SUBST(interfacedir, "${ipsecdir}/plugins/interfaces")]
 )
 
 AC_ARG_WITH(
@@ -114,6 +128,26 @@ AC_ARG_ENABLE(
 AM_CONDITIONAL(USE_LIBLDAP, test x$ldap = xtrue)
 
 AC_ARG_ENABLE(
+    [dbus],
+    AS_HELP_STRING([--enable-dbus],[enable DBUS configuration and control interface (default is NO). Requires libdbus.]),
+    [if test x$enableval = xyes; then
+        dbus=true
+        AC_DEFINE(LIBDBUS)
+    fi]
+)
+AM_CONDITIONAL(USE_LIBDBUS, test x$dbus = xtrue)
+
+AC_ARG_ENABLE(
+    [xml],
+    AS_HELP_STRING([--enable-xml],[enable XML configuration and control interface (default is NO). Requires libxml.]),
+    [if test x$enableval = xyes; then
+        xml=true
+        AC_DEFINE(LIBXML)
+    fi]
+)
+AM_CONDITIONAL(USE_LIBXML, test x$xml = xtrue)
+
+AC_ARG_ENABLE(
     [smartcard],
     AS_HELP_STRING([--enable-smartcard],[enable smartcard support (default is NO).]),
     [if test x$enableval = xyes; then
@@ -199,6 +233,17 @@ if test "$http" = "true"; then
     AC_HAVE_LIBRARY([curl],[LIBS="$LIBS"],[AC_MSG_ERROR([HTTP enabled, but library curl not found])])
 fi
 
+if test "$dbus" = "true"; then
+       PKG_CHECK_MODULES(dbus, dbus-1,, AC_MSG_ERROR([No libdbus package information found]))
+       AC_SUBST(dbus_CFLAGS)
+       AC_SUBST(dbus_LIBS)
+fi
+
+if test "$xml" = "true"; then
+       PKG_CHECK_MODULES(xml, libxml-2.0,, AC_MSG_ERROR([No libxml2 package information found]))
+       AC_SUBST(xml_CFLAGS)
+       AC_SUBST(xml_LIBS)
+fi
 
 dnl =============================
 dnl  check required header files
@@ -236,7 +281,6 @@ AC_OUTPUT(
        src/pluto/Makefile
        src/whack/Makefile
        src/charon/Makefile
-dnl    src/charon/testing/Makefile
        src/stroke/Makefile
        src/ipsec/Makefile
        src/starter/Makefile
index 2dad491..48696b2 100644 (file)
@@ -1,17 +1,4 @@
-# SUBDIRS = . testing
 
-eap_LTLIBRARIES = libeapidentity.la
-
-# always build EAP Identity module
-libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
-libeapidentity_la_LDFLAGS = -module
-
-# build optional EAP modules
-if BUILD_EAP_SIM
-  eap_LTLIBRARIES += libeapsim.la
-  libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
-  libeapsim_la_LDFLAGS = -module
-endif
 
 ipsec_PROGRAMS = charon
 
@@ -20,16 +7,14 @@ bus/bus.c bus/bus.h \
 bus/listeners/file_logger.c bus/listeners/file_logger.h \
 bus/listeners/sys_logger.c bus/listeners/sys_logger.h \
 config/backends/backend.h \
-config/backends/local_backend.c config/backends/local_backend.h \
-config/cfg_store.c config/cfg_store.h \
+config/backend_manager.c config/backend_maanger.h \
 config/child_cfg.c config/child_cfg.h \
 config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
 config/ike_cfg.c config/ike_cfg.h \
 config/peer_cfg.c config/peer_cfg.h \
 config/proposal.c config/proposal.h \
 config/traffic_selector.c config/traffic_selector.h \
-control/controller.c control/controller.h \
-control/stroke_interface.c control/stroke_interface.h \
+control/interface_manager.c control/interface_manager.h \
 daemon.c daemon.h \
 encoding/generator.c encoding/generator.h \
 encoding/message.c encoding/message.h \
@@ -103,10 +88,58 @@ sa/tasks/task.c sa/tasks/task.h
 
 
 INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
-AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\"
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \
+       -DIPSEC_EAPDIR=\"${eapdir}\" -DIPSEC_BACKENDDIR=\"${backenddir}\" -DIPSEC_INTERFACEDIR=\"${interfacedir}\"
 charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm -ldl
 
 if USE_LIBCURL
-   charon_LDADD += -lcurl
+  charon_LDADD += -lcurl
+endif
+
+
+# build EAP plugins, EAP-Identity is always built
+#################################################
+eap_LTLIBRARIES =
+
+eap_LTLIBRARIES += libeapidentity.la
+libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
+libeapidentity_la_LDFLAGS = -module
+
+if BUILD_EAP_SIM
+  eap_LTLIBRARIES += libeapsim.la
+  libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
+  libeapsim_la_LDFLAGS = -module
+endif
+
+# build backends, local backend is always built
+###############################################
+backend_LTLIBRARIES =
+
+backend_LTLIBRARIES += liblocal.la
+liblocal_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c
+liblocal_la_LDFLAGS = -module
+
+# build control interfaces, stroke interface is always built
+############################################################
+interface_LTLIBRARIES =
+
+interface_LTLIBRARIES += libstroke.la
+libstroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c
+libstroke_la_LDFLAGS = -module
+
+if USE_LIBDBUS
+  interface_LTLIBRARIES += libdbus.la
+  libdbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c
+  libdbus_la_LDFLAGS = -module
+  libdbus_la_LIBADD = ${dbus_LIBS}
+  INCLUDES += ${dbus_CFLAGS}
+endif
+
+if USE_LIBXML
+  interface_LTLIBRARIES += libxml.la
+  libxml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c
+  libxml_la_LDFLAGS = -module
+  libxml_la_LIBADD = ${xml_LIBS}
+  INCLUDES += ${xml_CFLAGS}
 endif
 
diff --git a/src/charon/config/backend_manager.c b/src/charon/config/backend_manager.c
new file mode 100644 (file)
index 0000000..186273b
--- /dev/null
@@ -0,0 +1,244 @@
+/**
+ * @file backend_manager.c
+ * 
+ * @brief Implementation of backend_manager_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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 "backend_manager.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <config/backends/writeable_backend.h>
+
+
+typedef struct private_backend_manager_t private_backend_manager_t;
+
+/**
+ * Private data of an backend_manager_t object.
+ */
+struct private_backend_manager_t {
+
+       /**
+        * Public part of backend_manager_t object.
+        */
+       backend_manager_t public;
+       
+       /**
+        * list of registered backends
+        */
+       linked_list_t *backends;
+       
+       /**
+        * Additional list of writable backends.
+        */
+       linked_list_t *writeable;
+       
+       /**
+        * List of dlopen() handles we used to open backends
+        */
+       linked_list_t *handles;
+};
+
+/**
+ * implements backend_manager_t.get_ike_cfg.
+ */
+static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this, 
+                                                         host_t *my_host, host_t *other_host)
+{
+       backend_t *backend;
+       ike_cfg_t *config = NULL;
+       iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE);
+       while (config == NULL && iterator->iterate(iterator, (void**)&backend))
+       {
+               config = backend->get_ike_cfg(backend, my_host, other_host);
+       }
+       iterator->destroy(iterator);
+       return config;
+}
+
+/**
+ * implements backend_manager_t.get_peer_cfg.
+ */                    
+static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this,
+                                                               identification_t *my_id, identification_t *other_id,
+                                                               identification_t *other_ca, char *other_group,
+                                                           host_t *my_host, host_t *other_host)
+{
+       backend_t *backend;
+       peer_cfg_t *config = NULL;
+       iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE);
+       while (config == NULL && iterator->iterate(iterator, (void**)&backend))
+       {
+               config = backend->get_peer_cfg(backend, my_id, other_id, other_ca,
+                                                                          other_group, my_host, other_host);
+       }
+       iterator->destroy(iterator);
+       return config;
+}
+
+/**
+ * implements backend_manager_t.add_peer_cfg.
+ */    
+static void add_peer_cfg(private_backend_manager_t *this, peer_cfg_t *config)
+{
+       writeable_backend_t *backend;
+       
+       if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS)
+       {
+               backend->add_cfg(backend, config);
+       }
+}
+
+/**
+ * implements backend_manager_t.create_iterator.
+ */    
+static iterator_t* create_iterator(private_backend_manager_t *this)
+{
+       writeable_backend_t *backend;
+       
+       if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS)
+       {
+               return backend->create_iterator(backend);
+       }
+       /* give out an empty iterator if we have no writable backend*/
+       return this->writeable->create_iterator(this->writeable, TRUE);
+}
+
+/**
+ * load the configuration backend modules
+ */
+static void load_backends(private_backend_manager_t *this)
+{
+       struct dirent* entry;
+       struct stat stb;
+       DIR* dir;
+       
+       if (stat(IPSEC_BACKENDDIR, &stb) == -1 || !(stb.st_mode & S_IFDIR))
+       {
+               DBG1(DBG_CFG, "error opening backend modules directory "IPSEC_BACKENDDIR);
+               return;
+       }
+
+       dir = opendir(IPSEC_BACKENDDIR);
+       if (dir == NULL)
+       {
+               DBG1(DBG_CFG, "error opening backend modules directory "IPSEC_BACKENDDIR);
+               return;
+       }
+       
+       DBG1(DBG_CFG, "loading backend modules from '"IPSEC_BACKENDDIR"'");
+
+       while ((entry = readdir(dir)) != NULL)
+       {
+               char file[256];
+               backend_t *backend;
+               backend_constructor_t constructor;
+               void *handle;
+               char *ending;
+               
+               snprintf(file, sizeof(file), IPSEC_BACKENDDIR"/%s", entry->d_name);
+               
+               if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
+               {
+                       DBG2(DBG_CFG, "  skipping %s, doesn't look like a file",
+                                entry->d_name);
+                       continue;
+               }
+               ending = entry->d_name + strlen(entry->d_name) - 3;
+               if (ending <= entry->d_name || !streq(ending, ".so"))
+               {
+                       /* skip anything which does not look like a library */
+                       DBG2(DBG_CFG, "  skipping %s, doesn't look like a library",
+                                entry->d_name);
+                       continue;
+               }
+               /* try to load the library */
+               handle = dlopen(file, RTLD_LAZY);
+               if (handle == NULL)
+               {
+                       DBG1(DBG_CFG, "  opening backend module %s failed: %s",
+                                entry->d_name, dlerror());
+                       continue;
+               }
+               constructor = dlsym(handle, "backend_create");
+               if (constructor == NULL)
+               {
+                       DBG1(DBG_CFG, "  backend module %s has no backend_create() "
+                                "function, skipped", entry->d_name);
+                       dlclose(handle);
+                       continue;
+               }
+               
+               backend = constructor();
+               if (backend == NULL)
+               {
+                       DBG1(DBG_CFG, "  unable to create instance of backend "
+                                "module %s, skipped", entry->d_name);
+                       dlclose(handle);
+                       continue;
+               }
+               DBG1(DBG_CFG, "  loaded backend module successfully from %s", entry->d_name);
+               this->backends->insert_last(this->backends, backend);
+               if (backend->is_writeable(backend))
+               {
+                       this->writeable->insert_last(this->writeable, backend);
+               }
+               this->handles->insert_last(this->handles, handle);
+       }
+       closedir(dir);
+}
+
+/**
+ * Implementation of backend_manager_t.destroy.
+ */
+static void destroy(private_backend_manager_t *this)
+{
+       this->backends->destroy_offset(this->backends, offsetof(backend_t, destroy));
+       this->writeable->destroy(this->writeable);
+       this->handles->destroy_function(this->handles, (void*)dlclose);
+       free(this);
+}
+
+/*
+ * Described in header-file
+ */
+backend_manager_t *backend_manager_create()
+{
+       private_backend_manager_t *this = malloc_thing(private_backend_manager_t);
+       
+       this->public.get_ike_cfg = (ike_cfg_t*(*)(backend_manager_t*, host_t *, host_t *))get_ike_cfg;
+       this->public.get_peer_cfg = (peer_cfg_t*(*)(backend_manager_t*, identification_t *, identification_t *))get_peer_cfg;
+       this->public.add_peer_cfg = (void(*)(backend_manager_t*, peer_cfg_t*))add_peer_cfg;
+       this->public.create_iterator = (iterator_t*(*)(backend_manager_t*))create_iterator;
+       this->public.destroy = (void(*)(backend_manager_t*))destroy;
+       
+       this->backends = linked_list_create();
+       this->writeable = linked_list_create();
+       this->handles = linked_list_create();
+       
+       load_backends(this);
+       
+       return &this->public;
+}
+
diff --git a/src/charon/config/backend_manager.h b/src/charon/config/backend_manager.h
new file mode 100644 (file)
index 0000000..07cd9c5
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * @file backend_manager.h
+ * 
+ * @brief Interface backend_manager_t.
+ *  
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#ifndef BACKEND_MANAGER_H_
+#define BACKEND_MANAGER_H_
+
+typedef struct backend_manager_t backend_manager_t;
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/identification.h>
+#include <config/ike_cfg.h>
+#include <config/peer_cfg.h>
+#include <config/backends/backend.h>
+
+
+/**
+ * @brief A multiplexer to use multiple backends.
+ *
+ * Charon allows the use of multiple backend_manager backends simultaneously. To
+ * access all this backends by a single call, this class wraps multiple
+ * backends behind a single object.
+ * Backends may be registered and unregister at runtime dynamically.
+ * @verbatim
+
+   +---------+      +-----------+         +--------------+     |
+   |         |      |           |       +--------------+ |     |
+   | daemon  |----->| backend_- |     +--------------+ |-+  <==|==> IPC
+   |  core   |      | manager   |---->|   backends   |-+       |
+   |         |----->|           |     +--------------+         |
+   |         |      |           |                              |
+   +---------+      +-----------+                              |
+   
+   @endverbatim
+ *
+ * @b Constructors:
+ * - backend_manager_create()
+ * 
+ * @ingroup config
+ */
+struct backend_manager_t {
+       
+       /**
+        * @brief Get an ike_config identified by two hosts.
+        *
+        * @param this                          calling object
+        * @param my_host                       address of own host
+        * @param other_host            address of remote host
+        * @return                                      matching ike_config, or NULL if none found
+        */
+       ike_cfg_t *(*get_ike_cfg)(backend_manager_t *this, 
+                                                         host_t *my_host, host_t *other_host);
+       
+       /**
+        * @brief Get a peer_config identified by two IDs.
+        *
+        * @param this                          calling object
+        * @param my_id                         own ID
+        * @param other_id                      peers ID
+        * @return                                      matching peer_config, or NULL if none found
+        */
+       peer_cfg_t *(*get_peer_cfg)(backend_manager_t *this, identification_t *my_id,
+                                                               identification_t *other_id);
+       
+       /**
+        * @brief Add a peer_config to the first found writable backend.
+        *
+        * @param this          calling object
+        * @param config        peer_config to add to the backend
+        */
+       void (*add_peer_cfg)(backend_manager_t *this, peer_cfg_t *config);
+       
+       /**
+        * @brief Create an iterator over all peer configs of the writable backend.
+        *
+        * @param this          calling object
+        * @return                      iterator over peer configs
+        */
+       iterator_t* (*create_iterator)(backend_manager_t *this);
+       
+       /**
+        * @brief Destroys a backend_manager_t object.
+        *
+        * @param this                                  calling object
+        */
+       void (*destroy) (backend_manager_t *this);
+};
+
+/**
+ * @brief Create a new instance of the manager and loads all backends.
+ *
+ * @return             backend_manager instance
+ *
+ * @ingroup config
+ */
+backend_manager_t *backend_manager_create(void);
+
+#endif /*BACKEND_MANAGER_H_*/
+
index 52df0a2..5f95430 100644 (file)
@@ -30,7 +30,6 @@ typedef struct backend_t backend_t;
 #include <config/peer_cfg.h>
 #include <utils/linked_list.h>
 
-
 /**
  * @brief The interface for a configuration backend.
  *
@@ -54,28 +53,48 @@ struct backend_t {
         * @return                                      matching ike_config, or NULL if none found
         */
        ike_cfg_t *(*get_ike_cfg)(backend_t *this, 
-                                                                host_t *my_host, host_t *other_host);
+                                                         host_t *my_host, host_t *other_host);
        
        /**
         * @brief Get a peer_cfg identified by two IDs.
+        * 
+        * Select a config for two IDs, the others certificate issuer, and
+        * a AC certificate group. The hosts are just a hint to select the
+        * correct config if multiple configs match.
         *
         * @param this                          calling object
         * @param my_id                         own ID
         * @param other_id                      peers ID
+        * @param my_host                       address of own host
+        * @param other_host            address of remote host
         * @return                                      matching peer_config, or NULL if none found
         */
        peer_cfg_t *(*get_peer_cfg)(backend_t *this,
-                                                                  identification_t *my_id,
-                                                                  identification_t *other_id);
+                                                               identification_t *my_id, identification_t *other_id,
+                                                               identification_t *other_ca, char *other_group,
+                                                           host_t *my_host, host_t *other_host);
        
        /**
-        * @brief Get a peer_cfg identified by its name.
+        * @brief Check if a backend is writable and implements writable_backend_t.
         *
-        * @param this                          calling object
-        * @param name                          configs name
-        * @return                                      matching peer_config, or NULL if none found
+        * @param this          calling object
+        * @return                      TRUE if backend implements writable_backend_t.
+        */
+       bool (*is_writeable)(backend_t *this);
+       
+       /**
+        * @brief Destroy a backend.
+        *
+        * @param this          calling object
         */
-       peer_cfg_t *(*get_peer_cfg_by_name)(backend_t *this, char *name);
+       void (*destroy)(backend_t *this);
 };
 
+
+/**
+ * Construction to create a backend.
+ */
+typedef backend_t*(*backend_constructor_t)(void);
+
 #endif /* BACKEND_H_ */
+
index be6fc92..b1e68ee 100644 (file)
@@ -52,7 +52,7 @@ struct private_local_backend_t {
 };
 
 /**
- * implements cfg_store_t.get_ike_cfg.
+ * implements backen_t.get_ike_cfg.
  */
 static ike_cfg_t *get_ike_cfg(private_local_backend_t *this, 
                                                          host_t *my_host, host_t *other_host)
@@ -116,11 +116,12 @@ static ike_cfg_t *get_ike_cfg(private_local_backend_t *this,
 }
 
 /**
- * implements cfg_store_t.get_peer.
+ * implements backend_t.get_peer.
  */                    
-static peer_cfg_t *get_peer_cfg(private_local_backend_t *this, 
-                                                                  identification_t *my_id,
-                                                                  identification_t *other_id)
+static peer_cfg_t *get_peer_cfg(private_local_backend_t *this,
+                                                               identification_t *my_id, identification_t *other_id,
+                                                               identification_t *other_ca, char *other_group,
+                                                           host_t *my_host, host_t *other_host)
 {
        peer_cfg_t *current, *found = NULL;
        iterator_t *iterator;
@@ -166,58 +167,25 @@ static peer_cfg_t *get_peer_cfg(private_local_backend_t *this,
 }
 
 /**
- * implements cfg_store_t.get_peer_by_name.
- */                                    
-static peer_cfg_t *get_peer_cfg_by_name(private_local_backend_t *this,
-                                                                               char *name)
+ * Implementation of backend_t.is_writable.
+ */
+static bool is_writeable(private_local_backend_t *this)
 {
-       iterator_t *i1, *i2;
-       peer_cfg_t *current, *found = NULL;
-       child_cfg_t *child;
-       
-       i1 = this->cfgs->create_iterator(this->cfgs, TRUE);
-       while (i1->iterate(i1, (void**)&current))
-       {
-               /* compare peer_cfgs name first */
-               if (streq(current->get_name(current), name))
-               {
-                       found = current;
-                       found->get_ref(found);
-                       break;
-               }
-               /* compare all child_cfg names otherwise */
-               i2 = current->create_child_cfg_iterator(current);
-               while (i2->iterate(i2, (void**)&child))
-               {
-                       if (streq(child->get_name(child), name))
-                       {
-                               found = current;
-                               found->get_ref(found);
-                               break;
-                       }
-               }
-               i2->destroy(i2);
-               if (found)
-               {
-                       break;
-               }
-       }
-       i1->destroy(i1);
-       return found;
+    return TRUE;
 }
 
 /**
- * Implementation of local_backend_t.create_peer_cfg_iterator.
+ * Implementation of writable_backend_t.create_iterator.
  */
-static iterator_t* create_peer_cfg_iterator(private_local_backend_t *this)
+static iterator_t* create_iterator(private_local_backend_t *this)
 {
        return this->cfgs->create_iterator_locked(this->cfgs, &this->mutex);
 }
 
 /**
- * Implementation of local_backend_t.add_peer_cfg.
+ * Implementation of writable_backend_t.add_peer_cfg.
  */
-static void add_peer_cfg(private_local_backend_t *this, peer_cfg_t *config)
+static void add_cfg(private_local_backend_t *this, peer_cfg_t *config)
 {
     pthread_mutex_lock(&this->mutex);
     this->cfgs->insert_last(this->cfgs, config);
@@ -225,7 +193,7 @@ static void add_peer_cfg(private_local_backend_t *this, peer_cfg_t *config)
 }
 
 /**
- * Implementation of local_backend_t.destroy.
+ * Implementation of backend_t.destroy.
  */
 static void destroy(private_local_backend_t *this)
 {
@@ -236,20 +204,20 @@ static void destroy(private_local_backend_t *this)
 /**
  * Described in header.
  */
-local_backend_t *local_backend_create(void)
+backend_t *backend_create(void)
 {
        private_local_backend_t *this = malloc_thing(private_local_backend_t);
        
-       this->public.backend.get_ike_cfg = (ike_cfg_t*(*)(backend_t*, host_t *, host_t *))get_ike_cfg;
-       this->public.backend.get_peer_cfg = (peer_cfg_t*(*)(backend_t*, identification_t *, identification_t *))get_peer_cfg;
-       this->public.create_peer_cfg_iterator = (iterator_t*(*)(local_backend_t*))create_peer_cfg_iterator;
-       this->public.get_peer_cfg_by_name = (peer_cfg_t*(*)(local_backend_t*, char *))get_peer_cfg_by_name;
-    this->public.add_peer_cfg = (void(*)(local_backend_t*, peer_cfg_t *))add_peer_cfg;
-    this->public.destroy = (void(*)(local_backend_t*))destroy;
+       this->public.backend.backend.get_ike_cfg = (ike_cfg_t*(*)(backend_t*, host_t *, host_t *))get_ike_cfg;
+       this->public.backend.backend.get_peer_cfg = (peer_cfg_t*(*)(backend_t*,identification_t*,identification_t*,identification_t*,char*,host_t*,host_t*))get_peer_cfg;
+    this->public.backend.backend.is_writeable = (bool(*)(backend_t*))is_writeable;
+    this->public.backend.backend.destroy = (void(*)(backend_t*))destroy;
+       this->public.backend.create_iterator = (iterator_t*(*)(writeable_backend_t*))create_iterator;
+    this->public.backend.add_cfg = (void(*)(writeable_backend_t*, peer_cfg_t *))add_cfg;
     
        /* private variables */
        this->cfgs = linked_list_create();
        pthread_mutex_init(&this->mutex, NULL);
        
-       return (&this->public);
+       return (&this->public.backend.backend);
 }
index 4caf4a8..f3538ea 100644 (file)
 typedef struct local_backend_t local_backend_t;
 
 #include <library.h>
-#include <config/backends/backend.h>
+#include <config/backends/writeable_backend.h>
 
 /**
  * @brief An in-memory backend to store configuration information.
  *
- * The local_backend_t stores the configuration in a simple list. Additional
- * to the backend_t functionality, it adds the modification (add/remove).
+ * The local_backend_t stores the configuration in a simple list. It
+ * implements both, backend_t and writeable_backend_t.
  *
  * @b Constructors:
  *  - local_backend_create()
@@ -42,50 +42,19 @@ typedef struct local_backend_t local_backend_t;
 struct local_backend_t {
        
        /**
-        * Implements backend_t interface
+        * Implements writable_backend_t interface
         */
-       backend_t backend;
-       
-       /**
-        * @brief Add a peer_config to the backend.
-        *
-        * @param this          calling object
-        * @param config        peer_config to add to the backend
-        */
-       void (*add_peer_cfg)(local_backend_t *this, peer_cfg_t *config);
-       
-       /**
-        * @brief Get a peer_config identified by name, or a name of its child_cfgs.
-        *
-        * @param this                          calling object
-        * @param name                          name of the peer config
-        * @return                                      matching peer_config, or NULL if none found
-        */
-       peer_cfg_t *(*get_peer_cfg_by_name)(local_backend_t *this, char *name);
-       
-       /**
-        * @brief Create an iterator over all peer configs.
-        *
-        * @param this          calling object
-        * @return                      iterator over peer configs
-        */
-       iterator_t* (*create_peer_cfg_iterator)(local_backend_t *this);
-       
-       /**
-        * @brief Destroy a local backend.
-        *
-        * @param this          calling object
-        */
-       void (*destroy)(local_backend_t *this);
+       writeable_backend_t backend;
 };
 
 /**
- * @brief Creates a local_backend_t instance.
+ * @brief Create a backend_t instance implemented as local backend.
  *
- * @return local_backend instance.
+ * @return backend instance.
  * 
  * @ingroup backends
  */
-local_backend_t *local_backend_create(void);
+backend_t *backend_create(void);
 
 #endif /* LOCAL_BACKEND_H_ */
+
diff --git a/src/charon/config/backends/writeable_backend.h b/src/charon/config/backends/writeable_backend.h
new file mode 100644 (file)
index 0000000..4771a0c
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * @file writeable_backend.h
+ *
+ * @brief Interface of writeable_backend_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+#ifndef WRITEABLE_BACKEND_H_
+#define WRITEABLE_BACKEND_H_
+
+typedef struct writeable_backend_t writeable_backend_t;
+
+#include <library.h>
+#include <config/backends/backend.h>
+
+/**
+ * @brief A writeable backend extends the backend by modification functions.
+ *
+ * @b Constructors:
+ *  - writeable_backend_create()
+ * 
+ * @ingroup backends
+ */
+struct writeable_backend_t {
+       
+       /**
+        * Implements backend_t interface
+        */
+       backend_t backend;
+       
+       /**
+        * @brief Add a peer_config to the backend.
+        *
+        * @param this          calling object
+        * @param config        peer_config to add to the backend
+        */
+       void (*add_cfg)(writeable_backend_t *this, peer_cfg_t *config);
+       
+       /**
+        * @brief Create an iterator over all peer configs.
+        *
+        * @param this          calling object
+        * @return                      iterator over peer configs
+        */
+       iterator_t* (*create_iterator)(writeable_backend_t *this);
+};
+
+#endif /* WRITEABLE_BACKEND_H_ */
+
diff --git a/src/charon/config/cfg_store.c b/src/charon/config/cfg_store.c
deleted file mode 100644 (file)
index ef945da..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * @file cfg_store.c
- * 
- * @brief Implementation of cfg_store_t.
- * 
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * 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 <pthread.h>
-
-#include "cfg_store.h"
-
-#include <library.h>
-#include <utils/linked_list.h>
-
-
-typedef struct private_cfg_store_t private_cfg_store_t;
-
-/**
- * Private data of an cfg_store_t object.
- */
-struct private_cfg_store_t {
-
-       /**
-        * Public part of cfg_store_t object.
-        */
-       cfg_store_t public;
-       
-       /**
-        * list of registered backends
-        */
-       linked_list_t *backends;
-       
-       /**
-        * mutex to lock backend list
-        */
-       pthread_mutex_t mutex;
-};
-
-/**
- * implements cfg_store_t.get_ike.
- */
-static ike_cfg_t *get_ike_cfg(private_cfg_store_t *this, 
-                                                         host_t *my_host, host_t *other_host)
-{
-       backend_t *backend;
-       ike_cfg_t *config = NULL;
-       iterator_t *iterator = this->backends->create_iterator_locked(
-                                                                                               this->backends, &this->mutex);
-       while (config == NULL && iterator->iterate(iterator, (void**)&backend))
-       {
-               config = backend->get_ike_cfg(backend, my_host, other_host);
-       }
-       iterator->destroy(iterator);
-       return config;
-}
-
-/**
- * implements cfg_store_t.get_peer.
- */                    
-static peer_cfg_t *get_peer_cfg(private_cfg_store_t *this, 
-                                                               identification_t *my_id,
-                                                               identification_t *other_id)
-{
-       backend_t *backend;
-       peer_cfg_t *config = NULL;
-       iterator_t *iterator = this->backends->create_iterator_locked(
-                                                                                               this->backends, &this->mutex);
-       while (config == NULL && iterator->iterate(iterator, (void**)&backend))
-       {
-               config = backend->get_peer_cfg(backend, my_id, other_id);
-       }
-       iterator->destroy(iterator);
-       return config;
-}
-
-/**
- * implements cfg_store_t.register_backend.
- */                    
-static void register_backend(private_cfg_store_t *this, backend_t *backend)
-{
-       pthread_mutex_lock(&this->mutex);
-       this->backends->insert_last(this->backends, backend);
-       pthread_mutex_unlock(&this->mutex);
-}
-
-/**
- * implements cfg_store_t.unregister_backend.
- */                    
-static void unregister_backend(private_cfg_store_t *this, backend_t *backend)
-{
-       backend_t *current;
-       iterator_t *iterator = this->backends->create_iterator_locked(
-                                                                                               this->backends, &this->mutex);
-       while (iterator->iterate(iterator, (void**)&current))
-       {
-               if (backend == current)
-               {
-                       iterator->remove(iterator);
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-}
-
-/**
- * Implementation of cfg_store_t.destroy.
- */
-static void destroy(private_cfg_store_t *this)
-{
-       this->backends->destroy(this->backends);
-       free(this);
-}
-
-/*
- * Described in header-file
- */
-cfg_store_t *cfg_store_create()
-{
-       private_cfg_store_t *this = malloc_thing(private_cfg_store_t);
-       
-       this->public.get_ike_cfg = (ike_cfg_t*(*)(cfg_store_t*, host_t *, host_t *))get_ike_cfg;
-       this->public.get_peer_cfg = (peer_cfg_t*(*)(cfg_store_t*, identification_t *, identification_t *))get_peer_cfg;
-       this->public.register_backend = (void(*)(cfg_store_t*, backend_t *))register_backend;
-       this->public.unregister_backend = (void(*)(cfg_store_t*, backend_t *))unregister_backend;
-       this->public.destroy = (void(*)(cfg_store_t*))destroy;
-       
-       this->backends = linked_list_create();
-       pthread_mutex_init(&this->mutex, NULL);
-       
-       return &this->public;
-}
diff --git a/src/charon/config/cfg_store.h b/src/charon/config/cfg_store.h
deleted file mode 100644 (file)
index be36cd3..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * @file cfg_store.h
- * 
- * @brief Interface cfg_store_t.
- *  
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * 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.
- */
-
-#ifndef CFG_STORE_H_
-#define CFG_STORE_H_
-
-typedef struct cfg_store_t cfg_store_t;
-
-#include <library.h>
-#include <utils/host.h>
-#include <utils/identification.h>
-#include <config/ike_cfg.h>
-#include <config/peer_cfg.h>
-#include <config/backends/backend.h>
-
-
-/**
- * @brief A multiplexer to use multiple cfg_store backends.
- *
- * Charon allows the use of multiple cfg_store backends simultaneously. To
- * access all this backends by a single call, this class wraps multiple
- * backends behind a single object.
- * Backends may be registered and unregister at runtime dynamically.
- * @verbatim
-
-   +---------+      +-----------+         +--------------+     |
-   |         |      |           |       +--------------+ |     |
-   | daemon  |----->| cfg_store |     +--------------+ |-+  <==|==> IPC
-   |  core   |      |           |---->|   backends   |-+       |
-   |         |----->|           |     +--------------+         |
-   |         |      |           |                              |
-   +---------+      +-----------+                              |
-   
-   @endverbatim
- * Configuration lookup is done only when acting as responder. For initating
- * the corresponding controller is responsible to get a config to initiate.
- *
- * @b Constructors:
- * - cfg_store_create()
- * 
- * @ingroup config
- */
-struct cfg_store_t {
-       
-       /**
-        * @brief Get an ike_config identified by two hosts.
-        *
-        * @param this                          calling object
-        * @param my_host                       address of own host
-        * @param other_host            address of remote host
-        * @return                                      matching ike_config, or NULL if none found
-        */
-       ike_cfg_t *(*get_ike_cfg)(cfg_store_t *this, 
-                                                         host_t *my_host, host_t *other_host);
-       
-       /**
-        * @brief Get a peer_config identified by two IDs.
-        *
-        * @param this                          calling object
-        * @param my_id                         own ID
-        * @param other_id                      peers ID
-        * @return                                      matching peer_config, or NULL if none found
-        */
-       peer_cfg_t *(*get_peer_cfg)(cfg_store_t *this, identification_t *my_id,
-                                                               identification_t *other_id);
-       
-       /**
-        * @brief Register a backend to be queried by the calls above.
-        *
-        * The backend first added is the most preferred.
-        *
-        * @param this                                  calling object
-        */
-       void (*register_backend) (cfg_store_t *this, backend_t *backend);
-       
-       /**
-        * @brief Unregister a backend.
-        *
-        * @param this                                  calling object
-        */
-       void (*unregister_backend) (cfg_store_t *this, backend_t *backend);
-       
-       /**
-        * @brief Destroys a cfg_store_t object.
-        *
-        * @param this                                  calling object
-        */
-       void (*destroy) (cfg_store_t *this);
-};
-
-/**
- * @brief Create a new instance of the store.
- *
- * @return             cfg_store instance
- *
- * @ingroup config
- */
-cfg_store_t *cfg_store_create(void);
-
-#endif /*CFG_STORE_H_*/
diff --git a/src/charon/control/controller.c b/src/charon/control/controller.c
deleted file mode 100644 (file)
index 8e0268e..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @file controller.c
- * 
- * @brief Implementation of controller_t.
- * 
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * 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 "controller.h"
-
-#include <daemon.h>
-#include <library.h>
-#include <processing/job_queue.h>
-#include <processing/jobs/initiate_job.h>
-
-
-typedef struct private_controller_t private_controller_t;
-
-/**
- * Private data of an stroke_t object.
- */
-struct private_controller_t {
-
-       /**
-        * Public part of stroke_t object.
-        */
-       controller_t public;
-};
-       
-/**
- * Implementation of controller_t.initiate.
- */
-static status_t initiate(private_controller_t *this,
-                                                peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-                                                bool(*cb)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),
-                                                void *param)
-{
-       ike_sa_t *ours = NULL;
-       job_t *job;
-       status_t retval;
-       
-       charon->bus->set_listen_state(charon->bus, TRUE);
-       
-       job = (job_t*)initiate_job_create(peer_cfg, child_cfg);
-       charon->job_queue->add(charon->job_queue, job);
-       
-       while (TRUE)
-       {
-               level_t level;
-               signal_t signal;
-               int thread;
-               ike_sa_t *ike_sa;
-               char* format;
-               va_list args;
-               
-               signal = charon->bus->listen(charon->bus, &level, &thread, 
-                                                                        &ike_sa, &format, &args);
-               
-               if (ike_sa == ours || ours == NULL)
-               {
-                       if (!cb(param, signal, level, ike_sa, format, args))
-                       {
-                               charon->bus->set_listen_state(charon->bus, FALSE);
-                               return NEED_MORE;
-                       }
-               }
-               
-               switch (signal)
-               {
-                       case CHILD_UP_SUCCESS:
-                               if (ike_sa == ours)
-                               {
-                                       retval = SUCCESS;
-                                       break;
-                               }
-                               continue;
-                       case CHILD_UP_FAILED:
-                       case IKE_UP_FAILED:
-                               if (ike_sa == ours)
-                               {
-                                       retval = FAILED;
-                                       break;
-                               }
-                               continue;
-                       case CHILD_UP_START:
-                       case IKE_UP_START:
-                               if (ours == NULL)
-                               {
-                                       ours = ike_sa;
-                               }
-                               continue;
-                       default:
-                               continue;
-               }
-               break;
-       }
-       charon->bus->set_listen_state(charon->bus, FALSE);
-       return retval;
-}
-
-/**
- * Implementation of stroke_t.destroy.
- */
-static void destroy(private_controller_t *this)
-{
-       free(this);
-}
-
-/*
- * Described in header-file
- */
-controller_t *controller_create(void)
-{
-       private_controller_t *this = malloc_thing(private_controller_t);
-       
-       this->public.initiate = (status_t(*)(controller_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate;
-       this->public.destroy = (void (*)(controller_t*))destroy;
-       
-       return &this->public;
-}
diff --git a/src/charon/control/controller.h b/src/charon/control/controller.h
deleted file mode 100644 (file)
index 7dc4b67..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * @file controller.h
- *
- * @brief Interface of controller_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * 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.
- */
-
-#ifndef CONTROLLER_H_
-#define CONTROLLER_H_
-
-#include <bus/bus.h>
-
-/**
- * callback to log things triggered by controller
- *
- * @param param                        echoed parameter supplied when function invoked
- * @param signal               type of signal
- * @param level                        verbosity level if log
- * @param ike_sa               associated IKE_SA, if any
- * @param format               printf like format string
- * @param args                 list of arguments to use for format
- * @return                             FALSE to return from invoked function
- * @ingroup control
- */
-typedef bool(*controller_cb_t)(void* param, signal_t signal, level_t level,
-                                                          ike_sa_t* ike_sa, char* format, va_list args);
-
-typedef struct controller_t controller_t;
-
-/**
- * @brief The controller controls the daemon.
- *
- * The controller starts actions by creating jobs. It then tries to
- * evaluate the result of the operation by listening on the bus.
- * 
- * @b Constructors:
- * - controller_create()
- * 
- * @ingroup control
- */
-struct controller_t {
-
-       /**
-        * @brief Initiate a CHILD_SA, and if required, an IKE_SA.
-        *
-        * @param this                  calling object
-        * @param peer_cfg              peer_cfg to use for IKE_SA setup
-        * @param child_cfg             child_cfg to set up CHILD_SA from
-        * @param cb                    logging callback
-        * @param param                 parameter to include in each call of cb
-        * @return
-        *                                              - SUCCESS, if CHILD_SA established
-        *                                              - FAILED, if setup failed
-        *                                              - NEED_MORE, if callback returned FALSE
-        */
-       status_t (*initiate)(controller_t *this,
-                                                peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-                                                controller_cb_t callback, void *param);
-       
-       /**
-        * @brief Destroy a controller_t instance.
-        * 
-        * @param this          controller_t objec to destroy
-        */
-       void (*destroy) (controller_t *this);
-};
-
-
-/**
- * @brief Create a controller instance.
- * 
- * @return                     controller_t object
- * 
- * @ingroup control
- */
-controller_t *controller_create();
-
-#endif /* CONTROLLER_H_ */
diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c
new file mode 100644 (file)
index 0000000..5f4a7e8
--- /dev/null
@@ -0,0 +1,239 @@
+/**
+ * @file interface_manager.c
+ * 
+ * @brief Implementation of interface_manager_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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 "interface_manager.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+
+#include <daemon.h>
+#include <library.h>
+#include <control/interfaces/interface.h>
+#include <processing/job_queue.h>
+#include <processing/jobs/initiate_job.h>
+
+
+typedef struct private_interface_manager_t private_interface_manager_t;
+
+/**
+ * Private data of an stroke_t object.
+ */
+struct private_interface_manager_t {
+
+       /**
+        * Public part of stroke_t object.
+        */
+       interface_manager_t public;
+       
+       /**
+        * a list of all loaded interfaces
+        */
+       linked_list_t *interfaces;
+       
+       /**
+        * dlopen() handles of interfaces
+        */
+       linked_list_t *handles;
+};
+       
+/**
+ * Implementation of interface_manager_t.initiate.
+ */
+static status_t initiate(private_interface_manager_t *this,
+                                                peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+                                                bool(*cb)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),
+                                                void *param)
+{
+       ike_sa_t *ours = NULL;
+       job_t *job;
+       status_t retval;
+       
+       charon->bus->set_listen_state(charon->bus, TRUE);
+       
+       job = (job_t*)initiate_job_create(peer_cfg, child_cfg);
+       charon->job_queue->add(charon->job_queue, job);
+       
+       while (TRUE)
+       {
+               level_t level;
+               signal_t signal;
+               int thread;
+               ike_sa_t *ike_sa;
+               char* format;
+               va_list args;
+               
+               signal = charon->bus->listen(charon->bus, &level, &thread, 
+                                                                        &ike_sa, &format, &args);
+               
+               if (cb && (ike_sa == ours || ours == NULL))
+               {
+                       if (!cb(param, signal, level, ike_sa, format, args))
+                       {
+                               charon->bus->set_listen_state(charon->bus, FALSE);
+                               return NEED_MORE;
+                       }
+               }
+               
+               switch (signal)
+               {
+                       case CHILD_UP_SUCCESS:
+                               if (ike_sa == ours)
+                               {
+                                       retval = SUCCESS;
+                                       break;
+                               }
+                               continue;
+                       case CHILD_UP_FAILED:
+                       case IKE_UP_FAILED:
+                               if (ike_sa == ours)
+                               {
+                                       retval = FAILED;
+                                       break;
+                               }
+                               continue;
+                       case CHILD_UP_START:
+                       case IKE_UP_START:
+                               if (ours == NULL)
+                               {
+                                       ours = ike_sa;
+                               }
+                               continue;
+                       default:
+                               continue;
+               }
+               break;
+       }
+       charon->bus->set_listen_state(charon->bus, FALSE);
+       return retval;
+}
+
+/**
+ * load the control interface modules
+ */
+static void load_interfaces(private_interface_manager_t *this)
+{
+       struct dirent* entry;
+       struct stat stb;
+       DIR* dir;
+       
+       if (stat(IPSEC_INTERFACEDIR, &stb) == -1 || !(stb.st_mode & S_IFDIR))
+       {
+               DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
+               return;
+       }
+
+       dir = opendir(IPSEC_INTERFACEDIR);
+       if (dir == NULL)
+       {
+               DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
+               return;
+       }
+       
+       DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'");
+
+       while ((entry = readdir(dir)) != NULL)
+       {
+               char file[256];
+               interface_t *interface;
+               interface_constructor_t constructor;
+               void *handle;
+               char *ending;
+               
+               snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name);
+               
+               if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
+               {
+                       DBG2(DBG_CFG, "  skipping %s, doesn't look like a file",
+                                entry->d_name);
+                       continue;
+               }
+               ending = entry->d_name + strlen(entry->d_name) - 3;
+               if (ending <= entry->d_name || !streq(ending, ".so"))
+               {
+                       /* skip anything which does not look like a library */
+                       DBG2(DBG_CFG, "  skipping %s, doesn't look like a library",
+                                entry->d_name);
+                       continue;
+               }
+               /* try to load the library */
+               handle = dlopen(file, RTLD_LAZY);
+               if (handle == NULL)
+               {
+                       DBG1(DBG_CFG, "  opening control interface module %s failed: %s",
+                                entry->d_name, dlerror());
+                       continue;
+               }
+               constructor = dlsym(handle, "interface_create");
+               if (constructor == NULL)
+               {
+                       DBG1(DBG_CFG, "  interface module %s has no interface_create() "
+                                "function, skipped", entry->d_name);
+                       dlclose(handle);
+                       continue;
+               }
+               
+               interface = constructor();
+               if (interface == NULL)
+               {
+                       DBG1(DBG_CFG, "  unable to create instance of interface "
+                                "module %s, skipped", entry->d_name);
+                       dlclose(handle);
+                       continue;
+               }
+               DBG1(DBG_CFG, "  loaded control interface module successfully from %s", entry->d_name);
+               this->interfaces->insert_last(this->interfaces, interface);
+               this->handles->insert_last(this->handles, handle);
+       }
+       closedir(dir);
+}
+
+
+/**
+ * Implementation of stroke_t.destroy.
+ */
+static void destroy(private_interface_manager_t *this)
+{
+       this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy));
+       this->handles->destroy_function(this->handles, (void*)dlclose);
+       free(this);
+}
+
+/*
+ * Described in header-file
+ */
+interface_manager_t *interface_manager_create(void)
+{
+       private_interface_manager_t *this = malloc_thing(private_interface_manager_t);
+       
+       this->public.initiate = (status_t(*)(interface_manager_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate;
+       this->public.destroy = (void (*)(interface_manager_t*))destroy;
+       
+       this->interfaces = linked_list_create();
+       this->handles = linked_list_create();
+       
+       load_interfaces(this);
+       
+       return &this->public;
+}
+
diff --git a/src/charon/control/interface_manager.h b/src/charon/control/interface_manager.h
new file mode 100644 (file)
index 0000000..57121c8
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * @file interface_manager.h
+ *
+ * @brief Interface of interface_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#ifndef INTERFACE_MANAGER_H_
+#define INTERFACE_MANAGER_H_
+
+#include <bus/bus.h>
+
+/**
+ * callback to log things triggered by interface_manager
+ *
+ * @param param                        echoed parameter supplied when function invoked
+ * @param signal               type of signal
+ * @param level                        verbosity level if log
+ * @param ike_sa               associated IKE_SA, if any
+ * @param format               printf like format string
+ * @param args                 list of arguments to use for format
+ * @return                             FALSE to return from invoked function
+ * @ingroup control
+ */
+typedef bool(*interface_manager_cb_t)(void* param, signal_t signal, level_t level,
+                                                          ike_sa_t* ike_sa, char* format, va_list args);
+
+typedef struct interface_manager_t interface_manager_t;
+
+/**
+ * @brief The interface_manager controls the daemon.
+ *
+ * The interface_manager starts actions by creating jobs. It then tries to
+ * evaluate the result of the operation by listening on the bus.
+ * 
+ * @b Constructors:
+ * - interface_manager_create()
+ * 
+ * @ingroup control
+ */
+struct interface_manager_t {
+
+       /**
+        * @brief Initiate a CHILD_SA, and if required, an IKE_SA.
+        *
+        * @param this                  calling object
+        * @param peer_cfg              peer_cfg to use for IKE_SA setup
+        * @param child_cfg             child_cfg to set up CHILD_SA from
+        * @param cb                    logging callback
+        * @param param                 parameter to include in each call of cb
+        * @return
+        *                                              - SUCCESS, if CHILD_SA established
+        *                                              - FAILED, if setup failed
+        *                                              - NEED_MORE, if callback returned FALSE
+        */
+       status_t (*initiate)(interface_manager_t *this,
+                                                peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+                                                interface_manager_cb_t callback, void *param);
+       
+       /**
+        * @brief Destroy a interface_manager_t instance.
+        * 
+        * @param this          interface_manager_t objec to destroy
+        */
+       void (*destroy) (interface_manager_t *this);
+};
+
+
+/**
+ * @brief Create a interface_manager instance and loads all interface modules.
+ * 
+ * @return                     interface_manager_t object
+ * 
+ * @ingroup control
+ */
+interface_manager_t *interface_manager_create(void);
+
+#endif /* INTERFACE_MANAGER_H_ */
+
diff --git a/src/charon/control/interfaces/dbus_interface.c b/src/charon/control/interfaces/dbus_interface.c
new file mode 100644 (file)
index 0000000..178f74f
--- /dev/null
@@ -0,0 +1,324 @@
+/**
+ * @file dbus_interface.c
+ * 
+ * @brief Implementation of dbus_interface_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <NetworkManager/NetworkManager.h>
+#include <NetworkManager/NetworkManagerVPN.h>
+#include <stdlib.h>
+
+#include "dbus_interface.h"
+
+#include <library.h>
+#include <daemon.h>
+
+
+#define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan"
+#define NM_DBUS_INTERFACE_STRONG "org.freedesktop.NetworkManager.strongswan"
+#define NM_DBUS_PATH_STRONG "/org/freedesktop/NetworkManager/strongswan"
+
+typedef struct private_dbus_interface_t private_dbus_interface_t;
+
+/**
+ * Private data of an dbus_interface_t object.
+ */
+struct private_dbus_interface_t {
+
+       /**
+        * Public part of dbus_t object.
+        */
+       dbus_interface_t public;
+       
+       /**
+        * DBUS connection
+        */
+       DBusConnection* conn;
+       
+       /**
+        * error value used here and there
+        */
+       DBusError err;
+       
+       /**
+        * state of the daemon
+        */
+       NMVPNState state;
+       
+       /**
+        * dispatcher thread for DBUS messages
+        */
+       pthread_t thread;
+};
+
+/**
+ * set daemon state and send StateChange signal to the bus
+ */
+static void set_state(private_dbus_interface_t *this, NMVPNState state)
+{
+       DBusMessage* msg;
+
+       msg = dbus_message_new_signal(NM_DBUS_PATH_STRONG, NM_DBUS_INTERFACE_STRONG, NM_DBUS_VPN_SIGNAL_STATE_CHANGE);
+
+       if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &this->state,
+                                                         DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID) ||
+               !dbus_connection_send(this->conn, msg, NULL))
+       {
+               DBG1(DBG_CFG, "unable to send DBUS StateChange signal");
+       }
+       dbus_connection_flush(this->conn);
+       dbus_message_unref(msg);
+       this->state = state;
+}
+
+/**
+ * process NetworkManagers startConnection method call
+ */
+static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg)
+{
+       DBusMessage *reply, *signal;
+       char *name, *user, **data, **passwords, **routes;
+       int data_count, passwords_count, routes_count;
+       u_int32_t me, other, p2p, netmask, mss;
+       char *dev, *domain, *banner;
+       const dbus_int32_t array[] = {};
+       const dbus_int32_t *varray = array;
+
+       if (!dbus_message_get_args(msg, &this->err,
+                        DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user,
+                        DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &passwords_count,
+                        DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data, &data_count,
+                        DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &routes, &routes_count,
+                        DBUS_TYPE_INVALID))
+       {
+               return FALSE;
+       }
+       set_state(this, NM_VPN_STATE_STARTING);
+       
+       reply = dbus_message_new_method_return(msg);
+       dbus_connection_send(this->conn, reply, NULL);
+       
+       signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG,
+                                                                        NM_DBUS_INTERFACE_STRONG,
+                                                                        NM_DBUS_VPN_SIGNAL_IP4_CONFIG);
+       
+       me = other = p2p = mss = netmask = 0;
+       dev = domain = banner = "";
+       if (dbus_message_append_args(signal,
+                                       DBUS_TYPE_UINT32, &other,
+                                       DBUS_TYPE_STRING, &dev,
+                                       DBUS_TYPE_UINT32, &me,
+                                       DBUS_TYPE_UINT32, &p2p,
+                                       DBUS_TYPE_UINT32, &netmask,
+                                       DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
+                                       DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
+                                       DBUS_TYPE_UINT32, &mss,
+                                       DBUS_TYPE_STRING, &domain,
+                                       DBUS_TYPE_STRING, &banner))
+       {
+               dbus_connection_send(this->conn, signal, NULL);
+       }                                                
+       dbus_message_unref(signal);
+       
+       set_state(this, NM_VPN_STATE_STARTED);
+       
+       dbus_connection_flush(this->conn);
+       dbus_message_unref(reply);
+       return TRUE;
+}
+
+/**
+ * process NetworkManagers stopConnection method call
+ */
+static bool stop_connection(private_dbus_interface_t *this, DBusMessage* msg)
+{
+       set_state(this, NM_VPN_STATE_STOPPING);
+       set_state(this, NM_VPN_STATE_STOPPED);
+       return FALSE;
+}
+
+/**
+ * process NetworkManagers getState method call
+ */
+static bool get_state(private_dbus_interface_t *this, DBusMessage* msg)
+{
+       DBusMessage* reply;
+       reply = dbus_message_new_method_return(msg);
+       if (!reply || !dbus_message_append_args(reply,
+                                                                                       DBUS_TYPE_UINT32, &this->state,
+                                                                                       DBUS_TYPE_INVALID))
+       {
+               return FALSE;
+       }
+       dbus_connection_send(this->conn, reply, NULL);
+       return TRUE;
+}
+
+/**
+ * Handle incoming messages
+ */
+static DBusHandlerResult message_handler(DBusConnection *con, DBusMessage *msg,
+                                                                                private_dbus_interface_t *this)
+{
+       bool handled;
+
+       if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
+                                                                       "startConnection"))
+       {
+               handled = start_connection(this, msg);
+       }
+       else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
+                                                                                "stopConnection"))
+       {
+               handled = stop_connection(this, msg);
+       }
+       else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
+                                                                                "getState"))
+       {
+               handled = get_state(this, msg);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "ignoring DBUS message %s.%s",
+                        dbus_message_get_interface(msg), dbus_message_get_member(msg));
+               handled = FALSE;
+       }
+       
+       if (handled)
+       {
+               return DBUS_HANDLER_RESULT_HANDLED;
+       }
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/**
+ * Handle received signals
+
+static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
+                                                                               private_dbus_interface_t *this)
+{
+       bool handled;
+
+       if (dbus_message_is_signal(msg, NM_DBUS_INTERFACE, "VPNConnectionStateChange"))
+       {
+               NMVPNState state;
+               char *name;
+               
+               if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name, 
+                                                                 DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID))
+               {
+                       DBG1(DBG_CFG, "got state %d for %s", state, name);
+               }
+               handled = TRUE;
+       }
+       else
+       {
+               DBG1(DBG_CFG, "ignoring DBUS signal %s.%s",
+                        dbus_message_get_interface(msg), dbus_message_get_member(msg));
+               handled = FALSE;
+       }
+       if (handled)
+       {
+               return DBUS_HANDLER_RESULT_HANDLED;
+       }
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+} */
+
+/**
+ * dispatcher function processed by a seperate thread
+ */
+static void dispatch(private_dbus_interface_t *this)
+{
+       while (dbus_connection_read_write_dispatch(this->conn, -1))
+       {
+               /* nothing */
+       }
+}
+
+/**
+ * Implementation of interface_t.destroy.
+ */
+static void destroy(private_dbus_interface_t *this)
+{
+       pthread_cancel(this->thread);
+       pthread_join(this->thread, NULL);
+       dbus_error_free(&this->err); 
+       free(this);
+}
+
+/*
+ * Described in header file
+ */
+interface_t *interface_create()
+{
+       int ret;
+       DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL};
+       private_dbus_interface_t *this = malloc_thing(private_dbus_interface_t);
+  
+       this->public.interface.destroy = (void (*)(dbus_interface_t*))destroy;
+       
+       dbus_error_init(&this->err); 
+       this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err);
+       if (dbus_error_is_set(&this->err))
+       { 
+               DBG1(DBG_CFG, "unable to open DBUS connection: %s", this->err.message); 
+               charon->kill(charon, "DBUS initialization failed");
+       }
+       
+       ret = dbus_bus_request_name(this->conn, NM_DBUS_SERVICE_STRONG,
+                                                           DBUS_NAME_FLAG_REPLACE_EXISTING , &this->err);
+       if (dbus_error_is_set(&this->err))
+       {
+               DBG1(DBG_CFG, "unable to set DBUS name: %s", this->err.message);
+               charon->kill(charon, "unable to set DBUS name");
+       }
+       if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+       {
+               charon->kill(charon, "DBUS name already owned");
+       }
+       if (!dbus_connection_register_object_path(this->conn, NM_DBUS_PATH_STRONG, &v, this))
+    {
+               charon->kill(charon, "unable to register DBUS message handler");
+    }
+       /*
+       if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL))
+       {
+               charon->kill(charon, "unable to register DBUS signal handler");
+       }
+       
+       dbus_bus_add_match(this->conn, "type='signal', "
+                                          "interface='" NM_DBUS_INTERFACE_VPN "',"
+                                          "path='" NM_DBUS_PATH_VPN "'", &this->err);
+       if (dbus_error_is_set (&this->err))
+       {
+               charon->kill(charon, "unable to add DBUS signal match");
+       }*/
+
+       this->state = NM_VPN_STATE_INIT;
+       set_state(this, NM_VPN_STATE_STOPPED);
+
+       if (pthread_create(&this->thread, NULL, (void*(*)(void*))dispatch, this) != 0)
+       {
+               charon->kill(charon, "unable to create stroke thread");
+       }
+
+       return &this->public;
+}
diff --git a/src/charon/control/interfaces/dbus_interface.h b/src/charon/control/interfaces/dbus_interface.h
new file mode 100644 (file)
index 0000000..0ce57bb
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file dbus_interface.h
+ *
+ * @brief Interface of dbus_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#ifndef DBUS_INTERFACE_H_
+#define DBUS_INTERFACE_H_
+
+typedef struct dbus_interface_t dbus_interface_t;
+
+#include <control/interfaces/interface.h>
+
+/**
+ * @brief The DBUS interface uses the DBUS system bus to communicate.
+ * 
+ * @b Constructors:
+ * - dbus_interface_create()
+ * 
+ * @ingroup interfaces
+ */
+struct dbus_interface_t {
+       
+       /**
+        * implements interface_t.
+        */
+       interface_t interface;
+};
+
+
+/**
+ * @brief Create the DBUS interface.
+ *
+ * @return                     stroke_t object
+ * 
+ * @ingroup interfaces
+ */
+interface_t *interface_create();
+
+#endif /* DBUS_INTERFACE_H_ */
+
diff --git a/src/charon/control/interfaces/interface.h b/src/charon/control/interfaces/interface.h
new file mode 100644 (file)
index 0000000..1949556
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * @file interface.h
+ *
+ * @brief Interface of interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#ifndef INTERFACE_H_
+#define INTERFACE_H_
+
+typedef struct interface_t interface_t;
+
+/**
+ * @brief Interface for a controller.
+ * 
+ * @b Constructors:
+ * - interface_create() of one of the modules
+ * 
+ * @ingroup interfaces
+ */
+struct interface_t {
+       
+       /**
+        * @brief Destroy all interfaces
+        * 
+        * @param this          stroke_t objec to destroy
+        */
+       void (*destroy) (interface_t *this);
+};
+
+
+/**
+ * Constructor in a control interface module to create the interface.
+ *
+ * @ingroup interfaces
+ */
+typedef interface_t*(*interface_constructor_t)(void);
+
+#endif /* INTERFACE_H_ */
+
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c
new file mode 100755 (executable)
index 0000000..d33cae8
--- /dev/null
@@ -0,0 +1,1622 @@
+/**
+ * @file stroke_interface.c
+ * 
+ * @brief Implementation of stroke_interface_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "stroke_interface.h"
+
+#include <library.h>
+#include <stroke.h>
+#include <daemon.h>
+#include <crypto/x509.h>
+#include <crypto/ca.h>
+#include <crypto/crl.h>
+#include <control/interface_manager.h>
+#include <control/interfaces/interface.h>
+#include <processing/jobs/initiate_job.h>
+#include <processing/jobs/route_job.h>
+#include <utils/leak_detective.h>
+
+#define IKE_PORT       500
+#define PATH_BUF       256
+#define STROKE_THREADS 3
+
+struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
+
+
+typedef struct private_stroke_interface_t private_stroke_interface_t;
+
+/**
+ * Private data of an stroke_interfacet object.
+ */
+struct private_stroke_interface_t {
+
+       /**
+        * Public part of stroke_interfacet object.
+        */
+       stroke_interface_t public;
+               
+       /**
+        * Unix socket to listen for strokes
+        */
+       int socket;
+       
+       /**
+        * Thread which reads from the Socket
+        */
+       pthread_t threads[STROKE_THREADS];
+};
+
+typedef struct stroke_log_info_t stroke_log_info_t;
+
+/**
+ * helper struct to say what and where to log when using controller callback
+ */
+struct stroke_log_info_t {
+
+       /**
+        * level to log up to
+        */
+       level_t level;
+       
+       /**
+        * where to write log
+        */
+       FILE* out;
+};
+
+/**
+ * Helper function which corrects the string pointers
+ * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
+ * contains RELATIVE addresses (relative to the beginning of the
+ * stroke_msg). They must be corrected if they reach our address
+ * space...
+ */
+static void pop_string(stroke_msg_t *msg, char **string)
+{
+       if (*string == NULL)
+               return;
+
+       /* check for sanity of string pointer and string */
+       if (string < (char**)msg
+       ||      string > (char**)msg + sizeof(stroke_msg_t)
+       || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg)
+       || (unsigned long)*string > msg->length)
+       {
+               *string = "(invalid pointer in stroke msg)";
+       }
+       else
+       {
+               *string = (char*)msg + (unsigned long)*string;
+       }
+}
+
+/**
+ * Load end entitity certificate
+ */
+static x509_t* load_end_certificate(const char *filename, identification_t **idp)
+{
+       char path[PATH_BUF];
+       x509_t *cert;
+
+       if (*filename == '/')
+       {
+               /* absolute path name */
+               snprintf(path, sizeof(path), "%s", filename);
+       }
+       else
+       {
+               /* relative path name */
+               snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+       }
+
+       cert = x509_create_from_file(path, "end entity");
+
+       if (cert)
+       {
+               identification_t *id = *idp;
+               identification_t *subject = cert->get_subject(cert);
+
+               err_t ugh = cert->is_valid(cert, NULL);
+
+               if (ugh != NULL)        
+               {
+                       DBG1(DBG_CFG, "warning: certificate %s", ugh);
+               }
+               if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
+               {
+                       id->destroy(id);
+                       id = subject;
+                       *idp = id->clone(id);
+               }
+               return charon->credentials->add_end_certificate(charon->credentials, cert);
+       }
+       return NULL;
+}
+
+/**
+ * Load ca certificate
+ */
+static x509_t* load_ca_certificate(const char *filename)
+{
+       char path[PATH_BUF];
+       x509_t *cert;
+
+       if (*filename == '/')
+       {
+               /* absolute path name */
+               snprintf(path, sizeof(path), "%s", filename);
+       }
+       else
+       {
+               /* relative path name */
+               snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+       }
+
+       cert = x509_create_from_file(path, "ca");
+
+       if (cert)
+       {
+               if (cert->is_ca(cert))
+               {
+                       return charon->credentials->add_auth_certificate(charon->credentials, cert, AUTH_CA);
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "  CA basic constraints flag not set, cert discarded");
+                       cert->destroy(cert);
+               }
+       }
+       return NULL;
+}
+
+/**
+ * Add a connection to the configuration list
+ */
+static void stroke_add_conn(private_stroke_interface_t *this,
+                                                       stroke_msg_t *msg, FILE *out)
+{
+       ike_cfg_t *ike_cfg;
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg;
+       identification_t *my_id, *other_id;
+       identification_t *my_ca = NULL;
+       identification_t *other_ca = NULL;
+       bool my_ca_same = FALSE;
+       bool other_ca_same =FALSE;
+       host_t *my_host, *other_host, *my_subnet, *other_subnet;
+       host_t *my_vip = NULL, *other_vip = NULL;
+       proposal_t *proposal;
+       traffic_selector_t *my_ts, *other_ts;
+       char *interface;
+       bool use_existing = FALSE;
+       iterator_t *iterator;
+       
+       pop_string(msg, &msg->add_conn.name);
+       pop_string(msg, &msg->add_conn.me.address);
+       pop_string(msg, &msg->add_conn.other.address);
+       pop_string(msg, &msg->add_conn.me.subnet);
+       pop_string(msg, &msg->add_conn.other.subnet);
+       pop_string(msg, &msg->add_conn.me.sourceip);
+       pop_string(msg, &msg->add_conn.other.sourceip);
+       pop_string(msg, &msg->add_conn.me.id);
+       pop_string(msg, &msg->add_conn.other.id);
+       pop_string(msg, &msg->add_conn.me.cert);
+       pop_string(msg, &msg->add_conn.other.cert);
+       pop_string(msg, &msg->add_conn.me.ca);
+       pop_string(msg, &msg->add_conn.other.ca);
+       pop_string(msg, &msg->add_conn.me.updown);
+       pop_string(msg, &msg->add_conn.other.updown);
+       pop_string(msg, &msg->add_conn.algorithms.ike);
+       pop_string(msg, &msg->add_conn.algorithms.esp);
+       
+       DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
+       
+       DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
+       DBG2(DBG_CFG, "  left=%s", msg->add_conn.me.address);
+       DBG2(DBG_CFG, "  right=%s", msg->add_conn.other.address);
+       DBG2(DBG_CFG, "  leftsubnet=%s", msg->add_conn.me.subnet);
+       DBG2(DBG_CFG, "  rightsubnet=%s", msg->add_conn.other.subnet);
+       DBG2(DBG_CFG, "  leftsourceip=%s", msg->add_conn.me.sourceip);
+       DBG2(DBG_CFG, "  rightsourceip=%s", msg->add_conn.other.sourceip);
+       DBG2(DBG_CFG, "  leftid=%s", msg->add_conn.me.id);
+       DBG2(DBG_CFG, "  rightid=%s", msg->add_conn.other.id);
+       DBG2(DBG_CFG, "  leftcert=%s", msg->add_conn.me.cert);
+       DBG2(DBG_CFG, "  rightcert=%s", msg->add_conn.other.cert);
+       DBG2(DBG_CFG, "  leftca=%s", msg->add_conn.me.ca);
+       DBG2(DBG_CFG, "  rightca=%s", msg->add_conn.other.ca);
+       DBG2(DBG_CFG, "  ike=%s", msg->add_conn.algorithms.ike);
+       DBG2(DBG_CFG, "  esp=%s", msg->add_conn.algorithms.esp);
+       
+       my_host = msg->add_conn.me.address?
+                         host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
+       if (my_host == NULL)
+       {
+               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
+               return;
+       }
+
+       other_host = msg->add_conn.other.address ?
+                       host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
+       if (other_host == NULL)
+       {
+               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
+               my_host->destroy(my_host);
+               return;
+       }
+       
+       interface = charon->kernel_interface->get_interface(charon->kernel_interface, 
+                                                                                                               other_host);
+       if (interface)
+       {
+               stroke_end_t tmp_end;
+               host_t *tmp_host;
+
+               DBG2(DBG_CFG, "left is other host, swapping ends\n");
+
+               tmp_host = my_host;
+               my_host = other_host;
+               other_host = tmp_host;
+
+               tmp_end = msg->add_conn.me;
+               msg->add_conn.me = msg->add_conn.other;
+               msg->add_conn.other = tmp_end;
+               free(interface);
+       }
+       if (!interface)
+       {
+               interface = charon->kernel_interface->get_interface(
+                                                                                       charon->kernel_interface, my_host);
+               if (!interface)
+               {
+                       DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
+                       goto destroy_hosts;
+               }
+               free(interface);
+       }
+
+       my_id = identification_create_from_string(msg->add_conn.me.id ?
+                                               msg->add_conn.me.id : msg->add_conn.me.address);
+       if (my_id == NULL)
+       {
+               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
+               goto destroy_hosts;
+       }
+
+       other_id = identification_create_from_string(msg->add_conn.other.id ?
+                                               msg->add_conn.other.id : msg->add_conn.other.address);
+       if (other_id == NULL)
+       {
+               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
+               my_id->destroy(my_id);
+               goto destroy_hosts;
+       }
+       
+       my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
+                                       msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
+       if (my_subnet == NULL)
+       {
+               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
+               goto destroy_ids;
+       }
+       
+       other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
+                                       msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
+       if (other_subnet == NULL)
+       {
+               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
+               my_subnet->destroy(my_subnet);
+               goto destroy_ids;
+       }
+       
+       if (msg->add_conn.me.virtual_ip)
+       {
+               my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
+       }
+       other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
+       
+       if (msg->add_conn.me.tohost)
+       {
+               my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol,
+                                       my_host->get_family(my_host) == AF_INET ?
+                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
+                                       msg->add_conn.me.port ? msg->add_conn.me.port : 0,
+                                       msg->add_conn.me.port ? msg->add_conn.me.port : 65535);
+       }
+       else
+       {
+               my_ts = traffic_selector_create_from_subnet(my_subnet,
+                               msg->add_conn.me.subnet ?  msg->add_conn.me.subnet_mask : 0,
+                               msg->add_conn.me.protocol, msg->add_conn.me.port);
+       }
+       my_subnet->destroy(my_subnet);
+       
+       if (msg->add_conn.other.tohost)
+       {
+               other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol,
+                                       other_host->get_family(other_host) == AF_INET ?
+                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
+                                       msg->add_conn.other.port ? msg->add_conn.other.port : 0,
+                                       msg->add_conn.other.port ? msg->add_conn.other.port : 65535);
+       }
+       else
+       {
+               other_ts = traffic_selector_create_from_subnet(other_subnet, 
+                               msg->add_conn.other.subnet ?  msg->add_conn.other.subnet_mask : 0,
+                               msg->add_conn.other.protocol, msg->add_conn.other.port);
+       }
+       other_subnet->destroy(other_subnet);
+
+       if (msg->add_conn.me.ca)
+       {
+               if (streq(msg->add_conn.me.ca, "%same"))
+               {
+                       my_ca_same = TRUE;
+               }
+               else
+               {
+                       my_ca = identification_create_from_string(msg->add_conn.me.ca);
+               }
+       }
+       if (msg->add_conn.other.ca)
+       {
+               if (streq(msg->add_conn.other.ca, "%same"))
+               {
+                       other_ca_same = TRUE;
+               }
+               else
+               {
+                       other_ca = identification_create_from_string(msg->add_conn.other.ca);
+               }
+       }
+       if (msg->add_conn.me.cert)
+       {
+               x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id);
+
+               if (my_ca == NULL && !my_ca_same && cert)
+               {
+                       identification_t *issuer = cert->get_issuer(cert);
+
+                       my_ca = issuer->clone(issuer);
+               }
+       }
+       if (msg->add_conn.other.cert)
+       {
+               x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id);
+
+               if (other_ca == NULL && !other_ca_same && cert)
+               {
+                       identification_t *issuer = cert->get_issuer(cert);
+
+                       other_ca = issuer->clone(issuer);
+               }
+       }
+       if (other_ca_same && my_ca)
+       {
+               other_ca = my_ca->clone(my_ca);
+       }
+       else if (my_ca_same && other_ca)
+       {
+               my_ca = other_ca->clone(other_ca);
+       }
+       if (my_ca == NULL)
+       {
+               my_ca = identification_create_from_string("%any");
+       }
+       if (other_ca == NULL)
+       {
+               other_ca = identification_create_from_string("%any");
+       }
+       DBG2(DBG_CFG, "  my ca:   '%D'", my_ca);
+       DBG2(DBG_CFG, "  other ca:'%D'", other_ca);
+       DBG2(DBG_CFG, "  updown: '%s'", msg->add_conn.me.updown);
+
+       /* have a look for an (almost) identical peer config to reuse */
+       iterator = charon->backends->create_iterator(charon->backends);
+       while (iterator->iterate(iterator, (void**)&peer_cfg))
+       {
+               ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+               if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg)) &&
+                       other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg)) &&
+                       my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) &&
+                       other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) &&
+                       peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) &&
+                       peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method &&
+                       peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type)
+               {
+                       DBG1(DBG_CFG, "reusing existing configuration '%s'",
+                                peer_cfg->get_name(peer_cfg));
+                       use_existing = TRUE;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+
+       if (use_existing)
+       {
+               DESTROY_IF(my_vip);
+               DESTROY_IF(other_vip);
+               my_host->destroy(my_host);
+               my_id->destroy(my_id);
+               my_ca->destroy(my_ca);
+               other_host->destroy(other_host);
+               other_id->destroy(other_id);
+               other_ca->destroy(other_ca);
+       }
+       else
+       {
+               ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
+                                                                my_host, other_host);
+
+               if (msg->add_conn.algorithms.ike)
+               {
+                       char *proposal_string;
+                       char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
+
+                       if (*strict == '!')
+                               *strict = '\0';
+                       else
+                               strict = NULL;
+
+                       while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
+                       {
+                               proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
+                               if (proposal == NULL)
+                               {
+                                       DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
+                                       my_id->destroy(my_id);
+                                       other_id->destroy(other_id);
+                                       my_ts->destroy(my_ts);
+                                       other_ts->destroy(other_ts);
+                                       my_ca->destroy(my_ca);
+                                       other_ca->destroy(other_ca);
+                                       ike_cfg->destroy(ike_cfg);
+                                       return;
+                               }
+                               ike_cfg->add_proposal(ike_cfg, proposal);
+                       }
+                       if (!strict)
+                       {
+                               proposal = proposal_create_default(PROTO_IKE);
+                               ike_cfg->add_proposal(ike_cfg, proposal);
+                       }
+               }
+               else
+               {
+                       proposal = proposal_create_default(PROTO_IKE);
+                       ike_cfg->add_proposal(ike_cfg, proposal);
+               }
+               
+               
+               peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1,
+                                       ike_cfg, my_id, other_id, my_ca, other_ca, msg->add_conn.me.sendcert, 
+                                       msg->add_conn.auth_method, msg->add_conn.eap_type,
+                                       msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
+                                       msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
+                                       msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
+                                       msg->add_conn.rekey.reauth, msg->add_conn.dpd.delay,
+                                       msg->add_conn.dpd.action,my_vip, other_vip);
+       }
+       
+       child_cfg = child_cfg_create(
+                               msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
+                               msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
+                               msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
+                               msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
+                               msg->add_conn.mode);
+       
+       peer_cfg->add_child_cfg(peer_cfg, child_cfg);
+       
+       child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts);
+       child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts);
+       
+       if (msg->add_conn.algorithms.esp)
+       {
+               char *proposal_string;
+               char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
+
+               if (*strict == '!')
+                       *strict = '\0';
+               else
+                       strict = NULL;
+               
+               while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
+               {
+                       proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
+                       if (proposal == NULL)
+                       {
+                               DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
+                               peer_cfg->destroy(peer_cfg);
+                               return;
+                       }
+                       child_cfg->add_proposal(child_cfg, proposal);
+               }
+               if (!strict)
+               {
+                       proposal = proposal_create_default(PROTO_ESP);
+                       child_cfg->add_proposal(child_cfg, proposal);
+               }
+       }
+       else
+       {
+               proposal = proposal_create_default(PROTO_ESP);
+               child_cfg->add_proposal(child_cfg, proposal);
+       }
+       
+       if (!use_existing)
+       {
+               /* add config to backend */
+               charon->backends->add_peer_cfg(charon->backends, peer_cfg);
+               DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]",
+                        msg->add_conn.name, my_host, my_id, other_host, other_id);
+       }
+       return;
+
+       /* mopping up after parsing errors */
+
+destroy_ids:
+       my_id->destroy(my_id);
+       other_id->destroy(other_id);
+
+destroy_hosts:
+       my_host->destroy(my_host);
+       other_host->destroy(other_host);
+}
+
+/**
+ * Delete a connection from the list
+ */
+static void stroke_del_conn(private_stroke_interface_t *this,
+                                                       stroke_msg_t *msg, FILE *out)
+{
+       iterator_t *peer_iter, *child_iter;
+       peer_cfg_t *peer, *child;
+       
+       pop_string(msg, &(msg->del_conn.name));
+       DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
+       
+       peer_iter = charon->backends->create_iterator(charon->backends);
+       while (peer_iter->iterate(peer_iter, (void**)&peer))
+       {
+               /* remove peer config with such a name */
+               if (streq(peer->get_name(peer), msg->del_conn.name))
+               {
+                       peer_iter->remove(peer_iter);
+                       peer->destroy(peer);
+                       continue;
+               }
+               /* remove any child with such a name */
+               child_iter = peer->create_child_cfg_iterator(peer);
+               while (child_iter->iterate(child_iter, (void**)&child))
+               {
+                       if (streq(child->get_name(child), msg->del_conn.name))
+                       {
+                               child_iter->remove(child_iter);
+                               child->destroy(child);
+                       }
+               }
+               child_iter->destroy(child_iter);
+       }
+       peer_iter->destroy(peer_iter);
+       
+       fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
+}
+
+/**
+ * get the child_cfg with the same name as the peer cfg
+ */
+static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
+{
+       child_cfg_t *current, *found = NULL;
+       iterator_t *iterator;
+       
+       iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
+       while (iterator->iterate(iterator, (void**)&current))
+       {
+               if (streq(current->get_name(current), name))
+               {
+                       found = current;
+                       found->get_ref(found);
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
+/**
+ * logging to the stroke interface
+ */
+static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level,
+                                          ike_sa_t *ike_sa, char *format, va_list args)
+{
+       if (level <= info->level)
+       {
+               vfprintf(info->out, format, args);
+               fprintf(info->out, "\n");
+               fflush(info->out);
+       }
+       return TRUE;
+}
+
+/**
+ * get a peer configuration by its name, or a name of its children
+ */
+static peer_cfg_t *get_peer_cfg_by_name(char *name)
+{
+       iterator_t *i1, *i2;
+       peer_cfg_t *current, *found = NULL;
+       child_cfg_t *child;
+
+       i1 = charon->backends->create_iterator(charon->backends);
+       while (i1->iterate(i1, (void**)&current))
+       {
+               /* compare peer_cfgs name first */
+               if (streq(current->get_name(current), name))
+               {
+                       found = current;
+                       found->get_ref(found);
+                       break;
+               }
+               /* compare all child_cfg names otherwise */
+               i2 = current->create_child_cfg_iterator(current);
+               while (i2->iterate(i2, (void**)&child))
+               {
+                       if (streq(child->get_name(child), name))
+                       {
+                               found = current;
+                               found->get_ref(found);
+                               break;
+                       }
+               }
+               i2->destroy(i2);
+               if (found)
+               {
+                       break;
+               }
+       }
+       i1->destroy(i1);
+       return found;
+}
+
+/**
+ * initiate a connection by name
+ */
+static void stroke_initiate(private_stroke_interface_t *this,
+                                                       stroke_msg_t *msg, FILE *out)
+{
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg;
+       stroke_log_info_t info;
+       
+       pop_string(msg, &(msg->initiate.name));
+       DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
+       
+       peer_cfg = get_peer_cfg_by_name(msg->initiate.name);
+       if (peer_cfg == NULL)
+       {
+               fprintf(out, "no config named '%s'\n", msg->initiate.name);
+               return;
+       }
+       if (peer_cfg->get_ike_version(peer_cfg) != 2)
+       {
+               DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
+                        peer_cfg->get_ike_version(peer_cfg));
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
+       if (child_cfg == NULL)
+       {
+               fprintf(out, "no child config named '%s'\n", msg->initiate.name);
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       info.out = out;
+       info.level = msg->output_verbosity;
+       
+       charon->interfaces->initiate(charon->interfaces, peer_cfg, child_cfg,
+                                                                (interface_manager_cb_t)stroke_log, &info);
+}
+
+/**
+ * route/unroute a policy (install SPD entries)
+ */
+static void stroke_route(private_stroke_interface_t *this,
+                                                stroke_msg_t *msg, FILE *out, bool route)
+{
+       route_job_t *job;
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg;
+       
+       pop_string(msg, &(msg->route.name));
+       DBG1(DBG_CFG, "received stroke: %s '%s'",
+                route ? "route" : "unroute", msg->route.name);
+       
+       peer_cfg = get_peer_cfg_by_name(msg->route.name);
+       if (peer_cfg == NULL)
+       {
+               fprintf(out, "no config named '%s'\n", msg->route.name);
+               return;
+       }
+       if (peer_cfg->get_ike_version(peer_cfg) != 2)
+       {
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
+       if (child_cfg == NULL)
+       {
+               fprintf(out, "no child config named '%s'\n", msg->route.name);
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       fprintf(out, "%s policy '%s'\n",
+                       route ? "routing" : "unrouting", msg->route.name);
+       job = route_job_create(peer_cfg, child_cfg, route);
+       charon->job_queue->add(charon->job_queue, (job_t*)job);
+}
+
+/**
+ * terminate a connection by name
+ */
+static void stroke_terminate(private_stroke_interface_t *this,
+                                                        stroke_msg_t *msg, FILE *out)
+{
+       char *string, *pos = NULL, *name = NULL;
+       u_int32_t id = 0;
+       bool child;
+       int len;
+       status_t status = SUCCESS;;
+       ike_sa_t *ike_sa;
+       
+       pop_string(msg, &(msg->terminate.name));
+       string = msg->terminate.name;
+       DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
+       
+       len = strlen(string);
+       if (len < 1)
+       {
+               DBG1(DBG_CFG, "error parsing string");
+               return;
+       }
+       switch (string[len-1])
+       {
+               case '}':
+                       child = TRUE;
+                       pos = strchr(string, '{');
+                       break;
+               case ']':
+                       child = FALSE;
+                       pos = strchr(string, '[');
+                       break;
+               default:
+                       name = string;
+                       child = FALSE;
+                       break;
+       }
+       
+       if (name)
+       {       /* must be a single name */
+               DBG1(DBG_CFG, "check out by single name '%s'", name);
+               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+                                                                                                                 name, child);
+       }
+       else if (pos == string + len - 2)
+       {       /* must be name[] or name{} */
+               string[len-2] = '\0';
+               DBG1(DBG_CFG, "check out by name '%s'", string);
+               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+                                                                                                                 string, child);
+       }
+       else
+       {       /* must be name[123] or name{23} */
+               string[len-1] = '\0';
+               id = atoi(pos + 1);
+               if (id == 0)
+               {
+                       DBG1(DBG_CFG, "error parsing string");
+                       return;
+               }
+               DBG1(DBG_CFG, "check out by id '%d'", id);
+               ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                               id, child);
+       }
+       if (ike_sa == NULL)
+       {
+               DBG1(DBG_CFG, "no such IKE_SA found");
+               return;
+       }
+       
+       if (!child)
+       {
+               status = ike_sa->delete(ike_sa);
+       }
+       else
+       {
+               child_sa_t *child_sa;
+               iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
+               while (iterator->iterate(iterator, (void**)&child_sa))
+               {
+                       if ((id && id == child_sa->get_reqid(child_sa)) ||
+                               (string && streq(string, child_sa->get_name(child_sa))))
+                       {
+                               u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
+                               protocol_id_t proto = child_sa->get_protocol(child_sa);
+                               
+                               status = ike_sa->delete_child_sa(ike_sa, proto, spi);
+                               break;
+                       }
+               }
+               iterator->destroy(iterator);
+       }
+       if (status == DESTROY_ME)
+       {
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                       ike_sa);
+               return;
+       }
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+}
+
+/**
+ * Add a ca information record to the cainfo list
+ */
+static void stroke_add_ca(private_stroke_interface_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       x509_t *cacert;
+       ca_info_t *ca_info;
+
+       pop_string(msg, &msg->add_ca.name);
+       pop_string(msg, &msg->add_ca.cacert);
+       pop_string(msg, &msg->add_ca.crluri);
+       pop_string(msg, &msg->add_ca.crluri2);
+       pop_string(msg, &msg->add_ca.ocspuri);
+       pop_string(msg, &msg->add_ca.ocspuri2);
+       
+       DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
+       
+       DBG2(DBG_CFG, "ca %s",        msg->add_ca.name);
+       DBG2(DBG_CFG, "  cacert=%s",  msg->add_ca.cacert);
+       DBG2(DBG_CFG, "  crluri=%s",  msg->add_ca.crluri);
+       DBG2(DBG_CFG, "  crluri2=%s", msg->add_ca.crluri2);
+       DBG2(DBG_CFG, "  ocspuri=%s", msg->add_ca.ocspuri);
+       DBG2(DBG_CFG, "  ocspuri2=%s", msg->add_ca.ocspuri2);
+
+       if (msg->add_ca.cacert == NULL)
+       {
+               DBG1(DBG_CFG, "missing cacert parameter\n");
+               return;
+       }
+
+       cacert = load_ca_certificate(msg->add_ca.cacert);
+
+       if (cacert == NULL)
+       {
+               return;
+       }
+       ca_info = ca_info_create(msg->add_ca.name, cacert);
+
+       if (msg->add_ca.crluri)
+       {
+               chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) };
+               
+               ca_info->add_crluri(ca_info, uri);
+       }
+       if (msg->add_ca.crluri2)
+       {
+               chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) };
+               
+               ca_info->add_crluri(ca_info, uri);
+       }
+       if (msg->add_ca.ocspuri)
+       {
+               chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) };
+               
+               ca_info->add_ocspuri(ca_info, uri);
+       }
+       if (msg->add_ca.ocspuri2)
+       {
+               chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) };
+               
+               ca_info->add_ocspuri(ca_info, uri);
+       }
+       charon->credentials->add_ca_info(charon->credentials, ca_info);
+       DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
+
+}
+
+/**
+ * Delete a ca information record from the cainfo list
+ */
+static void stroke_del_ca(private_stroke_interface_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       status_t status;
+       
+       pop_string(msg, &(msg->del_ca.name));
+       DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
+       
+       status = charon->credentials->release_ca_info(charon->credentials,
+                                                                                                 msg->del_ca.name);
+
+       if (status == SUCCESS)
+       {
+               fprintf(out, "deleted ca '%s'\n", msg->del_ca.name);
+       }
+       else
+       {
+               fprintf(out, "no ca named '%s'\n", msg->del_ca.name);
+       }
+}
+
+/**
+ * log an IKE_SA to out
+ */
+static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
+{
+       peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa);
+       ike_sa_id_t *id = ike_sa->get_id(ike_sa);
+       u_int32_t next, now = time(NULL);
+
+       fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
+                       ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+                       ike_sa_state_names, ike_sa->get_state(ike_sa),
+                       ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
+                       ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
+       
+       if (all)
+       {
+               fprintf(out, "%12s[%d]: IKE SPIs: 0x%0llx_i%s 0x%0llx_r%s, ",
+                               ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+                               id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
+                               id->get_responder_spi(id), id->is_initiator(id) ? "" : "");
+       
+               ike_sa->get_stats(ike_sa, &next);
+               if (next)
+               {
+                       fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ?
+                                       "reauthentication" : "rekeying", &now, &next);
+               }
+               else
+               {
+                       fprintf(out, "rekeying disabled\n");
+               }
+       }
+}
+
+/**
+ * log an CHILD_SA to out
+ */
+static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
+{
+       u_int32_t rekey, now = time(NULL);
+       u_int32_t use_in, use_out, use_fwd;
+       encryption_algorithm_t encr_alg;
+       integrity_algorithm_t int_alg;
+       size_t encr_len, int_len;
+       mode_t mode;
+       
+       child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
+                                               &int_alg, &int_len, &rekey, &use_in, &use_out,
+                                               &use_fwd);
+       
+       fprintf(out, "%12s{%d}:  %N, %N", 
+                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+                       child_sa_state_names, child_sa->get_state(child_sa),
+                       mode_names, mode);
+       
+       if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
+       {
+               fprintf(out, ", %N SPIs: 0x%0x_i 0x%0x_o",
+                               protocol_id_names, child_sa->get_protocol(child_sa),
+                               htonl(child_sa->get_spi(child_sa, TRUE)),
+                               htonl(child_sa->get_spi(child_sa, FALSE)));
+               
+               if (all)
+               {
+                       fprintf(out, "\n%12s{%d}:  ", child_sa->get_name(child_sa), 
+                                       child_sa->get_reqid(child_sa));
+                       
+                       
+                       if (child_sa->get_protocol(child_sa) == PROTO_ESP)
+                       {
+                               fprintf(out, "%N", encryption_algorithm_names, encr_alg);
+                               
+                               if (encr_len)
+                               {
+                                       fprintf(out, "-%d", encr_len);
+                               }
+                               fprintf(out, "/");
+                       }
+                       
+                       fprintf(out, "%N", integrity_algorithm_names, int_alg);
+                       if (int_len)
+                       {
+                               fprintf(out, "-%d", int_len);
+                       }
+                       fprintf(out, ", rekeying ");
+                       
+                       if (rekey)
+                       {
+                               fprintf(out, "in %V", &now, &rekey);
+                       }
+                       else
+                       {
+                               fprintf(out, "disabled");
+                       }
+                       
+                       fprintf(out, ", last use: ");
+                       use_in = max(use_in, use_fwd);
+                       if (use_in)
+                       {
+                               fprintf(out, "%ds_i ", now - use_in);
+                       }
+                       else
+                       {
+                               fprintf(out, "no_i ");
+                       }
+                       if (use_out)
+                       {
+                               fprintf(out, "%ds_o ", now - use_out);
+                       }
+                       else
+                       {
+                               fprintf(out, "no_o ");
+                       }
+               }
+       }
+       
+       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
+                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+                       child_sa->get_traffic_selectors(child_sa, TRUE),
+                       child_sa->get_traffic_selectors(child_sa, FALSE));
+}
+
+/**
+ * show status of daemon
+ */
+static void stroke_status(private_stroke_interface_t *this,
+                                                 stroke_msg_t *msg, FILE *out, bool all)
+{
+       iterator_t *iterator, *children;
+       linked_list_t *list;
+       host_t *host;
+       peer_cfg_t *peer_cfg;
+       ike_cfg_t *ike_cfg;
+       child_cfg_t *child_cfg;
+       ike_sa_t *ike_sa;
+       char *name = NULL;
+       
+       if (msg->status.name)
+       {
+               pop_string(msg, &(msg->status.name));
+               name = msg->status.name;
+       }
+       
+       if (all)
+       {
+               leak_detective_status(out);
+       
+               fprintf(out, "Performance:\n");
+               fprintf(out, "  worker threads: %d idle of %d,",
+                               charon->thread_pool->get_idle_threads(charon->thread_pool),
+                               charon->thread_pool->get_pool_size(charon->thread_pool));
+               fprintf(out, " job queue load: %d,",
+                               charon->job_queue->get_count(charon->job_queue));
+               fprintf(out, " scheduled events: %d\n",
+                               charon->event_queue->get_count(charon->event_queue));
+               list = charon->kernel_interface->create_address_list(charon->kernel_interface);
+
+               fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
+               while (list->remove_first(list, (void**)&host) == SUCCESS)
+               {
+                       fprintf(out, "  %H\n", host);
+                       host->destroy(host);
+               }
+               list->destroy(list);
+       
+               fprintf(out, "Connections:\n");
+               iterator = charon->backends->create_iterator(charon->backends);
+               while (iterator->iterate(iterator, (void**)&peer_cfg))
+               {
+                       if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
+                               (name && !streq(name, peer_cfg->get_name(peer_cfg))))
+                       {
+                               continue;
+                       }
+                       
+                       ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+                       fprintf(out, "%12s:  %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
+                                       ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
+                                       ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
+                       children = peer_cfg->create_child_cfg_iterator(peer_cfg);
+                       while (children->iterate(children, (void**)&child_cfg))
+                       {
+                               linked_list_t *my_ts, *other_ts;
+                               my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
+                               other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
+                               fprintf(out, "%12s:    %#R=== %#R\n", child_cfg->get_name(child_cfg),
+                                               my_ts, other_ts);
+                               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+                               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+                       }
+                       children->destroy(children);
+               }
+               iterator->destroy(iterator);
+       }
+       
+       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+       if (all && iterator->get_count(iterator) > 0)
+       {
+               fprintf(out, "Security Associations:\n");
+       }
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               bool ike_printed = FALSE;
+               child_sa_t *child_sa;
+               iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
+
+               if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
+               {
+                       log_ike_sa(out, ike_sa, all);
+                       ike_printed = TRUE;
+               }
+
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       if (name == NULL || streq(name, child_sa->get_name(child_sa)))
+                       {
+                               if (!ike_printed)
+                               {
+                                       log_ike_sa(out, ike_sa, all);
+                                       ike_printed = TRUE;
+                               }
+                               log_child_sa(out, child_sa, all);
+                       }       
+               }
+               children->destroy(children);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * list all authority certificates matching a specified flag 
+ */
+static void list_auth_certificates(private_stroke_interface_t *this,  u_int flag,
+                                                                  const char *label, bool utc, FILE *out)
+{
+       bool first = TRUE;
+       x509_t *cert;
+       
+       iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials);
+
+       while (iterator->iterate(iterator, (void**)&cert))
+       {
+               if (cert->has_authority_flag(cert, flag))
+               {
+                       if (first)
+                       {
+                               fprintf(out, "\n");
+                               fprintf(out, "List of X.509 %s Certificates:\n", label);
+                               fprintf(out, "\n");
+                               first = FALSE;
+                       }
+                       cert->list(cert, out, utc);
+                       fprintf(out, "\n");
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * list various information
+ */
+static void stroke_list(private_stroke_interface_t *this, 
+                                               stroke_msg_t *msg, FILE *out)
+{
+       iterator_t *iterator;
+       
+       if (msg->list.flags & LIST_CERTS)
+       {
+               x509_t *cert;
+               
+               iterator = charon->credentials->create_cert_iterator(charon->credentials);
+               if (iterator->get_count(iterator))
+               {
+                       fprintf(out, "\n");
+                       fprintf(out, "List of X.509 End Entity Certificates:\n");
+                       fprintf(out, "\n");
+               }
+               while (iterator->iterate(iterator, (void**)&cert))
+               {
+                       cert->list(cert, out, msg->list.utc);
+                       if (charon->credentials->has_rsa_private_key(
+                                       charon->credentials, cert->get_public_key(cert)))
+                       {
+                               fprintf(out, ", has private key");
+                       }
+                       fprintf(out, "\n");
+                       
+               }
+               iterator->destroy(iterator);
+       }
+       if (msg->list.flags & LIST_CACERTS)
+       {
+               list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_OCSPCERTS)
+       {
+               list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_AACERTS)
+       {
+               list_auth_certificates(this, AUTH_AA, "AA", msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_CAINFOS)
+       {
+               ca_info_t *ca_info;
+
+               iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+               if (iterator->get_count(iterator))
+               {
+                       fprintf(out, "\n");
+                       fprintf(out, "List of X.509 CA Information Records:\n");
+                       fprintf(out, "\n");
+               }
+               while (iterator->iterate(iterator, (void**)&ca_info))
+               {
+                       ca_info->list(ca_info, out, msg->list.utc);
+               }
+               iterator->destroy(iterator);
+       }
+       if (msg->list.flags & LIST_CRLS)
+       {
+        ca_info_t *ca_info;
+        bool first = TRUE;
+        
+        iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+        while (iterator->iterate(iterator, (void **)&ca_info))
+        {
+            if (ca_info->has_crl(ca_info))
+            {
+                if (first)
+                {
+                    fprintf(out, "\n");
+                    fprintf(out, "List of X.509 CRLs:\n");
+                    fprintf(out, "\n");
+                    first = FALSE;
+                }
+                ca_info->list_crl(ca_info, out, msg->list.utc);
+            }
+        }
+        iterator->destroy(iterator);
+       }
+       if (msg->list.flags & LIST_OCSP)
+       {
+               ca_info_t *ca_info;
+               bool first = TRUE;
+
+        iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+        while (iterator->iterate(iterator, (void **)&ca_info))
+        {
+            if (ca_info->has_certinfos(ca_info))
+            {
+                if (first)
+                {
+                    fprintf(out, "\n");
+                    fprintf(out, "List of OCSP responses:\n");
+                    first = FALSE;
+                }
+                fprintf(out, "\n");
+                ca_info->list_certinfos(ca_info, out, msg->list.utc);
+            }
+        }
+        iterator->destroy(iterator);
+       }
+}
+
+/**
+ * reread various information
+ */
+static void stroke_reread(private_stroke_interface_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       if (msg->reread.flags & REREAD_CACERTS)
+       {
+               charon->credentials->load_ca_certificates(charon->credentials);
+       }
+       if (msg->reread.flags & REREAD_OCSPCERTS)
+       {
+               charon->credentials->load_ocsp_certificates(charon->credentials);
+       }
+       if (msg->reread.flags & REREAD_CRLS)
+       {
+               charon->credentials->load_crls(charon->credentials);
+       }
+}
+
+/**
+ * purge various information
+ */
+static void stroke_purge(private_stroke_interface_t *this,
+                                                stroke_msg_t *msg, FILE *out)
+{
+       if (msg->purge.flags & PURGE_OCSP)
+       {
+               iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+               ca_info_t *ca_info;
+
+               while (iterator->iterate(iterator, (void**)&ca_info))
+               {
+                       ca_info->purge_ocsp(ca_info);
+               }
+               iterator->destroy(iterator);
+       }
+}
+
+signal_t get_signal_from_logtype(char *type)
+{
+       if      (strcasecmp(type, "any") == 0) return SIG_ANY;
+       else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
+       else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
+       else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
+       else if (strcasecmp(type, "job") == 0) return DBG_JOB;
+       else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
+       else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
+       else if (strcasecmp(type, "net") == 0) return DBG_NET;
+       else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
+       else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
+       else return -1;
+}
+
+/**
+ * set the verbosity debug output
+ */
+static void stroke_loglevel(private_stroke_interface_t *this,
+                                                       stroke_msg_t *msg, FILE *out)
+{
+       signal_t signal;
+       
+       pop_string(msg, &(msg->loglevel.type));
+       DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
+                msg->loglevel.level, msg->loglevel.type);
+       
+       signal = get_signal_from_logtype(msg->loglevel.type);
+       if (signal < 0)
+       {
+               fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
+               return;
+       }
+       
+       charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
+       charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
+}
+
+/**
+ * process a stroke request from the socket pointed by "fd"
+ */
+static void stroke_process(private_stroke_interface_t *this, int strokefd)
+{
+       stroke_msg_t *msg;
+       u_int16_t msg_length;
+       ssize_t bytes_read;
+       FILE *out;
+       
+       /* peek the length */
+       bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
+       if (bytes_read != sizeof(msg_length))
+       {
+               DBG1(DBG_CFG, "reading length of stroke message failed");
+               close(strokefd);
+               return;
+       }
+       
+       /* read message */
+       msg = malloc(msg_length);
+       bytes_read = recv(strokefd, msg, msg_length, 0);
+       if (bytes_read != msg_length)
+       {
+               DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
+               close(strokefd);
+               return;
+       }
+       
+       out = fdopen(dup(strokefd), "w");
+       if (out == NULL)
+       {
+               DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
+               close(strokefd);
+               free(msg);
+               return;
+       }
+       
+       DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
+       
+       switch (msg->type)
+       {
+               case STR_INITIATE:
+                       stroke_initiate(this, msg, out);
+                       break;
+               case STR_ROUTE:
+                       stroke_route(this, msg, out, TRUE);
+                       break;
+               case STR_UNROUTE:
+                       stroke_route(this, msg, out, FALSE);
+                       break;
+               case STR_TERMINATE:
+                       stroke_terminate(this, msg, out);
+                       break;
+               case STR_STATUS:
+                       stroke_status(this, msg, out, FALSE);
+                       break;
+               case STR_STATUS_ALL:
+                       stroke_status(this, msg, out, TRUE);
+                       break;
+               case STR_ADD_CONN:
+                       stroke_add_conn(this, msg, out);
+                       break;
+               case STR_DEL_CONN:
+                       stroke_del_conn(this, msg, out);
+                       break;
+               case STR_ADD_CA:
+                       stroke_add_ca(this, msg, out);
+                       break;
+               case STR_DEL_CA:
+                       stroke_del_ca(this, msg, out);
+                       break;
+               case STR_LOGLEVEL:
+                       stroke_loglevel(this, msg, out);
+                       break;
+               case STR_LIST:
+                       stroke_list(this, msg, out);
+                       break;
+               case STR_REREAD:
+                       stroke_reread(this, msg, out);
+                       break;
+               case STR_PURGE:
+                       stroke_purge(this, msg, out);
+                       break;
+               default:
+                       DBG1(DBG_CFG, "received unknown stroke");
+       }
+       fclose(out);
+       close(strokefd);
+       free(msg);
+}
+
+/**
+ * Implementation of private_stroke_interface_t.stroke_receive.
+ */
+static void stroke_receive(private_stroke_interface_t *this)
+{
+       struct sockaddr_un strokeaddr;
+       int strokeaddrlen = sizeof(strokeaddr);
+       int oldstate;
+       int strokefd;
+       
+       /* ignore sigpipe. writing over the pipe back to the console
+        * only fails if SIGPIPE is ignored. */
+       signal(SIGPIPE, SIG_IGN);
+       
+       /* disable cancellation by default */
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+       
+       while (TRUE)
+       {
+               /* wait for connections, but allow thread to terminate */
+               pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+               strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
+               pthread_setcancelstate(oldstate, NULL);
+               
+               if (strokefd < 0)
+               {
+                       DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
+                       continue;
+               }
+               stroke_process(this, strokefd);
+       }
+}
+
+/**
+ * Implementation of interface_t.destroy.
+ */
+static void destroy(private_stroke_interface_t *this)
+{
+       int i;
+       
+       for (i = 0; i < STROKE_THREADS; i++)
+       {
+               pthread_cancel(this->threads[i]);
+               pthread_join(this->threads[i], NULL);
+       }
+
+       close(this->socket);
+       unlink(socket_addr.sun_path);
+       free(this);
+}
+
+/*
+ * Described in header-file
+ */
+interface_t *interface_create()
+{
+       private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t);
+       mode_t old;
+       int i;
+
+       /* public functions */
+       this->public.interface.destroy = (void (*)(stroke_interface_t*))destroy;
+       
+       /* set up unix socket */
+       this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (this->socket == -1)
+       {
+               DBG1(DBG_CFG, "could not create whack socket");
+               free(this);
+               return NULL;
+       }
+       
+       old = umask(~S_IRWXU);
+       if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
+       {
+               DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
+               close(this->socket);
+               free(this);
+               return NULL;
+       }
+       umask(old);
+       
+       if (listen(this->socket, 0) < 0)
+       {
+               DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
+               close(this->socket);
+               unlink(socket_addr.sun_path);
+               free(this);
+               return NULL;
+       }
+       
+       /* start threads reading from the socket */
+       for (i = 0; i < STROKE_THREADS; i++)
+       {
+               if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0)
+               {
+                       charon->kill(charon, "unable to create stroke thread");
+               }
+       }
+       
+       return (&this->public);
+}
diff --git a/src/charon/control/interfaces/stroke_interface.h b/src/charon/control/interfaces/stroke_interface.h
new file mode 100644 (file)
index 0000000..f189048
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * @file stroke_interface.h
+ *
+ * @brief Interface of stroke_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * 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.
+ */
+
+#ifndef STROKE_INTERFACE_H_
+#define STROKE_INTERFACE_H_
+
+typedef struct stroke_interface_t stroke_interface_t;
+
+#include <control/interfaces/interface.h>
+
+/**
+ * @brief Stroke is a configuration and control interface which
+ * allows other processes to modify charons behavior.
+ * 
+ * stroke_t allows config manipulation (as whack in pluto). Configurations
+ * are stored in a special backend, the in-memory local_backend_t.
+ * Messages of type stroke_msg_t's are sent over a unix socket
+ * (/var/run/charon.ctl).
+ * 
+ * @b Constructors:
+ * - stroke_create()
+ * 
+ * @ingroup interfaces
+ */
+struct stroke_interface_t {
+       
+       /**
+        * implements interface_t.
+        */
+       interface_t interface;
+};
+
+
+/**
+ * @brief Create the stroke interface and listen on the socket.
+ * 
+ * @return                     stroke_t object
+ * 
+ * @ingroup interfaces
+ */
+interface_t *interface_create(void);
+
+#endif /* STROKE_INTERFACE_H_ */
+
diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c
new file mode 100644 (file)
index 0000000..ad92e80
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * @file xml_interface.c
+ * 
+ * @brief Implementation of xml_interface_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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 <stdlib.h>
+
+#include "xml_interface.h"
+
+#include <library.h>
+#include <daemon.h>
+
+
+typedef struct private_xml_interface_t private_xml_interface_t;
+
+/**
+ * Private data of an xml_interface_t object.
+ */
+struct private_xml_interface_t {
+
+       /**
+        * Public part of xml_t object.
+        */
+       xml_interface_t public;
+};
+
+
+/**
+ * Implementation of itnerface_t.destroy.
+ */
+static void destroy(private_xml_interface_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header file
+ */
+interface_t *interface_create()
+{
+       private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
+
+       this->public.interface.destroy = (void (*)(xml_interface_t*))destroy;
+       
+       return &this->public;
+}
diff --git a/src/charon/control/interfaces/xml_interface.h b/src/charon/control/interfaces/xml_interface.h
new file mode 100644 (file)
index 0000000..6d88c38
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file xml_interface.h
+ *
+ * @brief Interface of xml_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+#ifndef XML_INTERFACE_H_
+#define XML_INTERFACE_H_
+
+typedef struct xml_interface_t xml_interface_t;
+
+#include <control/interfaces/interface.h>
+
+/**
+ * @brief The XML interface uses a socket to communicate using XML.
+ * 
+ * @b Constructors:
+ * - xml_interface_create()
+ * 
+ * @ingroup interfaces
+ */
+struct xml_interface_t {
+       
+       /**
+        * implements interface_t.
+        */
+       interface_t interface;
+};
+
+
+/**
+ * @brief Create the XML interface.
+ *
+ * @return                     stroke_t object
+ * 
+ * @ingroup interfaces
+ */
+interface_t *interface_create(void);
+
+#endif /* XML_INTERFACE_H_ */
+
diff --git a/src/charon/control/stroke_interface.c b/src/charon/control/stroke_interface.c
deleted file mode 100755 (executable)
index 9743f57..0000000
+++ /dev/null
@@ -1,1589 +0,0 @@
-/**
- * @file stroke_interface.c
- * 
- * @brief Implementation of stroke_interface_t.
- * 
- */
-
-/*
- * Copyright (C) 2006-2007 Martin Willi
- * 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 <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/fcntl.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-
-#include "stroke_interface.h"
-
-#include <library.h>
-#include <stroke.h>
-#include <daemon.h>
-#include <crypto/x509.h>
-#include <crypto/ca.h>
-#include <crypto/crl.h>
-#include <control/controller.h>
-#include <processing/jobs/initiate_job.h>
-#include <processing/jobs/route_job.h>
-#include <utils/leak_detective.h>
-
-#define IKE_PORT       500
-#define PATH_BUF       256
-#define STROKE_THREADS 3
-
-struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
-
-
-typedef struct private_stroke_interface_t private_stroke_interface_t;
-
-/**
- * Private data of an stroke_t object.
- */
-struct private_stroke_interface_t {
-
-       /**
-        * Public part of stroke_t object.
-        */
-       stroke_t public;
-       
-       /**
-        * backend to store configurations
-        */
-       local_backend_t *backend;
-               
-       /**
-        * Unix socket to listen for strokes
-        */
-       int socket;
-       
-       /**
-        * Thread which reads from the Socket
-        */
-       pthread_t threads[STROKE_THREADS];
-};
-
-typedef struct stroke_log_info_t stroke_log_info_t;
-
-/**
- * helper struct to say what and where to log when using controller callback
- */
-struct stroke_log_info_t {
-
-       /**
-        * level to log up to
-        */
-       level_t level;
-       
-       /**
-        * where to write log
-        */
-       FILE* out;
-};
-
-/**
- * Helper function which corrects the string pointers
- * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
- * contains RELATIVE addresses (relative to the beginning of the
- * stroke_msg). They must be corrected if they reach our address
- * space...
- */
-static void pop_string(stroke_msg_t *msg, char **string)
-{
-       if (*string == NULL)
-               return;
-
-       /* check for sanity of string pointer and string */
-       if (string < (char**)msg
-       ||      string > (char**)msg + sizeof(stroke_msg_t)
-       || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg)
-       || (unsigned long)*string > msg->length)
-       {
-               *string = "(invalid pointer in stroke msg)";
-       }
-       else
-       {
-               *string = (char*)msg + (unsigned long)*string;
-       }
-}
-
-/**
- * Load end entitity certificate
- */
-static x509_t* load_end_certificate(const char *filename, identification_t **idp)
-{
-       char path[PATH_BUF];
-       x509_t *cert;
-
-       if (*filename == '/')
-       {
-               /* absolute path name */
-               snprintf(path, sizeof(path), "%s", filename);
-       }
-       else
-       {
-               /* relative path name */
-               snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
-       }
-
-       cert = x509_create_from_file(path, "end entity");
-
-       if (cert)
-       {
-               identification_t *id = *idp;
-               identification_t *subject = cert->get_subject(cert);
-
-               err_t ugh = cert->is_valid(cert, NULL);
-
-               if (ugh != NULL)        
-               {
-                       DBG1(DBG_CFG, "warning: certificate %s", ugh);
-               }
-               if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
-               {
-                       id->destroy(id);
-                       id = subject;
-                       *idp = id->clone(id);
-               }
-               return charon->credentials->add_end_certificate(charon->credentials, cert);
-       }
-       return NULL;
-}
-
-/**
- * Load ca certificate
- */
-static x509_t* load_ca_certificate(const char *filename)
-{
-       char path[PATH_BUF];
-       x509_t *cert;
-
-       if (*filename == '/')
-       {
-               /* absolute path name */
-               snprintf(path, sizeof(path), "%s", filename);
-       }
-       else
-       {
-               /* relative path name */
-               snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
-       }
-
-       cert = x509_create_from_file(path, "ca");
-
-       if (cert)
-       {
-               if (cert->is_ca(cert))
-               {
-                       return charon->credentials->add_auth_certificate(charon->credentials, cert, AUTH_CA);
-               }
-               else
-               {
-                       DBG1(DBG_CFG, "  CA basic constraints flag not set, cert discarded");
-                       cert->destroy(cert);
-               }
-       }
-       return NULL;
-}
-
-/**
- * Add a connection to the configuration list
- */
-static void stroke_add_conn(private_stroke_interface_t *this,
-                                                       stroke_msg_t *msg, FILE *out)
-{
-       ike_cfg_t *ike_cfg;
-       peer_cfg_t *peer_cfg;
-       child_cfg_t *child_cfg;
-       identification_t *my_id, *other_id;
-       identification_t *my_ca = NULL;
-       identification_t *other_ca = NULL;
-       bool my_ca_same = FALSE;
-       bool other_ca_same =FALSE;
-       host_t *my_host, *other_host, *my_subnet, *other_subnet;
-       host_t *my_vip = NULL, *other_vip = NULL;
-       proposal_t *proposal;
-       traffic_selector_t *my_ts, *other_ts;
-       char *interface;
-       bool use_existing = FALSE;
-       iterator_t *iterator;
-       
-       pop_string(msg, &msg->add_conn.name);
-       pop_string(msg, &msg->add_conn.me.address);
-       pop_string(msg, &msg->add_conn.other.address);
-       pop_string(msg, &msg->add_conn.me.subnet);
-       pop_string(msg, &msg->add_conn.other.subnet);
-       pop_string(msg, &msg->add_conn.me.sourceip);
-       pop_string(msg, &msg->add_conn.other.sourceip);
-       pop_string(msg, &msg->add_conn.me.id);
-       pop_string(msg, &msg->add_conn.other.id);
-       pop_string(msg, &msg->add_conn.me.cert);
-       pop_string(msg, &msg->add_conn.other.cert);
-       pop_string(msg, &msg->add_conn.me.ca);
-       pop_string(msg, &msg->add_conn.other.ca);
-       pop_string(msg, &msg->add_conn.me.updown);
-       pop_string(msg, &msg->add_conn.other.updown);
-       pop_string(msg, &msg->add_conn.algorithms.ike);
-       pop_string(msg, &msg->add_conn.algorithms.esp);
-       
-       DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
-       
-       DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
-       DBG2(DBG_CFG, "  left=%s", msg->add_conn.me.address);
-       DBG2(DBG_CFG, "  right=%s", msg->add_conn.other.address);
-       DBG2(DBG_CFG, "  leftsubnet=%s", msg->add_conn.me.subnet);
-       DBG2(DBG_CFG, "  rightsubnet=%s", msg->add_conn.other.subnet);
-       DBG2(DBG_CFG, "  leftsourceip=%s", msg->add_conn.me.sourceip);
-       DBG2(DBG_CFG, "  rightsourceip=%s", msg->add_conn.other.sourceip);
-       DBG2(DBG_CFG, "  leftid=%s", msg->add_conn.me.id);
-       DBG2(DBG_CFG, "  rightid=%s", msg->add_conn.other.id);
-       DBG2(DBG_CFG, "  leftcert=%s", msg->add_conn.me.cert);
-       DBG2(DBG_CFG, "  rightcert=%s", msg->add_conn.other.cert);
-       DBG2(DBG_CFG, "  leftca=%s", msg->add_conn.me.ca);
-       DBG2(DBG_CFG, "  rightca=%s", msg->add_conn.other.ca);
-       DBG2(DBG_CFG, "  ike=%s", msg->add_conn.algorithms.ike);
-       DBG2(DBG_CFG, "  esp=%s", msg->add_conn.algorithms.esp);
-       
-       my_host = msg->add_conn.me.address?
-                         host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
-       if (my_host == NULL)
-       {
-               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
-               return;
-       }
-
-       other_host = msg->add_conn.other.address ?
-                       host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
-       if (other_host == NULL)
-       {
-               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
-               my_host->destroy(my_host);
-               return;
-       }
-       
-       interface = charon->kernel_interface->get_interface(charon->kernel_interface, 
-                                                                                                               other_host);
-       if (interface)
-       {
-               stroke_end_t tmp_end;
-               host_t *tmp_host;
-
-               DBG2(DBG_CFG, "left is other host, swapping ends\n");
-
-               tmp_host = my_host;
-               my_host = other_host;
-               other_host = tmp_host;
-
-               tmp_end = msg->add_conn.me;
-               msg->add_conn.me = msg->add_conn.other;
-               msg->add_conn.other = tmp_end;
-               free(interface);
-       }
-       if (!interface)
-       {
-               interface = charon->kernel_interface->get_interface(
-                                                                                       charon->kernel_interface, my_host);
-               if (!interface)
-               {
-                       DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
-                       goto destroy_hosts;
-               }
-               free(interface);
-       }
-
-       my_id = identification_create_from_string(msg->add_conn.me.id ?
-                                               msg->add_conn.me.id : msg->add_conn.me.address);
-       if (my_id == NULL)
-       {
-               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
-               goto destroy_hosts;
-       }
-
-       other_id = identification_create_from_string(msg->add_conn.other.id ?
-                                               msg->add_conn.other.id : msg->add_conn.other.address);
-       if (other_id == NULL)
-       {
-               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
-               my_id->destroy(my_id);
-               goto destroy_hosts;
-       }
-       
-       my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
-                                       msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
-       if (my_subnet == NULL)
-       {
-               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
-               goto destroy_ids;
-       }
-       
-       other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
-                                       msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
-       if (other_subnet == NULL)
-       {
-               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
-               my_subnet->destroy(my_subnet);
-               goto destroy_ids;
-       }
-       
-       if (msg->add_conn.me.virtual_ip)
-       {
-               my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
-       }
-       other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
-       
-       if (msg->add_conn.me.tohost)
-       {
-               my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol,
-                                       my_host->get_family(my_host) == AF_INET ?
-                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
-                                       msg->add_conn.me.port ? msg->add_conn.me.port : 0,
-                                       msg->add_conn.me.port ? msg->add_conn.me.port : 65535);
-       }
-       else
-       {
-               my_ts = traffic_selector_create_from_subnet(my_subnet,
-                               msg->add_conn.me.subnet ?  msg->add_conn.me.subnet_mask : 0,
-                               msg->add_conn.me.protocol, msg->add_conn.me.port);
-       }
-       my_subnet->destroy(my_subnet);
-       
-       if (msg->add_conn.other.tohost)
-       {
-               other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol,
-                                       other_host->get_family(other_host) == AF_INET ?
-                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
-                                       msg->add_conn.other.port ? msg->add_conn.other.port : 0,
-                                       msg->add_conn.other.port ? msg->add_conn.other.port : 65535);
-       }
-       else
-       {
-               other_ts = traffic_selector_create_from_subnet(other_subnet, 
-                               msg->add_conn.other.subnet ?  msg->add_conn.other.subnet_mask : 0,
-                               msg->add_conn.other.protocol, msg->add_conn.other.port);
-       }
-       other_subnet->destroy(other_subnet);
-
-       if (msg->add_conn.me.ca)
-       {
-               if (streq(msg->add_conn.me.ca, "%same"))
-               {
-                       my_ca_same = TRUE;
-               }
-               else
-               {
-                       my_ca = identification_create_from_string(msg->add_conn.me.ca);
-               }
-       }
-       if (msg->add_conn.other.ca)
-       {
-               if (streq(msg->add_conn.other.ca, "%same"))
-               {
-                       other_ca_same = TRUE;
-               }
-               else
-               {
-                       other_ca = identification_create_from_string(msg->add_conn.other.ca);
-               }
-       }
-       if (msg->add_conn.me.cert)
-       {
-               x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id);
-
-               if (my_ca == NULL && !my_ca_same && cert)
-               {
-                       identification_t *issuer = cert->get_issuer(cert);
-
-                       my_ca = issuer->clone(issuer);
-               }
-       }
-       if (msg->add_conn.other.cert)
-       {
-               x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id);
-
-               if (other_ca == NULL && !other_ca_same && cert)
-               {
-                       identification_t *issuer = cert->get_issuer(cert);
-
-                       other_ca = issuer->clone(issuer);
-               }
-       }
-       if (other_ca_same && my_ca)
-       {
-               other_ca = my_ca->clone(my_ca);
-       }
-       else if (my_ca_same && other_ca)
-       {
-               my_ca = other_ca->clone(other_ca);
-       }
-       if (my_ca == NULL)
-       {
-               my_ca = identification_create_from_string("%any");
-       }
-       if (other_ca == NULL)
-       {
-               other_ca = identification_create_from_string("%any");
-       }
-       DBG2(DBG_CFG, "  my ca:   '%D'", my_ca);
-       DBG2(DBG_CFG, "  other ca:'%D'", other_ca);
-       DBG2(DBG_CFG, "  updown: '%s'", msg->add_conn.me.updown);
-
-       /* have a look for an (almost) identical peer config to reuse */
-       iterator = this->backend->create_peer_cfg_iterator(this->backend);
-       while (iterator->iterate(iterator, (void**)&peer_cfg))
-       {
-               ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
-               if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg)) &&
-                       other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg)) &&
-                       my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) &&
-                       other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) &&
-                       peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) &&
-                       peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method &&
-                       peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type)
-               {
-                       DBG1(DBG_CFG, "reusing existing configuration '%s'",
-                                peer_cfg->get_name(peer_cfg));
-                       use_existing = TRUE;
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-
-       if (use_existing)
-       {
-               DESTROY_IF(my_vip);
-               DESTROY_IF(other_vip);
-               my_host->destroy(my_host);
-               my_id->destroy(my_id);
-               my_ca->destroy(my_ca);
-               other_host->destroy(other_host);
-               other_id->destroy(other_id);
-               other_ca->destroy(other_ca);
-       }
-       else
-       {
-               ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
-                                                                my_host, other_host);
-
-               if (msg->add_conn.algorithms.ike)
-               {
-                       char *proposal_string;
-                       char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
-
-                       if (*strict == '!')
-                               *strict = '\0';
-                       else
-                               strict = NULL;
-
-                       while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
-                       {
-                               proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
-                               if (proposal == NULL)
-                               {
-                                       DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
-                                       my_id->destroy(my_id);
-                                       other_id->destroy(other_id);
-                                       my_ts->destroy(my_ts);
-                                       other_ts->destroy(other_ts);
-                                       my_ca->destroy(my_ca);
-                                       other_ca->destroy(other_ca);
-                                       ike_cfg->destroy(ike_cfg);
-                                       return;
-                               }
-                               ike_cfg->add_proposal(ike_cfg, proposal);
-                       }
-                       if (!strict)
-                       {
-                               proposal = proposal_create_default(PROTO_IKE);
-                               ike_cfg->add_proposal(ike_cfg, proposal);
-                       }
-               }
-               else
-               {
-                       proposal = proposal_create_default(PROTO_IKE);
-                       ike_cfg->add_proposal(ike_cfg, proposal);
-               }
-               
-               
-               peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1,
-                                       ike_cfg, my_id, other_id, my_ca, other_ca, msg->add_conn.me.sendcert, 
-                                       msg->add_conn.auth_method, msg->add_conn.eap_type,
-                                       msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
-                                       msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
-                                       msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
-                                       msg->add_conn.rekey.reauth, msg->add_conn.dpd.delay,
-                                       msg->add_conn.dpd.action,my_vip, other_vip);
-       }
-       
-       child_cfg = child_cfg_create(
-                               msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
-                               msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
-                               msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
-                               msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
-                               msg->add_conn.mode);
-       
-       peer_cfg->add_child_cfg(peer_cfg, child_cfg);
-       
-       child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts);
-       child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts);
-       
-       if (msg->add_conn.algorithms.esp)
-       {
-               char *proposal_string;
-               char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
-
-               if (*strict == '!')
-                       *strict = '\0';
-               else
-                       strict = NULL;
-               
-               while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
-               {
-                       proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
-                       if (proposal == NULL)
-                       {
-                               DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
-                               peer_cfg->destroy(peer_cfg);
-                               return;
-                       }
-                       child_cfg->add_proposal(child_cfg, proposal);
-               }
-               if (!strict)
-               {
-                       proposal = proposal_create_default(PROTO_ESP);
-                       child_cfg->add_proposal(child_cfg, proposal);
-               }
-       }
-       else
-       {
-               proposal = proposal_create_default(PROTO_ESP);
-               child_cfg->add_proposal(child_cfg, proposal);
-       }
-       
-       if (!use_existing)
-       {
-               /* add config to backend */
-               this->backend->add_peer_cfg(this->backend, peer_cfg);
-               DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]",
-                        msg->add_conn.name, my_host, my_id, other_host, other_id);
-       }
-       return;
-
-       /* mopping up after parsing errors */
-
-destroy_ids:
-       my_id->destroy(my_id);
-       other_id->destroy(other_id);
-
-destroy_hosts:
-       my_host->destroy(my_host);
-       other_host->destroy(other_host);
-}
-
-/**
- * Delete a connection from the list
- */
-static void stroke_del_conn(private_stroke_interface_t *this,
-                                                       stroke_msg_t *msg, FILE *out)
-{
-       iterator_t *peer_iter, *child_iter;
-       peer_cfg_t *peer, *child;
-       
-       pop_string(msg, &(msg->del_conn.name));
-       DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
-       
-       peer_iter = this->backend->create_peer_cfg_iterator(this->backend);
-       while (peer_iter->iterate(peer_iter, (void**)&peer))
-       {
-               /* remove peer config with such a name */
-               if (streq(peer->get_name(peer), msg->del_conn.name))
-               {
-                       peer_iter->remove(peer_iter);
-                       peer->destroy(peer);
-                       continue;
-               }
-               /* remove any child with such a name */
-               child_iter = peer->create_child_cfg_iterator(peer);
-               while (child_iter->iterate(child_iter, (void**)&child))
-               {
-                       if (streq(child->get_name(child), msg->del_conn.name))
-                       {
-                               child_iter->remove(child_iter);
-                               child->destroy(child);
-                       }
-               }
-               child_iter->destroy(child_iter);
-       }
-       peer_iter->destroy(peer_iter);
-       
-       fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
-}
-
-/**
- * get the child_cfg with the same name as the peer cfg
- */
-static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
-{
-       child_cfg_t *current, *found = NULL;
-       iterator_t *iterator;
-       
-       iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
-       while (iterator->iterate(iterator, (void**)&current))
-       {
-               if (streq(current->get_name(current), name))
-               {
-                       found = current;
-                       found->get_ref(found);
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-       return found;
-}
-
-/**
- * logging to the stroke interface
- */
-static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level,
-                                          ike_sa_t *ike_sa, char *format, va_list args)
-{
-       if (level <= info->level)
-       {
-               vfprintf(info->out, format, args);
-               fprintf(info->out, "\n");
-               fflush(info->out);
-       }
-       return TRUE;
-}
-
-/**
- * initiate a connection by name
- */
-static void stroke_initiate(private_stroke_interface_t *this,
-                                                       stroke_msg_t *msg, FILE *out)
-{
-       peer_cfg_t *peer_cfg;
-       child_cfg_t *child_cfg;
-       stroke_log_info_t info;
-       
-       pop_string(msg, &(msg->initiate.name));
-       DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
-       
-       peer_cfg = this->backend->get_peer_cfg_by_name(this->backend,
-                                                                                                  msg->initiate.name);
-       if (peer_cfg == NULL)
-       {
-               fprintf(out, "no config named '%s'\n", msg->initiate.name);
-               return;
-       }
-       if (peer_cfg->get_ike_version(peer_cfg) != 2)
-       {
-               DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
-                        peer_cfg->get_ike_version(peer_cfg));
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
-       if (child_cfg == NULL)
-       {
-               fprintf(out, "no child config named '%s'\n", msg->initiate.name);
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       info.out = out;
-       info.level = msg->output_verbosity;
-       
-       charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                (controller_cb_t)stroke_log, &info);
-}
-
-/**
- * route/unroute a policy (install SPD entries)
- */
-static void stroke_route(private_stroke_interface_t *this,
-                                                stroke_msg_t *msg, FILE *out, bool route)
-{
-       route_job_t *job;
-       peer_cfg_t *peer_cfg;
-       child_cfg_t *child_cfg;
-       
-       pop_string(msg, &(msg->route.name));
-       DBG1(DBG_CFG, "received stroke: %s '%s'",
-                route ? "route" : "unroute", msg->route.name);
-       
-       peer_cfg = this->backend->get_peer_cfg_by_name(this->backend, msg->route.name);
-       if (peer_cfg == NULL)
-       {
-               fprintf(out, "no config named '%s'\n", msg->route.name);
-               return;
-       }
-       if (peer_cfg->get_ike_version(peer_cfg) != 2)
-       {
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
-       if (child_cfg == NULL)
-       {
-               fprintf(out, "no child config named '%s'\n", msg->route.name);
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       fprintf(out, "%s policy '%s'\n",
-                       route ? "routing" : "unrouting", msg->route.name);
-       job = route_job_create(peer_cfg, child_cfg, route);
-       charon->job_queue->add(charon->job_queue, (job_t*)job);
-}
-
-/**
- * terminate a connection by name
- */
-static void stroke_terminate(private_stroke_interface_t *this,
-                                                        stroke_msg_t *msg, FILE *out)
-{
-       char *string, *pos = NULL, *name = NULL;
-       u_int32_t id = 0;
-       bool child;
-       int len;
-       status_t status = SUCCESS;;
-       ike_sa_t *ike_sa;
-       
-       pop_string(msg, &(msg->terminate.name));
-       string = msg->terminate.name;
-       DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
-       
-       len = strlen(string);
-       if (len < 1)
-       {
-               DBG1(DBG_CFG, "error parsing string");
-               return;
-       }
-       switch (string[len-1])
-       {
-               case '}':
-                       child = TRUE;
-                       pos = strchr(string, '{');
-                       break;
-               case ']':
-                       child = FALSE;
-                       pos = strchr(string, '[');
-                       break;
-               default:
-                       name = string;
-                       child = FALSE;
-                       break;
-       }
-       
-       if (name)
-       {       /* must be a single name */
-               DBG1(DBG_CFG, "check out by single name '%s'", name);
-               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
-                                                                                                                 name, child);
-       }
-       else if (pos == string + len - 2)
-       {       /* must be name[] or name{} */
-               string[len-2] = '\0';
-               DBG1(DBG_CFG, "check out by name '%s'", string);
-               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
-                                                                                                                 string, child);
-       }
-       else
-       {       /* must be name[123] or name{23} */
-               string[len-1] = '\0';
-               id = atoi(pos + 1);
-               if (id == 0)
-               {
-                       DBG1(DBG_CFG, "error parsing string");
-                       return;
-               }
-               DBG1(DBG_CFG, "check out by id '%d'", id);
-               ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
-                                                                                                               id, child);
-       }
-       if (ike_sa == NULL)
-       {
-               DBG1(DBG_CFG, "no such IKE_SA found");
-               return;
-       }
-       
-       if (!child)
-       {
-               status = ike_sa->delete(ike_sa);
-       }
-       else
-       {
-               child_sa_t *child_sa;
-               iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
-               while (iterator->iterate(iterator, (void**)&child_sa))
-               {
-                       if ((id && id == child_sa->get_reqid(child_sa)) ||
-                               (string && streq(string, child_sa->get_name(child_sa))))
-                       {
-                               u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
-                               protocol_id_t proto = child_sa->get_protocol(child_sa);
-                               
-                               status = ike_sa->delete_child_sa(ike_sa, proto, spi);
-                               break;
-                       }
-               }
-               iterator->destroy(iterator);
-       }
-       if (status == DESTROY_ME)
-       {
-               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
-                                                                                                       ike_sa);
-               return;
-       }
-       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-}
-
-/**
- * Add a ca information record to the cainfo list
- */
-static void stroke_add_ca(private_stroke_interface_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       x509_t *cacert;
-       ca_info_t *ca_info;
-
-       pop_string(msg, &msg->add_ca.name);
-       pop_string(msg, &msg->add_ca.cacert);
-       pop_string(msg, &msg->add_ca.crluri);
-       pop_string(msg, &msg->add_ca.crluri2);
-       pop_string(msg, &msg->add_ca.ocspuri);
-       pop_string(msg, &msg->add_ca.ocspuri2);
-       
-       DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
-       
-       DBG2(DBG_CFG, "ca %s",        msg->add_ca.name);
-       DBG2(DBG_CFG, "  cacert=%s",  msg->add_ca.cacert);
-       DBG2(DBG_CFG, "  crluri=%s",  msg->add_ca.crluri);
-       DBG2(DBG_CFG, "  crluri2=%s", msg->add_ca.crluri2);
-       DBG2(DBG_CFG, "  ocspuri=%s", msg->add_ca.ocspuri);
-       DBG2(DBG_CFG, "  ocspuri2=%s", msg->add_ca.ocspuri2);
-
-       if (msg->add_ca.cacert == NULL)
-       {
-               DBG1(DBG_CFG, "missing cacert parameter\n");
-               return;
-       }
-
-       cacert = load_ca_certificate(msg->add_ca.cacert);
-
-       if (cacert == NULL)
-       {
-               return;
-       }
-       ca_info = ca_info_create(msg->add_ca.name, cacert);
-
-       if (msg->add_ca.crluri)
-       {
-               chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) };
-               
-               ca_info->add_crluri(ca_info, uri);
-       }
-       if (msg->add_ca.crluri2)
-       {
-               chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) };
-               
-               ca_info->add_crluri(ca_info, uri);
-       }
-       if (msg->add_ca.ocspuri)
-       {
-               chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) };
-               
-               ca_info->add_ocspuri(ca_info, uri);
-       }
-       if (msg->add_ca.ocspuri2)
-       {
-               chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) };
-               
-               ca_info->add_ocspuri(ca_info, uri);
-       }
-       charon->credentials->add_ca_info(charon->credentials, ca_info);
-       DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
-
-}
-
-/**
- * Delete a ca information record from the cainfo list
- */
-static void stroke_del_ca(private_stroke_interface_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       status_t status;
-       
-       pop_string(msg, &(msg->del_ca.name));
-       DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
-       
-       status = charon->credentials->release_ca_info(charon->credentials,
-                                                                                                 msg->del_ca.name);
-
-       if (status == SUCCESS)
-       {
-               fprintf(out, "deleted ca '%s'\n", msg->del_ca.name);
-       }
-       else
-       {
-               fprintf(out, "no ca named '%s'\n", msg->del_ca.name);
-       }
-}
-
-/**
- * log an IKE_SA to out
- */
-static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
-{
-       peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa);
-       ike_sa_id_t *id = ike_sa->get_id(ike_sa);
-       u_int32_t next, now = time(NULL);
-
-       fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
-                       ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                       ike_sa_state_names, ike_sa->get_state(ike_sa),
-                       ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
-                       ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
-       
-       if (all)
-       {
-               fprintf(out, "%12s[%d]: IKE SPIs: 0x%0llx_i%s 0x%0llx_r%s, ",
-                               ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                               id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
-                               id->get_responder_spi(id), id->is_initiator(id) ? "" : "");
-       
-               ike_sa->get_stats(ike_sa, &next);
-               if (next)
-               {
-                       fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ?
-                                       "reauthentication" : "rekeying", &now, &next);
-               }
-               else
-               {
-                       fprintf(out, "rekeying disabled\n");
-               }
-       }
-}
-
-/**
- * log an CHILD_SA to out
- */
-static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
-{
-       u_int32_t rekey, now = time(NULL);
-       u_int32_t use_in, use_out, use_fwd;
-       encryption_algorithm_t encr_alg;
-       integrity_algorithm_t int_alg;
-       size_t encr_len, int_len;
-       mode_t mode;
-       
-       child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
-                                               &int_alg, &int_len, &rekey, &use_in, &use_out,
-                                               &use_fwd);
-       
-       fprintf(out, "%12s{%d}:  %N, %N", 
-                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa_state_names, child_sa->get_state(child_sa),
-                       mode_names, mode);
-       
-       if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
-       {
-               fprintf(out, ", %N SPIs: 0x%0x_i 0x%0x_o",
-                               protocol_id_names, child_sa->get_protocol(child_sa),
-                               htonl(child_sa->get_spi(child_sa, TRUE)),
-                               htonl(child_sa->get_spi(child_sa, FALSE)));
-               
-               if (all)
-               {
-                       fprintf(out, "\n%12s{%d}:  ", child_sa->get_name(child_sa), 
-                                       child_sa->get_reqid(child_sa));
-                       
-                       
-                       if (child_sa->get_protocol(child_sa) == PROTO_ESP)
-                       {
-                               fprintf(out, "%N", encryption_algorithm_names, encr_alg);
-                               
-                               if (encr_len)
-                               {
-                                       fprintf(out, "-%d", encr_len);
-                               }
-                               fprintf(out, "/");
-                       }
-                       
-                       fprintf(out, "%N", integrity_algorithm_names, int_alg);
-                       if (int_len)
-                       {
-                               fprintf(out, "-%d", int_len);
-                       }
-                       fprintf(out, ", rekeying ");
-                       
-                       if (rekey)
-                       {
-                               fprintf(out, "in %V", &now, &rekey);
-                       }
-                       else
-                       {
-                               fprintf(out, "disabled");
-                       }
-                       
-                       fprintf(out, ", last use: ");
-                       use_in = max(use_in, use_fwd);
-                       if (use_in)
-                       {
-                               fprintf(out, "%ds_i ", now - use_in);
-                       }
-                       else
-                       {
-                               fprintf(out, "no_i ");
-                       }
-                       if (use_out)
-                       {
-                               fprintf(out, "%ds_o ", now - use_out);
-                       }
-                       else
-                       {
-                               fprintf(out, "no_o ");
-                       }
-               }
-       }
-       
-       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
-                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa->get_traffic_selectors(child_sa, TRUE),
-                       child_sa->get_traffic_selectors(child_sa, FALSE));
-}
-
-/**
- * show status of daemon
- */
-static void stroke_status(private_stroke_interface_t *this,
-                                                 stroke_msg_t *msg, FILE *out, bool all)
-{
-       iterator_t *iterator, *children;
-       linked_list_t *list;
-       host_t *host;
-       peer_cfg_t *peer_cfg;
-       ike_cfg_t *ike_cfg;
-       child_cfg_t *child_cfg;
-       ike_sa_t *ike_sa;
-       char *name = NULL;
-       
-       if (msg->status.name)
-       {
-               pop_string(msg, &(msg->status.name));
-               name = msg->status.name;
-       }
-       
-       if (all)
-       {
-               leak_detective_status(out);
-       
-               fprintf(out, "Performance:\n");
-               fprintf(out, "  worker threads: %d idle of %d,",
-                               charon->thread_pool->get_idle_threads(charon->thread_pool),
-                               charon->thread_pool->get_pool_size(charon->thread_pool));
-               fprintf(out, " job queue load: %d,",
-                               charon->job_queue->get_count(charon->job_queue));
-               fprintf(out, " scheduled events: %d\n",
-                               charon->event_queue->get_count(charon->event_queue));
-               list = charon->kernel_interface->create_address_list(charon->kernel_interface);
-
-               fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
-               while (list->remove_first(list, (void**)&host) == SUCCESS)
-               {
-                       fprintf(out, "  %H\n", host);
-                       host->destroy(host);
-               }
-               list->destroy(list);
-       
-               fprintf(out, "Connections:\n");
-               iterator = this->backend->create_peer_cfg_iterator(this->backend);
-               while (iterator->iterate(iterator, (void**)&peer_cfg))
-               {
-                       if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
-                               (name && !streq(name, peer_cfg->get_name(peer_cfg))))
-                       {
-                               continue;
-                       }
-                       
-                       ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
-                       fprintf(out, "%12s:  %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
-                                       ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
-                                       ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
-                       children = peer_cfg->create_child_cfg_iterator(peer_cfg);
-                       while (children->iterate(children, (void**)&child_cfg))
-                       {
-                               linked_list_t *my_ts, *other_ts;
-                               my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
-                               other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
-                               fprintf(out, "%12s:    %#R=== %#R\n", child_cfg->get_name(child_cfg),
-                                               my_ts, other_ts);
-                               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
-                               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
-                       }
-                       children->destroy(children);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
-       if (all && iterator->get_count(iterator) > 0)
-       {
-               fprintf(out, "Security Associations:\n");
-       }
-       while (iterator->iterate(iterator, (void**)&ike_sa))
-       {
-               bool ike_printed = FALSE;
-               child_sa_t *child_sa;
-               iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
-
-               if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
-               {
-                       log_ike_sa(out, ike_sa, all);
-                       ike_printed = TRUE;
-               }
-
-               while (children->iterate(children, (void**)&child_sa))
-               {
-                       if (name == NULL || streq(name, child_sa->get_name(child_sa)))
-                       {
-                               if (!ike_printed)
-                               {
-                                       log_ike_sa(out, ike_sa, all);
-                                       ike_printed = TRUE;
-                               }
-                               log_child_sa(out, child_sa, all);
-                       }       
-               }
-               children->destroy(children);
-       }
-       iterator->destroy(iterator);
-}
-
-/**
- * list all authority certificates matching a specified flag 
- */
-static void list_auth_certificates(private_stroke_interface_t *this,  u_int flag,
-                                                                  const char *label, bool utc, FILE *out)
-{
-       bool first = TRUE;
-       x509_t *cert;
-       
-       iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials);
-
-       while (iterator->iterate(iterator, (void**)&cert))
-       {
-               if (cert->has_authority_flag(cert, flag))
-               {
-                       if (first)
-                       {
-                               fprintf(out, "\n");
-                               fprintf(out, "List of X.509 %s Certificates:\n", label);
-                               fprintf(out, "\n");
-                               first = FALSE;
-                       }
-                       cert->list(cert, out, utc);
-                       fprintf(out, "\n");
-               }
-       }
-       iterator->destroy(iterator);
-}
-
-/**
- * list various information
- */
-static void stroke_list(private_stroke_interface_t *this, 
-                                               stroke_msg_t *msg, FILE *out)
-{
-       iterator_t *iterator;
-       
-       if (msg->list.flags & LIST_CERTS)
-       {
-               x509_t *cert;
-               
-               iterator = charon->credentials->create_cert_iterator(charon->credentials);
-               if (iterator->get_count(iterator))
-               {
-                       fprintf(out, "\n");
-                       fprintf(out, "List of X.509 End Entity Certificates:\n");
-                       fprintf(out, "\n");
-               }
-               while (iterator->iterate(iterator, (void**)&cert))
-               {
-                       cert->list(cert, out, msg->list.utc);
-                       if (charon->credentials->has_rsa_private_key(
-                                       charon->credentials, cert->get_public_key(cert)))
-                       {
-                               fprintf(out, ", has private key");
-                       }
-                       fprintf(out, "\n");
-                       
-               }
-               iterator->destroy(iterator);
-       }
-       if (msg->list.flags & LIST_CACERTS)
-       {
-               list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_OCSPCERTS)
-       {
-               list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_AACERTS)
-       {
-               list_auth_certificates(this, AUTH_AA, "AA", msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_CAINFOS)
-       {
-               ca_info_t *ca_info;
-
-               iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
-               if (iterator->get_count(iterator))
-               {
-                       fprintf(out, "\n");
-                       fprintf(out, "List of X.509 CA Information Records:\n");
-                       fprintf(out, "\n");
-               }
-               while (iterator->iterate(iterator, (void**)&ca_info))
-               {
-                       ca_info->list(ca_info, out, msg->list.utc);
-               }
-               iterator->destroy(iterator);
-       }
-       if (msg->list.flags & LIST_CRLS)
-       {
-        ca_info_t *ca_info;
-        bool first = TRUE;
-        
-        iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
-        while (iterator->iterate(iterator, (void **)&ca_info))
-        {
-            if (ca_info->has_crl(ca_info))
-            {
-                if (first)
-                {
-                    fprintf(out, "\n");
-                    fprintf(out, "List of X.509 CRLs:\n");
-                    fprintf(out, "\n");
-                    first = FALSE;
-                }
-                ca_info->list_crl(ca_info, out, msg->list.utc);
-            }
-        }
-        iterator->destroy(iterator);
-       }
-       if (msg->list.flags & LIST_OCSP)
-       {
-               ca_info_t *ca_info;
-               bool first = TRUE;
-
-        iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
-        while (iterator->iterate(iterator, (void **)&ca_info))
-        {
-            if (ca_info->has_certinfos(ca_info))
-            {
-                if (first)
-                {
-                    fprintf(out, "\n");
-                    fprintf(out, "List of OCSP responses:\n");
-                    first = FALSE;
-                }
-                fprintf(out, "\n");
-                ca_info->list_certinfos(ca_info, out, msg->list.utc);
-            }
-        }
-        iterator->destroy(iterator);
-       }
-}
-
-/**
- * reread various information
- */
-static void stroke_reread(private_stroke_interface_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       if (msg->reread.flags & REREAD_CACERTS)
-       {
-               charon->credentials->load_ca_certificates(charon->credentials);
-       }
-       if (msg->reread.flags & REREAD_OCSPCERTS)
-       {
-               charon->credentials->load_ocsp_certificates(charon->credentials);
-       }
-       if (msg->reread.flags & REREAD_CRLS)
-       {
-               charon->credentials->load_crls(charon->credentials);
-       }
-}
-
-/**
- * purge various information
- */
-static void stroke_purge(private_stroke_interface_t *this,
-                                                stroke_msg_t *msg, FILE *out)
-{
-       if (msg->purge.flags & PURGE_OCSP)
-       {
-               iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
-               ca_info_t *ca_info;
-
-               while (iterator->iterate(iterator, (void**)&ca_info))
-               {
-                       ca_info->purge_ocsp(ca_info);
-               }
-               iterator->destroy(iterator);
-       }
-}
-
-signal_t get_signal_from_logtype(char *type)
-{
-       if      (strcasecmp(type, "any") == 0) return SIG_ANY;
-       else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
-       else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
-       else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
-       else if (strcasecmp(type, "job") == 0) return DBG_JOB;
-       else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
-       else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
-       else if (strcasecmp(type, "net") == 0) return DBG_NET;
-       else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
-       else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
-       else return -1;
-}
-
-/**
- * set the verbosity debug output
- */
-static void stroke_loglevel(private_stroke_interface_t *this,
-                                                       stroke_msg_t *msg, FILE *out)
-{
-       signal_t signal;
-       
-       pop_string(msg, &(msg->loglevel.type));
-       DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
-                msg->loglevel.level, msg->loglevel.type);
-       
-       signal = get_signal_from_logtype(msg->loglevel.type);
-       if (signal < 0)
-       {
-               fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
-               return;
-       }
-       
-       charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
-       charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
-}
-
-/**
- * process a stroke request from the socket pointed by "fd"
- */
-static void stroke_process(private_stroke_interface_t *this, int strokefd)
-{
-       stroke_msg_t *msg;
-       u_int16_t msg_length;
-       ssize_t bytes_read;
-       FILE *out;
-       
-       /* peek the length */
-       bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
-       if (bytes_read != sizeof(msg_length))
-       {
-               DBG1(DBG_CFG, "reading length of stroke message failed");
-               close(strokefd);
-               return;
-       }
-       
-       /* read message */
-       msg = malloc(msg_length);
-       bytes_read = recv(strokefd, msg, msg_length, 0);
-       if (bytes_read != msg_length)
-       {
-               DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
-               close(strokefd);
-               return;
-       }
-       
-       out = fdopen(dup(strokefd), "w");
-       if (out == NULL)
-       {
-               DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
-               close(strokefd);
-               free(msg);
-               return;
-       }
-       
-       DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
-       
-       switch (msg->type)
-       {
-               case STR_INITIATE:
-                       stroke_initiate(this, msg, out);
-                       break;
-               case STR_ROUTE:
-                       stroke_route(this, msg, out, TRUE);
-                       break;
-               case STR_UNROUTE:
-                       stroke_route(this, msg, out, FALSE);
-                       break;
-               case STR_TERMINATE:
-                       stroke_terminate(this, msg, out);
-                       break;
-               case STR_STATUS:
-                       stroke_status(this, msg, out, FALSE);
-                       break;
-               case STR_STATUS_ALL:
-                       stroke_status(this, msg, out, TRUE);
-                       break;
-               case STR_ADD_CONN:
-                       stroke_add_conn(this, msg, out);
-                       break;
-               case STR_DEL_CONN:
-                       stroke_del_conn(this, msg, out);
-                       break;
-               case STR_ADD_CA:
-                       stroke_add_ca(this, msg, out);
-                       break;
-               case STR_DEL_CA:
-                       stroke_del_ca(this, msg, out);
-                       break;
-               case STR_LOGLEVEL:
-                       stroke_loglevel(this, msg, out);
-                       break;
-               case STR_LIST:
-                       stroke_list(this, msg, out);
-                       break;
-               case STR_REREAD:
-                       stroke_reread(this, msg, out);
-                       break;
-               case STR_PURGE:
-                       stroke_purge(this, msg, out);
-                       break;
-               default:
-                       DBG1(DBG_CFG, "received unknown stroke");
-       }
-       fclose(out);
-       close(strokefd);
-       free(msg);
-}
-
-/**
- * Implementation of private_stroke_interface_t.stroke_receive.
- */
-static void stroke_receive(private_stroke_interface_t *this)
-{
-       struct sockaddr_un strokeaddr;
-       int strokeaddrlen = sizeof(strokeaddr);
-       int oldstate;
-       int strokefd;
-       
-       /* ignore sigpipe. writing over the pipe back to the console
-        * only fails if SIGPIPE is ignored. */
-       signal(SIGPIPE, SIG_IGN);
-       
-       /* disable cancellation by default */
-       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-       
-       while (TRUE)
-       {
-               /* wait for connections, but allow thread to terminate */
-               pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-               strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
-               pthread_setcancelstate(oldstate, NULL);
-               
-               if (strokefd < 0)
-               {
-                       DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
-                       continue;
-               }
-               stroke_process(this, strokefd);
-       }
-}
-
-/**
- * Implementation of stroke_t.destroy.
- */
-static void destroy(private_stroke_interface_t *this)
-{
-       int i;
-       
-       for (i = 0; i < STROKE_THREADS; i++)
-       {
-               pthread_cancel(this->threads[i]);
-               pthread_join(this->threads[i], NULL);
-       }
-
-       close(this->socket);
-       unlink(socket_addr.sun_path);
-       free(this);
-}
-
-/*
- * Described in header-file
- */
-stroke_t *stroke_create(local_backend_t *backend)
-{
-       private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t);
-       mode_t old;
-       int i;
-
-       /* public functions */
-       this->public.destroy = (void (*)(stroke_t*))destroy;
-       
-       this->backend = backend;
-       
-       /* set up unix socket */
-       this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (this->socket == -1)
-       {
-               DBG1(DBG_CFG, "could not create whack socket");
-               free(this);
-               return NULL;
-       }
-       
-       old = umask(~S_IRWXU);
-       if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
-       {
-               DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
-               close(this->socket);
-               free(this);
-               return NULL;
-       }
-       umask(old);
-       
-       if (listen(this->socket, 0) < 0)
-       {
-               DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
-               close(this->socket);
-               unlink(socket_addr.sun_path);
-               free(this);
-               return NULL;
-       }
-       
-       /* start threads reading from the socket */
-       for (i = 0; i < STROKE_THREADS; i++)
-       {
-               if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0)
-               {
-                       charon->kill(charon, "unable to create stroke thread");
-               }
-       }
-       
-       return (&this->public);
-}
diff --git a/src/charon/control/stroke_interface.h b/src/charon/control/stroke_interface.h
deleted file mode 100644 (file)
index 7fab28f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * @file stroke.h
- *
- * @brief Interface of stroke_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * 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.
- */
-
-#ifndef STROKE_INTERFACE_H_
-#define STROKE_INTERFACE_H_
-
-typedef struct stroke_t stroke_t;
-
-#include <config/backends/local_backend.h>
-
-/**
- * @brief Stroke is a configuration and control interface which
- * allows other processes to modify charons behavior.
- * 
- * stroke_t allows config manipulation (as whack in pluto). Configurations
- * are stored in a special backend, the in-memory local_backend_t.
- * Messages of type stroke_msg_t's are sent over a unix socket
- * (/var/run/charon.ctl).
- * 
- * @b Constructors:
- * - stroke_create()
- * 
- * @ingroup control
- */
-struct stroke_t {
-       
-       /**
-        * @brief Destroy a stroke_t instance.
-        * 
-        * @param this          stroke_t objec to destroy
-        */
-       void (*destroy) (stroke_t *this);
-};
-
-
-/**
- * @brief Create the stroke interface and listen on the socket.
- * 
- * @param backend      backend to store received configurations
- * @return                     stroke_t object
- * 
- * @ingroup control
- */
-stroke_t *stroke_create(local_backend_t *backend);
-
-#endif /* STROKE_INTERFACE_H_ */
index d2b8d34..ac16eb2 100644 (file)
@@ -164,8 +164,7 @@ static void destroy(private_daemon_t *this)
        /* we don't want to receive anything anymore... */
        DESTROY_IF(this->public.receiver);
        /* ignore all incoming user requests */
-       DESTROY_IF(this->public.stroke);
-       DESTROY_IF(this->public.controller);
+       DESTROY_IF(this->public.interfaces);
        /* stop scheduing jobs */
        DESTROY_IF(this->public.scheduler);
        /* stop processing jobs */
@@ -178,8 +177,7 @@ static void destroy(private_daemon_t *this)
        DESTROY_IF(this->public.job_queue);
        DESTROY_IF(this->public.event_queue);
        DESTROY_IF(this->public.credentials);
-       DESTROY_IF(this->public.cfg_store);
-       DESTROY_IF(this->public.local_backend);
+       DESTROY_IF(this->public.backends);
        sched_yield();
        /* we hope the sender could send the outstanding deletes, but 
         * we shut down here at any cost */
@@ -262,10 +260,7 @@ static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
        this->public.job_queue = job_queue_create();
        this->public.event_queue = event_queue_create();
        this->public.credentials = (credential_store_t*)local_credential_store_create();
-       this->public.cfg_store = cfg_store_create();
-       this->public.local_backend = local_backend_create();
-       this->public.cfg_store->register_backend(this->public.cfg_store,
-                                                                                       &this->public.local_backend->backend);
+       this->public.backends = backend_manager_create();
 
        /* initialize fetcher_t class */
        fetcher_initialize();
@@ -280,8 +275,7 @@ static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
        credentials->load_secrets(credentials);
        
        /* start building threads, we are multi-threaded NOW */
-       this->public.controller = controller_create();
-       this->public.stroke = stroke_create(this->public.local_backend);
+       this->public.interfaces = interface_manager_create();
        this->public.sender = sender_create();
        this->public.receiver = receiver_create();
        this->public.scheduler = scheduler_create();
@@ -336,15 +330,13 @@ private_daemon_t *daemon_create(void)
        this->public.job_queue = NULL;
        this->public.event_queue = NULL;
        this->public.credentials = NULL;
-       this->public.cfg_store = NULL;
-       this->public.local_backend = NULL;
+       this->public.backends = NULL;
        this->public.sender= NULL;
        this->public.receiver = NULL;
        this->public.scheduler = NULL;
        this->public.kernel_interface = NULL;
        this->public.thread_pool = NULL;
-       this->public.controller = NULL;
-       this->public.stroke = NULL;
+       this->public.interfaces = NULL;
        this->public.bus = NULL;
        this->public.outlog = NULL;
        this->public.syslog = NULL;
index 3a5a79d..c442094 100644 (file)
@@ -37,14 +37,12 @@ typedef struct daemon_t daemon_t;
 #include <processing/job_queue.h>
 #include <processing/event_queue.h>
 #include <kernel/kernel_interface.h>
-#include <control/controller.h>
-#include <control/stroke_interface.h>
+#include <control/interface_manager.h>
 #include <bus/bus.h>
 #include <bus/listeners/file_logger.h>
 #include <bus/listeners/sys_logger.h>
 #include <sa/ike_sa_manager.h>
-#include <config/cfg_store.h>
-#include <config/backends/local_backend.h>
+#include <config/backend_manager.h>
 
 /**
  * @defgroup charon charon
@@ -132,12 +130,20 @@ typedef struct daemon_t daemon_t;
 /**
  * @defgroup control control
  *
- * Classes which control the daemon using IPC mechanisms.
+ * Handling of loadable control interface modules.
  *
  * @ingroup charon
  */
 
 /**
+ * @defgroup interfaces interfaces
+ *
+ * Classes which control the daemon using IPC mechanisms.
+ *
+ * @ingroup control
+ */
+
+/**
  * @defgroup encoding encoding
  *
  * Classes used to encode and decode IKEv2 messages.
@@ -353,14 +359,9 @@ struct daemon_t {
        ike_sa_manager_t *ike_sa_manager;
        
        /**
-        * A connection_store_t instance.
+        * Manager for the different configuration backends.
         */
-       cfg_store_t *cfg_store;
-       
-       /**
-        * A backend for cfg_store using in-memory lists
-        */
-       local_backend_t *local_backend;
+       backend_manager_t *backends;
        
        /**
         * A credential_store_t instance.
@@ -413,14 +414,9 @@ struct daemon_t {
        kernel_interface_t *kernel_interface;
        
        /**
-        * control the daemon
-        */
-       controller_t *controller;;
-       
-       /**
-        * IPC interface, as whack in pluto
+        * Interfaces for IPC
         */
-       stroke_t *stroke;
+       interface_manager_t *interfaces;
        
        /**
         * @brief Shut down the daemon.
index b1d76ac..e9c56dc 100644 (file)
@@ -746,8 +746,8 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
                if (this->ike_cfg == NULL)
                {
                        job_t *job;
-                       this->ike_cfg = charon->cfg_store->get_ike_cfg(charon->cfg_store,
-                                                                                                                  me, other);
+                       this->ike_cfg = charon->backends->get_ike_cfg(charon->backends,
+                                                                                                                 me, other);
                        if (this->ike_cfg == NULL)
                        {
                                /* no config found for these hosts, destroy */
index 9e2f6b0..c6fc988 100644 (file)
@@ -511,7 +511,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
                return NEED_MORE;
        }
        
-       config = charon->cfg_store->get_peer_cfg(charon->cfg_store,
+       config = charon->backends->get_peer_cfg(charon->backends,
                                                                        this->ike_sa->get_my_id(this->ike_sa),
                                                                        this->ike_sa->get_other_id(this->ike_sa));
        if (config)