Annotation of embedaddon/strongswan/src/charon-cmd/charon-cmd.c, revision 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>