From f84dc62cc602eacb0daee3e9918a68b711ba94f0 Mon Sep 17 00:00:00 2001 From: Othmar Gsenger Date: Sat, 8 Dec 2007 20:59:57 +0000 Subject: removed isakmpd --- keyexchange/isakmpd-20041012/pf_key_v2.c | 4472 ------------------------------ 1 file changed, 4472 deletions(-) delete mode 100644 keyexchange/isakmpd-20041012/pf_key_v2.c (limited to 'keyexchange/isakmpd-20041012/pf_key_v2.c') diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.c b/keyexchange/isakmpd-20041012/pf_key_v2.c deleted file mode 100644 index 2614b7e..0000000 --- a/keyexchange/isakmpd-20041012/pf_key_v2.c +++ /dev/null @@ -1,4472 +0,0 @@ -/* $OpenBSD: pf_key_v2.c,v 1.150 2004/09/17 13:53:08 ho Exp $ */ -/* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */ - -/* - * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. - * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. - * Copyright (c) 2001 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This code was written under funding by Ericsson Radio Systems. - */ - -// TODO Check this -#include -#include -#include -#include -//--- - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "sysdep.h" - -#if !defined (LINUX_IPSEC) -#include -#endif -#include -#ifdef SADB_X_EXT_FLOW_TYPE -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "cert.h" -#include "conf.h" -#include "exchange.h" -#include "ipsec.h" -#include "ipsec_num.h" -#include "key.h" -#include "log.h" -#include "pf_key_v2.h" -#include "sa.h" -#include "timer.h" -#include "transport.h" -#include "util.h" - -#if defined (USE_KEYNOTE) -#include "policy.h" -#endif - -#if defined (USE_NAT_TRAVERSAL) -#include "udp_encap.h" -#endif - -#define IN6_IS_ADDR_FULL(a) \ - ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) && \ - (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) && \ - (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) && \ - (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff)) - -#define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255" - -/* - * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries. - */ -#define PF_KEY_V2_CHUNK 8 -#define PF_KEY_V2_ROUND(x) \ - (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1)) - -/* How many microseconds we will wait for a reply from the PF_KEY socket. */ -#define PF_KEY_REPLY_TIMEOUT 1000 - -struct pf_key_v2_node { - TAILQ_ENTRY(pf_key_v2_node) link; - void *seg; - size_t sz; - int cnt; - u_int16_t type; - u_int8_t flags; -}; - -TAILQ_HEAD(pf_key_v2_msg, pf_key_v2_node); - -#define PF_KEY_V2_NODE_MALLOCED 1 -#define PF_KEY_V2_NODE_MARK 2 - -#define PF_KEY_V2_SOCK_PATH "/var/run/pkkey" - -/* Used to derive "unique" connection identifiers. */ -int connection_seq = 0; - -#ifdef KAME -/* - * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the - * GETSPI creating the larval SA. - */ -struct pf_key_v2_sa_seq { - TAILQ_ENTRY(pf_key_v2_sa_seq) link; - u_int8_t *spi; - size_t sz; - u_int8_t proto; - struct sockaddr *dst; - int dstlen; - u_int32_t seq; -}; - -TAILQ_HEAD(, pf_key_v2_sa_seq) pf_key_v2_sa_seq_map; -#endif - -#ifndef KAME -static u_int8_t *pf_key_v2_convert_id(u_int8_t *, int, size_t *, int *); -#endif -static struct pf_key_v2_msg *pf_key_v2_call(struct pf_key_v2_msg *); -static struct pf_key_v2_node *pf_key_v2_find_ext(struct pf_key_v2_msg *, - u_int16_t); -static void pf_key_v2_notify(struct pf_key_v2_msg *); -static struct pf_key_v2_msg *pf_key_v2_read(u_int32_t); -static u_int32_t pf_key_v2_seq(void); -static u_int32_t pf_key_v2_write(struct pf_key_v2_msg *); -static int pf_key_v2_remove_conf(char *); -static int pf_key_v2_conf_refhandle(int, char *); - -#ifdef SADB_X_ASKPOLICY -static int pf_key_v2_conf_refinc(int, char *); -#endif - -/* The socket to use for PF_KEY interactions. */ -int pf_key_v2_socket; - -#ifdef KAME -static int -pf_key_v2_register_sa_seq(u_int8_t *spi, size_t sz, u_int8_t proto, - struct sockaddr *dst, int dstlen, u_int32_t seq) -{ - struct pf_key_v2_sa_seq *node = 0; - - node = malloc(sizeof *node); - if (!node) - goto cleanup; - memset(node, '0', sizeof *node); - node->spi = malloc(sz); - if (!node->spi) - goto cleanup; - node->dst = malloc(sysdep_sa_len(dst)); - if (!node->dst) - goto cleanup; - memcpy(node->dst, dst, sysdep_sa_len(dst)); - node->dstlen = sysdep_sa_len(dst); - memcpy(node->spi, spi, sz); - node->sz = sz; - node->proto = proto; - node->seq = seq; - TAILQ_INSERT_TAIL(&pf_key_v2_sa_seq_map, node, link); - return 1; - -cleanup: - if (node->dst) - free(node->dst); - if (node) - free(node); - return 0; -} - -static u_int32_t -pf_key_v2_seq_by_sa(u_int8_t *spi, size_t sz, u_int8_t proto, - struct sockaddr *dst, int dstlen) -{ - struct pf_key_v2_sa_seq *node; - - for (node = TAILQ_FIRST(&pf_key_v2_sa_seq_map); node; - node = TAILQ_NEXT(node, link)) - if (node->proto == proto && - node->sz == sz && memcmp(node->spi, spi, sz) == 0 && - node->dstlen == sysdep_sa_len(dst) && - memcmp(node->dst, dst, sysdep_sa_len(dst)) == 0) - return node->seq; - return 0; -} -#endif - -static struct pf_key_v2_msg * -pf_key_v2_msg_new(struct sadb_msg *msg, int flags) -{ - struct pf_key_v2_node *node = 0; - struct pf_key_v2_msg *ret; - - node = malloc(sizeof *node); - if (!node) - goto cleanup; - ret = malloc(sizeof *ret); - if (!ret) - goto cleanup; - TAILQ_INIT(ret); - node->seg = msg; - node->sz = sizeof *msg; - node->type = 0; - node->cnt = 1; - node->flags = flags; - TAILQ_INSERT_HEAD(ret, node, link); - return ret; - -cleanup: - if (node) - free(node); - return 0; -} - -/* Add a SZ sized segment SEG to the PF_KEY message MSG. */ -static int -pf_key_v2_msg_add(struct pf_key_v2_msg *msg, struct sadb_ext *ext, int flags) -{ - struct pf_key_v2_node *node; - - node = malloc(sizeof *node); - if (!node) - return -1; - node->seg = ext; - node->sz = ext->sadb_ext_len * PF_KEY_V2_CHUNK; - node->type = ext->sadb_ext_type; - node->flags = flags; - TAILQ_FIRST(msg)->cnt++; - TAILQ_INSERT_TAIL(msg, node, link); - return 0; -} - -/* Deallocate the PF_KEY message MSG. */ -static void -pf_key_v2_msg_free(struct pf_key_v2_msg *msg) -{ - struct pf_key_v2_node *np; - - np = TAILQ_FIRST(msg); - while (np) { - TAILQ_REMOVE(msg, np, link); - if (np->flags & PF_KEY_V2_NODE_MALLOCED) - free(np->seg); - free(np); - np = TAILQ_FIRST(msg); - } - free(msg); -} - -/* Just return a new sequence number. */ -static u_int32_t -pf_key_v2_seq(void) -{ - static u_int32_t seq = 0; - - return ++seq; -} - -/* - * Read a PF_KEY packet with SEQ as the sequence number, looping if necessary. - * If SEQ is zero just read the first message we see, otherwise we queue - * messages up until both the PID and the sequence number match. - */ -static struct pf_key_v2_msg * -pf_key_v2_read(u_int32_t seq) -{ - ssize_t n; - u_int8_t *buf = 0; - struct pf_key_v2_msg *ret = 0; - struct sadb_msg *msg; - struct sadb_msg hdr; - struct sadb_ext *ext; - struct timeval tv; - fd_set *fds; - - while (1) { - /* - * If this is a read of a reply we should actually expect the - * reply to get lost as PF_KEY is an unreliable service per - * the specs. Currently we do this by setting a short timeout, - * and if it is not readable in that time, we fail the read. - */ - if (seq) { - fds = calloc(howmany(pf_key_v2_socket + 1, NFDBITS), - sizeof(fd_mask)); - if (!fds) { - log_error("pf_key_v2_read: " - "calloc (%lu, %lu) failed", - (unsigned long) howmany(pf_key_v2_socket + 1, - NFDBITS), - (unsigned long) sizeof(fd_mask)); - goto cleanup; - } - FD_SET(pf_key_v2_socket, fds); - tv.tv_sec = 0; - tv.tv_usec = PF_KEY_REPLY_TIMEOUT; - n = select(pf_key_v2_socket + 1, fds, 0, 0, &tv); - free(fds); - if (n == -1) { - log_error("pf_key_v2_read: " - "select (%d, fds, 0, 0, &tv) failed", - pf_key_v2_socket + 1); - goto cleanup; - } - if (!n) { - log_print("pf_key_v2_read: " - "no reply from PF_KEY"); - goto cleanup; - } - } - n = recv(pf_key_v2_socket, &hdr, sizeof hdr, MSG_PEEK); - if (n == -1) { - log_error("pf_key_v2_read: recv (%d, ...) failed", - pf_key_v2_socket); - goto cleanup; - } - if (n != sizeof hdr) { - log_error("pf_key_v2_read: recv (%d, ...) " - "returned short packet (%lu bytes)", - pf_key_v2_socket, (unsigned long) n); - goto cleanup; - } - n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK; - buf = malloc(n); - if (!buf) { - log_error("pf_key_v2_read: malloc (%lu) failed", - (unsigned long) n); - goto cleanup; - } - n = read(pf_key_v2_socket, buf, n); - if (n == -1) { - log_error("pf_key_v2_read: read (%d, ...) failed", - pf_key_v2_socket); - goto cleanup; - } - if (n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) { - log_print("pf_key_v2_read: read (%d, ...) " - "returned short packet (%lu bytes)", - pf_key_v2_socket, (unsigned long) n); - goto cleanup; - } - LOG_DBG_BUF((LOG_SYSDEP, 80, "pf_key_v2_read: msg", buf, n)); - - /* We drop all messages that is not what we expect. */ - msg = (struct sadb_msg *) buf; - if (msg->sadb_msg_version != PF_KEY_V2 || - (msg->sadb_msg_pid != 0 && - msg->sadb_msg_pid != (u_int32_t) getpid())) { - if (seq) { - free(buf); - buf = 0; - continue; - } else { - LOG_DBG((LOG_SYSDEP, 90, "pf_key_v2_read:" - "bad version (%d) or PID (%d, mine is " - "%ld), ignored", msg->sadb_msg_version, - msg->sadb_msg_pid, (long) getpid())); - goto cleanup; - } - } - /* Parse the message. */ - ret = pf_key_v2_msg_new(msg, PF_KEY_V2_NODE_MALLOCED); - if (!ret) - goto cleanup; - buf = 0; - for (ext = (struct sadb_ext *) (msg + 1); - (u_int8_t *) ext - (u_int8_t *) msg < - msg->sadb_msg_len * PF_KEY_V2_CHUNK; - ext = (struct sadb_ext *) ((u_int8_t *) ext + - ext->sadb_ext_len * PF_KEY_V2_CHUNK)) - pf_key_v2_msg_add(ret, ext, 0); - - /* - * If the message is not the one we are waiting for, queue it - * up. - */ - if (seq && (msg->sadb_msg_pid != (u_int32_t) getpid() || - msg->sadb_msg_seq != seq)) { - gettimeofday(&tv, 0); - timer_add_event("pf_key_v2_notify", - (void (*) (void *)) pf_key_v2_notify, ret, &tv); - ret = 0; - continue; - } - return ret; - } - -cleanup: - if (buf) - free(buf); - if (ret) - pf_key_v2_msg_free(ret); - return 0; -} - -/* Write the message in PMSG to the PF_KEY socket. */ -u_int32_t -pf_key_v2_write(struct pf_key_v2_msg *pmsg) -{ - struct iovec *iov = 0; - ssize_t n; - size_t len; - int i, cnt = TAILQ_FIRST(pmsg)->cnt; - char header[80]; - struct sadb_msg *msg = TAILQ_FIRST(pmsg)->seg; - struct pf_key_v2_node *np = TAILQ_FIRST(pmsg); - - iov = (struct iovec *) malloc(cnt * sizeof *iov); - if (!iov) { - log_error("pf_key_v2_write: malloc (%lu) failed", - cnt * (unsigned long) sizeof *iov); - return 0; - } - msg->sadb_msg_version = PF_KEY_V2; - msg->sadb_msg_errno = 0; - msg->sadb_msg_reserved = 0; - msg->sadb_msg_pid = getpid(); - if (!msg->sadb_msg_seq) - msg->sadb_msg_seq = pf_key_v2_seq(); - - /* Compute the iovec segments as well as the message length. */ - len = 0; - for (i = 0; i < cnt; i++) { - iov[i].iov_base = np->seg; - len += iov[i].iov_len = np->sz; - - /* - * XXX One can envision setting specific extension fields, like - * *_reserved ones here. For now we require them to be set by the - * caller. - */ - - np = TAILQ_NEXT(np, link); - } - msg->sadb_msg_len = len / PF_KEY_V2_CHUNK; - - for (i = 0; i < cnt; i++) { - snprintf(header, sizeof header, "pf_key_v2_write: iov[%d]", i); - LOG_DBG_BUF((LOG_SYSDEP, 80, header, - (u_int8_t *) iov[i].iov_base, iov[i].iov_len)); - } - - n = writev(pf_key_v4_socket, iov, cnt); - if (n == -1) { - log_error("pf_key_v2_write: writev (%d, %p, %d) failed", - pf_key_v2_socket, iov, cnt); - goto cleanup; - } - if ((size_t) n != len) { - log_error("pf_key_v2_write: " - "writev (%d, ...) returned prematurely (%lu)", - pf_key_v2_socket, (unsigned long) n); - goto cleanup; - } - free(iov); - return msg->sadb_msg_seq; - -cleanup: - if (iov) - free(iov); - return 0; -} - -/* - * Do a PF_KEY "call", i.e. write a message MSG, read the reply and return - * it to the caller. - */ -static struct pf_key_v2_msg * -pf_key_v2_call(struct pf_key_v2_msg *msg) -{ - u_int32_t seq; - - seq = pf_key_v2_write(msg); - if (!seq) - return 0; - return pf_key_v2_read(seq); -} - -/* Find the TYPE extension in MSG. Return zero if none found. */ -static struct pf_key_v2_node * -pf_key_v2_find_ext(struct pf_key_v2_msg *msg, u_int16_t type) -{ - struct pf_key_v2_node *ext; - - for (ext = TAILQ_NEXT(TAILQ_FIRST(msg), link); ext; - ext = TAILQ_NEXT(ext, link)) - if (ext->type == type) - return ext; - return 0; -} - -/* - * Open the PF_KEYv2 sockets and return the descriptor used for notifies. - * Return -1 for failure and -2 if no notifies will show up. - */ -int -pf_key_v2_open(void) -{ - int fd = -1, err; - struct sadb_msg msg; - struct pf_key_v2_msg *regmsg = 0, *ret = 0; - struct sockaddr_un addr; - socklen_t addrLength = sizeof(addr); - - /* Open the socket we use to speak to IPsec. */ - pf_key_v2_socket = -1; - - fd = socket(PF_UNIX, SOCK_RAW, 0); - - if (fd == -1) { - log_error("pf_key_v2_open: " - "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed"); - goto cleanup; - } - - memset(&addr, 0, sizeof(struct sockaddr_un)); - /* Clear structure */ - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, PF_KEY_V2_SOCK_PATH, - sizeof(addr.sun_path) - 1); - - if (connect(fd, (struct sockaddr *) &addr, - sizeof(struct sockaddr_un)) == -1) { - perror("bind"); - exit(EXIT_FAILURE); - } - - - pf_key_v2_socket = fd; - - /* Register it to get ESP and AH acquires from the kernel. */ - msg.sadb_msg_seq = 0; - msg.sadb_msg_type = SADB_REGISTER; - msg.sadb_msg_satype = SADB_SATYPE_ESP; - regmsg = pf_key_v2_msg_new(&msg, 0); - if (!regmsg) - goto cleanup; - ret = pf_key_v2_call(regmsg); - pf_key_v2_msg_free(regmsg); - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); - goto cleanup; - } - /* XXX Register the accepted transforms. */ - - pf_key_v2_msg_free(ret); - ret = 0; - - msg.sadb_msg_seq = 0; - msg.sadb_msg_type = SADB_REGISTER; - msg.sadb_msg_satype = SADB_SATYPE_AH; - regmsg = pf_key_v2_msg_new(&msg, 0); - if (!regmsg) - goto cleanup; - ret = pf_key_v2_call(regmsg); - pf_key_v2_msg_free(regmsg); - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); - goto cleanup; - } - /* XXX Register the accepted transforms. */ - - pf_key_v2_msg_free(ret); - ret = 0; - -#ifdef SADB_X_SATYPE_IPCOMP - msg.sadb_msg_seq = 0; - msg.sadb_msg_type = SADB_REGISTER; - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - regmsg = pf_key_v2_msg_new(&msg, 0); - if (!regmsg) - goto cleanup; - ret = pf_key_v2_call(regmsg); - pf_key_v2_msg_free(regmsg); - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); - goto cleanup; - } - /* XXX Register the accepted transforms. */ - - pf_key_v2_msg_free(ret); -#endif /* SADB_X_SATYPE_IPCOMP */ - -#ifdef KAME - TAILQ_INIT(&pf_key_v2_sa_seq_map); -#endif - - return fd; - -cleanup: - if (pf_key_v2_socket != -1) { - close(pf_key_v2_socket); - pf_key_v2_socket = -1; - } - if (ret) - pf_key_v2_msg_free(ret); - return -1; -} - -/* - * Generate a SPI for protocol PROTO and the source/destination pair given by - * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. - */ -u_int8_t * -pf_key_v2_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src, - struct sockaddr *dst, u_int32_t seq) -{ - struct sadb_msg msg; - struct sadb_sa *sa; - struct sadb_address *addr = 0; - struct sadb_spirange spirange; - struct pf_key_v2_msg *getspi = 0, *ret = 0; - struct pf_key_v2_node *ext; - u_int8_t *spi = 0; - int len, err; -#ifdef KAME - struct sadb_x_sa2 ssa2; -#endif - - msg.sadb_msg_type = SADB_GETSPI; - switch (proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - break; -#ifdef SADB_X_SATYPE_IPCOMP - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - log_print("pf_key_v2_get_spi: invalid proto %d", proto); - goto cleanup; - } - - /* Set the sequence number from the ACQUIRE message. */ - msg.sadb_msg_seq = seq; - getspi = pf_key_v2_msg_new(&msg, 0); - if (!getspi) - goto cleanup; - -#ifdef KAME - memset(&ssa2, 0, sizeof ssa2); - ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; - ssa2.sadb_x_sa2_mode = 0; - if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&ssa2, 0) == -1) - goto cleanup; -#endif - - /* Setup the ADDRESS extensions. */ - len = - sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(src)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, src, sysdep_sa_len(src)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - len = - sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, dst, sysdep_sa_len(dst)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - /* Setup the SPIRANGE extension. */ - spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; - spirange.sadb_spirange_len = sizeof spirange / PF_KEY_V2_CHUNK; - if (proto == IPSEC_PROTO_IPCOMP) { - spirange.sadb_spirange_min = CPI_RESERVED_MAX + 1; - spirange.sadb_spirange_max = CPI_PRIVATE_MIN - 1; - } else { - spirange.sadb_spirange_min = IPSEC_SPI_LOW; - spirange.sadb_spirange_max = 0xffffffff; - } - spirange.sadb_spirange_reserved = 0; - if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&spirange, 0) == -1) - goto cleanup; - - ret = pf_key_v2_call(getspi); - pf_key_v2_msg_free(getspi); - getspi = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_get_spi: GETSPI: %s", strerror(err)); - goto cleanup; - } - ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); - if (!ext) { - log_print("pf_key_v2_get_spi: no SA extension found"); - goto cleanup; - } - sa = ext->seg; - - /* IPCOMP CPIs are only 16 bits long. */ - *sz = (proto == IPSEC_PROTO_IPCOMP) ? sizeof(u_int16_t) - : sizeof sa->sadb_sa_spi; - spi = malloc(*sz); - if (!spi) - goto cleanup; - /* XXX This is ugly. */ - if (proto == IPSEC_PROTO_IPCOMP) { - u_int32_t tspi = ntohl(sa->sadb_sa_spi); - *(u_int16_t *) spi = htons((u_int16_t) tspi); - } else - memcpy(spi, &sa->sadb_sa_spi, *sz); - -#ifdef KAME - if (!pf_key_v2_register_sa_seq(spi, *sz, proto, dst, - sysdep_sa_len(dst), - ((struct sadb_msg *) (TAILQ_FIRST(ret)->seg))->sadb_msg_seq)) - goto cleanup; -#endif - pf_key_v2_msg_free(ret); - - LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_spi: spi", spi, *sz)); - return spi; - -cleanup: - if (spi) - free(spi); - if (addr) - free(addr); - if (getspi) - pf_key_v2_msg_free(getspi); - if (ret) - pf_key_v2_msg_free(ret); - return 0; -} - -/* Fetch SA information from the kernel. XXX OpenBSD only? */ -struct sa_kinfo * -pf_key_v2_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, - struct sockaddr *dst) -{ - struct sadb_msg msg; - struct sadb_sa *ssa; - struct sadb_address *addr = 0; - struct sockaddr *sa; - struct sadb_lifetime *life; - struct pf_key_v2_msg *gettdb = 0, *ret = 0; - struct pf_key_v2_node *ext; - static struct sa_kinfo ksa; -#if defined (SADB_X_EXT_UDPENCAP) - struct sadb_x_udpencap *udpencap; -#endif - int len, err; - - if (spi_sz != sizeof (ssa->sadb_sa_spi)) - return 0; - - msg.sadb_msg_type = SADB_GET; - switch (proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - break; -#ifdef SADB_X_SATYPE_IPCOMP - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - log_print("pf_key_v2_get_kernel_sa: invalid proto %d", proto); - goto cleanup; - } - - gettdb = pf_key_v2_msg_new(&msg, 0); - if (!gettdb) - goto cleanup; - - /* SPI */ - ssa = (struct sadb_sa *)calloc(1, sizeof *ssa); - if (!ssa) { - log_print("pf_key_v2_get_kernel_sa: calloc(1, %lu) failed", - (unsigned long)sizeof *ssa); - goto cleanup; - } - - ssa->sadb_sa_exttype = SADB_EXT_SA; - ssa->sadb_sa_len = sizeof *ssa / PF_KEY_V2_CHUNK; - memcpy(&ssa->sadb_sa_spi, spi, sizeof ssa->sadb_sa_spi); - ssa->sadb_sa_state = SADB_SASTATE_MATURE; - if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)ssa, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - ssa = 0; - - /* XXX KAME SADB_X_EXT_xyz here? */ - - /* Address */ - len = - sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, dst, sysdep_sa_len(dst)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - ret = pf_key_v2_call(gettdb); - pf_key_v2_msg_free(gettdb); - gettdb = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_get_kernel_sa: SADB_GET: %s", - strerror(err)); - goto cleanup; - } - - /* Extract the data. */ - memset(&ksa, 0, sizeof ksa); - - ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); - if (!ext) - goto cleanup; - - ssa = (struct sadb_sa *)ext; - ksa.spi = ssa->sadb_sa_spi; - ksa.wnd = ssa->sadb_sa_replay; - ksa.flags = ssa->sadb_sa_flags; - - ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_CURRENT); - if (ext) { - life = (struct sadb_lifetime *)ext->seg; - ksa.cur_allocations = life->sadb_lifetime_allocations; - ksa.cur_bytes = life->sadb_lifetime_bytes; - ksa.first_use = life->sadb_lifetime_usetime; - ksa.established = life->sadb_lifetime_addtime; - } - - ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_SOFT); - if (ext) { - life = (struct sadb_lifetime *)ext->seg; - ksa.soft_allocations = life->sadb_lifetime_allocations; - ksa.soft_bytes = life->sadb_lifetime_bytes; - ksa.soft_timeout = life->sadb_lifetime_addtime; - ksa.soft_first_use = life->sadb_lifetime_usetime; - } - - ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_HARD); - if (ext) { - life = (struct sadb_lifetime *)ext->seg; - ksa.exp_allocations = life->sadb_lifetime_allocations; - ksa.exp_bytes = life->sadb_lifetime_bytes; - ksa.exp_timeout = life->sadb_lifetime_addtime; - ksa.exp_first_use = life->sadb_lifetime_usetime; - } - -#if defined (SADB_X_EXT_LIFETIME_LASTUSE) - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_LIFETIME_LASTUSE); - if (ext) { - life = (struct sadb_lifetime *)ext->seg; - ksa.last_used = life->sadb_lifetime_usetime; - } -#endif - - ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_SRC); - if (ext) { - sa = (struct sockaddr *)ext->seg; - memcpy(&ksa.src, sa, - sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)); - } - - ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_DST); - if (ext) { - sa = (struct sockaddr *)ext->seg; - memcpy(&ksa.dst, sa, - sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)); - } - - ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_PROXY); - if (ext) { - sa = (struct sockaddr *)ext->seg; - memcpy(sa, &ksa.proxy, - sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6)); - } - -#if defined (SADB_X_EXT_UDPENCAP) - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_UDPENCAP); - if (ext) { - udpencap = (struct sadb_x_udpencap *)ext->seg; - ksa.udpencap_port = udpencap->sadb_x_udpencap_port; - } -#endif - - pf_key_v2_msg_free(ret); - - LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_kernel_sa: spi", spi, - spi_sz)); - - return &ksa; - - cleanup: - if (addr) - free (addr); - if (gettdb) - pf_key_v2_msg_free(gettdb); - if (ret) - pf_key_v2_msg_free(ret); - return 0; -} - -static void -pf_key_v2_setup_sockaddr(void *res, struct sockaddr *src, - struct sockaddr *dst, in_port_t port, int ingress) -{ - struct sockaddr_in *ip4_sa; - struct sockaddr_in6 *ip6_sa; - u_int8_t *p; - - switch (src->sa_family) { - case AF_INET: - ip4_sa = (struct sockaddr_in *) res; - ip4_sa->sin_family = AF_INET; -#ifndef USE_OLD_SOCKADDR - ip4_sa->sin_len = sizeof *ip4_sa; -#endif - ip4_sa->sin_port = port; - if (dst) - p = (u_int8_t *) (ingress ? - &((struct sockaddr_in *)src)->sin_addr.s_addr : - &((struct sockaddr_in *)dst)->sin_addr.s_addr); - else - p = (u_int8_t *)&((struct sockaddr_in *)src)->sin_addr.s_addr; - ip4_sa->sin_addr.s_addr = *((in_addr_t *) p); - break; - - case AF_INET6: - ip6_sa = (struct sockaddr_in6 *) res; - ip6_sa->sin6_family = AF_INET6; -#ifndef USE_OLD_SOCKADDR - ip6_sa->sin6_len = sizeof *ip6_sa; -#endif - ip6_sa->sin6_port = port; - if (dst) - p = (u_int8_t *) (ingress ? - &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr : - &((struct sockaddr_in6 *)dst)->sin6_addr.s6_addr); - else - p = (u_int8_t *)&((struct sockaddr_in6 *)src)->sin6_addr.s6_addr; - memcpy(ip6_sa->sin6_addr.s6_addr, p, sizeof(struct in6_addr)); - break; - - default: - log_print("pf_key_v2_setup_sockaddr: unknown family %d\n", - src->sa_family); - break; - } -} - -/* - * Store/update a PF_KEY_V2 security association with full information from the - * IKE SA and PROTO into the kernel. INCOMING is set if we are setting the - * parameters for the incoming SA, and cleared otherwise. - */ -int -pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming, - struct sa *isakmp_sa) -{ - struct sadb_msg msg; - struct sadb_sa ssa; - struct sadb_lifetime *life = 0; - struct sadb_address *addr = 0; - struct sadb_key *key = 0; - struct sadb_ident *sid = 0; - struct sockaddr *src, *dst; - struct pf_key_v2_msg *update = 0, *ret = 0; - struct ipsec_proto *iproto = proto->data; - size_t len; - int keylen, hashlen, err; -#ifndef KAME - u_int8_t *pp; - int idtype; -#else /* KAME */ - struct sadb_x_sa2 ssa2; -#endif -#if defined (SADB_X_CREDTYPE_NONE) || defined (SADB_X_AUTHTYPE_NONE) - struct ipsec_sa *isa = sa->data; - struct sadb_x_cred *cred; - struct sadb_protocol flowtype, tprotocol; -#endif -#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) - struct sadb_x_udpencap udpencap; -#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE) - struct sadb_x_nat_t_type nat_t_type; - struct sadb_x_nat_t_port nat_t_sport; - struct sadb_x_nat_t_port nat_t_dport; -#endif -#ifdef USE_DEBUG - char *addr_str; -#endif - - msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD; - switch (proto->proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - keylen = ipsec_esp_enckeylength(proto); - hashlen = ipsec_esp_authkeylength(proto); - - switch (proto->id) { - case IPSEC_ESP_DES: - case IPSEC_ESP_DES_IV32: - case IPSEC_ESP_DES_IV64: - ssa.sadb_sa_encrypt = SADB_EALG_DESCBC; - break; - - case IPSEC_ESP_3DES: - ssa.sadb_sa_encrypt = SADB_EALG_3DESCBC; - break; - -#ifdef SADB_X_EALG_AES - case IPSEC_ESP_AES: - /* case IPSEC_ESP_AES_128_CTR: */ - ssa.sadb_sa_encrypt = SADB_X_EALG_AES; - break; -#endif - -#ifdef SADB_X_EALG_CAST - case IPSEC_ESP_CAST: - ssa.sadb_sa_encrypt = SADB_X_EALG_CAST; - break; -#endif - -#ifdef SADB_X_EALG_BLF - case IPSEC_ESP_BLOWFISH: - ssa.sadb_sa_encrypt = SADB_X_EALG_BLF; - break; -#endif - - default: - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " - "unknown encryption algorithm %d", proto->id)); - return -1; - } - - switch (iproto->auth) { - case IPSEC_AUTH_HMAC_MD5: -#ifdef SADB_AALG_MD5HMAC96 - ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; -#else - ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; -#endif - break; - - case IPSEC_AUTH_HMAC_SHA: -#ifdef SADB_AALG_SHA1HMAC96 - ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; -#else - ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; -#endif - break; - -#ifndef KAME - case IPSEC_AUTH_HMAC_RIPEMD: -#ifdef SADB_X_AALG_RIPEMD160HMAC96 - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; -#elif defined (SADB_X_AALG_RIPEMD160HMAC) - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; -#elif defined (SADB_X_AALG_RIPEMD160) - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; -#else - ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; -#endif - break; -#endif - -#ifdef SADB_X_AALG_SHA2_256 - case IPSEC_AUTH_HMAC_SHA2_256: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; - break; -#endif - -#ifdef SADB_X_AALG_SHA2_384 - case IPSEC_AUTH_HMAC_SHA2_384: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; - break; -#endif - -#ifdef SADB_X_AALG_SHA2_512 - case IPSEC_AUTH_HMAC_SHA2_512: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; - break; -#endif - - case IPSEC_AUTH_DES_MAC: - case IPSEC_AUTH_KPDK: - /* XXX We should be supporting KPDK */ - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " - "unknown authentication algorithm %d", - iproto->auth)); - return -1; - - default: - ssa.sadb_sa_auth = SADB_AALG_NONE; - } - break; - - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - hashlen = ipsec_ah_keylength(proto); - keylen = 0; - - ssa.sadb_sa_encrypt = SADB_EALG_NONE; - switch (proto->id) { - case IPSEC_AH_MD5: -#ifdef SADB_AALG_MD5HMAC96 - ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; -#else - ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; -#endif - break; - - case IPSEC_AH_SHA: -#ifdef SADB_AALG_SHA1HMAC96 - ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; -#else - ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; -#endif - break; - -#ifndef KAME - case IPSEC_AH_RIPEMD: -#ifdef SADB_X_AALG_RIPEMD160HMAC96 - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; -#elif defined (SADB_X_AALG_RIPEMD160HMAC) - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; -#elif defined (SADB_X_AALG_RIPEMD160) - ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; -#else - ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; -#endif - break; -#endif - -#ifdef SADB_X_AALG_SHA2_256 - case IPSEC_AH_SHA2_256: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; - break; -#endif - -#ifdef SADB_X_AALG_SHA2_384 - case IPSEC_AH_SHA2_384: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; - break; -#endif - -#ifdef SADB_X_AALG_SHA2_512 - case IPSEC_AH_SHA2_512: - ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; - break; -#endif - - default: - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " - "unknown authentication algorithm %d", proto->id)); - goto cleanup; - } - break; - -#ifdef SADB_X_SATYPE_IPCOMP - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - ssa.sadb_sa_auth = SADB_AALG_NONE; - keylen = 0; - hashlen = 0; - - /* - * Put compression algorithm type in the sadb_sa_encrypt - * field. - */ - switch (proto->id) { -#ifdef SADB_X_CALG_OUI - case IPSEC_IPCOMP_OUI: - ssa.sadb_sa_encrypt = SADB_X_CALG_OUI; - break; -#endif - -#ifdef SADB_X_CALG_DEFLATE - case IPSEC_IPCOMP_DEFLATE: - ssa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; - break; -#endif - -#ifdef SADB_X_CALG_LZS - case IPSEC_IPCOMP_LZS: - ssa.sadb_sa_encrypt = SADB_X_CALG_LZS; - break; -#endif - -#ifdef SADB_X_CALG_V42BIS - case IPSEC_IPCOMP_V42BIS: - ssa.sadb_sa_encrypt = SADB_X_CALG_V42BIS; - break; -#endif - - default: - break; - } - break; -#endif /* SADB_X_SATYPE_IPCOMP */ - - default: - log_print("pf_key_v2_set_spi: invalid proto %d", proto->proto); - goto cleanup; - } - if (incoming) { - sa->transport->vtbl->get_src(sa->transport, &dst); - sa->transport->vtbl->get_dst(sa->transport, &src); - } - else { - sa->transport->vtbl->get_dst(sa->transport, &dst); - sa->transport->vtbl->get_src(sa->transport, &src); - } - -#ifdef KAME - msg.sadb_msg_seq = (incoming ? - pf_key_v2_seq_by_sa(proto->spi[incoming], sizeof ssa.sadb_sa_spi, - proto->proto, dst, sysdep_sa_len(dst)) : 0); -#else - msg.sadb_msg_seq = sa->seq; -#endif - update = pf_key_v2_msg_new(&msg, 0); - if (!update) - goto cleanup; - -#ifdef KAME - memset(&ssa2, 0, sizeof ssa2); - ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; -#if defined (LINUX_IPSEC) - if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) - ssa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; - else - ssa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; -#else - ssa2.sadb_x_sa2_mode = 0; -#endif - if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa2, 0) == -1) - goto cleanup; -#endif - - /* Setup the rest of the SA extension. */ - ssa.sadb_sa_exttype = SADB_EXT_SA; - ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; - if (proto->spi_sz[incoming] == 2) /* IPCOMP uses 16bit CPIs. */ - ssa.sadb_sa_spi = htonl(proto->spi[incoming][0] << 8 | - proto->spi[incoming][1]); - else - memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], - sizeof ssa.sadb_sa_spi); - ssa.sadb_sa_replay = conf_get_str("General", "Shared-SADB") ? 0 : - iproto->replay_window; - ssa.sadb_sa_state = SADB_SASTATE_MATURE; - ssa.sadb_sa_flags = 0; -#ifdef SADB_X_SAFLAGS_TUNNEL - if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL || - iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL || - iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT) - ssa.sadb_sa_flags = SADB_X_SAFLAGS_TUNNEL; -#endif - - if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) { -#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) - memset(&udpencap, 0, sizeof udpencap); - ssa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; - udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; - udpencap.sadb_x_udpencap_len = - sizeof udpencap / PF_KEY_V2_CHUNK; - udpencap.sadb_x_udpencap_port = sockaddr_port(dst); - if (pf_key_v2_msg_add(update, (struct sadb_ext *)&udpencap, 0) - == -1) - goto cleanup; -#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE) -#ifndef UDP_ENCAP_ESPINUDP -#define UDP_ENCAP_ESPINUDP 2 -#endif - memset(&nat_t_type, 0, sizeof nat_t_type); - memset(&nat_t_sport, 0, sizeof nat_t_sport); - memset(&nat_t_dport, 0, sizeof nat_t_dport); - - /* type = draft-udp-encap-06 */ - nat_t_type.sadb_x_nat_t_type_len = sizeof nat_t_type / PF_KEY_V2_CHUNK; - nat_t_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; - nat_t_type.sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP; - if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_type, 0) == -1) - goto cleanup; - - /* source port */ - nat_t_sport.sadb_x_nat_t_port_len = sizeof nat_t_sport / - PF_KEY_V2_CHUNK; - nat_t_sport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; - nat_t_sport.sadb_x_nat_t_port_port = sockaddr_port(src); - if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_sport, 0) == -1) - goto cleanup; - - /* destination port */ - nat_t_dport.sadb_x_nat_t_port_len = sizeof nat_t_dport / - PF_KEY_V2_CHUNK; - nat_t_dport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; - nat_t_dport.sadb_x_nat_t_port_port = sockaddr_port(dst); - if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_dport, 0) == -1) - goto cleanup; - - /* original address (transport mode checksum missing info) goes here */ -#endif - } - - if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa, 0) == -1) - goto cleanup; - - if (sa->seconds || sa->kilobytes) { - /* Setup the hard limits. */ - life = malloc(sizeof *life); - if (!life) - goto cleanup; - life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; - life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; - life->sadb_lifetime_allocations = 0; - life->sadb_lifetime_bytes = sa->kilobytes * 1024; - /* - * XXX I am not sure which one is best in security respect. - * Maybe the RFCs actually mandate what a lifetime really is. - */ -#if 0 - life->sadb_lifetime_addtime = 0; - life->sadb_lifetime_usetime = sa->seconds; -#else - life->sadb_lifetime_addtime = sa->seconds; - life->sadb_lifetime_usetime = 0; -#endif - if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - life = 0; - - /* - * Setup the soft limits, we use 90 % of the hard ones. - * XXX A configurable ratio would be better. - */ - life = malloc(sizeof *life); - if (!life) - goto cleanup; - life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; - life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; - life->sadb_lifetime_allocations = 0; - life->sadb_lifetime_bytes = sa->kilobytes * 1024 * 9 / 10; - /* - * XXX I am not sure which one is best in security respect. - * Maybe the RFCs actually mandate what a lifetime really is. - */ -#if 0 - life->sadb_lifetime_addtime = 0; - life->sadb_lifetime_usetime = sa->seconds * 9 / 10; -#else - life->sadb_lifetime_addtime = sa->seconds * 9 / 10; - life->sadb_lifetime_usetime = 0; -#endif - if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - life = 0; - } - /* - * Setup the ADDRESS extensions. - */ - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, src, sysdep_sa_len(src)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, dst, sysdep_sa_len(dst)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - -#if 0 - /* XXX I am not sure about what to do here just yet. */ - if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) { - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, dst, sysdep_sa_len(dst)); - switch (((struct sockaddr *) (addr + 1))->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; -#if 0 - msg->em_odst = msg->em_dst; - msg->em_osrc = msg->em_src; -#endif - } -#endif - - if (proto->proto != IPSEC_PROTO_IPCOMP) { - /* Setup the KEY extensions. */ - if (hashlen) { - len = sizeof *key + PF_KEY_V2_ROUND(hashlen); - key = malloc(len); - if (!key) - goto cleanup; - key->sadb_key_exttype = SADB_EXT_KEY_AUTH; - key->sadb_key_len = len / PF_KEY_V2_CHUNK; - key->sadb_key_bits = hashlen * 8; - key->sadb_key_reserved = 0; - memcpy(key + 1, - iproto->keymat[incoming] + - (proto->proto == - IPSEC_PROTO_IPSEC_ESP ? keylen : 0), - hashlen); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - key = 0; - } - if (keylen) { - len = sizeof *key + PF_KEY_V2_ROUND(keylen); - key = malloc(len); - if (!key) - goto cleanup; - key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; - key->sadb_key_len = len / PF_KEY_V2_CHUNK; - key->sadb_key_bits = keylen * 8; - key->sadb_key_reserved = 0; - memcpy(key + 1, iproto->keymat[incoming], keylen); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - key = 0; - } - } -#ifndef KAME - /* Setup identity extensions. */ - if (isakmp_sa->id_i) { - pp = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len, - &len, &idtype); - if (!pp) - goto nosid; - - sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, - sizeof(u_int8_t)); - if (!sid) { - free(pp); - goto cleanup; - } - sid->sadb_ident_type = idtype; - sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + - PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; - if ((isakmp_sa->initiator && !incoming) || - (!isakmp_sa->initiator && incoming)) - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; - else - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; - - memcpy(sid + 1, pp, len); - free(pp); - - if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - sid = 0; - -nosid: - if (sid) - free(sid); - sid = 0; - } - if (isakmp_sa->id_r) { - pp = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len, - &len, &idtype); - if (!pp) - goto nodid; - - sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, - sizeof(u_int8_t)); - if (!sid) { - free(pp); - goto cleanup; - } - sid->sadb_ident_type = idtype; - sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + - PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; - if ((isakmp_sa->initiator && !incoming) || - (!isakmp_sa->initiator && incoming)) - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; - else - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; - - memcpy(sid + 1, pp, len); - free(pp); - - if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - sid = 0; - -nodid: - if (sid) - free(sid); - sid = 0; - } -#endif /* KAME */ - -#ifdef SADB_X_CREDTYPE_NONE - /* - * Send received credentials to the kernel. We don't bother with - * our credentials, since the process either knows them (if it - * specified them with setsockopt()), or has no business looking at - * them (e.g., system wide certs). - */ - if (isakmp_sa->recv_cert) { - switch (isakmp_sa->recv_certtype) { - case ISAKMP_CERTENC_NONE: - /* Nothing to be done here. */ - break; - -#if defined (USE_KEYNOTE) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) - case ISAKMP_CERTENC_KEYNOTE: - len = strlen(isakmp_sa->recv_cert); - cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, - sizeof(u_int8_t)); - if (!cred) - goto cleanup; - - cred->sadb_x_cred_len = - ((sizeof *cred) / PF_KEY_V2_CHUNK) + - PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; - cred->sadb_x_cred_exttype = - SADB_X_EXT_REMOTE_CREDENTIALS; - cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE; - memcpy(cred + 1, isakmp_sa->recv_cert, len); - - if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - break; -#endif /* USE_KEYNOTE */ - -#if defined (USE_X509) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) - case ISAKMP_CERTENC_X509_SIG: - { - u_int8_t *data; - u_int32_t datalen; - struct cert_handler *handler; - - /* We do it this way to avoid weird includes.*/ - handler = cert_get(ISAKMP_CERTENC_X509_SIG); - if (!handler) - break; - handler->cert_serialize(isakmp_sa->recv_cert, - &data, &datalen); - if (!data) - break; - - len = datalen; - cred = - calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, - sizeof(u_int8_t)); - if (!cred) { - free(data); - goto cleanup; - } - cred->sadb_x_cred_len = - ((sizeof *cred) / PF_KEY_V2_CHUNK) + - PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; - cred->sadb_x_cred_exttype = - SADB_X_EXT_REMOTE_CREDENTIALS; - cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509; - memcpy(cred + 1, data, len); - free(data); - - if (pf_key_v2_msg_add(update, - (struct sadb_ext *) cred, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - } - break; -#endif /* USE_X509 */ - } - } -#endif /* SADB_X_CREDTYPE_NONE */ - -#ifdef SADB_X_AUTHTYPE_NONE - /* - * Tell the kernel what the peer used to authenticate, unless it was a - * passphrase. - */ - if (isakmp_sa->recv_key) { - u_int8_t *data; - - /* - * If it's a private key, we shouldn't pass it to the kernel - * for processes to see; successful authentication of Phase 1 - * implies that the process already knew the passphrase. On - * the other hand, we don't want to reveal to processes any - * system-wide passphrases used for authentication with remote - * systems. Same reason we don't send up the key (private or - * passphrase) we used to authenticate with the peer. - */ - if (isakmp_sa->recv_keytype == ISAKMP_KEY_PASSPHRASE) - goto doneauth; - - key_serialize(isakmp_sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, - isakmp_sa->recv_key, &data, &len); - if (!data) - goto cleanup; - - cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, - sizeof(u_int8_t)); - if (!cred) { - free(data); - goto cleanup; - } - cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) + - PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; - cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_AUTH; - memcpy(cred + 1, data, len); - free(data); - - switch (isakmp_sa->recv_keytype) { - case ISAKMP_KEY_RSA: - cred->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA; - break; - - default: - log_print("pf_key_v2_set_spi: " - "unknown received key type %d", - isakmp_sa->recv_keytype); - free(cred); - goto cleanup; - } - - if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - } -doneauth: -#endif /* SADB_X_AUTHTYPE_NONE */ - -#ifdef SADB_X_EXT_FLOW_TYPE - /* Setup the flow type extension. */ - bzero(&flowtype, sizeof flowtype); - flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; - flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; - flowtype.sadb_protocol_direction = incoming ? - IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; - - if (pf_key_v2_msg_add(update, (struct sadb_ext *)&flowtype, 0) == -1) - goto cleanup; - - bzero(&tprotocol, sizeof tprotocol); - tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; - tprotocol.sadb_protocol_proto = isa->tproto; - - if (pf_key_v2_msg_add(update, (struct sadb_ext *)&tprotocol, - 0) == -1) - goto cleanup; - - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(isa->src_net)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = incoming ? - SADB_X_EXT_DST_FLOW : SADB_X_EXT_SRC_FLOW; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, isa->src_net, 0, isa->sport, 0); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = - incoming ? SADB_X_EXT_DST_MASK : SADB_X_EXT_SRC_MASK; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, isa->src_mask, 0, - isa->sport ? 0xffff : 0, 0); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = incoming ? - SADB_X_EXT_SRC_FLOW : SADB_X_EXT_DST_FLOW; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, isa->dst_net, 0, isa->dport, 0); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = - incoming ? SADB_X_EXT_SRC_MASK : SADB_X_EXT_DST_MASK; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, isa->dst_mask, 0, - isa->dport ? 0xffff : 0, 0); - if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; -#endif /* SADB_X_EXT_FLOW_TYPE */ - - /* XXX Here can sensitivity extensions be setup. */ - -#ifdef USE_DEBUG - if (sockaddr2text(dst, &addr_str, 0)) - addr_str = 0; - - LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: " - "satype %d dst %s SPI 0x%x", msg.sadb_msg_satype, - addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi))); - - if (addr_str) - free(addr_str); -#endif /* USE_DEBUG */ - - /* - * Although PF_KEY knows about expirations, it is unreliable per the - * specs thus we need to do them inside isakmpd as well. - */ - if (sa->seconds) - if (sa_setup_expirations(sa)) - goto cleanup; - - ret = pf_key_v2_call(update); - pf_key_v2_msg_free(update); - update = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - pf_key_v2_msg_free(ret); - ret = 0; - - /* - * If we are doing an addition into an SADB shared with our peer, - * errors here are to be expected as the peer will already have - * created the SA, and can thus be ignored. - */ - if (err && !(msg.sadb_msg_type == SADB_ADD && - conf_get_str("General", "Shared-SADB"))) { - log_print("pf_key_v2_set_spi: %s: %s", - msg.sadb_msg_type == SADB_ADD ? "ADD" : "UPDATE", - strerror(err)); - goto cleanup; - } - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: done")); - - return 0; - -cleanup: - if (sid) - free(sid); - if (addr) - free(addr); - if (life) - free(life); - if (key) - free(key); - if (update) - pf_key_v2_msg_free(update); - if (ret) - pf_key_v2_msg_free(ret); - return -1; -} - -static __inline__ int -pf_key_v2_mask_to_bits(u_int32_t mask) -{ - u_int32_t hmask = ntohl(mask); - - return (33 - ffs(~hmask + 1)) % 33; -} - -static int -pf_key_v2_mask6_to_bits(u_int8_t * mask) -{ - int n; - - bit_ffc(mask, 128, &n); - return n == -1 ? 128 : n; -} - -/* - * Enable/disable a flow. - * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions. - * Should probably be moved to sysdep.c - */ -static int -pf_key_v2_flow(struct sockaddr *laddr, struct sockaddr *lmask, - struct sockaddr *raddr, struct sockaddr *rmask, - u_int8_t tproto, u_int16_t sport, u_int16_t dport, - u_int8_t *spi, u_int8_t proto, struct sockaddr *dst, - struct sockaddr *src, int delete, int ingress, - u_int8_t srcid_type, u_int8_t *srcid, int srcid_len, - u_int8_t dstid_type, u_int8_t *dstid, int dstid_len, - struct ipsec_proto *iproto) -{ -#ifdef USE_DEBUG - char *laddr_str, *lmask_str, *raddr_str, *rmask_str; -#endif - -#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW) - struct sadb_msg msg; -#if defined (SADB_X_EXT_FLOW_TYPE) - struct sadb_protocol flowtype; - struct sadb_ident *sid = 0; -#else - struct sadb_sa ssa; -#endif - struct sadb_address *addr = 0; - struct sadb_protocol tprotocol; - struct pf_key_v2_msg *flow = 0, *ret = 0; - size_t len; - int err; - -#if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE) - if (ingress) - return 0; -#endif - - msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW; - switch (proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - break; - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - break; - default: - log_print("pf_key_v2_flow: invalid proto %d", proto); - goto cleanup; - } - msg.sadb_msg_seq = 0; - flow = pf_key_v2_msg_new(&msg, 0); - if (!flow) - goto cleanup; - -#if defined (SADB_X_EXT_FLOW_TYPE) - if (!delete) { - /* Setup the source ID, if provided. */ - if (srcid) { - sid = calloc( - PF_KEY_V2_ROUND(srcid_len + 1) + sizeof *sid, - sizeof(u_int8_t)); - if (!sid) - goto cleanup; - - sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) - + PF_KEY_V2_ROUND(srcid_len + 1) / PF_KEY_V2_CHUNK; - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; - sid->sadb_ident_type = srcid_type; - - memcpy(sid + 1, srcid, srcid_len); - - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - - sid = 0; - } - /* Setup the destination ID, if provided. */ - if (dstid) { - sid = calloc( - PF_KEY_V2_ROUND(dstid_len + 1) + sizeof *sid, - sizeof(u_int8_t)); - if (!sid) - goto cleanup; - - sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) - + PF_KEY_V2_ROUND(dstid_len + 1) / PF_KEY_V2_CHUNK; - sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; - sid->sadb_ident_type = dstid_type; - - memcpy(sid + 1, dstid, dstid_len); - - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - - sid = 0; - } - } - /* Setup the flow type extension. */ - bzero(&flowtype, sizeof flowtype); - flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; - flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; - flowtype.sadb_protocol_direction = - ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; - flowtype.sadb_protocol_proto = - ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE; - - if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&flowtype, 0) == -1) - goto cleanup; -#else /* SADB_X_EXT_FLOW_TYPE */ - /* Setup the SA extension. */ - ssa.sadb_sa_exttype = SADB_EXT_SA; - ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; - memcpy(&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi); - ssa.sadb_sa_replay = 0; - ssa.sadb_sa_state = 0; - ssa.sadb_sa_auth = 0; - ssa.sadb_sa_encrypt = 0; - ssa.sadb_sa_flags = 0; -#if defined (SADB_X_SAFLAGS_INGRESS_FLOW) - if (ingress) - ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW; -#endif -#if defined (SADB_X_SAFLAGS_REPLACEFLOW) - if (!delete && !ingress) - ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW; -#endif - - if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa, 0) == -1) - goto cleanup; -#endif /* SADB_X_EXT_FLOW_TYPE */ - - /* - * Setup the ADDRESS extensions. - */ - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); -#if !defined (SADB_X_EXT_FLOW_TYPE) - if (!delete || ingress) -#else - if (!delete) -#endif /* SADB_X_EXT_FLOW_TYPE */ - { - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; -#if defined (SADB_X_EXT_FLOW_TYPE) - pf_key_v2_setup_sockaddr(addr + 1, src, dst, 0, ingress); -#else - pf_key_v2_setup_sockaddr(addr + 1, dst, 0, 0, 0); -#endif - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - } - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(laddr)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, lmask, 0, sport ? 0xffff : 0, 0); - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_X_EXT_DST_MASK; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; - addr->sadb_address_reserved = 0; - pf_key_v2_setup_sockaddr(addr + 1, rmask, 0, dport ? 0xffff : 0, 0); - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - /* Setup the protocol extension. */ - bzero(&tprotocol, sizeof tprotocol); - tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; - tprotocol.sadb_protocol_proto = tproto; - - if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&tprotocol, 0) == -1) - goto cleanup; - -#ifdef USE_DEBUG - if (sockaddr2text(laddr, &laddr_str, 0)) - laddr_str = 0; - if (sockaddr2text(lmask, &lmask_str, 0)) - lmask_str = 0; - if (sockaddr2text(raddr, &raddr_str, 0)) - raddr_str = 0; - if (sockaddr2text(rmask, &rmask_str, 0)) - rmask_str = 0; - - LOG_DBG((LOG_SYSDEP, 50, - "pf_key_v2_flow: src %s %s dst %s %s proto %u sport %u dport %u", - laddr_str ? laddr_str : "", lmask_str ? lmask_str : "", - raddr_str ? raddr_str : "", rmask_str ? rmask_str : "", - tproto, ntohs(sport), ntohs(dport))); - - if (laddr_str) - free(laddr_str); - if (lmask_str) - free(lmask_str); - if (raddr_str) - free(raddr_str); - if (rmask_str) - free(rmask_str); -#endif /* USE_DEBUG */ - - ret = pf_key_v2_call(flow); - pf_key_v2_msg_free(flow); - flow = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - if (err == ESRCH) /* These are common and usually - * harmless. */ - LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s", - delete ? "DEL" : "ADD", strerror(err))); - else - log_print("pf_key_v2_flow: %sFLOW: %s", - delete ? "DEL" : "ADD", strerror(err)); - goto cleanup; - } - pf_key_v2_msg_free(ret); - - LOG_DBG((LOG_MISC, 50, "pf_key_v2_flow: %sFLOW: done", - delete ? "DEL" : "ADD")); - - return 0; - -cleanup: -#if defined (SADB_X_EXT_FLOW_TYPE) - if (sid) - free(sid); -#endif /* SADB_X_EXT_FLOW_TYPE */ - if (addr) - free(addr); - if (flow) - pf_key_v2_msg_free(flow); - if (ret) - pf_key_v2_msg_free(ret); - return -1; - -#elif defined (SADB_X_SPDUPDATE) && defined (SADB_X_SPDDELETE) - struct sadb_msg msg; - struct sadb_x_policy *policy = 0; - struct sadb_x_ipsecrequest *ipsecrequest; - struct sadb_x_sa2 ssa2; - struct sadb_address *addr = 0; - struct sockaddr *saddr; - struct pf_key_v2_msg *flow = 0, *ret = 0; - u_int8_t *policy_buf; - size_t len; - int err; - struct sockaddr_in *ip4_sa; - struct sockaddr_in6 *ip6_sa; - - msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDUPDATE; - msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; - msg.sadb_msg_seq = 0; - flow = pf_key_v2_msg_new(&msg, 0); - if (!flow) - goto cleanup; - - memset(&ssa2, 0, sizeof ssa2); - ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; - ssa2.sadb_x_sa2_mode = 0; - if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa2, 0) == -1) - goto cleanup; - - /* - * Setup the ADDRESS extensions. - */ - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifdef LINUX_IPSEC - addr->sadb_address_proto = tproto; -#else - addr->sadb_address_proto = IPSEC_ULPROTO_ANY; -#endif - addr->sadb_address_reserved = 0; -#ifdef LINUX_IPSEC - pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); -#else - pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, IPSEC_PORT_ANY, 0); -#endif - switch (laddr->sa_family) { - case AF_INET: - ip4_sa = (struct sockaddr_in *) lmask; - addr->sadb_address_prefixlen - = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); - break; - case AF_INET6: - ip6_sa = (struct sockaddr_in6 *) lmask; - addr->sadb_address_prefixlen = - pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); - break; - } - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(raddr)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifdef LINUX_IPSEC - addr->sadb_address_proto = tproto; -#else - addr->sadb_address_proto = IPSEC_ULPROTO_ANY; -#endif - addr->sadb_address_reserved = 0; -#ifdef LINUX_IPSEC - pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); -#else - pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, IPSEC_PORT_ANY, 0); -#endif - switch (raddr->sa_family) { - case AF_INET: - ip4_sa = (struct sockaddr_in *) rmask; - addr->sadb_address_prefixlen - = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); - break; - case AF_INET6: - ip6_sa = (struct sockaddr_in6 *) rmask; - addr->sadb_address_prefixlen = - pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); - break; - } - if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - /* Setup the POLICY extension. */ - len = sizeof *policy + sizeof *ipsecrequest + - 2 * PF_KEY_V2_ROUND(sysdep_sa_len(src)); - policy_buf = (u_int8_t *) calloc(1, len); - if (!policy_buf) { - log_error("pf_key_v2_flow: calloc %lu failed", - (unsigned long) len); - goto cleanup; - } - policy = (struct sadb_x_policy *) policy_buf; - policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY; - policy->sadb_x_policy_len = len / PF_KEY_V2_CHUNK; - policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC; - if (ingress) - policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND; - else - policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; - policy->sadb_x_policy_reserved = 0; - - /* Setup the IPSECREQUEST extension part. */ - ipsecrequest = (struct sadb_x_ipsecrequest *) (policy + 1); - ipsecrequest->sadb_x_ipsecrequest_len = len - sizeof *policy; - switch (proto) { - case IPSEC_PROTO_IPSEC_ESP: - ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH; - break; - default: - log_print("pf_key_v2_flow: invalid proto %d", proto); - goto cleanup; - } -#if defined (LINUX_IPSEC) - if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) - ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; - else - ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; -#else - ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ -#endif - ipsecrequest->sadb_x_ipsecrequest_level - = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; - ipsecrequest->sadb_x_ipsecrequest_reqid = 0; /* XXX */ - - /* Add source and destination addresses. */ - saddr = (struct sockaddr *)(ipsecrequest + 1); - pf_key_v2_setup_sockaddr(saddr, src, 0, 0, 0); - switch (src->sa_family) { - case AF_INET: - saddr = (struct sockaddr *)((struct sockaddr_in *)saddr + 1); - break; - case AF_INET6: - saddr = (struct sockaddr *)((struct sockaddr_in6 *)saddr + 1); - break; - } - pf_key_v2_setup_sockaddr(saddr, dst, 0, 0, 0); - if (pf_key_v2_msg_add(flow, (struct sadb_ext *)policy, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - policy = 0; - -#ifdef USE_DEBUG - if (sockaddr2text(laddr, &laddr_str, 0)) - laddr_str = 0; - if (sockaddr2text(lmask, &lmask_str, 0)) - lmask_str = 0; - if (sockaddr2text(raddr, &raddr_str, 0)) - raddr_str = 0; - if (sockaddr2text(rmask, &rmask_str, 0)) - rmask_str = 0; - - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s", - laddr_str ? laddr_str : "", lmask_str ? lmask_str : "", - raddr_str ? raddr_str : "", - rmask_str ? rmask_str : "")); - - if (laddr_str) - free(laddr_str); - if (lmask_str) - free(lmask_str); - if (raddr_str) - free(raddr_str); - if (rmask_str) - free(rmask_str); -#endif - - ret = pf_key_v2_call(flow); - pf_key_v2_msg_free(flow); - flow = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (!delete && err == EEXIST) { - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: " - "SPDADD returns EEXIST")); - } else if (err) { - log_print("pf_key_v2_flow: SPD%s: %s", - delete ? "DELETE" : "ADD", strerror(err)); - goto cleanup; - } - pf_key_v2_msg_free(ret); - - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: SPD%s: done", - delete ? "DELETE" : "ADD")); - - return 0; - -cleanup: - if (addr) - free(addr); - if (policy) - free(policy); - if (flow) - pf_key_v2_msg_free(flow); - if (ret) - pf_key_v2_msg_free(ret); - return -1; - -#else - log_print("pf_key_v2_flow: not supported in pure PF_KEYv2"); - return -1; -#endif -} - -#ifndef KAME -static u_int8_t * -pf_key_v2_convert_id(u_int8_t * id, int idlen, size_t * reslen, int *idtype) -{ - u_int8_t *addr, *res = 0; - char addrbuf[ADDRESS_MAX + 5]; - - switch (id[0]) { - case IPSEC_ID_FQDN: - res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, - sizeof(u_int8_t)); - if (!res) - return 0; - - *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; - memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); - *idtype = SADB_IDENTTYPE_FQDN; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: FQDN %.*s", - (int) *reslen, res)); - return res; - - case IPSEC_ID_USER_FQDN: - res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, - sizeof(u_int8_t)); - if (!res) - return 0; - - *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; - memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); - *idtype = SADB_IDENTTYPE_USERFQDN; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: UFQDN %.*s", - (int) *reslen, res)); - return res; - - case IPSEC_ID_IPV4_ADDR: /* XXX CONNECTION ? */ - if (inet_ntop(AF_INET, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, - addrbuf, ADDRESS_MAX) == NULL) - return 0; - *reslen = strlen(addrbuf) + 3; - strlcat(addrbuf, "/32", ADDRESS_MAX + 5); - res = (u_int8_t *) strdup(addrbuf); - if (!res) - return 0; - *idtype = SADB_IDENTTYPE_PREFIX; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " - "IPv4 address %s", res)); - return res; - - case IPSEC_ID_IPV6_ADDR: /* XXX CONNECTION ? */ - if (inet_ntop(AF_INET6, - id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, - addrbuf, ADDRESS_MAX) == NULL) - return 0; - *reslen = strlen(addrbuf) + 4; - strlcat(addrbuf, "/128", ADDRESS_MAX + 5); - res = (u_int8_t *) strdup(addrbuf); - if (!res) - return 0; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " - "IPv6 address %s", res)); - *idtype = SADB_IDENTTYPE_PREFIX; - return res; - - case IPSEC_ID_IPV4_ADDR_SUBNET: /* XXX PREFIX */ - addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; - if (inet_ntop(AF_INET, addr, addrbuf, ADDRESS_MAX) == NULL) - return 0; - snprintf(addrbuf + strlen(addrbuf), - ADDRESS_MAX - strlen(addrbuf), "/%d", - pf_key_v2_mask_to_bits(*(u_int32_t *)(addr + - sizeof(struct in_addr)))); - *reslen = strlen(addrbuf); - res = (u_int8_t *) strdup(addrbuf); - if (!res) - return 0; - *idtype = SADB_IDENTTYPE_PREFIX; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " - "IPv4 subnet %s", res)); - return res; - - case IPSEC_ID_IPV6_ADDR_SUBNET: /* XXX PREFIX */ - addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; - if (inet_ntop(AF_INET6, addr, addrbuf, ADDRESS_MAX) == NULL) - return 0; - snprintf(addrbuf + strlen(addrbuf), - ADDRESS_MAX - strlen(addrbuf), "/%d", - pf_key_v2_mask6_to_bits(addr + - sizeof(struct in6_addr))); - *reslen = strlen(addrbuf); - res = (u_int8_t *) strdup(addrbuf); - if (!res) - return 0; - LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " - "IPv6 subnet %s", res)); - *idtype = SADB_IDENTTYPE_PREFIX; - return res; - - case IPSEC_ID_IPV4_RANGE: - case IPSEC_ID_IPV6_RANGE: - case IPSEC_ID_DER_ASN1_DN: - case IPSEC_ID_DER_ASN1_GN: - case IPSEC_ID_KEY_ID: - /* XXX Not implemented yet. */ - return 0; - } - - return 0; -} -#endif - -/* Enable a flow given an SA. */ -int -pf_key_v2_enable_sa(struct sa *sa, struct sa *isakmp_sa) -{ - struct ipsec_sa *isa = sa->data; - struct sockaddr *dst, *src; - int error; - struct proto *proto = TAILQ_FIRST(&sa->protos); - int sidtype = 0, didtype = 0; - size_t sidlen = 0, didlen = 0; - u_int8_t *sid = 0, *did = 0; -#if !defined (SADB_X_EXT_FLOW_TYPE) - struct sockaddr_storage hostmask_storage; - struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; -#endif /* SADB_X_EXT_FLOW_TYPE */ - - sa->transport->vtbl->get_dst(sa->transport, &dst); - sa->transport->vtbl->get_src(sa->transport, &src); - -#if defined (SADB_X_EXT_FLOW_TYPE) - if (isakmp_sa->id_i) { - if (isakmp_sa->initiator) - sid = pf_key_v2_convert_id(isakmp_sa->id_i, - isakmp_sa->id_i_len, &sidlen, &sidtype); - else - did = pf_key_v2_convert_id(isakmp_sa->id_i, - isakmp_sa->id_i_len, &didlen, &didtype); - } - if (isakmp_sa->id_r) { - if (isakmp_sa->initiator) - did = pf_key_v2_convert_id(isakmp_sa->id_r, - isakmp_sa->id_r_len, &didlen, &didtype); - else - sid = pf_key_v2_convert_id(isakmp_sa->id_r, - isakmp_sa->id_r_len, &sidlen, &sidtype); - } -#endif /* SADB_X_EXT_FLOW_TYPE */ - - error = pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net, - isa->dst_mask, isa->tproto, isa->sport, isa->dport, - proto->spi[0], proto->proto, dst, src, 0, 0, - sidtype, sid, sidlen, didtype, did, didlen, - proto->data); - if (error) - goto cleanup; - -#if !defined (SADB_X_EXT_FLOW_TYPE) - /* Set hostmask to '-1'. */ - switch (dst->sa_family) { - case AF_INET: - ((struct sockaddr_in *) hostmask)->sin_family = AF_INET; -#ifndef USE_OLD_SOCKADDR - ((struct sockaddr_in *) hostmask)->sin_len = - sizeof(struct in_addr); -#endif - memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, - 0xff, sizeof(struct in_addr)); - break; - case AF_INET6: - ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6; -#ifndef USE_OLD_SOCKADDR - ((struct sockaddr_in6 *) hostmask)->sin6_len = - sizeof(struct in6_addr); -#endif - memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, - 0xff, sizeof(struct in6_addr)); - break; - } - - /* Ingress flows, handling SA bundles. */ - while (TAILQ_NEXT(proto, link)) { - error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0, - proto->spi[1], proto->proto, src, dst, - 0, 1, 0, 0, 0, 0, 0, 0, proto->data); - if (error) - goto cleanup; - proto = TAILQ_NEXT(proto, link); - } -#endif /* SADB_X_EXT_FLOW_TYPE */ - - error = pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net, - isa->src_mask, isa->tproto, isa->dport, isa->sport, - proto->spi[1], proto->proto, src, dst, 0, 1, - sidtype, sid, sidlen, didtype, did, didlen, - proto->data); - -cleanup: -#if defined (SADB_X_EXT_FLOW_TYPE) - if (sid) - free(sid); - if (did) - free(did); -#endif /* SADB_X_EXT_FLOW_TYPE */ - - return error; -} - -#if defined (SADB_X_ASKPOLICY) -/* Increase reference count of refcounted sections. */ -static int -pf_key_v2_conf_refinc(int af, char *section) -{ - char conn[22]; - int num; - - if (!section) - return 0; - - num = conf_get_num(section, "Refcount", 0); - if (num == 0) - return 0; - - snprintf(conn, sizeof conn, "%d", num + 1); - conf_set(af, section, "Refcount", conn, 1, 0); - return 0; -} -#endif - -/* - * Return 0 if the section didn't exist or was removed, non-zero otherwise. - * Don't touch non-refcounted (statically defined) sections. - */ -static int -pf_key_v2_conf_refhandle(int af, char *section) -{ - char conn[22]; - int num; - - if (!section) - return 0; - - num = conf_get_num(section, "Refcount", 0); - if (num == 1) { - conf_remove_section(af, section); - num--; - } else if (num != 0) { - snprintf(conn, sizeof conn, "%d", num - 1); - conf_set(af, section, "Refcount", conn, 1, 0); - } - return num; -} - -/* Remove all dynamically-established configuration entries. */ -static int -pf_key_v2_remove_conf(char *section) -{ - char *ikepeer, *localid, *remoteid, *configname; - struct conf_list_node *attr; - struct conf_list *attrs; - int af; - - if (!section) - return 0; - - if (!conf_get_str(section, "Phase")) - return 0; - - /* Only remove dynamically-established entries. */ - attrs = conf_get_list(section, "Flags"); - if (attrs) { - for (attr = TAILQ_FIRST(&attrs->fields); attr; - attr = TAILQ_NEXT(attr, link)) - if (!strcasecmp(attr->field, "__ondemand")) - goto passed; - - conf_free_list(attrs); - } - return 0; - -passed: - conf_free_list(attrs); - - af = conf_begin(); - - configname = conf_get_str(section, "Configuration"); - conf_remove_section(af, configname); - - /* These are the Phase 2 Local/Remote IDs. */ - localid = conf_get_str(section, "Local-ID"); - pf_key_v2_conf_refhandle(af, localid); - - remoteid = conf_get_str(section, "Remote-ID"); - pf_key_v2_conf_refhandle(af, remoteid); - - ikepeer = conf_get_str(section, "ISAKMP-peer"); - - pf_key_v2_conf_refhandle(af, section); - - if (ikepeer) { - remoteid = conf_get_str(ikepeer, "Remote-ID"); - localid = conf_get_str(ikepeer, "ID"); - configname = conf_get_str(ikepeer, "Configuration"); - - pf_key_v2_conf_refhandle(af, ikepeer); - pf_key_v2_conf_refhandle(af, configname); - - /* Phase 1 IDs */ - pf_key_v2_conf_refhandle(af, localid); - pf_key_v2_conf_refhandle(af, remoteid); - } - conf_end(af, 1); - return 0; -} - -/* Disable a flow given a SA. */ -static int -pf_key_v2_disable_sa(struct sa *sa, int incoming) -{ - struct ipsec_sa *isa = sa->data; - struct sockaddr *dst, *src; - struct proto *proto = TAILQ_FIRST(&sa->protos); -#if !defined (SADB_X_EXT_FLOW_TYPE) - struct sockaddr_storage hostmask_storage; - struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; - int error; -#endif /* SADB_X_EXT_FLOW_TYPE */ - - sa->transport->vtbl->get_dst(sa->transport, &dst); - sa->transport->vtbl->get_src(sa->transport, &src); - - if (!incoming) - return pf_key_v2_flow(isa->src_net, isa->src_mask, - isa->dst_net, isa->dst_mask, isa->tproto, isa->sport, - isa->dport, proto->spi[0], proto->proto, src, dst, 1, 0, - 0, 0, 0, 0, 0, 0, proto->data); - else { -#if !defined (SADB_X_EXT_FLOW_TYPE) - /* Set hostmask to '-1'. */ - switch (dst->sa_family) { - case AF_INET: - ((struct sockaddr_in *) hostmask)->sin_family = - AF_INET; -#ifndef USE_OLD_SOCKADDR - ((struct sockaddr_in *) hostmask)->sin_len = - sizeof(struct in_addr); -#endif - memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, - 0xff, sizeof(struct in_addr)); - break; - case AF_INET6: - ((struct sockaddr_in6 *) hostmask)->sin6_family = - AF_INET6; -#ifndef USE_OLD_SOCKADDR - ((struct sockaddr_in6 *) hostmask)->sin6_len = - sizeof(struct in6_addr); -#endif - memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, - 0xff, sizeof(struct in6_addr)); - break; - } - - /* Ingress flow --- SA bundles */ - while (TAILQ_NEXT(proto, link)) { - error = pf_key_v2_flow(dst, hostmask, src, hostmask, - 0, 0, 0, proto->spi[1], proto->proto, src, dst, - 1, 1, 0, 0, 0, 0, 0, 0, proto->data); - if (error) - return error; - proto = TAILQ_NEXT(proto, link); - } -#endif /* SADB_X_EXT_FLOW_TYPE */ - - return pf_key_v2_flow(isa->dst_net, isa->dst_mask, - isa->src_net, isa->src_mask, isa->tproto, isa->dport, - isa->sport, proto->spi[1], proto->proto, src, dst, 1, 1, - 0, 0, 0, 0, 0, 0, proto->data); - } -} - -/* - * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO - * of the IKE security association SA. Also delete potential flows tied to it. - */ -int -pf_key_v2_delete_spi(struct sa *sa, struct proto *proto, int incoming) -{ - struct sadb_msg msg; - struct sadb_sa ssa; - struct sadb_address *addr = 0; - struct sockaddr *saddr; - int len, err; - struct pf_key_v2_msg *delete = 0, *ret = 0; -#ifdef KAME - struct sadb_x_sa2 ssa2; -#endif - - /* If it's not an established SA, don't proceed. */ - if (!(sa->flags & SA_FLAG_READY)) - return 0; - - /* - * If the SA was not replaced and was not one acquired through the - * kernel (ACQUIRE message), remove the flow associated with it. - * We ignore any errors from the disabling of the flow. - */ - if (!(sa->flags & SA_FLAG_REPLACED) - && !(sa->flags & SA_FLAG_ONDEMAND)) - pf_key_v2_disable_sa(sa, incoming); - - if (sa->name && !(sa->flags & SA_FLAG_REPLACED)) { - LOG_DBG((LOG_SYSDEP, 50, - "pf_key_v2_delete_spi: removing configuration %s", - sa->name)); - pf_key_v2_remove_conf(sa->name); - } - msg.sadb_msg_type = SADB_DELETE; - switch (proto->proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - break; -#if defined (SADB_X_SATYPE_IPCOMP) - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - log_print("pf_key_v2_delete_spi: invalid proto %d", - proto->proto); - goto cleanup; - } - msg.sadb_msg_seq = 0; - delete = pf_key_v2_msg_new(&msg, 0); - if (!delete) - goto cleanup; - - /* Setup the SA extension. */ - ssa.sadb_sa_exttype = SADB_EXT_SA; - ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; - memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi); - ssa.sadb_sa_replay = 0; - ssa.sadb_sa_state = 0; - ssa.sadb_sa_auth = 0; - ssa.sadb_sa_encrypt = 0; - ssa.sadb_sa_flags = 0; - if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa, 0) == -1) - goto cleanup; - -#ifdef KAME - memset(&ssa2, 0, sizeof ssa2); - ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; - ssa2.sadb_x_sa2_mode = 0; - if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa2, 0) == -1) - goto cleanup; -#endif - - /* - * Setup the ADDRESS extensions. - */ - if (incoming) - sa->transport->vtbl->get_dst(sa->transport, &saddr); - else - sa->transport->vtbl->get_src(sa->transport, &saddr); - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); - switch (saddr->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - if (incoming) - sa->transport->vtbl->get_src(sa->transport, &saddr); - else - sa->transport->vtbl->get_dst(sa->transport, &saddr); - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); - switch (saddr->sa_family) { - case AF_INET: - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; - break; - } - if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - ret = pf_key_v2_call(delete); - pf_key_v2_msg_free(delete); - delete = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_delete_spi: DELETE: %s", - strerror(err))); - goto cleanup; - } - pf_key_v2_msg_free(ret); - - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: done")); - - return 0; - -cleanup: - if (addr) - free(addr); - if (delete) - pf_key_v2_msg_free(delete); - if (ret) - pf_key_v2_msg_free(ret); - return -1; -} - -static void -pf_key_v2_stayalive(struct exchange *exchange, void *vconn, int fail) -{ - char *conn = vconn; - struct sa *sa; - - /* XXX What if it is phase 1 ? */ - sa = sa_lookup_by_name(conn, 2); - if (sa) - sa->flags |= SA_FLAG_STAYALIVE; - - /* - * Remove failed configuration entry -- call twice because it is - * created with a Refcount of 2. - */ - if (fail && (!exchange || exchange->name)) { - pf_key_v2_remove_conf(conn); - pf_key_v2_remove_conf(conn); - } -} - -/* Check if a connection CONN exists, otherwise establish it. */ -void -pf_key_v2_connection_check(char *conn) -{ - if (!sa_lookup_by_name(conn, 2)) { - LOG_DBG((LOG_SYSDEP, 70, - "pf_key_v2_connection_check: SA for %s missing", conn)); - exchange_establish(conn, pf_key_v2_stayalive, conn); - } else - LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: " - "SA for %s exists", conn)); -} - -/* Handle a PF_KEY lifetime expiration message PMSG. */ -static void -pf_key_v2_expire(struct pf_key_v2_msg *pmsg) -{ - struct sadb_msg *msg; - struct sadb_sa *ssa; - struct sadb_address *dst; - struct sockaddr *dstaddr; - struct sadb_lifetime *life, *lifecurrent; - struct sa *sa; - struct pf_key_v2_node *lifenode, *ext; -#ifdef USE_DEBUG - char *dst_str; -#endif - - msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_SA); - if (!ext) { - log_print("pf_key_v2_expire: no SA extension found"); - return; - } - ssa = ext->seg; - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); - if (!ext) { - log_print("pf_key_v2_expire: " - "no destination address extension found"); - return; - } - dst = ext->seg; - dstaddr = (struct sockaddr *) (dst + 1); - lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_HARD); - if (!lifenode) - lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_SOFT); - if (!lifenode) { - log_print("pf_key_v2_expire: no lifetime extension found"); - return; - } - life = lifenode->seg; - - lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_CURRENT); - if (!lifenode) { - log_print("pf_key_v2_expire: " - "no current lifetime extension found"); - return; - } - lifecurrent = lifenode->seg; - -#ifdef USE_DEBUG - - if (sockaddr2text(dstaddr, &dst_str, 0)) - dst_str = 0; - - LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_expire: " - "%s dst %s SPI %x sproto %d", - life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT" - : "HARD", dst_str ? dst_str : "", - ntohl(ssa->sadb_sa_spi), msg->sadb_msg_satype)); - - if (dst_str) - free(dst_str); - -#endif /* USE_DEBUG */ - - /* - * Find the IPsec SA. The IPsec stack has two SAs for every IKE SA, - * one outgoing and one incoming, we regard expirations for any of - * them as an expiration of the full IKE SA. Likewise, in - * protection suites consisting of more than one protocol, any - * expired individual IPsec stack SA will be seen as an expiration - * of the full suite. - */ - switch (msg->sadb_msg_satype) { - case SADB_SATYPE_ESP: - sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, - IPSEC_PROTO_IPSEC_ESP); - break; - - case SADB_SATYPE_AH: - sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, - IPSEC_PROTO_IPSEC_AH); - break; - -#ifdef SADB_X_SATYPE_IPCOMP - case SADB_X_SATYPE_IPCOMP: - sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, - IPSEC_PROTO_IPCOMP); - break; -#endif - - default: - /* XXX Log? */ - sa = 0; - break; - } - - /* If the SA is already gone, don't do anything. */ - if (!sa) - return; - - /* - * If we got a notification, try to renegotiate the SA -- unless of - * course it has already been replaced by another. - * Also, ignore SAs that were not dynamically established, or that - * did not see any use. - */ - if (!(sa->flags & SA_FLAG_REPLACED) && - (sa->flags & SA_FLAG_ONDEMAND) && - lifecurrent->sadb_lifetime_bytes) - exchange_establish(sa->name, 0, 0); - - if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) { - /* Remove the old SA, it isn't useful anymore. */ - sa_free(sa); - } -} - -/* Handle a PF_KEY SA ACQUIRE message PMSG. */ -static void -pf_key_v2_acquire(struct pf_key_v2_msg *pmsg) -{ -#if defined (SADB_X_ASKPOLICY) - struct sadb_msg *msg, askpolicy_msg; - struct pf_key_v2_msg *askpolicy = 0, *ret = 0; - struct sadb_x_policy policy; - struct sadb_address *dst = 0, *src = 0; - struct sockaddr *dstaddr, *srcaddr = 0; - struct sadb_comb *scmb = 0; - struct sadb_prop *sprp = 0; - struct sadb_ident *srcident = 0, *dstident = 0; - char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0, - *conn = 0; - char confname[120]; - char *srcid = 0, *dstid = 0, *prefstring = 0; - int slen, af, afamily, masklen, buflen; - struct sockaddr *smask, *sflow, *dmask, *dflow; - struct sadb_protocol *sproto; - char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX]; - char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX]; - char *sidtype = 0, *didtype = 0; - char lname[100], dname[100], configname[30]; - int shostflag = 0, dhostflag = 0; - struct pf_key_v2_node *ext; - struct passwd *pwd = 0; - u_int16_t sport = 0, dport = 0; - u_int8_t tproto = 0; - char tmbuf[sizeof sport * 3 + 1], *xform; - int connlen; -#if defined (SADB_X_CREDTYPE_NONE) - struct sadb_x_cred *cred = 0, *sauth = 0; -#endif - - /* This needs to be dynamically allocated. */ - connlen = 22; - conn = malloc(connlen); - if (!conn) { - log_error("pf_key_v2_acquire: malloc (%d) failed", connlen); - return; - } - msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; - - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); - if (!ext) { - log_print("pf_key_v2_acquire: " - "no destination address specified"); - return; - } - dst = ext->seg; - - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_SRC); - if (ext) - src = ext->seg; - - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_PROPOSAL); - if (ext) { - sprp = ext->seg; - scmb = (struct sadb_comb *) (sprp + 1); - } - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_SRC); - if (ext) - srcident = ext->seg; - - ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_DST); - if (ext) - dstident = ext->seg; - - /* Ask the kernel for the matching policy. */ - bzero(&askpolicy_msg, sizeof askpolicy_msg); - askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY; - askpolicy = pf_key_v2_msg_new(&askpolicy_msg, 0); - if (!askpolicy) - goto fail; - - policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - policy.sadb_x_policy_len = sizeof policy / PF_KEY_V2_CHUNK; - policy.sadb_x_policy_seq = msg->sadb_msg_seq; - if (pf_key_v2_msg_add(askpolicy, (struct sadb_ext *)&policy, 0) == -1) - goto fail; - - ret = pf_key_v2_call(askpolicy); - if (!ret) - goto fail; - - /* Now we have all the information needed. */ - - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_FLOW); - if (!ext) { - log_print("pf_key_v2_acquire: no source flow extension found"); - goto fail; - } - sflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); - - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_FLOW); - if (!ext) { - log_print("pf_key_v2_acquire: " - "no destination flow extension found"); - goto fail; - } - dflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_MASK); - if (!ext) { - log_print("pf_key_v2_acquire: no source mask extension found"); - goto fail; - } - smask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); - - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_MASK); - if (!ext) { - log_print("pf_key_v2_acquire: " - "no destination mask extension found"); - goto fail; - } - dmask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); - - ext = pf_key_v2_find_ext(ret, SADB_X_EXT_FLOW_TYPE); - if (!ext) { - log_print("pf_key_v2_acquire: no flow type extension found"); - goto fail; - } - sproto = ext->seg; - tproto = sproto->sadb_protocol_proto; - -#if defined (SADB_X_EXT_LOCAL_CREDENTIALS) - ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_CREDENTIALS); - if (ext) - cred = (struct sadb_x_cred *) ext->seg; - else - cred = 0; -#endif - -#if defined (SADB_X_EXT_LOCAL_AUTH) - ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_AUTH); - if (ext) - sauth = (struct sadb_x_cred *) ext->seg; - else - sauth = 0; -#endif - - bzero(ssflow, sizeof ssflow); - bzero(sdflow, sizeof sdflow); - bzero(ssmask, sizeof ssmask); - bzero(sdmask, sizeof sdmask); - - sidtype = didtype = "IPV4_ADDR_SUBNET"; /* default */ - - switch (sflow->sa_family) { - case AF_INET: - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) sflow)->sin_addr, ssflow, - ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - sport = ((struct sockaddr_in *) sflow)->sin_port; - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) dflow)->sin_addr, sdflow, - ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - dport = ((struct sockaddr_in *) dflow)->sin_port; - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) smask)->sin_addr, ssmask, - ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) dmask)->sin_addr, sdmask, - ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - if (((struct sockaddr_in *) smask)->sin_addr.s_addr == - INADDR_BROADCAST) { - shostflag = 1; - sidtype = "IPV4_ADDR"; - } - if (((struct sockaddr_in *) dmask)->sin_addr.s_addr == - INADDR_BROADCAST) { - dhostflag = 1; - didtype = "IPV4_ADDR"; - } - break; - - case AF_INET6: - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *) sflow)->sin6_addr, - ssflow, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - sport = ((struct sockaddr_in6 *) sflow)->sin6_port; - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *) dflow)->sin6_addr, - sdflow, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - dport = ((struct sockaddr_in6 *) dflow)->sin6_port; - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *) smask)->sin6_addr, - ssmask, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *) dmask)->sin6_addr, - sdmask, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - sidtype = didtype = "IPV6_ADDR_SUBNET"; - if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)smask)->sin6_addr)) { - shostflag = 1; - sidtype = "IPV6_ADDR"; - } - if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)dmask)->sin6_addr)) { - dhostflag = 1; - didtype = "IPV6_ADDR"; - } - break; - } - - dstaddr = (struct sockaddr *)(dst + 1); - bzero(dstbuf, sizeof dstbuf); - bzero(srcbuf, sizeof srcbuf); - - if (dstaddr->sa_family == 0) { - /* - * Destination was not specified in the flow -- can we derive - * it? - */ - if (dhostflag == 0) { - log_print("pf_key_v2_acquire: " - "Cannot determine precise destination"); - goto fail; - } - dstaddr = dflow; - } - switch (dstaddr->sa_family) { - case AF_INET: - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) dstaddr)->sin_addr, - dstbuf, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - LOG_DBG((LOG_SYSDEP, 20, - "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, - msg->sadb_msg_satype)); - break; - - case AF_INET6: - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *) dstaddr)->sin6_addr, - dstbuf, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: inet_ntop failed"); - goto fail; - } - LOG_DBG((LOG_SYSDEP, 20, - "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, - msg->sadb_msg_satype)); - break; - } - - if (src) { - srcaddr = (struct sockaddr *) (src + 1); - - switch (srcaddr->sa_family) { - case AF_INET: - if (inet_ntop(AF_INET, - &((struct sockaddr_in *) srcaddr)->sin_addr, - srcbuf, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: " - "inet_ntop failed"); - goto fail; - } - break; - - case AF_INET6: - if (inet_ntop(AF_INET6, - &((struct sockaddr_in6 *)srcaddr)->sin6_addr, - srcbuf, ADDRESS_MAX) == NULL) { - log_print("pf_key_v2_acquire: " - "inet_ntop failed"); - goto fail; - } - break; - - default: - /* - * The kernel will pass an all '0' EXT_ADDRESS_SRC if - * it wasn't specified for the flow. In that case, do - * NOT specify the srcaddr in the Peer-name below - */ - srcbuf[0] = 0; - srcaddr = NULL; - break; - } - } - /* Insert source ID. */ - if (srcident) { - slen = (srcident->sadb_ident_len * sizeof(u_int64_t)) - - sizeof(struct sadb_ident); - if (((unsigned char *) (srcident + 1))[slen - 1] != '\0') { - log_print("pf_key_v2_acquire: " - "source identity not NUL-terminated"); - goto fail; - } - /* Check for valid type. */ - switch (srcident->sadb_ident_type) { -#if defined (SADB_X_IDENTTYPE_CONNECTION) - case SADB_X_IDENTTYPE_CONNECTION: - /* XXX */ - break; -#endif - - case SADB_IDENTTYPE_PREFIX: - /* Determine what the address family is. */ - srcid = memchr(srcident + 1, ':', slen); - if (srcid) - afamily = AF_INET6; - else - afamily = AF_INET; - - srcid = memchr(srcident + 1, '/', slen); - if (!srcid) { - log_print("pf_key_v2_acquire: " - "badly formatted PREFIX identity"); - goto fail; - } - masklen = atoi(srcid + 1); - - /* XXX We only support host addresses. */ - if ((afamily == AF_INET6 && masklen != 128) - || (afamily == AF_INET && masklen != 32)) { - log_print("pf_key_v2_acquire: " - "non-host address specified in source " - "identity (mask length %d), ignoring " - "request", masklen); - goto fail; - } - /* - * NUL-terminate the PREFIX string at the separator, - * then dup. - */ - *srcid = '\0'; - slen = strlen((char *) (srcident + 1)) + - sizeof "ID:Address/"; - srcid = malloc(slen); - if (!srcid) { - log_error("pf_key_v2_acquire: " - "malloc (%d) failed", slen); - goto fail; - } - snprintf(srcid, slen, "ID:Address/%s", - (char *) (srcident + 1)); - - /* Set the section if it doesn't already exist. */ - af = conf_begin(); - if (!conf_get_str(srcid, "ID-type")) { - if (conf_set(af, srcid, "ID-type", - afamily == AF_INET ? "IPV4_ADDR" : - "IPV6_ADDR", 1, 0) - || conf_set(af, srcid, "Refcount", "1", 1, - 0) - || conf_set(af, srcid, "Address", - (char *) (srcident + 1), 1, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, srcid); - conf_end(af, 1); - break; - - case SADB_IDENTTYPE_FQDN: - prefstring = "FQDN"; - /* Fall through */ - case SADB_IDENTTYPE_USERFQDN: - if (!prefstring) { - prefstring = "USER_FQDN"; - - /* - * Check whether there is a string following - * the header; if no, that there is a user ID - * (and acquire the login name). If there is - * both a string and a user ID, check that - * they match. - */ - if ((slen == 0) && - (srcident->sadb_ident_id == 0)) { - log_print("pf_key_v2_acquire: " - "no user FQDN or ID provided"); - goto fail; - } - if (srcident->sadb_ident_id) { - pwd = - getpwuid(srcident->sadb_ident_id); - if (!pwd) { - log_error("pf_key_v2_acquire: " - "could not acquire " - "username from provided " - "ID %llu", - srcident->sadb_ident_id); - goto fail; - } - if (slen != 0) - if (strcmp(pwd->pw_name, - (char *) (srcident + 1)) - != 0) { - log_print("pf_key_v2_acquire: " - "provided user " - "name and ID do " - "not match (%s != " - "%s)", - (char *) (srcident + 1), - pwd->pw_name); - /* - * String has - * precedence, per - * RFC 2367. - */ - } - } - } - buflen = (slen ? slen : strlen(pwd->pw_name)) + - strlen(prefstring) + sizeof "ID:/"; - srcid = malloc(buflen); - if (!srcid) { - log_error("pf_key_v2_acquire: " - "malloc (%d) failed", buflen); - goto fail; - } - snprintf(srcid, buflen, "ID:%s/", prefstring); - if (slen != 0) - strlcat(srcid, - (char *) (srcident + 1), buflen); - else - strlcat(srcid, pwd->pw_name, buflen); - pwd = 0; - - /* Set the section if it doesn't already exist. */ - af = conf_begin(); - if (!conf_get_str(srcid, "ID-type")) { - if (conf_set(af, srcid, "ID-type", prefstring, - 1, 0) - || conf_set(af, srcid, "Refcount", "1", 1, - 0) - || conf_set(af, srcid, "Name", - srcid + sizeof "ID:/" - 1 + - strlen(prefstring), 1, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, srcid); - conf_end(af, 1); - break; - - default: - LOG_DBG((LOG_SYSDEP, 20, - "pf_key_v2_acquire: invalid source ID type %d", - srcident->sadb_ident_type)); - goto fail; - } - - LOG_DBG((LOG_SYSDEP, 50, - "pf_key_v2_acquire: constructed source ID \"%s\"", srcid)); - prefstring = 0; - } - /* Insert destination ID. */ - if (dstident) { - slen = (dstident->sadb_ident_len * sizeof(u_int64_t)) - - sizeof(struct sadb_ident); - - /* Check for valid type. */ - switch (dstident->sadb_ident_type) { -#if defined (SADB_X_IDENTTYPE_CONNECTION) - case SADB_X_IDENTTYPE_CONNECTION: - /* XXX */ - break; -#endif - - case SADB_IDENTTYPE_PREFIX: - /* Determine what the address family is. */ - dstid = memchr(dstident + 1, ':', slen); - if (dstid) - afamily = AF_INET6; - else - afamily = AF_INET; - - dstid = memchr(dstident + 1, '/', slen); - if (!dstid) { - log_print("pf_key_v2_acquire: " - "badly formatted PREFIX identity"); - goto fail; - } - masklen = atoi(dstid + 1); - - /* XXX We only support host addresses. */ - if ((afamily == AF_INET6 && masklen != 128) - || (afamily == AF_INET && masklen != 32)) { - log_print("pf_key_v2_acquire: " - "non-host address specified in " - "destination identity (mask length %d), " - "ignoring request", masklen); - goto fail; - } - /* - * NUL-terminate the PREFIX string at the separator, - * then dup. - */ - *dstid = '\0'; - slen = strlen((char *) (dstident + 1)) + - sizeof "ID:Address/"; - dstid = malloc(slen); - if (!dstid) { - log_error("pf_key_v2_acquire: " - "malloc (%d) failed", slen); - goto fail; - } - snprintf(dstid, slen, "ID:Address/%s", - (char *) (dstident + 1)); - - /* Set the section if it doesn't already exist. */ - af = conf_begin(); - if (!conf_get_str(dstid, "ID-type")) { - if (conf_set(af, dstid, "ID-type", - afamily == AF_INET ? "IPV4_ADDR" : - "IPV6_ADDR", 1, 0) - || conf_set(af, dstid, "Refcount", "1", 1, - 0) - || conf_set(af, dstid, "Address", - (char *) (dstident + 1), 1, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, dstid); - conf_end(af, 1); - break; - - case SADB_IDENTTYPE_FQDN: - prefstring = "FQDN"; - /* Fall through */ - - case SADB_IDENTTYPE_USERFQDN: - if (!prefstring) { - prefstring = "USER_FQDN"; - - /* - * Check whether there is a string following - * the header; if no, that there is a user ID - * (and acquire the login name). If there is - * both a string and a user ID, check that - * they match. - */ - if (slen == 0 && - dstident->sadb_ident_id == 0) { - log_print("pf_key_v2_acquire: " - "no user FQDN or ID provided"); - goto fail; - } - if (dstident->sadb_ident_id) { - pwd = getpwuid(dstident->sadb_ident_id); - if (!pwd) { - log_error("pf_key_v2_acquire: " - "could not acquire " - "username from provided " - "ID %llu", - dstident->sadb_ident_id); - goto fail; - } - if (slen != 0) - if (strcmp(pwd->pw_name, - (char *) (dstident + 1)) - != 0) { - log_print("pf_key_v2_acquire: " - "provided user " - "name and ID do " - "not match (%s != " - "%s)", - (char *) (dstident + 1), - pwd->pw_name); - /* - * String has - * precedence, per RF - * 2367. - */ - } - } - } - buflen = (slen ? slen : strlen(pwd->pw_name)) + - strlen(prefstring) + sizeof "ID:/"; - dstid = malloc(buflen); - if (!dstid) { - log_error("pf_key_v2_acquire: " - "malloc (%d) failed", buflen); - goto fail; - } - snprintf(dstid, buflen, "ID:%s/", prefstring); - if (slen != 0) - strlcat(dstid, (char *) (dstident + 1), - buflen); - else - strlcat(dstid, pwd->pw_name, buflen); - pwd = 0; - - /* Set the section if it doesn't already exist. */ - af = conf_begin(); - if (!conf_get_str(dstid, "ID-type")) { - if (conf_set(af, dstid, "ID-type", prefstring, - 1, 0) - || conf_set(af, dstid, "Refcount", "1", 1, - 0) - || conf_set(af, dstid, "Name", - dstid + sizeof "ID:/" - 1 + - strlen(prefstring), 1, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, dstid); - conf_end(af, 1); - break; - - default: - LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: " - "invalid destination ID type %d", - dstident->sadb_ident_type)); - goto fail; - } - - LOG_DBG((LOG_SYSDEP, 50, - "pf_key_v2_acquire: constructed destination ID \"%s\"", - dstid)); - } - /* Now we've placed the necessary IDs in the configuration space. */ - - /* Get a new connection sequence number. */ - for (;; connection_seq++) { - snprintf(conn, connlen, "Connection-%u", connection_seq); - snprintf(configname, sizeof configname, "Config-Phase2-%u", - connection_seq); - - /* Does it exist ? */ - if (!conf_get_str(conn, "Phase") - && !conf_get_str(configname, "Suites")) - break; - } - - /* - * Set the IPsec connection entry. In particular, the following fields: - * - Phase - * - ISAKMP-peer - * - Local-ID/Remote-ID (if provided) - * - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2) - * - Configuration - * - * Also set the following section: - * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)] - * with these fields: - * - Phase - * - ID (if provided) - * - Remote-ID (if provided) - * - Local-address (if provided) - * - Address - * - Configuration (if an entry ISAKMP-configuration-dstaddr(/srcaddr) - * exists -- otherwise use the defaults) - */ - - slen = strlen(dstbuf) + strlen(srcbuf) + (srcid ? strlen(srcid) : 0) - + (dstid ? strlen(dstid) : 0) + sizeof "Peer-/-/"; - peer = malloc(slen); - if (!peer) - goto fail; - - /* - * The various cases: - * - Peer-dstaddr - * - Peer-dstaddr/srcaddr - * - Peer-dstaddr/srcaddr-srcid - * - Peer-dstaddr/srcaddr-srcid/dstid - * - Peer-dstaddr/srcaddr-/dstid - * - Peer-dstaddr-srcid/dstid - * - Peer-dstaddr-/dstid - * - Peer-dstaddr-srcid - */ - snprintf(peer, slen, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "", - srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "", - dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : ""); - - /* - * Set the IPsec connection section. Refcount is set to 2, because - * it will be linked both to the incoming and the outgoing SA. - */ - af = conf_begin(); - if (conf_set(af, conn, "Phase", "2", 0, 0) - || conf_set(af, conn, "Flags", "__ondemand", 0, 0) - || conf_set(af, conn, "Refcount", "2", 0, 0) - || conf_set(af, conn, "ISAKMP-peer", peer, 0, 0)) { - conf_end(af, 0); - goto fail; - } - /* Set the sequence number. */ - snprintf(lname, sizeof lname, "%u", msg->sadb_msg_seq); - if (conf_set(af, conn, "Acquire-ID", lname, 0, 0)) { - conf_end(af, 0); - goto fail; - } - /* Set Phase 2 IDs -- this is the Local-ID section. */ - snprintf(lname, sizeof lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask, - tproto, sport); - if (conf_set(af, conn, "Local-ID", lname, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (!conf_get_str(lname, "ID-type")) { - if (conf_set(af, lname, "Refcount", "1", 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (shostflag) { - if (conf_set(af, lname, "ID-type", sidtype, 0, 0) - || conf_set(af, lname, "Address", ssflow, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } else { - if (conf_set(af, lname, "ID-type", sidtype, 0, 0) - || conf_set(af, lname, "Network", ssflow, 0, 0) - || conf_set(af, lname, "Netmask", ssmask, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } - if (tproto) { - snprintf(tmbuf, sizeof sport * 3 + 1, "%u", tproto); - if (conf_set(af, lname, "Protocol", tmbuf, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (sport) { - snprintf(tmbuf, sizeof sport * 3 + 1, "%u", - ntohs(sport)); - if (conf_set(af, lname, "Port", tmbuf, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } - } - } else - pf_key_v2_conf_refinc(af, lname); - - /* Set Remote-ID section. */ - snprintf(dname, sizeof dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask, - tproto, dport); - if (conf_set(af, conn, "Remote-ID", dname, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (!conf_get_str(dname, "ID-type")) { - if (conf_set(af, dname, "Refcount", "1", 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (dhostflag) { - if (conf_set(af, dname, "ID-type", didtype, 0, 0) - || conf_set(af, dname, "Address", sdflow, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } else { - if (conf_set(af, dname, "ID-type", didtype, 0, 0) - || conf_set(af, dname, "Network", sdflow, 0, 0) - || conf_set(af, dname, "Netmask", sdmask, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } - - if (tproto) { - snprintf(tmbuf, sizeof dport * 3 + 1, "%u", tproto); - if (conf_set(af, dname, "Protocol", tmbuf, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (dport) { - snprintf(tmbuf, sizeof dport * 3 + 1, "%u", - ntohs(dport)); - if (conf_set(af, dname, "Port", tmbuf, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } - } - } else - pf_key_v2_conf_refinc(af, dname); - - /* - * XXX - * We should be using information from the proposal to set this up. - * At least, we should make this selectable. - */ - - /* Phase 2 configuration. */ - if (conf_set(af, conn, "Configuration", configname, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (conf_set(af, configname, "Exchange_type", "Quick_mode", 0, 0) - || conf_set(af, configname, "DOI", "IPSEC", 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (conf_get_str("General", "Default-phase-2-suites")) { - if (conf_set(af, configname, "Suites", - conf_get_str("General", "Default-phase-2-suites"), 0, 0)) { - conf_end(af, 0); - goto fail; - } - } else { - if (conf_set(af, configname, "Suites", - "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) { - conf_end(af, 0); - goto fail; - } - } - - /* Set the ISAKMP-peer section. */ - if (!conf_get_str(peer, "Phase")) { - if (conf_set(af, peer, "Phase", "1", 0, 0) - || conf_set(af, peer, "Refcount", "1", 0, 0) - || conf_set(af, peer, "Address", dstbuf, 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (srcaddr && conf_set(af, peer, "Local-address", srcbuf, 0, - 0)) { - conf_end(af, 0); - goto fail; - } - snprintf(confname, sizeof confname, "ISAKMP-Configuration-%s", - peer); - if (conf_set(af, peer, "Configuration", confname, 0, 0)) { - conf_end(af, 0); - goto fail; - } -#if defined (SADB_X_CREDTYPE_NONE) - /* Store any credentials passed to us. */ - if (cred) { - struct cert_handler *handler = 0; - void *cert; - char num[12], *certprint; - - /* Convert to bytes in-place. */ - cred->sadb_x_cred_len *= PF_KEY_V2_CHUNK; - - if (cred->sadb_x_cred_len <= sizeof *cred) { - log_print("pf_key_v2_acquire: " - "zero-length credentials, aborting SA " - "acquisition"); - conf_end(af, 0); - goto fail; - } - switch (cred->sadb_x_cred_type) { - case SADB_X_CREDTYPE_X509: - snprintf(num, sizeof num, "%d", - ISAKMP_CERTENC_X509_SIG); - handler = cert_get(ISAKMP_CERTENC_X509_SIG); - break; - case SADB_X_CREDTYPE_KEYNOTE: - snprintf(num, sizeof num, "%d", - ISAKMP_CERTENC_KEYNOTE); - handler = cert_get(ISAKMP_CERTENC_KEYNOTE); - break; - default: - log_print("pf_key_v2_acquire: " - "unknown credential type %d", - cred->sadb_x_cred_type); - conf_end(af, 0); - goto fail; - } - - if (!handler) { - log_print("pf_key_v2_acquire: " - "cert_get (%s) failed", num); - conf_end(af, 0); - goto fail; - } - /* Set the credential type as a number. */ - if (conf_set(af, peer, "Credential_type", num, 0, 0)) { - conf_end(af, 0); - goto fail; - } - /* Get the certificate. */ - cert = handler->cert_get((u_int8_t *) (cred + 1), - cred->sadb_x_cred_len - sizeof *cred); - - /* Now convert to printable format. */ - certprint = handler->cert_printable(cert); - handler->cert_free(cert); - if (!certprint - || conf_set(af, peer, "Credentials", certprint, 0, - 0)) { - if (certprint) - free(certprint); - conf_end(af, 0); - goto fail; - } - free(certprint); - } -#endif /* SADB_X_CREDTYPE_NONE */ - - /* Phase 1 configuration. */ - if (!conf_get_str(confname, "exchange_type")) { -#if defined (SADB_X_EXT_LOCAL_AUTH) - /* - * We may have been provided with authentication - * material. - */ - if (sauth) { - char *authm; - - /* Convert to bytes in-place. */ - sauth->sadb_x_cred_len *= PF_KEY_V2_CHUNK; - - switch (sauth->sadb_x_cred_type) { - case SADB_X_AUTHTYPE_PASSPHRASE: - if (conf_set(af, confname, - "Transforms", "3DES-SHA", 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (sauth->sadb_x_cred_len <= - sizeof *sauth) { - log_print("pf_key_v2_acquire: " - "zero-length passphrase, " - "aborting SA acquisition"); - conf_end(af, 0); - goto fail; - } - authm = malloc(sauth->sadb_x_cred_len - - sizeof *sauth + 1); - if (!authm) { - log_error("pf_key_v2_acquire: " - "malloc (%lu) failed", - sauth->sadb_x_cred_len - - (unsigned long) sizeof *sauth + 1); - conf_end(af, 0); - goto fail; - } - memcpy(authm, sauth + 1, - sauth->sadb_x_cred_len - - sizeof *sauth + 1); - - /* Set the passphrase in the peer. */ - if (conf_set(af, peer, - "Authentication", authm, 0, 0)) { - free(authm); - conf_end(af, 0); - goto fail; - } - free(authm); - break; - - case SADB_X_AUTHTYPE_RSA: - if (conf_set(af, confname, - "Transforms", "3DES-SHA-RSA_SIG", - 0, 0)) { - conf_end(af, 0); - goto fail; - } - if (sauth->sadb_x_cred_len <= - sizeof *sauth) { - log_print("pf_key_v2_acquire: " - "zero-length RSA key, " - "aborting SA acquisition"); - conf_end(af, 0); - goto fail; - } - authm = key_printable(ISAKMP_KEY_RSA, - ISAKMP_KEYTYPE_PRIVATE, - (u_int8_t *) sauth + 1, - sauth->sadb_x_cred_len - - sizeof *sauth); - if (!authm) { - log_print("pf_key_v2_acquire: " - "failed to convert " - "private key to printable " - "format (size %lu)", - sauth->sadb_x_cred_len - - (unsigned long) sizeof *sauth); - conf_end(af, 0); - goto fail; - } - /* - * Set the key in the peer. We don't - * use "Authentication" to avoid - * potential conflicts with file-based - * configurations that use public key - * authentication but still specify - * an "Authentication" tag (typically - * as a remnant of passphrase-based - * testing). - */ - if (conf_set(af, peer, - "PKAuthentication", authm, 0, 0)) { - free(authm); - conf_end(af, 0); - goto fail; - } - free(authm); - break; - - default: - log_print("pf_key_v2_acquire: " - "unknown authentication " - "material type %d received from " - "kernel", sauth->sadb_x_cred_type); - conf_end(af, 0); - goto fail; - } - } else /* Fall through */ -#endif /* SADB_X_EXT_LOCAL_AUTH */ - { - xform = conf_get_str( - "Default-phase-1-configuration", - "Transforms"); - if (conf_set(af, confname, "Transforms", - xform ? xform : "3DES-SHA-RSA_SIG", 0, - 0)) { - conf_end(af, 0); - goto fail; - } - } - - if (conf_set(af, confname, "Exchange_Type", "ID_PROT", - 0, 0) - || conf_set(af, confname, "DOI", "IPSEC", 0, 0) - || conf_set(af, confname, "Refcount", "1", 0, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, confname); - - /* The ID we should use in Phase 1. */ - if (srcid && conf_set(af, peer, "ID", srcid, 0, 0)) { - conf_end(af, 0); - goto fail; - } - /* The ID the other side should use in Phase 1. */ - if (dstid && conf_set(af, peer, "Remote-ID", dstid, 0, 0)) { - conf_end(af, 0); - goto fail; - } - } else - pf_key_v2_conf_refinc(af, peer); - - /* All done. */ - conf_end(af, 1); - - /* Let's rock 'n roll. */ - pf_key_v2_connection_check(conn); - conn = 0; - - /* Fall-through to cleanup. */ -fail: - if (ret) - pf_key_v2_msg_free(ret); - if (askpolicy) - pf_key_v2_msg_free(askpolicy); - if (srcid) - free(srcid); - if (dstid) - free(dstid); - if (peer) - free(peer); - if (conn) - free(conn); - return; -#else - /* acquire not supported */ - return; -#endif /* SADB_X_ASKPOLICY */ -} - -static void -pf_key_v2_notify(struct pf_key_v2_msg *msg) -{ - switch (((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type) { - case SADB_EXPIRE: - pf_key_v2_expire(msg); - break; - - case SADB_ACQUIRE: - pf_key_v2_acquire(msg); - break; - - default: - log_print("pf_key_v2_notify: unexpected message type (%d)", - ((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type); - } - pf_key_v2_msg_free(msg); -} - -void -pf_key_v2_handler(int fd) -{ - struct pf_key_v2_msg *msg; -#if !defined (LINUX_IPSEC) - int n; - - /* - * As synchronous read/writes to the socket can have taken place - * between the select(2) call of the main loop and this handler, we - * need to recheck the readability. - */ - if (ioctl(pf_key_v2_socket, FIONREAD, &n) == -1) { - log_error("pf_key_v2_handler: ioctl (%d, FIONREAD, &n) failed", - pf_key_v2_socket); - return; - } - if (!n) - return; -#endif /* LINUX_IPSEC */ - - msg = pf_key_v2_read(0); - if (msg) - pf_key_v2_notify(msg); -} - -/* - * Group 2 IPsec SAs given by the PROTO1 and PROTO2 protocols of the SA IKE - * security association in a chain. - * XXX Assumes OpenBSD GRPSPIS extension. Should probably be moved to sysdep.c - */ -int -pf_key_v2_group_spis(struct sa *sa, struct proto *proto1, - struct proto *proto2, int incoming) -{ -#if defined (SADB_X_GRPSPIS) - struct sadb_msg msg; - struct sadb_sa sa1, sa2; - struct sadb_address *addr = 0; - struct sadb_protocol protocol; - struct pf_key_v2_msg *grpspis = 0, *ret = 0; - struct sockaddr *saddr; - int err; - size_t len; -#ifdef KAME - struct sadb_x_sa2 kamesa2; -#endif - - msg.sadb_msg_type = SADB_X_GRPSPIS; - switch (proto1->proto) { - case IPSEC_PROTO_IPSEC_ESP: - msg.sadb_msg_satype = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - msg.sadb_msg_satype = SADB_SATYPE_AH; - break; -#if defined (SADB_X_SATYPE_IPCOMP) - case IPSEC_PROTO_IPCOMP: - msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - log_print("pf_key_v2_group_spis: invalid proto %d", - proto1->proto); - goto cleanup; - } - msg.sadb_msg_seq = 0; - grpspis = pf_key_v2_msg_new(&msg, 0); - if (!grpspis) - goto cleanup; - - /* Setup the SA extensions. */ - sa1.sadb_sa_exttype = SADB_EXT_SA; - sa1.sadb_sa_len = sizeof sa1 / PF_KEY_V2_CHUNK; - memcpy(&sa1.sadb_sa_spi, proto1->spi[incoming], - sizeof sa1.sadb_sa_spi); - sa1.sadb_sa_replay = 0; - sa1.sadb_sa_state = 0; - sa1.sadb_sa_auth = 0; - sa1.sadb_sa_encrypt = 0; - sa1.sadb_sa_flags = 0; - if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa1, 0) == -1) - goto cleanup; - -#ifndef KAME - sa2.sadb_sa_exttype = SADB_X_EXT_SA2; - sa2.sadb_sa_len = sizeof sa2 / PF_KEY_V2_CHUNK; - memcpy(&sa2.sadb_sa_spi, proto2->spi[incoming], - sizeof sa2.sadb_sa_spi); - sa2.sadb_sa_replay = 0; - sa2.sadb_sa_state = 0; - sa2.sadb_sa_auth = 0; - sa2.sadb_sa_encrypt = 0; - sa2.sadb_sa_flags = 0; - if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa2, 0) == -1) - goto cleanup; -#else - memset(&kamesa2, 0, sizeof kamesa2); - kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK; - kamesa2.sadb_x_sa2_mode = 0; - if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&kamesa2, 0) == -1) - goto cleanup; -#endif - - /* - * Setup the ADDRESS extensions. - */ - if (incoming) - sa->transport->vtbl->get_src(sa->transport, &saddr); - else - sa->transport->vtbl->get_dst(sa->transport, &saddr); - len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - addr = calloc(1, len); - if (!addr) - goto cleanup; - addr->sadb_address_exttype = SADB_X_EXT_DST2; - addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif - addr->sadb_address_reserved = 0; - memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); - ((struct sockaddr_in *) (addr + 1))->sin_port = 0; - if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, - PF_KEY_V2_NODE_MALLOCED) == -1) - goto cleanup; - addr = 0; - - /* Setup the PROTOCOL extension. */ - protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - protocol.sadb_protocol_len = sizeof protocol / PF_KEY_V2_CHUNK; - switch (proto2->proto) { - case IPSEC_PROTO_IPSEC_ESP: - protocol.sadb_protocol_proto = SADB_SATYPE_ESP; - break; - case IPSEC_PROTO_IPSEC_AH: - protocol.sadb_protocol_proto = SADB_SATYPE_AH; - break; -#if defined (SADB_X_SATYPE_IPCOMP) - case IPSEC_PROTO_IPCOMP: - protocol.sadb_protocol_proto = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - log_print("pf_key_v2_group_spis: invalid proto %d", - proto2->proto); - goto cleanup; - } - protocol.sadb_protocol_reserved2 = 0; - if (pf_key_v2_msg_add(grpspis, - (struct sadb_ext *)&protocol, 0) == -1) - goto cleanup; - - ret = pf_key_v2_call(grpspis); - pf_key_v2_msg_free(grpspis); - grpspis = 0; - if (!ret) - goto cleanup; - err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; - if (err) { - log_print("pf_key_v2_group_spis: GRPSPIS: %s", strerror(err)); - goto cleanup; - } - pf_key_v2_msg_free(ret); - - LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_group_spis: done")); - - return 0; - -cleanup: - if (addr) - free(addr); - if (grpspis) - pf_key_v2_msg_free(grpspis); - if (ret) - pf_key_v2_msg_free(ret); - return -1; - -#else /* SADB_X_GRPSPIS */ - log_print("pf_key_v2_group_spis: not supported in pure PF_KEYv2"); - return -1; -#endif -} -- cgit v1.2.3