diff options
Diffstat (limited to 'src/starter/starter.c')
-rw-r--r-- | src/starter/starter.c | 488 |
1 files changed, 236 insertions, 252 deletions
diff --git a/src/starter/starter.c b/src/starter/starter.c index 44e21431c..c6efcb2f4 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -12,12 +12,14 @@ * for more details. */ +#include <sys/select.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> +#include <syslog.h> #include <unistd.h> #include <sys/time.h> #include <time.h> @@ -26,25 +28,100 @@ #include <fcntl.h> #include <pwd.h> #include <grp.h> +#include <pthread.h> -#include <freeswan.h> #include <library.h> #include <hydra.h> - -#include "../pluto/constants.h" -#include "../pluto/defs.h" -#include "../pluto/log.h" +#include <utils/backtrace.h> +#include <threading/thread.h> +#include <debug.h> #include "confread.h" #include "files.h" -#include "starterwhack.h" #include "starterstroke.h" -#include "invokepluto.h" #include "invokecharon.h" #include "netkey.h" #include "klips.h" #include "cmp.h" -#include "interfaces.h" + +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif + +#define CHARON_RESTART_DELAY 5 + +/* logging */ +static bool log_to_stderr = TRUE; +static bool log_to_syslog = TRUE; +static level_t current_loglevel = 1; + +/** + * logging function for scepclient + */ +static void starter_dbg(debug_t group, level_t level, char *fmt, ...) +{ + char buffer[8192]; + char *current = buffer, *next; + va_list args; + + if (level <= current_loglevel) + { + if (log_to_stderr) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + } + if (log_to_syslog) + { + /* write in memory buffer first */ + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + /* do a syslog with every line */ + while (current) + { + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(LOG_INFO, "%s\n", current); + current = next; + } + } + } +} + +/** + * Initialize logging to stderr/syslog + */ +static void init_log(const char *program) +{ + dbg = starter_dbg; + + if (log_to_stderr) + { + setbuf(stderr, NULL); + } + if (log_to_syslog) + { + openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV); + } +} + +/** + * Deinitialize logging to syslog + */ +static void close_log() +{ + if (log_to_syslog) + { + closelog(); + } +} /** * Return codes defined by Linux Standard Base Core Specification 3.1 @@ -68,7 +145,10 @@ static unsigned int _action_ = 0; -static void fsig(int signal) +/** + * Handle signals in the main thread + */ +static void signal_handler(int signal) { switch (signal) { @@ -80,27 +160,19 @@ static void fsig(int signal) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - if (pid == starter_pluto_pid()) - { - name = " (Pluto)"; - } if (pid == starter_charon_pid()) { name = " (Charon)"; } if (WIFSIGNALED(status)) { - DBG(DBG_CONTROL, - DBG_log("child %d%s has been killed by sig %d\n", - pid, name?name:"", WTERMSIG(status)) - ) + DBG2(DBG_APP, "child %d%s has been killed by sig %d\n", + pid, name?name:"", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { - DBG(DBG_CONTROL, - DBG_log("child %d%s has been stopped by sig %d\n", - pid, name?name:"", WSTOPSIG(status)) - ) + DBG2(DBG_APP, "child %d%s has been stopped by sig %d\n", + pid, name?name:"", WSTOPSIG(status)); } else if (WIFEXITED(status)) { @@ -109,20 +181,12 @@ static void fsig(int signal) { _action_ = FLAG_ACTION_QUIT; } - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit (exit code %d)\n", - pid, name?name:"", exit_status) - ) + DBG2(DBG_APP, "child %d%s has quit (exit code %d)\n", + pid, name?name:"", exit_status); } else { - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit", pid, name?name:"") - ) - } - if (pid == starter_pluto_pid()) - { - starter_pluto_sigchild(pid, exit_status); + DBG2(DBG_APP, "child %d%s has quit", pid, name?name:""); } if (pid == starter_charon_pid()) { @@ -132,12 +196,7 @@ static void fsig(int signal) } break; - case SIGPIPE: - /** ignore **/ - break; - case SIGALRM: - _action_ |= FLAG_ACTION_START_PLUTO; _action_ |= FLAG_ACTION_START_CHARON; break; @@ -157,11 +216,27 @@ static void fsig(int signal) break; default: - plog("fsig(): unknown signal %d -- investigate", signal); + DBG1(DBG_APP, "fsig(): unknown signal %d -- investigate", signal); break; } } +/** + * Handle fatal signals raised by threads + */ +static void fatal_signal_handler(int signal) +{ + backtrace_t *backtrace; + + DBG1(DBG_APP, "thread %u received %d", thread_current_id(), signal); + backtrace = backtrace_create(2); + backtrace->log(backtrace, stderr, TRUE); + backtrace->destroy(backtrace); + + DBG1(DBG_APP, "killing ourself, received critical signal"); + abort(); +} + #ifdef GENERATE_SELFCERT static void generate_selfcert() { @@ -244,7 +319,7 @@ static bool check_pid(char *pid_file) return TRUE; } } - plog("removing pidfile '%s', process not running", pid_file); + DBG1(DBG_APP, "removing pidfile '%s', process not running", pid_file); unlink(pid_file); } return FALSE; @@ -252,8 +327,8 @@ static bool check_pid(char *pid_file) static void usage(char *name) { - fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " - "[--debug|--debug-more|--debug-all]\n"); + fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>]\n" + " [--debug|--debug-more|--debug-all|--nolog]\n"); exit(LSB_RC_INVALID_ARGUMENT); } @@ -264,21 +339,18 @@ int main (int argc, char **argv) starter_conn_t *conn, *conn2; starter_ca_t *ca, *ca2; + struct sigaction action; struct stat stb; int i; int id = 1; - struct timeval tv; + struct timespec ts; unsigned long auto_update = 0; time_t last_reload; bool no_fork = FALSE; bool attach_gdb = FALSE; bool load_warning = FALSE; - /* global variables defined in log.h */ - log_to_stderr = TRUE; - base_debugging = DBG_NONE; - library_init(NULL); atexit(library_deinit); @@ -290,15 +362,19 @@ int main (int argc, char **argv) { if (streq(argv[i], "--debug")) { - base_debugging |= DBG_CONTROL; + current_loglevel = 2; } else if (streq(argv[i], "--debug-more")) { - base_debugging |= DBG_CONTROLMORE; + current_loglevel = 3; } else if (streq(argv[i], "--debug-all")) { - base_debugging |= DBG_ALL; + current_loglevel = 4; + } + else if (streq(argv[i], "--nolog")) + { + current_loglevel = 0; } else if (streq(argv[i], "--nofork")) { @@ -321,20 +397,12 @@ int main (int argc, char **argv) } } - /* Init */ init_log("ipsec_starter"); - cur_debugging = base_debugging; - - signal(SIGHUP, fsig); - signal(SIGCHLD, fsig); - signal(SIGPIPE, fsig); - signal(SIGINT, fsig); - signal(SIGTERM, fsig); - signal(SIGQUIT, fsig); - signal(SIGALRM, fsig); - signal(SIGUSR1, fsig); - plog("Starting strongSwan "VERSION" IPsec [starter]..."); + DBG1(DBG_APP, "Starting %sSwan "VERSION" IPsec [starter]...", + lib->settings->get_bool(lib->settings, + "charon.i_dont_care_about_security_and_use_aggressive_mode_psk", + FALSE) ? "weak" : "strong"); #ifdef LOAD_WARNING load_warning = TRUE; @@ -342,34 +410,24 @@ int main (int argc, char **argv) if (lib->settings->get_bool(lib->settings, "starter.load_warning", load_warning)) { - if (lib->settings->get_str(lib->settings, "charon.load", NULL) || - lib->settings->get_str(lib->settings, "pluto.load", NULL)) + if (lib->settings->get_str(lib->settings, "charon.load", NULL)) { - plog("!! Your strongswan.conf contains manual plugin load options for"); - plog("!! pluto and/or charon. This is recommended for experts only, see"); - plog("!! http://wiki.strongswan.org/projects/strongswan/wiki/PluginLoad"); + DBG1(DBG_APP, "!! Your strongswan.conf contains manual plugin load options for charon."); + DBG1(DBG_APP, "!! This is recommended for experts only, see"); + DBG1(DBG_APP, "!! http://wiki.strongswan.org/projects/strongswan/wiki/PluginLoad"); } } /* verify that we can start */ if (getuid() != 0) { - plog("permission denied (must be superuser)"); + DBG1(DBG_APP, "permission denied (must be superuser)"); exit(LSB_RC_NOT_ALLOWED); } - if (check_pid(PLUTO_PID_FILE)) - { - plog("pluto is already running (%s exists) -- skipping pluto start", - PLUTO_PID_FILE); - } - else - { - _action_ |= FLAG_ACTION_START_PLUTO; - } if (check_pid(CHARON_PID_FILE)) { - plog("charon is already running (%s exists) -- skipping charon start", + DBG1(DBG_APP, "charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); } else @@ -378,20 +436,20 @@ int main (int argc, char **argv) } if (stat(DEV_RANDOM, &stb) != 0) { - plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); + DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); exit(LSB_RC_FAILURE); } if (stat(DEV_URANDOM, &stb)!= 0) { - plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); + DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); exit(LSB_RC_FAILURE); } cfg = confread_load(CONFIG_FILE); if (cfg == NULL || cfg->err > 0) { - plog("unable to start strongSwan -- fatal errors in config"); + DBG1(DBG_APP, "unable to start strongSwan -- fatal errors in config"); if (cfg) { confread_free(cfg); @@ -402,11 +460,11 @@ int main (int argc, char **argv) /* determine if we have a native netkey IPsec stack */ if (!starter_netkey_init()) { - plog("no netkey IPsec stack detected"); + DBG1(DBG_APP, "no netkey IPsec stack detected"); if (!starter_klips_init()) { - plog("no KLIPS IPsec stack detected"); - plog("no known IPsec stack detected, ignoring!"); + DBG1(DBG_APP, "no KLIPS IPsec stack detected"); + DBG1(DBG_APP, "no known IPsec stack detected, ignoring!"); } } @@ -414,7 +472,7 @@ int main (int argc, char **argv) if (check_pid(STARTER_PID_FILE)) { - plog("starter is already running (%s exists) -- no fork done", + DBG1(DBG_APP, "starter is already running (%s exists) -- no fork done", STARTER_PID_FILE); confread_free(cfg); exit(LSB_RC_SUCCESS); @@ -435,6 +493,7 @@ int main (int argc, char **argv) { int fnull; + close_log(); closefrom(3); fnull = open("/dev/null", O_RDWR); @@ -447,10 +506,11 @@ int main (int argc, char **argv) } setsid(); + init_log("ipsec_starter"); } break; case -1: - plog("can't fork: %s", strerror(errno)); + DBG1(DBG_APP, "can't fork: %s", strerror(errno)); break; default: confread_free(cfg); @@ -469,24 +529,46 @@ int main (int argc, char **argv) } } - /* load plugins */ - if (!lib->plugins->load(lib->plugins, NULL, - lib->settings->get_str(lib->settings, "starter.load", PLUGINS))) - { - exit(LSB_RC_FAILURE); - } + /* we handle these signals only in pselect() */ + memset(&action, 0, sizeof(action)); + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGHUP); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGTERM); + sigaddset(&action.sa_mask, SIGQUIT); + sigaddset(&action.sa_mask, SIGALRM); + sigaddset(&action.sa_mask, SIGUSR1); + pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); + + /* install a handler for fatal signals */ + action.sa_handler = fatal_signal_handler; + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGBUS, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + /* install main signal handler */ + action.sa_handler = signal_handler; + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGQUIT, &action, NULL); + sigaction(SIGALRM, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + /* this is not blocked above as we want to receive it asynchronously */ + sigaction(SIGCHLD, &action, NULL); + + /* empty mask for pselect() call below */ + sigemptyset(&action.sa_mask); for (;;) { /* - * Stop pluto/charon (if started) and exit + * Stop charon (if started) and exit */ if (_action_ & FLAG_ACTION_QUIT) { - if (starter_pluto_pid()) - { - starter_stop_pluto(); - } if (starter_charon_pid()) { starter_stop_charon(); @@ -494,8 +576,7 @@ int main (int argc, char **argv) starter_netkey_cleanup(); confread_free(cfg); unlink(STARTER_PID_FILE); - plog("ipsec starter stopped"); - lib->plugins->unload(lib->plugins); + DBG1(DBG_APP, "ipsec starter stopped"); close_log(); exit(LSB_RC_SUCCESS); } @@ -505,7 +586,7 @@ int main (int argc, char **argv) */ if (_action_ & FLAG_ACTION_RELOAD) { - if (starter_pluto_pid() || starter_charon_pid()) + if (starter_charon_pid()) { for (conn = cfg->conn_first; conn; conn = conn->next) { @@ -515,10 +596,6 @@ int main (int argc, char **argv) { starter_stroke_del_conn(conn); } - if (starter_pluto_pid()) - { - starter_whack_del_conn(conn); - } conn->state = STATE_TO_ADD; } } @@ -530,10 +607,6 @@ int main (int argc, char **argv) { starter_stroke_del_ca(ca); } - if (starter_pluto_pid()) - { - starter_whack_del_ca(ca); - } ca->state = STATE_TO_ADD; } } @@ -546,96 +619,68 @@ int main (int argc, char **argv) */ if (_action_ & FLAG_ACTION_UPDATE) { - DBG(DBG_CONTROL, - DBG_log("Reloading config...") - ); + DBG2(DBG_APP, "Reloading config..."); new_cfg = confread_load(CONFIG_FILE); if (new_cfg && (new_cfg->err + new_cfg->non_fatal_err == 0)) { /* Switch to new config. New conn will be loaded below */ - if (!starter_cmp_defaultroute(&new_cfg->defaultroute - , &cfg->defaultroute)) - { - _action_ |= FLAG_ACTION_LISTEN; - } - if (!starter_cmp_pluto(cfg, new_cfg)) - { - plog("Pluto has changed"); - if (starter_pluto_pid()) - starter_stop_pluto(); - _action_ &= ~FLAG_ACTION_LISTEN; - _action_ |= FLAG_ACTION_START_PLUTO; - } - else + /* Look for new connections that are already loaded */ + for (conn = cfg->conn_first; conn; conn = conn->next) { - /* Only reload conn and ca sections if pluto is not killed */ - - /* Look for new connections that are already loaded */ - for (conn = cfg->conn_first; conn; conn = conn->next) + if (conn->state == STATE_ADDED) { - if (conn->state == STATE_ADDED) + for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) { - for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) + if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2)) { - if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2)) - { - conn->state = STATE_REPLACED; - conn2->state = STATE_ADDED; - conn2->id = conn->id; - break; - } + conn->state = STATE_REPLACED; + conn2->state = STATE_ADDED; + conn2->id = conn->id; + break; } } } + } - /* Remove conn sections that have become unused */ - for (conn = cfg->conn_first; conn; conn = conn->next) + /* Remove conn sections that have become unused */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) { - if (conn->state == STATE_ADDED) + if (starter_charon_pid()) { - if (starter_charon_pid()) - { - starter_stroke_del_conn(conn); - } - if (starter_pluto_pid()) - { - starter_whack_del_conn(conn); - } + starter_stroke_del_conn(conn); } } + } - /* Look for new ca sections that are already loaded */ - for (ca = cfg->ca_first; ca; ca = ca->next) + /* Look for new ca sections that are already loaded */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) { - if (ca->state == STATE_ADDED) + for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) { - for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) + if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2)) { - if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2)) - { - ca->state = STATE_REPLACED; - ca2->state = STATE_ADDED; - break; - } + ca->state = STATE_REPLACED; + ca2->state = STATE_ADDED; + break; } } } + } - /* Remove ca sections that have become unused */ - for (ca = cfg->ca_first; ca; ca = ca->next) + /* Remove ca sections that have become unused */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) { - if (ca->state == STATE_ADDED) + if (starter_charon_pid()) { - if (starter_charon_pid()) - { - starter_stroke_del_ca(ca); - } - if (starter_pluto_pid()) - { - starter_whack_del_ca(ca); - } + starter_stroke_del_ca(ca); } } } @@ -644,7 +689,7 @@ int main (int argc, char **argv) } else { - plog("can't reload config file due to errors -- keeping old one"); + DBG1(DBG_APP, "can't reload config file due to errors -- keeping old one"); if (new_cfg) { confread_free(new_cfg); @@ -655,77 +700,43 @@ int main (int argc, char **argv) } /* - * Start pluto + * Start charon */ - if (_action_ & FLAG_ACTION_START_PLUTO) + if (_action_ & FLAG_ACTION_START_CHARON) { - if (cfg->setup.plutostart && !starter_pluto_pid()) + if (cfg->setup.charonstart && !starter_charon_pid()) { - DBG(DBG_CONTROL, - DBG_log("Attempting to start pluto...") - ); - - if (starter_start_pluto(cfg, no_fork, attach_gdb) == 0) - { - starter_whack_listen(); - } - else + DBG2(DBG_APP, "Attempting to start charon..."); + if (starter_start_charon(cfg, no_fork, attach_gdb)) { /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); + alarm(CHARON_RESTART_DELAY); } + starter_stroke_configure(cfg); } - _action_ &= ~FLAG_ACTION_START_PLUTO; + _action_ &= ~FLAG_ACTION_START_CHARON; for (ca = cfg->ca_first; ca; ca = ca->next) { if (ca->state == STATE_ADDED) + { ca->state = STATE_TO_ADD; + } } for (conn = cfg->conn_first; conn; conn = conn->next) { if (conn->state == STATE_ADDED) - conn->state = STATE_TO_ADD; - } - } - - /* - * Start charon - */ - if (_action_ & FLAG_ACTION_START_CHARON) - { - if (cfg->setup.charonstart && !starter_charon_pid()) - { - DBG(DBG_CONTROL, - DBG_log("Attempting to start charon...") - ); - if (starter_start_charon(cfg, no_fork, attach_gdb)) { - /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); + conn->state = STATE_TO_ADD; } - starter_stroke_configure(cfg); - } - _action_ &= ~FLAG_ACTION_START_CHARON; - } - - /* - * Tell pluto to reread its interfaces - */ - if (_action_ & FLAG_ACTION_LISTEN) - { - if (starter_pluto_pid()) - { - starter_whack_listen(); - _action_ &= ~FLAG_ACTION_LISTEN; } } /* * Add stale conn and ca sections */ - if (starter_pluto_pid() || starter_charon_pid()) + if (starter_charon_pid()) { for (ca = cfg->ca_first; ca; ca = ca->next) { @@ -735,10 +746,6 @@ int main (int argc, char **argv) { starter_stroke_add_ca(ca); } - if (starter_pluto_pid()) - { - starter_whack_add_ca(ca); - } ca->state = STATE_ADDED; } } @@ -756,44 +763,20 @@ int main (int argc, char **argv) { starter_stroke_add_conn(cfg, conn); } - if (starter_pluto_pid()) - { - starter_whack_add_conn(conn); - } conn->state = STATE_ADDED; if (conn->startup == STARTUP_START) { - if (conn->keyexchange != KEY_EXCHANGE_IKEV1) + if (starter_charon_pid()) { - if (starter_charon_pid()) - { - starter_stroke_initiate_conn(conn); - } - } - else - { - if (starter_pluto_pid()) - { - starter_whack_initiate_conn(conn); - } + starter_stroke_initiate_conn(conn); } } else if (conn->startup == STARTUP_ROUTE) { - if (conn->keyexchange != KEY_EXCHANGE_IKEV1) - { - if (starter_charon_pid()) - { - starter_stroke_route_conn(conn); - } - } - else + if (starter_charon_pid()) { - if (starter_pluto_pid()) - { - starter_whack_route_conn(conn); - } + starter_stroke_route_conn(conn); } } } @@ -807,15 +790,16 @@ int main (int argc, char **argv) { time_t now = time_monotonic(NULL); - tv.tv_sec = (now < last_reload + auto_update) - ? (last_reload + auto_update-now) : 0; - tv.tv_usec = 0; + ts.tv_sec = (now < last_reload + auto_update) ? + (last_reload + auto_update - now) : 0; + ts.tv_nsec = 0; } /* * Wait for something to happen */ - if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) + if (pselect(0, NULL, NULL, NULL, auto_update ? &ts : NULL, + &action.sa_mask) == 0) { /* timeout -> auto_update */ _action_ |= FLAG_ACTION_UPDATE; |