/* strongSwan charon launcher * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil * * Ported from invokepluto.c to fit charons needs. * * 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 #include #include #include #include #include #include #include #include #include "confread.h" #include "invokecharon.h" #include "files.h" static int _charon_pid = 0; static int _stop_requested; pid_t starter_charon_pid(void) { return _charon_pid; } void starter_charon_sigchild(pid_t pid, int status) { if (pid == _charon_pid) { _charon_pid = 0; if (status == SS_RC_LIBSTRONGSWAN_INTEGRITY || status == SS_RC_DAEMON_INTEGRITY) { DBG1(DBG_APP, "charon has quit: integrity test of %s failed", (status == 64) ? "libstrongswan" : "charon"); _stop_requested = 1; } else if (status == SS_RC_INITIALIZATION_FAILED) { DBG1(DBG_APP, "charon has quit: initialization failed"); _stop_requested = 1; } if (!_stop_requested) { DBG1(DBG_APP, "charon has died -- restart scheduled (%dsec)", CHARON_RESTART_DELAY); alarm(CHARON_RESTART_DELAY); // restart in 5 sec } unlink(CHARON_PID_FILE); } } int starter_stop_charon (void) { int i; pid_t pid = _charon_pid; if (pid) { _stop_requested = 1; /* be more and more aggressive */ for (i = 0; i < 50 && (pid = _charon_pid) != 0; i++) { if (i == 0) { kill(pid, SIGINT); } else if (i < 40) { kill(pid, SIGTERM); } else if (i == 40) { kill(pid, SIGKILL); DBG1(DBG_APP, "starter_stop_charon(): charon does not respond, sending KILL"); } else { kill(pid, SIGKILL); } usleep(200000); /* sleep for 200 ms */ } if (_charon_pid == 0) { DBG1(DBG_APP, "charon stopped after %d ms", 200*i); return 0; } DBG1(DBG_APP, "starter_stop_charon(): can't stop charon !!!"); return -1; } else { DBG1(DBG_APP, "stater_stop_charon(): charon was not started..."); } return -1; } int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb) { struct stat stb; int pid, i; char buffer[BUF_LEN]; int argc = 1; char *arg[] = { CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; if (attach_gdb) { argc = 0; arg[argc++] = "/usr/bin/gdb"; arg[argc++] = "--args"; arg[argc++] = CHARON_CMD; } if (!no_fork) { arg[argc++] = "--use-syslog"; } /* parse debug string */ { int level; char type[4]; char *pos = cfg->setup.charondebug; char *buf_pos = buffer; while (pos && sscanf(pos, "%3s %d,", type, &level) == 2) { snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type); arg[argc++] = buf_pos; buf_pos += strlen(buf_pos) + 1; if (buf_pos >= buffer + sizeof(buffer)) { break; } snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level); arg[argc++] = buf_pos; buf_pos += strlen(buf_pos) + 1; if (buf_pos >= buffer + sizeof(buffer)) { break; } /* get next */ pos = strchr(pos, ','); if (pos) { pos++; } } } if (_charon_pid) { DBG1(DBG_APP, "starter_start_charon(): charon already started..."); return -1; } else { unlink(CHARON_CTL_FILE); _stop_requested = 0; pid = fork(); switch (pid) { case -1: DBG1(DBG_APP, "can't fork(): %s", strerror(errno)); return -1; case 0: /* child */ setsid(); closefrom(3); sigprocmask(SIG_SETMASK, 0, NULL); /* disable glibc's malloc checker, conflicts with leak detective */ setenv("MALLOC_CHECK_", "0", 1); execv(arg[0], arg); DBG1(DBG_APP, "can't execv(%s,...): %s", arg[0], strerror(errno)); exit(1); default: /* father */ _charon_pid = pid; for (i = 0; i < 500 && _charon_pid; i++) { /* wait for charon for a maximum of 500 x 20 ms = 10 s */ usleep(20000); if (stat(CHARON_PID_FILE, &stb) == 0) { DBG1(DBG_APP, "charon (%d) started after %d ms", _charon_pid, 20*(i+1)); return 0; } } if (_charon_pid) { /* If charon is started but with no ctl file, stop it */ DBG1(DBG_APP, "charon too long to start... - kill kill"); for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++) { if (i == 0) { kill(pid, SIGINT); } else if (i < 10) { kill(pid, SIGTERM); } else { kill(pid, SIGKILL); } usleep(20000); /* sleep for 20 ms */ } } else { DBG1(DBG_APP, "charon refused to be started"); } return -1; } } return -1; }