Added a small libcharon wrapper intended to directly host the nm plugin.
authorTobias Brunner <tobias@strongswan.org>
Thu, 19 Apr 2012 14:35:44 +0000 (16:35 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 3 May 2012 11:38:14 +0000 (13:38 +0200)
For this reason it reclaims the --enable-nm configure option.

configure.in
src/Makefile.am
src/charon-nm/Makefile.am [new file with mode: 0644]
src/charon-nm/charon-nm.c [new file with mode: 0644]

index 69bc604..786d47c 100755 (executable)
@@ -190,7 +190,7 @@ ARG_ENABL_SET([addrblock],      [enables RFC 3779 address block constraint suppo
 ARG_ENABL_SET([uci],            [enable OpenWRT UCI configuration plugin.])
 ARG_ENABL_SET([android],        [enable Android specific plugin.])
 ARG_ENABL_SET([maemo],          [enable Maemo specific plugin.])
-ARG_ENABL_SET([nm],             [enable NetworkManager plugin.])
+ARG_ENABL_SET([nm],             [enable NetworkManager backend.])
 ARG_ENABL_SET([ha],             [enable high availability cluster plugin.])
 ARG_ENABL_SET([whitelist],      [enable peer identity whitelisting plugin.])
 ARG_ENABL_SET([certexpire],     [enable CSV export of expiration dates of used certificates.])
@@ -798,6 +798,7 @@ pki_plugins=
 scripts_plugins=
 manager_plugins=
 medsrv_plugins=
+nm_plugins=
 
 # location specific lists for checksumming,
 # for src/libcharon, src/pluto, src/libhydra and src/libstrongswan
@@ -807,60 +808,60 @@ h_plugins=
 s_plugins=
 
 ADD_PLUGIN([test-vectors],         [s charon pluto openac scepclient pki])
-ADD_PLUGIN([curl],                 [s charon pluto scepclient scripts])
-ADD_PLUGIN([soup],                 [s charon pluto scripts])
-ADD_PLUGIN([ldap],                 [s charon pluto scepclient scripts])
+ADD_PLUGIN([curl],                 [s charon pluto scepclient scripts nm])
+ADD_PLUGIN([soup],                 [s charon pluto scripts nm])
+ADD_PLUGIN([ldap],                 [s charon pluto scepclient scripts nm])
 ADD_PLUGIN([mysql],                [s charon pluto pool manager medsrv attest])
 ADD_PLUGIN([sqlite],               [s charon pluto pool manager medsrv attest])
-ADD_PLUGIN([pkcs11],               [s charon pki])
-ADD_PLUGIN([aes],                  [s charon pluto openac scepclient pki scripts])
-ADD_PLUGIN([des],                  [s charon pluto openac scepclient pki scripts])
-ADD_PLUGIN([blowfish],             [s charon pluto openac scepclient pki scripts])
-ADD_PLUGIN([sha1],                 [s charon pluto openac scepclient pki scripts medsrv attest])
-ADD_PLUGIN([sha2],                 [s charon pluto openac scepclient pki scripts medsrv attest])
-ADD_PLUGIN([md4],                  [s charon openac manager scepclient pki])
-ADD_PLUGIN([md5],                  [s charon pluto openac scepclient pki scripts attest])
-ADD_PLUGIN([random],               [s charon pluto openac scepclient pki scripts medsrv attest])
-ADD_PLUGIN([x509],                 [s charon pluto openac scepclient pki scripts attest])
-ADD_PLUGIN([revocation],           [s charon])
-ADD_PLUGIN([constraints],          [s charon])
+ADD_PLUGIN([pkcs11],               [s charon pki nm])
+ADD_PLUGIN([aes],                  [s charon pluto openac scepclient pki scripts nm])
+ADD_PLUGIN([des],                  [s charon pluto openac scepclient pki scripts nm])
+ADD_PLUGIN([blowfish],             [s charon pluto openac scepclient pki scripts nm])
+ADD_PLUGIN([sha1],                 [s charon pluto openac scepclient pki scripts medsrv attest nm])
+ADD_PLUGIN([sha2],                 [s charon pluto openac scepclient pki scripts medsrv attest nm])
+ADD_PLUGIN([md4],                  [s charon openac manager scepclient pki nm])
+ADD_PLUGIN([md5],                  [s charon pluto openac scepclient pki scripts attest nm])
+ADD_PLUGIN([random],               [s charon pluto openac scepclient pki scripts medsrv attest nm])
+ADD_PLUGIN([x509],                 [s charon pluto openac scepclient pki scripts attest nm])
+ADD_PLUGIN([revocation],           [s charon nm])
+ADD_PLUGIN([constraints],          [s charon nm])
 ADD_PLUGIN([pubkey],               [s charon])
-ADD_PLUGIN([pkcs1],                [s charon pluto openac scepclient pki scripts manager medsrv attest])
-ADD_PLUGIN([pkcs8],                [s charon pluto openac scepclient pki scripts manager medsrv attest])
+ADD_PLUGIN([pkcs1],                [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
+ADD_PLUGIN([pkcs8],                [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
 ADD_PLUGIN([pgp],                  [s charon pluto])
 ADD_PLUGIN([dnskey],               [s pluto])
-ADD_PLUGIN([pem],                  [s charon pluto openac scepclient pki scripts manager medsrv attest])
+ADD_PLUGIN([pem],                  [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
 ADD_PLUGIN([padlock],              [s charon])
-ADD_PLUGIN([openssl],              [s charon pluto openac scepclient pki scripts manager medsrv attest])
-ADD_PLUGIN([gcrypt],               [s charon pluto openac scepclient pki scripts manager medsrv attest])
-ADD_PLUGIN([af-alg],               [s charon pluto openac scepclient pki scripts medsrv attest])
-ADD_PLUGIN([fips-prf],             [s charon])
-ADD_PLUGIN([gmp],                  [s charon pluto openac scepclient pki scripts manager medsrv attest])
-ADD_PLUGIN([agent],                [s charon])
-ADD_PLUGIN([xcbc],                 [s charon])
-ADD_PLUGIN([cmac],                 [s charon])
-ADD_PLUGIN([hmac],                 [s charon pluto scripts])
-ADD_PLUGIN([ctr],                  [s charon scripts])
-ADD_PLUGIN([ccm],                  [s charon scripts])
-ADD_PLUGIN([gcm],                  [s charon scripts])
+ADD_PLUGIN([openssl],              [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
+ADD_PLUGIN([gcrypt],               [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
+ADD_PLUGIN([af-alg],               [s charon pluto openac scepclient pki scripts medsrv attest nm])
+ADD_PLUGIN([fips-prf],             [s charon nm])
+ADD_PLUGIN([gmp],                  [s charon pluto openac scepclient pki scripts manager medsrv attest nm])
+ADD_PLUGIN([agent],                [s charon nm])
+ADD_PLUGIN([xcbc],                 [s charon nm])
+ADD_PLUGIN([cmac],                 [s charon nm])
+ADD_PLUGIN([hmac],                 [s charon pluto scripts nm])
+ADD_PLUGIN([ctr],                  [s charon scripts nm])
+ADD_PLUGIN([ccm],                  [s charon scripts nm])
+ADD_PLUGIN([gcm],                  [s charon scripts nm])
 ADD_PLUGIN([xauth],                [p pluto])
 ADD_PLUGIN([attr],                 [h charon pluto])
 ADD_PLUGIN([attr-sql],             [h charon pluto])
 ADD_PLUGIN([load-tester],          [c charon])
-ADD_PLUGIN([kernel-pfkey],         [h charon pluto starter])
-ADD_PLUGIN([kernel-pfroute],       [h charon pluto starter])
+ADD_PLUGIN([kernel-pfkey],         [h charon pluto starter nm])
+ADD_PLUGIN([kernel-pfroute],       [h charon pluto starter nm])
 ADD_PLUGIN([kernel-klips],         [h charon pluto starter])
-ADD_PLUGIN([kernel-netlink],       [h charon pluto starter])
+ADD_PLUGIN([kernel-netlink],       [h charon pluto starter nm])
 ADD_PLUGIN([resolve],              [h charon pluto])
-ADD_PLUGIN([socket-default],       [c charon])
-ADD_PLUGIN([socket-raw],           [c charon])
+ADD_PLUGIN([socket-default],       [c charon nm])
+ADD_PLUGIN([socket-raw],           [c charon nm])
 ADD_PLUGIN([socket-dynamic],       [c charon])
 ADD_PLUGIN([farp],                 [c charon])
 ADD_PLUGIN([stroke],               [c charon])
 ADD_PLUGIN([smp],                  [c charon])
 ADD_PLUGIN([sql],                  [c charon])
 ADD_PLUGIN([updown],               [c charon])
-ADD_PLUGIN([eap-identity],         [c charon])
+ADD_PLUGIN([eap-identity],         [c charon nm])
 ADD_PLUGIN([eap-sim],              [c charon])
 ADD_PLUGIN([eap-sim-file],         [c charon])
 ADD_PLUGIN([eap-sim-pcsc],         [c charon])
@@ -869,13 +870,13 @@ ADD_PLUGIN([eap-aka-3gpp2],        [c charon])
 ADD_PLUGIN([eap-simaka-sql],       [c charon])
 ADD_PLUGIN([eap-simaka-pseudonym], [c charon])
 ADD_PLUGIN([eap-simaka-reauth],    [c charon])
-ADD_PLUGIN([eap-md5],              [c charon])
-ADD_PLUGIN([eap-gtc],              [c charon])
-ADD_PLUGIN([eap-mschapv2],         [c charon])
+ADD_PLUGIN([eap-md5],              [c charon nm])
+ADD_PLUGIN([eap-gtc],              [c charon nm])
+ADD_PLUGIN([eap-mschapv2],         [c charon nm])
 ADD_PLUGIN([eap-radius],           [c charon])
-ADD_PLUGIN([eap-tls],              [c charon])
-ADD_PLUGIN([eap-ttls],             [c charon])
-ADD_PLUGIN([eap-peap],             [c charon])
+ADD_PLUGIN([eap-tls],              [c charon nm])
+ADD_PLUGIN([eap-ttls],             [c charon nm])
+ADD_PLUGIN([eap-peap],             [c charon nm])
 ADD_PLUGIN([eap-tnc],              [c charon])
 ADD_PLUGIN([xauth-generic],        [c charon])
 ADD_PLUGIN([xauth-eap],            [c charon])
@@ -915,6 +916,7 @@ AC_SUBST(pki_plugins)
 AC_SUBST(scripts_plugins)
 AC_SUBST(manager_plugins)
 AC_SUBST(medsrv_plugins)
+AC_SUBST(nm_plugins)
 
 AC_SUBST(c_plugins)
 AC_SUBST(p_plugins)
@@ -1061,12 +1063,13 @@ AM_CONDITIONAL(USE_IKEV2, test x$ikev2 = xtrue)
 AM_CONDITIONAL(USE_THREADS, test x$threads = xtrue)
 AM_CONDITIONAL(USE_ADNS, test x$adns = xtrue)
 AM_CONDITIONAL(USE_CHARON, test x$charon = xtrue)
+AM_CONDITIONAL(USE_NM, test x$nm = xtrue)
 AM_CONDITIONAL(USE_TOOLS, test x$tools = 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$pluto = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue)
-AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$pluto = xtrue)
-AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pluto = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue)
+AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$pluto = xtrue -o x$nm = xtrue)
+AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue)
 AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
 AM_CONDITIONAL(USE_FILE_CONFIG, test x$pluto = xtrue -o x$stroke = xtrue)
@@ -1175,6 +1178,7 @@ AC_OUTPUT(
        src/pluto/plugins/xauth/Makefile
        src/whack/Makefile
        src/charon/Makefile
+       src/charon-nm/Makefile
        src/libcharon/Makefile
        src/libcharon/plugins/eap_aka/Makefile
        src/libcharon/plugins/eap_aka_3gpp2/Makefile
index 1440de2..0c19ea3 100644 (file)
@@ -56,6 +56,10 @@ if USE_CHARON
   SUBDIRS += charon
 endif
 
+if USE_NM
+  SUBDIRS += charon-nm
+endif
+
 if USE_STROKE
   SUBDIRS += stroke
 endif
diff --git a/src/charon-nm/Makefile.am b/src/charon-nm/Makefile.am
new file mode 100644 (file)
index 0000000..41c94b7
--- /dev/null
@@ -0,0 +1,20 @@
+ipsec_PROGRAMS = charon-nm
+
+charon_nm_SOURCES = \
+charon-nm.c
+
+INCLUDES = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = \
+       -DIPSEC_DIR=\"${ipsecdir}\" \
+       -DIPSEC_PIDDIR=\"${piddir}\" \
+       -DPLUGINS=\""${nm_plugins}\""
+
+charon_nm_LDADD = \
+       $(top_builddir)/src/libstrongswan/libstrongswan.la \
+       $(top_builddir)/src/libhydra/libhydra.la \
+       $(top_builddir)/src/libcharon/libcharon.la \
+       -lm $(PTHREADLIB) $(DLLIB)
diff --git a/src/charon-nm/charon-nm.c b/src/charon-nm/charon-nm.c
new file mode 100644 (file)
index 0000000..8b73f6a
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_PRCTL
+#include <sys/prctl.h>
+#endif
+
+#include <hydra.h>
+#include <daemon.h>
+
+#include <library.h>
+#include <utils/backtrace.h>
+#include <threading/thread.h>
+
+/**
+ * Hook in library for debugging messages
+ */
+extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
+
+/**
+ * Simple logging hook for library logs, using syslog output
+ */
+static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
+{
+       if (level <= 1)
+       {
+               char buffer[8192], groupstr[4];
+               va_list args;
+
+               va_start(args, fmt);
+               /* write in memory buffer first */
+               vsnprintf(buffer, sizeof(buffer), fmt, args);
+               /* cache group name */
+               snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
+               syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", groupstr, buffer);
+               va_end(args);
+       }
+}
+
+/**
+ * Run the daemon and handle unix signals
+ */
+static void run()
+{
+       sigset_t set;
+
+       /* handle SIGINT and SIGTERM in this handler */
+       sigemptyset(&set);
+       sigaddset(&set, SIGINT);
+       sigaddset(&set, SIGTERM);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+
+       while (TRUE)
+       {
+               int sig;
+               int error;
+
+               error = sigwait(&set, &sig);
+               if (error)
+               {
+                       DBG1(DBG_DMN, "error %d while waiting for a signal", error);
+                       return;
+               }
+               switch (sig)
+               {
+                       case SIGINT:
+                       {
+                               DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
+                               charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
+                               return;
+                       }
+                       case SIGTERM:
+                       {
+                               DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
+                               charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
+                               return;
+                       }
+                       default:
+                       {
+                               DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
+                               break;
+                       }
+               }
+       }
+}
+
+/**
+ * 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, stderr, TRUE);
+       backtrace->destroy(backtrace);
+
+       DBG1(DBG_DMN, "killing ourself, received critical signal");
+       abort();
+}
+
+/**
+ * Initialize logging to syslog
+ */
+static void initialize_logger()
+{
+       sys_logger_t *sys_logger;
+       debug_t group;
+       level_t def;
+
+       sys_logger = sys_logger_create(LOG_DAEMON, FALSE);
+       def = lib->settings->get_int(lib->settings,
+                                                                "charon-nm.syslog.default", 1);
+       for (group = 0; group < DBG_MAX; group++)
+       {
+               sys_logger->set_level(sys_logger, group,
+                       lib->settings->get_int(lib->settings, "charon-nm.syslog.%N", def,
+                                                                  debug_lower_names, group));
+       }
+       charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger);
+       charon->bus->add_logger(charon->bus, &sys_logger->logger);
+}
+
+/**
+ * Lookup UID and GID
+ */
+static bool lookup_uid_gid()
+{
+#ifdef IPSEC_USER
+       {
+               char buf[1024];
+               struct passwd passwd, *pwp;
+
+               if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
+                       pwp == NULL)
+               {
+                       DBG1(DBG_DMN, "resolving user '"IPSEC_USER"' failed");
+                       return FALSE;
+               }
+               charon->uid = pwp->pw_uid;
+       }
+#endif
+#ifdef IPSEC_GROUP
+       {
+               char buf[1024];
+               struct group group, *grp;
+
+               if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
+                       grp == NULL)
+               {
+                       DBG1(DBG_DMN, "resolving group '"IPSEC_GROUP"' failed");
+                       return FALSE;
+               }
+               charon->gid = grp->gr_gid;
+       }
+#endif
+       return TRUE;
+}
+
+/**
+ * Drop process capabilities
+ */
+static bool drop_capabilities()
+{
+#ifdef HAVE_PRCTL
+       prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+#endif
+
+       if (setgid(charon->gid) != 0)
+       {
+               DBG1(DBG_DMN, "change to unprivileged group failed");
+               return FALSE;
+       }
+       if (setuid(charon->uid) != 0)
+       {
+               DBG1(DBG_DMN, "change to unprivileged user failed");
+               return FALSE;
+       }
+       if (!charon->drop_capabilities(charon))
+       {
+               DBG1(DBG_DMN, "unable to drop daemon capabilities");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Main function, starts NetworkManager backend.
+ */
+int main(int argc, char *argv[])
+{
+       struct sigaction action;
+       int status = SS_RC_INITIALIZATION_FAILED;
+
+       /* logging for library during initialization, as we have no bus yet */
+       dbg = dbg_syslog;
+
+       /* initialize library */
+       if (!library_init(NULL))
+       {
+               library_deinit();
+               exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+       }
+
+       if (lib->integrity &&
+               !lib->integrity->check_file(lib->integrity, "charon-nm", argv[0]))
+       {
+               dbg_syslog(DBG_DMN, 1, "integrity check of charon-nm failed");
+               library_deinit();
+               exit(SS_RC_DAEMON_INTEGRITY);
+       }
+
+       if (!libhydra_init("charon-nm"))
+       {
+               dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
+               libhydra_deinit();
+               library_deinit();
+               exit(SS_RC_INITIALIZATION_FAILED);
+       }
+
+       if (!libcharon_init())
+       {
+               dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
+               goto deinit;
+       }
+
+       if (!lookup_uid_gid())
+       {
+               dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting charon-nm");
+               goto deinit;
+       }
+
+       initialize_logger();
+
+       DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
+       if (lib->integrity)
+       {
+               DBG1(DBG_DMN, "integrity tests enabled:");
+               DBG1(DBG_DMN, "lib    'libstrongswan': passed file and segment integrity tests");
+               DBG1(DBG_DMN, "lib    'libhydra': passed file and segment integrity tests");
+               DBG1(DBG_DMN, "lib    'libcharon': passed file and segment integrity tests");
+               DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test");
+       }
+
+       /* initialize daemon */
+       if (!charon->initialize(charon,
+                       lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS)))
+       {
+               DBG1(DBG_DMN, "initialization failed - aborting charon-nm");
+               goto deinit;
+       }
+
+       if (!drop_capabilities())
+       {
+               DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm");
+               goto deinit;
+       }
+
+       /* add handler for SEGV and ILL,
+        * INT and TERM 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);
+       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);
+
+       /* start daemon (i.e. the threads in the thread-pool) */
+       charon->start(charon);
+
+       /* main thread goes to run loop */
+       run();
+
+       status = 0;
+
+deinit:
+       libcharon_deinit();
+       libhydra_deinit();
+       library_deinit();
+       return status;
+}
+