/* Pluto main program * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2001 D. Hugh Redelmeier. * * 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. * * RCSID $Id: plutomain.c 3914 2008-05-08 10:58:04Z martin $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* missing from on old systems */ #include #include #include #include #include #include #include #include #include "constants.h" #include "defs.h" #include "id.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 "rnd.h" #include "state.h" #include "ipsec_doi.h" /* needs demux.h and state.h */ #include "ocsp.h" #include "crl.h" #include "fetch.h" #include "xauth.h" #include "sha1.h" #include "md5.h" #include "crypto.h" /* requires sha1.h and md5.h */ #include "nat_traversal.h" #include "virtual.h" /* on some distros, a capset() definition is missing */ #ifdef NO_CAPSET_DEFINED extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap); #endif /* NO_CAPSET_DEFINED */ 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]" " [--noklips]" " [--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-klips]" " [--debug-dns]" " \\\n\t" "[--debug-oppo]" " [--debug-controlmore]" " [--debug-private]" #endif " [ --debug-natt]" " \\\n\t" "[--nat_traversal] [--keep_alive ]" " \\\n\t" "[--force_keepalive] [--disable_port_floating]" " \\\n\t" "[--virtual_private ]" "\n" "strongSwan %s\n" , ipsec_version_code()); exit_pluto(mess == NULL? 0 : 1); } /* lock file support * - provides convenient way for scripts to find Pluto's pid * - prevents multiple Plutos competing for the same port * - same basename as unix domain control socket * NOTE: will not take account of sharing LOCK_DIR with other systems. */ static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; static bool pluto_lock_created = FALSE; /* create lockfile, or die in the attempt */ static int create_lock(void) { int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC , S_IRUSR | S_IRGRP | S_IROTH); if (fd < 0) { if (errno == EEXIST) { fprintf(stderr, "pluto: lock file \"%s\" already exists\n" , pluto_lock); exit_pluto(10); } else { fprintf(stderr , "pluto: unable to create lock file \"%s\" (%d %s)\n" , pluto_lock, errno, strerror(errno)); exit_pluto(1); } } pluto_lock_created = TRUE; return fd; } static bool fill_lock(int lockfd, pid_t pid) { char buf[30]; /* holds "\n" */ int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid); bool ok = len > 0 && write(lockfd, buf, len) == len; close(lockfd); return ok; } static void delete_lock(void) { if (pluto_lock_created) { delete_ctl_socket(); unlink(pluto_lock); /* is noting failure useful? */ } } /* 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; 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; int lockfd; struct __user_cap_header_struct hdr; struct __user_cap_data_struct data; /* 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' }, { "noklips", no_argument, NULL, 'n' }, { "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' }, #ifdef USE_LWRES { "lwdnsq", required_argument, NULL, 'a' }, #else /* !USE_LWRES */ { "adns", required_argument, NULL, 'a' }, #endif /* !USE_LWRES */ { "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_KLIPS + 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("%s%s\n", ipsec_version_string(), compile_time_interop_options); for (; *sp != NULL; sp++) puts(*sp); } exit_pluto(0); break; /* not actually reached */ case '+': /* --optionsfrom */ optionsfrom(optarg, &argc, &argv, optind, stderr); /* does not return on error */ continue; case 'd': /* --nofork*/ fork_desired = FALSE; continue; case 'e': /* --stderrlog */ log_to_stderr_desired = TRUE; continue; case 'n': /* --noklips */ no_klips = TRUE; continue; case 'c': /* --nocrsend */ no_cr_send = TRUE; continue; case 'r': /* --strictcrlpolicy */ strict_crl_policy = TRUE; continue; case 'x': /* --crlcheckinterval