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

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: }

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