diff options
Diffstat (limited to 'src/libcharon/daemon.c')
-rw-r--r-- | src/libcharon/daemon.c | 457 |
1 files changed, 55 insertions, 402 deletions
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index dfb2ee38d..be9672f7d 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Tobias Brunner + * Copyright (C) 2006-2010 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -17,22 +17,10 @@ */ #include <stdio.h> -#ifdef HAVE_PRCTL -#include <sys/prctl.h> -#endif -#define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */ -#include <signal.h> -#undef _POSIX_PTHREAD_SEMANTICS -#include <pthread.h> -#include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <time.h> -#include <string.h> -#include <getopt.h> #include <errno.h> -#include <pwd.h> -#include <grp.h> #ifdef CAPABILITIES #include <sys/capability.h> #endif /* CAPABILITIES */ @@ -40,8 +28,6 @@ #include "daemon.h" #include <library.h> -#include <utils/backtrace.h> -#include <threading/thread.h> #include <selectors/traffic_selector.h> #include <config/proposal.h> @@ -60,11 +46,6 @@ struct private_daemon_t { */ daemon_t public; - /** - * Signal set used for signal handling. - */ - sigset_t signal_set; - #ifdef CAPABILITIES /** * capabilities to keep @@ -84,6 +65,11 @@ daemon_t *charon; extern void (*dbg) (int level, char *fmt, ...); /** + * we store the previous debug function so we can reset it + */ +static void (*dbg_old) (int level, char *fmt, ...); + +/** * Logging hook for library logs, spreads debug message over bus */ static void dbg_bus(int level, char *fmt, ...) @@ -96,76 +82,6 @@ static void dbg_bus(int level, char *fmt, ...) } /** - * Logging hook for library logs, using stderr output - */ -static void dbg_stderr(int level, char *fmt, ...) -{ - va_list args; - - if (level <= 1) - { - va_start(args, fmt); - fprintf(stderr, "00[LIB] "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); - } -} - -/** - * Run the daemon and handle unix signals - */ -static void run(private_daemon_t *this) -{ - sigset_t set; - - /* handle SIGINT, SIGHUP ans SIGTERM in this handler */ - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGHUP); - 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 SIGHUP: - { - DBG1(DBG_DMN, "signal of type SIGHUP received. Ignored"); - break; - } - 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; - } - } - } -} - -/** * Clean up all daemon resources */ static void destroy(private_daemon_t *this) @@ -205,7 +121,7 @@ static void destroy(private_daemon_t *this) DESTROY_IF(this->public.processor); /* rehook library logging, shutdown logging */ - dbg = dbg_stderr; + dbg = dbg_old; DESTROY_IF(this->public.bus); this->public.file_loggers->destroy_offset(this->public.file_loggers, offsetof(file_logger_t, destroy)); @@ -214,40 +130,8 @@ static void destroy(private_daemon_t *this) free(this); } -/** - * drop daemon capabilities - */ -static bool drop_capabilities(private_daemon_t *this) -{ -#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; - } - -#ifdef CAPABILITIES - if (cap_set_proc(this->caps) != 0) - { - DBG1(DBG_DMN, "unable to drop daemon capabilities"); - return FALSE; - } -#endif /* CAPABILITIES */ - return TRUE; -} - -/** - * Implementation of daemon_t.keep_cap - */ -static void keep_cap(private_daemon_t *this, u_int cap) +METHOD(daemon_t, keep_cap, void, + private_daemon_t *this, u_int cap) { #ifdef CAPABILITIES cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); @@ -256,42 +140,27 @@ static void keep_cap(private_daemon_t *this, u_int cap) #endif /* CAPABILITIES */ } -/** - * lookup UID and GID - */ -static bool lookup_uid_gid(private_daemon_t *this) +METHOD(daemon_t, drop_capabilities, bool, + private_daemon_t *this) { -#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 +#ifdef CAPABILITIES + if (cap_set_proc(this->caps) != 0) { - 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; + return FALSE; } -#endif +#endif /* CAPABILITIES */ return TRUE; } +METHOD(daemon_t, start, void, + private_daemon_t *this) +{ + /* start the engine, go multithreaded */ + charon->processor->set_threads(charon->processor, + lib->settings->get_int(lib->settings, "charon.threads", + DEFAULT_THREADS)); +} + /** * Log loaded plugins */ @@ -434,10 +303,8 @@ static void initialize_loggers(private_daemon_t *this, bool use_stderr, } } -/** - * Initialize the daemon - */ -static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) +METHOD(daemon_t, initialize, bool, + private_daemon_t *this, bool syslog, level_t levels[]) { /* for uncritical pseudo random numbers */ srandom(time(NULL) + getpid()); @@ -445,6 +312,7 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) /* setup bus and it's listeners first to enable log output */ this->public.bus = bus_create(); /* set up hook to log dbg message in library via charons message bus */ + dbg_old = dbg; dbg = dbg_bus; initialize_loggers(this, !syslog, levels); @@ -455,6 +323,7 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) { DBG1(DBG_DMN, "integrity tests enabled:"); DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); + DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); DBG1(DBG_DMN, "daemon 'charon': passed file integrity test"); } @@ -504,55 +373,22 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) } /** - * 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); - backtrace->destroy(backtrace); - - DBG1(DBG_DMN, "killing ourself, received critical signal"); - abort(); -} - -/** * Create the daemon. */ -private_daemon_t *daemon_create(void) +private_daemon_t *daemon_create() { - struct sigaction action; - private_daemon_t *this = malloc_thing(private_daemon_t); - - /* assign methods */ - this->public.keep_cap = (void(*)(daemon_t*, u_int cap))keep_cap; - - /* NULL members for clean destruction */ - this->public.socket = NULL; - this->public.ike_sa_manager = NULL; - this->public.traps = NULL; - this->public.credentials = NULL; - this->public.backends = NULL; - this->public.sender= NULL; - this->public.receiver = NULL; - this->public.scheduler = NULL; - this->public.kernel_interface = NULL; - this->public.processor = NULL; - this->public.controller = NULL; - this->public.eap = NULL; - this->public.sim = NULL; - this->public.bus = NULL; - this->public.file_loggers = linked_list_create(); - this->public.sys_loggers = linked_list_create(); -#ifdef ME - this->public.connect_manager = NULL; - this->public.mediation_manager = NULL; -#endif /* ME */ - this->public.uid = 0; - this->public.gid = 0; + private_daemon_t *this; + + INIT(this, + .public = { + .keep_cap = _keep_cap, + .drop_capabilities = _drop_capabilities, + .initialize = _initialize, + .start = _start, + .file_loggers = linked_list_create(), + .sys_loggers = linked_list_create(), + }, + ); #ifdef CAPABILITIES this->caps = cap_init(); @@ -563,116 +399,28 @@ private_daemon_t *daemon_create(void) } #endif /* CAPABILITIES */ - /* 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); - return this; } /** - * Check/create PID file, return TRUE if already running + * Described in header. */ -static bool check_pidfile() +void libcharon_deinit() { - struct stat stb; - FILE *file; - - if (stat(PID_FILE, &stb) == 0) - { - file = fopen(PID_FILE, "r"); - if (file) - { - char buf[64]; - pid_t pid = 0; - - memset(buf, 0, sizeof(buf)); - if (fread(buf, 1, sizeof(buf), file)) - { - pid = atoi(buf); - } - fclose(file); - if (pid && kill(pid, 0) == 0) - { /* such a process is running */ - return TRUE; - } - } - DBG1(DBG_DMN, "removing pidfile '"PID_FILE"', process not running"); - unlink(PID_FILE); - } - /* create new pidfile */ - file = fopen(PID_FILE, "w"); - if (file) - { - fprintf(file, "%d\n", getpid()); - ignore_result(fchown(fileno(file), charon->uid, charon->gid)); - fclose(file); - } - return FALSE; -} - -/** - * print command line usage and exit - */ -static void usage(const char *msg) -{ - if (msg != NULL && *msg != '\0') - { - fprintf(stderr, "%s\n", msg); - } - fprintf(stderr, "Usage: charon\n" - " [--help]\n" - " [--version]\n" - " [--use-syslog]\n" - " [--debug-<type> <level>]\n" - " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib)\n" - " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n" - " 2 = controlmore, 3 = raw, 4 = private)\n" - "\n" - ); - exit(msg == NULL? 0 : 1); + destroy((private_daemon_t*)charon); + charon = NULL; } /** - * Main function, manages the daemon. + * Described in header. */ -int main(int argc, char *argv[]) +bool libcharon_init() { - bool use_syslog = FALSE; - private_daemon_t *private_charon; - level_t levels[DBG_MAX]; - int group; + private_daemon_t *this; - /* logging for library during initialization, as we have no bus yet */ - dbg = dbg_stderr; - - /* initialize library */ - if (!library_init(NULL)) - { - library_deinit(); - exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); - } - - if (lib->integrity && - !lib->integrity->check_file(lib->integrity, "charon", argv[0])) - { - dbg_stderr(1, "integrity check of charon failed"); - library_deinit(); - exit(SS_RC_DAEMON_INTEGRITY); - } + this = daemon_create(); + charon = &this->public; lib->printf_hook->add_handler(lib->printf_hook, 'R', traffic_selector_printf_hook, @@ -682,108 +430,13 @@ int main(int argc, char *argv[]) proposal_printf_hook, PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END); - private_charon = daemon_create(); - charon = (daemon_t*)private_charon; - - /* use CTRL loglevel for default */ - for (group = 0; group < DBG_MAX; group++) - { - levels[group] = LEVEL_CTRL; - } - - /* handle arguments */ - for (;;) - { - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { "use-syslog", no_argument, NULL, 'l' }, - /* TODO: handle "debug-all" */ - { "debug-dmn", required_argument, &group, DBG_DMN }, - { "debug-mgr", required_argument, &group, DBG_MGR }, - { "debug-ike", required_argument, &group, DBG_IKE }, - { "debug-chd", required_argument, &group, DBG_CHD }, - { "debug-job", required_argument, &group, DBG_JOB }, - { "debug-cfg", required_argument, &group, DBG_CFG }, - { "debug-knl", required_argument, &group, DBG_KNL }, - { "debug-net", required_argument, &group, DBG_NET }, - { "debug-enc", required_argument, &group, DBG_ENC }, - { "debug-lib", required_argument, &group, DBG_LIB }, - { 0,0,0,0 } - }; - - int c = getopt_long(argc, argv, "", long_opts, NULL); - switch (c) - { - case EOF: - break; - case 'h': - usage(NULL); - break; - case 'v': - printf("Linux strongSwan %s\n", VERSION); - exit(0); - case 'l': - use_syslog = TRUE; - continue; - case 0: - /* option is in group */ - levels[group] = atoi(optarg); - continue; - default: - usage(""); - break; - } - break; - } - - if (!lookup_uid_gid(private_charon)) - { - DBG1(DBG_DMN, "invalid uid/gid - aborting charon"); - destroy(private_charon); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); - } - - /* initialize daemon */ - if (!initialize(private_charon, use_syslog, levels)) - { - DBG1(DBG_DMN, "initialization failed - aborting charon"); - destroy(private_charon); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); - } - - if (check_pidfile()) - { - DBG1(DBG_DMN, "charon already running (\""PID_FILE"\" exists)"); - destroy(private_charon); - library_deinit(); - exit(-1); - } - if (!drop_capabilities(private_charon)) + if (lib->integrity && + !lib->integrity->check(lib->integrity, "libcharon", libcharon_init)) { - DBG1(DBG_DMN, "capability dropping failed - aborting charon"); - destroy(private_charon); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); + dbg(1, "integrity check of libcharon failed"); + return FALSE; } - /* start the engine, go multithreaded */ - charon->processor->set_threads(charon->processor, - lib->settings->get_int(lib->settings, "charon.threads", - DEFAULT_THREADS)); - - /* run daemon */ - run(private_charon); - - /* normal termination, cleanup and exit */ - destroy(private_charon); - unlink(PID_FILE); - - library_deinit(); - - return 0; + return TRUE; } - |