Annotation of embedaddon/strongswan/src/charon-cmd/charon-cmd.c, revision 1.1.1.2

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:                        case SIGTERM:
                    138:                        {
1.1.1.2 ! misho     139:                                DBG1(DBG_DMN, "%s received, shutting down",
        !           140:                                         sig == SIGINT ? "SIGINT" : "SIGTERM");
1.1       misho     141:                                charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
                    142:                                return 0;
                    143:                        }
                    144:                        case SIGUSR1:
                    145:                        {       /* an error occurred */
                    146:                                charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
                    147:                                return 1;
                    148:                        }
                    149:                }
                    150:        }
                    151: }
                    152: 
                    153: /**
                    154:  * lookup UID and GID
                    155:  */
                    156: static bool lookup_uid_gid()
                    157: {
                    158: #ifdef IPSEC_USER
                    159:        if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER))
                    160:        {
                    161:                return FALSE;
                    162:        }
                    163: #endif
                    164: #ifdef IPSEC_GROUP
                    165:        if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP))
                    166:        {
                    167:                return FALSE;
                    168:        }
                    169: #endif
                    170:        return TRUE;
                    171: }
                    172: 
                    173: #ifndef DISABLE_SIGNAL_HANDLER
                    174: /**
                    175:  * Handle SIGSEGV/SIGILL signals raised by threads
                    176:  */
                    177: static void segv_handler(int signal)
                    178: {
                    179:        backtrace_t *backtrace;
                    180: 
                    181:        DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
                    182:        backtrace = backtrace_create(2);
                    183:        backtrace->log(backtrace, stderr, TRUE);
                    184:        backtrace->destroy(backtrace);
                    185: 
                    186:        DBG1(DBG_DMN, "killing ourself, received critical signal");
                    187:        abort();
                    188: }
                    189: #endif /* DISABLE_SIGNAL_HANDLER */
                    190: 
                    191: /**
                    192:  * Print command line usage and exit
                    193:  */
                    194: static void usage(FILE *out, char *msg, char *binary)
                    195: {
                    196:        static const int padto = 18;
                    197:        char cmd[64], *pre, *post;
                    198:        int i, line, pad;
                    199: 
                    200:        if (msg)
                    201:        {
                    202:                fprintf(out, "%s\n", msg);
                    203:        }
                    204:        fprintf(out, "Usage: %s\n", binary);
                    205:        for (i = 0; i < CMD_OPT_COUNT; i++)
                    206:        {
                    207:                switch (cmd_options[i].has_arg)
                    208:                {
                    209:                        case required_argument:
                    210:                                pre = " <";
                    211:                                post = ">";
                    212:                                break;
                    213:                        case optional_argument:
                    214:                                pre = "[=";
                    215:                                post = "]";
                    216:                                break;
                    217:                        case no_argument:
                    218:                        default:
                    219:                                pre = "  ";
                    220:                                post = " ";
                    221:                                break;
                    222:                }
                    223:                snprintf(cmd, sizeof(cmd), "  --%s%s%s%s", cmd_options[i].name,
                    224:                                 pre, cmd_options[i].arg, post);
                    225:                pad = padto - strlen(cmd);
                    226:                if (pad >= 1)
                    227:                {
                    228:                        fprintf(out, "%s%-*s%s\n", cmd, pad, "", cmd_options[i].desc);
                    229:                }
                    230:                else
                    231:                {       /* write description to a separate line */
                    232:                        fprintf(out, "%s\n%-*s%s\n", cmd, padto, "", cmd_options[i].desc);
                    233:                }
                    234:                for (line = 0; line < countof(cmd_options[i].lines); line++)
                    235:                {
                    236:                        if (cmd_options[i].lines[line])
                    237:                        {
                    238:                                fprintf(out, "%-*s%s\n", padto, "", cmd_options[i].lines[line]);
                    239:                        }
                    240:                }
                    241:        }
                    242: }
                    243: 
                    244: /**
                    245:  * Handle command line options, if simple is TRUE only arguments like --help
                    246:  * and --version are handled.
                    247:  */
                    248: static void handle_arguments(int argc, char *argv[], bool simple)
                    249: {
                    250:        struct option long_opts[CMD_OPT_COUNT + 1] = {};
                    251:        int i, opt;
                    252: 
                    253:        for (i = 0; i < CMD_OPT_COUNT; i++)
                    254:        {
                    255:                long_opts[i].name = cmd_options[i].name;
                    256:                long_opts[i].val = cmd_options[i].id;
                    257:                long_opts[i].has_arg = cmd_options[i].has_arg;
                    258:        }
                    259:        /* reset option parser */
                    260:        optind = 1;
                    261:        while (TRUE)
                    262:        {
                    263:                bool handled = FALSE;
                    264: 
                    265:                opt = getopt_long(argc, argv, "", long_opts, NULL);
                    266:                switch (opt)
                    267:                {
                    268:                        case EOF:
                    269:                                break;
                    270:                        case CMD_OPT_HELP:
                    271:                                usage(stdout, NULL, argv[0]);
                    272:                                exit(0);
                    273:                        case CMD_OPT_VERSION:
                    274:                                printf("%s, strongSwan %s\n", "charon-cmd", VERSION);
                    275:                                exit(0);
                    276:                        case CMD_OPT_DEBUG:
                    277:                                default_loglevel = atoi(optarg);
                    278:                                continue;
                    279:                        default:
                    280:                                if (simple)
                    281:                                {
                    282:                                        continue;
                    283:                                }
                    284:                                handled |= conn->handle(conn, opt, optarg);
                    285:                                handled |= creds->handle(creds, opt, optarg);
                    286:                                if (handled)
                    287:                                {
                    288:                                        continue;
                    289:                                }
                    290:                                /* fall-through */
                    291:                        case '?':
                    292:                                /* missing argument, unrecognized option */
                    293:                                usage(stderr, NULL, argv[0]);
                    294:                                exit(1);
                    295:                }
                    296:                break;
                    297:        }
                    298: }
                    299: 
                    300: /**
                    301:  * Main function, starts the daemon.
                    302:  */
                    303: int main(int argc, char *argv[])
                    304: {
                    305:        struct sigaction action;
                    306:        struct utsname utsname;
                    307:        level_t levels[DBG_MAX];
                    308:        int group;
                    309: 
                    310:        /* handle simple arguments */
                    311:        handle_arguments(argc, argv, TRUE);
                    312: 
                    313:        dbg = dbg_stderr;
                    314:        atexit(library_deinit);
                    315:        if (!library_init(NULL, "charon-cmd"))
                    316:        {
                    317:                exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
                    318:        }
                    319:        if (lib->integrity)
                    320:        {
                    321:                if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0]))
                    322:                {
                    323:                        exit(SS_RC_DAEMON_INTEGRITY);
                    324:                }
                    325:        }
                    326:        atexit(libcharon_deinit);
                    327:        if (!libcharon_init())
                    328:        {
                    329:                exit(SS_RC_INITIALIZATION_FAILED);
                    330:        }
                    331:        for (group = 0; group < DBG_MAX; group++)
                    332:        {
                    333:                levels[group] = default_loglevel;
                    334:        }
                    335:        charon->set_default_loggers(charon, levels, TRUE);
                    336:        charon->load_loggers(charon);
                    337: 
                    338:        if (!lookup_uid_gid())
                    339:        {
                    340:                exit(SS_RC_INITIALIZATION_FAILED);
                    341:        }
                    342:        lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
                    343:        lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
                    344:        if (!charon->initialize(charon,
                    345:                        lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS)))
                    346:        {
                    347:                exit(SS_RC_INITIALIZATION_FAILED);
                    348:        }
                    349:        /* register this again after loading plugins to avoid issues with libraries
                    350:         * that register atexit() handlers */
                    351:        atexit(libcharon_deinit);
                    352:        if (!lib->caps->drop(lib->caps))
                    353:        {
                    354:                exit(SS_RC_INITIALIZATION_FAILED);
                    355:        }
                    356: 
                    357:        conn = cmd_connection_create();
                    358:        atexit(cleanup_conn);
                    359:        creds = cmd_creds_create();
                    360:        atexit(cleanup_creds);
                    361: 
                    362:        if (uname(&utsname) != 0)
                    363:        {
                    364:                memset(&utsname, 0, sizeof(utsname));
                    365:        }
                    366:        DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
                    367:                 VERSION, utsname.sysname, utsname.release, utsname.machine);
                    368:        lib->plugins->status(lib->plugins, LEVEL_CTRL);
                    369: 
                    370:        /* handle all arguments */
                    371:        handle_arguments(argc, argv, FALSE);
                    372: 
                    373:        /* add handler for fatal signals,
                    374:         * INT, TERM, HUP and USR1 are handled by sigwaitinfo() in run() */
                    375:        action.sa_flags = 0;
                    376:        sigemptyset(&action.sa_mask);
                    377:        sigaddset(&action.sa_mask, SIGINT);
                    378:        sigaddset(&action.sa_mask, SIGTERM);
                    379:        sigaddset(&action.sa_mask, SIGHUP);
                    380:        sigaddset(&action.sa_mask, SIGUSR1);
                    381: 
                    382:        /* optionally let the external system handle fatal signals */
                    383: #ifndef DISABLE_SIGNAL_HANDLER
                    384:        action.sa_handler = segv_handler;
                    385:        sigaction(SIGSEGV, &action, NULL);
                    386:        sigaction(SIGILL, &action, NULL);
                    387:        sigaction(SIGBUS, &action, NULL);
                    388: #endif /* DISABLE_SIGNAL_HANDLER */
                    389: 
                    390:        action.sa_handler = SIG_IGN;
                    391:        sigaction(SIGPIPE, &action, NULL);
                    392: 
                    393:        pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
                    394: 
                    395:        /* start daemon with thread-pool */
                    396:        charon->start(charon);
                    397:        /* wait for signal */
                    398:        return run();
                    399: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>