Merge branch 'systemd'
authorMartin Willi <martin@revosec.ch>
Wed, 24 Sep 2014 09:17:29 +0000 (11:17 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 24 Sep 2014 09:17:29 +0000 (11:17 +0200)
Introduces a systemd specific charon-systemd IKE daemon based on libcharon.
Uses systemd APIs for startup control and journal logging and a new systemd
service unit using swanctl as configuration backend.

37 files changed:
conf/Makefile.am
conf/options/charon-systemd.opt [new file with mode: 0644]
configure.ac
init/Makefile.am
init/systemd-swanctl/.gitignore [new file with mode: 0644]
init/systemd-swanctl/Makefile.am [new file with mode: 0644]
init/systemd-swanctl/strongswan-swanctl.service.in [new file with mode: 0644]
init/systemd/.gitignore [new file with mode: 0644]
init/systemd/strongswan.service.in
man/Makefile.am
scripts/test.sh
src/Makefile.am
src/charon-nm/nm/nm_backend.c
src/charon-systemd/.gitignore [new file with mode: 0644]
src/charon-systemd/Makefile.am [new file with mode: 0644]
src/charon-systemd/charon-systemd.c [new file with mode: 0644]
src/charon-tkm/src/charon-tkm.c
src/charon-tkm/src/tkm/tkm_diffie_hellman.c
src/charon-tkm/tests/tests.c
src/frontends/android/jni/libandroidbridge/charonservice.c
src/libcharon/daemon.c
src/libcharon/plugins/vici/vici_control.c
src/libstrongswan/plugins/plugin_loader.c
src/libstrongswan/plugins/plugin_loader.h
src/pt-tls-client/pt-tls-client.c
src/swanctl/Makefile.am
src/swanctl/command.c
src/swanctl/command.h
src/swanctl/commands/load_all.c [new file with mode: 0644]
src/swanctl/commands/load_conns.c
src/swanctl/commands/load_conns.h [new file with mode: 0644]
src/swanctl/commands/load_creds.c
src/swanctl/commands/load_creds.h [new file with mode: 0644]
src/swanctl/commands/load_pools.c
src/swanctl/commands/load_pools.h [new file with mode: 0644]
src/swanctl/commands/reload_settings.c [new file with mode: 0644]
src/swanctl/swanctl.8.in

index 373be16..0861370 100644 (file)
@@ -12,6 +12,7 @@ options = \
        options/attest.opt \
        options/charon.opt \
        options/charon-logging.opt \
+       options/charon-systemd.opt \
        options/imcv.opt \
        options/manager.opt \
        options/medsrv.opt \
diff --git a/conf/options/charon-systemd.opt b/conf/options/charon-systemd.opt
new file mode 100644 (file)
index 0000000..3482f44
--- /dev/null
@@ -0,0 +1,13 @@
+charon-systemd.journal {}
+       Section to configure native systemd journal logger, very similar to the
+       syslog logger as described in LOGGER CONFIGURATION in
+       **strongswan.conf**(5).
+
+charon-systemd.journal.default = 1
+       Default loglevel.
+
+       Specifies the default loglevel to be used for subsystems for which no
+       specific loglevel is defined.
+
+charon-systemd.journal.<subsystem> = <default>
+       Loglevel for a specific subsystem.
index b3a7366..3961270 100644 (file)
@@ -73,7 +73,6 @@ if test -n "$PKG_CONFIG"; then
        systemdsystemunitdir_default=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
 fi
 ARG_WITH_SET([systemdsystemunitdir], [$systemdsystemunitdir_default], [directory for systemd service files])
-AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno])
 AC_SUBST(systemdsystemunitdir)
 
 AC_ARG_WITH(
@@ -273,6 +272,7 @@ ARG_DISBL_SET([pki],            [disable pki certificate utility.])
 ARG_DISBL_SET([scepclient],     [disable SCEP client tool.])
 ARG_DISBL_SET([scripts],        [disable additional utilities (found in directory scripts).])
 ARG_ENABL_SET([svc],            [enable charon Windows service.])
+ARG_ENABL_SET([systemd],        [enable systemd specific IKE daemon charon-systemd.])
 ARG_ENABL_SET([swanctl],        [enable swanctl configuration and control tool.])
 ARG_ENABL_SET([tkm],            [enable Trusted Key Manager support.])
 # optional features
@@ -869,6 +869,23 @@ if test x$xml = xtrue; then
        AC_SUBST(xml_LIBS)
 fi
 
+if test x$systemd = xtrue; then
+       AC_MSG_CHECKING([for systemd system unit directory])
+       if test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno; then
+               AC_MSG_RESULT([$systemdsystemunitdir])
+       else
+               AC_MSG_ERROR([not found (try --with-systemdsystemunitdir)])
+       fi
+
+       PKG_CHECK_MODULES(systemd_daemon, [libsystemd-daemon])
+       AC_SUBST(systemd_daemon_CFLAGS)
+       AC_SUBST(systemd_daemon_LIBS)
+
+       PKG_CHECK_MODULES(systemd_journal, [libsystemd-journal])
+       AC_SUBST(systemd_journal_CFLAGS)
+       AC_SUBST(systemd_journal_LIBS)
+fi
+
 if test x$tss = xtrousers; then
        AC_CHECK_LIB([tspi],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([TrouSerS library libtspi not found])],[])
        AC_CHECK_HEADER([trousers/tss.h],,[AC_MSG_ERROR([TrouSerS header trousers/tss.h not found!])])
@@ -1467,9 +1484,9 @@ AM_CONDITIONAL(USE_PKI, test x$pki = xtrue)
 AM_CONDITIONAL(USE_SCEPCLIENT, test x$scepclient = xtrue)
 AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
 AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
-AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue)
-AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue)
-AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
+AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
+AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
 AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
 AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
@@ -1494,6 +1511,8 @@ AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
 AM_CONDITIONAL(USE_AIKGEN, test x$aikgen = xtrue)
 AM_CONDITIONAL(USE_SWANCTL, test x$swanctl = xtrue)
 AM_CONDITIONAL(USE_SVC, test x$svc = xtrue)
+AM_CONDITIONAL(USE_SYSTEMD, test x$systemd = xtrue)
+AM_CONDITIONAL(USE_LEGACY_SYSTEMD, test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno)
 
 # ========================
 #  set global definitions
@@ -1547,6 +1566,7 @@ AC_CONFIG_FILES([
        man/Makefile
        init/Makefile
        init/systemd/Makefile
+       init/systemd-swanctl/Makefile
        src/Makefile
        src/include/Makefile
        src/libstrongswan/Makefile
@@ -1637,6 +1657,7 @@ AC_CONFIG_FILES([
        src/charon-tkm/Makefile
        src/charon-cmd/Makefile
        src/charon-svc/Makefile
+       src/charon-systemd/Makefile
        src/libcharon/Makefile
        src/libcharon/plugins/eap_aka/Makefile
        src/libcharon/plugins/eap_aka_3gpp2/Makefile
index 69439a1..a72706c 100644 (file)
@@ -1,6 +1,12 @@
 
 SUBDIRS =
 
-if HAVE_SYSTEMD
+if USE_LEGACY_SYSTEMD
   SUBDIRS += systemd
 endif
+
+if USE_SYSTEMD
+if USE_SWANCTL
+  SUBDIRS += systemd-swanctl
+endif
+endif
diff --git a/init/systemd-swanctl/.gitignore b/init/systemd-swanctl/.gitignore
new file mode 100644 (file)
index 0000000..b973780
--- /dev/null
@@ -0,0 +1 @@
+strongswan-swanctl.service
diff --git a/init/systemd-swanctl/Makefile.am b/init/systemd-swanctl/Makefile.am
new file mode 100644 (file)
index 0000000..eee30ac
--- /dev/null
@@ -0,0 +1,11 @@
+
+EXTRA_DIST = strongswan-swanctl.service.in
+CLEANFILES = strongswan-swanctl.service
+
+systemdsystemunit_DATA = strongswan-swanctl.service
+
+strongswan-swanctl.service : strongswan-swanctl.service.in
+       $(AM_V_GEN) \
+       sed \
+       -e "s:@SBINDIR@:$(sbindir):" \
+       $(srcdir)/$@.in > $@
diff --git a/init/systemd-swanctl/strongswan-swanctl.service.in b/init/systemd-swanctl/strongswan-swanctl.service.in
new file mode 100644 (file)
index 0000000..818d352
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=strongSwan IPsec IKEv1/IKEv2 daemon using swanctl
+After=network.target
+
+[Service]
+Type=notify
+ExecStart=@SBINDIR@/charon-systemd
+ExecStartPost=@SBINDIR@/swanctl --load-all --noprompt
+ExecReload=@SBINDIR@/swanctl --reload
diff --git a/init/systemd/.gitignore b/init/systemd/.gitignore
new file mode 100644 (file)
index 0000000..0b90b36
--- /dev/null
@@ -0,0 +1 @@
+strongswan.service
index dee892e..608078b 100644 (file)
@@ -1,5 +1,5 @@
 [Unit]
-Description=strongSwan IPsec
+Description=strongSwan IPsec IKEv1/IKEv2 daemon using ipsec.conf
 After=syslog.target
 
 [Service]
index fbc78b9..5f9a938 100644 (file)
@@ -1,5 +1,9 @@
-man_MANS = \
+man_MANS =
+
+if USE_FILE_CONFIG
+  man_MANS += \
        ipsec.conf.5 \
        ipsec.secrets.5
+endif
 
 CLEANFILES = $(man_MANS)
index 48d4e9f..fafda66 100755 (executable)
@@ -34,6 +34,7 @@ all)
                        --disable-dumm --disable-kernel-pfroute --disable-keychain
                        --disable-lock-profiler --disable-maemo --disable-padlock
                        --disable-osx-attr --disable-tkm --disable-uci --disable-aikgen
+                       --disable-systemd
                        --disable-svc --disable-dbghelp-backtraces --disable-socket-win
                        --disable-kernel-wfp --disable-kernel-iph --disable-winhttp"
        if test "$LEAK_DETECTIVE" = "yes"; then
index 95c68d0..603c9d1 100644 (file)
@@ -60,6 +60,10 @@ if USE_CHARON
   SUBDIRS += charon
 endif
 
+if USE_SYSTEMD
+  SUBDIRS += charon-systemd
+endif
+
 if USE_NM
   SUBDIRS += charon-nm
 endif
index ebebde2..613c2f6 100644 (file)
@@ -174,5 +174,5 @@ void nm_backend_register()
                                PLUGIN_SDEPEND(CERT_DECODE, CERT_X509),
        };
        lib->plugins->add_static_features(lib->plugins, "nm-backend", features,
-                                                                         countof(features), TRUE);
+                                                                         countof(features), TRUE, NULL, NULL);
 }
diff --git a/src/charon-systemd/.gitignore b/src/charon-systemd/.gitignore
new file mode 100644 (file)
index 0000000..da7b648
--- /dev/null
@@ -0,0 +1 @@
+charon-systemd
diff --git a/src/charon-systemd/Makefile.am b/src/charon-systemd/Makefile.am
new file mode 100644 (file)
index 0000000..1b9ac15
--- /dev/null
@@ -0,0 +1,19 @@
+sbin_PROGRAMS = charon-systemd
+
+charon_systemd_SOURCES = \
+charon-systemd.c
+
+charon-systemd.o :     $(top_builddir)/config.status
+
+charon_systemd_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon \
+       $(systemd_daemon_CFLAGS) $(systemd_journal_CFLAGS) \
+       -DPLUGINS=\""${charon_plugins}\""
+
+charon_systemd_LDADD = \
+       $(top_builddir)/src/libstrongswan/libstrongswan.la \
+       $(top_builddir)/src/libhydra/libhydra.la \
+       $(top_builddir)/src/libcharon/libcharon.la \
+       $(systemd_daemon_LIBS) $(systemd_journal_LIBS) -lm $(PTHREADLIB) $(DLLIB)
diff --git a/src/charon-systemd/charon-systemd.c b/src/charon-systemd/charon-systemd.c
new file mode 100644 (file)
index 0000000..07444e8
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2006-2012 Tobias Brunner
+ * Copyright (C) 2005-2014 Martin Willi
+ * Copyright (C) 2006 Daniel Roethlisberger
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* won't make sense from our logging hook */
+#define SD_JOURNAL_SUPPRESS_LOCATION
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-journal.h>
+
+#include <hydra.h>
+#include <daemon.h>
+
+#include <library.h>
+#include <utils/backtrace.h>
+#include <threading/thread.h>
+#include <threading/rwlock.h>
+
+/**
+ * hook in library for debugging messages
+ */
+extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
+
+/**
+ * Logging hook for library logs, using stderr output
+ */
+static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
+{
+       va_list args;
+
+       if (level <= 1)
+       {
+               va_start(args, fmt);
+               fprintf(stderr, "00[%N] ", debug_names, group);
+               vfprintf(stderr, fmt, args);
+               fprintf(stderr, "\n");
+               va_end(args);
+       }
+}
+
+typedef struct journal_logger_t journal_logger_t;
+
+/**
+ * Logger implementation using systemd-journal
+ */
+struct journal_logger_t {
+
+       /**
+        * Implements logger_t
+        */
+       logger_t logger;
+
+       /**
+        * Configured loglevels
+        */
+       level_t levels[DBG_MAX];
+
+       /**
+        * Lock for levels
+        */
+       rwlock_t *lock;
+};
+
+METHOD(logger_t, vlog, void,
+       journal_logger_t *this, debug_t group, level_t level, int thread,
+       ike_sa_t *ike_sa, const char *fmt, va_list args)
+{
+       char buf[4096], *msg = buf;
+       ssize_t len;
+       va_list copy;
+
+       va_copy(copy, args);
+       len = vsnprintf(msg, sizeof(buf), fmt, copy);
+       va_end(copy);
+
+       if (len >= sizeof(buf))
+       {
+               len++;
+               msg = malloc(len);
+               va_copy(copy, args);
+               len = vsnprintf(msg, len, fmt, copy);
+               va_end(copy);
+       }
+       if (len > 0)
+       {
+               char unique[64] = "", name[256] = "";
+               int priority;
+
+               if (ike_sa)
+               {
+                       snprintf(unique, sizeof(unique), "IKE_SA_UNIQUE_ID=%u",
+                                        ike_sa->get_unique_id(ike_sa));
+                       if (ike_sa->get_peer_cfg(ike_sa))
+                       {
+                               snprintf(name, sizeof(name), "IKE_SA_NAME=%s",
+                                                ike_sa->get_name(ike_sa));
+                       }
+               }
+               switch (level)
+               {
+                       case LEVEL_AUDIT:
+                               priority = LOG_NOTICE;
+                               break;
+                       case LEVEL_CTRL:
+                               priority = LOG_INFO;
+                               break;
+                       default:
+                               priority = LOG_DEBUG;
+                               break;
+               }
+               sd_journal_send(
+                       "MESSAGE=%s", msg,
+                       "MESSAGE_ID=57d2708c-d607-43bd-8c39-66bf%.8x",
+                               chunk_hash_static(chunk_from_str((char*)fmt)),
+                       "PRIORITY=%d", priority,
+                       "GROUP=%N", debug_names, group,
+                       "LEVEL=%d", level,
+                       "THREAD=%d", thread,
+                       unique[0] ? unique : NULL,
+                       name[0] ? name : NULL,
+                       NULL);
+       }
+       if (msg != buf)
+       {
+               free(msg);
+       }
+}
+
+METHOD(logger_t, get_level, level_t,
+       journal_logger_t *this, debug_t group)
+{
+       level_t level;
+
+       this->lock->read_lock(this->lock);
+       level = this->levels[group];
+       this->lock->unlock(this->lock);
+
+       return level;
+}
+
+/**
+ * Reload journal logger configuration
+ */
+CALLBACK(journal_reload, bool,
+       journal_logger_t **journal)
+{
+       journal_logger_t *this = *journal;
+       debug_t group;
+       level_t def;
+
+       def = lib->settings->get_int(lib->settings, "%s.journal.default", 1, lib->ns);
+
+       this->lock->write_lock(this->lock);
+       for (group = 0; group < DBG_MAX; group++)
+       {
+               this->levels[group] =
+                       lib->settings->get_int(lib->settings,
+                               "%s.journal.%N", def, lib->ns, debug_lower_names, group);
+       }
+       this->lock->unlock(this->lock);
+
+       charon->bus->add_logger(charon->bus, &this->logger);
+
+       return TRUE;
+}
+
+/**
+ * Initialize/deinitialize journal logger
+ */
+static bool journal_register(void *plugin, plugin_feature_t *feature,
+                                                        bool reg, journal_logger_t **logger)
+{
+       journal_logger_t *this;
+
+       if (reg)
+       {
+               INIT(this,
+                       .logger = {
+                               .vlog = _vlog,
+                               .get_level = _get_level,
+                       },
+                       .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+               );
+
+               journal_reload(&this);
+
+               *logger = this;
+               return TRUE;
+       }
+       else
+       {
+               this = *logger;
+
+               charon->bus->remove_logger(charon->bus, &this->logger);
+
+               this->lock->destroy(this->lock);
+               free(this);
+
+               return TRUE;
+       }
+}
+
+/**
+ * Run the daemon and handle unix signals
+ */
+static int run()
+{
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, SIGTERM);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+
+       sd_notify(0, "READY=1\n");
+
+       while (TRUE)
+       {
+               int sig, error;
+
+               error = sigwait(&set, &sig);
+               if (error)
+               {
+                       DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(error));
+                       return SS_RC_INITIALIZATION_FAILED;
+               }
+               switch (sig)
+               {
+                       case SIGTERM:
+                       {
+                               DBG1(DBG_DMN, "SIGTERM received, shutting down");
+                               charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
+                               return 0;
+                       }
+                       default:
+                       {
+                               DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
+                               break;
+                       }
+               }
+       }
+}
+
+/**
+ * lookup UID and GID
+ */
+static bool lookup_uid_gid()
+{
+#ifdef IPSEC_USER
+       if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER))
+       {
+               return FALSE;
+       }
+#endif /* IPSEC_USER */
+#ifdef IPSEC_GROUP
+       if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP))
+       {
+               return FALSE;
+       }
+#endif /* IPSEC_GROUP */
+       return TRUE;
+}
+
+/**
+ * Handle SIGSEGV/SIGILL signals raised by threads
+ */
+static void segv_handler(int signal)
+{
+       backtrace_t *backtrace;
+
+       DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
+       backtrace = backtrace_create(2);
+       backtrace->log(backtrace, NULL, TRUE);
+       backtrace->log(backtrace, stderr, TRUE);
+       backtrace->destroy(backtrace);
+
+       DBG1(DBG_DMN, "killing ourself, received critical signal");
+       abort();
+}
+
+/**
+ * The journal logger instance
+ */
+static journal_logger_t *journal;
+
+/**
+ * Journal static features
+ */
+static plugin_feature_t features[] = {
+       PLUGIN_CALLBACK((plugin_feature_callback_t)journal_register, &journal),
+               PLUGIN_PROVIDE(CUSTOM, "systemd-journal"),
+};
+
+/**
+ * Main function, starts the daemon.
+ */
+int main(int argc, char *argv[])
+{
+       struct sigaction action;
+       struct utsname utsname;
+
+       dbg = dbg_stderr;
+
+       if (uname(&utsname) != 0)
+       {
+               memset(&utsname, 0, sizeof(utsname));
+       }
+
+       sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
+                          VERSION, utsname.sysname, utsname.release, utsname.machine);
+
+       atexit(library_deinit);
+       if (!library_init(NULL, "charon-systemd"))
+       {
+               sd_notifyf(0, "STATUS=libstrongswan initialization failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       if (lib->integrity &&
+               !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0]))
+       {
+               sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       atexit(libhydra_deinit);
+       if (!libhydra_init())
+       {
+               sd_notifyf(0, "STATUS=libhydra initialization failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       atexit(libcharon_deinit);
+       if (!libcharon_init())
+       {
+               sd_notifyf(0, "STATUS=libcharon initialization failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       if (!lookup_uid_gid())
+       {
+               sd_notifyf(0, "STATUS=unkown uid/gid");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       charon->load_loggers(charon, NULL, FALSE);
+
+       lib->plugins->add_static_features(lib->plugins, lib->ns, features,
+                                                       countof(features), TRUE, journal_reload, &journal);
+
+       if (!charon->initialize(charon, PLUGINS))
+       {
+               sd_notifyf(0, "STATUS=charon initialization failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+       lib->plugins->status(lib->plugins, LEVEL_CTRL);
+
+       if (!lib->caps->drop(lib->caps))
+       {
+               sd_notifyf(0, "STATUS=dropping capabilities failed");
+               return SS_RC_INITIALIZATION_FAILED;
+       }
+
+       /* add handler for SEGV and ILL,
+        * INT, TERM and HUP are handled by sigwait() in run() */
+       action.sa_handler = segv_handler;
+       action.sa_flags = 0;
+       sigemptyset(&action.sa_mask);
+       sigaddset(&action.sa_mask, SIGINT);
+       sigaddset(&action.sa_mask, SIGTERM);
+       sigaddset(&action.sa_mask, SIGHUP);
+       sigaction(SIGSEGV, &action, NULL);
+       sigaction(SIGILL, &action, NULL);
+       sigaction(SIGBUS, &action, NULL);
+       action.sa_handler = SIG_IGN;
+       sigaction(SIGPIPE, &action, NULL);
+
+       pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
+
+       charon->start(charon);
+
+       sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
+                          VERSION, utsname.sysname, utsname.release, utsname.machine);
+
+       return run();
+}
index 9a22f9a..a6770fc 100644 (file)
@@ -296,7 +296,7 @@ int main(int argc, char *argv[])
                        PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
        };
        lib->plugins->add_static_features(lib->plugins, "tkm-backend", features,
-                       countof(features), TRUE);
+                       countof(features), TRUE, NULL, NULL);
 
        if (!register_dh_mapping())
        {
index a34d0b1..67db5e6 100644 (file)
@@ -159,7 +159,8 @@ int register_dh_mapping()
        }
        enumerator->destroy(enumerator);
 
-       lib->plugins->add_static_features(lib->plugins, "tkm-dh", f, countof(f), TRUE);
+       lib->plugins->add_static_features(lib->plugins, "tkm-dh", f, countof(f),
+                                                                         TRUE, NULL, NULL);
 
        if (count > 0)
        {
index 18754c7..80894a1 100644 (file)
@@ -64,7 +64,7 @@ static bool test_runner_init(bool init)
                                PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
                };
                lib->plugins->add_static_features(lib->plugins, "tkm-tests", features,
-                                                                                 countof(features), TRUE);
+                                                                                 countof(features), TRUE, NULL, NULL);
 
                lib->settings->set_int(lib->settings, "%s.dh_mapping.%d", 1,
                                                           lib->ns, MODP_3072_BIT);
index 32bf28f..e6c9126 100644 (file)
@@ -543,7 +543,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
        charonservice = &this->public;
 
        lib->plugins->add_static_features(lib->plugins, "androidbridge", features,
-                                                                         countof(features), TRUE);
+                                                                         countof(features), TRUE, NULL, NULL);
 
 #ifdef USE_BYOD
        if (byod)
@@ -556,7 +556,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
                };
 
                lib->plugins->add_static_features(lib->plugins, "android-byod",
-                                                               byod_features, countof(byod_features), TRUE);
+                                       byod_features, countof(byod_features), TRUE, NULL, NULL);
        }
 #endif
 }
index a89995a..3ae7c4e 100644 (file)
@@ -593,7 +593,7 @@ METHOD(daemon_t, initialize, bool,
                                PLUGIN_DEPENDS(CUSTOM, "socket"),
        };
        lib->plugins->add_static_features(lib->plugins, lib->ns, features,
-                                                                         countof(features), TRUE);
+                                                                         countof(features), TRUE, NULL, NULL);
 
        /* load plugins, further infrastructure may need it */
        if (!lib->plugins->load(lib->plugins, plugins))
index 3cd0081..292a400 100644 (file)
@@ -450,6 +450,17 @@ CALLBACK(uninstall, vici_message_t*,
        return send_reply(this, "policy '%s' not found", child);
 }
 
+CALLBACK(reload_settings, vici_message_t*,
+       private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
+{
+       if (lib->settings->load_files(lib->settings, lib->conf, FALSE))
+       {
+               lib->plugins->reload(lib->plugins, NULL);
+               return send_reply(this, NULL);
+       }
+       return send_reply(this, "reloading '%s' failed", lib->conf);
+}
+
 static void manage_command(private_vici_control_t *this,
                                                   char *name, vici_command_cb_t cb, bool reg)
 {
@@ -466,6 +477,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
        manage_command(this, "terminate", terminate, reg);
        manage_command(this, "install", install, reg);
        manage_command(this, "uninstall", uninstall, reg);
+       manage_command(this, "reload-settings", reload_settings, reg);
        this->dispatcher->manage_event(this->dispatcher, "control-log", reg);
 }
 
index c23f2f0..1fec1b3 100644 (file)
@@ -218,6 +218,16 @@ typedef struct {
        char *name;
 
        /**
+        * Optional reload function for features
+        */
+       bool (*reload)(void *data);
+
+       /**
+        * User data to pass to reload function
+        */
+       void *reload_data;
+
+       /**
         * Static plugin features
         */
        plugin_feature_t *features;
@@ -242,6 +252,16 @@ METHOD(plugin_t, get_static_features, int,
        return this->count;
 }
 
+METHOD(plugin_t, static_reload, bool,
+       static_features_t *this)
+{
+       if (this->reload)
+       {
+               return this->reload(this->reload_data);
+       }
+       return FALSE;
+}
+
 METHOD(plugin_t, static_destroy, void,
        static_features_t *this)
 {
@@ -254,7 +274,8 @@ METHOD(plugin_t, static_destroy, void,
  * Create a wrapper around static plugin features.
  */
 static plugin_t *static_features_create(const char *name,
-                                                                               plugin_feature_t features[], int count)
+                                                                               plugin_feature_t features[], int count,
+                                                                               bool (*reload)(void*), void *reload_data)
 {
        static_features_t *this;
 
@@ -262,9 +283,12 @@ static plugin_t *static_features_create(const char *name,
                .public = {
                        .get_name = _get_static_name,
                        .get_features = _get_static_features,
+                       .reload = _static_reload,
                        .destroy = _static_destroy,
                },
                .name = strdup(name),
+               .reload = reload,
+               .reload_data = reload_data,
                .features = calloc(count, sizeof(plugin_feature_t)),
                .count = count,
        );
@@ -904,12 +928,13 @@ static void purge_plugins(private_plugin_loader_t *this)
 
 METHOD(plugin_loader_t, add_static_features, void,
        private_plugin_loader_t *this, const char *name,
-       plugin_feature_t features[], int count, bool critical)
+       plugin_feature_t features[], int count, bool critical,
+       bool (*reload)(void*), void *reload_data)
 {
        plugin_entry_t *entry;
        plugin_t *plugin;
 
-       plugin = static_features_create(name, features, count);
+       plugin = static_features_create(name, features, count, reload, reload_data);
 
        INIT(entry,
                .plugin = plugin,
index fec57ce..6be6a90 100644 (file)
@@ -44,6 +44,9 @@ struct plugin_loader_t {
         * If critical is TRUE load() will fail if any of the added features could
         * not be loaded.
         *
+        * If a reload callback function is given, it gets invoked for the
+        * registered feature set when reload() is invoked on the plugin_loader.
+        *
         * @note The name should be unique otherwise a plugin with the same name is
         * not loaded.
         *
@@ -51,10 +54,13 @@ struct plugin_loader_t {
         * @param features              array of plugin features
         * @param count                 number of features in the array
         * @param critical              TRUE if the features are critical
+        * @param reload                feature reload callback, or NULL
+        * @param reload_data   user data to pass to reload callback
         */
        void (*add_static_features) (plugin_loader_t *this, const char *name,
                                                                 struct plugin_feature_t *features, int count,
-                                                                bool critical);
+                                                                bool critical, bool (*reload)(void*),
+                                                                void *reload_data);
 
        /**
         * Load a list of plugins.
index 8b41ae2..a8d45b5 100644 (file)
@@ -227,7 +227,7 @@ static void init()
        options = options_create();
 
        lib->plugins->add_static_features(lib->plugins, "pt-tls-client", features,
-                                                                         countof(features), TRUE);
+                                                                         countof(features), TRUE, NULL, NULL);
        if (!lib->plugins->load(lib->plugins,
                        lib->settings->get_str(lib->settings, "pt-tls-client.load", PLUGINS)))
        {
index 385737a..dec7d62 100644 (file)
@@ -10,12 +10,14 @@ swanctl_SOURCES = \
        commands/list_conns.c \
        commands/list_certs.c \
        commands/list_pools.c \
-       commands/load_conns.c \
-       commands/load_creds.c \
-       commands/load_pools.c \
+       commands/load_all.c \
+       commands/load_conns.c commands/load_conns.h \
+       commands/load_creds.c commands/load_creds.h \
+       commands/load_pools.c commands/load_pools.h \
        commands/log.c \
        commands/version.c \
        commands/stats.c \
+       commands/reload_settings.c \
        swanctl.c swanctl.h
 
 swanctl_LDADD = \
index e488273..dbe16c3 100644 (file)
@@ -220,7 +220,7 @@ int command_usage(char *error, ...)
        {
                for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
                {
-                       fprintf(out, "  swanctl --%-10s (-%c)  %s\n",
+                       fprintf(out, "  swanctl --%-15s (-%c)  %s\n",
                                        cmds[i].cmd, cmds[i].op, cmds[i].description);
                }
        }
index 8510fa4..2d78a24 100644 (file)
@@ -27,7 +27,7 @@
 /**
  * Maximum number of commands (+1).
  */
-#define MAX_COMMANDS 16
+#define MAX_COMMANDS 18
 
 /**
  * Maximum number of options in a command (+3)
diff --git a/src/swanctl/commands/load_all.c b/src/swanctl/commands/load_all.c
new file mode 100644 (file)
index 0000000..f47fee5
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "command.h"
+#include "swanctl.h"
+#include "load_creds.h"
+#include "load_pools.h"
+#include "load_conns.h"
+
+static int load_all(vici_conn_t *conn)
+{
+       bool clear = FALSE, noprompt = FALSE;
+       command_format_options_t format = COMMAND_FORMAT_NONE;
+       settings_t *cfg;
+       int ret = 0;
+       char *arg;
+
+       while (TRUE)
+       {
+               switch (command_getopt(&arg))
+               {
+                       case 'h':
+                               return command_usage(NULL);
+                       case 'c':
+                               clear = TRUE;
+                               continue;
+                       case 'n':
+                               noprompt = TRUE;
+                               continue;
+                       case 'P':
+                               format |= COMMAND_FORMAT_PRETTY;
+                               /* fall through to raw */
+                       case 'r':
+                               format |= COMMAND_FORMAT_RAW;
+                               continue;
+                       case EOF:
+                               break;
+                       default:
+                               return command_usage("invalid --load-all option");
+               }
+               break;
+       }
+
+       cfg = settings_create(SWANCTL_CONF);
+       if (!cfg)
+       {
+               fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+               return EINVAL;
+       }
+
+       if (ret == 0)
+       {
+               ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
+       }
+       if (ret == 0)
+       {
+               ret = load_pools_cfg(conn, format, cfg);
+       }
+       if (ret == 0)
+       {
+               ret = load_conns_cfg(conn, format, cfg);
+       }
+
+       cfg->destroy(cfg);
+
+       return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+       command_register((command_t) {
+               load_all, 'q', "load-all", "load credentials, pools and connections",
+               {"[--raw|--pretty] [--clear] [--noprompt]"},
+               {
+                       {"help",                'h', 0, "show usage information"},
+                       {"clear",               'c', 0, "clear previously loaded credentials"},
+                       {"noprompt",    'n', 0, "do not prompt for passwords"},
+                       {"raw",                 'r', 0, "dump raw response message"},
+                       {"pretty",              'P', 0, "dump raw response message in pretty print"},
+               }
+       });
+}
index 7383f7a..de30d8e 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "command.h"
 #include "swanctl.h"
+#include "load_conns.h"
 
 /**
  * Check if we should handle a key as a list of comma separated values
@@ -319,41 +320,16 @@ static bool unload_conn(vici_conn_t *conn, char *name,
        return ret;
 }
 
-static int load_conns(vici_conn_t *conn)
+/**
+ * See header.
+ */
+int load_conns_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg)
 {
        u_int found = 0, loaded = 0, unloaded = 0;
-       command_format_options_t format = COMMAND_FORMAT_NONE;
-       char *arg, *section;
+       char *section;
        enumerator_t *enumerator;
        linked_list_t *conns;
-       settings_t *cfg;
-
-       while (TRUE)
-       {
-               switch (command_getopt(&arg))
-               {
-                       case 'h':
-                               return command_usage(NULL);
-                       case 'P':
-                               format |= COMMAND_FORMAT_PRETTY;
-                               /* fall through to raw */
-                       case 'r':
-                               format |= COMMAND_FORMAT_RAW;
-                               continue;
-                       case EOF:
-                               break;
-                       default:
-                               return command_usage("invalid --load-conns option");
-               }
-               break;
-       }
-
-       cfg = settings_create(SWANCTL_CONF);
-       if (!cfg)
-       {
-               fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
-               return EINVAL;
-       }
 
        conns = list_conns(conn, format);
 
@@ -369,8 +345,6 @@ static int load_conns(vici_conn_t *conn)
        }
        enumerator->destroy(enumerator);
 
-       cfg->destroy(cfg);
-
        /* unload all connection in daemon, but not in file */
        while (conns->remove_first(conns, (void**)&section) == SUCCESS)
        {
@@ -402,6 +376,47 @@ static int load_conns(vici_conn_t *conn)
        return EINVAL;
 }
 
+static int load_conns(vici_conn_t *conn)
+{
+       command_format_options_t format = COMMAND_FORMAT_NONE;
+       settings_t *cfg;
+       char *arg;
+       int ret;
+
+       while (TRUE)
+       {
+               switch (command_getopt(&arg))
+               {
+                       case 'h':
+                               return command_usage(NULL);
+                       case 'P':
+                               format |= COMMAND_FORMAT_PRETTY;
+                               /* fall through to raw */
+                       case 'r':
+                               format |= COMMAND_FORMAT_RAW;
+                               continue;
+                       case EOF:
+                               break;
+                       default:
+                               return command_usage("invalid --load-conns option");
+               }
+               break;
+       }
+
+       cfg = settings_create(SWANCTL_CONF);
+       if (!cfg)
+       {
+               fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+               return EINVAL;
+       }
+
+       ret = load_conns_cfg(conn, format, cfg);
+
+       cfg->destroy(cfg);
+
+       return ret;
+}
+
 /**
  * Register the command.
  */
diff --git a/src/swanctl/commands/load_conns.h b/src/swanctl/commands/load_conns.h
new file mode 100644 (file)
index 0000000..1e7abde
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+/**
+ * Load all connections from configuration file
+ *
+ * @param conn         vici connection to load to
+ * @param format       output format
+ * @param cfg          configuration to load from
+ */
+int load_conns_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg);
index f77084c..86ee3c1 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "command.h"
 #include "swanctl.h"
+#include "load_creds.h"
 
 #include <credentials/sets/mem_cred.h>
 #include <credentials/sets/callback_cred.h>
@@ -484,13 +485,50 @@ static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
        return TRUE;
 }
 
+/**
+ * See header.
+ */
+int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg, bool clear, bool noprompt)
+{
+       enumerator_t *enumerator;
+       char *section;
+
+       if (clear)
+       {
+               if (!clear_creds(conn, format))
+               {
+                       return ECONNREFUSED;
+               }
+       }
+
+       load_certs(conn, format, "x509", SWANCTL_X509DIR);
+       load_certs(conn, format, "x509ca", SWANCTL_X509CADIR);
+       load_certs(conn, format, "x509aa", SWANCTL_X509AADIR);
+       load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR);
+       load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR);
+
+       load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
+       load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
+       load_keys(conn, format, noprompt, cfg, "any", SWANCTL_PKCS8DIR);
+
+       enumerator = cfg->create_section_enumerator(cfg, "secrets");
+       while (enumerator->enumerate(enumerator, &section))
+       {
+               load_secret(conn, cfg, section, format);
+       }
+       enumerator->destroy(enumerator);
+
+       return 0;
+}
+
 static int load_creds(vici_conn_t *conn)
 {
        bool clear = FALSE, noprompt = FALSE;
        command_format_options_t format = COMMAND_FORMAT_NONE;
-       enumerator_t *enumerator;
        settings_t *cfg;
-       char *arg, *section;
+       char *arg;
+       int ret;
 
        while (TRUE)
        {
@@ -518,14 +556,6 @@ static int load_creds(vici_conn_t *conn)
                break;
        }
 
-       if (clear)
-       {
-               if (!clear_creds(conn, format))
-               {
-                       return ECONNREFUSED;
-               }
-       }
-
        cfg = settings_create(SWANCTL_CONF);
        if (!cfg)
        {
@@ -533,26 +563,11 @@ static int load_creds(vici_conn_t *conn)
                return EINVAL;
        }
 
-       load_certs(conn, format, "x509", SWANCTL_X509DIR);
-       load_certs(conn, format, "x509ca", SWANCTL_X509CADIR);
-       load_certs(conn, format, "x509aa", SWANCTL_X509AADIR);
-       load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR);
-       load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR);
-
-       load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
-       load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
-       load_keys(conn, format, noprompt, cfg, "any", SWANCTL_PKCS8DIR);
-
-       enumerator = cfg->create_section_enumerator(cfg, "secrets");
-       while (enumerator->enumerate(enumerator, &section))
-       {
-               load_secret(conn, cfg, section, format);
-       }
-       enumerator->destroy(enumerator);
+       ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
 
        cfg->destroy(cfg);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -562,7 +577,7 @@ static void __attribute__ ((constructor))reg()
 {
        command_register((command_t) {
                load_creds, 's', "load-creds", "(re-)load credentials",
-               {"[--raw|--pretty]"},
+               {"[--raw|--pretty] [--clear] [--noprompt]"},
                {
                        {"help",                'h', 0, "show usage information"},
                        {"clear",               'c', 0, "clear previously loaded credentials"},
diff --git a/src/swanctl/commands/load_creds.h b/src/swanctl/commands/load_creds.h
new file mode 100644 (file)
index 0000000..7f689ad
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+/**
+ * Load all credentials from configuration file
+ *
+ * @param conn         vici connection to load to
+ * @param format       output format
+ * @param cfg          configuration to load from
+ * @param clear                TRUE to clear existing credentials
+ * @param noprompt     TRUE to skip any password prompt
+ */
+int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg, bool clear, bool noprompt);
index 0ec56cc..d7fbd13 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "command.h"
 #include "swanctl.h"
+#include "load_pools.h"
 
 /**
  * Add a vici list from a comma separated string value
@@ -192,41 +193,16 @@ static bool unload_pool(vici_conn_t *conn, char *name,
        return ret;
 }
 
-static int load_pools(vici_conn_t *conn)
+/**
+ * See header.
+ */
+int load_pools_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg)
 {
-       command_format_options_t format = COMMAND_FORMAT_NONE;
        u_int found = 0, loaded = 0, unloaded = 0;
-       char *arg, *section;
+       char *section;
        enumerator_t *enumerator;
        linked_list_t *pools;
-       settings_t *cfg;
-
-       while (TRUE)
-       {
-               switch (command_getopt(&arg))
-               {
-                       case 'h':
-                               return command_usage(NULL);
-                       case 'P':
-                               format |= COMMAND_FORMAT_PRETTY;
-                               /* fall through to raw */
-                       case 'r':
-                               format |= COMMAND_FORMAT_RAW;
-                               continue;
-                       case EOF:
-                               break;
-                       default:
-                               return command_usage("invalid --load-pools option");
-               }
-               break;
-       }
-
-       cfg = settings_create(SWANCTL_CONF);
-       if (!cfg)
-       {
-               fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
-               return EINVAL;
-       }
 
        pools = list_pools(conn, format);
 
@@ -242,8 +218,6 @@ static int load_pools(vici_conn_t *conn)
        }
        enumerator->destroy(enumerator);
 
-       cfg->destroy(cfg);
-
        /* unload all pools in daemon, but not in file */
        while (pools->remove_first(pools, (void**)&section) == SUCCESS)
        {
@@ -275,6 +249,47 @@ static int load_pools(vici_conn_t *conn)
        return EINVAL;
 }
 
+static int load_pools(vici_conn_t *conn)
+{
+       command_format_options_t format = COMMAND_FORMAT_NONE;
+       settings_t *cfg;
+       char *arg;
+       int ret;
+
+       while (TRUE)
+       {
+               switch (command_getopt(&arg))
+               {
+                       case 'h':
+                               return command_usage(NULL);
+                       case 'P':
+                               format |= COMMAND_FORMAT_PRETTY;
+                               /* fall through to raw */
+                       case 'r':
+                               format |= COMMAND_FORMAT_RAW;
+                               continue;
+                       case EOF:
+                               break;
+                       default:
+                               return command_usage("invalid --load-pools option");
+               }
+               break;
+       }
+
+       cfg = settings_create(SWANCTL_CONF);
+       if (!cfg)
+       {
+               fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+               return EINVAL;
+       }
+
+       ret = load_pools_cfg(conn, format, cfg);
+
+       cfg->destroy(cfg);
+
+       return ret;
+}
+
 /**
  * Register the command.
  */
@@ -282,7 +297,7 @@ static void __attribute__ ((constructor))reg()
 {
        command_register((command_t) {
                load_pools, 'a', "load-pools", "(re-)load pool configuration",
-               {"[--raw|--pretty"},
+               {"[--raw|--pretty]"},
                {
                        {"help",                'h', 0, "show usage information"},
                        {"raw",                 'r', 0, "dump raw response message"},
diff --git a/src/swanctl/commands/load_pools.h b/src/swanctl/commands/load_pools.h
new file mode 100644 (file)
index 0000000..f424db9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+/**
+ * Load all pool definitions from configuration file
+ *
+ * @param conn         vici connection to load to
+ * @param format       output format
+ * @param cfg          configuration to load from
+ */
+int load_pools_cfg(vici_conn_t *conn, command_format_options_t format,
+                                  settings_t *cfg);
diff --git a/src/swanctl/commands/reload_settings.c b/src/swanctl/commands/reload_settings.c
new file mode 100644 (file)
index 0000000..ecd6338
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+static int reload_settings(vici_conn_t *conn)
+{
+       vici_req_t *req;
+       vici_res_t *res;
+       char *arg;
+       int ret = 0;
+       command_format_options_t format = COMMAND_FORMAT_NONE;
+
+       while (TRUE)
+       {
+               switch (command_getopt(&arg))
+               {
+                       case 'h':
+                               return command_usage(NULL);
+                       case 'P':
+                               format |= COMMAND_FORMAT_PRETTY;
+                               /* fall through to raw */
+                       case 'r':
+                               format |= COMMAND_FORMAT_RAW;
+                               continue;
+                       case EOF:
+                               break;
+                       default:
+                               return command_usage("invalid --reload-settings option");
+               }
+               break;
+       }
+
+       req = vici_begin("reload-settings");
+       res = vici_submit(req, conn);
+       if (!res)
+       {
+               fprintf(stderr, "reload-settings request failed: %s\n", strerror(errno));
+               return errno;
+       }
+       if (format & COMMAND_FORMAT_RAW)
+       {
+               vici_dump(res, "reload-settings reply",
+                                 format & COMMAND_FORMAT_PRETTY, stdout);
+       }
+       else
+       {
+               if (!streq(vici_find_str(res, "no", "success"), "yes"))
+               {
+                       fprintf(stderr, "reload-settings failed: %s\n",
+                                       vici_find_str(res, "", "errmsg"));
+                       ret = 1;
+               }
+       }
+       vici_free_res(res);
+       return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+       command_register((command_t) {
+               reload_settings, 'r', "reload-settings", "reload daemon strongswan.conf",
+               {"[--raw|--pretty]"},
+               {
+                       {"help",                'h', 0, "show usage information"},
+                       {"raw",                 'r', 0, "dump raw response message"},
+                       {"pretty",              'P', 0, "dump raw response message in pretty print"},
+               }
+       });
+}
index d5f4fc6..543c10a 100644 (file)
@@ -62,6 +62,9 @@ list stored certificates
 .B "\-A, \-\-list\-pools"
 list loaded pool configurations
 .TP
+.B "\-q, \-\-load\-all"
+(re\-)load credentials, pools and connections
+.TP
 .B "\-c, \-\-load\-conns"
 (re\-)load connection configuration
 .TP
@@ -77,6 +80,9 @@ trace logging output
 .B "\-S, \-\-stats"
 show daemon infos and statistics
 .TP
+.B "\-r, \-\-reload-settings"
+reload strongswan.conf(5) configuration
+.TP
 .B "\-v, \-\-version"
 show daemon version information
 .TP