From a84fb01b965831ee0b45f70aa44cb333c7d98473 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 27 Apr 2007 14:25:08 +0000 Subject: restructuring of configuration backends added propotypes of new control interfaces (xml & dbus) introduced loadable: configuration backends control interfaces using pluggable modules as in EAP --- configure.in | 50 +- src/charon/Makefile.am | 71 +- src/charon/config/backend_manager.c | 244 ++++ src/charon/config/backend_manager.h | 118 ++ src/charon/config/backends/backend.h | 37 +- src/charon/config/backends/local_backend.c | 78 +- src/charon/config/backends/local_backend.h | 49 +- src/charon/config/backends/writeable_backend.h | 64 + src/charon/config/cfg_store.c | 146 -- src/charon/config/cfg_store.h | 119 -- src/charon/control/controller.c | 134 -- src/charon/control/controller.h | 93 -- src/charon/control/interface_manager.c | 239 ++++ src/charon/control/interface_manager.h | 94 ++ src/charon/control/interfaces/dbus_interface.c | 324 +++++ src/charon/control/interfaces/dbus_interface.h | 57 + src/charon/control/interfaces/interface.h | 55 + src/charon/control/interfaces/stroke_interface.c | 1622 ++++++++++++++++++++++ src/charon/control/interfaces/stroke_interface.h | 63 + src/charon/control/interfaces/xml_interface.c | 63 + src/charon/control/interfaces/xml_interface.h | 57 + src/charon/control/stroke_interface.c | 1589 --------------------- src/charon/control/stroke_interface.h | 65 - src/charon/daemon.c | 20 +- src/charon/daemon.h | 34 +- src/charon/sa/ike_sa.c | 4 +- src/charon/sa/tasks/ike_auth.c | 2 +- 27 files changed, 3183 insertions(+), 2308 deletions(-) create mode 100644 src/charon/config/backend_manager.c create mode 100644 src/charon/config/backend_manager.h create mode 100644 src/charon/config/backends/writeable_backend.h delete mode 100644 src/charon/config/cfg_store.c delete mode 100644 src/charon/config/cfg_store.h delete mode 100644 src/charon/control/controller.c delete mode 100644 src/charon/control/controller.h create mode 100644 src/charon/control/interface_manager.c create mode 100644 src/charon/control/interface_manager.h create mode 100644 src/charon/control/interfaces/dbus_interface.c create mode 100644 src/charon/control/interfaces/dbus_interface.h create mode 100644 src/charon/control/interfaces/interface.h create mode 100755 src/charon/control/interfaces/stroke_interface.c create mode 100644 src/charon/control/interfaces/stroke_interface.h create mode 100644 src/charon/control/interfaces/xml_interface.c create mode 100644 src/charon/control/interfaces/xml_interface.h delete mode 100755 src/charon/control/stroke_interface.c delete mode 100644 src/charon/control/stroke_interface.h diff --git a/configure.in b/configure.in index 3748756e5..8b54b42c9 100644 --- a/configure.in +++ b/configure.in @@ -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( @@ -113,6 +127,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).]), @@ -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 diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 2dad4915c..48696b23c 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -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 index 000000000..186273b6e --- /dev/null +++ b/src/charon/config/backend_manager.c @@ -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 . + * + * 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 +#include +#include +#include + +#include +#include +#include + + +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 index 000000000..07cd9c541 --- /dev/null +++ b/src/charon/config/backend_manager.h @@ -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 . + * + * 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 +#include +#include +#include +#include +#include + + +/** + * @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_*/ + diff --git a/src/charon/config/backends/backend.h b/src/charon/config/backends/backend.h index 52df0a287..5f9543028 100644 --- a/src/charon/config/backends/backend.h +++ b/src/charon/config/backends/backend.h @@ -30,7 +30,6 @@ typedef struct backend_t backend_t; #include #include - /** * @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_ */ + diff --git a/src/charon/config/backends/local_backend.c b/src/charon/config/backends/local_backend.c index be6fc923b..b1e68ee6f 100644 --- a/src/charon/config/backends/local_backend.c +++ b/src/charon/config/backends/local_backend.c @@ -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**)¤t)) - { - /* 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); } diff --git a/src/charon/config/backends/local_backend.h b/src/charon/config/backends/local_backend.h index 4caf4a896..f3538eab2 100644 --- a/src/charon/config/backends/local_backend.h +++ b/src/charon/config/backends/local_backend.h @@ -26,13 +26,13 @@ typedef struct local_backend_t local_backend_t; #include -#include +#include /** * @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 index 000000000..4771a0cff --- /dev/null +++ b/src/charon/config/backends/writeable_backend.h @@ -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 . + * + * 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 +#include + +/** + * @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 index ef945da90..000000000 --- a/src/charon/config/cfg_store.c +++ /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 . - * - * 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 - -#include "cfg_store.h" - -#include -#include - - -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**)¤t)) - { - 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 index be36cd399..000000000 --- a/src/charon/config/cfg_store.h +++ /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 . - * - * 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 -#include -#include -#include -#include -#include - - -/** - * @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 index 8e0268e6a..000000000 --- a/src/charon/control/controller.c +++ /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 . - * - * 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 -#include -#include -#include - - -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 index 7dc4b6704..000000000 --- a/src/charon/control/controller.h +++ /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 . - * - * 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 - -/** - * 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 index 000000000..5f4a7e810 --- /dev/null +++ b/src/charon/control/interface_manager.c @@ -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 . + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include + + +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 index 000000000..57121c833 --- /dev/null +++ b/src/charon/control/interface_manager.h @@ -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 . + * + * 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 + +/** + * 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 index 000000000..178f74ff5 --- /dev/null +++ b/src/charon/control/interfaces/dbus_interface.c @@ -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 . + * + * 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 +#include +#include +#include + +#include "dbus_interface.h" + +#include +#include + + +#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 index 000000000..0ce57bbbc --- /dev/null +++ b/src/charon/control/interfaces/dbus_interface.h @@ -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 . + * + * 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 + +/** + * @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 index 000000000..1949556cc --- /dev/null +++ b/src/charon/control/interfaces/interface.h @@ -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 . + * + * 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 index 000000000..d33cae8ed --- /dev/null +++ b/src/charon/control/interfaces/stroke_interface.c @@ -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 . + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stroke_interface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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**)¤t)) + { + 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**)¤t)) + { + /* 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 index 000000000..f189048bd --- /dev/null +++ b/src/charon/control/interfaces/stroke_interface.h @@ -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 . + * + * 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 + +/** + * @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 index 000000000..ad92e8050 --- /dev/null +++ b/src/charon/control/interfaces/xml_interface.c @@ -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 . + * + * 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 + +#include "xml_interface.h" + +#include +#include + + +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 index 000000000..6d88c3842 --- /dev/null +++ b/src/charon/control/interfaces/xml_interface.h @@ -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 . + * + * 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 + +/** + * @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 index 9743f5778..000000000 --- a/src/charon/control/stroke_interface.c +++ /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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stroke_interface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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**)¤t)) - { - 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 index 7fab28fec..000000000 --- a/src/charon/control/stroke_interface.h +++ /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 . - * - * 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 - -/** - * @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_ */ diff --git a/src/charon/daemon.c b/src/charon/daemon.c index d2b8d346e..ac16eb2c2 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -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; diff --git a/src/charon/daemon.h b/src/charon/daemon.h index 3a5a79d9b..c442094ff 100644 --- a/src/charon/daemon.h +++ b/src/charon/daemon.h @@ -37,14 +37,12 @@ typedef struct daemon_t daemon_t; #include #include #include -#include -#include +#include #include #include #include #include -#include -#include +#include /** * @defgroup charon charon @@ -132,11 +130,19 @@ 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 * @@ -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. diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index b1d76ac84..e9c56dcbc 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -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 */ diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 9e2f6b085..c6fc98839 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -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) -- cgit v1.2.3