aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac9
-rw-r--r--src/Makefile.am4
-rw-r--r--src/charon-svc/Makefile.am16
-rw-r--r--src/charon-svc/charon-svc.c264
4 files changed, 290 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index e3e4f881a..4eda8eec4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -266,6 +266,7 @@ ARG_ENABL_SET([medcli], [enable mediation client configuration database
ARG_ENABL_SET([medsrv], [enable mediation server web frontend and daemon plugin.])
ARG_ENABL_SET([nm], [enable NetworkManager backend.])
ARG_DISBL_SET([scripts], [disable additional utilities (found in directory scripts).])
+ARG_ENABL_SET([svc], [enable charon Windows service.])
ARG_ENABL_SET([swanctl], [enable swanctl configuration and control tool.])
ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.])
ARG_DISBL_SET([tools], [disable additional utilities (scepclient and pki).])
@@ -1400,9 +1401,9 @@ 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$tools = 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)
-AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = 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)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = 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_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)
@@ -1426,6 +1427,7 @@ AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
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)
# ========================
# set global definitions
@@ -1565,6 +1567,7 @@ AC_CONFIG_FILES([
src/charon-nm/Makefile
src/charon-tkm/Makefile
src/charon-cmd/Makefile
+ src/charon-svc/Makefile
src/libcharon/Makefile
src/libcharon/plugins/eap_aka/Makefile
src/libcharon/plugins/eap_aka_3gpp2/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 38e4b834d..89c059255 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -116,6 +116,10 @@ if USE_CMD
SUBDIRS += charon-cmd
endif
+if USE_SVC
+ SUBDIRS += charon-svc
+endif
+
if USE_LIBPTTLS
SUBDIRS += pt-tls-client
endif
diff --git a/src/charon-svc/Makefile.am b/src/charon-svc/Makefile.am
new file mode 100644
index 000000000..ecccf02f5
--- /dev/null
+++ b/src/charon-svc/Makefile.am
@@ -0,0 +1,16 @@
+bin_PROGRAMS = charon-svc
+
+charon_svc_SOURCES = charon-svc.c
+
+charon-svc.o : $(top_builddir)/config.status
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon \
+ -DPLUGINS=\""${charon_plugins}\""
+
+charon_svc_LDADD = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ $(top_builddir)/src/libhydra/libhydra.la \
+ $(top_builddir)/src/libcharon/libcharon.la
diff --git a/src/charon-svc/charon-svc.c b/src/charon-svc/charon-svc.c
new file mode 100644
index 000000000..3f4b80dce
--- /dev/null
+++ b/src/charon-svc/charon-svc.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 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 <library.h>
+#include <hydra.h>
+#include <daemon.h>
+
+#include <utils/backtrace.h>
+#include <threading/thread.h>
+
+/**
+ * The name of our service, both internal and external
+ */
+#define SERVICE_NAME "charon-svc"
+
+/**
+ * Current service status
+ */
+static SERVICE_STATUS status;
+
+/**
+ * Handle for service status
+ */
+static SERVICE_STATUS_HANDLE handle;
+
+/**
+ * Wait event for main thread
+ */
+static HANDLE event;
+
+/**
+ * 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);
+ }
+}
+
+/**
+ * Log strongSwan/Windows version during startup
+ */
+static void print_version()
+{
+ OSVERSIONINFOEX osvie;
+
+ memset(&osvie, 0, sizeof(osvie));
+ osvie.dwOSVersionInfoSize = sizeof(osvie);
+
+ if (GetVersionEx((LPOSVERSIONINFO)&osvie))
+ {
+ DBG1(DBG_DMN, "Starting IKE service %s (strongSwan %s, "
+ "Windows %s %d.%d.%d (SP %d.%d)", SERVICE_NAME, VERSION,
+ osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server",
+ osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
+ osvie.wServicePackMajor, osvie.wServicePackMinor);
+ }
+}
+
+/**
+ * Update service state to SCM, increase check point if state didn't change
+ */
+static void update_status(DWORD state)
+{
+ if (state == status.dwCurrentState)
+ {
+ status.dwCheckPoint++;
+ }
+ else
+ {
+ status.dwCheckPoint = 0;
+ }
+ status.dwCurrentState = state;
+ if (handle)
+ {
+ SetServiceStatus(handle, &status);
+ }
+}
+
+/**
+ * Initialize and run charon
+ */
+static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ level_t levels[DBG_MAX];
+ int i;
+
+ for (i = 0; i < DBG_MAX; i++)
+ {
+ levels[i] = LEVEL_CTRL;
+ }
+
+ update_status(SERVICE_START_PENDING);
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event)
+ {
+ update_status(SERVICE_START_PENDING);
+ if (library_init(NULL, SERVICE_NAME))
+ {
+ update_status(SERVICE_START_PENDING);
+ if (libhydra_init())
+ {
+ update_status(SERVICE_START_PENDING);
+ if (libcharon_init())
+ {
+ charon->load_loggers(charon, levels, TRUE);
+ print_version();
+ update_status(SERVICE_START_PENDING);
+ if (charon->initialize(charon, PLUGINS))
+ {
+ update_status(SERVICE_START_PENDING);
+ lib->plugins->status(lib->plugins, LEVEL_CTRL);
+
+ charon->start(charon);
+
+ status.dwWin32ExitCode = 0;
+ update_status(SERVICE_RUNNING);
+
+ /* main thread goes to sleep */
+ WaitForSingleObjectEx(event, INFINITE, TRUE);
+ }
+ update_status(SERVICE_STOP_PENDING);
+ libcharon_deinit();
+ }
+ update_status(SERVICE_STOP_PENDING);
+ libhydra_deinit();
+ }
+ update_status(SERVICE_STOP_PENDING);
+ library_deinit();
+ }
+ update_status(SERVICE_STOP_PENDING);
+ CloseHandle(event);
+ }
+ update_status(SERVICE_STOPPED);
+}
+
+/**
+ * Control handler for console
+ */
+static BOOL console_handler(DWORD dwCtrlType)
+{
+ switch (dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ DBG1(DBG_DMN, "application is stopping, cleaning up");
+ charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, dwCtrlType);
+ /* signal main thread to clean up */
+ SetEvent(event);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ * Main routine when running from console
+ */
+static void console_main(DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ status.dwWin32ExitCode = 1;
+
+ if (SetConsoleCtrlHandler(console_handler, TRUE))
+ {
+ init_and_run(dwArgc, lpszArgv);
+ SetConsoleCtrlHandler(console_handler, FALSE);
+ }
+}
+
+/**
+ * Service handler function
+ */
+static DWORD service_handler(DWORD dwControl, DWORD dwEventType,
+ LPVOID lpEventData, LPVOID lpContext)
+{
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ DBG1(DBG_DMN, "service is stopping, cleaning up");
+ charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, dwControl);
+ /* signal main thread to clean up */
+ SetEvent(event);
+ return NO_ERROR;
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+/**
+ * Service main routine when running as service
+ */
+static void service_main(DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ memset(&status, 0, sizeof(status));
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ status.dwWin32ExitCode = 1;
+
+ handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, service_handler, NULL);
+ if (handle)
+ {
+ init_and_run(dwArgc, lpszArgv);
+ }
+}
+
+/**
+ * Main function, starts the service
+ */
+int main(int argc, char *argv[])
+{
+ SERVICE_TABLE_ENTRY services[] = {
+ {
+ .lpServiceName = SERVICE_NAME,
+ .lpServiceProc = service_main,
+ },
+ { NULL, NULL },
+ };
+ DWORD err;
+
+ dbg = dbg_stderr;
+
+ if (!StartServiceCtrlDispatcher(services))
+ {
+ err = GetLastError();
+ if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
+ {
+ console_main(argc, argv);
+ }
+ else
+ {
+ return 2;
+ }
+ }
+ return status.dwWin32ExitCode;
+}