aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2014-09-24 11:17:29 +0200
committerMartin Willi <martin@revosec.ch>2014-09-24 11:17:29 +0200
commit6fe02dda752cbb2c2389a3367a3b6e04add43425 (patch)
tree4c34d40922d0848bfa682b4819d983e4ff57c982 /src
parent2dee0a85a6923da94d669dc5de337dc5ef1806e7 (diff)
parent575d3ab19a73736bfa25833e1102d3473e5bc25a (diff)
downloadstrongswan-6fe02dda752cbb2c2389a3367a3b6e04add43425.tar.bz2
strongswan-6fe02dda752cbb2c2389a3367a3b6e04add43425.tar.xz
Merge branch 'systemd'
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.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/charon-nm/nm/nm_backend.c2
-rw-r--r--src/charon-systemd/.gitignore1
-rw-r--r--src/charon-systemd/Makefile.am19
-rw-r--r--src/charon-systemd/charon-systemd.c403
-rw-r--r--src/charon-tkm/src/charon-tkm.c2
-rw-r--r--src/charon-tkm/src/tkm/tkm_diffie_hellman.c3
-rw-r--r--src/charon-tkm/tests/tests.c2
-rw-r--r--src/frontends/android/jni/libandroidbridge/charonservice.c4
-rw-r--r--src/libcharon/daemon.c2
-rw-r--r--src/libcharon/plugins/vici/vici_control.c12
-rw-r--r--src/libstrongswan/plugins/plugin_loader.c31
-rw-r--r--src/libstrongswan/plugins/plugin_loader.h8
-rw-r--r--src/pt-tls-client/pt-tls-client.c2
-rw-r--r--src/swanctl/Makefile.am8
-rw-r--r--src/swanctl/command.c2
-rw-r--r--src/swanctl/command.h2
-rw-r--r--src/swanctl/commands/load_all.c103
-rw-r--r--src/swanctl/commands/load_conns.c81
-rw-r--r--src/swanctl/commands/load_conns.h26
-rw-r--r--src/swanctl/commands/load_creds.c71
-rw-r--r--src/swanctl/commands/load_creds.h28
-rw-r--r--src/swanctl/commands/load_pools.c83
-rw-r--r--src/swanctl/commands/load_pools.h26
-rw-r--r--src/swanctl/commands/reload_settings.c87
-rw-r--r--src/swanctl/swanctl.8.in6
26 files changed, 906 insertions, 112 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 95c68d0c8..603c9d164 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -60,6 +60,10 @@ if USE_CHARON
SUBDIRS += charon
endif
+if USE_SYSTEMD
+ SUBDIRS += charon-systemd
+endif
+
if USE_NM
SUBDIRS += charon-nm
endif
diff --git a/src/charon-nm/nm/nm_backend.c b/src/charon-nm/nm/nm_backend.c
index ebebde2c0..613c2f6b5 100644
--- a/src/charon-nm/nm/nm_backend.c
+++ b/src/charon-nm/nm/nm_backend.c
@@ -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
index 000000000..da7b648a5
--- /dev/null
+++ b/src/charon-systemd/.gitignore
@@ -0,0 +1 @@
+charon-systemd
diff --git a/src/charon-systemd/Makefile.am b/src/charon-systemd/Makefile.am
new file mode 100644
index 000000000..1b9ac150f
--- /dev/null
+++ b/src/charon-systemd/Makefile.am
@@ -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
index 000000000..07444e812
--- /dev/null
+++ b/src/charon-systemd/charon-systemd.c
@@ -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();
+}
diff --git a/src/charon-tkm/src/charon-tkm.c b/src/charon-tkm/src/charon-tkm.c
index 9a22f9ad9..a6770fc50 100644
--- a/src/charon-tkm/src/charon-tkm.c
+++ b/src/charon-tkm/src/charon-tkm.c
@@ -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())
{
diff --git a/src/charon-tkm/src/tkm/tkm_diffie_hellman.c b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
index a34d0b1d4..67db5e6d8 100644
--- a/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
+++ b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
@@ -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)
{
diff --git a/src/charon-tkm/tests/tests.c b/src/charon-tkm/tests/tests.c
index 18754c717..80894a133 100644
--- a/src/charon-tkm/tests/tests.c
+++ b/src/charon-tkm/tests/tests.c
@@ -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);
diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c
index 32bf28f09..e6c9126d7 100644
--- a/src/frontends/android/jni/libandroidbridge/charonservice.c
+++ b/src/frontends/android/jni/libandroidbridge/charonservice.c
@@ -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
}
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index a89995a51..3ae7c4e6f 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -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))
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 3cd008162..292a40032 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -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);
}
diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c
index c23f2f03f..1fec1b3ea 100644
--- a/src/libstrongswan/plugins/plugin_loader.c
+++ b/src/libstrongswan/plugins/plugin_loader.c
@@ -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,
diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h
index fec57ce98..6be6a909c 100644
--- a/src/libstrongswan/plugins/plugin_loader.h
+++ b/src/libstrongswan/plugins/plugin_loader.h
@@ -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.
diff --git a/src/pt-tls-client/pt-tls-client.c b/src/pt-tls-client/pt-tls-client.c
index 8b41ae25e..a8d45b54f 100644
--- a/src/pt-tls-client/pt-tls-client.c
+++ b/src/pt-tls-client/pt-tls-client.c
@@ -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)))
{
diff --git a/src/swanctl/Makefile.am b/src/swanctl/Makefile.am
index 385737ad4..dec7d62ed 100644
--- a/src/swanctl/Makefile.am
+++ b/src/swanctl/Makefile.am
@@ -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 = \
diff --git a/src/swanctl/command.c b/src/swanctl/command.c
index e488273bf..dbe16c3b7 100644
--- a/src/swanctl/command.c
+++ b/src/swanctl/command.c
@@ -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);
}
}
diff --git a/src/swanctl/command.h b/src/swanctl/command.h
index 8510fa44d..2d78a24da 100644
--- a/src/swanctl/command.h
+++ b/src/swanctl/command.h
@@ -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
index 000000000..f47fee5b4
--- /dev/null
+++ b/src/swanctl/commands/load_all.c
@@ -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"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/load_conns.c b/src/swanctl/commands/load_conns.c
index 7383f7a1e..de30d8eb4 100644
--- a/src/swanctl/commands/load_conns.c
+++ b/src/swanctl/commands/load_conns.c
@@ -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
index 000000000..1e7abdea4
--- /dev/null
+++ b/src/swanctl/commands/load_conns.h
@@ -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);
diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c
index f77084c60..86ee3c179 100644
--- a/src/swanctl/commands/load_creds.c
+++ b/src/swanctl/commands/load_creds.c
@@ -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
index 000000000..7f689ad71
--- /dev/null
+++ b/src/swanctl/commands/load_creds.h
@@ -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);
diff --git a/src/swanctl/commands/load_pools.c b/src/swanctl/commands/load_pools.c
index 0ec56cc43..d7fbd1341 100644
--- a/src/swanctl/commands/load_pools.c
+++ b/src/swanctl/commands/load_pools.c
@@ -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
index 000000000..f424db9f1
--- /dev/null
+++ b/src/swanctl/commands/load_pools.h
@@ -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
index 000000000..ecd633866
--- /dev/null
+++ b/src/swanctl/commands/reload_settings.c
@@ -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"},
+ }
+ });
+}
diff --git a/src/swanctl/swanctl.8.in b/src/swanctl/swanctl.8.in
index d5f4fc631..543c10a67 100644
--- a/src/swanctl/swanctl.8.in
+++ b/src/swanctl/swanctl.8.in
@@ -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