diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index 19142d894..477e1e0c4 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -17,11 +17,29 @@ #include #include #include -#include +#include +#include #include #include #include +#include +#include + +#include "xpc_dispatch.h" + +/** + * XPC dispatcher class + */ +static xpc_dispatch_t *dispatcher; + +/** + * atexit() cleanup for dispatcher + */ +void dispatcher_cleanup() +{ + DESTROY_IF(dispatcher); +} /** * Loglevel configuration @@ -51,97 +69,57 @@ static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) } /** - * Return version of this helper + * Run the daemon and handle unix signals */ -xpc_object_t get_version(xpc_object_t request, xpc_connection_t client) +static int run() { - xpc_object_t reply; + sigset_t set; - reply = xpc_dictionary_create_reply(request); - xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, NULL); - return reply; + while (TRUE) + { + int sig; + + if (sigwait(&set, &sig)) + { + DBG1(DBG_DMN, "error while waiting for a signal"); + return 1; + } + switch (sig) + { + case SIGINT: + DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return 0; + case SIGTERM: + DBG1(DBG_DMN, "signal of type 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; + } + } } /** - * XPC command dispatch table + * Handle SIGSEGV/SIGILL signals raised by threads */ -struct { - char *name; - xpc_object_t (*handler)(xpc_object_t request, xpc_connection_t client); -} commands[] = { - { "get_version", get_version }, -}; - -/** - * Handle a received XPC request message - */ -static void handle(xpc_object_t request) +static void segv_handler(int signal) { - xpc_connection_t client; - xpc_object_t reply; - const char *command; - int i; + backtrace_t *backtrace; - client = xpc_dictionary_get_remote_connection(request); - command = xpc_dictionary_get_string(request, "command"); - if (command) - { - for (i = 0; i < countof(commands); i++) - { - if (streq(commands[i].name, command)) - { - reply = commands[i].handler(request, client); - if (reply) - { - xpc_connection_send_message(client, reply); - xpc_release(reply); - } - break; - } - } - } -} + DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); + backtrace = backtrace_create(2); + backtrace->log(backtrace, NULL, TRUE); + backtrace->destroy(backtrace); -/** - * Dispatch XPC commands - */ -static int dispatch() -{ - xpc_connection_t service; - - service = xpc_connection_create_mach_service("org.strongswan.charon-xpc", - NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); - if (!service) - { - return EXIT_FAILURE; - } - - xpc_connection_set_event_handler(service, ^(xpc_object_t conn) { - - xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { - - if (xpc_get_type(event) == XPC_TYPE_ERROR) - { - if (event == XPC_ERROR_CONNECTION_INVALID || - event == XPC_ERROR_TERMINATION_IMMINENT) - { - xpc_connection_cancel(conn); - } - } - else - { - handle(event); - } - }); - xpc_connection_resume(conn); - }); - - xpc_connection_resume(service); - - dispatch_main(); - - xpc_release(service); + DBG1(DBG_DMN, "killing ourself, received critical signal"); + abort(); } /** @@ -149,6 +127,7 @@ static int dispatch() */ int main(int argc, char *argv[]) { + struct sigaction action; struct utsname utsname; int group; @@ -184,9 +163,9 @@ int main(int argc, char *argv[]) lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); if (!charon->initialize(charon, - lib->settings->get_str(lib->settings, "charon-xpc.load", - "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " - "socket-default eap-identity eap-mschapv2"))) + lib->settings->get_str(lib->settings, "charon-xpc.load", + "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " + "socket-default eap-identity eap-mschapv2"))) { exit(SS_RC_INITIALIZATION_FAILED); } @@ -198,6 +177,29 @@ int main(int argc, char *argv[]) DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)", VERSION, utsname.sysname, utsname.release, utsname.machine); + /* 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); + + dispatcher = xpc_dispatch_create(); + if (!dispatcher) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(dispatcher_cleanup); + charon->start(charon); - return dispatch(); + return run(); } diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c new file mode 100644 index 000000000..3ade31060 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -0,0 +1,168 @@ +/* + * 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 . + * + * 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 "xpc_dispatch.h" + +#include + +#include +#include + +typedef struct private_xpc_dispatch_t private_xpc_dispatch_t; + +/** + * Private data of an xpc_dispatch_t object. + */ +struct private_xpc_dispatch_t { + + /** + * Public xpc_dispatch_t interface. + */ + xpc_dispatch_t public; + + /** + * XPC service we offer + */ + xpc_connection_t service; + + /** + * GCD queue for XPC events + */ + dispatch_queue_t queue; +}; + +/** + * Return version of this helper + */ +static xpc_object_t get_version(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_connection_t client) +{ + xpc_object_t reply; + + reply = xpc_dictionary_create_reply(request); + xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); + + return reply; +} + +/** + * XPC command dispatch table + */ +static struct { + char *name; + xpc_object_t (*handler)(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_connection_t client); +} commands[] = { + { "get_version", get_version }, +}; + +/** + * Handle a received XPC request message + */ +static void handle(private_xpc_dispatch_t *this, xpc_object_t request) +{ + xpc_connection_t client; + xpc_object_t reply; + const char *command; + int i; + + client = xpc_dictionary_get_remote_connection(request); + command = xpc_dictionary_get_string(request, "command"); + if (command) + { + for (i = 0; i < countof(commands); i++) + { + if (streq(commands[i].name, command)) + { + reply = commands[i].handler(this, request, client); + if (reply) + { + xpc_connection_send_message(client, reply); + xpc_release(reply); + } + break; + } + } + } +} + +/** + * Set up GCD handler for XPC events + */ +static void set_handler(private_xpc_dispatch_t *this) +{ + xpc_connection_set_event_handler(this->service, ^(xpc_object_t conn) { + + xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { + + if (xpc_get_type(event) == XPC_TYPE_ERROR) + { + if (event == XPC_ERROR_CONNECTION_INVALID || + event == XPC_ERROR_TERMINATION_IMMINENT) + { + xpc_connection_cancel(conn); + } + } + else + { + handle(this, event); + } + }); + + xpc_connection_resume(conn); + }); + + xpc_connection_resume(this->service); +} + +METHOD(xpc_dispatch_t, destroy, void, + private_xpc_dispatch_t *this) +{ + if (this->service) + { + xpc_connection_suspend(this->service); + xpc_connection_cancel(this->service); + } + free(this); +} + +/** + * See header + */ +xpc_dispatch_t *xpc_dispatch_create() +{ + private_xpc_dispatch_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .queue = dispatch_queue_create("org.strongswan.charon-xpc.q", + DISPATCH_QUEUE_CONCURRENT), + ); + + this->service = xpc_connection_create_mach_service( + "org.strongswan.charon-xpc", this->queue, + XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!this->service) + { + destroy(this); + return NULL; + } + + set_handler(this); + + return &this->public; +} diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.h b/src/frontends/osx/charon-xpc/xpc_dispatch.h new file mode 100644 index 000000000..9f40e6027 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.h @@ -0,0 +1,42 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup xpc_dispatch xpc_dispatch + * @{ @ingroup xpc + */ + +#ifndef XPC_DISPATCH_H_ +#define XPC_DISPATCH_H_ + +typedef struct xpc_dispatch_t xpc_dispatch_t; + +/** + * XPC dispatcher to control the daemon. + */ +struct xpc_dispatch_t { + + /** + * Destroy a xpc_dispatch_t. + */ + void (*destroy)(xpc_dispatch_t *this); +}; + +/** + * Create a xpc_dispatch instance. + */ +xpc_dispatch_t *xpc_dispatch_create(); + +#endif /** XPC_DISPATCH_H_ @}*/ diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 88ee1fb49..8cf467a1e 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -10,9 +10,12 @@ 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; + 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5B74984C172AA3550041971E /* xpc_dispatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_dispatch.c; sourceTree = ""; }; + 5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = ""; }; 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; @@ -70,6 +73,8 @@ 5BD1CCD61726DB4000587077 /* charon-xpc.c */, 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */, 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */, + 5B74984C172AA3550041971E /* xpc_dispatch.c */, + 5B74984E172AA3670041971E /* xpc_dispatch.h */, ); path = "charon-xpc"; sourceTree = ""; @@ -125,6 +130,7 @@ buildActionMask = 2147483647; files = ( 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */, + 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };