X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=userapps%2Fopensource%2Fipsec-tools%2Fsrc%2Fracoon%2Fpfkey.c;fp=userapps%2Fopensource%2Fipsec-tools%2Fsrc%2Fracoon%2Fpfkey.c;h=0000000000000000000000000000000000000000;hb=3f05a9da74f56df22d185b66ee663a6fd8053cb3;hp=7a24189eac5029fba7ef05d3eda69f171548e8b9;hpb=864458111a0e69d94bbae210d5b7349ca072a6b7;p=bcm963xx.git diff --git a/userapps/opensource/ipsec-tools/src/racoon/pfkey.c b/userapps/opensource/ipsec-tools/src/racoon/pfkey.c deleted file mode 100755 index 7a24189e..00000000 --- a/userapps/opensource/ipsec-tools/src/racoon/pfkey.c +++ /dev/null @@ -1,2856 +0,0 @@ -/* $Id: pfkey.c,v 1.27.2.3 2005/02/18 10:09:55 vanhu Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#include - -#ifdef ENABLE_NATT -# ifdef __linux__ -# include -# endif -# if defined(__NetBSD__) || defined(__FreeBSD__) -# include -# endif -#endif - -#include -#include -#include -#include -//#include - -#include -#include - -#include -#ifndef HAVE_NETINET6_IPSEC -#include -#else -#include -#endif - -#include "libpfkey.h" - -#include "var.h" -#include "misc.h" -#include "vmbuf.h" -#include "plog.h" -#include "sockmisc.h" -#include "debug.h" - -#include "schedule.h" -#include "localconf.h" -#include "remoteconf.h" -#include "isakmp_var.h" -#include "isakmp.h" -#include "isakmp_inf.h" -#include "ipsec_doi.h" -#include "oakley.h" -#include "pfkey.h" -#include "handler.h" -#include "policy.h" -#include "algorithm.h" -#include "sainfo.h" -#include "proposal.h" -#include "admin.h" -#include "strnames.h" -#include "backupsa.h" -#include "gcmalloc.h" -#include "nattraversal.h" -#include "crypto_openssl.h" -#include "grabmyaddr.h" - -#if defined(SADB_X_EALG_RIJNDAELCBC) && !defined(SADB_X_EALG_AESCBC) -#define SADB_X_EALG_AESCBC SADB_X_EALG_RIJNDAELCBC -#endif - -/* prototype */ -static u_int ipsecdoi2pfkey_aalg __P((u_int)); -static u_int ipsecdoi2pfkey_ealg __P((u_int)); -static u_int ipsecdoi2pfkey_calg __P((u_int)); -static u_int ipsecdoi2pfkey_alg __P((u_int, u_int)); -static u_int keylen_aalg __P((u_int)); -static u_int keylen_ealg __P((u_int, int)); - -static int pk_recvgetspi __P((caddr_t *)); -static int pk_recvupdate __P((caddr_t *)); -static int pk_recvadd __P((caddr_t *)); -static int pk_recvdelete __P((caddr_t *)); -static int pk_recvacquire __P((caddr_t *)); -static int pk_recvexpire __P((caddr_t *)); -static int pk_recvflush __P((caddr_t *)); -static int getsadbpolicy __P((caddr_t *, int *, int, struct ph2handle *)); -static int pk_recvspdupdate __P((caddr_t *)); -static int pk_recvspdadd __P((caddr_t *)); -static int pk_recvspddelete __P((caddr_t *)); -static int pk_recvspdexpire __P((caddr_t *)); -static int pk_recvspdget __P((caddr_t *)); -static int pk_recvspddump __P((caddr_t *)); -static int pk_recvspdflush __P((caddr_t *)); -static struct sadb_msg *pk_recv __P((int, int *)); - -static int (*pkrecvf[]) __P((caddr_t *)) = { -NULL, -pk_recvgetspi, -pk_recvupdate, -pk_recvadd, -pk_recvdelete, -NULL, /* SADB_GET */ -pk_recvacquire, -NULL, /* SABD_REGISTER */ -pk_recvexpire, -pk_recvflush, -NULL, /* SADB_DUMP */ -NULL, /* SADB_X_PROMISC */ -NULL, /* SADB_X_PCHANGE */ -pk_recvspdupdate, -pk_recvspdadd, -pk_recvspddelete, -pk_recvspdget, -NULL, /* SADB_X_SPDACQUIRE */ -pk_recvspddump, -pk_recvspdflush, -NULL, /* SADB_X_SPDSETIDX */ -pk_recvspdexpire, -NULL, /* SADB_X_SPDDELETE2 */ -NULL, /* SADB_X_NAT_T_NEW_MAPPING */ -}; - -static int addnewsp __P((caddr_t *)); - -/* cope with old kame headers - ugly */ -#ifndef SADB_X_AALG_MD5 -#define SADB_X_AALG_MD5 SADB_AALG_MD5 -#endif -#ifndef SADB_X_AALG_SHA -#define SADB_X_AALG_SHA SADB_AALG_SHA -#endif -#ifndef SADB_X_AALG_NULL -#define SADB_X_AALG_NULL SADB_AALG_NULL -#endif - -#ifndef SADB_X_EALG_BLOWFISHCBC -#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC -#endif -#ifndef SADB_X_EALG_CAST128CBC -#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC -#endif -#ifndef SADB_X_EALG_RC5CBC -#ifdef SADB_EALG_RC5CBC -#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC -#endif -#endif - -/* - * PF_KEY packet handler - * 0: success - * -1: fail - */ -int -pfkey_handler() -{ - struct sadb_msg *msg; - int len; - caddr_t mhp[SADB_EXT_MAX + 1]; - int error = -1; - - /* receive pfkey message. */ - len = 0; - msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len); - if (msg == NULL) { - if (len < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to recv from pfkey (%s)\n", - strerror(errno)); - goto end; - } else { - /* short message - msg not ready */ - return 0; - } - } - - plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n", - s_pfkey_type(msg->sadb_msg_type)); - plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3); - - /* validity check */ - if (msg->sadb_msg_errno) { - int pri; - - /* when SPD is empty, treat the state as no error. */ - if (msg->sadb_msg_type == SADB_X_SPDDUMP && - msg->sadb_msg_errno == ENOENT) - pri = LLV_DEBUG; - else - pri = LLV_ERROR; - - plog(pri, LOCATION, NULL, - "pfkey %s failed: %s\n", - s_pfkey_type(msg->sadb_msg_type), - strerror(msg->sadb_msg_errno)); - - goto end; - } - - /* check pfkey message. */ - if (pfkey_align(msg, mhp)) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed pfkey align (%s)\n", - ipsec_strerror()); - goto end; - } - if (pfkey_check(mhp)) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed pfkey check (%s)\n", - ipsec_strerror()); - goto end; - } - msg = (struct sadb_msg *)mhp[0]; - - /* safety check */ - if (msg->sadb_msg_type >= ARRAYLEN(pkrecvf)) { - plog(LLV_ERROR, LOCATION, NULL, - "unknown PF_KEY message type=%u\n", - msg->sadb_msg_type); - goto end; - } - - if (pkrecvf[msg->sadb_msg_type] == NULL) { - plog(LLV_INFO, LOCATION, NULL, - "unsupported PF_KEY message %s\n", - s_pfkey_type(msg->sadb_msg_type)); - goto end; - } - - if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0) - goto end; - - error = 0; -end: - if (msg) - racoon_free(msg); - return(error); -} - -/* - * dump SADB - */ -vchar_t * -pfkey_dump_sadb(satype) - int satype; -{ - int s = -1; - vchar_t *buf = NULL; - pid_t pid = getpid(); - struct sadb_msg *msg = NULL; - size_t bl, ml; - int len; - - if ((s = pfkey_open()) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed pfkey open: %s\n", - ipsec_strerror()); - return NULL; - } - - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n"); - if (pfkey_send_dump(s, satype) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed dump: %s\n", ipsec_strerror()); - goto fail; - } - - while (1) { - if (msg) - racoon_free(msg); - msg = pk_recv(s, &len); - if (msg == NULL) { - if (len < 0) - goto done; - else - continue; - } - - if (msg->sadb_msg_type != SADB_DUMP || msg->sadb_msg_pid != pid) - continue; - - ml = msg->sadb_msg_len << 3; - bl = buf ? buf->l : 0; - buf = vrealloc(buf, bl + ml); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to reallocate buffer to dump.\n"); - goto fail; - } - memcpy(buf->v + bl, msg, ml); - - if (msg->sadb_msg_seq == 0) - break; - } - goto done; - -fail: - if (buf) - vfree(buf); - buf = NULL; -done: - if (msg) - racoon_free(msg); - if (s >= 0) - close(s); - return buf; -} - -#ifdef ENABLE_ADMINPORT -/* - * flush SADB - */ -void -pfkey_flush_sadb(proto) - u_int proto; -{ - int satype; - - /* convert to SADB_SATYPE */ - if ((satype = admin2pfkey_proto(proto)) < 0) - return; - - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_flush\n"); - if (pfkey_send_flush(lcconf->sock_pfkey, satype) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send flush (%s)\n", ipsec_strerror()); - return; - } - - return; -} -#endif - -/* - * These are the SATYPEs that we manage. We register to get - * PF_KEY messages related to these SATYPEs, and we also use - * this list to determine which SATYPEs to delete SAs for when - * we receive an INITIAL-CONTACT. - */ -const struct pfkey_satype pfkey_satypes[] = { - { SADB_SATYPE_AH, "AH" }, - { SADB_SATYPE_ESP, "ESP" }, - { SADB_X_SATYPE_IPCOMP, "IPCOMP" }, -}; -const int pfkey_nsatypes = - sizeof(pfkey_satypes) / sizeof(pfkey_satypes[0]); - -/* - * PF_KEY initialization - */ -int -pfkey_init() -{ - int i, reg_fail; - - if ((lcconf->sock_pfkey = pfkey_open()) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed pfkey open (%s)\n", ipsec_strerror()); - return -1; - } - - for (i = 0, reg_fail = 0; i < pfkey_nsatypes; i++) { - plog(LLV_DEBUG, LOCATION, NULL, - "call pfkey_send_register for %s\n", - pfkey_satypes[i].ps_name); - if (pfkey_send_register(lcconf->sock_pfkey, - pfkey_satypes[i].ps_satype) < 0 || - pfkey_recv_register(lcconf->sock_pfkey) < 0) { - plog(LLV_WARNING, LOCATION, NULL, - "failed to register %s (%s)\n", - pfkey_satypes[i].ps_name, - ipsec_strerror()); - reg_fail++; - } - } - - if (reg_fail == pfkey_nsatypes) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to regist any protocol.\n"); - pfkey_close(lcconf->sock_pfkey); - return -1; - } - - initsp(); - - if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec sending spddump failed: %s\n", - ipsec_strerror()); - pfkey_close(lcconf->sock_pfkey); - return -1; - } -#if 0 - if (pfkey_promisc_toggle(1) < 0) { - pfkey_close(lcconf->sock_pfkey); - return -1; - } -#endif - return 0; -} - -/* %%% for conversion */ -/* IPSECDOI_ATTR_AUTH -> SADB_AALG */ -static u_int -ipsecdoi2pfkey_aalg(hashtype) - u_int hashtype; -{ - switch (hashtype) { - case IPSECDOI_ATTR_AUTH_HMAC_MD5: - return SADB_AALG_MD5HMAC; - case IPSECDOI_ATTR_AUTH_HMAC_SHA1: - return SADB_AALG_SHA1HMAC; - case IPSECDOI_ATTR_AUTH_KPDK: /* need special care */ - return SADB_AALG_NONE; - - /* not supported */ - case IPSECDOI_ATTR_AUTH_DES_MAC: - plog(LLV_ERROR, LOCATION, NULL, - "Not supported hash type: %u\n", hashtype); - return ~0; - - case 0: /* reserved */ - default: - return SADB_AALG_NONE; - - plog(LLV_ERROR, LOCATION, NULL, - "Invalid hash type: %u\n", hashtype); - return ~0; - } - /*NOTREACHED*/ -} - -/* IPSECDOI_ESP -> SADB_EALG */ -static u_int -ipsecdoi2pfkey_ealg(t_id) - u_int t_id; -{ - switch (t_id) { - case IPSECDOI_ESP_DES_IV64: /* sa_flags |= SADB_X_EXT_OLD */ - return SADB_EALG_DESCBC; - case IPSECDOI_ESP_DES: - return SADB_EALG_DESCBC; - case IPSECDOI_ESP_3DES: - return SADB_EALG_3DESCBC; -#ifdef SADB_X_EALG_RC5CBC - case IPSECDOI_ESP_RC5: - return SADB_X_EALG_RC5CBC; -#endif - case IPSECDOI_ESP_CAST: - return SADB_X_EALG_CAST128CBC; - case IPSECDOI_ESP_BLOWFISH: - return SADB_X_EALG_BLOWFISHCBC; - case IPSECDOI_ESP_DES_IV32: /* flags |= (SADB_X_EXT_OLD| - SADB_X_EXT_IV4B)*/ - return SADB_EALG_DESCBC; - case IPSECDOI_ESP_NULL: - return SADB_EALG_NULL; -#ifdef SADB_X_EALG_AESCBC - case IPSECDOI_ESP_AES: - return SADB_X_EALG_AESCBC; -#endif -#ifdef SADB_X_EALG_TWOFISHCBC - case IPSECDOI_ESP_TWOFISH: - return SADB_X_EALG_TWOFISHCBC; -#endif - - /* not supported */ - case IPSECDOI_ESP_3IDEA: - case IPSECDOI_ESP_IDEA: - case IPSECDOI_ESP_RC4: - plog(LLV_ERROR, LOCATION, NULL, - "Not supported transform: %u\n", t_id); - return ~0; - - case 0: /* reserved */ - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid transform id: %u\n", t_id); - return ~0; - } - /*NOTREACHED*/ -} - -/* IPCOMP -> SADB_CALG */ -static u_int -ipsecdoi2pfkey_calg(t_id) - u_int t_id; -{ - switch (t_id) { - case IPSECDOI_IPCOMP_OUI: - return SADB_X_CALG_OUI; - case IPSECDOI_IPCOMP_DEFLATE: - return SADB_X_CALG_DEFLATE; - case IPSECDOI_IPCOMP_LZS: - return SADB_X_CALG_LZS; - - case 0: /* reserved */ - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid transform id: %u\n", t_id); - return ~0; - } - /*NOTREACHED*/ -} - -/* IPSECDOI_PROTO -> SADB_SATYPE */ -u_int -ipsecdoi2pfkey_proto(proto) - u_int proto; -{ - switch (proto) { - case IPSECDOI_PROTO_IPSEC_AH: - return SADB_SATYPE_AH; - case IPSECDOI_PROTO_IPSEC_ESP: - return SADB_SATYPE_ESP; - case IPSECDOI_PROTO_IPCOMP: - return SADB_X_SATYPE_IPCOMP; - - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid ipsec_doi proto: %u\n", proto); - return ~0; - } - /*NOTREACHED*/ -} - -static u_int -ipsecdoi2pfkey_alg(algclass, type) - u_int algclass, type; -{ - switch (algclass) { - case IPSECDOI_ATTR_AUTH: - return ipsecdoi2pfkey_aalg(type); - case IPSECDOI_PROTO_IPSEC_ESP: - return ipsecdoi2pfkey_ealg(type); - case IPSECDOI_PROTO_IPCOMP: - return ipsecdoi2pfkey_calg(type); - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid ipsec_doi algclass: %u\n", algclass); - return ~0; - } - /*NOTREACHED*/ -} - -/* SADB_SATYPE -> IPSECDOI_PROTO */ -u_int -pfkey2ipsecdoi_proto(satype) - u_int satype; -{ - switch (satype) { - case SADB_SATYPE_AH: - return IPSECDOI_PROTO_IPSEC_AH; - case SADB_SATYPE_ESP: - return IPSECDOI_PROTO_IPSEC_ESP; - case SADB_X_SATYPE_IPCOMP: - return IPSECDOI_PROTO_IPCOMP; - - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid pfkey proto: %u\n", satype); - return ~0; - } - /*NOTREACHED*/ -} - -/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ -u_int -ipsecdoi2pfkey_mode(mode) - u_int mode; -{ - switch (mode) { - case IPSECDOI_ATTR_ENC_MODE_TUNNEL: -#ifdef ENABLE_NATT - case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC: - case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT: -#endif - return IPSEC_MODE_TUNNEL; - case IPSECDOI_ATTR_ENC_MODE_TRNS: -#ifdef ENABLE_NATT - case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC: - case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT: -#endif - return IPSEC_MODE_TRANSPORT; - default: - plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); - return ~0; - } - /*NOTREACHED*/ -} - -/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ -u_int -pfkey2ipsecdoi_mode(mode) - u_int mode; -{ - switch (mode) { - case IPSEC_MODE_TUNNEL: - return IPSECDOI_ATTR_ENC_MODE_TUNNEL; - case IPSEC_MODE_TRANSPORT: - return IPSECDOI_ATTR_ENC_MODE_TRNS; - case IPSEC_MODE_ANY: - return IPSECDOI_ATTR_ENC_MODE_ANY; - default: - plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); - return ~0; - } - /*NOTREACHED*/ -} - -/* default key length for encryption algorithm */ -static u_int -keylen_aalg(hashtype) - u_int hashtype; -{ - int res; - - if (hashtype == 0) - return SADB_AALG_NONE; - - res = alg_ipsec_hmacdef_hashlen(hashtype); - if (res == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid hmac algorithm %u.\n", hashtype); - return ~0; - } - return res; -} - -/* default key length for encryption algorithm */ -static u_int -keylen_ealg(enctype, encklen) - u_int enctype; - int encklen; -{ - int res; - - res = alg_ipsec_encdef_keylen(enctype, encklen); - if (res == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algorithm %u.\n", enctype); - return ~0; - } - return res; -} - -int -pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, - e_type, e_keylen, a_type, a_keylen, flags) - u_int proto_id; - u_int t_id; - u_int hashtype; - u_int *e_type; - u_int *e_keylen; - u_int *a_type; - u_int *a_keylen; - u_int *flags; -{ - *flags = 0; - switch (proto_id) { - case IPSECDOI_PROTO_IPSEC_ESP: - if ((*e_type = ipsecdoi2pfkey_ealg(t_id)) == ~0) - goto bad; - if ((*e_keylen = keylen_ealg(t_id, *e_keylen)) == ~0) - goto bad; - *e_keylen >>= 3; - - if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) - goto bad; - if ((*a_keylen = keylen_aalg(hashtype)) == ~0) - goto bad; - *a_keylen >>= 3; - - if (*e_type == SADB_EALG_NONE) { - plog(LLV_ERROR, LOCATION, NULL, "no ESP algorithm.\n"); - goto bad; - } - break; - - case IPSECDOI_PROTO_IPSEC_AH: - if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) - goto bad; - if ((*a_keylen = keylen_aalg(hashtype)) == ~0) - goto bad; - *a_keylen >>= 3; - - if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 - && hashtype == IPSECDOI_ATTR_AUTH_KPDK) { - /* AH_MD5 + Auth(KPDK) = RFC1826 keyed-MD5 */ - *a_type = SADB_X_AALG_MD5; - *flags |= SADB_X_EXT_OLD; - } - *e_type = SADB_EALG_NONE; - *e_keylen = 0; - if (*a_type == SADB_AALG_NONE) { - plog(LLV_ERROR, LOCATION, NULL, "no AH algorithm.\n"); - goto bad; - } - break; - - case IPSECDOI_PROTO_IPCOMP: - if ((*e_type = ipsecdoi2pfkey_calg(t_id)) == ~0) - goto bad; - *e_keylen = 0; - - *flags = SADB_X_EXT_RAWCPI; - - *a_type = SADB_AALG_NONE; - *a_keylen = 0; - if (*e_type == SADB_X_CALG_NONE) { - plog(LLV_ERROR, LOCATION, NULL, "no IPCOMP algorithm.\n"); - goto bad; - } - break; - - default: - plog(LLV_ERROR, LOCATION, NULL, "unknown IPsec protocol.\n"); - goto bad; - } - - return 0; - - bad: - errno = EINVAL; - return -1; -} - -/* called from scheduler */ -void -pfkey_timeover_stub(p) - void *p; -{ - - pfkey_timeover((struct ph2handle *)p); -} - -void -pfkey_timeover(iph2) - struct ph2handle *iph2; -{ - plog(LLV_ERROR, LOCATION, NULL, - "%s give up to get IPsec-SA due to time up to wait.\n", - saddrwop2str(iph2->dst)); - SCHED_KILL(iph2->sce); - - /* If initiator side, send error to kernel by SADB_ACQUIRE. */ - if (iph2->side == INITIATOR) - pk_sendeacquire(iph2); - - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - - return; -} - -/*%%%*/ -/* send getspi message per ipsec protocol per remote address */ -/* - * the local address and remote address in ph1handle are dealed - * with destination address and source address respectively. - * Because SPI is decided by responder. - */ -int -pk_sendgetspi(iph2) - struct ph2handle *iph2; -{ - struct sockaddr *src = NULL, *dst = NULL; - u_int satype, mode; - struct saprop *pp; - struct saproto *pr; - u_int32_t minspi, maxspi; - int proxy = 0; - - if (iph2->side == INITIATOR) { - pp = iph2->proposal; - proxy = iph2->ph1->rmconf->support_proxy; - } else { - pp = iph2->approval; - if (iph2->sainfo && iph2->sainfo->id_i) - proxy = 1; - } - - /* for mobile IPv6 */ - if (proxy && iph2->src_id && iph2->dst_id && - ipsecdoi_transportmode(pp)) { - src = iph2->src_id; - dst = iph2->dst_id; - } else { - src = iph2->src; - dst = iph2->dst; - } - - for (pr = pp->head; pr != NULL; pr = pr->next) { - - /* validity check */ - satype = ipsecdoi2pfkey_proto(pr->proto_id); - if (satype == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", pr->proto_id); - return -1; - } - /* this works around a bug in Linux kernel where it allocates 4 byte - spi's for IPCOMP */ - else if (satype == SADB_X_SATYPE_IPCOMP) { - minspi = ntohl (0x100); - maxspi = ntohl (0xffff); - } - else { - minspi = 0; - maxspi = 0; - } - mode = ipsecdoi2pfkey_mode(pr->encmode); - if (mode == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encmode %d\n", pr->encmode); - return -1; - } - - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n"); - if (pfkey_send_getspi( - lcconf->sock_pfkey, - satype, - mode, - dst, /* src of SA */ - src, /* dst of SA */ - minspi, maxspi, - pr->reqid_in, iph2->seq) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ipseclib failed send getspi (%s)\n", - ipsec_strerror()); - return -1; - } - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey GETSPI sent: %s\n", - sadbsecas2str(dst, src, satype, 0, mode)); - } - - return 0; -} - -/* - * receive GETSPI from kernel. - */ -static int -pk_recvgetspi(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_sa *sa; - struct ph2handle *iph2; - struct sockaddr *dst; - int proto_id; - int allspiok, notfound; - struct saprop *pp; - struct saproto *pr; - - /* validity check */ - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb getspi message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */ - - /* the message has to be processed or not ? */ - if (msg->sadb_msg_pid != getpid()) { - plog(LLV_DEBUG, LOCATION, NULL, - "%s message is not interesting " - "because pid %d is not mine.\n", - s_pfkey_type(msg->sadb_msg_type), - msg->sadb_msg_pid); - return -1; - } - - iph2 = getph2byseq(msg->sadb_msg_seq); - if (iph2 == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, - "seq %d of %s message not interesting.\n", - msg->sadb_msg_seq, - s_pfkey_type(msg->sadb_msg_type)); - return -1; - } - - if (iph2->status != PHASE2ST_GETSPISENT) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatch (db:%d msg:%d)\n", - iph2->status, PHASE2ST_GETSPISENT); - return -1; - } - - /* set SPI, and check to get all spi whether or not */ - allspiok = 1; - notfound = 1; - proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); - pp = iph2->side == INITIATOR ? iph2->proposal : iph2->approval; - - for (pr = pp->head; pr != NULL; pr = pr->next) { - if (pr->proto_id == proto_id && pr->spi == 0) { - pr->spi = sa->sadb_sa_spi; - notfound = 0; - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey GETSPI succeeded: %s\n", - sadbsecas2str(iph2->dst, iph2->src, - msg->sadb_msg_satype, - sa->sadb_sa_spi, - ipsecdoi2pfkey_mode(pr->encmode))); - } - if (pr->spi == 0) - allspiok = 0; /* not get all spi */ - } - - if (notfound) { - plog(LLV_ERROR, LOCATION, NULL, - "get spi for unknown address %s\n", - saddrwop2str(iph2->dst)); - return -1; - } - - if (allspiok) { - /* update status */ - iph2->status = PHASE2ST_GETSPIDONE; - if (isakmp_post_getspi(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to start post getspi.\n"); - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - iph2 = NULL; - return -1; - } - } - - return 0; -} - -/* - * set inbound SA - */ -int -pk_sendupdate(iph2) - struct ph2handle *iph2; -{ - struct saproto *pr; - struct sockaddr *src = NULL, *dst = NULL; - int e_type, e_keylen, a_type, a_keylen, flags; - u_int satype, mode; - u_int64_t lifebyte = 0; - u_int wsize = 4; /* XXX static size of window */ - int proxy = 0; - struct ph2natt natt; - - /* sanity check */ - if (iph2->approval == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no approvaled SAs found.\n"); - } - - if (iph2->side == INITIATOR) - proxy = iph2->ph1->rmconf->support_proxy; - else if (iph2->sainfo && iph2->sainfo->id_i) - proxy = 1; - - /* for mobile IPv6 */ - if (proxy && iph2->src_id && iph2->dst_id && - ipsecdoi_transportmode(iph2->approval)) { - src = iph2->src_id; - dst = iph2->dst_id; - } else { - src = iph2->src; - dst = iph2->dst; - } - - for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { - /* validity check */ - satype = ipsecdoi2pfkey_proto(pr->proto_id); - if (satype == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", pr->proto_id); - return -1; - } - else if (satype == SADB_X_SATYPE_IPCOMP) { - /* IPCOMP has no replay window */ - wsize = 0; - } -#ifdef ENABLE_SAMODE_UNSPECIFIED - mode = IPSEC_MODE_ANY; -#else - mode = ipsecdoi2pfkey_mode(pr->encmode); - if (mode == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encmode %d\n", pr->encmode); - return -1; - } -#endif - - /* set algorithm type and key length */ - e_keylen = pr->head->encklen; - if (pfkey_convertfromipsecdoi( - pr->proto_id, - pr->head->trns_id, - pr->head->authtype, - &e_type, &e_keylen, - &a_type, &a_keylen, &flags) < 0) - return -1; - -#if 0 - lifebyte = iph2->approval->lifebyte * 1024, -#else - lifebyte = 0; -#endif - -#ifdef ENABLE_NATT - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update_nat\n"); - if (pr->udp_encap) { - memset (&natt, 0, sizeof (natt)); - natt.type = iph2->ph1->natt_options->encaps_type; - natt.sport = extract_port (iph2->ph1->remote); - natt.dport = extract_port (iph2->ph1->local); - natt.oa = NULL; // FIXME: Here comes OA!!! - } - else - memset (&natt, 0, sizeof (natt)); - - if (pfkey_send_update_nat( - lcconf->sock_pfkey, - satype, - mode, - dst, - src, - pr->spi, - pr->reqid_in, - wsize, - pr->keymat->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, lifebyte, iph2->approval->lifetime, 0, - iph2->seq, - natt.type, natt.sport, natt.dport, natt.oa) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send update_nat (%s)\n", - ipsec_strerror()); - return -1; - } -#else - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n"); - if (pfkey_send_update( - lcconf->sock_pfkey, - satype, - mode, - dst, - src, - pr->spi, - pr->reqid_in, - wsize, - pr->keymat->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, lifebyte, iph2->approval->lifetime, 0, - iph2->seq) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send update (%s)\n", - ipsec_strerror()); - return -1; - } -#endif /* ENABLE_NATT */ - - if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) - continue; - - /* - * It maybe good idea to call backupsa_to_file() after - * racoon will receive the sadb_update messages. - * But it is impossible because there is not key in the - * information from the kernel. - */ - if (backupsa_to_file(satype, mode, dst, src, - pr->spi, pr->reqid_in, 4, - pr->keymat->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, iph2->approval->lifebyte * 1024, - iph2->approval->lifetime, 0, - iph2->seq) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "backuped SA failed: %s\n", - sadbsecas2str(dst, src, - satype, pr->spi, mode)); - } - plog(LLV_DEBUG, LOCATION, NULL, - "backuped SA: %s\n", - sadbsecas2str(dst, src, - satype, pr->spi, mode)); - } - - return 0; -} - -static int -pk_recvupdate(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_sa *sa; - struct sockaddr *src, *dst; - struct ph2handle *iph2; - u_int proto_id, encmode, sa_mode; - int incomplete = 0; - struct saproto *pr; - - /* ignore this message because of local test mode. */ - if (f_local) - return 0; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb update message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); - sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; - - sa_mode = mhp[SADB_X_EXT_SA2] == NULL - ? IPSEC_MODE_ANY - : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - - /* the message has to be processed or not ? */ - if (msg->sadb_msg_pid != getpid()) { - plog(LLV_DEBUG, LOCATION, NULL, - "%s message is not interesting " - "because pid %d is not mine.\n", - s_pfkey_type(msg->sadb_msg_type), - msg->sadb_msg_pid); - return -1; - } - - iph2 = getph2byseq(msg->sadb_msg_seq); - if (iph2 == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, - "seq %d of %s message not interesting.\n", - msg->sadb_msg_seq, - s_pfkey_type(msg->sadb_msg_type)); - return -1; - } - - if (iph2->status != PHASE2ST_ADDSA) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatch (db:%d msg:%d)\n", - iph2->status, PHASE2ST_ADDSA); - return -1; - } - - /* check to complete all keys ? */ - for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { - proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); - if (proto_id == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", msg->sadb_msg_satype); - return -1; - } - encmode = pfkey2ipsecdoi_mode(sa_mode); - if (encmode == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encmode %d\n", sa_mode); - return -1; - } - - if (pr->proto_id == proto_id - && pr->spi == sa->sadb_sa_spi) { - pr->ok = 1; - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey UPDATE succeeded: %s\n", - sadbsecas2str(iph2->dst, iph2->src, - msg->sadb_msg_satype, - sa->sadb_sa_spi, - sa_mode)); - - plog(LLV_INFO, LOCATION, NULL, - "IPsec-SA established: %s\n", - sadbsecas2str(iph2->dst, iph2->src, - msg->sadb_msg_satype, sa->sadb_sa_spi, - sa_mode)); - } - - if (pr->ok == 0) - incomplete = 1; - } - - if (incomplete) - return 0; - - /* turn off the timer for calling pfkey_timeover() */ - SCHED_KILL(iph2->sce); - - /* update status */ - iph2->status = PHASE2ST_ESTABLISHED; - -#ifdef ENABLE_STATS - gettimeofday(&iph2->end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase2", "quick", timedelta(&iph2->start, &iph2->end)); -#endif - - /* count up */ - iph2->ph1->ph2cnt++; - - /* turn off schedule */ - if (iph2->scr) - SCHED_KILL(iph2->scr); - - /* - * since we are going to reuse the phase2 handler, we need to - * remain it and refresh all the references between ph1 and ph2 to use. - */ - /* XXX ??? - */ -/* unbindph12(iph2);*/ - - iph2->sce = sched_new(iph2->approval->lifetime, - isakmp_ph2expire_stub, iph2); - - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - return 0; -} - -/* - * set outbound SA - */ -int -pk_sendadd(iph2) - struct ph2handle *iph2; -{ - struct saproto *pr; - struct sockaddr *src = NULL, *dst = NULL; - int e_type, e_keylen, a_type, a_keylen, flags; - u_int satype, mode; - u_int64_t lifebyte = 0; - u_int wsize = 4; /* XXX static size of window */ - int proxy = 0; - struct ph2natt natt; - - /* sanity check */ - if (iph2->approval == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no approvaled SAs found.\n"); - } - - if (iph2->side == INITIATOR) - proxy = iph2->ph1->rmconf->support_proxy; - else if (iph2->sainfo && iph2->sainfo->id_i) - proxy = 1; - - /* for mobile IPv6 */ - if (proxy && iph2->src_id && iph2->dst_id && - ipsecdoi_transportmode(iph2->approval)) { - src = iph2->src_id; - dst = iph2->dst_id; - } else { - src = iph2->src; - dst = iph2->dst; - } - - for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { - /* validity check */ - satype = ipsecdoi2pfkey_proto(pr->proto_id); - if (satype == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", pr->proto_id); - return -1; - } - else if (satype == SADB_X_SATYPE_IPCOMP) { - /* no replay window for IPCOMP */ - wsize = 0; - } -#ifdef ENABLE_SAMODE_UNSPECIFIED - mode = IPSEC_MODE_ANY; -#else - mode = ipsecdoi2pfkey_mode(pr->encmode); - if (mode == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encmode %d\n", pr->encmode); - return -1; - } -#endif - - /* set algorithm type and key length */ - e_keylen = pr->head->encklen; - if (pfkey_convertfromipsecdoi( - pr->proto_id, - pr->head->trns_id, - pr->head->authtype, - &e_type, &e_keylen, - &a_type, &a_keylen, &flags) < 0) - return -1; - -#if 0 - lifebyte = iph2->approval->lifebyte * 1024, -#else - lifebyte = 0; -#endif - -#ifdef ENABLE_NATT - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add_nat\n"); - - if (pr->udp_encap) { - memset (&natt, 0, sizeof (natt)); - natt.type = UDP_ENCAP_ESPINUDP; - natt.sport = extract_port (iph2->ph1->local); - natt.dport = extract_port (iph2->ph1->remote); - natt.oa = NULL; // FIXME: Here comes OA!!! - } - else - memset (&natt, 0, sizeof (natt)); - - if (pfkey_send_add_nat( - lcconf->sock_pfkey, - satype, - mode, - src, - dst, - pr->spi_p, - pr->reqid_out, - wsize, - pr->keymat_p->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, lifebyte, iph2->approval->lifetime, 0, - iph2->seq, - natt.type, natt.sport, natt.dport, natt.oa) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send add_nat (%s)\n", - ipsec_strerror()); - return -1; - } -#else - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n"); - - if (pfkey_send_add( - lcconf->sock_pfkey, - satype, - mode, - src, - dst, - pr->spi_p, - pr->reqid_out, - wsize, - pr->keymat_p->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, lifebyte, iph2->approval->lifetime, 0, - iph2->seq) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send add (%s)\n", - ipsec_strerror()); - return -1; - } -#endif /* ENABLE_NATT */ - - if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) - continue; - - /* - * It maybe good idea to call backupsa_to_file() after - * racoon will receive the sadb_update messages. - * But it is impossible because there is not key in the - * information from the kernel. - */ - if (backupsa_to_file(satype, mode, src, dst, - pr->spi_p, pr->reqid_out, 4, - pr->keymat_p->v, - e_type, e_keylen, a_type, a_keylen, flags, - 0, iph2->approval->lifebyte * 1024, - iph2->approval->lifetime, 0, - iph2->seq) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "backuped SA failed: %s\n", - sadbsecas2str(src, dst, - satype, pr->spi_p, mode)); - } - plog(LLV_DEBUG, LOCATION, NULL, - "backuped SA: %s\n", - sadbsecas2str(src, dst, - satype, pr->spi_p, mode)); - } - - return 0; -} - -static int -pk_recvadd(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_sa *sa; - struct sockaddr *src, *dst; - struct ph2handle *iph2; - u_int sa_mode; - - /* ignore this message because of local test mode. */ - if (f_local) - return 0; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb add message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); - sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; - - sa_mode = mhp[SADB_X_EXT_SA2] == NULL - ? IPSEC_MODE_ANY - : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - - /* the message has to be processed or not ? */ - if (msg->sadb_msg_pid != getpid()) { - plog(LLV_DEBUG, LOCATION, NULL, - "%s message is not interesting " - "because pid %d is not mine.\n", - s_pfkey_type(msg->sadb_msg_type), - msg->sadb_msg_pid); - return -1; - } - - iph2 = getph2byseq(msg->sadb_msg_seq); - if (iph2 == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, - "seq %d of %s message not interesting.\n", - msg->sadb_msg_seq, - s_pfkey_type(msg->sadb_msg_type)); - return -1; - } - - /* - * NOTE don't update any status of phase2 handle - * because they must be updated by SADB_UPDATE message - */ - - plog(LLV_INFO, LOCATION, NULL, - "IPsec-SA established: %s\n", - sadbsecas2str(iph2->src, iph2->dst, - msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); - - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - return 0; -} - -static int -pk_recvexpire(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_sa *sa; - struct sockaddr *src, *dst; - struct ph2handle *iph2; - u_int proto_id, sa_mode; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || (mhp[SADB_EXT_LIFETIME_HARD] != NULL - && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb expire message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); - - sa_mode = mhp[SADB_X_EXT_SA2] == NULL - ? IPSEC_MODE_ANY - : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - - proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); - if (proto_id == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", msg->sadb_msg_satype); - return -1; - } - - plog(LLV_INFO, LOCATION, NULL, - "IPsec-SA expired: %s\n", - sadbsecas2str(src, dst, - msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); - - iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); - if (iph2 == NULL) { - /* - * Ignore it because two expire messages are come up. - * phase2 handler has been deleted already when 2nd message - * is received. - */ - plog(LLV_DEBUG, LOCATION, NULL, - "no such a SA found: %s\n", - sadbsecas2str(src, dst, - msg->sadb_msg_satype, sa->sadb_sa_spi, - sa_mode)); - return 0; - } - if (iph2->status != PHASE2ST_ESTABLISHED) { - /* - * If the status is not equal to PHASE2ST_ESTABLISHED, - * racoon ignores this expire message. There are two reason. - * One is that the phase 2 probably starts because there is - * a potential that racoon receives the acquire message - * without receiving a expire message. Another is that racoon - * may receive the multiple expire messages from the kernel. - */ - plog(LLV_WARNING, LOCATION, NULL, - "the expire message is received " - "but the handler has not been established.\n"); - return 0; - } - - /* turn off the timer for calling isakmp_ph2expire() */ - SCHED_KILL(iph2->sce); - - iph2->status = PHASE2ST_EXPIRED; - - /* INITIATOR, begin phase 2 exchange. */ - /* allocate buffer for status management of pfkey message */ - if (iph2->side == INITIATOR) { - - initph2(iph2); - - /* update status for re-use */ - iph2->status = PHASE2ST_STATUS2; - - /* start isakmp initiation by using ident exchange */ - if (isakmp_post_acquire(iph2) < 0) { - plog(LLV_ERROR, LOCATION, iph2->dst, - "failed to begin ipsec sa " - "re-negotication.\n"); - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - return -1; - } - - return 0; - /*NOTREACHED*/ - } - - /* If not received SADB_EXPIRE, INITIATOR delete ph2handle. */ - /* RESPONDER always delete ph2handle, keep silent. RESPONDER doesn't - * manage IPsec SA, so delete the list */ - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - - return 0; -} - -static int -pk_recvacquire(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_x_policy *xpl; - struct secpolicy *sp_out = NULL, *sp_in = NULL; -#define MAXNESTEDSA 5 /* XXX */ - struct ph2handle *iph2[MAXNESTEDSA]; - int n; /* # of phase 2 handler */ - - /* ignore this message because of local test mode. */ - if (f_local) - return 0; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb acquire message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - - /* ignore if type is not IPSEC_POLICY_IPSEC */ - if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { - plog(LLV_DEBUG, LOCATION, NULL, - "ignore ACQUIRE message. type is not IPsec.\n"); - return 0; - } - - /* ignore it if src is multicast address */ - { - struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); - - if ((sa->sa_family == AF_INET - && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr))) -#ifdef INET6 - || (sa->sa_family == AF_INET6 - && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr)) -#endif - ) { - plog(LLV_DEBUG, LOCATION, NULL, - "ignore due to multicast address: %s.\n", - saddrwop2str(sa)); - return 0; - } - } - - /* ignore, if we do not listen on source address */ - { - /* reasons behind: - * - if we'll contact peer from address we do not listen - - * we will be unable to complete negotiation; - * - if we'll negotiate using address we're listening - - * remote peer will send packets to address different - * than one in the policy, so kernel will drop them; - * => therefore this acquire is not for us! --Aidas - */ - struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - struct myaddrs *p; - int do_listen = 0; - for (p = lcconf->myaddrs; p; p = p->next) { - if (!cmpsaddrwop(p->addr, sa)) { - do_listen = 1; - break; - } - } - - if (!do_listen) { - plog(LLV_DEBUG, LOCATION, NULL, - "ignore because do not listen on source address : %s.\n", - saddrwop2str(sa)); - return 0; - } - } - - /* - * If there is a phase 2 handler against the policy identifier in - * the acquire message, and if - * 1. its state is less than PHASE2ST_ESTABLISHED, then racoon - * should ignore such a acquire message because the phase 2 - * is just negotiating. - * 2. its state is equal to PHASE2ST_ESTABLISHED, then racoon - * has to prcesss such a acquire message because racoon may - * lost the expire message. - */ - iph2[0] = getph2byspid(xpl->sadb_x_policy_id); - if (iph2[0] != NULL) { - if (iph2[0]->status < PHASE2ST_ESTABLISHED) { - plog(LLV_DEBUG, LOCATION, NULL, - "ignore the acquire because ph2 found\n"); - return -1; - } - if (iph2[0]->status == PHASE2ST_EXPIRED) - iph2[0] = NULL; - /*FALLTHROUGH*/ - } - - /* search for proper policyindex */ - sp_out = getspbyspid(xpl->sadb_x_policy_id); - if (sp_out == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n", - xpl->sadb_x_policy_id); - return -1; - } - plog(LLV_DEBUG, LOCATION, NULL, - "suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx)); - - /* get inbound policy */ - { - struct policyindex spidx; - - spidx.dir = IPSEC_DIR_INBOUND; - memcpy(&spidx.src, &sp_out->spidx.dst, sizeof(spidx.src)); - memcpy(&spidx.dst, &sp_out->spidx.src, sizeof(spidx.dst)); - spidx.prefs = sp_out->spidx.prefd; - spidx.prefd = sp_out->spidx.prefs; - spidx.ul_proto = sp_out->spidx.ul_proto; - - sp_in = getsp(&spidx); - if (sp_in) { - plog(LLV_DEBUG, LOCATION, NULL, - "suitable inbound SP found: %s.\n", - spidx2str(&sp_in->spidx)); - } else { - plog(LLV_NOTIFY, LOCATION, NULL, - "no in-bound policy found: %s\n", - spidx2str(&spidx)); - } - } - - memset(iph2, 0, MAXNESTEDSA); - - n = 0; - - /* allocate a phase 2 */ - iph2[n] = newph2(); - if (iph2[n] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate phase2 entry.\n"); - return -1; - } - iph2[n]->side = INITIATOR; - iph2[n]->spid = xpl->sadb_x_policy_id; - iph2[n]->satype = msg->sadb_msg_satype; - iph2[n]->seq = msg->sadb_msg_seq; - iph2[n]->status = PHASE2ST_STATUS2; - - /* set end addresses of SA */ - iph2[n]->dst = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST])); - if (iph2[n]->dst == NULL) { - delph2(iph2[n]); - return -1; - } - iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC])); - if (iph2[n]->src == NULL) { - delph2(iph2[n]); - return -1; - } - - plog(LLV_DEBUG, LOCATION, NULL, - "new acquire %s\n", spidx2str(&sp_out->spidx)); - - /* get sainfo */ - { - vchar_t *idsrc, *iddst; - - idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src, - sp_out->spidx.prefs, sp_out->spidx.ul_proto); - if (idsrc == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get ID for %s\n", - spidx2str(&sp_out->spidx)); - delph2(iph2[n]); - return -1; - } - iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst, - sp_out->spidx.prefd, sp_out->spidx.ul_proto); - if (iddst == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get ID for %s\n", - spidx2str(&sp_out->spidx)); - vfree(idsrc); - delph2(iph2[n]); - return -1; - } - iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL); - vfree(idsrc); - vfree(iddst); - if (iph2[n]->sainfo == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get sainfo.\n"); - delph2(iph2[n]); - return -1; - /* XXX should use the algorithm list from register message */ - } - } - - if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to create saprop.\n"); - delph2(iph2[n]); - return -1; - } - insph2(iph2[n]); - - /* start isakmp initiation by using ident exchange */ - /* XXX should be looped if there are multiple phase 2 handler. */ - if (isakmp_post_acquire(iph2[n]) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to begin ipsec sa negotication.\n"); - goto err; - } - - return 0; - -err: - while (n >= 0) { - unbindph12(iph2[n]); - remph2(iph2[n]); - delph2(iph2[n]); - iph2[n] = NULL; - n--; - } - return -1; -} - -static int -pk_recvdelete(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_sa *sa; - struct sockaddr *src, *dst; - struct ph2handle *iph2 = NULL; - u_int proto_id; - - /* ignore this message because of local test mode. */ - if (f_local) - return 0; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb acquire message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); - - /* the message has to be processed or not ? */ - if (msg->sadb_msg_pid == getpid()) { - plog(LLV_DEBUG, LOCATION, NULL, - "%s message is not interesting " - "because the message was originated by me.\n", - s_pfkey_type(msg->sadb_msg_type)); - return -1; - } - - proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); - if (proto_id == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", msg->sadb_msg_satype); - return -1; - } - - iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); - if (iph2 == NULL) { - /* ignore */ - plog(LLV_ERROR, LOCATION, NULL, - "no iph2 found: %s\n", - sadbsecas2str(src, dst, msg->sadb_msg_satype, - sa->sadb_sa_spi, IPSEC_MODE_ANY)); - return 0; - } - - plog(LLV_ERROR, LOCATION, NULL, - "pfkey DELETE received: %s\n", - sadbsecas2str(iph2->src, iph2->dst, - msg->sadb_msg_satype, sa->sadb_sa_spi, IPSEC_MODE_ANY)); - - /* send delete information */ - if (iph2->status == PHASE2ST_ESTABLISHED) - isakmp_info_send_d2(iph2); - - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - - return 0; -} - -static int -pk_recvflush(mhp) - caddr_t *mhp; -{ - /* ignore this message because of local test mode. */ - if (f_local) - return 0; - - /* sanity check */ - if (mhp[0] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb acquire message passed.\n"); - return -1; - } - - flushph2(); - - return 0; -} - -static int -getsadbpolicy(policy0, policylen0, type, iph2) - caddr_t *policy0; - int *policylen0, type; - struct ph2handle *iph2; -{ - struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; - struct sadb_x_policy *xpl; - struct sadb_x_ipsecrequest *xisr; - struct saproto *pr; - caddr_t policy, p; - int policylen; - int xisrlen; - u_int satype, mode; - - /* get policy buffer size */ - policylen = sizeof(struct sadb_x_policy); - if (type != SADB_X_SPDDELETE) { - for (pr = iph2->approval->head; pr; pr = pr->next) { - xisrlen = sizeof(*xisr); - if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { - xisrlen += (sysdep_sa_len(iph2->src) - + sysdep_sa_len(iph2->dst)); - } - - policylen += PFKEY_ALIGN8(xisrlen); - } - } - - /* make policy structure */ - policy = racoon_malloc(policylen); - if (!policy) { - plog(LLV_ERROR, LOCATION, NULL, - "buffer allocation failed.\n"); - return -1; - } - - xpl = (struct sadb_x_policy *)policy; - xpl->sadb_x_policy_len = PFKEY_UNIT64(policylen); - xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; - xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC; - xpl->sadb_x_policy_dir = spidx->dir; - xpl->sadb_x_policy_id = 0; -#ifdef HAVE_PFKEY_POLICY_PRIORITY - xpl->sadb_x_policy_priority = PRIORITY_DEFAULT; -#endif - - /* no need to append policy information any more if type is SPDDELETE */ - if (type == SADB_X_SPDDELETE) - goto end; - - xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); - - for (pr = iph2->approval->head; pr; pr = pr->next) { - - satype = doi2ipproto(pr->proto_id); - if (satype == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto_id %d\n", pr->proto_id); - goto err; - } - mode = ipsecdoi2pfkey_mode(pr->encmode); - if (mode == ~0) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encmode %d\n", pr->encmode); - goto err; - } - - /* - * the policy level cannot be unique because the policy - * is defined later than SA, so req_id cannot be bound to SA. - */ - xisr->sadb_x_ipsecrequest_proto = satype; - xisr->sadb_x_ipsecrequest_mode = mode; - xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; - xisr->sadb_x_ipsecrequest_reqid = 0; - p = (caddr_t)(xisr + 1); - - xisrlen = sizeof(*xisr); - - if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { - int src_len, dst_len; - - src_len = sysdep_sa_len(iph2->src); - dst_len = sysdep_sa_len(iph2->dst); - xisrlen += src_len + dst_len; - - memcpy(p, iph2->src, src_len); - p += src_len; - - memcpy(p, iph2->dst, dst_len); - p += dst_len; - } - - xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen); - } - -end: - *policy0 = policy; - *policylen0 = policylen; - - return 0; - -err: - if (policy) - racoon_free(policy); - - return -1; -} - -int -pk_sendspdupdate2(iph2) - struct ph2handle *iph2; -{ - struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; - caddr_t policy = NULL; - int policylen = 0; - u_int64_t ltime, vtime; - - ltime = iph2->approval->lifetime; - vtime = 0; - - if (getsadbpolicy(&policy, &policylen, SADB_X_SPDUPDATE, iph2)) { - plog(LLV_ERROR, LOCATION, NULL, - "getting sadb policy failed.\n"); - return -1; - } - - if (pfkey_send_spdupdate2( - lcconf->sock_pfkey, - (struct sockaddr *)&spidx->src, - spidx->prefs, - (struct sockaddr *)&spidx->dst, - spidx->prefd, - spidx->ul_proto, - ltime, vtime, - policy, policylen, 0) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send spdupdate2 (%s)\n", - ipsec_strerror()); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdupdate2\n"); - -end: - if (policy) - racoon_free(policy); - - return 0; -} - -static int -pk_recvspdupdate(mhp) - caddr_t *mhp; -{ - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - struct policyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spdupdate message passed.\n"); - return -1; - } - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &spidx); -#endif - - sp = getsp(&spidx); - if (sp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "such policy does not already exist: %s\n", - spidx2str(&spidx)); - } else { - remsp(sp); - delsp(sp); - } - - if (addnewsp(mhp) < 0) - return -1; - - return 0; -} - -/* - * this function has to be used by responder side. - */ -int -pk_sendspdadd2(iph2) - struct ph2handle *iph2; -{ - struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; - caddr_t policy = NULL; - int policylen = 0; - u_int64_t ltime, vtime; - - ltime = iph2->approval->lifetime; - vtime = 0; - - if (getsadbpolicy(&policy, &policylen, SADB_X_SPDADD, iph2)) { - plog(LLV_ERROR, LOCATION, NULL, - "getting sadb policy failed.\n"); - return -1; - } - - if (pfkey_send_spdadd2( - lcconf->sock_pfkey, - (struct sockaddr *)&spidx->src, - spidx->prefs, - (struct sockaddr *)&spidx->dst, - spidx->prefd, - spidx->ul_proto, - ltime, vtime, - policy, policylen, 0) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send spdadd2 (%s)\n", - ipsec_strerror()); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdadd2\n"); - -end: - if (policy) - racoon_free(policy); - - return 0; -} - -static int -pk_recvspdadd(mhp) - caddr_t *mhp; -{ - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - struct policyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spdadd message passed.\n"); - return -1; - } - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &spidx); -#endif - - sp = getsp(&spidx); - if (sp != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "such policy already exists. " - "anyway replace it: %s\n", - spidx2str(&spidx)); - remsp(sp); - delsp(sp); - } - - if (addnewsp(mhp) < 0) - return -1; - - return 0; -} - -/* - * this function has to be used by responder side. - */ -int -pk_sendspddelete(iph2) - struct ph2handle *iph2; -{ - struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; - caddr_t policy = NULL; - int policylen; - - if (getsadbpolicy(&policy, &policylen, SADB_X_SPDDELETE, iph2)) { - plog(LLV_ERROR, LOCATION, NULL, - "getting sadb policy failed.\n"); - return -1; - } - - if (pfkey_send_spddelete( - lcconf->sock_pfkey, - (struct sockaddr *)&spidx->src, - spidx->prefs, - (struct sockaddr *)&spidx->dst, - spidx->prefd, - spidx->ul_proto, - policy, policylen, 0) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "libipsec failed send spddelete (%s)\n", - ipsec_strerror()); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spddelete\n"); - -end: - if (policy) - racoon_free(policy); - - return 0; -} - -static int -pk_recvspddelete(mhp) - caddr_t *mhp; -{ - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - struct policyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spddelete message passed.\n"); - return -1; - } - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &spidx); -#endif - - sp = getsp(&spidx); - if (sp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no policy found: %s\n", - spidx2str(&spidx)); - return -1; - } - - remsp(sp); - delsp(sp); - - return 0; -} - -static int -pk_recvspdexpire(mhp) - caddr_t *mhp; -{ - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - struct policyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (mhp[0] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spdexpire message passed.\n"); - return -1; - } - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &spidx); -#endif - - sp = getsp(&spidx); - if (sp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no policy found: %s\n", - spidx2str(&spidx)); - return -1; - } - - remsp(sp); - delsp(sp); - - return 0; -} - -static int -pk_recvspdget(mhp) - caddr_t *mhp; -{ - /* sanity check */ - if (mhp[0] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spdget message passed.\n"); - return -1; - } - - return 0; -} - -static int -pk_recvspddump(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg; - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - struct policyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (mhp[0] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spddump message passed.\n"); - return -1; - } - msg = (struct sadb_msg *)mhp[0]; - - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - - if (saddr == NULL || daddr == NULL || xpl == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spddump message passed.\n"); - return -1; - } - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &spidx); -#endif - - sp = getsp(&spidx); - if (sp != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "such policy already exists. " - "anyway replace it: %s\n", - spidx2str(&spidx)); - remsp(sp); - delsp(sp); - } - - if (addnewsp(mhp) < 0) - return -1; - - return 0; -} - -static int -pk_recvspdflush(mhp) - caddr_t *mhp; -{ - /* sanity check */ - if (mhp[0] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spdflush message passed.\n"); - return -1; - } - - flushsp(); - - return 0; -} - -/* - * send error against acquire message to kenrel. - */ -int -pk_sendeacquire(iph2) - struct ph2handle *iph2; -{ - struct sadb_msg *newmsg; - int len; - - len = sizeof(struct sadb_msg); - newmsg = racoon_calloc(1, len); - if (newmsg == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send acquire.\n"); - return -1; - } - - memset(newmsg, 0, len); - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = SADB_ACQUIRE; - newmsg->sadb_msg_errno = ENOENT; /* XXX */ - newmsg->sadb_msg_satype = iph2->satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_reserved = 0; - newmsg->sadb_msg_seq = iph2->seq; - newmsg->sadb_msg_pid = (u_int32_t)getpid(); - - /* send message */ - len = pfkey_send(lcconf->sock_pfkey, newmsg, len); - - racoon_free(newmsg); - - return 0; -} - -/* - * check if the algorithm is supported or not. - * OUT 0: ok - * -1: ng - */ -int -pk_checkalg(class, calg, keylen) - int class, calg, keylen; -{ - int sup, error; - u_int alg; - struct sadb_alg alg0; - - switch (algclass2doi(class)) { - case IPSECDOI_PROTO_IPSEC_ESP: - sup = SADB_EXT_SUPPORTED_ENCRYPT; - break; - case IPSECDOI_ATTR_AUTH: - sup = SADB_EXT_SUPPORTED_AUTH; - break; - case IPSECDOI_PROTO_IPCOMP: - plog(LLV_DEBUG, LOCATION, NULL, - "compression algorithm can not be checked " - "because sadb message doesn't support it.\n"); - return 0; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid algorithm class.\n"); - return -1; - } - alg = ipsecdoi2pfkey_alg(algclass2doi(class), algtype2doi(class, calg)); - if (alg == ~0) - return -1; - - if (keylen == 0) { - if (ipsec_get_keylen(sup, alg, &alg0)) { - plog(LLV_ERROR, LOCATION, NULL, - "%s.\n", ipsec_strerror()); - return -1; - } - keylen = alg0.sadb_alg_minbits; - } - - error = ipsec_check_keylen(sup, alg, keylen); - if (error) - plog(LLV_ERROR, LOCATION, NULL, - "%s.\n", ipsec_strerror()); - - return error; -} - -/* - * differences with pfkey_recv() in libipsec/pfkey.c: - * - never performs busy wait loop. - * - returns NULL and set *lenp to negative on fatal failures - * - returns NULL and set *lenp to non-negative on non-fatal failures - * - returns non-NULL on success - */ -static struct sadb_msg * -pk_recv(so, lenp) - int so; - int *lenp; -{ - struct sadb_msg buf, *newmsg; - int reallen; - - *lenp = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK); - if (*lenp < 0) - return NULL; /*fatal*/ - else if (*lenp < sizeof(buf)) - return NULL; - - reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); - if ((newmsg = racoon_calloc(1, reallen)) == NULL) - return NULL; - - *lenp = recv(so, (caddr_t)newmsg, reallen, MSG_PEEK); - if (*lenp < 0) { - racoon_free(newmsg); - return NULL; /*fatal*/ - } else if (*lenp != reallen) { - racoon_free(newmsg); - return NULL; - } - - *lenp = recv(so, (caddr_t)newmsg, reallen, 0); - if (*lenp < 0) { - racoon_free(newmsg); - return NULL; /*fatal*/ - } else if (*lenp != reallen) { - racoon_free(newmsg); - return NULL; - } - - return newmsg; -} - -/* see handler.h */ -u_int32_t -pk_getseq() -{ - return eay_random(); -} - -static int -addnewsp(mhp) - caddr_t *mhp; -{ - struct secpolicy *new; - struct sadb_address *saddr, *daddr; - struct sadb_x_policy *xpl; - - /* sanity check */ - if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "inappropriate sadb spd management message passed.\n"); - return -1; - } - - saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; - -#ifdef __linux__ - /* bsd skips over per-socket policies because there will be no - * src and dst extensions in spddump messages. On Linux the only - * way to achieve the same is check for policy id. - */ - if (xpl->sadb_x_policy_id % 8 >= 3) return 0; -#endif - - new = newsp(); - if (new == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate buffer\n"); - return -1; - } - - new->spidx.dir = xpl->sadb_x_policy_dir; - new->id = xpl->sadb_x_policy_id; - new->policy = xpl->sadb_x_policy_type; - new->req = NULL; - - /* check policy */ - switch (xpl->sadb_x_policy_type) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - case IPSEC_POLICY_ENTRUST: - case IPSEC_POLICY_BYPASS: - break; - - case IPSEC_POLICY_IPSEC: - { - int tlen; - struct sadb_x_ipsecrequest *xisr; - struct ipsecrequest **p_isr = &new->req; - - /* validity check */ - if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid msg length.\n"); - return -1; - } - - tlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); - - while (tlen > 0) { - - /* length check */ - if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid msg length.\n"); - return -1; - } - - /* allocate request buffer */ - *p_isr = newipsecreq(); - if (*p_isr == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get new ipsecreq.\n"); - return -1; - } - - /* set values */ - (*p_isr)->next = NULL; - - switch (xisr->sadb_x_ipsecrequest_proto) { - case IPPROTO_ESP: - case IPPROTO_AH: - case IPPROTO_IPCOMP: - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid proto type: %u\n", - xisr->sadb_x_ipsecrequest_proto); - return -1; - } - (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; - - switch (xisr->sadb_x_ipsecrequest_mode) { - case IPSEC_MODE_TRANSPORT: - case IPSEC_MODE_TUNNEL: - break; - case IPSEC_MODE_ANY: - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid mode: %u\n", - xisr->sadb_x_ipsecrequest_mode); - return -1; - } - (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; - - switch (xisr->sadb_x_ipsecrequest_level) { - case IPSEC_LEVEL_DEFAULT: - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - case IPSEC_LEVEL_UNIQUE: - (*p_isr)->saidx.reqid = - xisr->sadb_x_ipsecrequest_reqid; - break; - - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid level: %u\n", - xisr->sadb_x_ipsecrequest_level); - return -1; - } - (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; - - /* set IP addresses if there */ - if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { - struct sockaddr *paddr; - - paddr = (struct sockaddr *)(xisr + 1); - bcopy(paddr, &(*p_isr)->saidx.src, - sysdep_sa_len(paddr)); - - paddr = (struct sockaddr *)((caddr_t)paddr - + sysdep_sa_len(paddr)); - bcopy(paddr, &(*p_isr)->saidx.dst, - sysdep_sa_len(paddr)); - } - - (*p_isr)->sp = new; - - /* initialization for the next. */ - p_isr = &(*p_isr)->next; - tlen -= xisr->sadb_x_ipsecrequest_len; - - /* validity check */ - if (tlen < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "becoming tlen < 0\n"); - } - - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); - } - } - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid policy type.\n"); - return -1; - } - -#ifdef HAVE_PFKEY_POLICY_PRIORITY - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - xpl->sadb_x_policy_priority, - &new->spidx); -#else - KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, - saddr + 1, - daddr + 1, - saddr->sadb_address_prefixlen, - daddr->sadb_address_prefixlen, - saddr->sadb_address_proto, - &new->spidx); -#endif - - inssp(new); - - return 0; -} - -/* proto/mode/src->dst spi */ -const char * -sadbsecas2str(src, dst, proto, spi, mode) - struct sockaddr *src, *dst; - int proto; - u_int32_t spi; - int mode; -{ - static char buf[256]; - u_int doi_proto, doi_mode = 0; - char *p; - int blen, i; - - doi_proto = pfkey2ipsecdoi_proto(proto); - if (doi_proto == ~0) - return NULL; - if (mode) { - doi_mode = pfkey2ipsecdoi_mode(mode); - if (doi_mode == ~0) - return NULL; - } - - blen = sizeof(buf) - 1; - p = buf; - - i = snprintf(p, blen, "%s%s%s ", - s_ipsecdoi_proto(doi_proto), - mode ? "/" : "", - mode ? s_ipsecdoi_encmode(doi_mode) : ""); - if (i < 0 || i >= blen) - return NULL; - p += i; - blen -= i; - - i = snprintf(p, blen, "%s->", saddrwop2str(src)); - if (i < 0 || i >= blen) - return NULL; - p += i; - blen -= i; - - i = snprintf(p, blen, "%s ", saddrwop2str(dst)); - if (i < 0 || i >= blen) - return NULL; - p += i; - blen -= i; - - if (spi) { - snprintf(p, blen, "spi=%lu(0x%lx)", (unsigned long)ntohl(spi), - (unsigned long)ntohl(spi)); - } - - return buf; -}