/* Pluto main program * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2001 D. Hugh Redelmeier. * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* missing from on old systems */ #include #include #include #include #include #ifdef CAPABILITIES #ifdef HAVE_SYS_CAPABILITY_H #include #endif /* HAVE_SYS_CAPABILITY_H */ #endif /* CAPABILITIES */ #include #include #include #include #include #include #include #include #include "constants.h" #include "defs.h" #include "myid.h" #include "ca.h" #include "certs.h" #include "ac.h" #include "connections.h" #include "foodgroups.h" #include "packet.h" #include "demux.h" /* needs packet.h */ #include "server.h" #include "kernel.h" #include "log.h" #include "keys.h" #include "adns.h" /* needs */ #include "dnskey.h" /* needs keys.h and adns.h */ #include "state.h" #include "ipsec_doi.h" /* needs demux.h and state.h */ #include "ocsp.h" #include "crl.h" #include "fetch.h" #include "crypto.h" #include "nat_traversal.h" #include "virtual.h" #include "timer.h" #include "vendor.h" #include "builder.h" #include "whack_attribute.h" #include "pluto.h" #ifdef ANDROID #include /* for AID_VPN */ #endif /** * Number of threads in the thread pool, if not specified in config. */ #define DEFAULT_THREADS 4 /** * PID file, in which pluto stores its process id */ static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; /** * TRUE if the lock has been checked. This helps to avoid any unintended * deletion of the lock or control socket. */ static bool pluto_lock_checked = FALSE; /** * Global reference to PID file (required to truncate, if undeletable) */ static FILE *pidfile = NULL; static void usage(const char *mess) { if (mess != NULL && *mess != '\0') fprintf(stderr, "%s\n", mess); fprintf(stderr , "Usage: pluto" " [--help]" " [--version]" " [--optionsfrom ]" " \\\n\t" "[--nofork]" " [--stderrlog]" " [--nocrsend]" " \\\n\t" "[--strictcrlpolicy]" " [--crlcheckinterval ]" " [--cachecrls]" " [--uniqueids]" " \\\n\t" "[--interface ]" " [--ikeport ]" " \\\n\t" "[--ctlbase ]" " \\\n\t" "[--perpeerlogbase ] [--perpeerlog]" " \\\n\t" "[--secretsfile ]" " [--policygroupsdir ]" " \\\n\t" "[--adns ]" "[--pkcs11module ]" "[--pkcs11keepstate]" "[--pkcs11initargs ]" #ifdef DEBUG " \\\n\t" "[--debug-none]" " [--debug-all]" " \\\n\t" "[--debug-raw]" " [--debug-crypt]" " [--debug-parsing]" " [--debug-emitting]" " \\\n\t" "[--debug-control]" " [--debug-lifecycle]" " [--debug-kernel]" " [--debug-dns]" " \\\n\t" "[--debug-oppo]" " [--debug-controlmore]" " [--debug-private]" " [--debug-natt]" #endif " \\\n\t" "[--nat_traversal] [--keep_alive ]" " \\\n\t" "[--force_keepalive] [--disable_port_floating]" " \\\n\t" "[--virtual_private ]" "\n" "strongSwan "VERSION"\n"); exit_pluto(mess == NULL? 0 : 1); } static bool check_lock() { struct stat stb; FILE *fpid; if (stat(pluto_lock, &stb) == 0) { fpid = fopen(pluto_lock, "r"); if (fpid) { char buf[64]; pid_t pid = 0; memset(buf, 0, sizeof(buf)); if (fread(buf, 1, sizeof(buf), fpid)) { buf[sizeof(buf) - 1] = '\0'; pid = atoi(buf); } fclose(fpid); if (pid && kill(pid, 0) == 0) { /* such a process is running */ return TRUE; } } fprintf(stderr, "pluto: removing lock file \"%s\", process not " "running\n", pluto_lock); unlink(pluto_lock); } pluto_lock_checked = TRUE; return FALSE; } static void fill_lock(void) { pidfile = fopen(pluto_lock, "w"); if (pidfile) { fprintf(pidfile, "%u\n", (u_int)getpid()); fflush(pidfile); } /* keep pidfile open so we can truncate it, if we cannot delete it */ } static void delete_lock(void) { /* because unlinking the PID file may fail, we truncate it to ensure the * daemon can be properly restarted. one probable cause for this is the * combination of not running as root and the effective user lacking * permissions on the parent dir(s) of the PID file */ if (pluto_lock_checked) { if (pidfile) { ignore_result(ftruncate(fileno(pidfile), 0)); fclose(pidfile); } unlink(pluto_lock); /* delete this here to avoid that exit_pluto calls delete the socket */ delete_ctl_socket(); } } /* by default pluto sends certificate requests to its peers */ bool no_cr_send = FALSE; /* by default the CRL policy is lenient */ bool strict_crl_policy = FALSE; /* by default CRLs are cached locally as files */ bool cache_crls = FALSE; /* by default pluto does not check crls dynamically */ long crl_check_interval = 0; /* path to the PKCS#11 module */ char *pkcs11_module_path = NULL; /* by default pluto logs out after every smartcard use */ bool pkcs11_keep_state = FALSE; /* by default pluto does not allow pkcs11 proxy access via whack */ bool pkcs11_proxy = FALSE; /* argument string to pass to PKCS#11 module. * Not used for compliant modules, just for NSS softoken */ static const char *pkcs11_init_args = NULL; /* options read by optionsfrom */ options_t *options; int main(int argc, char **argv) { bool fork_desired = TRUE; bool log_to_stderr_desired = FALSE; bool nat_traversal = FALSE; bool nat_t_spf = TRUE; /* support port floating */ unsigned int keep_alive = 0; bool force_keepalive = FALSE; char *virtual_private = NULL; #ifdef CAPABILITIES int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, #ifdef ANDROID CAP_NET_RAW, #endif }; #endif /* CAPABILITIES */ /* initialize library and optionsfrom */ if (!library_init(NULL)) { library_deinit(); exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (!libhydra_init("pluto")) { libhydra_deinit(); library_deinit(); exit(SS_RC_INITIALIZATION_FAILED); } if (!pluto_init(argv[0])) { pluto_deinit(); libhydra_deinit(); library_deinit(); exit(SS_RC_DAEMON_INTEGRITY); } options = options_create(); /* handle arguments */ for (;;) { # define DBG_OFFSET 256 static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "nofork", no_argument, NULL, 'd' }, { "stderrlog", no_argument, NULL, 'e' }, { "nocrsend", no_argument, NULL, 'c' }, { "strictcrlpolicy", no_argument, NULL, 'r' }, { "crlcheckinterval", required_argument, NULL, 'x'}, { "cachecrls", no_argument, NULL, 'C' }, { "uniqueids", no_argument, NULL, 'u' }, { "interface", required_argument, NULL, 'i' }, { "ikeport", required_argument, NULL, 'p' }, { "ctlbase", required_argument, NULL, 'b' }, { "secretsfile", required_argument, NULL, 's' }, { "foodgroupsdir", required_argument, NULL, 'f' }, { "perpeerlogbase", required_argument, NULL, 'P' }, { "perpeerlog", no_argument, NULL, 'l' }, { "policygroupsdir", required_argument, NULL, 'f' }, { "adns", required_argument, NULL, 'a' }, { "pkcs11module", required_argument, NULL, 'm' }, { "pkcs11keepstate", no_argument, NULL, 'k' }, { "pkcs11initargs", required_argument, NULL, 'z' }, { "pkcs11proxy", no_argument, NULL, 'y' }, { "nat_traversal", no_argument, NULL, '1' }, { "keep_alive", required_argument, NULL, '2' }, { "force_keepalive", no_argument, NULL, '3' }, { "disable_port_floating", no_argument, NULL, '4' }, { "debug-natt", no_argument, NULL, '5' }, { "virtual_private", required_argument, NULL, '6' }, #ifdef DEBUG { "debug-none", no_argument, NULL, 'N' }, { "debug-all", no_argument, NULL, 'A' }, { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET }, { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET }, { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET }, { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET }, { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET }, #endif { 0,0,0,0 } }; /* Note: we don't like the way short options get parsed * by getopt_long, so we simply pass an empty string as * the list. It could be "hvdenp:l:s:" "NARXPECK". */ int c = getopt_long(argc, argv, "", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* long option already handled */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ usage(""); break; /* not actually reached */ case 'h': /* --help */ usage(NULL); break; /* not actually reached */ case 'v': /* --version */ { const char **sp = ipsec_copyright_notice(); printf("strongSwan "VERSION"%s\n", compile_time_interop_options); for (; *sp != NULL; sp++) puts(*sp); } exit_pluto(0); break; /* not actually reached */ case '+': /* --optionsfrom */ if (!options->from(options, optarg, &argc, &argv, optind)) { exit_pluto(1); } continue; case 'd': /* --nofork*/ fork_desired = FALSE; continue; case 'e': /* --stderrlog */ log_to_stderr_desired = TRUE; continue; case 'c': /* --nocrsend */ no_cr_send = TRUE; continue; case 'r': /* --strictcrlpolicy */ strict_crl_policy = TRUE; continue; case 'x': /* --crlcheckinterval