Return to charon-cmd.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon-cmd |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2006-2013 Tobias Brunner ! 3: * Copyright (C) 2005-2013 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/types.h> ! 23: #include <sys/utsname.h> ! 24: #include <unistd.h> ! 25: #include <getopt.h> ! 26: #include <errno.h> ! 27: ! 28: #include <library.h> ! 29: #include <daemon.h> ! 30: #include <utils/backtrace.h> ! 31: #include <threading/thread.h> ! 32: ! 33: #include "cmd/cmd_options.h" ! 34: #include "cmd/cmd_connection.h" ! 35: #include "cmd/cmd_creds.h" ! 36: ! 37: /** ! 38: * Default loglevel ! 39: */ ! 40: static level_t default_loglevel = LEVEL_CTRL; ! 41: ! 42: /** ! 43: * Connection to initiate ! 44: */ ! 45: static cmd_connection_t *conn; ! 46: ! 47: /** ! 48: * Credential backend ! 49: */ ! 50: static cmd_creds_t *creds; ! 51: ! 52: /** ! 53: * hook in library for debugging messages ! 54: */ ! 55: extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); ! 56: ! 57: /** ! 58: * Logging hook for library logs, using stderr output ! 59: */ ! 60: static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) ! 61: { ! 62: va_list args; ! 63: ! 64: if (level <= default_loglevel) ! 65: { ! 66: va_start(args, fmt); ! 67: fprintf(stderr, "00[%N] ", debug_names, group); ! 68: vfprintf(stderr, fmt, args); ! 69: fprintf(stderr, "\n"); ! 70: va_end(args); ! 71: } ! 72: } ! 73: ! 74: /** ! 75: * Clean up connection definition atexit() ! 76: */ ! 77: static void cleanup_conn() ! 78: { ! 79: DESTROY_IF(conn); ! 80: } ! 81: ! 82: /** ! 83: * Clean up credentials atexit() ! 84: */ ! 85: static void cleanup_creds() ! 86: { ! 87: DESTROY_IF(creds); ! 88: } ! 89: ! 90: /** ! 91: * Run the daemon and handle unix signals ! 92: */ ! 93: static int run() ! 94: { ! 95: sigset_t set; ! 96: ! 97: /* handle SIGINT, SIGHUP and SIGTERM in this handler */ ! 98: sigemptyset(&set); ! 99: sigaddset(&set, SIGINT); ! 100: sigaddset(&set, SIGHUP); ! 101: sigaddset(&set, SIGTERM); ! 102: sigaddset(&set, SIGUSR1); ! 103: sigprocmask(SIG_BLOCK, &set, NULL); ! 104: ! 105: while (TRUE) ! 106: { ! 107: int sig; ! 108: ! 109: sig = sigwaitinfo(&set, NULL); ! 110: if (sig == -1) ! 111: { ! 112: if (errno == EINTR) ! 113: { /* ignore signals we didn't wait for */ ! 114: continue; ! 115: } ! 116: DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno)); ! 117: return 1; ! 118: } ! 119: switch (sig) ! 120: { ! 121: case SIGHUP: ! 122: { ! 123: DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " ! 124: "configuration"); ! 125: if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) ! 126: { ! 127: charon->load_loggers(charon); ! 128: lib->plugins->reload(lib->plugins, NULL); ! 129: } ! 130: else ! 131: { ! 132: DBG1(DBG_DMN, "reloading config failed, keeping old"); ! 133: } ! 134: break; ! 135: } ! 136: case SIGINT: ! 137: { ! 138: DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); ! 139: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 140: return 0; ! 141: } ! 142: case SIGTERM: ! 143: { ! 144: DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); ! 145: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 146: return 0; ! 147: } ! 148: case SIGUSR1: ! 149: { /* an error occurred */ ! 150: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 151: return 1; ! 152: } ! 153: } ! 154: } ! 155: } ! 156: ! 157: /** ! 158: * lookup UID and GID ! 159: */ ! 160: static bool lookup_uid_gid() ! 161: { ! 162: #ifdef IPSEC_USER ! 163: if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) ! 164: { ! 165: return FALSE; ! 166: } ! 167: #endif ! 168: #ifdef IPSEC_GROUP ! 169: if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) ! 170: { ! 171: return FALSE; ! 172: } ! 173: #endif ! 174: return TRUE; ! 175: } ! 176: ! 177: #ifndef DISABLE_SIGNAL_HANDLER ! 178: /** ! 179: * Handle SIGSEGV/SIGILL signals raised by threads ! 180: */ ! 181: static void segv_handler(int signal) ! 182: { ! 183: backtrace_t *backtrace; ! 184: ! 185: DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); ! 186: backtrace = backtrace_create(2); ! 187: backtrace->log(backtrace, stderr, TRUE); ! 188: backtrace->destroy(backtrace); ! 189: ! 190: DBG1(DBG_DMN, "killing ourself, received critical signal"); ! 191: abort(); ! 192: } ! 193: #endif /* DISABLE_SIGNAL_HANDLER */ ! 194: ! 195: /** ! 196: * Print command line usage and exit ! 197: */ ! 198: static void usage(FILE *out, char *msg, char *binary) ! 199: { ! 200: static const int padto = 18; ! 201: char cmd[64], *pre, *post; ! 202: int i, line, pad; ! 203: ! 204: if (msg) ! 205: { ! 206: fprintf(out, "%s\n", msg); ! 207: } ! 208: fprintf(out, "Usage: %s\n", binary); ! 209: for (i = 0; i < CMD_OPT_COUNT; i++) ! 210: { ! 211: switch (cmd_options[i].has_arg) ! 212: { ! 213: case required_argument: ! 214: pre = " <"; ! 215: post = ">"; ! 216: break; ! 217: case optional_argument: ! 218: pre = "[="; ! 219: post = "]"; ! 220: break; ! 221: case no_argument: ! 222: default: ! 223: pre = " "; ! 224: post = " "; ! 225: break; ! 226: } ! 227: snprintf(cmd, sizeof(cmd), " --%s%s%s%s", cmd_options[i].name, ! 228: pre, cmd_options[i].arg, post); ! 229: pad = padto - strlen(cmd); ! 230: if (pad >= 1) ! 231: { ! 232: fprintf(out, "%s%-*s%s\n", cmd, pad, "", cmd_options[i].desc); ! 233: } ! 234: else ! 235: { /* write description to a separate line */ ! 236: fprintf(out, "%s\n%-*s%s\n", cmd, padto, "", cmd_options[i].desc); ! 237: } ! 238: for (line = 0; line < countof(cmd_options[i].lines); line++) ! 239: { ! 240: if (cmd_options[i].lines[line]) ! 241: { ! 242: fprintf(out, "%-*s%s\n", padto, "", cmd_options[i].lines[line]); ! 243: } ! 244: } ! 245: } ! 246: } ! 247: ! 248: /** ! 249: * Handle command line options, if simple is TRUE only arguments like --help ! 250: * and --version are handled. ! 251: */ ! 252: static void handle_arguments(int argc, char *argv[], bool simple) ! 253: { ! 254: struct option long_opts[CMD_OPT_COUNT + 1] = {}; ! 255: int i, opt; ! 256: ! 257: for (i = 0; i < CMD_OPT_COUNT; i++) ! 258: { ! 259: long_opts[i].name = cmd_options[i].name; ! 260: long_opts[i].val = cmd_options[i].id; ! 261: long_opts[i].has_arg = cmd_options[i].has_arg; ! 262: } ! 263: /* reset option parser */ ! 264: optind = 1; ! 265: while (TRUE) ! 266: { ! 267: bool handled = FALSE; ! 268: ! 269: opt = getopt_long(argc, argv, "", long_opts, NULL); ! 270: switch (opt) ! 271: { ! 272: case EOF: ! 273: break; ! 274: case CMD_OPT_HELP: ! 275: usage(stdout, NULL, argv[0]); ! 276: exit(0); ! 277: case CMD_OPT_VERSION: ! 278: printf("%s, strongSwan %s\n", "charon-cmd", VERSION); ! 279: exit(0); ! 280: case CMD_OPT_DEBUG: ! 281: default_loglevel = atoi(optarg); ! 282: continue; ! 283: default: ! 284: if (simple) ! 285: { ! 286: continue; ! 287: } ! 288: handled |= conn->handle(conn, opt, optarg); ! 289: handled |= creds->handle(creds, opt, optarg); ! 290: if (handled) ! 291: { ! 292: continue; ! 293: } ! 294: /* fall-through */ ! 295: case '?': ! 296: /* missing argument, unrecognized option */ ! 297: usage(stderr, NULL, argv[0]); ! 298: exit(1); ! 299: } ! 300: break; ! 301: } ! 302: } ! 303: ! 304: /** ! 305: * Main function, starts the daemon. ! 306: */ ! 307: int main(int argc, char *argv[]) ! 308: { ! 309: struct sigaction action; ! 310: struct utsname utsname; ! 311: level_t levels[DBG_MAX]; ! 312: int group; ! 313: ! 314: /* handle simple arguments */ ! 315: handle_arguments(argc, argv, TRUE); ! 316: ! 317: dbg = dbg_stderr; ! 318: atexit(library_deinit); ! 319: if (!library_init(NULL, "charon-cmd")) ! 320: { ! 321: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); ! 322: } ! 323: if (lib->integrity) ! 324: { ! 325: if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0])) ! 326: { ! 327: exit(SS_RC_DAEMON_INTEGRITY); ! 328: } ! 329: } ! 330: atexit(libcharon_deinit); ! 331: if (!libcharon_init()) ! 332: { ! 333: exit(SS_RC_INITIALIZATION_FAILED); ! 334: } ! 335: for (group = 0; group < DBG_MAX; group++) ! 336: { ! 337: levels[group] = default_loglevel; ! 338: } ! 339: charon->set_default_loggers(charon, levels, TRUE); ! 340: charon->load_loggers(charon); ! 341: ! 342: if (!lookup_uid_gid()) ! 343: { ! 344: exit(SS_RC_INITIALIZATION_FAILED); ! 345: } ! 346: lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); ! 347: lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); ! 348: if (!charon->initialize(charon, ! 349: lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS))) ! 350: { ! 351: exit(SS_RC_INITIALIZATION_FAILED); ! 352: } ! 353: /* register this again after loading plugins to avoid issues with libraries ! 354: * that register atexit() handlers */ ! 355: atexit(libcharon_deinit); ! 356: if (!lib->caps->drop(lib->caps)) ! 357: { ! 358: exit(SS_RC_INITIALIZATION_FAILED); ! 359: } ! 360: ! 361: conn = cmd_connection_create(); ! 362: atexit(cleanup_conn); ! 363: creds = cmd_creds_create(); ! 364: atexit(cleanup_creds); ! 365: ! 366: if (uname(&utsname) != 0) ! 367: { ! 368: memset(&utsname, 0, sizeof(utsname)); ! 369: } ! 370: DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)", ! 371: VERSION, utsname.sysname, utsname.release, utsname.machine); ! 372: lib->plugins->status(lib->plugins, LEVEL_CTRL); ! 373: ! 374: /* handle all arguments */ ! 375: handle_arguments(argc, argv, FALSE); ! 376: ! 377: /* add handler for fatal signals, ! 378: * INT, TERM, HUP and USR1 are handled by sigwaitinfo() in run() */ ! 379: action.sa_flags = 0; ! 380: sigemptyset(&action.sa_mask); ! 381: sigaddset(&action.sa_mask, SIGINT); ! 382: sigaddset(&action.sa_mask, SIGTERM); ! 383: sigaddset(&action.sa_mask, SIGHUP); ! 384: sigaddset(&action.sa_mask, SIGUSR1); ! 385: ! 386: /* optionally let the external system handle fatal signals */ ! 387: #ifndef DISABLE_SIGNAL_HANDLER ! 388: action.sa_handler = segv_handler; ! 389: sigaction(SIGSEGV, &action, NULL); ! 390: sigaction(SIGILL, &action, NULL); ! 391: sigaction(SIGBUS, &action, NULL); ! 392: #endif /* DISABLE_SIGNAL_HANDLER */ ! 393: ! 394: action.sa_handler = SIG_IGN; ! 395: sigaction(SIGPIPE, &action, NULL); ! 396: ! 397: pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); ! 398: ! 399: /* start daemon with thread-pool */ ! 400: charon->start(charon); ! 401: /* wait for signal */ ! 402: return run(); ! 403: }