/* * Initialize crypto helper debug delay value from environment variable. * This function is NOT thread safe (getenv). */ static void init_crypto_helper_delay(void) { const char *envdelay; unsigned long delay; err_t error; envdelay = getenv("PLUTO_CRYPTO_HELPER_DELAY"); if (envdelay == NULL) return; error = ttoulb(envdelay, 0, 0, secs_per_hour, &delay); if (error != NULL) libreswan_log("$PLUTO_CRYPTO_HELPER_DELAY malformed: %s", error); else crypto_helper_delay = (int)delay; }
/* - main - mostly argument parsing */ int main(int argc, char *argv[]) { log_to_stderr = FALSE; tool_init_log("ipsec rsasigkey"); int opt; int nbits = 0; int seedbits = DEFAULT_SEED_BITS; while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF) switch (opt) { case 'n': case 'p': fprintf(stderr, "%s: --noopt and --rounds options have been obsoleted - ignored\n", progname); break; case 'v': /* verbose description */ log_to_stderr = TRUE; break; case 'r': fprintf(stderr, "%s: Warning: --random is obsoleted for --seeddev. It no longer specifies the random device used for obtaining random key material", progname); /* FALLTHROUGH */ case 'S': /* nonstandard random device for seed */ device = optarg; break; case 'H': /* set hostname for output */ { size_t full_len = strlen(optarg); bool oflow = sizeof(outputhostname) - 1 < full_len; size_t copy_len = oflow ? sizeof(outputhostname) - 1 : full_len; memcpy(outputhostname, optarg, copy_len); outputhostname[copy_len] = '\0'; } break; case 'h': /* help */ printf("Usage:\t%s\n", usage); exit(0); break; case 'V': /* version */ printf("%s %s\n", progname, ipsec_version_code()); exit(0); break; case 'c': /* obsoleted by --nssdir|-d */ case 'd': /* -d is used for nssdirdir with nss tools */ lsw_conf_nssdir(optarg); break; case 'P': /* token authentication password */ lsw_conf_nsspassword(optarg); break; case 's': /* seed bits */ seedbits = atoi(optarg); if (PK11_IsFIPS()) { if (seedbits < DEFAULT_SEED_BITS) { fprintf(stderr, "%s: FIPS mode does not allow < %d seed bits\n", progname, DEFAULT_SEED_BITS); exit(1); } } break; case '?': default: printf("Usage:\t%s\n", usage); exit(2); } if (outputhostname[0] == '\0') { if (gethostname(outputhostname, sizeof(outputhostname)) < 0) { fprintf(stderr, "%s: gethostname failed (%s)\n", progname, strerror(errno)); exit(1); } } /* * RSA-PSS requires keysize to be a multiple of 8 bits * (see PCS#1 v2.1). * We require a multiple of 16. (??? why?) */ if (argv[optind] == NULL) { /* default keysize: a multiple of 16 in [3072,4096) */ srand(time(NULL)); nbits = 3072 + 16 * (rand() % (1024 / 16)); } else { unsigned long u; err_t ugh = ttoulb(argv[optind], 0, 10, INT_MAX, &u); if (ugh != NULL) { fprintf(stderr, "%s: keysize specification is malformed: %s\n", progname, ugh); exit(1); } nbits = u; } if (nbits < MIN_KEYBIT ) { fprintf(stderr, "%s: requested RSA key size (%d) is too small - use %d or more\n", progname, nbits, MIN_KEYBIT); exit(1); } else if (nbits > MAXBITS) { fprintf(stderr, "%s: requested RSA key size (%d) is too large - (max %d)\n", progname, nbits, MAXBITS); exit(1); } else if (nbits % (BITS_PER_BYTE * 2) != 0) { fprintf(stderr, "%s: requested RSA key size (%d) is not a multiple of %d\n", progname, nbits, (int)BITS_PER_BYTE * 2); exit(1); } /* * Don't fetch the config options until after they have been * processed, and really are "constant". */ const struct lsw_conf_options *oco = lsw_init_options(); rsasigkey(nbits, seedbits, oco); exit(0); }
int main(int argc, char **argv) { #if 0 NSS_NoDB_Init("."); if (!test_aes_cbc(&algo_aes_cbc)) { printf("aes-cbc failed\n"); } if (!test_camellia_cbc(&algo_camellia_cbc)) { printf("camellia-cbc failed\n"); } if (!test_aes_ctr(&algo_aes_ctr)) { printf("aes-ctr failed\n"); } exit(0); #endif int lockfd; /* * We read the intentions for how to log from command line options * and the config file. Then we prepare to be able to log, but until * then log to stderr (better then nothing). Once we are ready to * actually do loggin according to the methods desired, we set the * variables for those methods */ bool log_to_stderr_desired = FALSE; bool log_to_file_desired = FALSE; { int i; /* MUST BE BEFORE ANY allocs */ for (i = 1; i < argc; ++i) { if (streq(argv[i], "--leak-detective")) leak_detective = TRUE; } } pluto_name = argv[0]; coredir = clone_str("/var/run/pluto", "coredir in main()"); pluto_vendorid = clone_str(ipsec_version_vendorid(), "vendorid in main()"); unsigned int keep_alive = 0; /* Overridden by virtual_private= in ipsec.conf */ char *virtual_private = NULL; libreswan_passert_fail = passert_fail; /* handle arguments */ for (;; ) { /* * 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 longindex = -1; int c = getopt_long(argc, argv, "", long_opts, &longindex); const char *optname = NULL; err_t ugh = NULL; /* complaint from case */ unsigned long u = 0; /* scratch for case */ if (longindex != -1) { const char *optmeta; optname = long_opts[longindex].name; optmeta = optname + strlen(optname) + 1; /* after '\0' */ switch (optmeta[0]) { case '_': libreswan_log("warning: option \"--%s\" with '_' in its name is obsolete; use '-'", optname); break; case '>': libreswan_log("warning: option \"--%s\" is obsolete; use \"--%s\"", optname, optmeta + 1); break; case '!': libreswan_log("warning: option \"--%s\" is obsolete; ignored", optname); continue; /* ignore it! */ } } /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* * Long option already handled by getopt_long. * Not currently used since we always set flag to NULL. */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ invocation_fail(NULL); break; case 'h': /* --help */ usage(); break; /* not actually reached */ case 'X': /* --leak-detective */ /* * This flag was already processed at the start of main() * because leak_detective must be immutable from before * the first alloc(). * If this option is specified, we must have already * set it at the start of main(), so assert it. */ passert(leak_detective); continue; case 'C': /* --coredir */ pfree(coredir); coredir = clone_str(optarg, "coredir via getopt"); continue; case 'V': /* --vendorid */ pfree(pluto_vendorid); coredir = clone_str(optarg, "pluto_vendorid via getopt"); continue; case 'S': /* --statsdir */ pfreeany(pluto_stats_binary); pluto_stats_binary = clone_str(optarg, "statsbin"); continue; case 'v': /* --version */ printf("%s%s\n", ipsec_version_string(), compile_time_interop_options); /* not exit_pluto because we are not initialized yet */ exit(0); break; /* not actually reached */ case 'j': /* --nhelpers */ if (streq(optarg, "-1")) { nhelpers = -1; } else { ugh = ttoulb(optarg, 0, 10, 1000, &u); if (ugh != NULL) break; nhelpers = u; } continue; case 'c': /* --seedbits */ pluto_nss_seedbits = atoi(optarg); if (pluto_nss_seedbits == 0) { printf("pluto: seedbits must be an integer > 0"); /* not exit_pluto because we are not initialized yet */ exit(PLUTO_EXIT_NSS_FAIL); } continue; #ifdef HAVE_LABELED_IPSEC case 'w': /* --secctx-attr-type */ ugh = ttoulb(optarg, 0, 0, 0xFFFF, &u); if (ugh != NULL) break; if (u != SECCTX && u != ECN_TUNNEL_or_old_SECCTX) { ugh = "must be a positive 32001 (default) or 10 (for backward compatibility)"; break; } secctx_attr_type = u; continue; #endif case 'd': /* --nofork*/ fork_desired = FALSE; continue; case 'e': /* --stderrlog */ log_to_stderr_desired = TRUE; continue; case 'g': /* --logfile */ pluto_log_file = optarg; log_to_file_desired = TRUE; continue; case 't': /* --log-no-time */ log_with_timestamp = FALSE; continue; case '7': /* --log-no-append */ log_append = FALSE; continue; case '8': /* --drop-oppo-null */ pluto_drop_oppo_null = TRUE; continue; case '9': /* --expire-bare-shunt <interval> */ ugh = ttoulb(optarg, 0, 10, 1000, &u); if (ugh != NULL) break; bare_shunt_interval = u; continue; case 'k': /* --use-klips */ kern_interface = USE_KLIPS; continue; case 'L': /* --listen ip_addr */ { ip_address lip; err_t e = ttoaddr(optarg, 0, AF_UNSPEC, &lip); if (e != NULL) { /* *??? should we continue on failure? * If not, use ugh mechanism. */ libreswan_log( "invalid listen argument ignored: %s\n", e); } else { pluto_listen = clone_str(optarg, "pluto_listen"); libreswan_log( "bind() will be filtered for %s\n", pluto_listen); } } continue; case 'M': /* --use-mast */ kern_interface = USE_MASTKLIPS; continue; case 'F': /* --use-bsdkame */ kern_interface = USE_BSDKAME; continue; case 'K': /* --use-netkey */ kern_interface = USE_NETKEY; continue; case 'n': /* --use-nostack */ kern_interface = NO_KERNEL; continue; case 'D': /* --force-busy */ pluto_ddos_mode = DDOS_FORCE_BUSY; continue; case 'U': /* --force-unlimited */ pluto_ddos_mode = DDOS_FORCE_UNLIMITED; continue; case 'Z': /* --curl-iface */ curl_iface = optarg; continue; case 'I': /* --curl-timeout */ ugh = ttoulb(optarg, 0, 10, 0xFFFF, &u); if (ugh != NULL) break; if (u <= 0) { ugh = "must not be < 1"; break; } curl_timeout = u; continue; case 'r': /* --strictcrlpolicy */ strict_crl_policy = TRUE; continue; case 'o': strict_ocsp_policy = TRUE; continue; case 'O': ocsp_enable = TRUE; continue; case 'Y': ocsp_default_uri = optarg; continue; case 'J': ocsp_trust_name = optarg; continue; case 'T': /* --ocsp_timeout <seconds> */ ugh = ttoulb(optarg, 0, 10, 0xFFFF, &u); if (ugh != NULL) break; if (u == 0) { ugh = "must not be 0"; break; } ocsp_timeout = u; continue; case 'x': /* --crlcheckinterval <seconds> */ ugh = ttoulb(optarg, 0, 10, TIME_T_MAX, &u); if (ugh != NULL) break; crl_check_interval = deltatime(u); continue; case 'u': /* --uniqueids */ uniqueIDs = TRUE; continue; case 'i': /* --interface <ifname|ifaddr> */ if (!use_interface(optarg)) { ugh = "too many --interface specifications"; break; } continue; /* * This option does not really work, as this is the "left" * site only, you also need --to --ikeport again later on * It will result in: yourport -> 500, still not bypassing * filters */ case 'p': /* --ikeport <portnumber> */ ugh = ttoulb(optarg, 0, 10, 0xFFFF, &u); if (ugh != NULL) break; if (u == 0) { ugh = "must not be 0"; break; } pluto_port = u; continue; case 'q': /* --natikeport <portnumber> */ ugh = ttoulb(optarg, 0, 10, 0xFFFF, &u); if (ugh != NULL) break; if (u == 0) { ugh = "must not be 0"; break; } pluto_nat_port = u; continue; case 'b': /* --ctlbase <path> */ /* * ??? work to be done here: * * snprintf returns the required space if there * isn't enough, not -1. * -1 indicates another kind of error. * * This appears to be the only place where the * ctlbase value is used yet it is set elsewhere. * (This isn't clear -- it may be OK.) */ ctlbase = optarg; if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path), "%s%s", ctlbase, CTL_SUFFIX) == -1) { ugh = "<path>" CTL_SUFFIX " too long for sun_path"; break; } if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path), "%s%s", ctlbase, INFO_SUFFIX) == -1) { ugh = "<path>" INFO_SUFFIX " too long for sun_path"; break; } if (snprintf(pluto_lock, sizeof(pluto_lock), "%s%s", ctlbase, LOCK_SUFFIX) == -1) { ugh = "<path>" LOCK_SUFFIX " must fit"; break; } continue; case 's': /* --secretsfile <secrets-file> */ lsw_conf_secretsfile(optarg); continue; case 'f': /* --ipsecdir <ipsec-dir> */ lsw_init_ipsecdir(optarg); continue; case 'N': /* --debug-none */ base_debugging = DBG_NONE; continue; case 'A': /* --debug-all */ base_debugging = DBG_ALL; continue; case 'P': /* --perpeerlogbase */ base_perpeer_logdir = optarg; continue; case 'l': /* --perpeerlog */ log_to_perpeer = TRUE; continue; case '2': /* --keep-alive <delay_secs> */ ugh = ttoulb(optarg, 0, 10, secs_per_day, &u); if (ugh != NULL) break; keep_alive = u; continue; case '5': /* --debug-nat-t */ base_debugging |= DBG_NATT; continue; case '6': /* --virtual-private */ virtual_private = optarg; continue; case 'z': /* --config */ { /* * Config struct to variables mapper. This will * overwrite all previously set options. Keep this * in the same order as long_opts[] is. */ struct starter_config *cfg = read_cfg_file(optarg); /* leak */ set_cfg_string(&pluto_log_file, cfg->setup.strings[KSF_PLUTOSTDERRLOG]); if (pluto_log_file != NULL) log_to_syslog = FALSE; /* plutofork= no longer supported via config file */ log_with_timestamp = cfg->setup.options[KBF_PLUTOSTDERRLOGTIME]; log_append = cfg->setup.options[KBF_PLUTOSTDERRLOGAPPEND]; pluto_drop_oppo_null = cfg->setup.options[KBF_DROP_OPPO_NULL]; pluto_ddos_mode = cfg->setup.options[KBF_DDOS_MODE]; if (cfg->setup.options[KBF_FORCEBUSY]) { /* force-busy is obsoleted, translate to ddos-mode= */ pluto_ddos_mode = cfg->setup.options[KBF_DDOS_MODE] = DDOS_FORCE_BUSY; } /* ddos-ike-threshold and max-halfopen-ike */ pluto_ddos_threshold = cfg->setup.options[KBF_DDOS_IKE_THRESHOLD]; pluto_max_halfopen = cfg->setup.options[KBF_MAX_HALFOPEN_IKE]; strict_crl_policy = cfg->setup.options[KBF_STRICTCRLPOLICY]; pluto_shunt_lifetime = deltatime(cfg->setup.options[KBF_SHUNTLIFETIME]); strict_ocsp_policy = cfg->setup.options[KBF_STRICTOCSPPOLICY]; ocsp_enable = cfg->setup.options[KBF_OCSPENABLE]; set_cfg_string(&ocsp_default_uri, cfg->setup.strings[KSF_OCSPURI]); ocsp_timeout = cfg->setup.options[KBF_OCSPTIMEOUT]; set_cfg_string(&ocsp_trust_name, cfg->setup.strings[KSF_OCSPTRUSTNAME]); crl_check_interval = deltatime( cfg->setup.options[KBF_CRLCHECKINTERVAL]); uniqueIDs = cfg->setup.options[KBF_UNIQUEIDS]; /* * We don't check interfaces= here because that part * has been dealt with in _stackmanager before we * started */ set_cfg_string(&pluto_listen, cfg->setup.strings[KSF_LISTEN]); /* --ikeport */ pluto_port = cfg->setup.options[KBF_IKEPORT]; /* --nflog-all */ /* only causes nflog nmber to show in ipsec status */ pluto_nflog_group = cfg->setup.options[KBF_NFLOG_ALL]; /* only causes nflog nmber to show in ipsec status */ pluto_xfrmlifetime = cfg->setup.options[KBF_XFRMLIFETIME]; /* no config option: ctlbase */ /* --secrets */ if (cfg->setup.strings[KSF_SECRETSFILE] && *cfg->setup.strings[KSF_SECRETSFILE]) { lsw_conf_secretsfile(cfg->setup.strings[KSF_SECRETSFILE]); } if (cfg->setup.strings[KSF_IPSECDIR] != NULL && *cfg->setup.strings[KSF_IPSECDIR] != 0) { /* --ipsecdir */ lsw_init_ipsecdir(cfg->setup.strings[KSF_IPSECDIR]); } /* --perpeerlog */ log_to_perpeer = cfg->setup.options[KBF_PERPEERLOG]; if (log_to_perpeer) { /* --perpeerlogbase */ if (cfg->setup.strings[KSF_PERPEERDIR]) { set_cfg_string(&base_perpeer_logdir, cfg->setup.strings[KSF_PERPEERDIR]); } else { base_perpeer_logdir = clone_str("/var/log/pluto/", "perpeer_logdir"); } } if (cfg->setup.strings[KSF_CURLIFACE]) { pfreeany(curl_iface); /* curl-iface= */ curl_iface = clone_str(cfg->setup.strings[KSF_CURLIFACE], "curl-iface= via --config"); } if (cfg->setup.options[KBF_CURLTIMEOUT]) curl_timeout = cfg->setup.options[KBF_CURLTIMEOUT]; if (cfg->setup.strings[KSF_DUMPDIR]) { pfree(coredir); /* dumpdir= */ coredir = clone_str(cfg->setup.strings[KSF_DUMPDIR], "coredir via --config"); } /* --vendorid */ if (cfg->setup.strings[KSF_MYVENDORID]) { pfree(pluto_vendorid); pluto_vendorid = clone_str(cfg->setup.strings[KSF_MYVENDORID], "pluto_vendorid via --config"); } /* no config option: pluto_adns_option */ if (cfg->setup.strings[KSF_STATSBINARY] != NULL) { if (access(cfg->setup.strings[KSF_STATSBINARY], X_OK) == 0) { pfreeany(pluto_stats_binary); /* statsbin= */ pluto_stats_binary = clone_str(cfg->setup.strings[KSF_STATSBINARY], "statsbin via --config"); libreswan_log("statsbinary set to %s", pluto_stats_binary); } else { libreswan_log("statsbinary= '%s' ignored - file does not exist or is not executable", pluto_stats_binary); } } pluto_nss_seedbits = cfg->setup.options[KBF_SEEDBITS]; pluto_nat_port = cfg->setup.options[KBF_NATIKEPORT]; keep_alive = cfg->setup.options[KBF_KEEPALIVE]; set_cfg_string(&virtual_private, cfg->setup.strings[KSF_VIRTUALPRIVATE]); nhelpers = cfg->setup.options[KBF_NHELPERS]; #ifdef HAVE_LABELED_IPSEC secctx_attr_type = cfg->setup.options[KBF_SECCTX]; #endif base_debugging = cfg->setup.options[KBF_PLUTODEBUG]; char *protostack = cfg->setup.strings[KSF_PROTOSTACK]; if (protostack == NULL || *protostack == '\0') { kern_interface = USE_NETKEY; } else if (streq(protostack, "none")) { kern_interface = NO_KERNEL; } else if (streq(protostack, "auto")) { libreswan_log( "The option protostack=auto is obsoleted, falling back to protostack=netkey\n"); kern_interface = USE_NETKEY; } else if (streq(protostack, "klips")) { kern_interface = USE_KLIPS; } else if (streq(protostack, "mast")) { kern_interface = USE_MASTKLIPS; } else if (streq(protostack, "netkey") || streq(protostack, "native")) { kern_interface = USE_NETKEY; } else if (streq(protostack, "bsd") || streq(protostack, "kame") || streq(protostack, "bsdkame")) { kern_interface = USE_BSDKAME; } else if (streq(protostack, "win2k")) { kern_interface = USE_WIN2K; } confread_free(cfg); continue; } default: if (DBG_OFFSET <= c && c < DBG_OFFSET + IMPAIR_roof_IX) { base_debugging |= LELEM(c - DBG_OFFSET); continue; } bad_case(c); } /* if ugh is set, bail with diagnostic */ if (ugh != NULL) { char mess[200]; if (longindex == -1) { snprintf(mess, sizeof(mess), "unknown option: %s", ugh); } else if (optarg == NULL) { snprintf(mess, sizeof(mess), "--%s option: %s", optname, ugh); } else { snprintf(mess, sizeof(mess), "--%s \"%s\" option: %s", optname, optarg, ugh); } invocation_fail(mess); } break; } if (optind != argc) invocation_fail("unexpected argument"); reset_debugging(); if (chdir(coredir) == -1) { int e = errno; libreswan_log("pluto: warning: chdir(\"%s\") to dumpdir failed (%d: %s)", coredir, e, strerror(e)); } oco = lsw_init_options(); lockfd = create_lock(); /* select between logging methods */ if (log_to_stderr_desired || log_to_file_desired) log_to_syslog = FALSE; if (!log_to_stderr_desired) log_to_stderr = FALSE; #if 0 if (kernel_ops->set_debug != NULL) (*kernel_ops->set_debug)(cur_debugging, DBG_log, DBG_log); #endif /* * create control socket. * We must create it before the parent process returns so that * there will be no race condition in using it. The easiest * place to do this is before the daemon fork. */ { err_t ugh = init_ctl_socket(); if (ugh != NULL) { fprintf(stderr, "pluto: FATAL: %s", ugh); exit_pluto(PLUTO_EXIT_SOCKET_FAIL); } } /* If not suppressed, do daemon fork */ if (fork_desired) { #if USE_DAEMON if (daemon(TRUE, TRUE) < 0) { fprintf(stderr, "pluto: FATAL: daemon failed (%d %s)\n", errno, strerror(errno)); exit_pluto(PLUTO_EXIT_FORK_FAIL); } /* * Parent just exits, so need to fill in our own PID * file. This is racy, since the file won't be * created until after the parent has exited. * * Since "ipsec start" invokes pluto with --nofork, it * is probably safer to leave this feature disabled * then implement it using the daemon call. */ (void) fill_lock(lockfd, getpid()); #elif USE_FORK { pid_t pid = fork(); if (pid < 0) { int e = errno; fprintf(stderr, "pluto: FATAL: fork failed (%d %s)\n", errno, strerror(e)); exit_pluto(PLUTO_EXIT_FORK_FAIL); } if (pid != 0) { /* * parent: die, after filling PID into lock * file. * must not use exit_pluto: lock would be * removed! */ exit(fill_lock(lockfd, pid) ? 0 : 1); } } #else fprintf(stderr, "pluto: FATAL: fork/daemon not supported\n"); exit_pluto(PLUTO_EXIT_FORK_FAIL); #endif if (setsid() < 0) { int e = errno; fprintf(stderr, "FATAL: setsid() failed in main(). Errno %d: %s\n", errno, strerror(e)); exit_pluto(PLUTO_EXIT_FAIL); } } else { /* no daemon fork: we have to fill in lock file */ (void) fill_lock(lockfd, getpid()); if (isatty(fileno(stdout))) { fprintf(stdout, "Pluto initialized\n"); fflush(stdout); } } /* * Close everything but ctl_fd and (if needed) stderr. * There is some danger that a library that we don't know * about is using some fd that we don't know about. * I guess we'll soon find out. */ { int i; for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */ if ((!log_to_stderr || i != 2) && i != ctl_fd) close(i); /* make sure that stdin, stdout, stderr are reserved */ if (open("/dev/null", O_RDONLY) != 0) lsw_abort(); if (dup2(0, 1) != 1) lsw_abort(); if (!log_to_stderr && dup2(0, 2) != 2) lsw_abort(); } init_constants(); init_pluto_constants(); pluto_init_log(); if (!pluto_init_nss(oco->nssdb)) { loglog(RC_LOG_SERIOUS, "FATAL: NSS initialization failure"); exit_pluto(PLUTO_EXIT_NSS_FAIL); } libreswan_log("NSS crypto library initialized"); if (ocsp_enable) { if (!init_nss_ocsp(ocsp_default_uri, ocsp_trust_name, ocsp_timeout, strict_ocsp_policy)) { loglog(RC_LOG_SERIOUS, "Initializing NSS OCSP failed"); exit_pluto(PLUTO_EXIT_NSS_FAIL); } else { libreswan_log("NSS OCSP Enabled"); } } #ifdef HAVE_LIBCAP_NG /* * Drop capabilities - this generates a false positive valgrind warning * See: http://marc.info/?l=linux-security-module&m=125895232029657 * * We drop these after creating the pluto socket or else we can't * create a socket if the parent dir is non-root (eg openstack) */ capng_clear(CAPNG_SELECT_BOTH); capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_NET_BIND_SERVICE, CAP_NET_ADMIN, CAP_NET_RAW, CAP_IPC_LOCK, CAP_AUDIT_WRITE, /* for google authenticator pam */ CAP_SETGID, CAP_SETUID, CAP_DAC_READ_SEARCH, -1); /* * We need to retain some capabilities for our children (updown): * CAP_NET_ADMIN to change routes * CAP_NET_RAW for iptables -t mangle * CAP_DAC_READ_SEARCH for pam / google authenticator */ capng_updatev(CAPNG_ADD, CAPNG_BOUNDING_SET, CAP_NET_ADMIN, CAP_NET_RAW, CAP_DAC_READ_SEARCH, -1); capng_apply(CAPNG_SELECT_BOTH); libreswan_log("libcap-ng support [enabled]"); #else libreswan_log("libcap-ng support [disabled]"); #endif #ifdef FIPS_CHECK libreswan_log("FIPS HMAC integrity support [enabled]"); /* * FIPS mode requires two conditions to be true: * - FIPS Kernel mode: fips=1 kernel boot parameter * - FIPS Product mode: See FIPSPRODUCTCHECK in Makefile.inc * (in RHEL/Fedora, dracut-fips installs $FIPSPRODUCTCHECK) * * When FIPS mode, abort on self-check hmac failure. Otherwise, complain */ { if (DBGP(IMPAIR_FORCE_FIPS)) { libreswan_log("Forcing FIPS checks to true to emulate FIPS mode"); lsw_set_fips_mode(LSW_FIPS_ON); } enum lsw_fips_mode pluto_fips_mode = lsw_get_fips_mode(); bool nss_fips_mode = PK11_IsFIPS(); /* * Now verify the consequences. Always run the tests * as combinations such as NSS in fips mode but as out * of it could be bad. */ switch (pluto_fips_mode) { case LSW_FIPS_UNKNOWN: loglog(RC_LOG_SERIOUS, "ABORT: pluto FIPS mode could not be determined"); exit_pluto(PLUTO_EXIT_FIPS_FAIL); break; case LSW_FIPS_ON: libreswan_log("FIPS mode enabled for pluto daemon"); if (nss_fips_mode) { libreswan_log("NSS library is running in FIPS mode"); } else { loglog(RC_LOG_SERIOUS, "ABORT: pluto in FIPS mode but NSS library is not"); exit_pluto(PLUTO_EXIT_FIPS_FAIL); } break; case LSW_FIPS_OFF: libreswan_log("FIPS mode disabled for pluto daemon"); if (nss_fips_mode) { loglog(RC_LOG_SERIOUS, "Warning: NSS library is running in FIPS mode"); } break; case LSW_FIPS_UNSET: default: bad_case(pluto_fips_mode); } /* always run hmac check so we can print diagnostic */ bool fips_files = FIPSCHECK_verify_files(fips_package_files); if (fips_files) { libreswan_log("FIPS HMAC integrity verification self-test passed"); } else { loglog(RC_LOG_SERIOUS, "FIPS HMAC integrity verification self-test FAILED"); } if (pluto_fips_mode == LSW_FIPS_ON && !fips_files) { exit_pluto(PLUTO_EXIT_FIPS_FAIL); } } #else libreswan_log("FIPS HMAC integrity support [disabled]"); #endif #ifdef USE_LINUX_AUDIT linux_audit_init(); #else libreswan_log("Linux audit support [disabled]"); #endif { const char *vc = ipsec_version_code(); libreswan_log("Starting Pluto (Libreswan Version %s%s) pid:%u", vc, compile_time_interop_options, getpid()); } libreswan_log("core dump dir: %s", coredir); if (oco->secretsfile && *oco->secretsfile) libreswan_log("secrets file: %s", oco->secretsfile); libreswan_log(leak_detective ? "leak-detective enabled" : "leak-detective disabled"); /* Check for SAREF support */ #ifdef KLIPS_MAST #include <ipsec_saref.h> { int e, sk, saref; saref = 1; errno = 0; sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); e = setsockopt(sk, IPPROTO_IP, IP_IPSEC_REFINFO, &saref, sizeof(saref)); if (e == -1 ) libreswan_log("SAref support [disabled]: %s", strerror(errno)); else libreswan_log("SAref support [enabled]"); errno = 0; e = setsockopt(sk, IPPROTO_IP, IP_IPSEC_BINDREF, &saref, sizeof(saref)); if (e == -1 ) libreswan_log("SAbind support [disabled]: %s", strerror(errno)); else libreswan_log("SAbind support [enabled]"); close(sk); } #endif libreswan_log("NSS crypto [enabled]"); #ifdef XAUTH_HAVE_PAM libreswan_log("XAUTH PAM support [enabled]"); #else libreswan_log("XAUTH PAM support [disabled]"); #endif /* Log various impair-* functions if they were enabled */ if (DBGP(IMPAIR_BUST_MI2)) libreswan_log("Warning: IMPAIR_BUST_MI2 enabled"); if (DBGP(IMPAIR_BUST_MR2)) libreswan_log("Warning: IMPAIR_BUST_MR2 enabled"); if (DBGP(IMPAIR_SA_CREATION)) libreswan_log("Warning: IMPAIR_SA_CREATION enabled"); if (DBGP(IMPAIR_JACOB_TWO_TWO)) libreswan_log("Warning: IMPAIR_JACOB_TWO_TWO enabled"); if (DBGP(IMPAIR_DIE_ONINFO)) libreswan_log("Warning: IMPAIR_DIE_ONINFO enabled"); if (DBGP(IMPAIR_MAJOR_VERSION_BUMP)) libreswan_log("Warning: IMPAIR_MAJOR_VERSION_BUMP enabled"); if (DBGP(IMPAIR_MINOR_VERSION_BUMP)) libreswan_log("Warning: IMPAIR_MINOR_VERSION_BUMP enabled"); if (DBGP(IMPAIR_RETRANSMITS)) libreswan_log("Warning: IMPAIR_RETRANSMITS enabled"); if (DBGP(IMPAIR_SEND_BOGUS_ISAKMP_FLAG)) libreswan_log("Warning: IMPAIR_SEND_BOGUS_ISAKMP_FLAG enabled"); if (DBGP(IMPAIR_SEND_BOGUS_PAYLOAD_FLAG)) libreswan_log("Warning: IMPAIR_SEND_BOGUS_PAYLOAD_FLAG enabled"); if (DBGP(IMPAIR_SEND_IKEv2_KE)) libreswan_log("Warning: IMPAIR_SEND_IKEv2_KE enabled"); if (DBGP(IMPAIR_SEND_KEY_SIZE_CHECK)) libreswan_log("Warning: IMPAIR_SEND_KEY_SIZE_CHECK enabled"); if (DBGP(IMPAIR_SEND_NO_DELETE)) libreswan_log("Warning: IMPAIR_SEND_NO_DELETE enabled"); if (DBGP(IMPAIR_FORCE_FIPS)) libreswan_log("Warning: IMPAIR_FORCE_FIPS enabled"); if (DBGP(IMPAIR_SEND_NO_IKEV2_AUTH)) libreswan_log("Warning: IMPAIR_SEND_NO_IKEV2_AUTH enabled"); if (DBGP(IMPAIR_SEND_ZERO_GX)) libreswan_log("Warning: IMPAIR_SEND_ZERO_GX enabled"); if (DBGP(IMPAIR_SEND_BOGUS_DCOOKIE)) libreswan_log("Warning: IMPAIR_SEND_BOGUS_DCOOKIE enabled"); /* Initialize all of the various features */ init_nat_traversal(keep_alive); init_virtual_ip(virtual_private); /* obsoleted by nss code init_rnd_pool(); */ init_event_base(); init_secret(); init_states(); init_connections(); init_crypto(); init_crypto_helpers(nhelpers); init_demux(); init_kernel(); init_id(); init_vendorid(); #if defined(LIBCURL) || defined(LDAP_VER) init_fetch(); #endif load_crls(); #ifdef HAVE_LABELED_IPSEC init_avc(); #endif daily_log_event(); #ifdef USE_SYSTEMD_WATCHDOG pluto_sd_init(); #endif call_server(); return -1; /* Shouldn't ever reach this */ }
/* - main - mostly argument parsing */ int main(int argc, char *argv[]) { const struct lsw_conf_options *oco = lsw_init_options(); int opt; int nbits = 0; int seedbits = DEFAULT_SEED_BITS; char *configdir = oco->confddir; /* where the NSS databases reside */ char *password = NULL; /* password for token authentication */ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF) switch (opt) { case 'n': case 'p': fprintf(stderr, "%s: --noopt and --rounds options have been obsoleted - ignored\n", me); break; case 'v': /* verbose description */ verbose = 1; break; case 'r': fprintf(stderr, "%s: Warning: --random is obsoleted for --seeddev. It no longer specifies the random device used for obtaining random key material", me); /* FALLTHROUGH */ case 'S': /* nonstandard random device for seed */ device = optarg; break; case 'H': /* set hostname for output */ { size_t full_len = strlen(optarg); bool oflow = sizeof(outputhostname) - 1 < full_len; size_t copy_len = oflow ? sizeof(outputhostname) - 1 : full_len; memcpy(outputhostname, optarg, copy_len); outputhostname[copy_len] = '\0'; } break; case 'h': /* help */ printf("Usage:\t%s\n", usage); exit(0); break; case 'V': /* version */ printf("%s %s\n", me, ipsec_version_code()); exit(0); break; case 'c': /* nss configuration directory */ case 'd': /* -d is used for configdir with nss tools */ configdir = optarg; break; case 'P': /* token authentication password */ password = optarg; break; case 's': /* seed bits */ seedbits = atoi(optarg); if (PK11_IsFIPS()) { if (seedbits < DEFAULT_SEED_BITS) { fprintf(stderr, "%s: FIPS mode does not allow < %d seed bits\n", me, DEFAULT_SEED_BITS); exit(1); } } break; case '?': default: printf("Usage:\t%s\n", usage); exit(2); } if (outputhostname[0] == '\0') { if (gethostname(outputhostname, sizeof(outputhostname)) < 0) { fprintf(stderr, "%s: gethostname failed (%s)\n", me, strerror(errno)); exit(1); } } if (argv[optind] == NULL) { /* default: spread bits between 3072 - 4096 in multiple's of 16 */ srand(time(NULL)); nbits = 3072 + 16 * (rand() % 64); } else { unsigned long u; err_t ugh = ttoulb(argv[optind], 0, 10, INT_MAX, &u); if (ugh != NULL) { fprintf(stderr, "%s: keysize specification is malformed: %s\n", me, ugh); exit(1); } nbits = u; } if (nbits < MIN_KEYBIT ) { fprintf(stderr, "%s: requested RSA key size of %d is too small - use %d or more\n", me, nbits, MIN_KEYBIT); exit(1); } else if (nbits > MAXBITS) { fprintf(stderr, "%s: overlarge bit count (max %d)\n", me, MAXBITS); exit(1); } else if (nbits % (BITS_PER_BYTE * 2) != 0) { fprintf(stderr, "%s: bit count (%d) not multiple of %d\n", me, nbits, (int)BITS_PER_BYTE * 2); exit(1); } rsasigkey(nbits, seedbits, configdir, password); exit(0); }
int main(int argc, char *argv[]) { __u32 spi = 0; int c; ip_said said; const char *error_s; char ipsaid_txt[SATOT_BUF]; int outif = 0; int error = 0; ssize_t io_error; int argcount = argc; pid_t mypid; int listenreply = 0; unsigned char authalg, encryptalg; struct sadb_ext *extensions[K_SADB_EXT_MAX + 1]; struct sadb_msg *pfkey_msg; char *edst_opt, *spi_opt, *proto_opt, *af_opt, *said_opt, *dst_opt, *src_opt; u_int32_t natt; u_int16_t sport, dport; uint32_t life[life_maxsever][life_maxtype]; char *life_opt[life_maxsever][life_maxtype]; struct stat sts; struct sadb_builds sab; progname = argv[0]; mypid = getpid(); natt = 0; sport = 0; dport = 0; tool_init_log(); zero(&said); /* OK: no pointer fields */ edst_opt = spi_opt = proto_opt = af_opt = said_opt = dst_opt = src_opt = NULL; { int i, j; for (i = 0; i < life_maxsever; i++) { for (j = 0; j < life_maxtype; j++) { life_opt[i][j] = NULL; life[i][j] = 0; } } } while ((c = getopt_long(argc, argv, "" /*"H:P:Z:46dcA:E:e:s:a:w:i:D:S:hvgl:+:f:"*/, longopts, 0)) != EOF) { unsigned long u; err_t ugh; switch (c) { case 'g': debug = TRUE; pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX; /* paul: this is a plutoism? cur_debugging = 0xffffffff; */ argcount--; break; case 'R': listenreply = 1; argcount--; break; case 'r': dumpsaref = 1; argcount--; break; case 'b': /* set the SAref to use */ ugh = ttoulb(optarg, 0, 0, INT_MAX, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid SAREFi parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } saref_me = u; argcount--; break; case 'B': /* set the SAref to use for outgoing packets */ ugh = ttoulb(optarg, 0, 0, INT_MAX, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid SAREFo parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } saref_him = u; argcount--; break; case 'O': /* set interface from which packet should arrive */ ugh = ttoulb(optarg, 0, 0, INT_MAX, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid outif parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } outif = u; argcount--; break; case 'l': { static const char combine_fmt[] = "%s --label %s"; size_t room = strlen(argv[0]) + sizeof(combine_fmt) + strlen(optarg); progname = malloc(room); snprintf(progname, room, combine_fmt, argv[0], optarg); tool_close_log(); tool_init_log(); argcount -= 2; break; } case 'H': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } if (streq(optarg, "hmac-md5-96")) { alg = XF_AHHMACMD5; } else if (streq(optarg, "hmac-sha1-96")) { alg = XF_AHHMACSHA1; } else { fprintf(stderr, "%s: Unknown authentication algorithm '%s' follows '--ah' option.\n", progname, optarg); exit(1); } if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case 'P': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } alg = decode_esp(optarg); if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case 'Z': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } if (streq(optarg, "deflate")) { alg = XF_COMPDEFLATE; } else if (streq(optarg, "lzs")) { alg = XF_COMPLZS; } else { fprintf(stderr, "%s: Unknown compression algorithm '%s' follows '--comp' option.\n", progname, optarg); exit(1); } if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case '4': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } alg = XF_IP4; address_family = AF_INET; if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case '6': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } alg = XF_IP6; address_family = AF_INET6; if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case 'd': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } alg = XF_DEL; if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case 'c': if (alg) { fprintf(stderr, "%s: Only one of '--ah', '--esp', '--comp', '--ip4', '--ip6', '--del' or '--clear' options permitted.\n", progname); exit(1); } alg = XF_CLR; if (debug) { fprintf(stdout, "%s: Algorithm %d selected.\n", progname, alg); } break; case 'e': if (said_opt) { fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined in SA:%s\n", progname, optarg, said_opt); exit(1); } if (edst_opt) { fprintf(stderr, "%s: Error, EDST parameter redefined:%s, already defined as:%s\n", progname, optarg, edst_opt); exit(1); } error_s = ttoaddr(optarg, 0, address_family, &edst); if (error_s != NULL) { if (error_s) { fprintf(stderr, "%s: Error, %s converting --edst argument:%s\n", progname, error_s, optarg); exit(1); } } edst_opt = optarg; if (debug) { ipstr_buf b; fprintf(stdout, "%s: edst=%s.\n", progname, ipstr(&edst, &b)); } break; case 's': if (said_opt != NULL) { fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined in SA:%s\n", progname, optarg, said_opt); exit(1); } if (spi_opt != NULL) { fprintf(stderr, "%s: Error, SPI parameter redefined:%s, already defined as:%s\n", progname, optarg, spi_opt); exit(1); } ugh = ttoulb(optarg, 0, 0, 0xFFFFFFFFul, &u); if (ugh == NULL && u < 0x100) ugh = "0 - 0xFF are reserved"; if (ugh != NULL) { fprintf(stderr, "%s: Invalid SPI parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } spi = u; spi_opt = optarg; break; case 'p': if (said_opt != NULL) { fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined in SA:%s\n", progname, optarg, said_opt); exit(1); } if (proto_opt != NULL) { fprintf(stderr, "%s: Error, PROTO parameter redefined:%s, already defined as:%s\n", progname, optarg, proto_opt); exit(1); } if (streq(optarg, "ah")) { proto = SA_AH; } else if (streq(optarg, "esp")) { proto = SA_ESP; } else if (streq(optarg, "tun")) { proto = SA_IPIP; } else if (streq(optarg, "comp")) { proto = SA_COMP; } else { fprintf(stderr, "%s: Invalid PROTO parameter: %s\n", progname, optarg); exit(1); } proto_opt = optarg; break; case 'a': if (said_opt) { fprintf(stderr, "%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined in SA:%s\n", progname, optarg, said_opt); exit(1); } if (af_opt) { fprintf(stderr, "%s: Error, ADDRESS FAMILY parameter redefined:%s, already defined as:%s\n", progname, optarg, af_opt); exit(1); } if (streq(optarg, "inet")) { address_family = AF_INET; /* currently we ensure that all addresses belong to the same address family */ anyaddr(address_family, &dst); anyaddr(address_family, &edst); anyaddr(address_family, &src); } else if (streq(optarg, "inet6")) { address_family = AF_INET6; /* currently we ensure that all addresses belong to the same address family */ anyaddr(address_family, &dst); anyaddr(address_family, &edst); anyaddr(address_family, &src); } else { fprintf(stderr, "%s: Invalid ADDRESS FAMILY parameter: %s.\n", progname, optarg); exit(1); } af_opt = optarg; break; case 'I': if (said_opt) { fprintf(stderr, "%s: Error, SAID parameter redefined:%s, already defined in SA:%s\n", progname, optarg, said_opt); exit(1); } if (proto_opt) { fprintf(stderr, "%s: Error, PROTO parameter redefined in SA:%s, already defined as:%s\n", progname, optarg, proto_opt); exit(1); } if (edst_opt) { fprintf(stderr, "%s: Error, EDST parameter redefined in SA:%s, already defined as:%s\n", progname, optarg, edst_opt); exit(1); } if (spi_opt) { fprintf(stderr, "%s: Error, SPI parameter redefined in SA:%s, already defined as:%s\n", progname, optarg, spi_opt); exit(1); } error_s = ttosa(optarg, 0, &said); if (error_s != NULL) { fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n", progname, error_s, optarg); exit(1); } if (debug) { satot(&said, 0, ipsaid_txt, sizeof(ipsaid_txt)); fprintf(stdout, "%s: said=%s.\n", progname, ipsaid_txt); } /* init the src and dst with the same address family */ if (address_family == 0) { address_family = addrtypeof(&said.dst); } else if (address_family != addrtypeof(&said.dst)) { fprintf(stderr, "%s: Error, specified address family (%d) is different that of SAID: %s\n", progname, address_family, optarg); exit(1); } anyaddr(address_family, &dst); anyaddr(address_family, &edst); anyaddr(address_family, &src); said_opt = optarg; break; case 'A': decode_blob(optarg, "Authentication Key", &authkey, &authkeylen); break; case 'E': decode_blob(optarg, "Encryption Key", &enckey, &enckeylen); break; case 'w': { err_t ugh = ttoul(optarg, 0, 0, &replay_window); if (ugh != NULL) { fprintf(stderr, "%s: Invalid replay_window parameter: %s\n", progname, ugh); exit(1); } if (!(1 <= replay_window && replay_window <= 64)) { fprintf(stderr, "%s: Failed -- Illegal window size: arg=%s, replay_window=%lu, must be 1 <= size <= 64.\n", progname, optarg, replay_window); exit(1); } } break; case 'i': decode_blob(optarg, "IV", &iv, &ivlen); break; case 'D': if (dst_opt) { fprintf(stderr, "%s: Error, DST parameter redefined:%s, already defined as:%s\n", progname, optarg, dst_opt); exit(1); } error_s = ttoaddr(optarg, 0, address_family, &dst); if (error_s != NULL) { fprintf(stderr, "%s: Error, %s converting --dst argument:%s\n", progname, error_s, optarg); exit(1); } dst_opt = optarg; if (debug) { ipstr_buf b; fprintf(stdout, "%s: dst=%s.\n", progname, ipstr(&dst, &b)); } break; case 'F': /* src port */ { unsigned long u; err_t ugh = ttoulb(optarg, 0, 0, 0xFFFF, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid source port parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } sport = u; } break; case 'G': /* dst port */ { unsigned long u; err_t ugh = ttoulb(optarg, 0, 0, 0xFFFF, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid destination port parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } dport = u; } break; case 'N': /* nat-type */ if (strcaseeq(optarg, "nonesp")) { natt = ESPINUDP_WITH_NON_ESP; } else if (strcaseeq(optarg, "none")) { natt = 0; } else { /* ??? what does this do? Where is it documented? */ unsigned long u; err_t ugh = ttoulb(optarg, 0, 0, 0xFFFFFFFFul, &u); if (ugh != NULL) { fprintf(stderr, "%s: Invalid character in natt parameter \"%s\": %s\n", progname, optarg, ugh); exit(1); } natt = u; } break; case 'S': if (src_opt) { fprintf(stderr, "%s: Error, SRC parameter redefined:%s, already defined as:%s\n", progname, optarg, src_opt); exit(1); } error_s = ttoaddr(optarg, 0, address_family, &src); if (error_s != NULL) { fprintf(stderr, "%s: Error, %s converting --src argument:%s\n", progname, error_s, optarg); exit(1); } src_opt = optarg; if (debug) { ipstr_buf b; fprintf(stdout, "%s: src=%s.\n", progname, ipstr(&src, &b)); } break; case 'h': usage(progname, stdout); exit(0); case '?': usage(progname, stderr); exit(1); case 'v': fprintf(stdout, "%s, %s\n", progname, ipsec_version_code()); exit(1); case 'f': if (parse_life_options(life, life_opt, optarg) != 0) exit(1); break; default: fprintf(stderr, "%s: unrecognized option '%c', update option processing.\n", progname, c); exit(1); } } if (debug) { fprintf(stdout, "%s: All options processed.\n", progname); } if (stat("/proc/net/pfkey", &sts) == 0) { fprintf(stderr, "%s: NETKEY does not use the ipsec spi command. Use 'ip xfrm' instead.\n", progname); exit(1); } if (argcount == 1) { int ret = 1; if ((stat("/proc/net/ipsec_spi", &sts)) != 0) { fprintf(stderr, "%s: No spi - no IPsec support in kernel (are the modules loaded?)\n", progname); } else { ret = system("cat /proc/net/ipsec_spi"); ret = ret != -1 && WIFEXITED(ret) ? WEXITSTATUS(ret) : 1; } exit(ret); } switch (alg) { case XF_OTHER_ALG: /* validate keysizes */ if (proc_read_ok) { const struct sadb_alg *alg_p; size_t keylen, minbits, maxbits; alg_p = kernel_alg_sadb_alg_get(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, esp_info->encryptalg); assert(alg_p != NULL); keylen = enckeylen * 8; minbits = alg_p->sadb_alg_minbits; maxbits = alg_p->sadb_alg_maxbits; /* * if explicit keylen told in encrypt algo, eg "aes128" * check actual keylen "equality" */ if (esp_info->enckeylen && esp_info->enckeylen != keylen) { fprintf(stderr, "%s: invalid encryption keylen=%d, " "required %d by encrypt algo string=\"%s\"\n", progname, (int)keylen, (int)esp_info->enckeylen, alg_string); exit(1); } /* thanks DES for this sh*t */ if (minbits > keylen || maxbits < keylen) { fprintf(stderr, "%s: invalid encryption keylen=%d, " "must be between %d and %d bits\n", progname, (int)keylen, (int)minbits, (int)maxbits); exit(1); } alg_p = kernel_alg_sadb_alg_get(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_AUTH, esp_info->authalg); assert(alg_p); keylen = authkeylen * 8; minbits = alg_p->sadb_alg_minbits; maxbits = alg_p->sadb_alg_maxbits; if (minbits > keylen || maxbits < keylen) { fprintf(stderr, "%s: invalid auth keylen=%d, " "must be between %d and %d bits\n", progname, (int)keylen, (int)minbits, (int)maxbits); exit(1); } } /* * ??? this break was added in a2791fda77a5cfcc6bc992fbc5019f4448112f88 * It is likely correct, but we're not sure. * Luckily this code is probably never used. */ break; case XF_IP4: case XF_IP6: case XF_DEL: case XF_COMPDEFLATE: case XF_COMPLZS: if (!said_opt) { if (isanyaddr(&edst)) { fprintf(stderr, "%s: SA destination not specified.\n", progname); exit(1); } if (!spi) { fprintf(stderr, "%s: SA SPI not specified.\n", progname); exit(1); } if (!proto) { fprintf(stderr, "%s: SA PROTO not specified.\n", progname); exit(1); } initsaid(&edst, htonl(spi), proto, &said); } else { proto = said.proto; spi = ntohl(said.spi); edst = said.dst; } if ((address_family != 0) && (address_family != addrtypeof(&said.dst))) { fprintf(stderr, "%s: Defined address family and address family of SA missmatch.\n", progname); exit(1); } if (debug) { fprintf(stdout, "%s: SA valid.\n", progname); } break; case XF_CLR: break; default: fprintf(stderr, "%s: No action chosen. See '%s --help' for usage.\n", progname, progname); exit(1); } switch (alg) { case XF_CLR: case XF_DEL: case XF_IP4: case XF_IP6: case XF_COMPDEFLATE: case XF_COMPLZS: case XF_OTHER_ALG: break; default: fprintf(stderr, "%s: No action chosen. See '%s --help' for usage.\n", progname, progname); exit(1); } if (debug) { fprintf(stdout, "%s: Algorithm ok.\n", progname); } pfkey_sock = pfkey_open_sock_with_error(); if (pfkey_sock < 0) exit(1); /* Build an SADB_ADD message to send down. */ /* It needs <base, SA, address(SD), key(AE)> minimum. */ /* Lifetime(HS) could be added before addresses. */ pfkey_extensions_init(extensions); error = pfkey_msg_hdr_build(&extensions[0], alg == XF_DEL ? SADB_DELETE : alg == XF_CLR ? SADB_FLUSH : SADB_ADD, proto2satype(proto), 0, ++pfkey_seq, mypid); if (error != 0) { fprintf(stderr, "%s: Trouble building message header, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } switch (alg) { case XF_OTHER_ALG: authalg = esp_info->authalg; if (debug) { fprintf(stdout, "%s: debug: authalg=%d\n", progname, authalg); } break; default: authalg = SADB_AALG_NONE; } switch (alg) { case XF_COMPDEFLATE: encryptalg = SADB_X_CALG_DEFLATE; break; case XF_COMPLZS: encryptalg = SADB_X_CALG_LZS; break; case XF_OTHER_ALG: encryptalg = esp_info->encryptalg; if (debug) { fprintf(stdout, "%s: debug: encryptalg=%d\n", progname, encryptalg); } break; default: encryptalg = SADB_EALG_NONE; } /* IE: pfkey_msg->sadb_msg_type == SADB_FLUSH */ if (!(alg == XF_CLR)) { sab.sa_base.sadb_sa_len = 0; sab.sa_base.sadb_sa_exttype = SADB_EXT_SA; sab.sa_base.sadb_sa_spi = htonl(spi); sab.sa_base.sadb_sa_replay = replay_window; sab.sa_base.sadb_sa_state = K_SADB_SASTATE_MATURE; sab.sa_base.sadb_sa_auth = authalg; sab.sa_base.sadb_sa_encrypt = encryptalg; sab.sa_base.sadb_sa_flags = 0; sab.sa_base.sadb_x_sa_ref = IPSEC_SAREF_NULL; sab.sa_base.sadb_x_reserved[0] = 0; sab.sa_base.sadb_x_reserved[1] = 0; sab.sa_base.sadb_x_reserved[2] = 0; sab.sa_base.sadb_x_reserved[3] = 0; error = pfkey_sa_builds(&extensions[SADB_EXT_SA], sab); if (error != 0) { fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } if (saref_me || saref_him) { error = pfkey_saref_build(&extensions[ K_SADB_X_EXT_SAREF], saref_me, saref_him); if (error) { fprintf(stderr, "%s: Trouble building saref extension, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } } if (outif != 0) { error = pfkey_outif_build(&extensions[ SADB_X_EXT_PLUMBIF], outif); if (error != 0) { fprintf(stderr, "%s: Trouble building outif extension, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } } if (debug) { fprintf(stdout, "%s: extensions[0]=0p%p previously set with msg_hdr.\n", progname, extensions[0]); } if (debug) { fprintf(stdout, "%s: assembled SA extension, pfkey msg authalg=%d encalg=%d.\n", progname, authalg, encryptalg); } if (debug) { int i, j; for (i = 0; i < life_maxsever; i++) { for (j = 0; j < life_maxtype; j++) { fprintf(stdout, "%s: i=%d, j=%d, life_opt[%d][%d]=0p%p, life[%d][%d]=%d\n", progname, i, j, i, j, life_opt[i][j], i, j, life[i][j]); } } } emit_lifetime("lifetime_s", SADB_EXT_LIFETIME_SOFT, extensions, life_opt[life_soft], life[life_soft]); emit_lifetime("lifetime_h", SADB_EXT_LIFETIME_HARD, extensions, life_opt[life_hard], life[life_hard]); if (debug) { ipstr_buf b; fprintf(stdout, "%s: assembling address_s extension (%s).\n", progname, ipstr(&src, &b)); } error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], SADB_EXT_ADDRESS_SRC, 0, 0, sockaddrof(&src)); if (error != 0) { ipstr_buf b; fprintf(stderr, "%s: Trouble building address_s extension (%s), error=%d.\n", progname, ipstr(&src, &b), error); pfkey_extensions_free(extensions); exit(1); } error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], SADB_EXT_ADDRESS_DST, 0, 0, sockaddrof(&edst)); if (error != 0) { ipstr_buf b; fprintf(stderr, "%s: Trouble building address_d extension (%s), error=%d.\n", progname, ipstr(&edst, &b), error); pfkey_extensions_free(extensions); exit(1); } switch (alg) { /* Allow no auth ... after all is local root decision 8) */ case XF_OTHER_ALG: if (!authalg) break; error = pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH], SADB_EXT_KEY_AUTH, authkeylen * 8, authkey); if (error != 0) { fprintf(stderr, "%s: Trouble building key_a extension, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } if (debug) { fprintf(stdout, "%s: key_a extension assembled.\n", progname); } break; default: break; } switch (alg) { case XF_OTHER_ALG: if (enckeylen == 0) { if (debug) fprintf(stdout, "%s: key not provided (NULL alg?).\n", progname); break; } error = pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT], SADB_EXT_KEY_ENCRYPT, enckeylen * 8, enckey); if (error != 0) { fprintf(stderr, "%s: Trouble building key_e extension, error=%d.\n", progname, error); pfkey_extensions_free(extensions); exit(1); } if (debug) { fprintf(stdout, "%s: key_e extension assembled.\n", progname); } break; default: break; } } if (natt != 0) { bool success; int err; err = pfkey_x_nat_t_type_build(&extensions[ K_SADB_X_EXT_NAT_T_TYPE], natt); success = pfkey_build(err, "pfkey_nat_t_type Add ESP SA", ipsaid_txt, extensions); if (!success) return FALSE; if (debug) fprintf(stderr, "setting natt_type to %d\n", natt); if (sport != 0) { err = pfkey_x_nat_t_port_build( &extensions[K_SADB_X_EXT_NAT_T_SPORT], K_SADB_X_EXT_NAT_T_SPORT, sport); success = pfkey_build(err, "pfkey_nat_t_sport Add ESP SA", ipsaid_txt, extensions); if (debug) fprintf(stderr, "setting natt_sport to %d\n", sport); if (!success) return FALSE; } if (dport != 0) { err = pfkey_x_nat_t_port_build( &extensions[K_SADB_X_EXT_NAT_T_DPORT], K_SADB_X_EXT_NAT_T_DPORT, dport); success = pfkey_build(err, "pfkey_nat_t_dport Add ESP SA", ipsaid_txt, extensions); if (debug) fprintf(stderr, "setting natt_dport to %d\n", dport); if (!success) return FALSE; } #if 0 /* not yet implemented */ if (natt != 0 && !isanyaddr(&natt_oa)) { ip_str_buf b; success = pfkeyext_address(SADB_X_EXT_NAT_T_OA, &natt_oa, "pfkey_nat_t_oa Add ESP SA", ipsaid_txt, extensions); if (debug) fprintf(stderr, "setting nat_oa to %s\n", ipstr(&natt_oa, &b)); if (!success) return FALSE; } #endif } if (debug) { fprintf(stdout, "%s: assembling pfkey msg....\n", progname); } error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); if (error != 0) { fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n", progname, error); pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); exit(1); } if (debug) { fprintf(stdout, "%s: assembled.\n", progname); } if (debug) { fprintf(stdout, "%s: writing pfkey msg.\n", progname); } io_error = write(pfkey_sock, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); if (io_error < 0) { fprintf(stderr, "%s: pfkey write failed (errno=%d): ", progname, errno); pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); switch (errno) { case EACCES: fprintf(stderr, "access denied. "); if (getuid() == 0) fprintf(stderr, "Check permissions. Should be 600.\n"); else fprintf(stderr, "You must be root to open this file.\n"); break; case EUNATCH: fprintf(stderr, "Netlink not enabled OR KLIPS not loaded.\n"); break; case EBUSY: fprintf(stderr, "KLIPS is busy. Most likely a serious internal error occured in a previous command. Please report as much detail as possible to development team.\n"); break; case EINVAL: fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n"); break; case ENODEV: fprintf(stderr, "KLIPS not loaded or enabled.\n"); fprintf(stderr, "No device?!?\n"); break; case ENOBUFS: fprintf(stderr, "No kernel memory to allocate SA.\n"); break; case ESOCKTNOSUPPORT: fprintf(stderr, "Algorithm support not available in the kernel. Please compile in support.\n"); break; case EEXIST: fprintf(stderr, "SA already in use. Delete old one first.\n"); break; case ENOENT: fprintf(stderr, "device does not exist. See Libreswan installation procedure.\n"); break; case ENXIO: case ESRCH: fprintf(stderr, "SA does not exist. Cannot delete.\n"); break; case ENOSPC: fprintf(stderr, "no room in kernel SAref table. Cannot process request.\n"); break; case ESPIPE: fprintf(stderr, "kernel SAref table internal error. Cannot process request.\n"); break; default: fprintf(stderr, "Unknown socket write error %d (%s). Please report as much detail as possible to development team.\n", errno, strerror(errno)); } exit(1); } else if (io_error != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) { fprintf(stderr, "%s: pfkey write truncated to %d bytes\n", progname, (int)io_error); pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); exit(1); } if (debug) { fprintf(stdout, "%s: pfkey command written to socket.\n", progname); } if (pfkey_msg != NULL) { pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); } if (debug) { fprintf(stdout, "%s: pfkey message buffer freed.\n", progname); } if (authkey != NULL) { memset(authkey, 0, authkeylen); free(authkey); } if (enckey != NULL) { memset(enckey, 0, enckeylen); free(enckey); } if (iv != NULL) { memset(iv, 0, ivlen); free(iv); } if (listenreply || saref_me || dumpsaref) { ssize_t readlen; unsigned char pfkey_buf[PFKEYv2_MAX_MSGSIZE]; while ((readlen = read(pfkey_sock, pfkey_buf, sizeof(pfkey_buf))) > 0) { struct sadb_ext *extensions[K_SADB_EXT_MAX + 1]; pfkey_extensions_init(extensions); pfkey_msg = (struct sadb_msg *)pfkey_buf; /* first, see if we got enough for an sadb_msg */ if ((size_t)readlen < sizeof(struct sadb_msg)) { if (debug) { printf("%s: runt packet of size: %ld (<%lu)\n", progname, (long)readlen, (unsigned long)sizeof(struct sadb_msg)); } continue; } /* okay, we got enough for a message, print it out */ if (debug) { printf("%s: pfkey v%d msg received. type=%d(%s) seq=%d len=%d pid=%d errno=%d satype=%d(%s)\n", progname, pfkey_msg->sadb_msg_version, pfkey_msg->sadb_msg_type, pfkey_v2_sadb_type_string(pfkey_msg-> sadb_msg_type), pfkey_msg->sadb_msg_seq, pfkey_msg->sadb_msg_len, pfkey_msg->sadb_msg_pid, pfkey_msg->sadb_msg_errno, pfkey_msg->sadb_msg_satype, satype2name(pfkey_msg->sadb_msg_satype)); } if (readlen != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) { if (debug) { printf("%s: packet size read from socket=%d doesn't equal sadb_msg_len %u * %u; message not decoded\n", progname, (int)readlen, (unsigned)pfkey_msg->sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN); } continue; } if (pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_OUT)) { if (debug) { printf("%s: unparseable PF_KEY message.\n", progname); } continue; } if (debug) { printf("%s: parseable PF_KEY message.\n", progname); } if ((pid_t)pfkey_msg->sadb_msg_pid == mypid) { if (saref_me || dumpsaref) { struct sadb_x_saref *s = (struct sadb_x_saref *) extensions[ K_SADB_X_EXT_SAREF]; if (s != NULL) { printf("%s: saref=%d/%d\n", progname, s->sadb_x_saref_me, s->sadb_x_saref_him); } } break; } } } (void) close(pfkey_sock); /* close the socket */ if (debug || listenreply) printf("%s: exited normally\n", progname); exit(0); }