Return to charon.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2006-2017 Tobias Brunner ! 3: * Copyright (C) 2005-2009 Martin Willi ! 4: * Copyright (C) 2006 Daniel Roethlisberger ! 5: * Copyright (C) 2005 Jan Hutter ! 6: * HSR Hochschule fuer Technik Rapperswil ! 7: * ! 8: * This program is free software; you can redistribute it and/or modify it ! 9: * under the terms of the GNU General Public License as published by the ! 10: * Free Software Foundation; either version 2 of the License, or (at your ! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. ! 12: * ! 13: * This program is distributed in the hope that it will be useful, but ! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ! 16: * for more details. ! 17: */ ! 18: ! 19: #include <stdio.h> ! 20: #include <signal.h> ! 21: #include <pthread.h> ! 22: #include <sys/stat.h> ! 23: #include <sys/types.h> ! 24: #include <sys/utsname.h> ! 25: #include <unistd.h> ! 26: #include <getopt.h> ! 27: #include <fcntl.h> ! 28: #include <errno.h> ! 29: ! 30: #include <daemon.h> ! 31: ! 32: #include <library.h> ! 33: #include <utils/backtrace.h> ! 34: #include <threading/thread.h> ! 35: ! 36: #ifdef ANDROID ! 37: #include <private/android_filesystem_config.h> /* for AID_VPN */ ! 38: #endif ! 39: ! 40: /** ! 41: * PID file, in which charon stores its process id ! 42: */ ! 43: #define PID_FILE IPSEC_PIDDIR "/charon.pid" ! 44: ! 45: /** ! 46: * Default user and group ! 47: */ ! 48: #ifndef IPSEC_USER ! 49: #define IPSEC_USER NULL ! 50: #endif ! 51: ! 52: #ifndef IPSEC_GROUP ! 53: #define IPSEC_GROUP NULL ! 54: #endif ! 55: ! 56: /** ! 57: * Global reference to PID file (required to truncate, if undeletable) ! 58: */ ! 59: static FILE *pidfile = NULL; ! 60: ! 61: /** ! 62: * hook in library for debugging messages ! 63: */ ! 64: extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); ! 65: ! 66: /** ! 67: * Logging hook for library logs, using stderr output ! 68: */ ! 69: static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) ! 70: { ! 71: va_list args; ! 72: ! 73: if (level <= 1) ! 74: { ! 75: va_start(args, fmt); ! 76: fprintf(stderr, "00[%N] ", debug_names, group); ! 77: vfprintf(stderr, fmt, args); ! 78: fprintf(stderr, "\n"); ! 79: va_end(args); ! 80: } ! 81: } ! 82: ! 83: /** ! 84: * Run the daemon and handle unix signals ! 85: */ ! 86: static void run() ! 87: { ! 88: sigset_t set; ! 89: ! 90: /* handle SIGINT, SIGHUP and SIGTERM in this handler */ ! 91: sigemptyset(&set); ! 92: sigaddset(&set, SIGINT); ! 93: sigaddset(&set, SIGHUP); ! 94: sigaddset(&set, SIGTERM); ! 95: sigprocmask(SIG_BLOCK, &set, NULL); ! 96: ! 97: while (TRUE) ! 98: { ! 99: int sig; ! 100: ! 101: sig = sigwaitinfo(&set, NULL); ! 102: if (sig == -1) ! 103: { ! 104: if (errno == EINTR) ! 105: { /* ignore signals we didn't wait for */ ! 106: continue; ! 107: } ! 108: DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno)); ! 109: return; ! 110: } ! 111: switch (sig) ! 112: { ! 113: case SIGHUP: ! 114: { ! 115: DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " ! 116: "configuration"); ! 117: if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) ! 118: { ! 119: charon->load_loggers(charon); ! 120: lib->plugins->reload(lib->plugins, NULL); ! 121: } ! 122: else ! 123: { ! 124: DBG1(DBG_DMN, "reloading config failed, keeping old"); ! 125: } ! 126: break; ! 127: } ! 128: case SIGINT: ! 129: { ! 130: DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); ! 131: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 132: return; ! 133: } ! 134: case SIGTERM: ! 135: { ! 136: DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); ! 137: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 138: return; ! 139: } ! 140: } ! 141: } ! 142: } ! 143: ! 144: /** ! 145: * lookup UID and GID ! 146: */ ! 147: static bool lookup_uid_gid() ! 148: { ! 149: char *name; ! 150: ! 151: name = lib->settings->get_str(lib->settings, "charon.user", IPSEC_USER); ! 152: if (name && !lib->caps->resolve_uid(lib->caps, name)) ! 153: { ! 154: return FALSE; ! 155: } ! 156: name = lib->settings->get_str(lib->settings, "charon.group", IPSEC_GROUP); ! 157: if (name && !lib->caps->resolve_gid(lib->caps, name)) ! 158: { ! 159: return FALSE; ! 160: } ! 161: #ifdef ANDROID ! 162: lib->caps->set_uid(lib->caps, AID_VPN); ! 163: #endif ! 164: return TRUE; ! 165: } ! 166: ! 167: /** ! 168: * Handle SIGSEGV/SIGILL signals raised by threads ! 169: */ ! 170: #ifndef DISABLE_SIGNAL_HANDLER ! 171: static void segv_handler(int signal) ! 172: { ! 173: backtrace_t *backtrace; ! 174: ! 175: DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); ! 176: backtrace = backtrace_create(2); ! 177: backtrace->log(backtrace, NULL, TRUE); ! 178: backtrace->log(backtrace, stderr, TRUE); ! 179: backtrace->destroy(backtrace); ! 180: ! 181: DBG1(DBG_DMN, "killing ourself, received critical signal"); ! 182: abort(); ! 183: } ! 184: #endif /* DISABLE_SIGNAL_HANDLER */ ! 185: ! 186: /** ! 187: * Check/create PID file, return TRUE if already running ! 188: */ ! 189: static bool check_pidfile() ! 190: { ! 191: struct stat stb; ! 192: ! 193: if (stat(PID_FILE, &stb) == 0) ! 194: { ! 195: pidfile = fopen(PID_FILE, "r"); ! 196: if (pidfile) ! 197: { ! 198: char buf[64]; ! 199: pid_t pid = 0; ! 200: ! 201: memset(buf, 0, sizeof(buf)); ! 202: if (fread(buf, 1, sizeof(buf), pidfile)) ! 203: { ! 204: buf[sizeof(buf) - 1] = '\0'; ! 205: pid = atoi(buf); ! 206: } ! 207: fclose(pidfile); ! 208: pidfile = NULL; ! 209: if (pid && pid != getpid() && kill(pid, 0) == 0) ! 210: { ! 211: DBG1(DBG_DMN, "charon already running ('"PID_FILE"' exists)"); ! 212: return TRUE; ! 213: } ! 214: } ! 215: DBG1(DBG_DMN, "removing pidfile '"PID_FILE"', process not running"); ! 216: unlink(PID_FILE); ! 217: } ! 218: ! 219: /* create new pidfile */ ! 220: pidfile = fopen(PID_FILE, "w"); ! 221: if (pidfile) ! 222: { ! 223: int fd; ! 224: ! 225: fd = fileno(pidfile); ! 226: if (fd == -1) ! 227: { ! 228: DBG1(DBG_DMN, "unable to determine fd for '"PID_FILE"'"); ! 229: return TRUE; ! 230: } ! 231: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) ! 232: { ! 233: DBG1(DBG_LIB, "setting FD_CLOEXEC for '"PID_FILE"' failed: %s", ! 234: strerror(errno)); ! 235: } ! 236: /* Only change owner of the pidfile if we have CAP_CHOWN. Otherwise, ! 237: * attempt to change group of pidfile to group under which charon ! 238: * runs after dropping caps. This requires the user that charon ! 239: * starts as to: ! 240: * a) Have write access to the socket dir. ! 241: * b) Belong to the group that charon will run under after dropping ! 242: * caps. */ ! 243: if (lib->caps->check(lib->caps, CAP_CHOWN)) ! 244: { ! 245: ignore_result(fchown(fd, ! 246: lib->caps->get_uid(lib->caps), ! 247: lib->caps->get_gid(lib->caps))); ! 248: } ! 249: else ! 250: { ! 251: ignore_result(fchown(fd, -1, ! 252: lib->caps->get_gid(lib->caps))); ! 253: } ! 254: fprintf(pidfile, "%d\n", getpid()); ! 255: fflush(pidfile); ! 256: return FALSE; ! 257: } ! 258: else ! 259: { ! 260: DBG1(DBG_DMN, "unable to create pidfile '"PID_FILE"'"); ! 261: return TRUE; ! 262: } ! 263: } ! 264: ! 265: /** ! 266: * Delete/truncate the PID file ! 267: */ ! 268: static void unlink_pidfile() ! 269: { ! 270: /* because unlinking the PID file may fail, we truncate it to ensure the ! 271: * daemon can be properly restarted. one probable cause for this is the ! 272: * combination of not running as root and the effective user lacking ! 273: * permissions on the parent dir(s) of the PID file */ ! 274: if (pidfile) ! 275: { ! 276: ignore_result(ftruncate(fileno(pidfile), 0)); ! 277: fclose(pidfile); ! 278: unlink(PID_FILE); ! 279: } ! 280: } ! 281: ! 282: /** ! 283: * print command line usage and exit ! 284: */ ! 285: static void usage(const char *msg) ! 286: { ! 287: if (msg != NULL && *msg != '\0') ! 288: { ! 289: fprintf(stderr, "%s\n", msg); ! 290: } ! 291: fprintf(stderr, "Usage: charon\n" ! 292: " [--help]\n" ! 293: " [--version]\n" ! 294: " [--use-syslog]\n" ! 295: " [--debug-<type> <level>]\n" ! 296: " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|esp|lib)\n" ! 297: " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n" ! 298: " 2 = controlmore, 3 = raw, 4 = private)\n" ! 299: "\n" ! 300: ); ! 301: } ! 302: ! 303: /** ! 304: * Main function, starts the daemon. ! 305: */ ! 306: int main(int argc, char *argv[]) ! 307: { ! 308: struct sigaction action; ! 309: int group, status = SS_RC_INITIALIZATION_FAILED; ! 310: struct utsname utsname; ! 311: level_t levels[DBG_MAX]; ! 312: bool use_syslog = FALSE; ! 313: ! 314: /* logging for library during initialization, as we have no bus yet */ ! 315: dbg = dbg_stderr; ! 316: ! 317: /* initialize library */ ! 318: if (!library_init(NULL, "charon")) ! 319: { ! 320: library_deinit(); ! 321: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); ! 322: } ! 323: ! 324: if (lib->integrity && ! 325: !lib->integrity->check_file(lib->integrity, "charon", argv[0])) ! 326: { ! 327: dbg_stderr(DBG_DMN, 1, "integrity check of charon failed"); ! 328: library_deinit(); ! 329: exit(SS_RC_DAEMON_INTEGRITY); ! 330: } ! 331: ! 332: if (!libcharon_init()) ! 333: { ! 334: dbg_stderr(DBG_DMN, 1, "initialization failed - aborting charon"); ! 335: goto deinit; ! 336: } ! 337: ! 338: /* use CTRL loglevel for default */ ! 339: for (group = 0; group < DBG_MAX; group++) ! 340: { ! 341: levels[group] = LEVEL_CTRL; ! 342: } ! 343: ! 344: /* handle arguments */ ! 345: for (;;) ! 346: { ! 347: struct option long_opts[] = { ! 348: { "help", no_argument, NULL, 'h' }, ! 349: { "version", no_argument, NULL, 'v' }, ! 350: { "use-syslog", no_argument, NULL, 'l' }, ! 351: /* TODO: handle "debug-all" */ ! 352: { "debug-dmn", required_argument, &group, DBG_DMN }, ! 353: { "debug-mgr", required_argument, &group, DBG_MGR }, ! 354: { "debug-ike", required_argument, &group, DBG_IKE }, ! 355: { "debug-chd", required_argument, &group, DBG_CHD }, ! 356: { "debug-job", required_argument, &group, DBG_JOB }, ! 357: { "debug-cfg", required_argument, &group, DBG_CFG }, ! 358: { "debug-knl", required_argument, &group, DBG_KNL }, ! 359: { "debug-net", required_argument, &group, DBG_NET }, ! 360: { "debug-asn", required_argument, &group, DBG_ASN }, ! 361: { "debug-enc", required_argument, &group, DBG_ENC }, ! 362: { "debug-tnc", required_argument, &group, DBG_TNC }, ! 363: { "debug-imc", required_argument, &group, DBG_IMC }, ! 364: { "debug-imv", required_argument, &group, DBG_IMV }, ! 365: { "debug-pts", required_argument, &group, DBG_PTS }, ! 366: { "debug-tls", required_argument, &group, DBG_TLS }, ! 367: { "debug-esp", required_argument, &group, DBG_ESP }, ! 368: { "debug-lib", required_argument, &group, DBG_LIB }, ! 369: { 0,0,0,0 } ! 370: }; ! 371: ! 372: int c = getopt_long(argc, argv, "", long_opts, NULL); ! 373: switch (c) ! 374: { ! 375: case EOF: ! 376: break; ! 377: case 'h': ! 378: usage(NULL); ! 379: status = 0; ! 380: goto deinit; ! 381: case 'v': ! 382: printf("FreeBSD strongSwan %s\n", VERSION); ! 383: status = 0; ! 384: goto deinit; ! 385: case 'l': ! 386: use_syslog = TRUE; ! 387: continue; ! 388: case 0: ! 389: /* option is in group */ ! 390: levels[group] = atoi(optarg); ! 391: continue; ! 392: default: ! 393: usage(""); ! 394: status = 1; ! 395: goto deinit; ! 396: } ! 397: break; ! 398: } ! 399: ! 400: if (!lookup_uid_gid()) ! 401: { ! 402: dbg_stderr(DBG_DMN, 1, "invalid uid/gid - aborting charon"); ! 403: goto deinit; ! 404: } ! 405: ! 406: charon->set_default_loggers(charon, levels, !use_syslog); ! 407: charon->load_loggers(charon); ! 408: ! 409: if (uname(&utsname) != 0) ! 410: { ! 411: memset(&utsname, 0, sizeof(utsname)); ! 412: } ! 413: DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)", ! 414: utsname.sysname, utsname.release, utsname.machine); ! 415: if (lib->integrity) ! 416: { ! 417: DBG1(DBG_DMN, "integrity tests enabled:"); ! 418: DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); ! 419: DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); ! 420: DBG1(DBG_DMN, "daemon 'charon': passed file integrity test"); ! 421: } ! 422: ! 423: /* initialize daemon */ ! 424: if (!charon->initialize(charon, ! 425: lib->settings->get_str(lib->settings, "charon.load", PLUGINS))) ! 426: { ! 427: DBG1(DBG_DMN, "initialization failed - aborting charon"); ! 428: goto deinit; ! 429: } ! 430: lib->plugins->status(lib->plugins, LEVEL_CTRL); ! 431: ! 432: if (check_pidfile()) ! 433: { ! 434: goto deinit; ! 435: } ! 436: ! 437: if (!lib->caps->drop(lib->caps)) ! 438: { ! 439: DBG1(DBG_DMN, "capability dropping failed - aborting charon"); ! 440: goto deinit; ! 441: } ! 442: ! 443: /* add handler for fatal signals, ! 444: * INT, TERM and HUP are handled by sigwaitinfo() in run() */ ! 445: action.sa_flags = 0; ! 446: sigemptyset(&action.sa_mask); ! 447: sigaddset(&action.sa_mask, SIGINT); ! 448: sigaddset(&action.sa_mask, SIGTERM); ! 449: sigaddset(&action.sa_mask, SIGHUP); ! 450: ! 451: /* optionally let the external system handle fatal signals */ ! 452: #ifndef DISABLE_SIGNAL_HANDLER ! 453: action.sa_handler = segv_handler; ! 454: sigaction(SIGSEGV, &action, NULL); ! 455: sigaction(SIGILL, &action, NULL); ! 456: sigaction(SIGBUS, &action, NULL); ! 457: #endif /* DISABLE_SIGNAL_HANDLER */ ! 458: ! 459: action.sa_handler = SIG_IGN; ! 460: sigaction(SIGPIPE, &action, NULL); ! 461: ! 462: pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); ! 463: ! 464: /* start daemon (i.e. the threads in the thread-pool) */ ! 465: charon->start(charon); ! 466: ! 467: /* main thread goes to run loop */ ! 468: run(); ! 469: ! 470: status = 0; ! 471: ! 472: deinit: ! 473: libcharon_deinit(); ! 474: unlink_pidfile(); ! 475: library_deinit(); ! 476: return status; ! 477: }