/* * generate an RSA signature key * * e is fixed at 3, without discussion. That would not be wise if these * keys were to be used for encryption, but for signatures there are some * real speed advantages. * See also: https://www.imperialviolet.org/2012/03/16/rsae.html */ void rsasigkey(int nbits, int seedbits, const struct lsw_conf_options *oco) { PK11RSAGenParams rsaparams = { nbits, (long) E }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; realtime_t now = realnow(); lsw_nss_buf_t err; if (!lsw_nss_setup(oco->confddir, 0, lsw_nss_get_password, err)) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } #ifdef FIPS_CHECK if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) { fprintf(stderr, "FIPS HMAC integrity verification test failed.\n"); exit(1); } #endif /* Good for now but someone may want to use a hardware token */ slot = lsw_nss_get_authenticated_slot(err); if (slot == NULL) { fprintf(stderr, "%s: %s\n", progname, err); lsw_nss_shutdown(); exit(1); } /* Do some random-number initialization. */ UpdateNSS_RNG(seedbits); privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, PK11_IsFIPS() ? PR_TRUE : PR_FALSE, lsw_return_nss_password_file_info()); /* inTheToken, isSensitive, passwordCallbackFunction */ if (privkey == NULL) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", progname, PORT_GetError()); return; } chunk_t public_modulus = { .ptr = pubkey->u.rsa.modulus.data, .len = pubkey->u.rsa.modulus.len, }; chunk_t public_exponent = { .ptr = pubkey->u.rsa.publicExponent.data, .len = pubkey->u.rsa.publicExponent.len, }; char *hex_ckaid; { SECItem *ckaid = PK11_GetLowLevelKeyIDForPrivateKey(privkey); if (ckaid == NULL) { fprintf(stderr, "%s: 'CKAID' calculation failed\n", progname); exit(1); } hex_ckaid = strdup(conv(ckaid->data, ckaid->len, 16)); SECITEM_FreeItem(ckaid, PR_TRUE); } /*privkey->wincx = &pwdata;*/ PORT_Assert(pubkey != NULL); fprintf(stderr, "Generated RSA key pair with CKAID %s was stored in the NSS database\n", hex_ckaid); /* and the output */ libreswan_log("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.real_secs)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); printf("\t#ckaid=%s\n", hex_ckaid); /* RFC2537/RFC3110-ish format */ { char *bundle = base64_bundle(E, public_modulus); printf("\t#pubkey=%s\n", bundle); pfree(bundle); } printf("\tModulus: 0x%s\n", conv(public_modulus.ptr, public_modulus.len, 16)); printf("\tPublicExponent: 0x%s\n", conv(public_exponent.ptr, public_exponent.len, 16)); if (hex_ckaid != NULL) free(hex_ckaid); if (privkey != NULL) SECKEY_DestroyPrivateKey(privkey); if (pubkey != NULL) SECKEY_DestroyPublicKey(pubkey); lsw_nss_shutdown(); } /* * getrandom - get some random bytes from /dev/random (or wherever) * NOTE: This is only used for additional seeding of the NSS RNG */ void getrandom(size_t nbytes, unsigned char *buf) { size_t ndone; int dev; ssize_t got; dev = open(device, 0); if (dev < 0) { fprintf(stderr, "%s: could not open %s (%s)\n", progname, device, strerror(errno)); exit(1); } ndone = 0; libreswan_log("getting %d random seed bytes for NSS from %s...\n", (int) nbytes * BITS_PER_BYTE, device); while (ndone < nbytes) { got = read(dev, buf + ndone, nbytes - ndone); if (got < 0) { fprintf(stderr, "%s: read error on %s (%s)\n", progname, device, strerror(errno)); exit(1); } if (got == 0) { fprintf(stderr, "%s: eof on %s!?!\n", progname, device); exit(1); } ndone += got; } close(dev); } /* - conv - convert bits to output in specified datatot format * NOTE: result points into a STATIC buffer */ static const char *conv(const unsigned char *bits, size_t nbytes, int format) { static char convbuf[MAXBITS / 4 + 50]; /* enough for hex */ size_t n; n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf)); if (n == 0) { fprintf(stderr, "%s: can't-happen convert error\n", progname); exit(1); } if (n > sizeof(convbuf)) { fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n", progname, (int) n); exit(1); } return convbuf; }
/* synchronous blocking resolving - simple replacement of ttoaddr() * src_len 0 means "apply strlen" * af 0 means "try both families */ int unbound_resolve(struct ub_ctx *dnsctx, char *src, size_t srclen, int af, ip_address *ipaddr) { const int qtype = (af == AF_INET6) ? 28 : 1; /* 28 = AAAA record, 1 = A record */ struct ub_result *result; passert(dnsctx != NULL); if (srclen == 0) { srclen = strlen(src); if (srclen == 0) { libreswan_log("empty hostname in host lookup\n"); ub_resolve_free(result); return 0; } } { int ugh = ub_resolve(dnsctx, src, qtype, 1 /* CLASS IN */, &result); if(ugh != 0) { libreswan_log("unbound error: %s", ub_strerror(ugh)); ub_resolve_free(result); return 0; } } if(result->bogus) { libreswan_log("ERROR: %s failed DNSSEC valdation!\n", result->qname); ub_resolve_free(result); return 0; } if(!result->havedata) { if(result->secure) { DBG(DBG_DNS,DBG_log("Validated reply proves '%s' does not exist\n", src)); } else { DBG(DBG_DNS,DBG_log("Failed to resolve '%s' (%s)\n", src, (result->bogus) ? "BOGUS" : "insecure")); } ub_resolve_free(result); return 0; } else if(!result->bogus) { if(!result->secure) { DBG(DBG_DNS,DBG_log("warning: %s lookup was not protected by DNSSEC!\n", result->qname)); } } #if 0 { int i = 0; DBG_log("The result has:\n"); DBG_log("qname: %s\n", result->qname); DBG_log("qtype: %d\n", result->qtype); DBG_log("qclass: %d\n", result->qclass); if(result->canonname) DBG_log("canonical name: %s\n", result->canonname); DBG_log("DNS rcode: %d\n", result->rcode); for(i=0; result->data[i] != NULL; i++) { DBG_log("result data element %d has length %d\n", i, result->len[i]); } DBG_log("result has %d data element(s)\n", i); } #endif /* XXX: for now pick the first one and return that */ passert(result->data[0] != NULL); { char dst[INET6_ADDRSTRLEN]; err_t err = tnatoaddr(inet_ntop(af, result->data[0], dst , (af==AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN) , 0, af, ipaddr); ub_resolve_free(result); if(err == NULL) { DBG(DBG_DNS,DBG_log("success for %s lookup", (af==AF_INET) ? "IPv4" : "IPv6")); return 1; } else { libreswan_log("tnatoaddr failed in unbound_resolve()"); return 0; } } }
static void bsdkame_process_raw_ifaces(struct raw_iface *rifaces) { struct raw_iface *ifp; /* * There are no virtual interfaces, so all interfaces are valid */ for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { if (vfp == ifp) { after = TRUE; } else if (sameaddr(&ifp->addr, &vfp->addr)) { if (after) { loglog(RC_LOG_SERIOUS, "IP interfaces %s and %s share address %s!", ifp->name, vfp->name, ip_str(&ifp->addr)); } bad = TRUE; } } if (bad) continue; /* We've got all we need; see if this is a new thing: * search old interfaces list. */ { struct iface_port **p = &interfaces; for (;; ) { struct iface_port *q = *p; struct iface_dev *id = NULL; /* search is over if at end of list */ if (q == NULL) { /* matches nothing -- create a new entry */ int fd = create_socket(ifp, ifp->name, pluto_port); if (fd < 0) break; if (nat_traversal_support_non_ike && addrtypeof(&ifp->addr) == AF_INET) nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_IKE); q = alloc_thing(struct iface_port, "struct iface_port"); id = alloc_thing(struct iface_dev, "struct iface_dev"); LIST_INSERT_HEAD(&interface_dev, id, id_entry); q->ip_dev = id; id->id_rname = clone_str(ifp->name, "real device name"); id->id_vname = clone_str(ifp->name, "virtual device name bsd"); id->id_count++; q->ip_addr = ifp->addr; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->port = pluto_port; q->ike_float = FALSE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q->ip_addr), q->port); /* * right now, we do not support NAT-T on IPv6, because * the kernel did not support it, and gave an error * it one tried to turn it on. */ if (nat_traversal_support_port_floating && addrtypeof(&ifp->addr) == AF_INET) { fd = create_socket(ifp, id->id_vname, pluto_natt_float_port); if (fd < 0) break; nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_ESP); q = alloc_thing( struct iface_port, "struct iface_port"); q->ip_dev = id; id->id_count++; q->ip_addr = ifp->addr; setportof(htons(pluto_natt_float_port), &q->ip_addr); q->port = pluto_natt_float_port; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->ike_float = TRUE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q-> ip_addr), q->port); } break; } /* search over if matching old entry found */ if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, ifp->name) && sameaddr(&q->ip_addr, &ifp->addr)) { /* matches -- rejuvinate old entry */ q->change = IFN_KEEP; /* look for other interfaces to keep (due to NAT-T) */ for (q = q->next; q; q = q->next) { if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, ifp->name) && sameaddr(&q->ip_addr, &ifp->addr)) q->change = IFN_KEEP; } break; } /* try again */ p = &q->next; } /* for (;;) */ }
int main(int argc, char **argv) { int lockfd; int nhelpers = -1; char *coredir; const struct lsw_conf_options *oco; /* * 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; coredir = NULL; /* set up initial defaults that need a cast */ pluto_shared_secrets_file = DISCARD_CONST(char *, SHARED_SECRETS_FILE); #ifdef NAT_TRAVERSAL /** Overridden by nat_traversal= in ipsec.conf */ bool nat_traversal = FALSE; bool nat_t_spf = TRUE; /* support port floating */ unsigned int keep_alive = 0; bool force_keepalive = FALSE; #endif /** Overridden by virtual_private= in ipsec.conf */ char *virtual_private = NULL; #ifdef LEAK_DETECTIVE leak_detective=1; #else leak_detective=0; #endif #ifdef HAVE_LIBCAP_NG /* Drop capabilities */ 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, -1); /* our children must be able to CAP_NET_ADMIN to change routes. */ capng_updatev(CAPNG_ADD, CAPNG_BOUNDING_SET, CAP_NET_ADMIN, -1); capng_apply(CAPNG_SELECT_BOTH); #endif #ifdef DEBUG libreswan_passert_fail = passert_fail; #endif if(getenv("PLUTO_WAIT_FOR_GDB")) { sleep(120); } /* 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' }, { "config", required_argument, NULL, 'z' }, { "nofork", no_argument, NULL, 'd' }, { "stderrlog", no_argument, NULL, 'e' }, { "logfile", required_argument, NULL, 'g' }, { "plutostderrlogtime", no_argument, NULL, 't' }, { "noklips", no_argument, NULL, 'n' }, { "use-nostack", no_argument, NULL, 'n' }, { "use-none", no_argument, NULL, 'n' }, { "force_busy", no_argument, NULL, 'D' }, { "strictcrlpolicy", no_argument, NULL, 'r' }, { "crlcheckinterval", required_argument, NULL, 'x'}, { "uniqueids", no_argument, NULL, 'u' }, { "useklips", no_argument, NULL, 'k' }, { "use-klips", no_argument, NULL, 'k' }, { "use-auto", no_argument, NULL, 'G' }, { "usenetkey", no_argument, NULL, 'K' }, { "use-netkey", no_argument, NULL, 'K' }, { "use-mast", no_argument, NULL, 'M' }, { "use-mastklips", no_argument, NULL, 'M' }, { "use-bsdkame", no_argument, NULL, 'F' }, { "interface", required_argument, NULL, 'i' }, { "listen", required_argument, NULL, 'L' }, { "ikeport", required_argument, NULL, 'p' }, { "natikeport", required_argument, NULL, 'q' }, { "ctlbase", required_argument, NULL, 'b' }, { "secretsfile", required_argument, NULL, 's' }, { "perpeerlogbase", required_argument, NULL, 'P' }, { "perpeerlog", no_argument, NULL, 'l' }, { "noretransmits", no_argument, NULL, 'R' }, { "coredir", required_argument, NULL, 'C' }, { "ipsecdir", required_argument, NULL, 'f' }, { "ipsec_dir", required_argument, NULL, 'f' }, { "foodgroupsdir", required_argument, NULL, 'f' }, { "adns", required_argument, NULL, 'a' }, #ifdef NAT_TRAVERSAL { "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-nat_t", no_argument, NULL, '5' }, { "debug-nattraversal", no_argument, NULL, '5' }, { "debug-nat-t", no_argument, NULL, '5' }, #endif { "virtual_private", required_argument, NULL, '6' }, { "nhelpers", required_argument, NULL, 'j' }, #ifdef HAVE_LABELED_IPSEC { "secctx_attr_value", required_argument, NULL, 'w' }, #endif #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-crypto", 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-netkey", no_argument, NULL, DBG_NETKEY + DBG_OFFSET }, { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, { "debug-oppoinfo", no_argument, NULL, DBG_OPPOINFO + DBG_OFFSET }, { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, { "debug-dpd", no_argument, NULL, DBG_DPD + DBG_OFFSET }, { "debug-x509", no_argument, NULL, DBG_X509 + DBG_OFFSET }, { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, { "debug-pfkey", no_argument, NULL, DBG_PFKEY + 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 }, { "impair-sa-creation", no_argument, NULL, IMPAIR_SA_CREATION + DBG_OFFSET }, { "impair-die-oninfo", no_argument, NULL, IMPAIR_DIE_ONINFO + DBG_OFFSET }, { "impair-jacob-two-two", no_argument, NULL, IMPAIR_JACOB_TWO_TWO + DBG_OFFSET }, { "impair-major-version-bump", no_argument, NULL, IMPAIR_MAJOR_VERSION_BUMP + DBG_OFFSET }, { "impair-minor-version-bump", no_argument, NULL, IMPAIR_MINOR_VERSION_BUMP + DBG_OFFSET }, { "impair-retransmits", no_argument, NULL, IMPAIR_RETRANSMITS + DBG_OFFSET }, { "impair-send-bogus-isakmp-flag", no_argument, NULL, IMPAIR_SEND_BOGUS_ISAKMP_FLAG + 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 'C': coredir = clone_str(optarg, "coredir"); continue; case 'v': /* --version */ { printf("%s%s\n", ipsec_version_string(), compile_time_interop_options); } exit(0); /* not exit_pluto because we are not initialized yet */ break; /* not actually reached */ case 'j': /* --nhelpers */ if (optarg == NULL || !isdigit(optarg[0])) usage("missing number of pluto helpers"); { char *endptr; long count = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || count < -1) usage("<nhelpers> must be a positive number, 0 or -1"); nhelpers = count; } continue; #ifdef HAVE_LABELED_IPSEC case 'w': /* --secctx_attr_value*/ if (optarg == NULL || !isdigit(optarg[0])) usage("missing (positive integer) value of secctx_attr_value (needed only if using labeled ipsec)"); { char *endptr; long value = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || (value != SECCTX && value !=10) ) usage("<secctx_attr_value> must be a positive number (32001 by default, 10 for backward compatibility, or any other future number assigned by IANA)"); secctx_attr_value = (u_int16_t)value; } 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': /* --plutostderrlogtime */ log_with_timestamp = TRUE; continue; case 'G': /* --use-auto */ libreswan_log("The option --use-auto is obsoleted, falling back to --use-netkey\n"); kern_interface = USE_NETKEY; continue; case 'k': /* --use-klips */ kern_interface = USE_KLIPS; continue; case 'L': /* --listen ip_addr */ { ip_address lip; err_t e = ttoaddr(optarg,0,0,&lip); if(e) { 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 */ force_busy = TRUE; continue ; case 'r': /* --strictcrlpolicy */ strict_crl_policy = TRUE; continue ; case 'R': no_retransmits = TRUE; continue; case 'x': /* --crlcheckinterval <time>*/ if (optarg == NULL || !isdigit(optarg[0])) usage("missing interval time"); { char *endptr; long interval = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || interval <= 0) usage("<interval-time> must be a positive number"); crl_check_interval = interval; } continue ; case 'u': /* --uniqueids */ uniqueIDs = TRUE; continue; case 'i': /* --interface <ifname|ifaddr> */ if (!use_interface(optarg)) usage("too many --interface specifications"); 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> */ if (optarg == NULL || !isdigit(optarg[0])) usage("missing port number"); { char *endptr; long port = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || port <= 0 || port > 0x10000) usage("<port-number> must be a number between 1 and 65535"); pluto_port = port; } continue; #ifdef NAT_TRAVERSAL case 'q': /* --natikeport <portnumber> */ if (optarg == NULL || !isdigit(optarg[0])) usage("missing port number"); { char *endptr; long port = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || port <= 0 || port > 0x10000) usage("<port-number> must be a number between 1 and 65535"); pluto_natt_float_port = port; } continue; #endif case 'b': /* --ctlbase <path> */ ctlbase = optarg; if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path) , "%s%s", ctlbase, CTL_SUFFIX) == -1) usage("<path>" CTL_SUFFIX " too long for sun_path"); if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path) , "%s%s", ctlbase, INFO_SUFFIX) == -1) usage("<path>" INFO_SUFFIX " too long for sun_path"); if (snprintf(pluto_lock, sizeof(pluto_lock) , "%s%s", ctlbase, LOCK_SUFFIX) == -1) usage("<path>" LOCK_SUFFIX " must fit"); continue; case 's': /* --secretsfile <secrets-file> */ pluto_shared_secrets_file = optarg; continue; case 'f': /* --ipsecdir <ipsec-dir> */ (void)lsw_init_ipsecdir(optarg); continue; case 'a': /* --adns <pathname> */ pluto_adns_option = optarg; continue; #ifdef DEBUG case 'N': /* --debug-none */ base_debugging = DBG_NONE; continue; case 'A': /* --debug-all */ base_debugging = DBG_ALL; continue; #endif case 'P': /* --perpeerlogbase */ base_perpeer_logdir = optarg; continue; case 'l': log_to_perpeer = TRUE; continue; #ifdef NAT_TRAVERSAL case '1': /* --nat_traversal */ nat_traversal = TRUE; continue; case '2': /* --keep_alive */ keep_alive = atoi(optarg); continue; case '3': /* --force_keepalive */ force_keepalive = TRUE; continue; case '4': /* --disable_port_floating */ nat_t_spf = FALSE; continue; #ifdef DEBUG case '5': /* --debug-nat_t */ base_debugging |= DBG_NATT; continue; #endif #endif 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 than */ /* long_opts[] is. */ struct starter_config *cfg = read_cfg_file(optarg); set_cfg_string(&pluto_log_file, cfg->setup.strings[KSF_PLUTOSTDERRLOG]); fork_desired = cfg->setup.options[KBF_PLUTOFORK]; /* plutofork= */ log_with_timestamp = cfg->setup.options[KBF_PLUTOSTDERRLOGTIME]; force_busy = cfg->setup.options[KBF_FORCEBUSY]; strict_crl_policy = cfg->setup.options[KBF_STRICTCRLPOLICY]; crl_check_interval = 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]); pluto_port = cfg->setup.options[KBF_IKEPORT]; /* --ikeport */ /* no config option: ctlbase */ set_cfg_string(&pluto_shared_secrets_file, cfg->setup.strings[KSF_SECRETSFILE]); /* --secrets */ if(cfg->setup.strings[KSF_IPSECDIR] != NULL && *cfg->setup.strings[KSF_IPSECDIR] != 0) { lsw_init_ipsecdir(cfg->setup.strings[KSF_IPSECDIR]); /* --ipsecdir */ } set_cfg_string(&base_perpeer_logdir, cfg->setup.strings[KSF_PERPEERDIR]); /* --perpeerlogbase */ log_to_perpeer = cfg->setup.options[KBF_PERPEERLOG]; /* --perpeerlog */ no_retransmits = !cfg->setup.options[KBF_RETRANSMITS]; /* --noretransmits */ set_cfg_string(&coredir, cfg->setup.strings[KSF_DUMPDIR]); /* --dumpdir */ /* no config option: pluto_adns_option */ #ifdef NAT_TRAVERSAL pluto_natt_float_port = cfg->setup.options[KBF_NATIKEPORT]; nat_traversal = cfg->setup.options[KBF_NATTRAVERSAL]; keep_alive = cfg->setup.options[KBF_KEEPALIVE]; force_keepalive = cfg->setup.options[KBF_FORCE_KEEPALIVE]; nat_t_spf = !cfg->setup.options[KBF_DISABLEPORTFLOATING]; #endif set_cfg_string(&virtual_private, cfg->setup.strings[KSF_VIRTUALPRIVATE]); nhelpers = cfg->setup.options[KBF_NHELPERS]; #ifdef HAVE_LABELED_IPSEC secctx_attr_value = cfg->setup.options[KBF_SECCTX]; #endif #ifdef DEBUG base_debugging = cfg->setup.options[KBF_PLUTODEBUG]; #endif char *protostack = cfg->setup.strings[KSF_PROTOSTACK]; if (protostack == NULL || *protostack == 0) kern_interface = USE_NETKEY; else if (strcmp(protostack, "none") == 0) kern_interface = NO_KERNEL; else if (strcmp(protostack, "auto") == 0) { libreswan_log("The option protostack=auto is obsoleted, falling back to protostack=netkey\n"); kern_interface = USE_NETKEY; } else if (strcmp(protostack, "klips") == 0) kern_interface = USE_KLIPS; else if (strcmp(protostack, "mast") == 0) kern_interface = USE_MASTKLIPS; else if (strcmp(protostack, "netkey") == 0 || strcmp(protostack, "native") == 0) kern_interface = USE_NETKEY; else if (strcmp(protostack, "bsd") == 0 || strcmp(protostack, "kame") == 0 || strcmp(protostack, "bsdkame") == 0) kern_interface = USE_BSDKAME; else if (strcmp(protostack, "win2k") == 0) kern_interface = USE_WIN2K; confread_free(cfg); continue; default: #ifdef DEBUG if (c >= DBG_OFFSET) { base_debugging |= c - DBG_OFFSET; continue; } # undef DBG_OFFSET #endif bad_case(c); } break; } if (optind != argc) usage("unexpected argument"); reset_debugging(); #ifdef HAVE_NO_FORK fork_desired = FALSE; nhelpers = 0; #endif /* default coredir to location compatible with SElinux */ if(!coredir) { coredir = clone_str("/var/run/pluto", "coredir"); } if(chdir(coredir) == -1) { int e = errno; libreswan_log("pluto: chdir() do dumpdir failed (%d: %s)\n", 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; #ifdef DEBUG #if 0 if(kernel_ops->set_debug) { (*kernel_ops->set_debug)(cur_debugging, DBG_log, DBG_log); } #endif #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: %s", ugh); exit_pluto(1); } } /* If not suppressed, do daemon fork */ if (fork_desired) { { pid_t pid = fork(); if (pid < 0) { int e = errno; fprintf(stderr, "pluto: fork failed (%d %s)\n", errno, strerror(e)); exit_pluto(1); } 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); } } if (setsid() < 0) { int e = errno; fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n", errno, strerror(e)); exit_pluto(1); } } 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(); pluto_init_log(); pluto_init_nss(oco->confddir); #ifdef FIPS_CHECK const char *package_files[]= { IPSECLIBDIR"/setup", IPSECLIBDIR"/addconn", IPSECLIBDIR"/auto", IPSECLIBDIR"/barf", IPSECLIBDIR"/eroute", IPSECLIBDIR"/ikeping", IPSECLIBDIR"/readwriteconf", IPSECLIBDIR"/_keycensor", IPSECLIBDIR"/klipsdebug", IPSECLIBDIR"/look", IPSECLIBDIR"/newhostkey", IPSECLIBDIR"/pf_key", IPSECLIBDIR"/_pluto_adns", IPSECLIBDIR"/_plutorun", IPSECLIBDIR"/ranbits", IPSECLIBDIR"/_realsetup", IPSECLIBDIR"/rsasigkey", IPSECLIBDIR"/pluto", IPSECLIBDIR"/_secretcensor", IPSECLIBDIR"/secrets", IPSECLIBDIR"/showhostkey", IPSECLIBDIR"/spi", IPSECLIBDIR"/spigrp", IPSECLIBDIR"/_stackmanager", IPSECLIBDIR"/tncfg", IPSECLIBDIR"/_updown", IPSECLIBDIR"/_updown.klips", IPSECLIBDIR"/_updown.mast", IPSECLIBDIR"/_updown.netkey", IPSECLIBDIR"/verify", IPSECLIBDIR"/whack", IPSECSBINDIR"/ipsec", NULL }; if (Pluto_IsFIPS() && !FIPSCHECK_verify_files(package_files)) { loglog(RC_LOG_SERIOUS, "FATAL: FIPS integrity verification test failed"); exit_pluto(10); } #else libreswan_log("FIPS integrity support [disabled]"); #endif #ifdef HAVE_LIBCAP_NG libreswan_log("libcap-ng support [enabled]"); #else libreswan_log("libcap-ng support [disabled]"); #endif #ifdef USE_LINUX_AUDIT libreswan_log("Linux audit support [enabled]"); /* test and log if audit is enabled on the system */ int audit_fd, rc; audit_fd = audit_open(); if (audit_fd < 0) { if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { loglog(RC_LOG_SERIOUS, "Warning: kernel has no audit support"); } else { loglog(RC_LOG_SERIOUS, "FATAL (SOON): audit_open() failed : %s", strerror(errno)); /* temp disabled exit_pluto(10); */ } } rc = audit_log_acct_message(audit_fd, AUDIT_USER_START, NULL, "starting pluto daemon", NULL, -1, NULL, NULL, NULL, 1); close(audit_fd); if (rc < 0) { loglog(RC_LOG_SERIOUS, "FATAL: audit_log_acct_message failed: %s", strerror(errno)); exit_pluto(10); } #else libreswan_log("Linux audit support [disabled]"); #endif /* Note: some scripts may look for this exact message -- don't change * ipsec barf was one, but it no longer does. */ { const char *vc = ipsec_version_code(); #ifdef PLUTO_SENDS_VENDORID const char *v = init_pluto_vendorid(); libreswan_log("Starting Pluto (Libreswan Version %s%s; Vendor ID %s) pid:%u" , vc, compile_time_interop_options, v, getpid()); #else libreswan_log("Starting Pluto (Libreswan Version %s%s) pid:%u" , vc, compile_time_interop_options, getpid()); #endif if(Pluto_IsFIPS()) { libreswan_log("Pluto is running in FIPS mode"); } else { libreswan_log("Pluto is NOT running in FIPS mode"); } if((vc[0]=='c' && vc[1]=='v' && vc[2]=='s') || (vc[2]=='g' && vc[3]=='i' && vc[4]=='t')) { /* * when people build RPMs from CVS or GIT, make sure they * get blamed appropriately, and that we get some way to * identify who did it, and when they did it. Use string concat, * so that strings the binary can or classic SCCS "what", will find * stuff too. */ libreswan_log("@(#) built on "__DATE__":" __TIME__ " by " BUILDER); } #if defined(USE_1DES) libreswan_log("WARNING: 1DES is enabled"); #endif } if(coredir) { libreswan_log("core dump dir: %s", coredir); } if(pluto_shared_secrets_file) { libreswan_log("secrets file: %s", pluto_shared_secrets_file); } #ifdef LEAK_DETECTIVE libreswan_log("LEAK_DETECTIVE support [enabled]"); #else libreswan_log("LEAK_DETECTIVE support [disabled]"); #endif #ifdef HAVE_OCF { struct stat buf; errno=0; if( stat("/dev/crypto",&buf) != -1) libreswan_log("OCF support for IKE via /dev/crypto [enabled]"); else libreswan_log("OCF support for IKE via /dev/crypto [failed:%s]", strerror(errno)); } #else libreswan_log("OCF support for IKE [disabled]"); #endif /* 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 #ifdef HAVE_STATSD libreswan_log("HAVE_STATSD notification via /bin/libreswan-statsd enabled"); #else libreswan_log("HAVE_STATSD notification 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_DELAY_ADNS_KEY_ANSWER)) libreswan_log("Warning: IMPAIR_DELAY_ADNS_KEY_ANSWER enabled"); if(DBGP(IMPAIR_DELAY_ADNS_TXT_ANSWER)) libreswan_log("Warning: IMPAIR_DELAY_ADNS_TXT_ANSWER enabled"); /** Initialize all of the various features */ #ifdef NAT_TRAVERSAL init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf); #endif init_virtual_ip(virtual_private); /* obsoletd by nss code init_rnd_pool(); */ init_timer(); init_secret(); init_states(); init_connections(); init_crypto(); init_crypto_helpers(nhelpers); load_lswcrypto(); init_demux(); init_kernel(); init_adns(); init_id(); #ifdef TPM init_tpm(); #endif #if defined(LIBCURL) || defined(LDAP_VER) init_fetch(); #endif /* loading X.509 CA certificates */ load_authcerts("CA cert", oco->cacerts_dir, AUTH_CA); #if 0 /* unused */ /* loading X.509 AA certificates */ load_authcerts("AA cert", oco->aacerts_dir, AUTH_AA); #endif /* loading X.509 CRLs */ load_crls(); /* loading attribute certificates (experimental) */ load_acerts(); /*Loading CA certs from NSS DB*/ load_authcerts_from_nss("CA cert", AUTH_CA); #ifdef HAVE_LABELED_IPSEC init_avc(); #endif daily_log_event(); call_server(); return -1; /* Shouldn't ever reach this */ }
void ike_alg_serpent_init(void) { if (!ike_alg_register_enc(&encrypt_desc_serpent)) libreswan_log( "ike_alg_serpent_init(): OAKLEY_SERPENT_CBC activation failed"); }
/** * virtual string must be : * {vhost,vnet}:[%method]* * * vhost = accept only a host (/32) * vnet = accept any network * * %no = no virtual IP (accept public IP) * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented] * %ike = accept affected IKE Config Mode IP [not implemented] * %priv = accept system-wide private net list * %v4:x = accept ipv4 in list 'x' * %v6:x = accept ipv6 in list 'x' * %all = accept all ips [only for testing] * * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24 * * @param c Connection Struct * @param string (virtual_private= from ipsec.conf) * @return virtual_t */ struct virtual_t *create_virtual(const struct connection *c, const char *string) { unsigned short flags = 0, n_net = 0, i; const char *str = string, *next, *first_net = NULL; ip_subnet sub; struct virtual_t *v; if ((!string) || (string[0] == '\0')) return NULL; if ((strlen(string) >= 6) && (strncmp(string, "vhost:", 6) == 0)) { flags |= F_VIRTUAL_HOST; str += 6; } else if ((strlen(string) >= 5) && (strncmp(string, "vnet:", 5) == 0)) { str += 5; } else { goto fail; } /** * Parse string : fill flags & count subnets */ while ((str) && (*str)) { next = strchr(str, ','); if (!next) next = str + strlen(str); if ((next - str == 3) && (strncmp(str, "%no", 3) == 0)) { flags |= F_VIRTUAL_NO; } #if 0 else if ((next - str == 4) && (strncmp(str, "%ike", 4) == 0)) { flags |= F_VIRTUAL_IKE_CONFIG; } else if ((next - str == 5) && (strncmp(str, "%dhcp", 5) == 0)) { flags |= F_VIRTUAL_DHCP; } #endif else if ((next - str == 5) && (strncmp(str, "%priv", 5) == 0)) { flags |= F_VIRTUAL_PRIVATE; } else if ((next - str == 4) && (strncmp(str, "%all", 4) == 0)) { flags |= F_VIRTUAL_ALL; } else if (_read_subnet(str, next - str, &sub, NULL, NULL)) { n_net++; if (!first_net) first_net = str; } else { goto fail; } str = *next ? next + 1 : NULL; } v = (struct virtual_t *)alloc_bytes( sizeof(struct virtual_t) + (n_net * sizeof(ip_subnet)), "virtual description"); if (!v) goto fail; v->flags = flags; v->n_net = n_net; if (n_net && first_net) { /** * Save subnets in newly allocated struct */ for (str = first_net, i = 0; (str) && (*str); ) { next = strchr(str, ','); if (!next) next = str + strlen(str); if (_read_subnet(str, next - str, &(v->net[i]), NULL, NULL)) i++; str = *next ? next + 1 : NULL; } } return v; fail: libreswan_log("invalid virtual string [%s] - " "virtual selection disabled for connection '%s'", string, c->name); return NULL; }
bool invoke_command(const char *verb, const char *verb_suffix, char *cmd) { DBG(DBG_CONTROL, DBG_log("executing %s%s: %s", verb, verb_suffix, cmd)); { /* invoke the script, catching stderr and stdout * It may be of concern that some file descriptors will * be inherited. For the ones under our control, we * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. * Any used by library routines (perhaps the resolver or syslog) * will remain. */ sig_t savesig; FILE *f; savesig = signal(SIGCHLD, SIG_DFL); f = popen(cmd, "r"); if (f == NULL) { loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); signal(SIGCHLD, savesig); return FALSE; } /* log any output */ for (;; ) { /* if response doesn't fit in this buffer, it will be folded */ char resp[256]; if (fgets(resp, sizeof(resp), f) == NULL) { if (ferror(f)) { log_errno((e, "fgets failed on output of %s%s command", verb, verb_suffix)); signal(SIGCHLD, savesig); return FALSE; } else { passert(feof(f)); break; } } else { char *e = resp + strlen(resp); if (e > resp && e[-1] == '\n') e[-1] = '\0'; /* trim trailing '\n' */ libreswan_log("%s%s output: %s", verb, verb_suffix, resp); } } /* report on and react to return code */ { int r = pclose(f); signal(SIGCHLD, savesig); if (r == -1) { log_errno((e, "pclose failed for %s%s command", verb, verb_suffix)); return FALSE; } else if (WIFEXITED(r)) { if (WEXITSTATUS(r) != 0) { loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d", verb, verb_suffix, WEXITSTATUS(r)); return FALSE; } } else if (WIFSIGNALED(r)) { loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d", verb, verb_suffix, WTERMSIG(r)); return FALSE; } else { loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d", verb, verb_suffix, r); return FALSE; } } } return TRUE; }
static void init_seccomp(uint32_t def_action, bool main) { scmp_filter_ctx ctx = seccomp_init(def_action); if (ctx == NULL) { libreswan_log("seccomp_init() failed!"); exit_pluto(PLUTO_EXIT_SECCOMP_FAIL); } /* * read() and wait4() take the vast majority of syscall time * So we place these at the head of the list for performance * example strace -c -f output if pluto: * * % time seconds usecs/call calls errors syscall * ------ ----------- ----------- --------- --------- ---------------- * 73.70 41.137940 1202 34232 343 read * 20.77 11.595734 3549 3267 1176 wait4 * 1.47 0.819570 709 1156 epoll_wait * 0.60 0.332147 1 319902 rt_sigprocmask * 0.55 0.307552 5 61578 mmap * 0.41 0.230820 6 37788 2877 open * [...] */ LSW_SECCOMP_ADD(ctx, read); if (main) { LSW_SECCOMP_ADD(ctx, wait4); } #ifdef USE_EFENCE LSW_SECCOMP_ADD(ctx, madvise); #endif /* needed for pluto and updown, not helpers */ if (main) { LSW_SECCOMP_ADD(ctx, accept); LSW_SECCOMP_ADD(ctx, access); LSW_SECCOMP_ADD(ctx, bind); LSW_SECCOMP_ADD(ctx, brk); LSW_SECCOMP_ADD(ctx, chdir); LSW_SECCOMP_ADD(ctx, clone); LSW_SECCOMP_ADD(ctx, close); LSW_SECCOMP_ADD(ctx, connect); LSW_SECCOMP_ADD(ctx, dup); LSW_SECCOMP_ADD(ctx, dup2); LSW_SECCOMP_ADD(ctx, epoll_create); LSW_SECCOMP_ADD(ctx, epoll_ctl); LSW_SECCOMP_ADD(ctx, epoll_wait); LSW_SECCOMP_ADD(ctx, epoll_pwait); LSW_SECCOMP_ADD(ctx, execve); LSW_SECCOMP_ADD(ctx, faccessat); LSW_SECCOMP_ADD(ctx, fadvise64); LSW_SECCOMP_ADD(ctx, fcntl); LSW_SECCOMP_ADD(ctx, getcwd); LSW_SECCOMP_ADD(ctx, getdents); LSW_SECCOMP_ADD(ctx, getegid); LSW_SECCOMP_ADD(ctx, geteuid); LSW_SECCOMP_ADD(ctx, getgid); LSW_SECCOMP_ADD(ctx, getgroups); LSW_SECCOMP_ADD(ctx, getpgrp); LSW_SECCOMP_ADD(ctx, getpid); LSW_SECCOMP_ADD(ctx, getppid); LSW_SECCOMP_ADD(ctx, getrlimit); LSW_SECCOMP_ADD(ctx, getsockname); LSW_SECCOMP_ADD(ctx, getsockopt); LSW_SECCOMP_ADD(ctx, getuid); LSW_SECCOMP_ADD(ctx, ioctl); LSW_SECCOMP_ADD(ctx, lstat); LSW_SECCOMP_ADD(ctx, mkdir); LSW_SECCOMP_ADD(ctx, munmap); LSW_SECCOMP_ADD(ctx, newfstatat); LSW_SECCOMP_ADD(ctx, open); LSW_SECCOMP_ADD(ctx, openat); LSW_SECCOMP_ADD(ctx, pipe); LSW_SECCOMP_ADD(ctx, pipe2); LSW_SECCOMP_ADD(ctx, poll); LSW_SECCOMP_ADD(ctx, prctl); LSW_SECCOMP_ADD(ctx, pread64); LSW_SECCOMP_ADD(ctx, prlimit64); LSW_SECCOMP_ADD(ctx, readlink); LSW_SECCOMP_ADD(ctx, recvfrom); LSW_SECCOMP_ADD(ctx, recvmsg); LSW_SECCOMP_ADD(ctx, select); LSW_SECCOMP_ADD(ctx, sendmsg); LSW_SECCOMP_ADD(ctx, set_robust_list); LSW_SECCOMP_ADD(ctx, setsockopt); LSW_SECCOMP_ADD(ctx, socket); LSW_SECCOMP_ADD(ctx, socketcall); LSW_SECCOMP_ADD(ctx, socketpair); LSW_SECCOMP_ADD(ctx, sysinfo); LSW_SECCOMP_ADD(ctx, uname); LSW_SECCOMP_ADD(ctx, unlink); LSW_SECCOMP_ADD(ctx, unlinkat); } /* common to pluto and helpers */ LSW_SECCOMP_ADD(ctx, arch_prctl); LSW_SECCOMP_ADD(ctx, exit_group); LSW_SECCOMP_ADD(ctx, gettid); LSW_SECCOMP_ADD(ctx, gettimeofday); LSW_SECCOMP_ADD(ctx, fstat); LSW_SECCOMP_ADD(ctx, futex); LSW_SECCOMP_ADD(ctx, lseek); LSW_SECCOMP_ADD(ctx, mmap); LSW_SECCOMP_ADD(ctx, mprotect); LSW_SECCOMP_ADD(ctx, nanosleep); LSW_SECCOMP_ADD(ctx, rt_sigaction); LSW_SECCOMP_ADD(ctx, rt_sigprocmask); LSW_SECCOMP_ADD(ctx, rt_sigreturn); LSW_SECCOMP_ADD(ctx, sched_setparam); LSW_SECCOMP_ADD(ctx, sendto); LSW_SECCOMP_ADD(ctx, set_tid_address); LSW_SECCOMP_ADD(ctx, sigaltstack); LSW_SECCOMP_ADD(ctx, sigreturn); LSW_SECCOMP_ADD(ctx, stat); LSW_SECCOMP_ADD(ctx, statfs); LSW_SECCOMP_ADD(ctx, clock_gettime); LSW_SECCOMP_ADD(ctx, waitpid); LSW_SECCOMP_ADD(ctx, write); int rc = seccomp_load(ctx); if (rc < 0) { LOG_ERRNO(-rc, "seccomp_load() failed!"); seccomp_release(ctx); exit_pluto(PLUTO_EXIT_SECCOMP_FAIL); } libreswan_log("seccomp security enabled"); }
/* * Parses an X.509 attribute certificate */ static bool parse_ac(chunk_t blob, x509acert_t *ac) { asn1_ctx_t ctx; bool critical; chunk_t extnID; chunk_t type; chunk_t object; u_int level; u_int objectID = 0; asn1_init(&ctx, blob, 0, FALSE, DBG_RAW); while (objectID < AC_OBJ_ROOF) { if (!extract_object(acObjects, &objectID, &object, &level, &ctx)) return FALSE; /* those objects which will parsed further need the next higher level */ level++; switch (objectID) { case AC_OBJ_CERTIFICATE: ac->certificate = object; break; case AC_OBJ_CERTIFICATE_INFO: ac->certificateInfo = object; break; case AC_OBJ_VERSION: ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; DBG(DBG_PARSING, DBG_log(" v%d", ac->version); ) if (ac->version != 2) { libreswan_log("v%d attribute certificates are not supported" , ac->version); return FALSE; } break; case AC_OBJ_HOLDER_ISSUER: ac->holderIssuer = get_directoryName(object, level, FALSE); break; case AC_OBJ_HOLDER_SERIAL: ac->holderSerial = object; break; case AC_OBJ_ENTITY_NAME: ac->entityName = get_directoryName(object, level, TRUE); break; case AC_OBJ_ISSUER_NAME: ac->issuerName = get_directoryName(object, level, FALSE); break; case AC_OBJ_SIG_ALG: ac->sigAlg = parse_algorithmIdentifier(object, level); break; case AC_OBJ_SERIAL_NUMBER: ac->serialNumber = object; break; case AC_OBJ_NOT_BEFORE: ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME); break; case AC_OBJ_NOT_AFTER: ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME); break; case AC_OBJ_ATTRIBUTE_TYPE: type = object; break; case AC_OBJ_ATTRIBUTE_VALUE: { u_int type_oid = known_oid(type); switch (type_oid) { case OID_AUTHENTICATION_INFO: DBG(DBG_PARSING, DBG_log(" need to parse authenticationInfo") ) break; case OID_ACCESS_IDENTITY: DBG(DBG_PARSING, DBG_log(" need to parse accessIdentity") ) break; case OID_CHARGING_IDENTITY: ac->charging = parse_ietfAttrSyntax(object, level); break; case OID_GROUP: ac->groups = parse_ietfAttrSyntax(object, level); break; case OID_ROLE: parse_roleSyntax(object, level); break; default: break; } } break; case AC_OBJ_EXTN_ID: extnID = object; break; case AC_OBJ_CRITICAL: critical = object.len && *object.ptr; DBG(DBG_PARSING, DBG_log(" %s",(critical)?"TRUE":"FALSE"); ) break; case AC_OBJ_EXTN_VALUE: { u_int extn_oid = known_oid(extnID); switch (extn_oid) { case OID_CRL_DISTRIBUTION_POINTS: DBG(DBG_PARSING, DBG_log(" need to parse crlDistributionPoints") ) break; case OID_AUTHORITY_KEY_ID: parse_authorityKeyIdentifier(object, level , &ac->authKeyID, &ac->authKeySerialNumber); break; case OID_TARGET_INFORMATION: DBG(DBG_PARSING, DBG_log(" need to parse targetInformation") ) break; case OID_NO_REV_AVAIL: ac->noRevAvail = TRUE; break; default: break; } } break; case AC_OBJ_ALGORITHM: ac->algorithm = parse_algorithmIdentifier(object, level); break; case AC_OBJ_SIGNATURE: ac->signature = object; break; default: break; }
static bool ikev2_calculate_psk_sighash(struct state *st, enum original_role role, unsigned char *idhash, chunk_t firstpacket, unsigned char *signed_octets) { const chunk_t *nonce; const char *nonce_name; const struct connection *c = st->st_connection; const chunk_t *pss = &empty_chunk; const size_t hash_len = st->st_oakley.prf_hasher->hash_digest_len; if (!(c->policy & POLICY_AUTH_NULL)) { pss = get_preshared_secret(c); if (pss == NULL) { libreswan_log("No matching PSK found for connection:%s", st->st_connection->name); return FALSE; /* failure: no PSK to use */ } DBG(DBG_PRIVATE, DBG_dump_chunk("User PSK:", *pss)); } else { /* * draft-ietf-ipsecme-ikev2-null-auth-02 * * When using the NULL Authentication Method, the * content of the AUTH payload is computed using the * syntax of pre-shared secret authentication, * described in Section 2.15 of [RFC7296]. The values * SK_pi and SK_pr are used as shared secrets for the * content of the AUTH payloads generated by the * initiator and the responder respectively. * * We have SK_pi/SK_pr as PK11SymKey in st_skey_pi_nss * and st_skey_pr_nss */ passert(st->hidden_variables.st_skeyid_calculated); /* * This is wrong as role - we need to role for THIS exchange * But verify calls this routine with the role inverted, so we * cannot juse st->st_state either. */ if (role == ORIGINAL_INITIATOR) { /* we are sending initiator, or verifying responder */ pss = &st->st_skey_chunk_SK_pi; } else { /* we are verifying initiator, or sending responder */ pss = &st->st_skey_chunk_SK_pr; } DBG(DBG_PRIVATE, DBG_dump_chunk("AUTH_NULL PSK:", *pss)); } /* * RFC 4306 2.15: * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ /* calculate inner prf */ PK11SymKey *prf_psk; { struct crypt_prf *prf = crypt_prf_init(("<prf-psk>" " = prf(<psk>,\"Key Pad for IKEv2\")"), st->st_oakley.prf_hasher, st->st_shared_nss/*scratch*/); crypt_prf_init_chunk("shared secret", prf, *pss); crypt_prf_update(prf); crypt_prf_update_bytes(psk_key_pad_str/*name*/, prf, psk_key_pad_str, psk_key_pad_str_len); prf_psk = crypt_prf_final(prf); } /* decide nonce based on the role */ if (role == ORIGINAL_INITIATOR) { /* on initiator, we need to hash responders nonce */ nonce = &st->st_nr; nonce_name = "inputs to hash2 (responder nonce)"; } else { nonce = &st->st_ni; nonce_name = "inputs to hash2 (initiator nonce)"; } /* calculate outer prf */ { struct crypt_prf *prf = crypt_prf_init(("<signed-octets>" " = prf(<prf-psk>, <msg octets>)"), st->st_oakley.prf_hasher, st->st_shared_nss /*scratch*/); crypt_prf_init_symkey("<prf-psk>", prf, prf_psk); /* * For the responder, the octets to be signed start * with the first octet of the first SPI in the header * of the second message and end with the last octet * of the last payload in the second message. * Appended to this (for purposes of computing the * signature) are the initiator's nonce Ni (just the * value, not the payload containing it), and the * value prf(SK_pr,IDr') where IDr' is the responder's * ID payload excluding the fixed header. Note that * neither the nonce Ni nor the value prf(SK_pr,IDr') * are transmitted. */ crypt_prf_update(prf); crypt_prf_update_chunk("first-packet", prf, firstpacket); crypt_prf_update_chunk("nonce", prf, *nonce); crypt_prf_update_bytes("hash", prf, idhash, hash_len); crypt_prf_final_bytes(prf, signed_octets, hash_len); } free_any_symkey("<prf-psk>", &prf_psk); DBG(DBG_CRYPT, DBG_dump_chunk("inputs to hash1 (first packet)", firstpacket); DBG_dump_chunk(nonce_name, *nonce); DBG_dump("idhash", idhash, hash_len)); return TRUE; }
bool invoke_command(const char *verb, const char *verb_suffix, char *cmd) { DBG(DBG_CONTROL, DBG_log("executing %s%s: %s", verb, verb_suffix, cmd)); { char tmp[100]; int slen, i; memset(tmp, 0, sizeof(tmp)); slen = strlen(cmd); DBG(DBG_CONTROL, DBG_log("popen(): cmd is %d chars long", slen)); for (i = 0; i < slen; i += 80) { strncpy(tmp, &cmd[i], 80); DBG(DBG_CONTROL, DBG_log("cmd(%4d):%s:", i, tmp)); } } { /* invoke the script, catching stderr and stdout * It may be of concern that some file descriptors will * be inherited. For the ones under our control, we * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. * Any used by library routines (perhaps the resolver or syslog) * will remain. */ __sighandler_t savesig; FILE *f; savesig = signal(SIGCHLD, SIG_DFL); f = popen(cmd, "r"); if (f == NULL) { #ifdef HAVE_BROKEN_POPEN /* See bug #1067 Angstrom Linux on a arm7 has no popen() */ if (errno == ENOSYS) { /* Try system(), though it will not give us output */ system(cmd); DBG_log( "unable to popen(), falling back to system()"); return TRUE; } #endif loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); signal(SIGCHLD, savesig); return FALSE; } /* log any output */ for (;; ) { /* if response doesn't fit in this buffer, it will be folded */ char resp[256]; if (fgets(resp, sizeof(resp), f) == NULL) { if (ferror(f)) { log_errno((e, "fgets failed on output of %s%s command", verb, verb_suffix)); signal(SIGCHLD, savesig); return FALSE; } else { passert(feof(f)); break; } } else { char *e = resp + strlen(resp); if (e > resp && e[-1] == '\n') e[-1] = '\0'; /* trim trailing '\n' */ libreswan_log("%s%s output: %s", verb, verb_suffix, resp); } } /* report on and react to return code */ { int r = pclose(f); signal(SIGCHLD, savesig); if (r == -1) { log_errno((e, "pclose failed for %s%s command", verb, verb_suffix)); return FALSE; } else if (WIFEXITED(r)) { if (WEXITSTATUS(r) != 0) { loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d", verb, verb_suffix, WEXITSTATUS( r)); return FALSE; } } else if (WIFSIGNALED(r)) { loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d", verb, verb_suffix, WTERMSIG(r)); return FALSE; } else { loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d", verb, verb_suffix, r); return FALSE; } } } return TRUE; }
/* * initialize a helper. */ static void init_crypto_helper(struct pluto_crypto_worker *w, int n) { int fds[2]; int thread_status; /* reset this */ w->pcw_master_fd = -1; w->pcw_helpernum = n; if (w->evm != NULL) { event_del(w->evm); w->evm = NULL; } if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) != 0) { loglog(RC_LOG_SERIOUS, "could not create socketpair for crypto helper %d: %s", n, strerror(errno)); return; } w->pcw_master_fd = fds[0]; w->pcw_helper_fd = fds[1]; w->pcw_maxbasicwork = MAX_HELPER_BASIC_WORK; w->pcw_maxcritwork = MAX_HELPER_CRIT_WORK; w->pcw_work = 0; w->pcw_dead = FALSE; TAILQ_INIT(&w->pcw_active); /* set the send/received queue length to be at least maxcritwork * times sizeof(pluto_crypto_req) in size */ { int qlen = w->pcw_maxcritwork * sizeof(struct pluto_crypto_req); if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &qlen, sizeof(qlen)) == -1 || setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, &qlen, sizeof(qlen)) == -1 || setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, &qlen, sizeof(qlen)) == -1 || setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &qlen, sizeof(qlen)) == -1) { loglog(RC_LOG_SERIOUS, "could not set socket queue to %d for crypto helper %d", qlen, n); return; } } thread_status = pthread_create(&w->pcw_pid, NULL, pluto_helper_thread, (void *)w); if (thread_status != 0) { loglog(RC_LOG_SERIOUS, "failed to start child thread for crypto helper %d, error = %d", n, thread_status); close(fds[1]); close(fds[0]); w->pcw_master_fd = -1; w->pcw_dead = TRUE; } else { libreswan_log("started thread for crypto helper %d (master fd %d)", n, w->pcw_master_fd); } { /* setup call back crypto helper fd */ /* EV_WRITE event is ignored do we care about EV_WRITE AA_2015 ??? */ DBG(DBG_CONTROL, DBG_log("setup helper callback for master fd %d", w->pcw_master_fd)); w->evm = pluto_event_new(w->pcw_master_fd, EV_READ | EV_PERSIST, handle_helper_answer_cb, w, NULL); } }
static stf_status aggr_inI1_outR1_common(struct msg_digest *md, int authtype) { /* With Aggressive Mode, we get an ID payload in this, the first * message, so we can use it to index the preshared-secrets * when the IP address would not be meaningful (i.e. Road * Warrior). So our first task is to unravel the ID payload. */ struct state *st; struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct connection *c = find_host_connection(&md->iface->ip_addr, md->iface->port, &md->sender, md->sender_port, LEMPTY); #if 0 if (c == NULL && md->iface->ike_float) { c = find_host_connection(&md->iface->addr, pluto_nat_port, &md->sender, md->sender_port, LEMPTY); } #endif if (c == NULL) { /* see if a wildcarded connection can be found */ pb_stream pre_sa_pbs = sa_pd->pbs; lset_t policy = preparse_isakmp_sa_body(&pre_sa_pbs) | POLICY_AGGRESSIVE; c = find_host_connection(&md->iface->ip_addr, pluto_port, (ip_address*)NULL, md->sender_port, policy); if (c == NULL || (c->policy & POLICY_AGGRESSIVE) == 0) { ipstr_buf b; loglog(RC_LOG_SERIOUS, "initial Aggressive Mode message from %s" " but no (wildcard) connection has been configured%s%s", ipstr(&md->sender, &b), (policy != LEMPTY) ? " with policy=" : "", (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); /* XXX notification is in order! */ return STF_IGNORE; } /* Create a temporary connection that is a copy of this one. * His ID isn't declared yet. */ c = rw_instantiate(c, &md->sender, NULL, NULL); } /* Set up state */ cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */ st->st_connection = c; st->st_remoteaddr = md->sender; st->st_remoteport = md->sender_port; st->st_localaddr = md->iface->ip_addr; st->st_localport = md->iface->port; st->st_interface = md->iface; change_state(st, STATE_AGGR_R1); /* until we have clue who this is, then be conservative about allocating * them any crypto bandwidth */ st->st_import = pcim_stranger_crypto; st->st_policy |= POLICY_AGGRESSIVE; st->st_oakley.auth = authtype; if (!ikev1_decode_peer_id(md, FALSE, TRUE)) { char buf[IDTOA_BUF]; ipstr_buf b; (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "initial Aggressive Mode packet claiming to be from %s" " on %s but no connection has been authorized", buf, ipstr(&md->sender, &b)); /* XXX notification is in order! */ return STF_FAIL + INVALID_ID_INFORMATION; } c = st->st_connection; extra_debugging(c); st->st_try = 0; /* Not our job to try again from start */ st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); insert_state(st); /* needs cookies, connection, and msgid (0) */ st->st_doi = ISAKMP_DOI_IPSEC; st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ { ipstr_buf b; libreswan_log("responding to Aggressive Mode, state #%lu, connection \"%s\" from %s", st->st_serialno, st->st_connection->name, ipstr(&c->spd.that.host_addr, &b)); } merge_quirks(st, md); set_nat_traversal(st, md); /* save initiator SA for HASH */ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in aggr_inI1_outR1()"); /* * parse_isakmp_sa picks the right group, which we need to know * before we do any calculations. We will call it again to have it * emit the winning SA into the output. */ /* SA body in */ { pb_stream sabs = sa_pd->pbs; RETURN_STF_FAILURE(parse_isakmp_sa_body(&sabs, &sa_pd->payload.sa, NULL, FALSE, st)); } /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, &md->chain[ISAKMP_NEXT_KE]->pbs)); /* Ni in */ RETURN_STF_FAILURE(accept_v1_nonce(md, &st->st_ni, "Ni")); { struct ke_continuation *ke = alloc_thing( struct ke_continuation, "outI2 KE"); ke->ke_md = md; set_suspended(st, md); if (!st->st_sec_in_use) { /* need to calculate KE and Nonce */ pcrc_init(&ke->ke_pcrc, aggr_inI1_outR1_continue1); return build_ke(&ke->ke_pcrc, st, st->st_oakley.group, st->st_import); } else { /* KE and Nonce calculated */ ke->ke_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ return aggr_inI1_outR1_tail(&ke->ke_pcrc, NULL); } } }
bool lsw_nss_setup(const char *configdir, unsigned setup_flags, PK11PasswordFunc get_password, lsw_nss_buf_t err) { /* * save for cleanup */ flags = setup_flags; /* * According to the manual, not needed, and all parameters are * ignored. Does no harm? */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1); libreswan_log("Initializing NSS"); if (configdir) { const char sql[] = "sql:"; char *nssdb; if (strncmp(sql, configdir, strlen(sql)) == 0) { nssdb = strdup(configdir); } else { nssdb = alloc_bytes(strlen(configdir) + strlen(sql) + 1, "nssdb"); strcpy(nssdb, sql); strcat(nssdb, configdir); } libreswan_log("Opening NSS database \"%s\" %s", nssdb, (flags & LSW_NSS_READONLY) ? "read-only" : "read-write"); SECStatus rv = NSS_Initialize(nssdb, "", "", SECMOD_DB, (flags & LSW_NSS_READONLY) ? NSS_INIT_READONLY : 0); if (rv != SECSuccess) { snprintf(err, sizeof(lsw_nss_buf_t), "Initialization of NSS with %s database \"%s\" failed (%d)", (flags & LSW_NSS_READONLY) ? "read-only" : "read-write", nssdb, PR_GetError()); pfree(nssdb); return FALSE; } } else { NSS_NoDB_Init("."); } if (PK11_IsFIPS() && get_password == NULL) { snprintf(err, sizeof(lsw_nss_buf_t), "on FIPS mode a password is required"); return FALSE; } if (get_password) { PK11_SetPasswordFunc(get_password); } if (!(flags & LSW_NSS_SKIP_AUTH)) { PK11SlotInfo *slot = lsw_nss_get_authenticated_slot(err); if (slot == NULL) { return FALSE; } PK11_FreeSlot(slot); } return TRUE; }
static void klips_process_raw_ifaces(struct raw_iface *rifaces) { struct raw_iface *ifp; /* Find all virtual/real interface pairs. * For each real interface... */ for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { struct raw_iface *v = NULL; /* matching ipsecX interface */ struct raw_iface fake_v; bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; ip_address lip; if (pluto_listen) { err_t e; e = ttoaddr(pluto_listen, 0, 0, &lip); if (e) { DBG_log("invalid listen= option ignored: %s\n", e); pluto_listen = NULL; } } /* ignore if virtual (ipsec*) interface */ if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX) - 1) == 0) continue; /* ignore if virtual (mast*) interface */ if (strncmp(ifp->name, MASTDEVPREFIX, sizeof(MASTDEVPREFIX) - 1) == 0) continue; for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { if (vfp == ifp) { after = TRUE; } else if (sameaddr(&ifp->addr, &vfp->addr)) { /* Different entries with matching IP addresses. * Many interesting cases. */ if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX) - 1) == 0) { if (v != NULL) { loglog(RC_LOG_SERIOUS, "ipsec interfaces %s and %s share same address %s", v->name, vfp->name, ip_str(&ifp->addr)); bad = TRUE; } else { v = vfp; /* current winner */ } } else { /* ugh: a second real interface with the same IP address * "after" allows us to avoid double reporting. */ #if defined(linux) && defined(NETKEY_SUPPORT) if (kern_interface == USE_NETKEY) { if (after) { bad = TRUE; break; } continue; } #endif if (after) { loglog(RC_LOG_SERIOUS, "IP interfaces %s and %s share address %s!", ifp->name, vfp->name, ip_str(&ifp->addr)); } bad = TRUE; } } } if (bad) continue; #if defined(linux) && defined(NETKEY_SUPPORT) if (kern_interface == USE_NETKEY) { v = ifp; goto add_entry; } #endif /* what if we didn't find a virtual interface? */ if (v == NULL) { if (kern_interface == NO_KERNEL) { /* kludge for testing: invent a virtual device */ static const char fvp[] = "virtual"; fake_v = *ifp; passert(sizeof(fake_v.name) > sizeof(fvp)); strcpy(fake_v.name, fvp); addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1, sizeof(fake_v.name) - (sizeof(fvp) - 1)); v = &fake_v; } else { DBG(DBG_CONTROL, DBG_log( "IP interface %s %s has no matching ipsec* interface -- ignored", ifp->name, ip_str(&ifp->addr))); continue; } } /* ignore if --listen is specified and we do not match */ if (pluto_listen != NULL) { if (!sameaddr(&lip, &ifp->addr)) { libreswan_log("skipping interface %s with %s", ifp->name, ip_str(&ifp->addr)); continue; } } /* We've got all we need; see if this is a new thing: * search old interfaces list. */ #if defined(linux) && defined(NETKEY_SUPPORT) add_entry: #endif { struct iface_port **p = &interfaces; for (;; ) { struct iface_port *q = *p; struct iface_dev *id = NULL; /* search is over if at end of list */ if (q == NULL) { /* matches nothing -- create a new entry */ int fd = create_socket(ifp, v->name, pluto_port); if (fd < 0) break; DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: checking for nat_traversal_support_non_ike for IPv4")); if (nat_traversal_support_non_ike && addrtypeof(&ifp->addr) == AF_INET) { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: found, calling nat_traversal_espinudp_socket")); nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_IKE); } else { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: support not found, nat_traversal_support_non_ike = %s", nat_traversal_support_non_ike ? "TRUE" : "FALSE")); } q = alloc_thing(struct iface_port, "struct iface_port"); id = alloc_thing(struct iface_dev, "struct iface_dev"); LIST_INSERT_HEAD(&interface_dev, id, id_entry); q->ip_dev = id; id->id_rname = clone_str(ifp->name, "real device name"); id->id_vname = clone_str(v->name, "virtual device name klips"); id->id_count++; q->ip_addr = ifp->addr; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->port = pluto_port; q->ike_float = FALSE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q->ip_addr), q->port); /* * right now, we do not support NAT-T on IPv6, because * the kernel did not support it, and gave an error * it one tried to turn it on. */ if (nat_traversal_support_port_floating && addrtypeof(&ifp->addr) == AF_INET) { DBG(DBG_NATT, DBG_log( "NAT-T KLIPS: found floating port, calling nat_traversal_espinudp_socket")); fd = create_socket(ifp, v->name, pluto_natt_float_port); if (fd < 0) break; nat_traversal_espinudp_socket( fd, "IPv4", ESPINUDP_WITH_NON_ESP); q = alloc_thing( struct iface_port, "struct iface_port"); q->ip_dev = id; id->id_count++; q->ip_addr = ifp->addr; setportof(htons( pluto_natt_float_port), &q->ip_addr); q->port = pluto_natt_float_port; q->fd = fd; q->next = interfaces; q->change = IFN_ADD; q->ike_float = TRUE; interfaces = q; libreswan_log( "adding interface %s/%s %s:%d", q->ip_dev->id_vname, q->ip_dev->id_rname, ip_str(&q-> ip_addr), q->port); } break; } /* search over if matching old entry found */ if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, v->name) && sameaddr(&q->ip_addr, &ifp->addr)) { /* matches -- rejuvinate old entry */ q->change = IFN_KEEP; /* look for other interfaces to keep (due to NAT-T) */ for (q = q->next; q; q = q->next) { if (streq(q->ip_dev->id_rname, ifp->name) && streq(q->ip_dev->id_vname, v->name) && sameaddr(&q->ip_addr, &ifp->addr)) q->change = IFN_KEEP; } break; } /* try again */ p = &q->next; } /* for (;;) */ }
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 */ }
char *getNSSPassword(PK11SlotInfo *slot, PRBool retry, void *arg) { secuPWData *pwdInfo = (secuPWData *)arg; PRFileDesc *fd; PRInt32 nb; /*number of bytes*/ char* password; char* strings; char* token=NULL; const long maxPwdFileSize = NSSpwdfilesize; int i, tlen=0; if (slot) { token = PK11_GetTokenName(slot); if (token) { tlen = PORT_Strlen(token); /* libreswan_log("authentication needed for token name %s with length %d",token,tlen); */ } else { return 0; } } else { return 0; } if(retry) return 0; strings=PORT_ZAlloc(maxPwdFileSize); if(!strings) { libreswan_log("Not able to allocate memory for reading NSS password file"); return 0; } if(pwdInfo->source == PW_FROMFILE) { if(pwdInfo->data !=NULL) { fd = PR_Open(pwdInfo->data, PR_RDONLY, 0); if (!fd) { PORT_Free(strings); libreswan_log("No password file \"%s\" exists.", pwdInfo->data); return 0; } nb = PR_Read(fd, strings, maxPwdFileSize); PR_Close(fd); if (nb == 0) { libreswan_log("password file contains no data"); PORT_Free(strings); return 0; } i = 0; do { int start = i; int slen; while (strings[i] != '\r' && strings[i] != '\n' && i < nb) i++; strings[i++] = '\0'; while ( (i<nb) && (strings[i] == '\r' || strings[i] == '\n')) { strings[i++] = '\0'; } password = &strings[start]; if (PORT_Strncmp(password, token, tlen)) continue; slen = PORT_Strlen(password); if (slen < (tlen+1)) continue; if (password[tlen] != ':') continue; password = &password[tlen+1]; break; } while (i<nb); password = PORT_Strdup((char*)password); PORT_Free(strings); /* libreswan_log("Password passed to NSS is %s with length %d", password, PORT_Strlen(password)); */ return password; } else { libreswan_log("File with Password to NSS DB is not provided"); return 0; } } libreswan_log("nss password source is not specified as file"); return 0; }