From 50ba589c666f7d356304339b9cfc7fc9d173ad8d Mon Sep 17 00:00:00 2001 From: shin Date: Wed, 22 Dec 1999 19:13:38 +0000 Subject: IPSEC support in the kernel. pr_input() routines prototype is also changed to support IPSEC and IPV6 chained protocol headers. Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project --- sys/netkey/key.c | 7360 +++++++++++++++++++++++++++++++++--------------- sys/netkey/key.h | 367 +-- sys/netkey/key_debug.c | 1262 ++++----- sys/netkey/key_debug.h | 240 +- sys/netkey/key_var.h | 40 +- sys/netkey/keysock.c | 542 ++++ sys/netkey/keysock.h | 2 +- 7 files changed, 6346 insertions(+), 3467 deletions(-) create mode 100644 sys/netkey/keysock.c (limited to 'sys/netkey') diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 0116b2a..d9ec961 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,2558 +1,5316 @@ /* - * modified by Jun-ichiro itojun Itoh , 1997 - */ -/*---------------------------------------------------------------------- - key.c : Key Management Engine for BSD - - Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald, - All Rights Reserved. All Rights have been assigned to the US - Naval Research Laboratory (NRL). The NRL Copyright Notice and - License governs distribution and use of this software. - - Patents are pending on this technology. NRL grants a license - to use this technology at no cost under the terms below with - the additional requirement that software, hardware, and - documentation relating to use of this technology must include - the note that: - This product includes technology developed at and - licensed from the Information Technology Division, - US Naval Research Laboratory. - -----------------------------------------------------------------------*/ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - -#include "opt_key.h" - -#ifdef KEY + * 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. + * + * $FreeBSD$ + */ + +/* KAME $Id: key.c,v 1.1.6.5.2.19 1999/07/22 14:09:24 itojun Exp $ */ + +/* + * This code is referd to RFC 2367 + */ +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" + +#include #include #include #include -#include -#include #include -#include +#include #include +#include #include #include +#include +#include +#include +#include -#include #include -#include #include +#include #include +#include +#include #include #include #ifdef INET6 -#include +#include #include +#include #endif /* INET6 */ +#include +#include +#include #include +#include +#ifdef IPSEC_DEBUG #include +#else +#define KEYDEBUG(lev,arg) +#endif + +#include +#include +#ifdef INET6 +#include +#include +#endif +#ifdef IPSEC_ESP +#include +#ifdef INET6 +#include +#endif +#endif + +MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); + +#if defined(IPSEC_DEBUG) +u_int32_t key_debug_level = 0; +#endif /* defined(IPSEC_DEBUG) */ +static u_int key_spi_trycnt = 1000; +static u_int32_t key_spi_minval = 0x100; +static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */ +static u_int key_int_random = 60; /*interval to initialize randseed,1(m)*/ +static u_int key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/ +static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/ +static int key_blockacq_lifetime = 20; /* lifetime for blocking SADB_ACQUIRE.*/ + +static u_int32_t acq_seq = 0; +static int key_tick_init_random = 0; + +static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD */ +static LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */ +static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1]; + /* registed list */ +#ifndef IPSEC_NONBLOCK_ACQUIRE +static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */ +#endif + +struct key_cb key_cb; + +/* search order for SAs */ +static u_int saorder_state_valid[] = { + SADB_SASTATE_MATURE, SADB_SASTATE_DYING +}; +static u_int saorder_state_alive[] = { + /* except DEAD */ + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL +}; +static u_int saorder_state_any[] = { + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, + SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD +}; + +#if defined(IPSEC_DEBUG) +SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ + &key_debug_level, 0, ""); +#endif /* defined(IPSEC_DEBUG) */ + +/* max count of trial for the decision of spi value */ +SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ + &key_spi_trycnt, 0, ""); + +/* minimum spi value to allocate automatically. */ +SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ + &key_spi_minval, 0, ""); + +/* maximun spi value to allocate automatically. */ +SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ + &key_spi_maxval, 0, ""); + +/* interval to initialize randseed */ +SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ + &key_int_random, 0, ""); + +/* lifetime for larval SA */ +SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ + &key_larval_lifetime, 0, ""); + +/* counter for blocking to send SADB_ACQUIRE to IKEd */ +SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ + &key_blockacq_count, 0, ""); + +/* lifetime for blocking to send SADB_ACQUIRE to IKEd */ +SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ + &key_blockacq_lifetime, 0, ""); + +#define __LIST_FOREACH(elm, head, field) \ + for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field)) +#define __LIST_CHAINED(elm) \ + (!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL)) + +#define KEY_CHKSASTATE(head, sav, name) { \ + if ((head) != (sav)) { \ + printf("%s: state mismatched (TREE=%d SA=%d)\n", \ + (name), (head), (sav)); \ + continue; \ + } \ +} + +#define KEY_CHKSPDIR(head, sp, name) { \ + if ((head) != (sp)) { \ + printf("%s: direction mismatched (TREE=%d SP=%d), " \ + "anyway continue.\n", \ + (name), (head), (sp)); \ + } \ +} -static MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); +#define KMALLOC(p, t, n) \ + ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) +#define KFREE(p) \ + free((caddr_t)(p), M_SECA); -#define KMALLOC(p, t, n) (p = (t) malloc((unsigned long)(n), M_SECA, M_DONTWAIT)) -#define KFREE(p) free((caddr_t)p, M_SECA); +#define KEY_NEWBUF(dst, t, src, len) \ + ((dst) = (t)key_newbuf((src), (len))) -#define CRITICAL_DCL int critical_s; -#define CRITICAL_START critical_s = splnet() -#define CRITICAL_END splx(critical_s) +/* + * set parameters into secpolicyindex buffer. + * Must allocate secpolicyindex buffer passed to this function. + */ +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) do { \ + bzero((idx), sizeof(struct secpolicyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) +/* + * set parameters into secasindex buffer. + * Must allocate secasindex buffer before calling this function. + */ +#define KEY_SETSECASIDX(p, m, s, d, idx) do { \ + bzero((idx), sizeof(struct secasindex)); \ + (idx)->proto = (p); \ + (idx)->mode = (m); \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) + +/* key statistics */ +struct _keystat { + u_long getspi_count; /* the avarage of count to try to get new SPI */ +} keystat; + +static struct secasvar *key_allocsa_policy __P((struct ipsecrequest *isr)); +static void key_freesp_so __P((struct secpolicy **sp)); +static struct secasvar *key_do_allocsa_policy __P((struct secashead *sah, + u_int state)); +static void key_delsp __P((struct secpolicy *sp)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *spidx)); +static struct sadb_msg *key_spdadd __P((caddr_t *mhp)); +static struct sadb_msg *key_spddelete __P((caddr_t *mhp)); +static struct sadb_msg *key_spdflush __P((caddr_t *mhp)); +static int key_spddump __P((caddr_t *mhp, struct socket *so, int target)); +static u_int key_setdumpsp __P((struct sadb_msg *newmsg, struct secpolicy *sp, + u_int8_t type, u_int32_t seq, u_int32_t pid)); +static u_int key_getspmsglen __P((struct secpolicy *sp)); +static u_int key_getspreqmsglen __P((struct secpolicy *sp)); +static struct secashead *key_newsah __P((struct secasindex *saidx)); +static void key_delsah __P((struct secashead *sah)); +static struct secasvar *key_newsav __P((caddr_t *mhp, struct secashead *sah)); +static void key_delsav __P((struct secasvar *sav)); +static struct secashead *key_getsah __P((struct secasindex *saidx)); +static struct secasvar *key_checkspidup __P((struct secasindex *saidx, + u_int32_t spi)); +static struct secasvar *key_getsavbyspi __P((struct secashead *sah, + u_int32_t spi)); +static int key_setsaval __P((struct secasvar *sav, caddr_t *mhp)); +static u_int key_getmsglen __P((struct secasvar *sav)); +static int key_mature __P((struct secasvar *sav)); +static u_int key_setdumpsa __P((struct sadb_msg *newmsg, struct secasvar *sav, + u_int8_t type, u_int8_t satype, + u_int32_t seq, u_int32_t pid)); +static caddr_t key_setsadbmsg __P((caddr_t buf, u_int8_t type, int tlen, + u_int8_t satype, u_int32_t seq, pid_t pid, + u_int8_t reserved1, u_int8_t reserved2)); +static caddr_t key_setsadbsa __P((caddr_t buf, struct secasvar *sav)); +static caddr_t key_setsadbaddr __P((caddr_t buf, u_int16_t exttype, + struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); +static caddr_t key_setsadbident + __P((caddr_t buf, u_int16_t exttype, u_int16_t idtype, + caddr_t string, int stringlen, u_int64_t id)); +static caddr_t key_setsadbext __P((caddr_t p, caddr_t ext)); +static void *key_newbuf __P((void *src, u_int len)); #ifdef INET6 -#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in6)) -#else -#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in)) +static int key_ismyaddr6 __P((caddr_t addr)); #endif +static int key_cmpsaidx_exactly + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpsaidx_withmode + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpspidx_exactly + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_cmpspidx_withmask + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_bbcmp __P((caddr_t p1, caddr_t p2, u_int bits)); +static u_int16_t key_satype2proto __P((u_int8_t satype)); +static u_int8_t key_proto2satype __P((u_int16_t proto)); + +static struct sadb_msg *key_getspi __P((caddr_t *mhp)); +static u_int32_t key_do_getnewspi __P((struct sadb_spirange *spirange, + struct secasindex *saidx)); +static struct sadb_msg *key_update __P((caddr_t *mhp)); +static struct secasvar *key_getsavbyseq __P((struct secashead *sah, + u_int32_t seq)); +static struct sadb_msg *key_add __P((caddr_t *mhp)); +static struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *mhp)); +static struct sadb_msg *key_delete __P((caddr_t *mhp)); +static struct sadb_msg *key_get __P((caddr_t *mhp)); +static int key_acquire __P((struct secasindex *saidx, + struct secpolicyindex *spidx)); +static struct secacq *key_newacq __P((struct secasindex *saidx)); +static struct secacq *key_getacq __P((struct secasindex *saidx)); +static struct secacq *key_getacqbyseq __P((u_int32_t seq)); +static struct sadb_msg *key_acquire2 __P((caddr_t *mhp)); +static struct sadb_msg *key_register __P((caddr_t *mhp, struct socket *so)); +static int key_expire __P((struct secasvar *sav)); +static struct sadb_msg *key_flush __P((caddr_t *mhp)); +static int key_dump __P((caddr_t *mhp, struct socket *so, int target)); +static void key_promisc __P((caddr_t *mhp, struct socket *so)); +static int key_sendall __P((struct sadb_msg *msg, u_int len)); +static int key_align __P((struct sadb_msg *msg, caddr_t *mhp)); +static void key_sa_chgstate __P((struct secasvar *sav, u_int8_t state)); +/* %%% IPsec policy management */ +/* + * allocating a SP for OUTBOUND or INBOUND packet. + * Must call key_freesp() later. + * OUT: NULL: not found + * others: found and return the pointer. + */ +struct secpolicy * +key_allocsp(spidx, dir) + struct secpolicyindex *spidx; + u_int dir; +{ + struct secpolicy *sp; + int s; + + /* sanity check */ + if (spidx == NULL) + panic("key_allocsp: NULL pointer is passed.\n"); + + /* check direction */ + switch (dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + panic("key_allocsp: Invalid direction is passed.\n"); + } + + /* get a SP entry */ + s = splnet(); /*called from softclock()*/ + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** objects\n"); + kdebug_secpolicyindex(spidx)); + + __LIST_FOREACH(sp, &sptree[dir], chain) { + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** in SPD\n"); + kdebug_secpolicyindex(&sp->spidx)); + + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + if (key_cmpspidx_withmask(&sp->spidx, spidx)) + goto found; + } + + splx(s); + return NULL; + +found: + /* sanity check */ + KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); + + /* found a SPD entry */ + sp->refcnt++; + splx(s); + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP key_allocsp cause refcnt++:%d SP:%p\n", + sp->refcnt, sp)); + + return sp; +} /* - * Not clear whether these values should be - * tweakable at kernel config time. - */ -#define KEYTBLSIZE 61 -#define KEYALLOCTBLSIZE 61 -#define SO2SPITBLSIZE 61 - -/* - * These values should be tweakable... - * perhaps by using sysctl - */ - -#define MAXLARVALTIME 240; /* Lifetime of a larval key table entry */ -#define MAXKEYACQUIRE 1; /* Max number of key acquire messages sent */ - /* per destination address */ -#define MAXACQUIRETIME 15; /* Lifetime of acquire message */ - -/* - * Key engine tables and global variables - */ - -struct key_tblnode keytable[KEYTBLSIZE]; -struct key_allocnode keyalloctbl[KEYALLOCTBLSIZE]; -struct key_so2spinode so2spitbl[SO2SPITBLSIZE]; - -struct keyso_cb keyso_cb; -struct key_tblnode nullkeynode; -struct key_registry *keyregtable; -struct key_acquirelist *key_acquirelist; -u_long maxlarvallifetime = MAXLARVALTIME; -int maxkeyacquire = MAXKEYACQUIRE; -u_long maxacquiretime = MAXACQUIRETIME; - -extern struct sockaddr key_addr; - -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define ADVANCE(x, n) \ - { x += ROUNDUP(n); } - -static int addrpart_equal __P((struct sockaddr *, struct sockaddr *)); -static int key_gethashval __P((char *, int, int)); -static int key_createkey __P((char *, u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, u_int)); -static struct key_so2spinode *key_sosearch __P((u_int, struct sockaddr *, - struct sockaddr *, struct socket *)); -static void key_deleteacquire __P((u_int, struct sockaddr *)); -static struct key_tblnode *key_search __P((u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, int, struct key_tblnode **)); -static struct key_tblnode *key_addnode __P((int, struct key_secassoc *)); -static int key_alloc __P((u_int, struct sockaddr *, struct sockaddr *, - struct socket *, u_int, struct key_tblnode **)); -static int key_xdata __P((struct key_msghdr *, struct key_msgdata *, int)); -static int key_sendup __P((struct socket *, struct key_msghdr *)); -static void key_init __P((void)); -static int my_addr __P((struct sockaddr *)); -static int key_output __P((struct mbuf *, struct socket *)); -static int key_attach __P((struct socket *, int, struct proc *)); -static int key_detach __P((struct socket *)); -static void key_cbinit __P((void)); - -/*---------------------------------------------------------------------- - * key_secassoc2msghdr(): - * Copy info from a security association into a key message buffer. - * Assume message buffer is sufficiently large to hold all security - * association information including src, dst, from, key and iv. - ----------------------------------------------------------------------*/ + * checking each request entries in SP, and acquire SA if need. + * OUT: 0: there are valid requests. + * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. + */ int -key_secassoc2msghdr(secassoc, km, keyinfo) - struct key_secassoc *secassoc; - struct key_msghdr *km; - struct key_msgdata *keyinfo; -{ - char *cp; - DPRINTF(IDL_FINISHED, ("Entering key_secassoc2msghdr\n")); - - if ((km == 0) || (keyinfo == 0) || (secassoc == 0)) - return(-1); - - km->type = secassoc->type; - km->vers = secassoc->vers; - km->state = secassoc->state; - km->label = secassoc->label; - km->spi = secassoc->spi; - km->keylen = secassoc->keylen; - km->ekeylen = secassoc->ekeylen; - km->ivlen = secassoc->ivlen; - km->algorithm = secassoc->algorithm; - km->lifetype = secassoc->lifetype; - km->lifetime1 = secassoc->lifetime1; - km->lifetime2 = secassoc->lifetime2; - km->antireplay = secassoc->antireplay; - - /* - * Stuff src/dst/from/key/iv/ekey in buffer after - * the message header. - */ - cp = (char *)(km + 1); - - DPRINTF(IDL_FINISHED, ("sa2msghdr: 1\n")); - keyinfo->src = (struct sockaddr *)cp; - if (secassoc->src->sa_len) { - bcopy(secassoc->src, cp, secassoc->src->sa_len); - ADVANCE(cp, secassoc->src->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } - - DPRINTF(IDL_FINISHED, ("sa2msghdr: 2\n")); - keyinfo->dst = (struct sockaddr *)cp; - if (secassoc->dst->sa_len) { - bcopy(secassoc->dst, cp, secassoc->dst->sa_len); - ADVANCE(cp, secassoc->dst->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } +key_checkrequest(isr) + struct ipsecrequest *isr; +{ + u_int level; + int error; + + /* sanity check */ + if (isr == NULL) + panic("key_checkrequest: NULL pointer is passed.\n"); + + /* check mode */ + switch (isr->saidx.mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: + panic("key_checkrequest: Invalid policy defined.\n"); + } - DPRINTF(IDL_FINISHED, ("sa2msghdr: 3\n")); - keyinfo->from = (struct sockaddr *)cp; - if (secassoc->from->sa_len) { - bcopy(secassoc->from, cp, secassoc->from->sa_len); - ADVANCE(cp, secassoc->from->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } + /* get current level */ + level = ipsec_get_reqlevel(isr); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 4\n")); + /* + * We don't allocate new SA if the state of SA in the holder is + * SADB_SASTATE_MATURE, and if this is newer one. + */ + if (isr->sav != NULL) { + /* + * XXX While SA is hanging on policy request(isr), its refcnt + * can not be zero. So isr->sav->sah is valid pointer if + * isr->sav != NULL. But that may not be true in fact. + * There may be missunderstanding by myself. Anyway I set + * zero to isr->sav->sah when isr->sav is flushed. + * I must check to have conviction this issue. + */ + if (isr->sav->sah != NULL + && isr->sav != (struct secasvar *)LIST_FIRST( + &isr->sav->sah->savtree[SADB_SASTATE_MATURE])) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP checkrequest calls free SA:%p\n", + isr->sav)); + key_freesav(isr->sav); + } + isr->sav = NULL; + } - keyinfo->key = cp; - keyinfo->keylen = secassoc->keylen; - if (secassoc->keylen) { - bcopy((char *)(secassoc->key), cp, secassoc->keylen); - ADVANCE(cp, secassoc->keylen); - } + /* new SA allocation if no SA found. */ + if (isr->sav == NULL) + isr->sav = key_allocsa_policy(isr); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 5\n")); - keyinfo->iv = cp; - keyinfo->ivlen = secassoc->ivlen; - if (secassoc->ivlen) { - bcopy((char *)(secassoc->iv), cp, secassoc->ivlen); - ADVANCE(cp, secassoc->ivlen); - } + /* When there is SA. */ + if (isr->sav != NULL) + return 0; - DPRINTF(IDL_FINISHED, ("sa2msghdr: 6\n")); - keyinfo->ekey = cp; - keyinfo->ekeylen = secassoc->ekeylen; - if (secassoc->ekeylen) { - bcopy((char *)(secassoc->ekey), cp, secassoc->ekeylen); - ADVANCE(cp, secassoc->ekeylen); - } + /* there is no SA */ + if ((error = key_acquire(&isr->saidx, &isr->sp->spidx)) != 0) { + /* XXX What I do ? */ + printf("key_checkrequest: error %d returned " + "from key_acquire.\n", error); + return error; + } - DDO(IDL_FINISHED,printf("msgbuf(len=%d):\n",(char *)cp - (char *)km)); - DDO(IDL_FINISHED,dump_buf((char *)km, (char *)cp - (char *)km)); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 6\n")); - return(0); + return level == IPSEC_LEVEL_REQUIRE ? ENOENT : 0; } +/* + * allocating a SA for policy entry from SAD. + * NOTE: searching SAD of aliving state. + * OUT: NULL: not found. + * others: found and return the pointer. + */ +static struct secasvar * +key_allocsa_policy(isr) + struct ipsecrequest *isr; +{ + struct secashead *sah; + struct secasvar *sav; + u_int stateidx, state; + + __LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withmode(&sah->saidx, &isr->saidx)) + goto found; + } -/*---------------------------------------------------------------------- - * key_msghdr2secassoc(): - * Copy info from a key message buffer into a key_secassoc - * structure - ----------------------------------------------------------------------*/ -int -key_msghdr2secassoc(secassoc, km, keyinfo) - struct key_secassoc *secassoc; - struct key_msghdr *km; - struct key_msgdata *keyinfo; -{ - DPRINTF(IDL_FINISHED, ("Entering key_msghdr2secassoc\n")); - - if ((km == 0) || (keyinfo == 0) || (secassoc == 0)) - return(-1); - - secassoc->len = sizeof(*secassoc); - secassoc->type = km->type; - secassoc->vers = km->vers; - secassoc->state = km->state; - secassoc->label = km->label; - secassoc->spi = km->spi; - secassoc->keylen = km->keylen; - secassoc->ekeylen = km->ekeylen; - secassoc->ivlen = km->ivlen; - secassoc->algorithm = km->algorithm; - secassoc->lifetype = km->lifetype; - secassoc->lifetime1 = km->lifetime1; - secassoc->lifetime2 = km->lifetime2; - secassoc->antireplay = km->antireplay; - - if (keyinfo->src) { - KMALLOC(secassoc->src, struct sockaddr *, keyinfo->src->sa_len); - if (!secassoc->src) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for src\n")); - return(-1); - } - bcopy((char *)keyinfo->src, (char *)secassoc->src, - keyinfo->src->sa_len); - } else - secassoc->src = NULL; - - if (keyinfo->dst) { - KMALLOC(secassoc->dst, struct sockaddr *, keyinfo->dst->sa_len); - if (!secassoc->dst) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for dst\n")); - return(-1); - } - bcopy((char *)keyinfo->dst, (char *)secassoc->dst, - keyinfo->dst->sa_len); - } else - secassoc->dst = NULL; - - if (keyinfo->from) { - KMALLOC(secassoc->from, struct sockaddr *, keyinfo->from->sa_len); - if (!secassoc->from) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for from\n")); - return(-1); - } - bcopy((char *)keyinfo->from, (char *)secassoc->from, - keyinfo->from->sa_len); - } else - secassoc->from = NULL; - - /* - * Make copies of key and iv - */ - if (secassoc->ivlen) { - KMALLOC(secassoc->iv, caddr_t, secassoc->ivlen); - if (secassoc->iv == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for iv\n")); - return(-1); - } - bcopy((char *)keyinfo->iv, (char *)secassoc->iv, secassoc->ivlen); - } else - secassoc->iv = NULL; - - if (secassoc->keylen) { - KMALLOC(secassoc->key, caddr_t, secassoc->keylen); - if (secassoc->key == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for key\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - return(-1); - } - bcopy((char *)keyinfo->key, (char *)secassoc->key, secassoc->keylen); - } else - secassoc->key = NULL; - - if (secassoc->ekeylen) { - KMALLOC(secassoc->ekey, caddr_t, secassoc->ekeylen); - if (secassoc->ekey == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for ekey\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - return(-1); - } - bcopy((char *)keyinfo->ekey, (char *)secassoc->ekey, secassoc->ekeylen); - } else - secassoc->ekey = NULL; + return NULL; - return(0); -} + found: + /* search valid state */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_valid); + stateidx++) { -/*---------------------------------------------------------------------- - * addrpart_equal(): - * Determine if the address portion of two sockaddrs are equal. - * Currently handles only AF_INET and AF_INET6 address families. - ----------------------------------------------------------------------*/ -static int -addrpart_equal(sa1, sa2) - struct sockaddr *sa1; - struct sockaddr *sa2; -{ - if ((sa1->sa_family != sa2->sa_family) || - (sa1->sa_len != sa2->sa_len)) - return 0; - - switch(sa1->sa_family) { - case AF_INET: - return (((struct sockaddr_in *)sa1)->sin_addr.s_addr == - ((struct sockaddr_in *)sa2)->sin_addr.s_addr); -#ifdef INET6 - case AF_INET6: - return (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr, - &((struct sockaddr_in6 *)sa2)->sin6_addr)); -#endif /* INET6 */ - } - return(0); + state = saorder_state_valid[stateidx]; + + sav = key_do_allocsa_policy(sah, state); + if (sav != NULL) + return sav; + } + + return NULL; } -/*---------------------------------------------------------------------- - * key_inittables(): - * Allocate space and initialize key engine tables - ----------------------------------------------------------------------*/ -int -key_inittables() -{ - int i; - - KMALLOC(keyregtable, struct key_registry *, sizeof(struct key_registry)); - if (!keyregtable) - return -1; - bzero((char *)keyregtable, sizeof(struct key_registry)); - KMALLOC(key_acquirelist, struct key_acquirelist *, - sizeof(struct key_acquirelist)); - if (!key_acquirelist) - return -1; - bzero((char *)key_acquirelist, sizeof(struct key_acquirelist)); - for (i = 0; i < KEYTBLSIZE; i++) - bzero((char *)&keytable[i], sizeof(struct key_tblnode)); - for (i = 0; i < KEYALLOCTBLSIZE; i++) - bzero((char *)&keyalloctbl[i], sizeof(struct key_allocnode)); - for (i = 0; i < SO2SPITBLSIZE; i++) - bzero((char *)&so2spitbl[i], sizeof(struct key_so2spinode)); - - return 0; -} - -#ifdef notyet -static int -key_freetables() +/* + * searching SAD with direction, protocol, mode and state. + * called by key_allocsa_policy(). + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_do_allocsa_policy(sah, state) + struct secashead *sah; + u_int state; { - KFREE(keyregtable); - keyregtable = NULL; - KFREE(key_acquirelist); - key_acquirelist = NULL; - return 0; -} -#endif + struct secasvar *sav, *candidate; + + /* initilize */ + candidate = NULL; + + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy"); + + /* initialize */ + if (candidate == NULL) { + candidate = sav; + continue; + } + + /* Which SA is the better ? */ + + /* sanity check 2 */ + if (candidate->lft_c == NULL || sav->lft_c == NULL) { + /*XXX do panic ? */ + printf("key_do_allocsa_policy: " + "lifetime_current is NULL.\n"); + continue; + } + + /* XXX What the best method is to compare ? */ + if (candidate->lft_c->sadb_lifetime_addtime < + sav->lft_c->sadb_lifetime_addtime) { + candidate = sav; + continue; + } + } -/*---------------------------------------------------------------------- - * key_gethashval(): - * Determine keytable hash value. - ----------------------------------------------------------------------*/ -static int -key_gethashval(buf, len, tblsize) - char *buf; - int len; - int tblsize; -{ - int i, j = 0; - - /* - * Todo: Use word size xor and check for alignment - * and zero pad if necessary. Need to also pick - * a good hash function and table size. - */ - if (len <= 0) { - DPRINTF(IDL_ERROR,("key_gethashval got bogus len!\n")); - return(-1); - } - for(i = 0; i < len; i++) { - j ^= (u_int8_t)(*(buf + i)); - } - return (j % tblsize); + if (candidate) { + candidate->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP allocsa_policy cause " + "refcnt++:%d SA:%p\n", + candidate->refcnt, candidate)); + } + return candidate; } +/* + * allocating a SA entry for a *INBOUND* packet. + * Must call key_freesav() later. + * OUT: positive: pointer to a sav. + * NULL: not found, or error occured. + */ +struct secasvar * +key_allocsa(family, src, dst, proto, spi) + u_int family, proto; + caddr_t src, dst; + u_int32_t spi; +{ + struct secashead *sah; + struct secasvar *sav; + u_int stateidx, state; + int s; + + /* sanity check */ + if (src == NULL || dst == NULL) + panic("key_allocsa: NULL pointer is passed.\n"); + + /* + * searching SAD. + * XXX: to be checked internal IP header somewhere. Also when + * IPsec tunnel packet is received. But ESP tunnel mode is + * encrypted so we can't check internal IP header. + */ + s = splnet(); /*called from softclock()*/ + __LIST_FOREACH(sah, &sahtree, chain) { + + /* search valid state */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_valid); + stateidx++) { + + state = saorder_state_valid[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + KEY_CHKSASTATE(sav->state, state, "key_allocsav"); + if (proto != sav->sah->saidx.proto) + continue; + if (spi != sav->spi) + continue; + + if (key_bbcmp(src, + _INADDRBYSA(&sav->sah->saidx.src), + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3) + && key_bbcmp(dst, + _INADDRBYSA(&sav->sah->saidx.dst), + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3)) + goto found; + } + } + } -/*---------------------------------------------------------------------- - * key_createkey(): - * Create hash key for hash function - * key is: type+src+dst if keytype = 1 - * type+src+dst+spi if keytype = 0 - * Uses only the address portion of the src and dst sockaddrs to - * form key. Currently handles only AF_INET and AF_INET6 sockaddrs - ----------------------------------------------------------------------*/ -static int -key_createkey(buf, type, src, dst, spi, keytype) - char *buf; - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - u_int keytype; + /* not found */ + splx(s); + return NULL; + +found: + sav->refcnt++; + splx(s); + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP allocsa cause refcnt++:%d SA:%p\n", + sav->refcnt, sav)); + return sav; +} + +/* + * Must be called after calling key_allocsp(). + * For both the packet without socket and key_freeso(). + */ +void +key_freesp(sp) + struct secpolicy *sp; { - char *cp, *p; + /* sanity check */ + if (sp == NULL) + panic("key_freesp: NULL pointer is passed.\n"); - DPRINTF(IDL_FINISHED,("Entering key_createkey\n")); + sp->refcnt--; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freesp cause refcnt--:%d SP:%p\n", + sp->refcnt, sp)); - if (!buf || !src || !dst) - return(-1); + if (sp->refcnt == 0) + key_delsp(sp); - cp = buf; - bcopy((char *)&type, cp, sizeof(type)); - cp += sizeof(type); + return; +} +/* + * Must be called after calling key_allocsp(). + * For the packet with socket. + */ +void +key_freeso(so) + struct socket *so; +{ + /* sanity check */ + if (so == NULL) + panic("key_freeso: NULL pointer is passed.\n"); + + switch (so->so_proto->pr_domain->dom_family) { +#ifdef INET + case PF_INET: + { + struct inpcb *pcb = sotoinpcb(so); + + /* Does it have a PCB ? */ + if (pcb == NULL) + return; + key_freesp_so(&pcb->inp_sp->sp_in); + key_freesp_so(&pcb->inp_sp->sp_out); + } + break; +#endif #ifdef INET6 - /* - * Assume only IPv4 and IPv6 addresses. - */ -#define ADDRPART(a) \ - ((a)->sa_family == AF_INET6) ? \ - (char *)&(((struct sockaddr_in6 *)(a))->sin6_addr) : \ - (char *)&(((struct sockaddr_in *)(a))->sin_addr) - -#define ADDRSIZE(a) \ - ((a)->sa_family == AF_INET6) ? sizeof(struct in6_addr) : \ - sizeof(struct in_addr) -#else /* INET6 */ -#define ADDRPART(a) (char *)&(((struct sockaddr_in *)(a))->sin_addr) -#define ADDRSIZE(a) sizeof(struct in_addr) + case PF_INET6: + { + struct in6pcb *pcb = sotoin6pcb(so); + + /* Does it have a PCB ? */ + if (pcb == NULL) + return; + key_freesp_so(&pcb->in6p_sp->sp_in); + key_freesp_so(&pcb->in6p_sp->sp_out); + } + break; #endif /* INET6 */ + default: + printf("key_freeso: unknown address family=%d.\n", + so->so_proto->pr_domain->dom_family); + return; + } + + return; +} - DPRINTF(IDL_FINISHED,("src addr:\n")); - DDO(IDL_FINISHED,dump_smart_sockaddr(src)); - DPRINTF(IDL_FINISHED,("dst addr:\n")); - DDO(IDL_FINISHED,dump_smart_sockaddr(dst)); +static void +key_freesp_so(sp) + struct secpolicy **sp; +{ + /* sanity check */ + if (sp == NULL || *sp == NULL) + panic("key_freesp_so: sp == NULL\n"); + + switch ((*sp)->policy) { + case IPSEC_POLICY_IPSEC: + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freeso calls free SP:%p\n", *sp)); + key_freesp(*sp); + *sp = NULL; + break; + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + return; + default: + panic("key_freesp_so: Invalid policy found %d", (*sp)->policy); + } - p = ADDRPART(src); - bcopy(p, cp, ADDRSIZE(src)); - cp += ADDRSIZE(src); + return; +} - p = ADDRPART(dst); - bcopy(p, cp, ADDRSIZE(dst)); - cp += ADDRSIZE(dst); +/* + * Must be called after calling key_allocsa(). + * This function is called by key_freesp() to free some SA allocated + * for a policy. + */ +void +key_freesav(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("key_freesav: NULL pointer is passed.\n"); -#undef ADDRPART -#undef ADDRSIZE + sav->refcnt--; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); - if (keytype == 0) { - bcopy((char *)&spi, cp, sizeof(spi)); - cp += sizeof(spi); - } + if (sav->refcnt == 0) + key_delsav(sav); - DPRINTF(IDL_FINISHED,("hash key:\n")); - DDO(IDL_FINISHED, dump_buf(buf, cp - buf)); - return(cp - buf); + return; } - -/*---------------------------------------------------------------------- - * key_sosearch(): - * Search the so2spi table for the security association allocated to - * the socket. Returns pointer to a struct key_so2spinode which can - * be used to locate the security association entry in the keytable. - ----------------------------------------------------------------------*/ -static struct key_so2spinode * -key_sosearch(type, src, dst, so) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *so; +/* %%% SPD management */ +/* + * free security policy entry. + */ +static void +key_delsp(sp) + struct secpolicy *sp; { - struct key_so2spinode *np = 0; + int s; - if (!(src && dst)) { - DPRINTF(IDL_ERROR,("key_sosearch: got null src or dst pointer!\n")); - return(NULL); - } + /* sanity check */ + if (sp == NULL) + panic("key_delsp: NULL pointer is passed.\n"); - for (np = so2spitbl[((u_int32_t)so) % SO2SPITBLSIZE].next; np; np = np->next) { - if ((so == np->socket) && (type == np->keynode->secassoc->type) - && addrpart_equal(src, np->keynode->secassoc->src) - && addrpart_equal(dst, np->keynode->secassoc->dst)) - return(np); - } - return(NULL); -} + sp->state = IPSEC_SPSTATE_DEAD; + if (sp->refcnt > 0) + return; /* can't free */ -/*---------------------------------------------------------------------- - * key_sodelete(): - * Delete entries from the so2spi table. - * flag = 1 purge all entries - * flag = 0 delete entries with socket pointer matching socket - ----------------------------------------------------------------------*/ -void -key_sodelete(socket, flag) - struct socket *socket; - int flag; -{ - struct key_so2spinode *prevnp, *np; - CRITICAL_DCL + s = splnet(); /*called from softclock()*/ + /* remove from SP index */ + if (__LIST_CHAINED(sp)) + LIST_REMOVE(sp, chain); - CRITICAL_START; + { + struct ipsecrequest *isr = sp->req, *nextisr; + + while (isr != NULL) { + if (isr->sav != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP delsp calls free SA:%p\n", + isr->sav)); + key_freesav(isr->sav); + isr->sav = NULL; + } + + nextisr = isr->next; + KFREE(isr); + isr = nextisr; + } + } - DPRINTF(IDL_EVENT,("Entering keysodelete w/so=0x%x flag=%d\n", - (unsigned int)socket,flag)); + KFREE(sp); - if (flag) { - int i; + splx(s); - for (i = 0; i < SO2SPITBLSIZE; i++) - for(np = so2spitbl[i].next; np; np = np->next) { - KFREE(np); - } - CRITICAL_END; - return; - } + return; +} - prevnp = &so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE]; - for(np = prevnp->next; np; np = np->next) { - if (np->socket == socket) { - struct socketlist *socklp, *prevsocklp; - - (np->keynode->alloc_count)--; - - /* - * If this socket maps to a unique secassoc, - * we go ahead and delete the secassoc, since it - * can no longer be allocated or used by any other - * socket. - */ - if (np->keynode->secassoc->state & K_UNIQUE) { - if (key_delete(np->keynode->secassoc) != 0) - panic("key_sodelete"); - np = prevnp; - continue; - } +/* + * search SPD + * OUT: NULL : not found + * others : found, pointer to a SP. + */ +static struct secpolicy * +key_getsp(spidx) + struct secpolicyindex *spidx; +{ + struct secpolicy *sp; + + /* sanity check */ + if (spidx == NULL) + panic("key_getsp: NULL pointer is passed.\n"); + + __LIST_FOREACH(sp, &sptree[spidx->dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + if (key_cmpspidx_exactly(spidx, &sp->spidx)) { + sp->refcnt++; + return sp; + } + } - /* - * We traverse the socketlist and remove the entry - * for this socket - */ - DPRINTF(IDL_FINISHED,("keysodelete: deleting from socklist...")); - prevsocklp = np->keynode->solist; - for (socklp = prevsocklp->next; socklp; socklp = socklp->next) { - if (socklp->socket == socket) { - prevsocklp->next = socklp->next; - KFREE(socklp); - break; - } - prevsocklp = socklp; - } - DPRINTF(IDL_FINISHED,("done\n")); - prevnp->next = np->next; - KFREE(np); - np = prevnp; - } - prevnp = np; - } - CRITICAL_END; + return NULL; } +struct secpolicy * +key_newsp() +{ + struct secpolicy *newsp = NULL; -/*---------------------------------------------------------------------- - * key_deleteacquire(): - * Delete an entry from the key_acquirelist - ----------------------------------------------------------------------*/ -static void -key_deleteacquire(type, target) - u_int type; - struct sockaddr *target; -{ - struct key_acquirelist *ap, *prev; - - prev = key_acquirelist; - for(ap = key_acquirelist->next; ap; ap = ap->next) { - if (addrpart_equal(target, (struct sockaddr *)&(ap->target)) && - (type == ap->type)) { - DPRINTF(IDL_EVENT,("Deleting entry from acquire list!\n")); - prev->next = ap->next; - KFREE(ap); - ap = prev; - } - prev = ap; - } + KMALLOC(newsp, struct secpolicy *, sizeof(*newsp)); + if (newsp == NULL) { + printf("key_newsp: No more memory.\n"); + return NULL; + } + bzero(newsp, sizeof(*newsp)); + + newsp->refcnt = 1; + newsp->req = NULL; + + return newsp; } +/* + * create secpolicy structure from sadb_x_policy structure. + * NOTE: `state', `secpolicyindex' in secpolicy structure are not set, + * so must be set properly later. + */ +struct secpolicy * +key_msg2sp(xpl0) + struct sadb_x_policy *xpl0; +{ + struct secpolicy *newsp; + + /* sanity check */ + if (xpl0 == NULL) + panic("key_msg2sp: NULL pointer was passed.\n"); + + if ((newsp = key_newsp()) == NULL) + return NULL; + + newsp->spidx.dir = xpl0->sadb_x_policy_dir; + newsp->policy = xpl0->sadb_x_policy_type; + + /* check policy */ + switch (xpl0->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + newsp->req = NULL; + break; + + case IPSEC_POLICY_IPSEC: + { + int tlen; + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest **p_isr = &newsp->req; + + /* validity check */ + if (PFKEY_EXTLEN(xpl0) <= sizeof(*xpl0)) { + printf("key_msg2sp: Invalid msg length.\n"); + key_freesp(newsp); + return NULL; + } + + tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0); + xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1); + + while (tlen > 0) { + + /* length check */ + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { + printf("key_msg2sp: " + "invalid ipsecrequest length.\n"); + key_freesp(newsp); + return NULL; + } + + /* allocate request buffer */ + KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr)); + if ((*p_isr) == NULL) { + printf("key_msg2sp: No more memory.\n"); + key_freesp(newsp); + return NULL; + } + bzero(*p_isr, sizeof(**p_isr)); + + /* set values */ + (*p_isr)->next = NULL; + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + break; + default: + printf("key_msg2sp: invalid proto type=%u\n", + xisr->sadb_x_ipsecrequest_proto); + key_freesp(newsp); + return NULL; + } + (*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: + printf("key_msg2sp: invalid mode=%u\n", + xisr->sadb_x_ipsecrequest_mode); + key_freesp(newsp); + return NULL; + } + (*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; + default: + printf("key_msg2sp: invalid level=%u\n", + xisr->sadb_x_ipsecrequest_level); + key_freesp(newsp); + return NULL; + } + (*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); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.src)) { + printf("key_msg2sp: invalid request " + "address length.\n"); + key_freesp(newsp); + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.src, + paddr->sa_len); + + paddr = (struct sockaddr *)((caddr_t)paddr + + paddr->sa_len); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.dst)) { + printf("key_msg2sp: invalid request " + "address length.\n"); + key_freesp(newsp); + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.dst, + paddr->sa_len); + } + + (*p_isr)->sav = NULL; + (*p_isr)->sp = newsp; + + /* initialization for the next. */ + p_isr = &(*p_isr)->next; + tlen -= xisr->sadb_x_ipsecrequest_len; + + /* validity check */ + if (tlen < 0) { + printf("key_msg2sp: becoming tlen < 0.\n"); + key_freesp(newsp); + return NULL; + } + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + } + break; + default: + printf("key_msg2sp: invalid policy type.\n"); + key_freesp(newsp); + return NULL; + } -/*---------------------------------------------------------------------- - * key_search(): - * Search the key table for an entry with same type, src addr, dest - * addr, and spi. Returns a pointer to struct key_tblnode if found - * else returns null. - ----------------------------------------------------------------------*/ -static struct key_tblnode * -key_search(type, src, dst, spi, indx, prevkeynode) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - int indx; - struct key_tblnode **prevkeynode; -{ - struct key_tblnode *keynode, *prevnode; - - if (indx > KEYTBLSIZE || indx < 0) - return (NULL); - if (!(&keytable[indx])) - return (NULL); - -#define sec_type keynode->secassoc->type -#define sec_spi keynode->secassoc->spi -#define sec_src keynode->secassoc->src -#define sec_dst keynode->secassoc->dst - - prevnode = &keytable[indx]; - for (keynode = keytable[indx].next; keynode; keynode = keynode->next) { - if ((type == sec_type) && (spi == sec_spi) && - addrpart_equal(src, sec_src) - && addrpart_equal(dst, sec_dst)) - break; - prevnode = keynode; - } - *prevkeynode = prevnode; - return(keynode); + return newsp; } +/* + * copy secpolicy struct to sadb_x_policy structure indicated. + */ +struct sadb_x_policy * +key_sp2msg(sp) + struct secpolicy *sp; +{ + struct sadb_x_policy *xpl; + int tlen; + caddr_t p; + + /* sanity check. */ + if (sp == NULL) + panic("key_sp2msg: NULL pointer was passed.\n"); + + tlen = key_getspreqmsglen(sp); + + KMALLOC(xpl, struct sadb_x_policy *, tlen); + if (xpl == NULL) { + printf("key_sp2msg: No more memory.\n"); + return NULL; + } + bzero(xpl, tlen); + + xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen); + xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl->sadb_x_policy_type = sp->policy; + xpl->sadb_x_policy_dir = sp->spidx.dir; + p = (caddr_t)xpl + sizeof(*xpl); + + /* if is the policy for ipsec ? */ + if (sp->policy == IPSEC_POLICY_IPSEC) { + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest *isr; + + for (isr = sp->req; isr != NULL; isr = isr->next) { + + xisr = (struct sadb_x_ipsecrequest *)p; + + xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto; + xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode; + xisr->sadb_x_ipsecrequest_level = isr->level; + + p += sizeof(*xisr); + bcopy(&isr->saidx.src, p, isr->saidx.src.__ss_len); + p += isr->saidx.src.__ss_len; + bcopy(&isr->saidx.dst, p, isr->saidx.dst.__ss_len); + p += isr->saidx.src.__ss_len; + + xisr->sadb_x_ipsecrequest_len = + PFKEY_ALIGN8(sizeof(*xisr) + + isr->saidx.src.__ss_len + + isr->saidx.dst.__ss_len); + } + } + + return xpl; +} -/*---------------------------------------------------------------------- - * key_addnode(): - * Insert a key_tblnode entry into the key table. Returns a pointer - * to the newly created key_tblnode. - ----------------------------------------------------------------------*/ -static struct key_tblnode * -key_addnode(indx, secassoc) - int indx; - struct key_secassoc *secassoc; +/* + * SADB_SPDADD processing + * add a entry to SP database, when received + * + * from the user(?). + * Adding to SP database, + * and send + * + * to the socket which was send. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + * + */ +static struct sadb_msg * +key_spdadd(mhp) + caddr_t *mhp; { - struct key_tblnode *keynode; + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct sadb_x_policy *xpl0; + struct secpolicyindex spidx; + struct secpolicy *newsp; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spdadd: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + printf("key_spdadd: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - DPRINTF(IDL_FINISHED,("Entering key_addnode w/indx=%d secassoc=0x%x\n", - indx, (unsigned int)secassoc)); + src0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + /* make secindex */ + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); + + /* checking the direciton. */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + printf("key_spdadd: Invalid SP direction.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - if (!(&keytable[indx])) - return(NULL); - if (!secassoc) { - panic("key_addnode: Someone passed in a null secassoc!\n"); - } + /* Is there SP in SPD ? */ + newsp = key_getsp(&spidx); + if (newsp != NULL) { + key_freesp(newsp); + printf("key_spdadd: a SP entry exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } - KMALLOC(keynode, struct key_tblnode *, sizeof(struct key_tblnode)); - if (keynode == 0) - return(NULL); - bzero((char *)keynode, sizeof(struct key_tblnode)); + /* check policy */ + /* key_spdadd() accepts DISCARD, NONE and IPSEC. */ + if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST + || xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { + printf("key_spdadd: Invalid policy type.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - KMALLOC(keynode->solist, struct socketlist *, sizeof(struct socketlist)); - if (keynode->solist == 0) { - KFREE(keynode); - return(NULL); - } - bzero((char *)(keynode->solist), sizeof(struct socketlist)); + /* allocation new SP entry */ + if ((newsp = key_msg2sp(xpl0)) == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } - keynode->secassoc = secassoc; - keynode->solist->next = NULL; - keynode->next = keytable[indx].next; - keytable[indx].next = keynode; - return(keynode); -} + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &newsp->spidx); + newsp->refcnt = 1; /* do not reclaim until I say I do */ + newsp->state = IPSEC_SPSTATE_ALIVE; + LIST_INSERT_HEAD(&sptree[newsp->spidx.dir], newsp, chain); -/*---------------------------------------------------------------------- - * key_add(): - * Add a new security association to the key table. Caller is - * responsible for allocating memory for the key_secassoc as - * well as the buffer space for the key, iv. Assumes the security - * association passed in is well-formed. - ----------------------------------------------------------------------*/ -int -key_add(secassoc) - struct key_secassoc *secassoc; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - int inbound = 0; - int outbound = 0; - struct key_tblnode *keynode, *prevkeynode; - struct key_allocnode *np = NULL; - CRITICAL_DCL - - DPRINTF(IDL_FINISHED, ("Entering key_add w/secassoc=0x%x\n", - (unsigned int)secassoc)); - - if (!secassoc) { - panic("key_add: who the hell is passing me a null pointer"); - } + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spdadd: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); - /* - * Should we allow a null key to be inserted into the table ? - * or can we use null key to indicate some policy action... - */ + bcopy((caddr_t)msg0, (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); -#if 0 - /* - * For esp using des-cbc or tripple-des we call - * des_set_odd_parity. - */ - if (secassoc->key && (secassoc->type == KEY_TYPE_ESP) && - ((secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) || - (secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES))) - des_set_odd_parity(secassoc->key); -#endif /* 0 */ - - /* - * initialization for anti-replay services. - */ - secassoc->sequence = 0; - secassoc->replayright = 0; - secassoc->replaywindow = 0; - - /* - * Check if secassoc with same spi exists before adding - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keyadd: keytbl hash position=%d\n", indx)); - keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode); - if (keynode) { - DPRINTF(IDL_EVENT,("keyadd: secassoc already exists!\n")); - return(-2); - } + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); - inbound = my_addr(secassoc->dst); - outbound = my_addr(secassoc->src); - DPRINTF(IDL_FINISHED,("inbound=%d outbound=%d\n", inbound, outbound)); - - /* - * We allocate mem for an allocation entry if needed. - * This is done here instead of in the allocaton code - * segment so that we can easily recover/cleanup from a - * memory allocation error. - */ - if (outbound || (!inbound && !outbound)) { - KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode)); - if (np == 0) { - DPRINTF(IDL_ERROR,("keyadd: can't allocate allocnode!\n")); - return(-1); + return newmsg; } - } +} + +/* + * SADB_SPDDELETE processing + * receive + * + * from the user(?), and set SADB_SASTATE_DEAD, + * and send, + * + * to the ikmpd. + * policy(*) including direction of policy. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static struct sadb_msg * +key_spddelete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct sadb_x_policy *xpl0; + struct secpolicyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spddelete: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + printf("key_spddelete: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + /* make secindex */ + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); + + /* checking the direciton. */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + printf("key_spddelete: Invalid SP direction.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - CRITICAL_START; + /* Is there SP in SPD ? */ + if ((sp = key_getsp(&spidx)) == NULL) { + printf("key_spddelete: no SP found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } - if ((keynode = key_addnode(indx, secassoc)) == NULL) { - DPRINTF(IDL_ERROR,("keyadd: key_addnode failed!\n")); - if (np) - KFREE(np); - CRITICAL_END; - return(-1); - } - DPRINTF(IDL_GROSS_EVENT,("Added new keynode:\n")); - DDO(IDL_FINISHED, dump_keytblnode(keynode)); - DDO(IDL_FINISHED, dump_secassoc(keynode->secassoc)); - - /* - * We add an entry to the allocation table for - * this secassoc if the interfaces are up, - * the secassoc is outbound. In the case - * where the interfaces are not up, we go ahead - * , do it anyways. This wastes an allocation - * entry if the secassoc later turned out to be - * inbound when the interfaces are ifconfig up. - */ - if (outbound || (!inbound && !outbound)) { - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keyadd: keyalloc hash position=%d\n", indx)); - np->keynode = keynode; - np->next = keyalloctbl[indx].next; - keyalloctbl[indx].next = np; - } - if (inbound) - secassoc->state |= K_INBOUND; - if (outbound) - secassoc->state |= K_OUTBOUND; + sp->state = IPSEC_SPSTATE_DEAD; + key_freesp(sp); - key_deleteacquire(secassoc->type, secassoc->dst); + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spddelete: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); - CRITICAL_END; - return 0; + return newmsg; + } } +/* + * SADB_SPDFLUSH processing + * receive + * + * from the user, and free all entries in secpctree. + * and send, + * + * to the user. + * NOTE: what to do is only marking SADB_SASTATE_DEAD. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static struct sadb_msg * +key_spdflush(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct secpolicy *sp; + u_int dir; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spdflush: NULL pointer is passed.\n"); -/*---------------------------------------------------------------------- - * key_get(): - * Get a security association from the key table. - ----------------------------------------------------------------------*/ -int -key_get(type, src, dst, spi, secassoc) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - struct key_secassoc **secassoc; -{ - char buf[MAXHASHKEYLEN]; - struct key_tblnode *keynode, *prevkeynode; - int len, indx; - - bzero(&buf, sizeof(buf)); - *secassoc = NULL; - len = key_createkey((char *)&buf, type, src, dst, spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keyget: indx=%d\n",indx)); - keynode = key_search(type, src, dst, spi, indx, &prevkeynode); - if (keynode) { - DPRINTF(IDL_GROSS_EVENT,("keyget: found it! keynode=0x%x", - (unsigned int)keynode)); - *secassoc = keynode->secassoc; - return(0); - } else - return(-1); /* Not found */ -} - - -/*---------------------------------------------------------------------- - * key_dump(): - * Dump all valid entries in the keytable to a pf_key socket. Each - * security associaiton is sent one at a time in a pf_key message. A - * message with seqno = 0 signifies the end of the dump transaction. - ----------------------------------------------------------------------*/ -int -key_dump(so) - struct socket *so; -{ - int len, i; - int seq = 1; - struct key_msgdata keyinfo; - struct key_msghdr *km; - struct key_tblnode *keynode; - int kmlen; - - /* - * Routine to dump the key table to a routing socket - * Use for debugging only! - */ - - kmlen = sizeof(struct key_msghdr) + 3 * MAX_SOCKADDR_SZ + MAX_KEY_SZ - + MAX_IV_SZ; - KMALLOC(km, struct key_msghdr *, kmlen); - if (!km) - return(ENOBUFS); - - DPRINTF(IDL_FINISHED,("Entering key_dump()")); - /* - * We need to speed this up later. Fortunately, key_dump - * messages are not sent often. - */ - for (i = 0; i < KEYTBLSIZE; i++) { - for (keynode = keytable[i].next; keynode; keynode = keynode->next) { - /* - * We exclude dead/larval/zombie security associations for now - * but it may be useful to also send these up for debugging purposes - */ - if (keynode->secassoc->state & (K_DEAD | K_LARVAL | K_ZOMBIE)) - continue; - - len = (sizeof(struct key_msghdr) + - ROUNDUP(keynode->secassoc->src->sa_len) + - ROUNDUP(keynode->secassoc->dst->sa_len) + - ROUNDUP(keynode->secassoc->from->sa_len) + - ROUNDUP(keynode->secassoc->keylen) + - ROUNDUP(keynode->secassoc->ivlen) + - ROUNDUP(keynode->secassoc->ekeylen)); - - if (kmlen < len) { - KFREE(km); - kmlen = len; - KMALLOC(km, struct key_msghdr *, kmlen); - if (!km) - return(ENOBUFS); - } + msg0 = (struct sadb_msg *)mhp[0]; - if (key_secassoc2msghdr(keynode->secassoc, km, &keyinfo) != 0) - panic("key_dump"); + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + sp->state = IPSEC_SPSTATE_DEAD; + } + } - km->key_msglen = len; - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_DUMP; - km->key_pid = curproc->p_pid; - km->key_seq = seq++; - km->key_errno = 0; + { + struct sadb_msg *newmsg; + u_int len; - key_sendup(so, km); - } - } - bzero((char *)km, sizeof(struct key_msghdr)); - km->key_msglen = sizeof(struct key_msghdr); - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_DUMP; - km->key_pid = curproc->p_pid; - km->key_seq = 0; - km->key_errno = 0; - - key_sendup(so, km); - KFREE(km); - DPRINTF(IDL_FINISHED,("Leaving key_dump()\n")); - return(0); -} - -/*---------------------------------------------------------------------- - * key_delete(): - * Delete a security association from the key table. - ----------------------------------------------------------------------*/ -int -key_delete(secassoc) - struct key_secassoc *secassoc; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - struct key_tblnode *keynode = 0; - struct key_tblnode *prevkeynode = 0; - struct socketlist *socklp, *deadsocklp; - struct key_so2spinode *np, *prevnp; - struct key_allocnode *ap, *prevap; - CRITICAL_DCL - - DPRINTF(IDL_FINISHED,("Entering key_delete w/secassoc=0x%x\n", - (unsigned int)secassoc)); - - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keydelete: keytbl hash position=%d\n", indx)); - keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode); - - if (keynode) { - CRITICAL_START; - DPRINTF(IDL_GROSS_EVENT,("keydelete: found keynode to delete\n")); - keynode->secassoc->state |= K_DEAD; - - if (keynode->ref_count > 0) { - DPRINTF(IDL_EVENT,("keydelete: secassoc still held, marking for deletion only!\n")); - CRITICAL_END; - return(0); - } + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg); - prevkeynode->next = keynode->next; - - /* - * Walk the socketlist, delete the - * entries mapping sockets to this secassoc - * from the so2spi table. - */ - DPRINTF(IDL_FINISHED,("keydelete: deleting socklist...")); - for(socklp = keynode->solist->next; socklp; ) { - prevnp = &so2spitbl[((u_int32_t)(socklp->socket)) % SO2SPITBLSIZE]; - for(np = prevnp->next; np; np = np->next) { - if ((np->socket == socklp->socket) && (np->keynode == keynode)) { - prevnp->next = np->next; - KFREE(np); - break; - } - prevnp = np; - } - deadsocklp = socklp; - socklp = socklp->next; - KFREE(deadsocklp); + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spdflush: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + + return(newmsg); } - DPRINTF(IDL_FINISHED,("done\n")); - /* - * If an allocation entry exist for this - * secassoc, delete it. - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keydelete: alloctbl hash position=%d\n", indx)); - prevap = &keyalloctbl[indx]; - for (ap = prevap->next; ap; ap = ap->next) { - if (ap->keynode == keynode) { - prevap->next = ap->next; - KFREE(ap); - break; - } - prevap = ap; - } - - if (keynode->secassoc->iv) - KFREE(keynode->secassoc->iv); - if (keynode->secassoc->key) - KFREE(keynode->secassoc->key); - if (keynode->secassoc->ekey) - KFREE(keynode->secassoc->ekey); - KFREE(keynode->secassoc); - if (keynode->solist) - KFREE(keynode->solist); - KFREE(keynode); - CRITICAL_END; - return(0); - } - return(-1); } +/* + * SADB_SPDDUMP processing + * receive + * + * from the user, and dump all SP leaves + * and send, + * ..... + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static int +key_spddump(mhp, so, target) + caddr_t *mhp; + struct socket *so; + int target; +{ + struct sadb_msg *msg0; + struct secpolicy *sp; + int len, cnt, cnt_sanity; + struct sadb_msg *newmsg; + u_int dir; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spddump: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* search SPD entry and get buffer size. */ + cnt = cnt_sanity = 0; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + cnt++; + } + } -/*---------------------------------------------------------------------- - * key_flush(): - * Delete all entries from the key table. - ----------------------------------------------------------------------*/ -void -key_flush() + if (cnt == 0) + return ENOENT; + + newmsg = NULL; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + len = key_getspmsglen(sp); + + /* making buffer */ + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spddump: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + --cnt; + (void)key_setdumpsp(newmsg, sp, SADB_X_SPDDUMP, + cnt, msg0->sadb_msg_pid); + + key_sendup(so, newmsg, len, target); + KFREE(newmsg); + newmsg = NULL; + } + } + + return 0; +} + +static u_int +key_setdumpsp(newmsg, sp, type, seq, pid) + struct sadb_msg *newmsg; + struct secpolicy *sp; + u_int8_t type; + u_int32_t seq, pid; { - struct key_tblnode *keynode; - int i; -#if 1 - int timo; -#endif + u_int tlen; + caddr_t p; + + tlen = key_getspmsglen(sp); + + p = key_setsadbmsg((caddr_t)newmsg, type, tlen, + SADB_SATYPE_UNSPEC, seq, pid, + IPSEC_MODE_ANY, sp->refcnt); + + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, + sp->spidx.ul_proto); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, + sp->spidx.ul_proto); - /* - * This is slow, but simple. - */ - DPRINTF(IDL_FINISHED,("Flushing key table...")); - for (i = 0; i < KEYTBLSIZE; i++) { - timo = 0; - while ((keynode = keytable[i].next)) { - if (key_delete(keynode->secassoc) != 0) - panic("key_flush"); - timo++; - if (10000 < timo) { -printf("key_flush: timo exceeds limit; terminate the loop to prevent hangup\n"); - break; - } + { + struct sadb_x_policy *tmp; + + if ((tmp = key_sp2msg(sp)) == NULL) { + printf("key_setdumpsp: No more memory.\n"); + return ENOBUFS; + } + + /* validity check */ + if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len)) + panic("key_setdumpsp: length mismatch." + "sp:%d msg:%d\n", + key_getspreqmsglen(sp), + PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); + + bcopy(tmp, p, PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); + KFREE(tmp); } - } - DPRINTF(IDL_FINISHED,("done\n")); + + return tlen; } +/* get sadb message length for a SP. */ +static u_int +key_getspmsglen(sp) + struct secpolicy *sp; +{ + u_int tlen; -/*---------------------------------------------------------------------- - * key_getspi(): - * Get a unique spi value for a key management daemon/program. The - * spi value, once assigned, cannot be assigned again (as long as the - * entry with that same spi value remains in the table). - ----------------------------------------------------------------------*/ -int -key_getspi(type, vers, src, dst, lowval, highval, spi) - u_int type; - u_int vers; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t lowval; - u_int32_t highval; - u_int32_t *spi; -{ - struct key_secassoc *secassoc; - struct key_tblnode *keynode, *prevkeynode; - int count, done, len, indx; - int maxcount = 1000; - u_int32_t val; - char buf[MAXHASHKEYLEN]; - CRITICAL_DCL - - DPRINTF(IDL_EVENT,("Entering getspi w/type=%d,low=%u,high=%u\n", - type, lowval, highval)); - if (!(src && dst)) - return(EINVAL); - - if ((lowval == 0) || (highval == 0)) - return(EINVAL); - - if (lowval > highval) { - u_int32_t temp; - temp = lowval; - lowval = highval; - highval = lowval; - } + /* sanity check */ + if (sp == NULL) + panic("key_getspmsglen: NULL pointer is passed.\n"); - done = count = 0; - do { - count++; - /* - * This may not be "random enough". - */ - val = lowval + (random() % (highval - lowval + 1)); - - if (lowval == highval) - count = maxcount; - DPRINTF(IDL_FINISHED,("%u ",val)); - if (val) { - DPRINTF(IDL_FINISHED,("\n")); - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, val, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - if (!key_search(type, src, dst, val, indx, &prevkeynode)) { - CRITICAL_START; - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - CRITICAL_END; - return(ENOBUFS); - } - bzero((char *)secassoc, sizeof(*secassoc)); - - DPRINTF(IDL_FINISHED,("getspi: indx=%d\n",indx)); - secassoc->len = sizeof(struct key_secassoc); - secassoc->type = type; - secassoc->vers = vers; - secassoc->spi = val; - secassoc->state |= K_LARVAL; - if (my_addr(dst)) - secassoc->state |= K_INBOUND; - if (my_addr(src)) - secassoc->state |= K_OUTBOUND; - - KMALLOC(secassoc->src, struct sockaddr *, src->sa_len); - if (!secassoc->src) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - KFREE(secassoc); - CRITICAL_END; - return(ENOBUFS); - } - bcopy((char *)src, (char *)secassoc->src, src->sa_len); - KMALLOC(secassoc->dst, struct sockaddr *, dst->sa_len); - if (!secassoc->dst) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - KFREE(secassoc->src); - KFREE(secassoc); - CRITICAL_END; - return(ENOBUFS); - } - bcopy((char *)dst, (char *)secassoc->dst, dst->sa_len); - - /* We fill this in with a plausable value now to insure - that other routines don't break. These will get - overwritten later with the correct values. */ -#if 0 -#ifdef INET6 - secassoc->from->sa_family = AF_INET6; - secassoc->from->sa_len = sizeof(struct sockaddr_in6); -#else /* INET6 */ - secassoc->from->sa_family = AF_INET; - secassoc->from->sa_len = sizeof(struct sockaddr_in); -#endif /* INET6 */ -#endif + tlen = (sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.src.__ss_family)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.dst.__ss_family))); + + tlen += key_getspreqmsglen(sp); + + return tlen; +} + +/* + * get PFKEY message length for security policy and request. + */ +static u_int +key_getspreqmsglen(sp) + struct secpolicy *sp; +{ + u_int tlen; + + tlen = sizeof(struct sadb_x_policy); + + /* if is the policy for ipsec ? */ + if (sp->policy != IPSEC_POLICY_IPSEC) + return tlen; + + /* get length of ipsec requests */ + { + struct ipsecrequest *isr; + int len; + + for (isr = sp->req; isr != NULL; isr = isr->next) { + len = sizeof(struct sadb_x_ipsecrequest) + + isr->saidx.src.__ss_len + + isr->saidx.dst.__ss_len; + + tlen += PFKEY_ALIGN8(len); + } + } + + return tlen; +} + +/* %%% SAD management */ +/* + * allocating a memory for new SA head, and copy from the values of mhp. + * OUT: NULL : failure due to the lack of memory. + * others : pointer to new SA head. + */ +static struct secashead * +key_newsah(saidx) + struct secasindex *saidx; +{ + struct secashead *newsah; + u_int stateidx; + + /* sanity check */ + if (saidx == NULL) + panic("key_newsaidx: NULL pointer is passed.\n"); + + KMALLOC(newsah, struct secashead *, sizeof(struct secashead)); + if (newsah == NULL) { + return NULL; + } + bzero((caddr_t)newsah, sizeof(struct secashead)); + + bcopy(saidx, &newsah->saidx, sizeof(newsah->saidx)); + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + LIST_INIT(&newsah->savtree[saorder_state_any[stateidx]]); + } + + /* add to saidxtree */ + newsah->state = SADB_SASTATE_MATURE; + LIST_INSERT_HEAD(&sahtree, newsah, chain); + + return(newsah); +} + +/* + * delete SA index and all SA registerd. + */ +static void +key_delsah(sah) + struct secashead *sah; +{ + struct secasvar *sav, *nextsav; + u_int stateidx, state; + int s; + + /* sanity check */ + if (sah == NULL) + panic("key_delsah: NULL pointer is passed.\n"); + + s = splnet(); /*called from softclock()*/ + + /* remove from tree of SA index */ + if (__LIST_CHAINED(sah)) + LIST_REMOVE(sah, chain); + + /* searching all SA registerd in the secindex. */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + for (sav = (struct secasvar *)LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + /* sanity check */ + KEY_CHKSASTATE(state, sav->state, "key_delsah"); + + /* remove back pointer */ + sav->sah = NULL; + + if (sav->refcnt < 0) { + printf("key_delsah: why refcnt < 0 ?, " + "sav->refcnt=%d\n", + sav->refcnt); + } + key_freesav(sav); + sav = NULL; + } + } + + if (sah->sa_route.ro_rt) { + RTFREE(sah->sa_route.ro_rt); + sah->sa_route.ro_rt = (struct rtentry *)NULL; + } + + KFREE(sah); + + splx(s); + return; +} + +/* + * allocating a new SA with LARVAL state. key_add() and key_getspi() call, + * and copy the values of mhp into new buffer. + * When SAD message type is GETSPI: + * to set sequence number from acq_seq++, + * to set zero to SPI. + * not to call key_setsava(). + * OUT: NULL : fail + * others : pointer to new secasvar. + */ +static struct secasvar * +key_newsav(mhp, sah) + caddr_t *mhp; + struct secashead *sah; +{ + struct secasvar *newsav; + struct sadb_msg *msg0; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL || sah == NULL) + panic("key_newsa: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar)); + if (newsav == NULL) { + printf("key_newsa: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newsav, sizeof(struct secasvar)); + + switch (msg0->sadb_msg_type) { + case SADB_GETSPI: + newsav->spi = 0; + + /* sync sequence number */ + if (msg0->sadb_msg_seq == 0) + newsav->seq = + (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); + else + newsav->seq = msg0->sadb_msg_seq; + break; + + case SADB_ADD: + /* sanity check */ + if (mhp[SADB_EXT_SA] == NULL) { + KFREE(newsav); + printf("key_newsa: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + newsav->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi; + newsav->seq = msg0->sadb_msg_seq; + break; + default: + KFREE(newsav); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* copy sav values */ + if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsav, mhp)) { + KFREE(newsav); + /* msg0->sadb_msg_errno is set at key_setsaval. */ + return NULL; + } + + /* reset tick */ + newsav->tick = 0; + + newsav->pid = msg0->sadb_msg_pid; + + /* add to satree */ + newsav->sah = sah; + newsav->refcnt = 1; + newsav->state = SADB_SASTATE_LARVAL; + LIST_INSERT_HEAD(&sah->savtree[SADB_SASTATE_LARVAL], newsav, chain); + + return newsav; +} + +/* + * free() SA variable entry. + */ +static void +key_delsav(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("key_delsav: NULL pointer is passed.\n"); + + if (sav->refcnt > 0) return; /* can't free */ + + /* remove from SA header */ + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); + + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->replay != NULL) { + if (sav->replay->bitmap != NULL) + KFREE(sav->replay->bitmap); + KFREE(sav->replay); + } + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); + if (sav->iv != NULL) + KFREE(sav->iv); +#if notyet + if (sav->misc1 != NULL) + KFREE(sav->misc1); + if (sav->misc2 != NULL) + KFREE(sav->misc2); + if (sav->misc3 != NULL) + KFREE(sav->misc3); +#endif + + sav->sah = NULL; + /* XXX for making sure. See key_checkrequest(), + * Refcnt may be suspicious. */ + + KFREE(sav); + + return; +} + +/* + * search SAD. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secashead * +key_getsah(saidx) + struct secasindex *saidx; +{ + struct secashead *sah; + + __LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_exactly(&sah->saidx, saidx)) + return(sah); + } + + return NULL; +} + +/* + * check not to be duplicated SPI. + * NOTE: this function is too slow due to searching all SAD. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_checkspidup(saidx, spi) + struct secasindex *saidx; + u_int32_t spi; +{ + struct secashead *sah; + struct secasvar *sav; + + /* check address family */ + if (saidx->src.__ss_family != saidx->src.__ss_family) { + printf("key_checkspidup: address family mismatched.\n"); + return NULL; + } + + /* check all SAD */ + __LIST_FOREACH(sah, &sahtree, chain) { + if (!key_ismyaddr(sah->saidx.dst.__ss_family, + _INADDRBYSA(&sah->saidx.dst))) + continue; + sav = key_getsavbyspi(sah, spi); + if (sav != NULL) + return sav; + } + + return NULL; +} + +/* + * search SAD litmited alive SA, protocol, SPI. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_getsavbyspi(sah, spi) + struct secashead *sah; + u_int32_t spi; +{ + struct secasvar *sav; + u_int stateidx, state; + + /* search all status */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { + + state = saorder_state_alive[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + if (sav->state != state) { + printf("key_getsavbyspi: " + "invalid sav->state " + "(queue: %d SA: %d)\n", + state, sav->state); + continue; + } + + if (sav->spi == spi) + return sav; + } + } + + return NULL; +} + +/* + * copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*. + * You must update these if need. + * OUT: 0: success. + * 1: failure. set errno to (mhp[0])->sadb_msg_errno. + */ +static int +key_setsaval(sav, mhp) + struct secasvar *sav; + caddr_t *mhp; +{ + struct sadb_msg *msg0; + int error = 0; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_setsaval: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* initialization */ + sav->replay = NULL; + sav->key_auth = NULL; + sav->key_enc = NULL; + sav->iv = NULL; + sav->lft_c = NULL; + sav->lft_h = NULL; + sav->lft_s = NULL; + + /* SA */ + if (mhp[SADB_EXT_SA] != NULL) { + struct sadb_sa *sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sav->alg_auth = sa0->sadb_sa_auth; + sav->alg_enc = sa0->sadb_sa_encrypt; + sav->flags = sa0->sadb_sa_flags; + + /* replay window */ + if ((sa0->sadb_sa_flags & SADB_X_EXT_OLD) == 0) { + KMALLOC(sav->replay, struct secreplay *, + sizeof(struct secreplay)); + if (sav->replay == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + bzero(sav->replay, sizeof(struct secreplay)); + + if ((sav->replay->wsize = sa0->sadb_sa_replay) != 0) { + KMALLOC(sav->replay->bitmap, caddr_t, + sav->replay->wsize); + if (sav->replay->bitmap == NULL) { + printf("key_setsaval: " + "No more memory.\n"); + error = ENOBUFS; + goto err; + } + bzero(sav->replay->bitmap, sa0->sadb_sa_replay); + } + } + } + + /* Authentication keys */ + if (mhp[SADB_EXT_KEY_AUTH] != NULL) { + struct sadb_key *key0; + u_int len; + + key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; + len = PFKEY_UNUNIT64(key0->sadb_key_len); + + error = 0; + if (len < sizeof(struct sadb_key)) + error = EINVAL; + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + if (len == sizeof(struct sadb_key) + && sav->alg_auth != SADB_AALG_NULL) { + error = EINVAL; + } + break; + case SADB_X_SATYPE_IPCOMP: + error = EINVAL; + break; + default: + error = EINVAL; + break; + } + if (error) { + printf("key_setsaval: invalid key_auth values.\n"); + goto err; + } + + KEY_NEWBUF(sav->key_auth, struct sadb_key *, key0, len); + if (sav->key_auth == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + /* make length shift up for kernel*/ + sav->key_auth->sadb_key_len = len; + } + + /* Encryption key */ + if (mhp[SADB_EXT_KEY_ENCRYPT] != NULL) { + struct sadb_key *key0; + u_int len; + + key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; + len = PFKEY_UNUNIT64(key0->sadb_key_len); + + error = 0; + if (len < sizeof(struct sadb_key)) + error = EINVAL; + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_ESP: + if (len == sizeof(struct sadb_key) + && sav->alg_enc != SADB_EALG_NULL) { + error = EINVAL; + } + break; + case SADB_SATYPE_AH: + error = EINVAL; + break; + case SADB_X_SATYPE_IPCOMP: + break; + default: + error = EINVAL; + break; + } + if (error) { + printf("key_setsatval: invalid key_enc value.\n"); + goto err; + } + + KEY_NEWBUF(sav->key_enc, struct sadb_key *, key0, len); + if (sav->key_enc == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + /* make length shift up for kernel*/ + sav->key_enc->sadb_key_len = len; + } + + /* set iv */ + sav->ivlen = 0; + + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_ESP: +#ifdef IPSEC_ESP + { + struct esp_algorithm *algo; + + algo = &esp_algorithms[sav->alg_enc]; + if (algo && algo->ivlen) + sav->ivlen = (*algo->ivlen)(sav); + KMALLOC(sav->iv, caddr_t, sav->ivlen); + if (sav->iv == 0) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* initialize ? */ + break; + } +#else + break; +#endif + case SADB_SATYPE_AH: + break; + default: + printf("key_setsaval: invalid SA type.\n"); + error = EINVAL; + goto err; + } + + /* reset tick */ + sav->tick = 0; + + /* make lifetime for CURRENT */ + { + struct timeval tv; + + KMALLOC(sav->lft_c, struct sadb_lifetime *, + sizeof(struct sadb_lifetime)); + if (sav->lft_c == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + microtime(&tv); + + sav->lft_c->sadb_lifetime_len = + PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + sav->lft_c->sadb_lifetime_allocations = 0; + sav->lft_c->sadb_lifetime_bytes = 0; + sav->lft_c->sadb_lifetime_addtime = tv.tv_sec; + sav->lft_c->sadb_lifetime_usetime = 0; + } + + /* lifetimes for HARD and SOFT */ + { + struct sadb_lifetime *lft0; + + lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + if (lft0 != NULL) { + KEY_NEWBUF(sav->lft_h, struct sadb_lifetime *, + lft0, sizeof(*lft0)); + if (sav->lft_h == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* to be initialize ? */ + } + + lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + if (lft0 != NULL) { + KEY_NEWBUF(sav->lft_s, struct sadb_lifetime *, + lft0, sizeof(*lft0)); + if (sav->lft_s == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* to be initialize ? */ + } + } + + msg0->sadb_msg_errno = 0; + return 0; + + err: + /* initialization */ + if (sav->replay != NULL) { + if (sav->replay->bitmap != NULL) + KFREE(sav->replay->bitmap); + KFREE(sav->replay); + } + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->iv != NULL) + KFREE(sav->iv); + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); + + msg0->sadb_msg_errno = error; + return 1; +} + +/* + * get message buffer length. + */ +static u_int +key_getmsglen(sav) + struct secasvar *sav; +{ + int len = sizeof(struct sadb_msg); + + len += sizeof(struct sadb_sa); + len += (sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.src.__ss_family))); + len += (sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.dst.__ss_family))); + + if (sav->key_auth != NULL) + len += sav->key_auth->sadb_key_len; + if (sav->key_enc != NULL) + len += sav->key_enc->sadb_key_len; + + if (sav->lft_c != NULL) + len += sizeof(struct sadb_lifetime); + if (sav->lft_h != NULL) + len += sizeof(struct sadb_lifetime); + if (sav->lft_s != NULL) + len += sizeof(struct sadb_lifetime); + + return len; +} + +/* + * validation with a secasvar entry, and set SADB_SATYPE_MATURE. + * OUT: 0: valid + * other: errno + */ +static int +key_mature(sav) + struct secasvar *sav; +{ + int mature; + int checkmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ + int mustmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ + + mature = 0; + + /* check SPI value */ + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { + printf("key_mature: illegal range of SPI %d.\n", sav->spi); + return EINVAL; + } + + /* check satype */ + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: + /* check flags */ + if ((sav->flags & SADB_X_EXT_OLD) + && (sav->flags & SADB_X_EXT_DERIV)) { + printf("key_mature: " + "invalid flag (derived) given to old-esp.\n"); + return EINVAL; + } + checkmask = 3; + mustmask = 1; + break; + case IPPROTO_AH: + /* check flags */ + if (sav->flags & SADB_X_EXT_DERIV) { + printf("key_mature: " + "invalid flag (derived) given to AH SA.\n"); + return EINVAL; + } + if (sav->alg_enc != SADB_EALG_NONE) { + printf("key_mature: " + "protocol and algorithm mismated.\n"); + return(EINVAL); + } + checkmask = 2; + mustmask = 2; + break; + default: + printf("key_mature: Invalid satype.\n"); + return EPROTONOSUPPORT; + } + + /* check authentication algorithm */ + if ((checkmask & 2) != 0) { + struct ah_algorithm *algo; + int keylen; + + /* XXX: should use algorithm map to check. */ + switch (sav->alg_auth) { + case SADB_AALG_NONE: + case SADB_AALG_MD5HMAC: + case SADB_AALG_SHA1HMAC: + case SADB_AALG_MD5: + case SADB_AALG_SHA: + case SADB_AALG_NULL: + break; + default: + printf("key_mature: " + "unknown authentication algorithm.\n"); + return EINVAL; + } + + /* algorithm-dependent check */ + algo = &ah_algorithms[sav->alg_auth]; + + if (sav->key_auth) + keylen = sav->key_auth->sadb_key_bits; + else + keylen = 0; + if (keylen < algo->keymin || algo->keymax < keylen) { + printf("key_mature: invalid AH key length %d " + "(%d-%d allowed)\n", keylen, + algo->keymin, algo->keymax); + return EINVAL; + } + + if (algo->mature) { + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ + return EINVAL; + } else + mature = SADB_SATYPE_AH; + } + + if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) + return EINVAL; + } + + /* check encryption algorithm */ + if ((checkmask & 1) != 0) { +#ifdef IPSEC_ESP + struct esp_algorithm *algo; + int keylen; + + switch (sav->alg_enc) { + case SADB_EALG_NONE: + case SADB_EALG_DESCBC: + case SADB_EALG_3DESCBC: + case SADB_EALG_NULL: + case SADB_EALG_BLOWFISHCBC: + case SADB_EALG_CAST128CBC: + case SADB_EALG_RC5CBC: + break; + default: + printf("key_mature: unknown encryption algorithm.\n"); + return(EINVAL); + } + + /* algorithm-dependent check */ + algo = &esp_algorithms[sav->alg_enc]; + + if (sav->key_enc) + keylen = sav->key_enc->sadb_key_bits; + else + keylen = 0; + if (keylen < algo->keymin || algo->keymax < keylen) { + printf("key_mature: invalid ESP key length %d " + "(%d-%d allowed)\n", keylen, + algo->keymin, algo->keymax); + return EINVAL; + } + + if (algo->mature) { + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ + return EINVAL; + } else + mature = SADB_SATYPE_ESP; + } + + if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) + return EINVAL; +#else + printf("key_mature: ESP not supported in this configuration\n"); + return EINVAL; +#endif + } + + key_sa_chgstate(sav, SADB_SASTATE_MATURE); + + return 0; +} + +/* + * subroutine for SADB_GET and SADB_DUMP. + * the buf must be allocated sufficent space. + */ +static u_int +key_setdumpsa(newmsg, sav, type, satype, seq, pid) + struct sadb_msg *newmsg; + struct secasvar *sav; + u_int8_t type, satype; + u_int32_t seq, pid; +{ + u_int tlen; + caddr_t p; + int i; + + tlen = key_getmsglen(sav); + + p = key_setsadbmsg((caddr_t)newmsg, type, tlen, + satype, seq, pid, + sav->sah->saidx.mode, sav->refcnt); + + for (i = 1; i <= SADB_EXT_MAX; i++) { + switch (i) { + case SADB_EXT_SA: + p = key_setsadbsa(p, sav); + break; + + case SADB_EXT_ADDRESS_SRC: + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + break; + + case SADB_EXT_ADDRESS_DST: + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + break; + + case SADB_EXT_KEY_AUTH: + { + u_int len; + if (sav->key_auth == NULL) break; + len = sav->key_auth->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_auth, p, len); + ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); + p += len; + } + break; + + case SADB_EXT_KEY_ENCRYPT: + { + u_int len; + if (sav->key_enc == NULL) break; + len = sav->key_enc->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_enc, p, len); + ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); + p += len; + } + break;; + + case SADB_EXT_LIFETIME_CURRENT: + if (sav->lft_c == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_c); + break; + + case SADB_EXT_LIFETIME_HARD: + if (sav->lft_h == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_h); + break; + + case SADB_EXT_LIFETIME_SOFT: + if (sav->lft_s == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_s); + break; + + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + /* XXX: should we brought from SPD ? */ + case SADB_EXT_SENSITIVITY: + default: + break; + } + } + + return tlen; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbmsg(buf, type, tlen, satype, seq, pid, reserved1, reserved2) + caddr_t buf; + u_int8_t type, satype; + u_int16_t tlen; + u_int32_t seq; + pid_t pid; + u_int8_t reserved1; + u_int8_t reserved2; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + bzero(p, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_mode = reserved1; + p->sadb_msg_reserved = reserved2; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbsa(buf, sav) + caddr_t buf; + struct secasvar *sav; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + bzero(p, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = sav->spi; + p->sadb_sa_replay = (sav->replay != NULL ? sav->replay->wsize : 0); + p->sadb_sa_state = sav->state; + p->sadb_sa_auth = sav->alg_auth; + p->sadb_sa_encrypt = sav->alg_enc; + p->sadb_sa_flags = sav->flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + u_int16_t exttype; + struct sockaddr *saddr; + u_int8_t prefixlen; + u_int16_t ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + bzero(p, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype; + p->sadb_address_proto = ul_proto; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + bcopy(saddr, p + 1, saddr->sa_len); + + return(buf + len); +} + +/* + * set data into sadb_ident. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbident(buf, exttype, idtype, string, stringlen, id) + caddr_t buf; + u_int16_t exttype, idtype; + caddr_t string; + int stringlen; + u_int64_t id; +{ + struct sadb_ident *p; + u_int len; + + p = (struct sadb_ident *)buf; + len = sizeof(struct sadb_ident) + PFKEY_ALIGN8(stringlen); + + bzero(p, len); + p->sadb_ident_len = PFKEY_UNIT64(len); + p->sadb_ident_exttype = exttype; + p->sadb_ident_type = idtype; + p->sadb_ident_reserved = 0; + p->sadb_ident_id = id; + + bcopy(string, p + 1, stringlen); + + return(buf + len); +} + +/* + * copy buffer of any sadb extension type into sadb_ext. + * assume that sadb_ext_len shifted down >> 3. + * i.e. shift length up when setting length of extension. + */ +static caddr_t +key_setsadbext(p, ext) + caddr_t p, ext; +{ + u_int len; + + len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len); + + bcopy(ext, p, len); + + return(p + len); +} + +/* %%% utilities */ +/* + * copy a buffer into the new buffer allocated. + */ +static void * +key_newbuf(src, len) + void *src; + u_int len; +{ + caddr_t new; + + KMALLOC(new, caddr_t, len); + if (new == NULL) { + printf("key_newbuf: No more memory.\n"); + return NULL; + } + bcopy((caddr_t)src, new, len); + + return new; +} + +/* compare my own address + * OUT: 1: true, i.e. my address. + * 0: false + */ +int +key_ismyaddr(family, addr) + u_int family; + caddr_t addr; +{ + /* sanity check */ + if (addr == NULL) + panic("key_ismyaddr: NULL pointer is passed.\n"); + + switch (family) { + case AF_INET: + { + struct in_ifaddr *ia; + + for (ia = in_ifaddrhead.tqh_first; ia; + ia = ia->ia_link.tqe_next) + if (bcmp(addr, + (caddr_t)&ia->ia_addr.sin_addr, + _INALENBYAF(family)) == 0) + return 1; + } + break; +#ifdef INET6 + case AF_INET6: + return key_ismyaddr6(addr); +#endif + } + + return 0; +} + +#ifdef INET6 +/* + * compare my own address for IPv6. + * 1: ours + * 0: other + * NOTE: derived ip6_input() in KAME. This is necessary to modify more. + */ +#include +#include + +static int +key_ismyaddr6(addr) + caddr_t addr; +{ + struct in6_addr *a = (struct in6_addr *)addr; + struct in6_ifaddr *ia; + + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (bcmp(addr, (caddr_t)&ia->ia_addr.sin6_addr, + _INALENBYAF(AF_INET6)) == 0) { + return 1; + } + + /* XXX Multicast */ + { + struct in6_multi *in6m = 0; + + IN6_LOOKUP_MULTI(*(struct in6_addr *)addr, ia->ia_ifp, in6m); + if (in6m) + return 1; + } + } + + /* loopback, just for safety */ + if (IN6_IS_ADDR_LOOPBACK(a)) + return 1; + + /* XXX anycast */ + + return 0; +} +#endif /*INET6*/ + +/* + * compare two secasindex structure exactly. + * IN: + * saidx0: source, it can be in SAD. + * saidx1: object, it can be from SPD. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_exactly(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; + + if (saidx0 == NULL || saidx1 == NULL) + return 0; + + if (saidx0->proto != saidx1->proto + || saidx0->mode != saidx1->mode) + return 0; + + if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.__ss_len) != 0 + || bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.__ss_len) != 0) + return 0; + + return 1; +} + +/* + * compare two secasindex structure with consideration mode. + * don't compare port. + * IN: + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from SPD. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_withmode(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; + + if (saidx0 == NULL || saidx1 == NULL) + return 0; + + if (saidx0->proto != saidx1->proto + || saidx0->src.__ss_family != saidx1->src.__ss_family + || saidx0->dst.__ss_family != saidx1->dst.__ss_family) + return 0; + + if (saidx0->mode != IPSEC_MODE_ANY + && saidx0->mode != saidx1->mode) + return 0; + + { + int sa_len = _INALENBYAF(saidx0->src.__ss_family); + + if (bcmp(_INADDRBYSA(&saidx0->src), _INADDRBYSA(&saidx1->src), sa_len) + || bcmp(_INADDRBYSA(&saidx0->dst), _INADDRBYSA(&saidx1->dst), sa_len)) + return 0; + } + + return 1; +} + +/* + * compare two secindex structure exactly. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from PFKEY message. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_exactly(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; + + if (spidx0 == NULL || spidx1 == NULL) + return 0; + + if (spidx0->prefs != spidx1->prefs + || spidx0->prefd != spidx1->prefd + || spidx0->ul_proto != spidx1->ul_proto) + return 0; + + if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.__ss_len) != 0 + || bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.__ss_len) != 0) + return 0; + + return 1; +} + +/* + * compare two secindex structure with mask. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from IP header. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_withmask(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; + + if (spidx0 == NULL || spidx1 == NULL) + return 0; + + if (spidx0->src.__ss_family != spidx1->src.__ss_family + || spidx0->dst.__ss_family != spidx1->dst.__ss_family) + return 0; + + /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ + if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY + && spidx0->ul_proto != spidx1->ul_proto) + return 0; + + if (_INPORTBYSA(&spidx0->src) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->src) != _INPORTBYSA(&spidx1->src)) + return 0; + + if (_INPORTBYSA(&spidx0->dst) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->dst) != _INPORTBYSA(&spidx1->dst)) + return 0; + + if (!key_bbcmp(_INADDRBYSA(&spidx0->src), + _INADDRBYSA(&spidx1->src), + spidx0->prefs)) + return 0; + + if (!key_bbcmp(_INADDRBYSA(&spidx0->dst), + _INADDRBYSA(&spidx1->dst), + spidx0->prefd)) + return 0; + + /* XXX Do we check other field ? e.g. flowinfo, scope_id. */ + + return 1; +} + +/* + * compare two buffers with mask. + * IN: + * addr1: source + * addr2: object + * bits: Number of bits to compare + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_bbcmp(p1, p2, bits) + register caddr_t p1, p2; + register u_int bits; +{ + u_int8_t mask; + + /* XXX: This could be considerably faster if we compare a word + * at a time, but it is complicated on LSB Endian machines */ + + /* Handle null pointers */ + if (p1 == NULL || p2 == NULL) + return (p1 == p2); + + while (bits >= 8) { + if (*p1++ != *p2++) + return 0; + bits -= 8; + } + + if (bits > 0) { + mask = ~((1<<(8-bits))-1); + if ((*p1 & mask) != (*p2 & mask)) + return 0; + } + return 1; /* Match! */ +} + +/* + * time handler. + * scanning SPD and SAD to check status for each entries, + * and do to remove or to expire. + */ +void +key_timehandler(void) +{ + u_int dir; + int s; + + s = splnet(); /*called from softclock()*/ + + /* SPD */ + { + struct secpolicy *sp, *nextsp; + + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + for (sp = LIST_FIRST(&sptree[dir]); + sp != NULL; + sp = nextsp) { + + nextsp = LIST_NEXT(sp, chain); + + if (sp->state == IPSEC_SPSTATE_DEAD) + key_freesp(sp); + } + } + } + + /* SAD */ + { + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; + + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { + + nextsah = LIST_NEXT(sah, chain); + + /* if sah has been dead, then delete it and process next sah. */ + if (sah->state == SADB_SASTATE_DEAD) { + key_delsah(sah); + continue; + } + + /* if LARVAL entry doesn't become MATURE, delete it. */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_LARVAL]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + if (key_larval_lifetime < sav->tick) { + key_freesav(sav); + } + } + + /* + * check MATURE entry to start to send expire message + * whether or not. + */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + /* we don't need to check. */ + if (sav->lft_s == NULL) + continue; + + /* sanity check */ + if (sav->lft_c == NULL) { + printf("key_timehandler: " + "There is no CURRENT time, why?\n"); + continue; + } + + /* compare SOFT lifetime and tick */ + if (sav->lft_s->sadb_lifetime_addtime != 0 + && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + /* + * check SA to be used whether or not. + * when SA hasn't been used, delete it. + */ + if (sav->lft_c->sadb_lifetime_usetime == 0) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } else { + key_sa_chgstate(sav, SADB_SASTATE_DYING); + /* + * XXX If we keep to send expire + * message in the status of + * DYING. Do remove below code. + */ + key_expire(sav); + } + } + /* check SOFT lifetime by bytes */ + /* + * XXX I don't know the way to delete this SA + * when new SA is installed. Caution when it's + * installed too big lifetime by time. + */ + else if (sav->lft_s->sadb_lifetime_bytes != 0 + && sav->lft_s->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { + + key_sa_chgstate(sav, SADB_SASTATE_DYING); + /* + * XXX If we keep to send expire + * message in the status of + * DYING. Do remove below code. + */ + key_expire(sav); + } + } + + /* check DYING entry to change status to DEAD. */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DYING]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + /* we don't need to check. */ + if (sav->lft_h == NULL) + continue; + + /* sanity check */ + if (sav->lft_c == NULL) { + printf("key_timehandler: " + "There is no CURRENT time, why?\n"); + continue; + } + + /* compare HARD lifetime and tick */ + if (sav->lft_h->sadb_lifetime_addtime != 0 + && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } + /* check HARD lifetime by bytes */ + else if (sav->lft_h->sadb_lifetime_bytes != 0 + && sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } + } + + /* delete entry in DEAD */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DEAD]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + /* sanity check */ + if (sav->state != SADB_SASTATE_DEAD) { + printf("key_timehandler: " + "invalid sav->state " + "(queue: %d SA: %d): " + "kill it anyway\n", + SADB_SASTATE_DEAD, sav->state); + } + + /* + * do not call key_freesav() here. + * sav should already be freed, and sav->refcnt + * shows other references to sav + * (such as from SPD). + */ + } + } + } + +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* ACQ tree */ + { + struct secacq *acq, *nextacq; + + for (acq = LIST_FIRST(&acqtree); + acq != NULL; + acq = nextacq) { + + nextacq = LIST_NEXT(acq, chain); + + acq->tick++; + + if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + LIST_REMOVE(acq, chain); + KFREE(acq); + } + } + } +#endif + + /* initialize random seed */ + if (key_tick_init_random++ > key_int_random) { + key_tick_init_random = 0; + key_srandom(); + } + +#ifndef IPSEC_DEBUG2 + /* do exchange to tick time !! */ + (void)timeout((void *)key_timehandler, (void *)0, 100); +#endif /* IPSEC_DEBUG2 */ + + splx(s); + return; +} + +/* + * to initialize a seed for random() + */ +void +key_srandom() +{ + struct timeval tv; + + microtime(&tv); + srandom(tv.tv_usec); + + return; +} + +/* + * map SADB_SATYPE_* to IPPROTO_*. + * if satype == SADB_SATYPE then satype is mapped to ~0. + * OUT: + * 0: invalid satype. + */ +static u_int16_t +key_satype2proto(satype) + u_int8_t satype; +{ + switch (satype) { + case SADB_SATYPE_UNSPEC: + return IPSEC_PROTO_ANY; + case SADB_SATYPE_AH: + return IPPROTO_AH; + case SADB_SATYPE_ESP: + return IPPROTO_ESP; + default: + return 0; + } + /* NOTREACHED */ +} + +/* + * map IPPROTO_* to SADB_SATYPE_* + * OUT: + * 0: invalid protocol type. + */ +static u_int8_t +key_proto2satype(proto) + u_int16_t proto; +{ + switch (proto) { + case IPPROTO_AH: + return SADB_SATYPE_AH; + case IPPROTO_ESP: + return SADB_SATYPE_ESP; + default: + return 0; + } + /* NOTREACHED */ +} + +/* %%% PF_KEY */ +/* + * SADB_GETSPI processing is to receive + * + * from the IKMPd, to assign a unique spi value, to hang on the INBOUND + * tree with the status of LARVAL, and send + * + * to the IKMPd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_getspi(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int8_t proto; + u_int32_t spi; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_getspi: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_getspi: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_getspi: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* SPI allocation */ + spi = key_do_getnewspi((struct sadb_spirange *)mhp[SADB_EXT_SPIRANGE], + &saidx); + if (spi == 0) { + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + + /* get a SA index */ + if ((newsah = key_getsah(&saidx)) == NULL) { + + /* create a new SA index */ + if ((newsah = key_newsah(&saidx)) == NULL) { + printf("key_getspi: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + } + + /* get a new SA */ + if ((newsav = key_newsav(mhp, newsah)) == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + /* XXX don't free new SA index allocated in above. */ + return NULL; + } + + /* set spi */ + newsav->spi = htonl(spi); + +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* delete the entry in acqtree */ + if (msg0->sadb_msg_seq != 0) { + struct secacq *acq; + if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) != NULL) { + /* reset counter in order to deletion by timehander. */ + acq->tick = key_blockacq_lifetime; + acq->count = 0; + } + } +#endif + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_getspi: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_seq = newsav->seq; + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + { + struct sadb_sa *m_sa; + m_sa = (struct sadb_sa *)p; + m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); + m_sa->sadb_sa_exttype = SADB_EXT_SA; + m_sa->sadb_sa_spi = htonl(spi); + p += sizeof(struct sadb_sa); + } + + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; + } +} + +/* + * allocating new SPI + * called by key_getspi(). + * OUT: + * 0: failure. + * others: success. + */ +static u_int32_t +key_do_getnewspi(spirange, saidx) + struct sadb_spirange *spirange; + struct secasindex *saidx; +{ + u_int32_t newspi; + u_int32_t min, max; + int count = key_spi_trycnt; + + /* set spi range to allocate */ + if (spirange != NULL) { + min = spirange->sadb_spirange_min; + max = spirange->sadb_spirange_max; + } else { + min = key_spi_minval; + max = key_spi_maxval; + } + + if (min == max) { + if (key_checkspidup(saidx, min) != NULL) { + printf("key_do_getnewspi: SPI %u exists already.\n", min); + return 0; + } + + count--; /* taking one cost. */ + newspi = min; + + } else { + + /* init SPI */ + newspi = 0; + + /* when requesting to allocate spi ranged */ + while (count--) { + /* generate pseudo-random SPI value ranged. */ + newspi = min + (random() % ( max - min + 1 )); + + if (key_checkspidup(saidx, newspi) == NULL) + break; + } + + if (count == 0 || newspi == 0) { + printf("key_do_getnewspi: to allocate spi is failed.\n"); + return 0; + } + } + + /* statistics */ + keystat.getspi_count = + (keystat.getspi_count + key_spi_trycnt - count) / 2; + + return newspi; +} + +/* + * SADB_UPDATE processing + * receive + * + * from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL. + * and send + * + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_update(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_update: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_update: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + printf("key_update: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_update: no SA index found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* find a SA with sequence number. */ + if ((sav = key_getsavbyseq(sah, msg0->sadb_msg_seq)) == NULL) { + printf("key_update: no larval SA with sequence %u exists.\n", + msg0->sadb_msg_seq); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* validity check */ + if (sav->sah->saidx.proto != proto) { + printf("key_update: protocol mismatched (DB=%u param=%u)\n", + sav->sah->saidx.proto, proto); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (sav->spi != sa0->sadb_sa_spi) { + printf("key_update: SPI mismatched (DB:%u param:%u)\n", + (u_int32_t)ntohl(sav->spi), + (u_int32_t)ntohl(sa0->sadb_sa_spi)); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (sav->pid != msg0->sadb_msg_pid) { + printf("key_update: pid mismatched (DB:%u param:%u)\n", + sav->pid, msg0->sadb_msg_pid); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* copy sav values */ + if (key_setsaval(sav, mhp)) { + key_freesav(sav); + return NULL; + } + + /* check SA values to be mature. */ + if ((msg0->sadb_msg_errno = key_mature(sav)) != 0) { + key_freesav(sav); + return NULL; + } + + /* + * we must call key_freesav() whenever we leave a function context, + * as we did not allocated a new sav (we updated existing sav). + */ + key_freesav(sav); + sav = NULL; + + { + struct sadb_msg *newmsg; + + /* set msg buf from mhp */ + if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + printf("key_update: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + return newmsg; + } +} + +/* + * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL. + * only called by key_update(). + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_getsavbyseq(sah, seq) + struct secashead *sah; + u_int32_t seq; +{ + struct secasvar *sav; + u_int state; + + state = SADB_SASTATE_LARVAL; + + /* search SAD with sequence number ? */ + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + KEY_CHKSASTATE(state, sav->state, "key_getsabyseq"); + + if (sav->seq == seq) { + sav->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP key_getsavbyseq cause " + "refcnt++:%d SA:%p\n", + sav->refcnt, sav)); + return sav; + } + } + + return NULL; +} + +/* + * SADB_ADD processing + * add a entry to SA database, when received + * + * from the ikmpd, + * and send + * + * to the ikmpd. + * + * IGNORE identity and sensitivity messages. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_add(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_add: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_add: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + printf("key_add: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((newsah = key_getsah(&saidx)) == NULL) { + + /* create a new SA header */ + if ((newsah = key_newsah(&saidx)) == NULL) { + printf("key_add: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + } + + /* create new SA entry. */ + /* We can create new SA only if SPI is differenct. */ + if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) { + printf("key_add: SA already exists.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + if ((newsav = key_newsav(mhp, newsah)) == NULL) + return NULL; + + /* check SA values to be mature. */ + if ((msg0->sadb_msg_errno = key_mature(newsav)) != NULL) { + key_freesav(newsav); + return NULL; + } + + /* + * don't call key_freesav() here, as we would like to keep the SA + * in the database on success. + */ + + { + struct sadb_msg *newmsg; + + /* set msg buf from mhp */ + if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + printf("key_add: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + + return newmsg; + } +} + +static struct sadb_msg * +key_getmsgbuf_x1(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_getmsgbuf_x1: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]) + + (mhp[SADB_EXT_LIFETIME_HARD] == NULL + ? 0 : sizeof(struct sadb_lifetime)) + + (mhp[SADB_EXT_LIFETIME_SOFT] == NULL + ? 0 : sizeof(struct sadb_lifetime)); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) + return NULL; + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + if (mhp[SADB_EXT_LIFETIME_HARD] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_HARD]); + + if (mhp[SADB_EXT_LIFETIME_SOFT] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]); + + return newmsg; +} + +/* + * SADB_DELETE processing + * receive + * + * from the ikmpd, and set SADB_SASTATE_DEAD, + * and send, + * + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_delete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_delete: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_delete: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_delete: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_delete: no SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { + printf("key_delete: no alive SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_delete: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; + } +} + +/* + * SADB_GET processing + * receive + * + * from the ikmpd, and get a SP and a SA to respond, + * and send, + * + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_get(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_get: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_get: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_get: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_get: no SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { + printf("key_get: no SA with state of mature found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + { + struct sadb_msg *newmsg; + u_int len; + u_int8_t satype; + + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { + printf("key_get: there was invalid proto in SAD.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* calculate a length of message buffer */ + len = key_getmsglen(sav); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_get: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + + /* create new sadb_msg to reply. */ + (void)key_setdumpsa(newmsg, sav, SADB_GET, + satype, msg0->sadb_msg_seq, msg0->sadb_msg_pid); + + return newmsg; + } +} + +/* + * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). + * send + * + * to KMD, and expect to receive + * with SADB_ACQUIRE if error occured, + * or + * with SADB_GETSPI + * from KMD by PF_KEY. + * + * sensitivity is not supported. + * + * OUT: + * 0 : succeed + * others: error number + */ +static int +key_acquire(saidx, spidx) + struct secasindex *saidx; + struct secpolicyindex *spidx; +{ +#ifndef IPSEC_NONBLOCK_ACQUIRE + struct secacq *newacq; +#endif + u_int8_t satype; + int error; + + /* sanity check */ + if (saidx == NULL || spidx == NULL) + panic("key_acquire: NULL pointer is passed.\n"); + if ((satype = key_proto2satype(saidx->proto)) == 0) + panic("key_acquire: invalid proto is passed.\n"); + +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* + * We never do anything about acquirng SA. There is anather + * solution that kernel blocks to send SADB_ACQUIRE message until + * getting something message from IKEd. In later case, to be + * managed with ACQUIRING list. + */ + /* get a entry to check whether sending message or not. */ + if ((newacq = key_getacq(saidx)) != NULL) { + if (key_blockacq_count < newacq->count) { + /* reset counter and do send message. */ + newacq->count = 0; + } else { + /* increment counter and do nothing. */ + newacq->count++; + return 0; + } + } else { + /* make new entry for blocking to send SADB_ACQUIRE. */ + if ((newacq = key_newacq(saidx)) == NULL) + return ENOBUFS; + + /* add to acqtree */ + LIST_INSERT_HEAD(&acqtree, newacq, chain); + } +#endif + + { + struct sadb_msg *newmsg = NULL; + union sadb_x_ident_id id; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(saidx->src.__ss_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(saidx->dst.__ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->src.__ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->dst.__ss_len) + + sizeof(struct sadb_prop) + + sizeof(struct sadb_comb); /* XXX to be multiple */ + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == 0) { + printf("key_acquire: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + newmsg->sadb_msg_version = PF_KEY_V2; + newmsg->sadb_msg_type = SADB_ACQUIRE; + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_satype = satype; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + +#ifndef IPSEC_NONBLOCK_ACQUIRE + newmsg->sadb_msg_seq = newacq->seq; +#else + newmsg->sadb_msg_seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); +#endif + + newmsg->sadb_msg_pid = 0; + p = (caddr_t)newmsg + sizeof(struct sadb_msg); + + /* set sadb_address for saidx's. */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&saidx->src, + _INALENBYAF(saidx->src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&saidx->dst, + _INALENBYAF(saidx->dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + /* set sadb_address for spidx's. */ + id.sadb_x_ident_id_addr.prefix = spidx->prefs; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_SRC, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->src, + spidx->src.__ss_len, + *(u_int64_t *)&id); + + id.sadb_x_ident_id_addr.prefix = spidx->prefd; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_DST, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->dst, + spidx->dst.__ss_len, + *(u_int64_t *)&id); + + /* create proposal extension */ + /* set combination extension */ + /* XXX: to be defined by proposal database */ + { + struct sadb_prop *prop; + struct sadb_comb *comb; + + prop = (struct sadb_prop *)p; + prop->sadb_prop_len = PFKEY_UNIT64(sizeof(*prop) + sizeof(*comb)); + /* XXX to be multiple */ + prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; + prop->sadb_prop_replay = 32; /* XXX be variable ? */ + p += sizeof(struct sadb_prop); + + comb = (struct sadb_comb *)p; + comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; /* XXX ??? */ + comb->sadb_comb_encrypt = SADB_EALG_DESCBC; /* XXX ??? */ + comb->sadb_comb_flags = 0; + comb->sadb_comb_auth_minbits = 8; /* XXX */ + comb->sadb_comb_auth_maxbits = 1024; /* XXX */ + comb->sadb_comb_encrypt_minbits = 64; /* XXX */ + comb->sadb_comb_encrypt_maxbits = 64; /* XXX */ + comb->sadb_comb_soft_allocations = 0; + comb->sadb_comb_hard_allocations = 0; + comb->sadb_comb_soft_bytes = 0; + comb->sadb_comb_hard_bytes = 0; + comb->sadb_comb_soft_addtime = 0; + comb->sadb_comb_hard_addtime = 0; + comb->sadb_comb_soft_usetime = 0; + comb->sadb_comb_hard_usetime = 0; + + p += sizeof(*comb); + } + + error = key_sendall(newmsg, len); + if (error != 0) + printf("key_acquire: key_sendall returned %d\n", error); + return error; + } + + return 0; +} + +#ifndef IPSEC_NONBLOCK_ACQUIRE +static struct secacq * +key_newacq(saidx) + struct secasindex *saidx; +{ + struct secacq *newacq; + + /* get new entry */ + KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); + if (newacq == NULL) { + printf("key_newacq: No more memory.\n"); + return NULL; + } + bzero(newacq, sizeof(*newacq)); + + /* copy secindex */ + bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); + newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); + newacq->tick = 0; + newacq->count = 0; + + return newacq; +} + +static struct secacq * +key_getacq(saidx) + struct secasindex *saidx; +{ + struct secacq *acq; + + __LIST_FOREACH(acq, &acqtree, chain) { + if (key_cmpsaidx_exactly(saidx, &acq->saidx)) + return acq; + } - /* - * We need to add code to age these larval key table - * entries so they don't linger forever waiting for - * a KEY_UPDATE message that may not come for various - * reasons. This is another task that key_reaper can - * do once we have it coded. - */ - secassoc->lifetime1 += time_second + maxlarvallifetime; - - if (!(keynode = key_addnode(indx, secassoc))) { - DPRINTF(IDL_ERROR,("key_getspi: can't add node\n")); - CRITICAL_END; - return(ENOBUFS); - } - DPRINTF(IDL_FINISHED,("key_getspi: added node 0x%x\n", - (unsigned int)keynode)); - done++; - CRITICAL_END; - } - } - } while ((count < maxcount) && !done); - DPRINTF(IDL_EVENT,("getspi returns w/spi=%u,count=%d\n",val,count)); - if (done) { - *spi = val; - return(0); - } else { - *spi = 0; - return(EADDRNOTAVAIL); - } + return NULL; } +static struct secacq * +key_getacqbyseq(seq) + u_int32_t seq; +{ + struct secacq *acq; -/*---------------------------------------------------------------------- - * key_update(): - * Update a keytable entry that has an spi value assigned but is - * incomplete (e.g. no key/iv). - ----------------------------------------------------------------------*/ -int -key_update(secassoc) - struct key_secassoc *secassoc; -{ - struct key_tblnode *keynode, *prevkeynode; - struct key_allocnode *np = 0; - u_int8_t newstate; - int len, indx, inbound, outbound; - char buf[MAXHASHKEYLEN]; - CRITICAL_DCL - - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - if(!(keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode))) { - return(ESRCH); - } - if (keynode->secassoc->state & K_DEAD) - return(ESRCH); + __LIST_FOREACH(acq, &acqtree, chain) { + if (acq->seq == seq) + return acq; + } - /* Should we also restrict updating of only LARVAL entries ? */ + return NULL; +} +#endif - CRITICAL_START; +/* + * SADB_ACQUIRE processing, + * in first situation, is receiving + * + * from the ikmpd, and clear sequence of its secasvar entry. + * + * In second situation, is receiving + * + * from a user land process, and return + * + * to the socket. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_acquire2(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_acquire2: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* + * Error message from KMd. + * We assume that if error was occured in IKEd, the length of PFKEY + * message is equal to the size of sadb_msg structure. + * We return ~0 even if error occured in this function. + */ + if (msg0->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { + +#ifndef IPSEC_NONBLOCK_ACQUIRE + struct secacq *acq; + + /* check sequence number */ + if (msg0->sadb_msg_seq == 0) { + printf("key_acquire2: must specify sequence number.\n"); + return (struct sadb_msg *)~0; + } + + if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) == NULL) { + printf("key_acquire2: " + "invalid sequence number is passed.\n"); + return (struct sadb_msg *)~0; + } + + /* reset acq counter in order to deletion by timehander. */ + acq->tick = key_blockacq_lifetime; + acq->count = 0; +#endif + return (struct sadb_msg *)~0; + /* NOTREACHED */ + } - inbound = my_addr(secassoc->dst); - outbound = my_addr(secassoc->src); + /* + * This message is from user land. + */ - newstate = keynode->secassoc->state; - newstate &= ~K_LARVAL; + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_acquire2: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - if (inbound) - newstate |= K_INBOUND; - if (outbound) - newstate |= K_OUTBOUND; + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_EXT_PROPOSAL] == NULL) { + /* error */ + printf("key_acquire2: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - if (outbound || (!inbound && !outbound)) { - KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode)); - if (np == 0) { - DPRINTF(IDL_ERROR,("keyupdate: can't allocate allocnode!\n")); - CRITICAL_END; - return(ENOBUFS); - } - } + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); - /* - * Free the old key, iv if they're there. - */ - if (keynode->secassoc->key) - KFREE(keynode->secassoc->key); - if (keynode->secassoc->iv) - KFREE(keynode->secassoc->iv); - if (keynode->secassoc->ekey) - KFREE(keynode->secassoc->ekey); - - /* - * We now copy the secassoc over. We don't need to copy - * the key, iv into new buffers since the calling routine - * does that already. - */ - - *(keynode->secassoc) = *secassoc; - keynode->secassoc->state = newstate; - - /* - * Should we allow a null key to be inserted into the table ? - * or can we use null key to indicate some policy action... - */ - -#if 0 - if (keynode->secassoc->key && - (keynode->secassoc->type == KEY_TYPE_ESP) && - ((keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) || - (keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES))) - des_set_odd_parity(keynode->secassoc->key); -#endif /* 0 */ - - /* - * We now add an entry to the allocation table for this - * updated key table entry. - */ - if (outbound || (!inbound && !outbound)) { - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keyupdate: keyalloc hash position=%d\n", indx)); - np->keynode = keynode; - np->next = keyalloctbl[indx].next; - keyalloctbl[indx].next = np; - } + /* get a SA index */ + if ((sah = key_getsah(&saidx)) != NULL) { + printf("key_acquire2: a SA exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } - key_deleteacquire(secassoc->type, (struct sockaddr *)&(secassoc->dst)); + msg0->sadb_msg_errno = key_acquire(&saidx, NULL); + if (msg0->sadb_msg_errno != 0) { + /* XXX What I do ? */ + printf("key_acquire2: error %d returned " + "from key_acquire.\n", msg0->sadb_msg_errno); + return NULL; + } - CRITICAL_END; - return(0); -} + { + struct sadb_msg *newmsg; + u_int len; -/*---------------------------------------------------------------------- - * key_register(): - * Register a socket as one capable of acquiring security associations - * for the kernel. - ----------------------------------------------------------------------*/ -int -key_register(socket, type) - struct socket *socket; - u_int type; -{ - struct key_registry *p, *new; - CRITICAL_DCL - - CRITICAL_START; - - DPRINTF(IDL_EVENT,("Entering key_register w/so=0x%x,type=%d\n", - (unsigned int)socket,type)); - - if (!(keyregtable && socket)) - panic("key_register"); - - /* - * Make sure entry is not already in table - */ - for(p = keyregtable->next; p; p = p->next) { - if ((p->type == type) && (p->socket == socket)) { - CRITICAL_END; - return(EEXIST); - } - } + /* create new sadb_msg to reply. */ + len = PFKEY_UNUNIT64(msg0->sadb_msg_len); - KMALLOC(new, struct key_registry *, sizeof(struct key_registry)); - if (new == 0) { - CRITICAL_END; - return(ENOBUFS); - } - new->type = type; - new->socket = socket; - new->next = keyregtable->next; - keyregtable->next = new; - CRITICAL_END; - return(0); -} - -/*---------------------------------------------------------------------- - * key_unregister(): - * Delete entries from the registry list. - * allflag = 1 : delete all entries with matching socket - * allflag = 0 : delete only the entry matching socket, type - ----------------------------------------------------------------------*/ -void -key_unregister(socket, type, allflag) - struct socket *socket; - u_int type; - int allflag; -{ - struct key_registry *p, *prev; - CRITICAL_DCL - - CRITICAL_START; - - DPRINTF(IDL_EVENT,("Entering key_unregister w/so=0x%x,type=%d,flag=%d\n", - (unsigned int)socket, type, allflag)); - - if (!(keyregtable && socket)) - panic("key_register"); - prev = keyregtable; - for(p = keyregtable->next; p; p = p->next) { - if ((allflag && (p->socket == socket)) || - ((p->type == type) && (p->socket == socket))) { - prev->next = p->next; - KFREE(p); - p = prev; + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_acquire2: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy(mhp[0], (caddr_t)newmsg, len); + + return newmsg; } - prev = p; - } - CRITICAL_END; } +/* + * SADB_REGISTER processing. + * If SATYPE_UNSPEC has been passed as satype, only return sabd_supported. + * receive + * + * from the ikmpd, and register a socket to send PF_KEY messages, + * and send + * + * to KMD by PF_KEY. + * If socket is detached, must free from regnode. + * OUT: + * 0 : succeed + * others: error number + */ +static struct sadb_msg * +key_register(mhp, so) + caddr_t *mhp; + struct socket *so; +{ + struct sadb_msg *msg0; + struct secreg *reg, *newreg = 0; + + /* sanity check */ + if (mhp == NULL || so == NULL || mhp[0] == NULL) + panic("key_register: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ + if (msg0->sadb_msg_satype == SADB_SATYPE_UNSPEC) + goto setmsg; + + /* check whether existing or not */ + __LIST_FOREACH(reg, ®tree[msg0->sadb_msg_satype], chain) { + if (reg->so == so) { + printf("key_register: socket exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + } -/*---------------------------------------------------------------------- - * key_acquire(): - * Send a key_acquire message to all registered key mgnt daemons - * capable of acquire security association of type type. - * - * Return: 0 if succesfully called key mgnt. daemon(s) - * -1 if not successfull. - ----------------------------------------------------------------------*/ -int -key_acquire(type, src, dst) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; -{ - struct key_registry *p; - struct key_acquirelist *ap, *prevap; - int success = 0, created = 0; - u_int etype; - struct key_msghdr *km = NULL; - int len; - - DPRINTF(IDL_EVENT,("Entering key_acquire()\n")); - - if (!keyregtable || !src || !dst) - return (-1); - - /* - * We first check the acquirelist to see if a key_acquire - * message has been sent for this destination. - */ - etype = type; - prevap = key_acquirelist; - for(ap = key_acquirelist->next; ap; ap = ap->next) { - if (addrpart_equal(dst, ap->target) && - (etype == ap->type)) { - DPRINTF(IDL_EVENT,("acquire message previously sent!\n")); - if (ap->expiretime < time_second) { - DPRINTF(IDL_EVENT,("acquire message has expired!\n")); - ap->count = 0; - break; - } - if (ap->count < maxkeyacquire) { - DPRINTF(IDL_EVENT,("max acquire messages not yet exceeded!\n")); - break; - } - return(0); - } else if (ap->expiretime < time_second) { - /* - * Since we're already looking at the list, we may as - * well delete expired entries as we scan through the list. - * This should really be done by a function like key_reaper() - * but until we code key_reaper(), this is a quick, dirty - * hack. - */ - DPRINTF(IDL_EVENT,("found an expired entry...deleting it!\n")); - prevap->next = ap->next; - KFREE(ap); - ap = prevap; - } - prevap = ap; - } + /* create regnode */ + KMALLOC(newreg, struct secreg *, sizeof(struct secreg)); + if (newreg == NULL) { + printf("key_register: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newreg, sizeof(struct secreg)); - /* - * Scan registry, send KEY_ACQUIRE message to - * appropriate key management daemons. - */ - for(p = keyregtable->next; p; p = p->next) { - if (p->type != type) - continue; - - if (!created) { - len = sizeof(struct key_msghdr) + ROUNDUP(src->sa_len) + - ROUNDUP(dst->sa_len); - KMALLOC(km, struct key_msghdr *, len); - if (!km) { - DPRINTF(IDL_ERROR,("key_acquire: no memory\n")); - return(-1); - } - DPRINTF(IDL_FINISHED,("key_acquire/created: 1\n")); - bzero((char *)km, len); - km->key_msglen = len; - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_ACQUIRE; - km->type = type; - DPRINTF(IDL_FINISHED,("key_acquire/created: 2\n")); - /* - * This is inefficient, slow. - */ - - /* - * We zero out sin_zero here for AF_INET addresses because - * ip_output() currently does not do it for performance reasons. - */ - if (src->sa_family == AF_INET) - bzero((char *)(((struct sockaddr_in *)src)->sin_zero), - sizeof(((struct sockaddr_in *)src)->sin_zero)); - if (dst->sa_family == AF_INET) - bzero((char *)(((struct sockaddr_in *)dst)->sin_zero), - sizeof(((struct sockaddr_in *)dst)->sin_zero)); - - bcopy((char *)src, (char *)(km + 1), src->sa_len); - bcopy((char *)dst, (char *)((int)(km + 1) + ROUNDUP(src->sa_len)), - dst->sa_len); - DPRINTF(IDL_FINISHED,("key_acquire/created: 3\n")); - created++; - } - if (key_sendup(p->socket, km)) - success++; - } + newreg->so = so; + ((struct keycb *)sotorawcb(so))->kp_registered++; - if (km) - KFREE(km); - - /* - * Update the acquirelist - */ - if (success) { - if (!ap) { - DPRINTF(IDL_EVENT,("Adding new entry in acquirelist\n")); - KMALLOC(ap, struct key_acquirelist *, - sizeof(struct key_acquirelist) + dst->sa_len); - if (ap == 0) - return(success ? 0 : -1); - bzero((char *)ap, sizeof(struct key_acquirelist)); - ap->target = (struct sockaddr *)(ap + 1); - bcopy((char *)dst, (char *)ap->target, dst->sa_len); - ap->type = etype; - ap->next = key_acquirelist->next; - key_acquirelist->next = ap; - } - DPRINTF(IDL_GROSS_EVENT,("Updating acquire counter, expiration time\n")); - ap->count++; - ap->expiretime = time_second + maxacquiretime; - } - DPRINTF(IDL_EVENT,("key_acquire: done! success=%d\n",success)); - return(success ? 0 : -1); -} - -/*---------------------------------------------------------------------- - * key_alloc(): - * Allocate a security association to a socket. A socket requesting - * unique keying (per-socket keying) is assigned a security assocation - * exclusively for its use. Sockets not requiring unique keying are - * assigned the first security association which may or may not be - * used by another socket. - ----------------------------------------------------------------------*/ -static int -key_alloc(type, src, dst, socket, unique_key, keynodep) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *socket; - u_int unique_key; - struct key_tblnode **keynodep; -{ - struct key_tblnode *keynode; - char buf[MAXHASHKEYLEN]; - struct key_allocnode *np, *prevnp; - struct key_so2spinode *newnp; - int len; - int indx; - - DPRINTF(IDL_FINISHED,("Entering key_alloc w/type=%u!\n",type)); - if (!(src && dst)) { - DPRINTF(IDL_ERROR,("key_alloc: received null src or dst!\n")); - return(-1); - } + /* add regnode to regtree. */ + LIST_INSERT_HEAD(®tree[msg0->sadb_msg_satype], newreg, chain); - /* - * Search key allocation table - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - -#define np_type np->keynode->secassoc->type -#define np_state np->keynode->secassoc->state -#define np_src np->keynode->secassoc->src -#define np_dst np->keynode->secassoc->dst - - prevnp = &keyalloctbl[indx]; - for (np = keyalloctbl[indx].next; np; np = np->next) { - if ((type == np_type) && addrpart_equal(src, np_src) && - addrpart_equal(dst, np_dst) && - !(np_state & (K_LARVAL | K_DEAD | K_UNIQUE))) { - if (!(unique_key)) - break; - if (!(np_state & K_USED)) - break; - } - prevnp = np; - } + setmsg: + { + struct sadb_msg *newmsg; + struct sadb_supported *sup; + u_int len, alen, elen; + caddr_t p; + + /* create new sadb_msg to reply. */ + alen = sizeof(struct sadb_supported) + + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg)); + +#ifdef IPSEC_ESP + elen = sizeof(struct sadb_supported) + + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg)); +#else + elen = 0; +#endif - if (np) { - struct socketlist *newsp; - CRITICAL_DCL + len = sizeof(struct sadb_msg) + + alen + + elen; - CRITICAL_START; + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_register: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); - DPRINTF(IDL_EVENT,("key_alloc: found node to allocate\n")); - keynode = np->keynode; + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); - KMALLOC(newnp, struct key_so2spinode *, sizeof(struct key_so2spinode)); - if (newnp == 0) { - DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for so2spi node!\n")); - CRITICAL_END; - return(ENOBUFS); - } - KMALLOC(newsp, struct socketlist *, sizeof(struct socketlist)); - if (newsp == 0) { - DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for socketlist!\n")); - if (newnp) - KFREE(newnp); - CRITICAL_END; - return(ENOBUFS); - } + /* for authentication algorithm */ + sup = (struct sadb_supported *)p; + sup->sadb_supported_len = PFKEY_UNIT64(alen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; + p += sizeof(*sup); - /* - * Add a hash entry into the so2spi table to - * map socket to allocated secassoc. - */ - DPRINTF(IDL_FINISHED,("key_alloc: adding entry to so2spi table...")); - newnp->keynode = keynode; - newnp->socket = socket; - newnp->next = so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next; - so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next = newnp; - DPRINTF(IDL_FINISHED,("done\n")); - - if (unique_key) { - /* - * Need to remove the allocation entry - * since the secassoc is now unique, - * can't be allocated to any other socket - */ - DPRINTF(IDL_EVENT,("key_alloc: making keynode unique...")); - keynode->secassoc->state |= K_UNIQUE; - prevnp->next = np->next; - KFREE(np); - DPRINTF(IDL_EVENT,("done\n")); + { + int i; + struct sadb_alg *alg; + struct ah_algorithm *algo; + + for (i = 1; i < SADB_AALG_MAX; i++) { + algo = &ah_algorithms[i]; + alg = (struct sadb_alg *)p; + alg->sadb_alg_id = i; + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = algo->keymin; + alg->sadb_alg_maxbits = algo->keymax; + p += sizeof(struct sadb_alg); + } } - keynode->secassoc->state |= K_USED; - keynode->secassoc->state |= K_OUTBOUND; - keynode->alloc_count++; - - /* - * Add socket to list of socket using secassoc. - */ - DPRINTF(IDL_FINISHED,("key_alloc: adding so to solist...")); - newsp->socket = socket; - newsp->next = keynode->solist->next; - keynode->solist->next = newsp; - DPRINTF(IDL_FINISHED,("done\n")); - *keynodep = keynode; - CRITICAL_END; - return(0); - } - *keynodep = NULL; - return(0); -} - - -/*---------------------------------------------------------------------- - * key_free(): - * Decrement the refcount for a key table entry. If the entry is - * marked dead,, the refcount is zero, we go ahead, delete it. - ----------------------------------------------------------------------*/ -void -key_free(keynode) - struct key_tblnode *keynode; -{ - DPRINTF(IDL_GROSS_EVENT,("Entering key_free w/keynode=0x%x\n", - (unsigned int)keynode)); - if (!keynode) { - DPRINTF(IDL_ERROR,("Warning: key_free got null pointer\n")); - return; - } - (keynode->ref_count)--; - if (keynode->ref_count < 0) { - DPRINTF(IDL_ERROR,("Warning: key_free decremented refcount to %d\n",keynode->ref_count)); - } - if ((keynode->secassoc->state & K_DEAD) && (keynode->ref_count <= 0)) { - DPRINTF(IDL_GROSS_EVENT,("key_free: calling key_delete\n")); - key_delete(keynode->secassoc); - } -} - -/*---------------------------------------------------------------------- - * getassocbyspi(): - * Get a security association for a given type, src, dst,, spi. - * - * Returns: 0 if sucessfull - * -1 if error/not found - * - * Caller must convert spi to host order. Function assumes spi is - * in host order! - ----------------------------------------------------------------------*/ -int -getassocbyspi(type, src, dst, spi, keyentry) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - struct key_tblnode **keyentry; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - struct key_tblnode *keynode, *prevkeynode = 0; - - DPRINTF(IDL_FINISHED,("Entering getassocbyspi w/type=%u spi=%u\n",type,spi)); - - *keyentry = NULL; - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("getassocbyspi: indx=%d\n",indx)); - DDO(IDL_FINISHED,dump_sockaddr(src);dump_sockaddr(dst)); - keynode = key_search(type, src, dst, spi, indx, &prevkeynode); - DPRINTF(IDL_FINISHED,("getassocbyspi: keysearch ret=0x%x\n", - (unsigned int)keynode)); - if (keynode && !(keynode->secassoc->state & (K_DEAD | K_LARVAL))) { - DPRINTF(IDL_GROSS_EVENT,("getassocbyspi: found secassoc!\n")); - (keynode->ref_count)++; - keynode->secassoc->state |= K_USED; - *keyentry = keynode; - } else { - DPRINTF(IDL_EVENT,("getassocbyspi: secassoc not found!\n")); - return (-1); - } - return(0); -} +#ifdef IPSEC_ESP + /* for encryption algorithm */ + sup = (struct sadb_supported *)p; + sup->sadb_supported_len = PFKEY_UNIT64(elen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; + p += sizeof(*sup); -/*---------------------------------------------------------------------- - * getassocbysocket(): - * Get a security association for a given type, src, dst,, socket. - * If not found, try to allocate one. - * Returns: 0 if successfull - * -1 if error condition/secassoc not found (*keyentry = NULL) - * 1 if secassoc temporarily unavailable (*keynetry = NULL) - * (e.g., key mgnt. daemon(s) called) - ----------------------------------------------------------------------*/ -int -getassocbysocket(type, src, dst, socket, unique_key, keyentry) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *socket; - u_int unique_key; - struct key_tblnode **keyentry; -{ - struct key_tblnode *keynode = 0; - struct key_so2spinode *np; - u_int realtype; - - DPRINTF(IDL_FINISHED,("Entering getassocbysocket w/type=%u so=0x%x\n", - type,(unsigned int)socket)); - - /* - * We treat esp-transport mode, esp-tunnel mode - * as a single type in the keytable. This has a side - * effect that socket using both esp-transport, - * esp-tunnel will use the same security association - * for both modes. Is this a problem? - */ - realtype = type; - if ((np = key_sosearch(type, src, dst, socket))) { - if (np->keynode && np->keynode->secassoc && - !(np->keynode->secassoc->state & (K_DEAD | K_LARVAL))) { - DPRINTF(IDL_FINISHED,("getassocbysocket: found secassoc!\n")); - (np->keynode->ref_count)++; - *keyentry = np->keynode; - return(0); + { + int i; + struct sadb_alg *alg; + struct esp_algorithm *algo; + + for (i = 1; i < SADB_EALG_MAX; i++) { + algo = &esp_algorithms[i]; + + alg = (struct sadb_alg *)p; + alg->sadb_alg_id = i; + if (algo && algo->ivlen) { + /* + * give NULL to get the value preferred by algorithm + * XXX SADB_X_EXT_DERIV ? + */ + alg->sadb_alg_ivlen = (*algo->ivlen)(NULL); + } else + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = algo->keymin; + alg->sadb_alg_maxbits = algo->keymax; + p += sizeof(struct sadb_alg); + } } - } +#endif - /* - * No secassoc has been allocated to socket, - * so allocate one, if available - */ - DPRINTF(IDL_GROSS_EVENT,("getassocbyso: can't find it, trying to allocate!\n")); - if (key_alloc(realtype, src, dst, socket, unique_key, &keynode) == 0) { - if (keynode) { - DPRINTF(IDL_GROSS_EVENT,("getassocbyso: key_alloc found secassoc!\n")); - keynode->ref_count++; - *keyentry = keynode; - return(0); - } else { - /* - * Kick key mgnt. daemon(s) - * (this should be done in ipsec_output_policy() instead or - * selectively called based on a flag value) - */ - DPRINTF(IDL_FINISHED,("getassocbyso: calling key mgnt daemons!\n")); - *keyentry = NULL; - if (key_acquire(realtype, src, dst) == 0) - return (1); - else - return(-1); - } + return newmsg; } - *keyentry = NULL; - return(-1); } -/*---------------------------------------------------------------------- - * key_xdata(): - * Parse message buffer for src/dst/from/iv/key if parseflag = 0 - * else parse for src/dst only. - ----------------------------------------------------------------------*/ -static int -key_xdata(km, kip, parseflag) - struct key_msghdr *km; - struct key_msgdata *kip; - int parseflag; +/* + * free secreg entry registered. + * XXX: I want to do free a socket marked done SADB_RESIGER to socket. + */ +void +key_freereg(so) + struct socket *so; { - char *cp, *cpmax; - - if (!km || (km->key_msglen <= 0)) - return (-1); + struct secreg *reg; + int i; - cp = (caddr_t)(km + 1); - cpmax = (caddr_t)km + km->key_msglen; + /* sanity check */ + if (so == NULL) + panic("key_freereg: NULL pointer is passed.\n"); - /* - * Assumes user process passes message with - * correct word alignment. - */ + /* + * check whether existing or not. + * check all type of SA, because there is a potential that + * one socket is registered to multiple type of SA. + */ + for (i = 0; i <= SADB_SATYPE_MAX; i++) { + __LIST_FOREACH(reg, ®tree[i], chain) { + if (reg->so == so + && __LIST_CHAINED(reg)) { + LIST_REMOVE(reg, chain); + KFREE(reg); + break; + } + } + } - /* - * Need to clean up this code later. - */ + return; +} - /* Grab src addr */ - kip->src = (struct sockaddr *)cp; - if (!kip->src->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse src addr\n")); - return(-1); - } +/* + * SADB_EXPIRE processing + * send + * + * to KMD by PF_KEY. + * NOTE: We send only soft lifetime extension. + * + * OUT: 0 : succeed + * others : error number + */ +static int +key_expire(sav) + struct secasvar *sav; +{ + int s; + int satype; - ADVANCE(cp, kip->src->sa_len); + /* XXX: Why do we lock ? */ + s = splnet(); /*called from softclock()*/ - /* Grab dest addr */ - kip->dst = (struct sockaddr *)cp; - if (!kip->dst->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse dest addr\n")); - return(-1); - } + /* sanity check */ + if (sav == NULL) + panic("key_expire: NULL pointer is passed.\n"); + if (sav->sah == NULL) + panic("key_expire: Why was SA index in SA NULL.\n"); + if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0) + panic("key_expire: invalid proto is passed.\n"); - ADVANCE(cp, kip->dst->sa_len); - if (parseflag == 1) { - kip->from = 0; - kip->key = kip->iv = kip->ekey = 0; - kip->keylen = kip->ivlen = kip->ekeylen = 0; - return(0); - } - - /* Grab from addr */ - kip->from = (struct sockaddr *)cp; - if (!kip->from->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse from addr\n")); - return(-1); - } + { + struct sadb_msg *newmsg = NULL; + u_int len; + caddr_t p; + int error; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sav->sah->saidx.src.__ss_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sav->sah->saidx.dst.__ss_len); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_expire: No more memory.\n"); + splx(s); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); - ADVANCE(cp, kip->from->sa_len); - - /* Grab key */ - if ((kip->keylen = km->keylen)) { - kip->key = cp; - ADVANCE(cp, km->keylen); - } else - kip->key = 0; + /* set msg header */ + p = key_setsadbmsg((caddr_t)newmsg, SADB_EXPIRE, len, + satype, sav->seq, 0, + sav->sah->saidx.mode, sav->refcnt); - /* Grab iv */ - if ((kip->ivlen = km->ivlen)) { - kip->iv = cp; - ADVANCE(cp, km->ivlen); - } else - kip->iv = 0; + /* create SA extension */ + p = key_setsadbsa(p, sav); - /* Grab ekey */ - if ((kip->ekeylen = km->ekeylen)) { - kip->ekey = cp; - ADVANCE(cp, km->ekeylen); - } else - kip->ekey = 0; + /* create lifetime extension */ + { + struct sadb_lifetime *m_lt = (struct sadb_lifetime *)p; + + m_lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + m_lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + m_lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; + m_lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; + m_lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; + m_lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; + p += sizeof(struct sadb_lifetime); + + /* copy SOFT lifetime extension. */ + bcopy(sav->lft_s, p, sizeof(struct sadb_lifetime)); + p += sizeof(struct sadb_lifetime); + } - return (0); + /* set sadb_address for source */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + /* set sadb_address for destination */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + error = key_sendall(newmsg, len); + splx(s); + return error; + } } - -int -key_parse(kmp, so, dstfamily) - struct key_msghdr **kmp; - struct socket *so; - int *dstfamily; +/* + * SADB_FLUSH processing + * receive + * + * from the ikmpd, and free all entries in secastree. + * and send, + * + * to the ikmpd. + * NOTE: to do is only marking SADB_SASTATE_DEAD. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_flush(mhp) + caddr_t *mhp; { - int error = 0, keyerror = 0; - struct key_msgdata keyinfo; - struct key_secassoc *secassoc = NULL; - struct key_msghdr *km = *kmp; + struct sadb_msg *msg0; + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; + u_int16_t proto; + u_int8_t state; + u_int stateidx; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_flush: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_flush: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - DPRINTF(IDL_MAJOR_EVENT, ("Entering key_parse\n")); + /* no SATYPE specified, i.e. flushing all SA. */ + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { -#define senderr(e) \ - { error = (e); goto flush; } + nextsah = LIST_NEXT(sah, chain); - if (km->key_msgvers != KEY_VERSION) { - DPRINTF(IDL_CRITICAL,("keyoutput: Unsupported key message version!\n")); - senderr(EPROTONOSUPPORT); - } + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; - km->key_pid = curproc->p_pid; + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { - DDO(IDL_MAJOR_EVENT, printf("keymsghdr:\n"); dump_keymsghdr(km)); + state = saorder_state_any[stateidx]; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { - /* - * Parse buffer for src addr, dest addr, from addr, key, iv - */ - bzero((char *)&keyinfo, sizeof(keyinfo)); + nextsav = LIST_NEXT(sav, chain); - switch (km->key_msgtype) { - case KEY_ADD: - DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_ADD msg\n")); + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + } + } - if (key_xdata(km, &keyinfo, 0) < 0) - goto parsefail; + sah->state = SADB_SASTATE_DEAD; + } - /* - * Allocate the secassoc structure to insert - * into key table here. - */ - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: No more memory!\n")); - senderr(ENOBUFS); - } + { + struct sadb_msg *newmsg; + u_int len; - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: key_msghdr2secassoc failed!\n")); - KFREE(secassoc); - senderr(EINVAL); - } - DPRINTF(IDL_MAJOR_EVENT,("secassoc to add:\n")); - DDO(IDL_MAJOR_EVENT,dump_secassoc(secassoc)); - - if ((keyerror = key_add(secassoc)) != 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: key_add failed\n")); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - if (keyerror == -2) { - senderr(EEXIST); - } else { - senderr(ENOBUFS); - } - } - break; - case KEY_DELETE: - DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_DELETE msg\n")); + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg); - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_flush: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - senderr(ENOBUFS); - } - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - KFREE(secassoc); - senderr(EINVAL); - } - if (key_delete(secassoc) != 0) { - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - senderr(ESRCH); - } - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - break; - case KEY_UPDATE: - DPRINTF(IDL_EVENT,("key_output got KEY_UPDATE msg\n")); - - if (key_xdata(km, &keyinfo, 0) < 0) - goto parsefail; - - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - senderr(ENOBUFS); - } - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - KFREE(secassoc); - senderr(EINVAL); - } - if ((keyerror = key_update(secassoc)) != 0) { - DPRINTF(IDL_CRITICAL,("Error updating key entry\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - senderr(keyerror); - } - KFREE(secassoc); - break; - case KEY_GET: - DPRINTF(IDL_EVENT,("key_output got KEY_GET msg\n")); - - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; - - if (key_get(km->type, (struct sockaddr *)keyinfo.src, - (struct sockaddr *)keyinfo.dst, - km->spi, &secassoc) != 0) { - DPRINTF(IDL_EVENT,("keyoutput: can't get key\n")); - senderr(ESRCH); - } + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); - if (secassoc) { - int newlen; - - DPRINTF(IDL_EVENT,("keyoutput: Found secassoc!\n")); - newlen = sizeof(struct key_msghdr) + ROUNDUP(secassoc->src->sa_len) + - ROUNDUP(secassoc->dst->sa_len) + ROUNDUP(secassoc->from->sa_len) + - ROUNDUP(secassoc->keylen) + ROUNDUP(secassoc->ivlen) + - ROUNDUP(secassoc->ekeylen); - DPRINTF(IDL_EVENT,("keyoutput: newlen=%d\n", newlen)); - if (newlen > km->key_msglen) { - struct key_msghdr *newkm; - - DPRINTF(IDL_EVENT,("keyoutput: Allocating new buffer!\n")); - KMALLOC(newkm, struct key_msghdr *, newlen); - if (newkm == 0) { - senderr(ENOBUFS); - } - bcopy((char *)km, (char *)newkm, km->key_msglen); - DPRINTF(IDL_FINISHED,("keyoutput: 1\n")); - KFREE(km); - *kmp = km = newkm; - DPRINTF(IDL_CRITICAL, ("km->key_msglen = %d, newlen = %d\n", - km->key_msglen, newlen)); - km->key_msglen = newlen; - } - DPRINTF(IDL_FINISHED,("keyoutput: 2\n")); - if (key_secassoc2msghdr(secassoc, km, &keyinfo)) { - DPRINTF(IDL_CRITICAL,("keyoutput: Can't create msghdr!\n")); - senderr(EINVAL); - } - DPRINTF(IDL_FINISHED,("keyoutput: 3\n")); + return newmsg; } - break; - case KEY_GETSPI: - DPRINTF(IDL_EVENT,("key_output got KEY_GETSPI msg\n")); - - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; - - if ((keyerror = key_getspi(km->type, km->vers, keyinfo.src, keyinfo.dst, - km->lifetime1, km->lifetime2, - &(km->spi))) != 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: getspi failed error=%d\n", keyerror)); - senderr(keyerror); - } - break; - case KEY_REGISTER: - DPRINTF(IDL_EVENT,("key_output got KEY_REGISTER msg\n")); - key_register(so, km->type); - break; - case KEY_DUMP: - DPRINTF(IDL_EVENT,("key_output got KEY_DUMP msg\n")); - error = key_dump(so); - return(error); - break; - case KEY_FLUSH: - DPRINTF(IDL_EVENT,("key_output got KEY_FLUSH msg\n")); - key_flush(); - break; - default: - DPRINTF(IDL_CRITICAL,("key_output got unsupported msg type=%d\n", - km->key_msgtype)); - senderr(EOPNOTSUPP); - } - - goto flush; - -parsefail: - keyinfo.dst = NULL; - error = EINVAL; - -flush: - if (km) - km->key_errno = error; - - if (dstfamily) - *dstfamily = keyinfo.dst ? keyinfo.dst->sa_family : 0; - - DPRINTF(IDL_MAJOR_EVENT, ("key_parse exiting with error=%d\n", error)); - return error; } /* - * Definitions of protocols supported in the KEY domain. + * SADB_DUMP processing + * dump all entries including status of DEAD in SAD. + * receive + * + * from the ikmpd, and dump all secasvar leaves + * and send, + * ..... + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: error code. 0 on success. */ +static int +key_dump(mhp, so, target) + caddr_t *mhp; + struct socket *so; + int target; +{ + struct sadb_msg *msg0; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + u_int stateidx; + u_int8_t satype; + u_int8_t state; + int len, cnt; + struct sadb_msg *newmsg; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_dump: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_dump: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } -struct sockaddr key_addr = { 2, PF_KEY, }; -struct sockproto key_proto = { PF_KEY, }; + /* count sav entries to be sent to the userland. */ + cnt = 0; + __LIST_FOREACH(sah, &sahtree, chain) { -#define KEYREAPERINT 120 + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; -static int -key_sendup(s, km) - struct socket *s; - struct key_msghdr *km; -{ - struct mbuf *m; - - if (!km) - panic("km == NULL in key_sendup\n"); - MGETHDR(m, M_WAIT, MT_DATA); - m->m_len = m->m_pkthdr.len = 0; - m->m_next = 0; - m->m_nextpkt = 0; - m->m_pkthdr.rcvif = 0; - if (km) - m_copyback(m, 0, km->key_msglen, (caddr_t)km); - - if (sbappendaddr(&(s->so_rcv), &key_addr, m, NULL)) { - sorwakeup(s); - return 1; - } else { - if (m) m_freem(m); - } + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { - return(0); -} + state = saorder_state_any[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + cnt++; + } + } + } -#ifdef notyet -/*---------------------------------------------------------------------- - * key_reaper(): - * Scan key table, nuke unwanted entries - ----------------------------------------------------------------------*/ -static void -key_reaper(whocares) - void *whocares; -{ - DPRINTF(IDL_GROSS_EVENT,("Entering key_reaper()\n")); + if (cnt == 0) + return ENOENT; + + /* send this to the userland, one at a time. */ + newmsg = NULL; + __LIST_FOREACH(sah, &sahtree, chain) { + + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; + + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { + printf("key_dump: there was invalid proto in SAD.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + len = key_getmsglen(sav); + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_dump: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + --cnt; + (void)key_setdumpsa(newmsg, sav, SADB_DUMP, + satype, cnt, msg0->sadb_msg_pid); + + key_sendup(so, newmsg, len, target); + KFREE(newmsg); + newmsg = NULL; + } + } + } - timeout(key_reaper, NULL, KEYREAPERINT * HZ); + return 0; } -#endif /* notyet */ -/*---------------------------------------------------------------------- - * key_init(): - * Init routine for key socket, key engine - ----------------------------------------------------------------------*/ +/* + * SADB_X_PROMISC processing + */ static void -key_init() +key_promisc(mhp, so) + caddr_t *mhp; + struct socket *so; { - DPRINTF(IDL_EVENT,("Called key_init().\n")); - if (key_inittables()) - panic("key_inittables failed!\n"); -#ifdef notyet - timeout(key_reaper, NULL, HZ); -#endif /* notyet */ - bzero((char *)&keyso_cb, sizeof(keyso_cb)); + struct sadb_msg *msg0; + int olen; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_promisc: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + olen = PFKEY_UNUNIT64(msg0->sadb_msg_len); + + if (olen < sizeof(struct sadb_msg)) { + return; + } else if (olen == sizeof(struct sadb_msg)) { + /* enable/disable promisc mode */ + struct keycb *kp; + int target = 0; + + target = KEY_SENDUP_ONE; + + if (so == NULL) { + return; + } + if ((kp = (struct keycb *)sotorawcb(so)) == NULL) { + msg0->sadb_msg_errno = EINVAL; + goto sendorig; + } + msg0->sadb_msg_errno = 0; + if (msg0->sadb_msg_satype == 1 || msg0->sadb_msg_satype == 0) { + kp->kp_promisc = msg0->sadb_msg_satype; + } else { + msg0->sadb_msg_errno = EINVAL; + goto sendorig; + } + + /* send the original message back to everyone */ + msg0->sadb_msg_errno = 0; + target = KEY_SENDUP_ALL; +sendorig: + key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), target); + } else { + /* send packet as is */ + struct sadb_msg *msg; + int len; + + len = olen - sizeof(struct sadb_msg); + KMALLOC(msg, struct sadb_msg *, len); + if (msg == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), + KEY_SENDUP_ONE); /*XXX*/ + } + + /* XXX if sadb_msg_seq is specified, send to specific pid */ + key_sendup(so, msg, len, KEY_SENDUP_ALL); + KFREE(msg); + } } -/*---------------------------------------------------------------------- - * my_addr(): - * Determine if an address belongs to one of my configured interfaces. - * Currently handles only AF_INET, AF_INET6 addresses. - ----------------------------------------------------------------------*/ +/* + * send message to the socket. + * OUT: + * 0 : success + * others : fail + */ static int -my_addr(sa) - struct sockaddr *sa; +key_sendall(msg, len) + struct sadb_msg *msg; + u_int len; { - switch(sa->sa_family) { -#ifdef INET6 - case AF_INET6: { - struct in6_ifaddr *i6a = 0; - - for (i6a = in6_ifaddr; i6a; i6a = i6a->ia_next) { /*XXX*/ - if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa)->sin6_addr, - &i6a->ia_addr.sin6_addr)) - return(1); - } - } - break; -#endif /* INET6 */ - case AF_INET: { - struct in_ifaddr *ia = 0; + struct secreg *reg; + int error = 0; + + /* sanity check */ + if (msg == NULL) + panic("key_sendall: NULL pointer is passed.\n"); + + /* search table registerd socket to send a message. */ + __LIST_FOREACH(reg, ®tree[msg->sadb_msg_satype], chain) { + error = key_sendup(reg->so, msg, len, KEY_SENDUP_ONE); + if (error != 0) { + if (error == ENOBUFS) + printf("key_sendall: No more memory.\n"); + else { + printf("key_sendall: key_sendup returned %d\n", + error); + } + KFREE(msg); + return error; + } + } - for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { - if (((struct sockaddr_in *)sa)->sin_addr.s_addr == - ia->ia_addr.sin_addr.s_addr) - return(1); - } - } - break; - } - return(0); + KFREE(msg); + return 0; } -/*---------------------------------------------------------------------- - * key_output(): - * Process outbound pf_key message. - ----------------------------------------------------------------------*/ -static int -key_output(m, so) - struct mbuf *m; - struct socket *so; +/* + * parse sadb_msg buffer to process PFKEYv2, + * and create a data to response if needed. + * I think to be dealed with mbuf directly. + * IN: + * msgp : pointer to pointer to a received buffer pulluped. + * This is rewrited to response. + * so : pointer to socket. + * OUT: + * length for buffer to send to user process. + */ +int +key_parse(msgp, so, targetp) + struct sadb_msg **msgp; + struct socket *so; + int *targetp; { - struct key_msghdr *km = 0; - int len; - int error = 0; - int dstfamily = 0; + struct sadb_msg *msg = *msgp, *newmsg = NULL; + caddr_t mhp[SADB_EXT_MAX + 1]; + u_int orglen; + int error; - DPRINTF(IDL_EVENT,("key_output() got a message len=%d.\n", m->m_pkthdr.len)); + /* sanity check */ + if (msg == NULL || so == NULL) + panic("key_parse: NULL pointer is passed.\n"); -#undef senderr -#define senderr(e) \ - { error = (e); if (km) km->key_errno = error; goto flush; } + KEYDEBUG(KEYDEBUG_KEY_DUMP, + printf("key_parse: passed sadb_msg\n"); + kdebug_sadb(msg)); - if (m == 0 || ((m->m_len < sizeof(long)) && - (m = m_pullup(m, sizeof(long))) == 0)) { - DPRINTF(IDL_CRITICAL,("key_output can't pullup mbuf\n")); - return (ENOBUFS); - } - if ((m->m_flags & M_PKTHDR) == 0) - panic("key_output"); - - DDO(IDL_FINISHED,dump_mbuf(m)); - - len = m->m_pkthdr.len; - if (len < sizeof(*km) || len != mtod(m, struct key_msghdr *)->key_msglen) { - DPRINTF(IDL_CRITICAL,("keyout: Invalid length field/length mismatch!\n")); - senderr(EINVAL); - } - KMALLOC(km, struct key_msghdr *, len); - if (km == 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: Can't malloc memory!\n")); - senderr(ENOBUFS); - } + orglen = PFKEY_UNUNIT64(msg->sadb_msg_len); - m_copydata(m, 0, len, (caddr_t)km); + if (targetp) + *targetp = KEY_SENDUP_ONE; - km->key_errno = error = key_parse(&km, so, &dstfamily); - DPRINTF(IDL_MAJOR_EVENT, ("Back from key_parse\n")); -flush: - if (km) - key_sendup(so, km); -#if 0 - { - struct rawcb *rp = 0; - struct mbuf *m; - - if ((so->so_options & SO_USELOOPBACK) == 0) { - if (keyso_cb.any_count <= 1) { - if (km) - KFREE(km); - return (error); - } - rp = sotorawcb(so); - } + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + printf("key_parse: PF_KEY version %u is mismatched.\n", + msg->sadb_msg_version); + return EINVAL; + } - DPRINTF(IDL_MAJOR_EVENT, ("key_output: foo\n")); - key_proto.sp_protocol = dstfamily; + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } - if (km) { - m = m_devget(km, len, 0, NULL, NULL); - KFREE(km); - } + /* align message. */ + if (key_align(msg, mhp) != 0) { + msg->sadb_msg_errno = EINVAL; + return orglen; + } - DPRINTF(IDL_MAJOR_EVENT, ("key_output: bar\n")); - if (rp) - rp->rcb_proto.sp_family = 0; /* Prevent us from receiving message */ + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + printf("key_parse: must specify satype " + "when msg type=%u.\n", + msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + break; + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + printf("key_parse: illegal satype=%u\n", msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + printf("key_parse: type %u isn't supported.\n", + msg->sadb_msg_satype); + msg->sadb_msg_errno = EOPNOTSUPP; + return orglen; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_satype); + msg->sadb_msg_errno = EINVAL; + return orglen; + } - raw_input(m, &key_proto, &key_addr, &key_addr); + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + u_int prefix; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + /* check upper layer protocol */ + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + printf("key_parse: upper layer protocol mismatched.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* check family */ + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + printf("key_parse: address family mismatched.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + prefix = _INALENBYAF(PFKEY_ADDR_SADDR(src0)->sa_family) << 3; + + /* check max prefixlen */ + if (prefix < src0->sadb_address_prefixlen + || prefix < dst0->sadb_address_prefixlen) { + printf("key_parse: illegal prefixlen.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + printf("key_parse: invalid address family.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* + * prefixlen == 0 is valid because there can be a case when + * all addresses are matched. + */ + } - if (rp) - rp->rcb_proto.sp_family = PF_KEY; - } - DPRINTF(IDL_MAJOR_EVENT, ("key_output: baz\n")); -#endif /* 0 */ - return (error); -} + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + if ((newmsg = key_getspi(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_UPDATE: + if ((newmsg = key_update(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_ADD: + if ((newmsg = key_add(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_DELETE: + if ((newmsg = key_delete(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_GET: + if ((newmsg = key_get(mhp)) == NULL) + return orglen; + break; + + case SADB_ACQUIRE: + if ((newmsg = key_acquire2(mhp)) == NULL) + return orglen; + + if (newmsg == (struct sadb_msg *)~0) { + /* + * It's not need to reply because of the message + * that was reporting an error occured from the KMd. + */ + KFREE(msg); + return 0; + } + break; + + case SADB_REGISTER: + if ((newmsg = key_register(mhp, so)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_REGISTERED; + break; + + case SADB_EXPIRE: + printf("key_parse: why is SADB_EXPIRE received ?\n"); + msg->sadb_msg_errno = EINVAL; + if (targetp) + *targetp = KEY_SENDUP_ALL; + return orglen; + + case SADB_FLUSH: + if ((newmsg = key_flush(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_DUMP: + /* key_dump will call key_sendup() on her own */ + error = key_dump(mhp, so, KEY_SENDUP_ONE); + if (error) { + msg->sadb_msg_errno = error; + return orglen; + } else { + KFREE(msg); + return 0; + } + break; + + case SADB_X_PROMISC: + /* everything is handled in key_promisc() */ + key_promisc(mhp, so); + KFREE(msg); + return 0; /*nothing to reply*/ + + case SADB_X_PCHANGE: + printf("key_parse: SADB_X_PCHANGE isn't supported.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + + case SADB_X_SPDADD: + if ((newmsg = key_spdadd(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_X_SPDDELETE: + if ((newmsg = key_spddelete(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_X_SPDDUMP: + /* key_spddump will call key_sendup() on her own */ + error = key_spddump(mhp, so, KEY_SENDUP_ONE); + if (error) { + msg->sadb_msg_errno = error; + return orglen; + } else { + KFREE(msg); + return 0; + } + break; + + + case SADB_X_SPDFLUSH: + if ((newmsg = key_spdflush(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + default: + msg->sadb_msg_errno = EOPNOTSUPP; + return orglen; + } + /* switch from old sadb_msg to new one if success. */ + KFREE(msg); + *msgp = newmsg; -/*---------------------------------------------------------------------- - * key_*(): - * Handles protocol requests for pf_key sockets. - ----------------------------------------------------------------------*/ + return PFKEY_UNUNIT64((*msgp)->sadb_msg_len); +} +/* + * set the pointer to each header into message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer allocated like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: 0: + * EINVAL: + */ static int -key_attach(struct socket *so, int proto, struct proc *p) +key_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; { - register int error = 0; - register struct rawcb *rp; - int s; + struct sadb_ext *ext; + int tlen, extlen; + int i; + + /* sanity check */ + if (msg == NULL || mhp == NULL) + panic("key_align: NULL pointer is passed.\n"); + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg)); + + while (tlen > 0) { + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + printf("key_align: duplicate ext_type %u is passed.\n", + ext->sadb_ext_type); + return EINVAL; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* must to be chek weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* must to be chek weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + printf("key_align: invalid ext_type %u is passed.\n", + ext->sadb_ext_type); + return EINVAL; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } - DPRINTF(IDL_EVENT,("Entering key_attach\n")); + return 0; +} - MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); - if (rp) { - bzero(rp, sizeof(*rp)); - so->so_pcb = (caddr_t)rp; - } - s = splnet(); - error = (raw_usrreqs.pru_attach)(so, proto, p); - if (!error) { /* XXX was: if (!so) which didn't make sense */ - splx(s); - return error; - } +void +key_init() +{ + int i; - rp = sotorawcb(so); /* isn't this redundant? */ - if (rp) { - int af = rp->rcb_proto.sp_protocol; - if (error) { - free((caddr_t)rp, M_PCB); - splx(s); - return error; - } - if (af == AF_INET) - keyso_cb.ip4_count++; -#ifdef INET6 - else if (af == AF_INET6) - keyso_cb.ip6_count++; -#endif /* INET6 */ - keyso_cb.any_count++; -#if 0 /*itojun*/ - rp->rcb_faddr = &key_addr; -#else - { - struct mbuf *m; - MGET(m, M_DONTWAIT, MT_DATA); - if (m) { /* XXX but what about sin_len here? -PW */ - rp->rcb_faddr = mtod(m, struct sockaddr *); - bcopy(&key_addr, rp->rcb_faddr, sizeof(struct sockaddr)); - } else - rp->rcb_faddr = NULL; - } -#endif - soisconnected(so); /* Key socket, like routing socket, must be - connected. */ + bzero((caddr_t)&key_cb, sizeof(key_cb)); - /* Possibly set other needed flags/options at creation time in here. */ - so->so_options |= SO_USELOOPBACK; /* Like routing socket, we turn this */ - /* on by default */ - } - splx(s); - return error; -} + for (i = 0; i < IPSEC_DIR_MAX; i++) { + LIST_INIT(&sptree[i]); + } -static int -key_detach(struct socket *so) -{ - register int error = 0; - register struct rawcb *rp; - int s; + LIST_INIT(&sahtree); + + for (i = 0; i <= SADB_SATYPE_MAX; i++) { + LIST_INIT(®tree[i]); + } - DPRINTF(IDL_EVENT,("Entering key_detach\n")); +#ifndef IPSEC_NONBLOCK_ACQUIRE + LIST_INIT(&acqtree); +#endif - rp = sotorawcb(so); - if (rp) { - int af = rp->rcb_proto.sp_protocol; - if (af == AF_INET) - keyso_cb.ip4_count--; + /* system default */ + ip4_def_policy.policy = IPSEC_POLICY_NONE; + ip4_def_policy.refcnt++; /*never reclaim this*/ #ifdef INET6 - else if (af == AF_INET6) - keyso_cb.ip6_count--; -#endif /* INET6 */ - keyso_cb.any_count--; - } - s = splnet(); - error = (raw_usrreqs.pru_detach)(so); - splx(s); - return error; + ip6_def_policy.policy = IPSEC_POLICY_NONE; + ip6_def_policy.refcnt++; /*never reclaim this*/ +#endif -} +#ifndef IPSEC_DEBUG2 + timeout((void *)key_timehandler, (void *)0, 100); +#endif /*IPSEC_DEBUG2*/ -static int -key_abort(struct socket *so) -{ - DPRINTF(IDL_EVENT,("Entering key_abort\n")); + /* initialize key statistics */ + keystat.getspi_count = 1; - return (raw_usrreqs.pru_abort)(so); + printf("IPsec: Initialized Security Association Processing.\n"); + + return; } -static int -key_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +/* + * XXX: maybe This function is called after INBOUND IPsec processing. + * + * Special check for tunnel-mode packets. + * We must make some checks for consistency between inner and outer IP header. + * + * xxx more checks to be provided + */ +int +key_checktunnelsanity(sav, family, src, dst) + struct secasvar *sav; + u_int family; + caddr_t src; + caddr_t dst; { - DPRINTF(IDL_EVENT,("Entering key_bind\n")); + /* sanity check */ + if (sav->sah == NULL) + panic("sav->sah == NULL at key_checktunnelsanity"); + + /* XXX: check inner IP header */ - return (raw_usrreqs.pru_bind)(so, nam, p); + return 1; } -static int -key_connect(struct socket *so, struct sockaddr *nam, struct proc *p) -{ - DPRINTF(IDL_EVENT,("Entering key_connect\n")); +#if 0 +#ifdef __FreeBSD__ +#define hostnamelen strlen(hostname) +#endif - return (raw_usrreqs.pru_connect)(so, nam, p); +/* + * Get FQDN for the host. + * If the administrator configured hostname (by hostname(1)) without + * domain name, returns nothing. + */ +static const char * +key_getfqdn() +{ + int i; + int hasdot; + static char fqdn[MAXHOSTNAMELEN + 1]; + + if (!hostnamelen) + return NULL; + + /* check if it comes with domain name. */ + hasdot = 0; + for (i = 0; i < hostnamelen; i++) { + if (hostname[i] == '.') + hasdot++; + } + if (!hasdot) + return NULL; + + /* NOTE: hostname may not be NUL-terminated. */ + bzero(fqdn, sizeof(fqdn)); + bcopy(hostname, fqdn, hostnamelen); + fqdn[hostnamelen] = '\0'; + return fqdn; } -static int -key_disconnect(struct socket *so) +/* + * get username@FQDN for the host/user. + */ +static const char * +key_getuserfqdn() { - DPRINTF(IDL_EVENT,("Entering key_disconnect\n")); - - return (raw_usrreqs.pru_disconnect)(so); + const char *host; + static char userfqdn[MAXHOSTNAMELEN + MAXLOGNAME + 2]; + struct proc *p = curproc; + char *q; + + if (!p || !p->p_pgrp || !p->p_pgrp->pg_session) + return NULL; + if (!(host = key_getfqdn())) + return NULL; + + /* NOTE: s_login may not be-NUL terminated. */ + bzero(userfqdn, sizeof(userfqdn)); + bcopy(p->p_pgrp->pg_session->s_login, userfqdn, MAXLOGNAME); + userfqdn[MAXLOGNAME] = '\0'; /* safeguard */ + q = userfqdn + strlen(userfqdn); + *q++ = '@'; + bcopy(host, q, strlen(host)); + q += strlen(host); + *q++ = '\0'; + + return userfqdn; } +#endif -static int -key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, - struct mbuf *control, struct proc *p) +/* record data transfer on SA, and update timestamps */ +void +key_sa_recordxfer(sav, m) + struct secasvar *sav; + struct mbuf *m; { - DPRINTF(IDL_EVENT,("Entering key_send\n")); + if (!sav) + panic("key_sa_recordxfer called with sav == NULL"); + if (!m) + panic("key_sa_recordxfer called with m == NULL"); + if (!sav->lft_c) + return; + + sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len; + /* to check bytes lifetime is done in key_timehandler(). */ + + /* + * We use the number of packets as the unit of + * sadb_lifetime_allocations. We increment the variable + * whenever {esp,ah}_{in,out}put is called. + */ + sav->lft_c->sadb_lifetime_allocations++; + /* XXX check for expires? */ + + /* + * NOTE: We record CURRENT sadb_lifetime_usetime by using wall clock, + * in seconds. HARD and SOFT lifetime are measured by the time + * difference (again in seconds) from sadb_lifetime_usetime. + * + * usetime + * v expire expire + * -----+-----+--------+---> t + * <--------------> HARD + * <-----> SOFT + */ + { + struct timeval tv; + microtime(&tv); + sav->lft_c->sadb_lifetime_usetime = tv.tv_sec; + /* XXX check for expires? */ + } - return (raw_usrreqs.pru_send)(so, flags, m, nam, control, p); + return; } -static int -key_shutdown(struct socket *so) +/* dumb version */ +void +key_sa_routechange(dst) + struct sockaddr *dst; { - DPRINTF(IDL_EVENT,("Entering key_shutdown\n")); + struct secashead *sah; + struct route *ro; + + __LIST_FOREACH(sah, &sahtree, chain) { + ro = &sah->sa_route; + if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len + && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)NULL; + } + } - return (raw_usrreqs.pru_shutdown)(so); + return; } -/*---------------------------------------------------------------------- - * key_cbinit(): - * Control block init routine for key socket - ----------------------------------------------------------------------*/ static void -key_cbinit() +key_sa_chgstate(sav, state) + struct secasvar *sav; + u_int8_t state; { - /* - * This is equivalent to raw_init for the routing socket. - * The key socket uses the same control block as the routing - * socket. - */ - DPRINTF(IDL_EVENT,("Called key_cbinit().\n")); -} - -/* - * Protoswitch entry for pf_key - */ - -extern struct domain keydomain; /* or at least forward */ + if (sav == NULL) + panic("key_sa_chgstate called with sav == NULL"); -struct pr_usrreqs key_usrreqs = { - key_abort, pru_accept_notsupp, key_attach, key_bind, key_connect, - pru_connect2_notsupp, in_control, key_detach, key_disconnect, - pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, - pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown, - in_setsockaddr, sosend, soreceive, sopoll -}; - - -struct protosw keysw[] = { -{ SOCK_RAW, &keydomain, 0, PR_ATOMIC|PR_ADDR, - 0, key_output, raw_ctlinput, 0, - 0, - key_cbinit, 0, 0, 0, - &key_usrreqs, -}, -}; + if (sav->state == state) + return; -struct domain keydomain = - { PF_KEY, "key", key_init, 0, 0, - keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); -#ifdef __FreeBSD__ -DOMAIN_SET(key); -#endif - -#endif /*KEY*/ + sav->state = state; + LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); +} diff --git a/sys/netkey/key.h b/sys/netkey/key.h index ccd2fc7..ec02403 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,299 +1,78 @@ -/*---------------------------------------------------------------------- - * key.h : Declarations and Definitions for Key Engine for BSD. +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. * - * Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald, - * All Rights Reserved. All rights have been assigned to the US - * Naval Research Laboratory (NRL). The NRL Copyright Notice and - * License Agreement governs distribution and use of this software. + * 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. * - * Patents are pending on this technology. NRL grants a license - * to use this technology at no cost under the terms below with - * the additional requirement that software, hardware, and - * documentation relating to use of this technology must include - * the note that: - * This product includes technology developed at and - * licensed from the Information Technology Division, - * US Naval Research Laboratory. + * 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. * - ----------------------------------------------------------------------*/ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - -#ifndef _netkey_key_h -#define _netkey_key_h 1 - -/* - * PF_KEY messages - */ - -#define KEY_ADD 1 -#define KEY_DELETE 2 -#define KEY_UPDATE 3 -#define KEY_GET 4 -#define KEY_ACQUIRE 5 -#define KEY_GETSPI 6 -#define KEY_REGISTER 7 -#define KEY_EXPIRE 8 -#define KEY_DUMP 9 -#define KEY_FLUSH 10 - -#define KEY_VERSION 1 -#define POLICY_VERSION 1 - -#define SECURITY_TYPE_NONE 0 - -#define KEY_TYPE_AH 1 -#define KEY_TYPE_ESP 2 -#define KEY_TYPE_RSVP 3 -#define KEY_TYPE_OSPF 4 -#define KEY_TYPE_RIPV2 5 -#define KEY_TYPE_MIPV4 6 -#define KEY_TYPE_MIPV6 7 -#define KEY_TYPE_MAX 7 - -/* - * Security association state + * $FreeBSD$ */ -#define K_USED 0x1 /* Key used/not used */ -#define K_UNIQUE 0x2 /* Key unique/reusable */ -#define K_LARVAL 0x4 /* SPI assigned, but sa incomplete */ -#define K_ZOMBIE 0x8 /* sa expired but still useable */ -#define K_DEAD 0x10 /* sa marked for deletion, ready for reaping */ -#define K_INBOUND 0x20 /* sa for inbound packets, ie. dst=myhost */ -#define K_OUTBOUND 0x40 /* sa for outbound packets, ie. src=myhost */ - - -#ifndef MAX_SOCKADDR_SZ -#ifdef INET6 -#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in6)) -#else /* INET6 */ -#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in)) -#endif /* INET6 */ -#endif /* MAX_SOCKADDR_SZ */ - -#ifndef MAX_KEY_SZ -#define MAX_KEY_SZ 16 -#endif /* MAX_KEY_SZ */ - -#ifndef MAX_IV_SZ -#define MAX_IV_SZ 16 -#endif /* MAX_IV_SZ */ - -/* Security association data for IP Security */ -struct key_secassoc { - u_int8_t len; /* Length of the data (for radix) */ - u_int8_t type; /* Type of association */ - u_int8_t vers; /* Version of association (AH/ESP) */ - u_int8_t state; /* State of the association */ - u_int8_t label; /* Sensitivity label (unused) */ - u_int32_t spi; /* SPI */ - u_int8_t keylen; /* Key length */ - u_int8_t ekeylen; /* Extra key length */ - u_int8_t ivlen; /* Initialization vector length */ - u_int8_t algorithm; /* Algorithm switch index */ - u_int8_t lifetype; /* Type of lifetime */ - caddr_t iv; /* Initialization vector */ - caddr_t key; /* Key */ - caddr_t ekey; /* Extra key */ - u_int32_t lifetime1; /* Lifetime value 1 */ - u_int32_t lifetime2; /* Lifetime value 2 */ - struct sockaddr *src; /* Source host address */ - struct sockaddr *dst; /* Destination host address */ - struct sockaddr *from; /* Originator of association */ - - int antireplay; /*anti replay flag*/ - u_int32_t sequence; /*send: sequence number*/ - u_int32_t replayright; /*receive: replay window, right*/ - u_int64_t replaywindow; /*receive: replay window*/ -}; - -/* - * Structure for key message header. PF_KEY message consists of key_msghdr - * followed by src struct sockaddr, dest struct sockaddr, from struct - * sockaddr, key, and iv. Assumes size of key message header less than MHLEN. - */ - -struct key_msghdr { - u_short key_msglen; /* length of message including - * src/dst/from/key/iv */ - u_char key_msgvers; /* key version number */ - u_char key_msgtype; /* key message type, eg. KEY_ADD */ - pid_t key_pid; /* process id of message sender */ - int key_seq; /* message sequence number */ - int key_errno; /* error code */ - u_int8_t type; /* type of security association */ - u_int8_t vers; /* version of sassoc (AH/ESP) */ - u_int8_t state; /* state of security association */ - u_int8_t label; /* sensitivity level */ - u_int8_t pad; /* padding for allignment */ - u_int32_t spi; /* spi value */ - u_int8_t keylen; /* key length */ - u_int8_t ekeylen; /* extra key length */ - u_int8_t ivlen; /* iv length */ - u_int8_t algorithm; /* algorithm identifier */ - u_int8_t lifetype; /* type of lifetime */ - u_int32_t lifetime1; /* lifetime value 1 */ - u_int32_t lifetime2; /* lifetime value 2 */ - - int antireplay; /* anti replay flag */ -}; - -struct key_msgdata { - struct sockaddr *src; /* source host address */ - struct sockaddr *dst; /* destination host address */ - struct sockaddr *from; /* originator of security association */ - caddr_t iv; /* initialization vector */ - caddr_t key; /* key */ - caddr_t ekey; /* extra key */ - int ivlen; /* key length */ - int keylen; /* iv length */ - int ekeylen; /* extra key length */ -}; - -struct policy_msghdr { - u_short policy_msglen; /* message length */ - u_char policy_msgvers; /* message version */ - u_char policy_msgtype; /* message type */ - int policy_seq; /* message sequence number */ - int policy_errno; /* error code */ -}; - -/* - * Key engine table structures - */ - -struct socketlist { - struct socket *socket; /* pointer to socket */ - struct socketlist *next; /* next */ -}; - -struct key_tblnode { - int alloc_count; /* number of sockets allocated to - * secassoc */ - int ref_count; /* number of sockets referencing - * secassoc */ - struct socketlist *solist; /* list of sockets allocated to - * secassoc */ - struct key_secassoc *secassoc; /* security association */ - struct key_tblnode *next; /* next node */ -}; - -struct key_allocnode { - struct key_tblnode *keynode; - struct key_allocnode *next; -}; - -struct key_so2spinode { - struct socket *socket; /* socket pointer */ - struct key_tblnode *keynode; /* pointer to tblnode containing - * secassoc */ - /* info for socket */ - struct key_so2spinode *next; -}; - -struct key_registry { - u_int8_t type; /* secassoc type that key mgnt. daemon can - * acquire */ - struct socket *socket; /* key management daemon socket pointer */ - struct key_registry *next; -}; - -struct key_acquirelist { - u_int8_t type; /* secassoc type to acquire */ - struct sockaddr *target; /* destination address of secassoc */ - u_int32_t count; /* number of acquire messages sent */ - u_long expiretime; /* expiration time for acquire message */ - struct key_acquirelist *next; -}; - -struct keyso_cb { - int ip4_count; -#ifdef INET6 - int ip6_count; -#endif /*INET6*/ - int any_count; /* Sum of above counters */ -}; - -#ifdef KERNEL -extern int key_secassoc2msghdr __P((struct key_secassoc *, struct key_msghdr *, - struct key_msgdata *)); -extern int key_msghdr2secassoc __P((struct key_secassoc *, struct key_msghdr *, - struct key_msgdata *)); -extern int key_inittables __P((void)); -extern void key_sodelete __P((struct socket *, int)); -extern int key_add __P((struct key_secassoc *)); -extern int key_delete __P((struct key_secassoc *)); -extern int key_get __P((u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, struct key_secassoc **)); -extern void key_flush __P((void)); -extern int key_dump __P((struct socket *)); -extern int key_getspi __P((u_int, u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, u_int32_t, u_int32_t *)); -extern int key_update __P((struct key_secassoc *)); -extern int key_register __P((struct socket *, u_int)); -extern void key_unregister __P((struct socket *, u_int, int)); -extern int key_acquire __P((u_int, struct sockaddr *, struct sockaddr *)); -extern int getassocbyspi __P((u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, struct key_tblnode **)); -extern int getassocbysocket __P((u_int, struct sockaddr *, struct sockaddr *, - struct socket *, u_int, struct key_tblnode **)); -extern void key_free __P((struct key_tblnode *)); -extern int key_parse __P((struct key_msghdr ** km, struct socket * so, - int *)); -#endif /* KERNEL */ - -#endif /* _netkey_key_h */ +/* $Id: key.h,v 1.1.6.1.6.1 1999/05/17 17:03:14 itojun Exp $ */ + +#ifndef _NETKEY_KEY_H_ +#define _NETKEY_KEY_H_ + +#if defined(KERNEL) + +extern struct key_cb key_cb; + +struct secpolicy; +struct secpolicyindex; +struct ipsecrequest; +struct secasvar; +struct sockaddr; +struct socket; +struct sadb_msg; +struct sadb_x_policy; + +extern struct secpolicy *key_allocsp __P((struct secpolicyindex *spidx, + u_int dir)); +extern int key_checkrequest __P((struct ipsecrequest *isr)); +extern struct secasvar *key_allocsa __P((u_int family, caddr_t src, caddr_t dst, + u_int proto, u_int32_t spi)); +extern void key_freesp __P((struct secpolicy *sp)); +extern void key_freeso __P((struct socket *so)); +extern void key_freesav __P((struct secasvar *sav)); +extern struct secpolicy *key_newsp __P((void)); +extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *xpl0)); +extern struct sadb_x_policy *key_sp2msg __P((struct secpolicy *sp)); +extern int key_ismyaddr __P((u_int family, caddr_t addr)); +extern void key_timehandler __P((void)); +extern void key_srandom __P((void)); +extern void key_freereg __P((struct socket *so)); +extern int key_parse __P((struct sadb_msg **msgp, struct socket *so, + int *targetp)); +extern void key_init __P((void)); +extern int key_checktunnelsanity __P((struct secasvar *sav, u_int family, + caddr_t src, caddr_t dst)); +extern void key_sa_recordxfer __P((struct secasvar *sav, struct mbuf *m)); +extern void key_sa_routechange __P((struct sockaddr *dst)); + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_SECA); +#endif /* MALLOC_DECLARE */ + +#endif /* defined(KERNEL) */ +#endif /* _NETKEY_KEY_H_ */ diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c index b9b2c0f..ad91068 100644 --- a/sys/netkey/key_debug.c +++ b/sys/netkey/key_debug.c @@ -1,759 +1,689 @@ /* - * modified by Jun-ichiro itojun Itoh , 1997 - */ -/* - * in6_debug.c -- Insipired by Craig Metz's Net/2 in6_debug.c, but - * not quite as heavyweight (initially, anyway). + * 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. * - * The idea is to have globals here, and dump netinet6/ data structures. + * 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. * - * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson, - * All Rights Reserved. - * All Rights under this copyright have been assigned to NRL. + * $FreeBSD$ */ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. +/* KAME @(#)$Id: key_debug.c,v 1.1.6.2.4.3 1999/07/06 12:05:13 itojun Exp $ */ -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - - -#define INET6_DEBUG_C - -#include "opt_key.h" - -#ifdef KEY -#ifdef KEY_DEBUG /*wraps the whole code*/ +#ifdef _KERNEL +# ifndef KERNEL +# define KERNEL +# endif +#endif -/*#include */ +#ifdef KERNEL +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif +#include #include -#include -#include +#ifdef KERNEL #include +#include +#endif +#include -#include -#include #include -#include - -#include -#include +#include +#include -#ifdef INET6 +#include #include -#include -#include -#include -#include -#include -#else /* INET6 */ -#if 0 -#include "in6_types.h" +#include + +#if !defined(KERNEL) +#include +#include +#include +#endif /* defined(KERNEL) */ + +#if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); + +#ifdef KERNEL +static void kdebug_secreplay __P((struct secreplay *)); #endif -#endif /* INET6 */ - -#define SA_LEN 1 -#define SIN_LEN 1 -#ifdef KEY_DEBUG -#include -#include -#endif /* KEY_DEBUG */ -#ifdef IPSEC_DEBUG -#include -#endif /* IPSEC_DEBUG */ - -#if 0 -#include +#ifndef KERNEL +#define panic(param) { printf(param); exit(-1); } #endif -/* - * Globals - */ - -/* The following should be sysctl-tweakable. */ - -unsigned int in6_debug_level = IDL_FINISHED + 1; /* 0 is no debugging */ +/* NOTE: host byte order */ -/* - * Functions and macros. - */ - -void in6_debug_init() +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; { - /* For now, nothing. */ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u mode=%u reserved=%u seq=%u pid=%u }\n", + base->sadb_msg_len, base->sadb_msg_mode, + base->sadb_msg_reserved, base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } + + return; } -/*---------------------------------------------------------------------- - * dump_* dumps various data structures. These should be called within - * the context of a DDO() macro. They assume address and port fields - * are in network order. - ----------------------------------------------------------------------*/ - -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 address. Don't compress 0's out because of debugging. - ----------------------------------------------------------------------*/ -void dump_in6_addr(in6_addr) - struct in6_addr *in6_addr; +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; { - u_short *shorts = (u_short *)in6_addr; - int i = 0; - - if (!in6_addr) { - printf("Dereference a NULL in6_addr? I don't think so.\n"); - return; - } - - printf("(conv. for printing) "); - while (i < 7) - printf("%4x:",htons(shorts[i++])); - printf("%4x\n",htons(shorts[7])); + struct sadb_prop *prop = (struct sadb_prop *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (struct sadb_comb *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump and IPv4 address in x.x.x.x form. - ----------------------------------------------------------------------*/ -void dump_in_addr(in_addr) - struct in_addr *in_addr; +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; { - u_char *chars = (u_char *)in_addr; - int i = 0; - - if (!in_addr) { - printf("Dereference a NULL in_addr? I don't think so.\n"); - return; - } + struct sadb_ident *id = (struct sadb_ident *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + printf(" }\n"); - while (i < 3) - printf("%d.",chars[i++]); - printf("%d\n",chars[3]); + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 socket address. - ----------------------------------------------------------------------*/ -void dump_sockaddr_in6(sin6) - struct sockaddr_in6 *sin6; +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; { - if (!sin6) { - printf("Dereference a NULL sockaddr_in6? I don't think so.\n"); - return; - } - - printf("sin6_len = %d, sin6_family = %d, sin6_port = %d (0x%x)\n", - sin6->sin6_len,sin6->sin6_family, htons(sin6->sin6_port), - htons(sin6->sin6_port)); - printf("sin6_flowinfo = 0x%x\n",sin6->sin6_flowinfo); - printf("sin6_addr = "); - dump_in6_addr(&sin6->sin6_addr); + struct sadb_supported *sup = (struct sadb_supported *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (struct sadb_alg *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump an IPv4 socket address. - ----------------------------------------------------------------------*/ -void dump_sockaddr_in(sin) - struct sockaddr_in *sin; +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; { - int i; - - if (!sin) { - printf("Dereference a NULL sockaddr_in? I don't think so.\n"); - return; - } - -#ifdef SIN_LEN - printf("sin_len = %d, ", sin->sin_len); -#endif /* SIN_LEN */ - printf("sin_family = %d, sin_port (conv.) = %d (0x%x)\n", - sin->sin_family, htons(sin->sin_port), - htons(sin->sin_port)); - printf("sin_addr = "); - dump_in_addr(&sin->sin_addr); - printf("sin_zero == "); - for(i=0;i<8;i++) - printf("0x%2x ",sin->sin_zero[i]); - printf("\n"); -} + struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; -/*---------------------------------------------------------------------- - * Dump a generic socket address. Use if no family-specific routine is - * available. - ----------------------------------------------------------------------*/ -void dump_sockaddr(sa) - struct sockaddr *sa; -{ - if (!sa) { - printf("Dereference a NULL sockaddr? I don't think so.\n"); - return; - } - -#ifdef SA_LEN - printf("sa_len = %d, ", sa->sa_len); -#endif /* SA_LEN */ - printf("sa_family = %d", sa->sa_family); -#ifdef SA_LEN - printf(", remaining bytes are:\n"); - { - int i; - for (i = 0; i sa_len - 2; i++) - printf("0x%2x ",(unsigned char)sa->sa_data[i]); - } -#endif /* SA_LEN */ - printf("\n"); -} + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); -/*---------------------------------------------------------------------- - * Dump a link-layer socket address. (Not that there are user-level link - * layer sockets, but there are plenty of link-layer addresses in the kernel.) - ----------------------------------------------------------------------*/ -void dump_sockaddr_dl(sdl) - struct sockaddr_dl *sdl; -{ - char buf[256]; - - if (!sdl) { - printf("Dereference a NULL sockaddr_dl? I don't think so.\n"); - return; - } - - printf("sdl_len = %d, sdl_family = %d, sdl_index = %d, sdl_type = %d,\n", - sdl->sdl_len, sdl->sdl_family, sdl->sdl_index, sdl->sdl_type); - buf[sdl->sdl_nlen] = 0; - if (sdl->sdl_nlen) - bcopy(sdl->sdl_data,buf,sdl->sdl_nlen); - printf("sdl_nlen = %d, (name = '%s'\n",sdl->sdl_nlen,buf); - printf("sdl_alen = %d, ",sdl->sdl_alen); - if (sdl->sdl_alen) - { - int i; - - printf("(addr = "); - for (i = 0; isdl_alen; i++) - printf("0x%2x ",(unsigned char)sdl->sdl_data[i+sdl->sdl_nlen]); - } - printf("\n"); - printf("sdl_slen = %d, ",sdl->sdl_slen); - if (sdl->sdl_slen) - { - int i; - - printf("(addr = "); - for (i = 0; isdl_slen; i++) - printf("0x%2x ", - (unsigned char)sdl->sdl_data[i+sdl->sdl_nlen+sdl->sdl_alen]); - } - printf("\n"); -} + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); -/*---------------------------------------------------------------------- - * Dump a socket address, calling a family-specific routine if available. - ----------------------------------------------------------------------*/ -void dump_smart_sockaddr(sa) - struct sockaddr *sa; -{ - DPRINTF(IDL_MAJOR_EVENT, ("Entering dump_smart_sockaddr\n")); - if (!sa) { - printf("Dereference a NULL sockaddr? I don't think so.\n"); - return; - } - - switch (sa->sa_family) - { -#ifdef INET6 - case AF_INET6: - dump_sockaddr_in6((struct sockaddr_in6 *)sa); - break; -#endif /* INET6 */ - case AF_INET: - dump_sockaddr_in((struct sockaddr_in *)sa); - break; - case AF_LINK: - dump_sockaddr_dl((struct sockaddr_dl *)sa); - break; - default: - dump_sockaddr(sa); - break; - } + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 header. - ----------------------------------------------------------------------*/ -void dump_ipv6(ip6) - struct ip6 *ip6; +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; { - if (!ip6) { - printf("Dereference a NULL ip6? I don't think so.\n"); - return; - } - - printf("Vers = %d, pri = 0x%x, flow label = 0x%x\n", - ip6->ip6_v, ip6->ip6_pri, htonl(ip6->ip6_flbl)); - printf("Length (conv) = %d, nexthdr = %d, hoplimit = %d.\n", - htons(ip6->ip6_len),ip6->ip6_nh,ip6->ip6_hlim); - printf("Src: "); - dump_in6_addr(&ip6->ip6_src); - printf("Dst: "); - dump_in6_addr(&ip6->ip6_dst); -} + struct sadb_sa *sa = (struct sadb_sa *)ext; -/*---------------------------------------------------------------------- - * Dump an ICMPv6 header. This function is not very smart beyond the - * type, code, and checksum. - ----------------------------------------------------------------------*/ -void dump_ipv6_icmp(icp) - struct icmp6 *icp; -{ - int i; + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); - if (!icp) { - printf("Dereference a NULL ipv6_icmp? I don't think so.\n"); - return; - } + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); - printf("type %d, code %d, cksum (conv) = 0x%x\n",icp->icmp6_type, - icp->icmp6_code,htons(icp->icmp6_cksum)); - printf("First four bytes: 0x%x",htonl(icp->icmp6_flags)); - printf("\n"); + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump only the header fields of a single mbuf. - ----------------------------------------------------------------------*/ -void dump_mbuf_hdr(m) - struct mbuf *m; +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; { - if (!m) { - printf("Dereference a NULL mbuf? I don't think so.\n"); - return; - } - - printf("Single mbuf at %p\n", (void *)m); - printf("m_len = %d, m_data = %p, m_type = %d\n",m->m_len, - (void *)m->m_data, m->m_type); - printf("m_flags = 0x%x ",m->m_flags); - if (m->m_flags & M_PKTHDR) - printf("m_pkthdr.len = %d, m_pkthdr.rcvif = %p",m->m_pkthdr.len, - (void *)m->m_pkthdr.rcvif); - if (m->m_flags & M_EXT) - printf(" (IS CLUSTER MBUF)"); - printf("\nm_next = %p m_nextpkt = %p\n",(void *)m->m_next, - (void *)m->m_nextpkt); -} + struct sadb_address *addr = (struct sadb_address *)ext; -/*---------------------------------------------------------------------- - * Dump the entire contents of a single mbuf. - ----------------------------------------------------------------------*/ -void dump_mbuf(m) - struct mbuf *m; -{ - int i; + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); - dump_mbuf_hdr(m); - printf("m_data:\n"); - for (i = 0; i < m->m_len; i++) - printf("0x%2x%s",(unsigned char)m->m_data[i] , ((i+1) % 16)?" ":"\n"); - printf((i % 16)?"\n":""); -} + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)&addr->sadb_address_reserved)[0], + ((u_char *)&addr->sadb_address_reserved)[1]); -/*---------------------------------------------------------------------- - * Dump the contents of an mbuf chain. (WARNING: Lots of text may - * result. - ----------------------------------------------------------------------*/ -void dump_mchain(m) - struct mbuf *m; -{ - struct mbuf *walker; - int i; + kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); - for (walker = m, i = 0; walker != NULL && (i < 10); - walker = walker->m_next, i++) - dump_mbuf(walker); + return; } -/*---------------------------------------------------------------------- - * Dump an mbuf chain's data in a format similar to tcpdump(8). - ----------------------------------------------------------------------*/ -void dump_tcpdump(m) - struct mbuf *m; +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; { - int i, j, count; - - for (i = count = 0; m && (i < 10); m = m->m_next, i++) { - for (j = 0; j < m->m_len; j++, count++) { - if (!(count % (2 * 8))) - printf("\n\t\t\t"); - if (!(count % 2)) - printf(" "); - printf("%02x", (u_int8_t)(m->m_data[j])); - } - } + struct sadb_key *key = (struct sadb_key *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if ((key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), + key->sadb_key_bits >> 3); + printf(" }\n"); + return; } -#if 0 -/*---------------------------------------------------------------------- - * Dump an IPv6 header index table, which is terminated by an entry with - * a NULL mbuf pointer. - ----------------------------------------------------------------------*/ -void dump_ihitab(ihi) - struct in6_hdrindex *ihi; +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; { - int i=0; - - if (!ihi) { - printf("Dereference a NULL hdrindex/ihi? I don't think so.\n"); - return; - } - - /* This is dangerous, make sure ihitab was bzeroed. */ - while (ihi[i].ihi_mbuf) - { - printf("ihi_nexthdr = %d, ihi_mbuf = 0x%x.\n",ihi[i].ihi_nexthdr, - ihi[i].ihi_mbuf); - i++; - } + struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + + printf("sadb_x_policy{ type=%u dir=%u reserved=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_reserved); + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level); + + addr = (struct sockaddr *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len); + kdebug_sockaddr(addr); + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump an interface address. - ----------------------------------------------------------------------*/ -void dump_ifa(ifa) - struct ifaddr *ifa; +#ifdef KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; { - if (ifa == NULL) - { - printf("ifa of NULL.\n"); - return; - } - - printf("ifa_addr: "); - dump_smart_sockaddr(ifa->ifa_addr); - printf("ifa_netmask: "); - dump_smart_sockaddr(ifa->ifa_netmask); + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; } -/*---------------------------------------------------------------------- - * Dump an interface structure. - ----------------------------------------------------------------------*/ -void dump_ifp(ifp) - struct ifnet *ifp; +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; { - if (!ifp) { - printf("Dereference a NULL ifnet/ifp? I don't think so.\n"); - return; - } - - printf("Interface name: %s.\n",ifp->if_name); - printf("Interface type: %d. ",ifp->if_type); - printf("MTU: %lu.\n",ifp->if_mtu); + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, spidx->src.__ss_len); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, spidx->dst.__ss_len); + printf("}\n"); + + return; } -/*---------------------------------------------------------------------- - * Dump a route structure (sockaddr/rtentry pair). - ----------------------------------------------------------------------*/ -void dump_route(ro) - struct route *ro; +void +kdebug_secasindex(saidx) + struct secasindex *saidx; { - if (!ro) { - printf("Dereference a NULL route? I don't think so.\n"); - return; - } + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, saidx->src.__ss_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, saidx->dst.__ss_len); + printf("\n"); - printf("ro_rt = %p, ro_dst is:\n",(void *)ro->ro_rt); - dump_smart_sockaddr(&ro->ro_dst); + return; } -/*---------------------------------------------------------------------- - * Dump a routing entry. - ----------------------------------------------------------------------*/ -void dump_rtentry(rt) - struct rtentry *rt; +void +kdebug_secasv(sav) + struct secasvar *sav; { - if (!rt) { - printf("Dereference a NULL rtentry? I don't think so.\n"); - return; - } - - printf("rt_key is:\n"); - dump_smart_sockaddr(rt_key(rt)); - printf("rt_mask is:\n"); - dump_smart_sockaddr(rt_mask(rt)); - printf("rt_llinfo = %p ",(void *)rt->rt_llinfo); - printf("rt_rmx.rmx_mtu = %lu ",rt->rt_rmx.rmx_mtu); - printf("rt_refcnt = %ld ",rt->rt_refcnt); - printf("rt_flags = 0x%lx\n",rt->rt_flags); - printf("rt_ifp is:\n"); - dump_ifp(rt->rt_ifp); - printf("rt_ifa is:\n"); - dump_ifa(rt->rt_ifa); + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + + return; } -/*---------------------------------------------------------------------- - * Dump an Internet v4 protocol control block. - ----------------------------------------------------------------------*/ -void dump_inpcb(inp) - struct inpcb *inp; +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; { - if (!inp) { - printf("Dereference a NULL inpcb? I don't think so.\n"); - return; - } - -#if 0 - printf("inp_next = 0x%x, inp_prev = 0x%x, inp_head = 0x%x.\n", - inp->inp_next, inp->inp_prev, inp->inp_head); -#endif - printf("inp_socket = %p, inp_ppcb = %p\n", - (void *)inp->inp_socket,(void *)inp->inp_ppcb); - printf("faddr:\n"); - dump_in_addr(&inp->inp_faddr); - printf("laddr:\n"); - dump_in_addr(&inp->inp_laddr); - printf("inp_route: "); - dump_route(&inp->inp_route); - printf("inp_ip:"); - printf("\n"); - printf("inp_options = %p, inp_moptions{6,} = %p,\n", - (void *)inp->inp_options, (void *)inp->inp_moptions); - printf("inp_flags = 0x%x, inp_fport = %d, inp_lport = %d.\n", - (unsigned)inp->inp_flags,inp->inp_fport, inp->inp_lport); + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an Internet v6 protocol control block. - ----------------------------------------------------------------------*/ -void dump_in6pcb(in6p) - struct in6pcb *in6p; +void +kdebug_mbufhdr(m) + struct mbuf *m; { - if (!in6p) { - printf("Dereference a NULL in6pcb? I don't think so.\n"); - return; - } - - printf("in6p_next = 0x%x, in6p_prev = 0x%x, in6p_head = 0x%x.\n", - in6p->in6p_next, in6p->in6p_prev, in6p->in6p_head); - printf("in6p_socket = 0x%x, in6p_ppcb\n", - in6p->in6p_socket, in6p->in6p_ppcb); - printf("faddr:\n"); - dump_in6_addr(&in6p->in6p_faddr); - printf("laddr:\n"); - dump_in6_addr(&in6p->in6p_laddr); - printf("in6p_route: "); - dump_route(&in6p->in6p_route); - printf("in6p_ip6:"); - dump_ipv6(&in6p->in6p_ip6); - printf("in6p_options = 0x%x, in6p_moptions{6,} = 0x%x,\n", - in6p->in6p_options, in6p->in6p_moptions); - printf("in6p_flags = 0x%x, in6p_fport = %d, in6p_lport = %d.\n", - (unsigned)in6p->in6p_flags, in6p->in6p_fport, in6p->in6p_lport); + /* sanity check */ + if (m == NULL) + panic("debug_mbufhdr: NULL pointer was passed.\n"); + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } + return; } -#endif /*INET6*/ - -#if 0 -/*---------------------------------------------------------------------- - * Dump an IPv6 discovery queue structure. - ----------------------------------------------------------------------*/ -void dump_discq(dq) - struct discq *dq; + +void +kdebug_mbuf(m0) + struct mbuf *m0; { - if (!dq) { - printf("Dereference a NULL discq? I don't think so.\n"); - return; - } - - printf("dq_next = 0x%x, dq_prev = 0x%x, dq_rt = 0x%x,\n",dq->dq_next, - dq->dq_prev, dq->dq_rt); - printf("dq_queue = 0x%x.\n",dq->dq_queue); - /* Dump first mbuf chain? */ - /*printf("dq_expire = %d (0x%x).\n",dq->dq_expire,dq->dq_expire);*/ + struct mbuf *m = m0; + int i, j; + + kdebug_mbufhdr(m); + printf(" m_data=\n"); + for (j = 0; m; m = m->m_next) { + for (i = 0; i < m->m_len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + } + + printf("\n"); + + return; } -#endif /* INET6 */ - -/*---------------------------------------------------------------------- - * Dump a data buffer - ----------------------------------------------------------------------*/ -void dump_buf(buf, len) - char *buf; - int len; +#endif /* KERNEL */ + +void +kdebug_sockaddr(addr) + struct sockaddr *addr; { - int i; + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); - printf("buf=0x%x len=%d:\n", (unsigned int)buf, len); - for (i = 0; i < len; i++) { - printf("0x%x ", (u_int8_t)*(buf+i)); - } - printf("\n"); -} + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u port=%u\n", + addr->sa_len, addr->sa_family, ntohs(_INPORTBYSA(addr))); +#ifdef INET6 + if (addr->sa_family == PF_INET6) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + in6->sin6_flowinfo, in6->sin6_scope_id); + } +#endif -/*---------------------------------------------------------------------- - * Dump a key_tblnode structrue - ----------------------------------------------------------------------*/ -void dump_keytblnode(ktblnode) - struct key_tblnode *ktblnode; -{ - if (!ktblnode) { - printf("NULL key table node pointer!\n"); - return; - } - printf("solist=0x%x ", (unsigned int)ktblnode->solist); - printf("secassoc=0x%x ", (unsigned int)ktblnode->secassoc); - printf("next=0x%x\n", (unsigned int)ktblnode->next); -} + ipsec_hexdump(_INADDRBYSA(addr), _INALENBYAF(addr->sa_family)); -/*---------------------------------------------------------------------- - * Dump an ipsec_assoc structure - ----------------------------------------------------------------------*/ -void dump_secassoc(seca) - struct key_secassoc *seca; -{ - u_int8_t *p; - int i; - - if (seca) { - printf("secassoc_len=%u ", seca->len); - printf("secassoc_type=%d ", seca->type); - printf("secassoc_state=0x%x\n", seca->state); - printf("secassoc_label=%u ", seca->label); - printf("secassoc_spi=0x%x ", (unsigned int)seca->spi); - printf("secassoc_keylen=%u\n", seca->keylen); - printf("secassoc_ivlen=%u ", seca->ivlen); - printf("secassoc_algorithm=%u ", seca->algorithm); - printf("secassoc_lifetype=%u\n", seca->lifetype); - printf("secassoc_iv=0x%x:\n", (unsigned int)seca->iv); - p = (u_int8_t *)(seca->iv); - for (i = 0 ; i < seca->ivlen; i++) - printf("0x%x ", *(p + i)); - printf("secassoc_key=0x%x:\n", (unsigned int)seca->key); - p = (u_int8_t *)(seca->key); - for (i = 0 ; i < seca->keylen; i++) - printf("0x%x ", *(p + i)); - printf("secassoc_lifetime1=%u ", (unsigned int)seca->lifetime1); - printf("secassoc_lifetime2=%u\n", (unsigned int)seca->lifetime2); - dump_smart_sockaddr(seca->src); - dump_smart_sockaddr(seca->dst); - dump_smart_sockaddr(seca->from); - } else - printf("can't dump null secassoc pointer!\n"); + printf(" }\n"); + + return; } +#endif /* !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) */ -/*---------------------------------------------------------------------- - * Dump a key_msghdr structure - ----------------------------------------------------------------------*/ -void dump_keymsghdr(km) - struct key_msghdr *km; +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; { - if (km) { - printf("key_msglen=%d\n", km->key_msglen); - printf("key_msgvers=%d\n", km->key_msgvers); - printf("key_msgtype=%d\n", km->key_msgtype); - printf("key_pid=%d\n", km->key_pid); - printf("key_seq=%d\n", km->key_seq); - printf("key_errno=%d\n", km->key_errno); - printf("type=0x%x\n", (unsigned int)km->type); - printf("state=0x%x\n", (unsigned int)km->state); - printf("label=0x%x\n", (unsigned int)km->label); - printf("spi=0x%x\n", (unsigned int)km->spi); - printf("keylen=%d\n", km->keylen); - printf("ivlen=%d\n", km->ivlen); - printf("algorithm=%d\n", km->algorithm); - printf("lifetype=0x%x\n", (unsigned int)km->lifetype); - printf("lifetime1=%u\n", (unsigned int)km->lifetime1); - printf("lifetime2=%u\n", (unsigned int)km->lifetime2); - } else - printf("key_msghdr pointer is NULL!\n"); + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; } -/*---------------------------------------------------------------------- - * Dump a key_msgdata structure - ----------------------------------------------------------------------*/ -void dump_keymsginfo(kp) - struct key_msgdata *kp; +void +ipsec_hexdump(buf, len) + caddr_t buf; + int len; { - int i; - - if (kp) { - printf("src addr:\n"); - dump_smart_sockaddr(kp->src); - printf("dest addr:\n"); - dump_smart_sockaddr(kp->dst); - printf("from addr:\n"); - dump_smart_sockaddr(kp->from); -#define dumpbuf(a, b) \ - { for (i= 0; i < (b); i++) \ - printf("0x%2x%s", (unsigned char)(*((caddr_t)a+i)),((i+1)%16)?" ":"\n");\ - printf("\n"); } - printf("iv is:\n"); - dumpbuf(kp->iv, kp->ivlen); - printf("key is:\n"); - dumpbuf(kp->key, kp->keylen); -#undef dumpbuf - } else - printf("key_msgdata point is NULL!\n"); + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + + return; } -#endif /*KEY_DEBUG*/ -#endif /*KEY*/ diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h index 78bae82..2ce0dc0 100644 --- a/sys/netkey/key_debug.h +++ b/sys/netkey/key_debug.h @@ -1,187 +1,89 @@ /* - * modified by Jun-ichiro itojun Itoh , 1997 - */ -/* - * in6_debug.h -- Insipired by Craig Metz's Net/2 in6_debug.h, but - * not quite as heavyweight (initially, anyway). + * 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. * - * In particular, if function exit-entries are to be - * documented, do them in a lightweight fashion. + * 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. * - * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson, - * All Rights Reserved. - * All Rights under this copyright have been assigned to NRL. + * $FreeBSD$ */ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. +/* $Id: key_debug.h,v 1.1.6.2.6.1 1999/05/17 17:03:16 itojun Exp $ */ -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. +#ifndef _NETKEY_KEY_DEBUG_H_ +#define _NETKEY_KEY_DEBUG_H_ -NRL LICENSE +/* debug flags */ +#define KEYDEBUG_STAMP 0x00000001 /* path */ +#define KEYDEBUG_DATA 0x00000002 /* data */ +#define KEYDEBUG_DUMP 0x00000004 /* dump */ -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL provided that the following conditions are met: +#define KEYDEBUG_KEY 0x00000010 /* key processing */ +#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */ +#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */ -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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: +#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP) +#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA) +#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP) +#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP) +#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA) +#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP) +#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP) +#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA) +#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP) - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ +#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } #ifdef KERNEL +extern u_int32_t key_debug_level; +#endif /*KERNEL*/ -/* IDL_* is IPv6 Debug Level */ - -#define IDL_ALL 0xFFFFFFFE /* Report all messages. */ -#define IDL_NONE 0 /* Report no messages. */ - -#define IDL_CRITICAL 3 -#define IDL_ERROR 7 -#define IDL_MAJOR_EVENT 10 -#define IDL_EVENT 15 -#define IDL_GROSS_EVENT 20 -#define IDL_FINISHED 0xFFFFFFF0 - -/* - * Make sure argument for DPRINTF is in parentheses. - * - * For both DPRINTF and DDO, and attempt was made to make both macros - * be usable as normal C statments. There is a small amount of compiler - * trickery (if-else clauses with effectively null statements), which may - * cause a few compilers to complain. - */ - -#ifdef KEY_DEBUG - -/* - * DPRINTF() is a general printf statement. The "arg" is literally what - * would follow the function name printf, which means it has to be in - * parenthesis. Unlimited arguments can be used this way. - * - * EXAMPLE: - * DPRINTF(IDL_MAJOR_EVENT,("Hello, world. IP version %d.\n",vers)); - */ -#define DPRINTF(lev,arg) \ - if ((lev) < in6_debug_level) { \ - printf arg; \ - } else \ - in6_debug_level = in6_debug_level - -/* - * DDO() executes a series of statements at a certain debug level. The - * "stmt" argument is a statement in the sense of a "statement list" in a - * C grammar. "stmt" does not have to end with a semicolon. - * - * EXAMPLE: - * DDO(IDL_CRITICAL,dump_ipv6(header), dump_inpcb(inp)); - */ -#define DDO(lev,stmt) \ - if ((lev) < in6_debug_level) { \ - stmt ; \ - } else \ - in6_debug_level = in6_debug_level - -/* - * DP() is a shortcut for DPRINTF(). Basically: - * - * DP(lev, var, fmt) == DPRINTF(IDL_lev, ("var = %fmt\n", var)) - * - * It is handy for printing single variables without a lot of typing. - * - * EXAMPLE: - * - * DP(CRITICAL,length,d); - * same as DPRINTF(IDL_CRITICAL, ("length = %d\n", length)) - */ -#define DP(lev, var, fmt) DPRINTF(IDL_ ## lev, (#var " = %" #fmt "\n", var)) - -struct inpcb; - -extern void in6_debug_init __P((void)); -#ifdef INET6 -extern void dump_in6_addr __P((struct in6_addr *)); -#endif -extern void dump_in_addr __P((struct in_addr *)); -#ifdef INET6 -extern void dump_sockaddr_in6 __P((struct sockaddr_in6 *)); -#endif -extern void dump_sockaddr_in __P((struct sockaddr_in *)); -extern void dump_sockaddr __P((struct sockaddr *)); -extern void dump_sockaddr_dl __P((struct sockaddr_dl *)); -extern void dump_smart_sockaddr __P((struct sockaddr *)); -#ifdef INET6 -extern void dump_ipv6 __P((struct ip6 *)); -extern void dump_ipv6_icmp __P((struct icmp6 *)); -#endif /*INET6*/ -extern void dump_mbuf_hdr __P((struct mbuf *)); -extern void dump_mbuf __P((struct mbuf *)); -extern void dump_mchain __P((struct mbuf *)); -extern void dump_tcpdump __P((struct mbuf *)); -extern void dump_ifa __P((struct ifaddr *)); -extern void dump_ifp __P((struct ifnet *)); -extern void dump_route __P((struct route *)); -extern void dump_rtentry __P((struct rtentry *)); -extern void dump_inpcb __P((struct inpcb *)); -#ifdef INET6 -extern void dump_in6pcb __P((struct in6pcb *)); -#endif -extern void dump_buf __P((char *, int)); -extern void dump_keytblnode __P((struct key_tblnode *)); -extern void dump_secassoc __P((struct key_secassoc *)); -extern void dump_keymsghdr __P((struct key_msghdr *)); -extern void dump_keymsginfo __P((struct key_msgdata *)); +struct sadb_msg; +struct sadb_ext; +extern void kdebug_sadb __P((struct sadb_msg *)); +extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); -#else /* ! KEY_DEBUG */ +#ifdef KERNEL +struct secpolicy; +struct secpolicyindex; +struct secasindex; +struct secasvar; +struct secreplay; +struct mbuf; +extern void kdebug_secpolicy __P((struct secpolicy *)); +extern void kdebug_secpolicyindex __P((struct secpolicyindex *)); +extern void kdebug_secasindex __P((struct secasindex *)); +extern void kdebug_secasv __P((struct secasvar *)); +extern void kdebug_mbufhdr __P((struct mbuf *)); +extern void kdebug_mbuf __P((struct mbuf *)); +#endif /*KERNEL*/ -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) +struct sockaddr; +extern void kdebug_sockaddr __P((struct sockaddr *)); -#endif /* KEY_DEBUG */ +extern void ipsec_hexdump __P((caddr_t, int)); +extern void ipsec_bindump __P((caddr_t, int)); -#ifndef INET6_DEBUG_C -extern unsigned int in6_debug_level; -#endif +#endif /* _NETKEY_KEY_DEBUG_H_ */ -#endif /*KERNEL*/ diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h index 41750b7..85e4b92 100644 --- a/sys/netkey/key_var.h +++ b/sys/netkey/key_var.h @@ -43,40 +43,12 @@ #define KEYCTL_BLOCKACQ_LIFETIME 8 #define KEYCTL_MAXID 9 -#define KEYCTL_NAMES { \ - { 0, 0 }, \ - { "debug", CTLTYPE_INT }, \ - { "spi_try", CTLTYPE_INT }, \ - { "spi_min_value", CTLTYPE_INT }, \ - { "spi_max_value", CTLTYPE_INT }, \ - { "random_int", CTLTYPE_INT }, \ - { "larval_lifetime", CTLTYPE_INT }, \ - { "blockacq_count", CTLTYPE_INT }, \ - { "blockacq_lifetime", CTLTYPE_INT }, \ -} - -#define KEYCTL_VARS { \ - 0, \ - &key_debug_level, \ - &key_spi_trycnt, \ - &key_spi_minval, \ - &key_spi_maxval, \ - &key_int_random, \ - &key_larval_lifetime, \ - &key_blockacq_count, \ - &key_blockacq_lifetime, \ -} - #define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0])) #define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3)) #define _KEYBITS(key) ((u_int)((key)->sadb_key_bits)) #define _KEYBUF(key) ((caddr_t)((caddr_t)(key) + sizeof(struct sadb_key))) #define _INADDR(in) ((struct sockaddr_in *)(in)) - -/* should not ifdef kernel opt in kernel header file */ -#if !defined(KERNEL) && !defined(_KERNEL) -#if defined(INET6) #define _IN6ADDR(in6) ((struct sockaddr_in6 *)(in6)) #define _SALENBYAF(family) \ (((family) == AF_INET) ? \ @@ -94,13 +66,9 @@ ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \ ((struct sockaddr_in *)(saddr))->sin_port : \ ((struct sockaddr_in6 *)(saddr))->sin6_port) -#else -#define _IN6ADDR(in6) "#error" -#define _SALENBYAF(family) sizeof(struct sockaddr_in) -#define _INALENBYAF(family) sizeof(struct in_addr) -#define _INADDRBYSA(saddr) ((caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr) -#define _INPORTBYSA(saddr) (((struct sockaddr_in *)(saddr))->sin_port) -#endif /* defined(INET6) */ -#endif /* !defined(KERNEL) && !defined(_KERNEL) */ + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_key); +#endif #endif /* _NETKEY_KEY_VAR_H_ */ diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c new file mode 100644 index 0000000..b3c8652 --- /dev/null +++ b/sys/netkey/keysock.c @@ -0,0 +1,542 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* KAME @(#)$Id: keysock.c,v 1.2 1999/08/16 19:30:36 shin Exp $ */ + +/* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#ifdef IPSEC_DEBUG +#include +#else +#define KEYDEBUG(lev,arg) +#endif + +#include + +static MALLOC_DEFINE(M_SECA, "key mgmt", + "security associations, key management"); + +struct sockaddr key_dst = { 2, PF_KEY, }; +struct sockaddr key_src = { 2, PF_KEY, }; +struct sockproto key_proto = { PF_KEY, PF_KEY_V2 }; + +static int key_sendup0 __P((struct rawcb *, struct mbuf *, int)); + +#define KMALLOC(p, t, n) \ + ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) +#define KFREE(p) \ + free((caddr_t)(p), M_SECA); + +/* + * key_abort() + * derived from net/rtsock.c:rts_abort() + */ +static int +key_abort(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_abort(so); + splx(s); + return error; +} + +/* + * key_attach() + * derived from net/rtsock.c:rts_attach() + */ +static int +key_attach(struct socket *so, int proto, struct proc *p) +{ + struct keycb *kp; + int s, error; + + if (sotorawcb(so) != 0) + return EISCONN; /* XXX panic? */ + MALLOC(kp, struct keycb *, sizeof *kp, M_PCB, M_WAITOK); /* XXX */ + if (kp == 0) + return ENOBUFS; + bzero(kp, sizeof *kp); + + /* + * The splnet() is necessary to block protocols from sending + * error notifications (like RTM_REDIRECT or RTM_LOSING) while + * this PCB is extant but incompletely initialized. + * Probably we should try to do more of this work beforehand and + * eliminate the spl. + */ + s = splnet(); + so->so_pcb = (caddr_t)kp; + error = raw_usrreqs.pru_attach(so, proto, p); + kp = (struct keycb *)sotorawcb(so); + if (error) { + free(kp, M_PCB); + so->so_pcb = (caddr_t) 0; + splx(s); + printf("key_usrreq: key_usrreq results %d\n", error); + return error; + } + + kp->kp_promisc = kp->kp_registered = 0; + + if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ + key_cb.key_count++; + key_cb.any_count++; + kp->kp_raw.rcb_laddr = &key_src; + kp->kp_raw.rcb_faddr = &key_dst; + soisconnected(so); + so->so_options |= SO_USELOOPBACK; + + splx(s); + return 0; +} + +/* + * key_bind() + * derived from net/rtsock.c:rts_bind() + */ +static int +key_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_bind(so, nam, p); /* xxx just EINVAL */ + splx(s); + return error; +} + +/* + * key_connect() + * derived from net/rtsock.c:rts_connect() + */ +static int +key_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_connect(so, nam, p); /* XXX just EINVAL */ + splx(s); + return error; +} + +/* + * key_detach() + * derived from net/rtsock.c:rts_detach() + */ +static int +key_detach(struct socket *so) +{ + struct keycb *kp = (struct keycb *)sotorawcb(so); + int s, error; + + s = splnet(); + if (kp != 0) { + if (kp->kp_raw.rcb_proto.sp_protocol + == PF_KEY) /* XXX: AF_KEY */ + key_cb.key_count--; + key_cb.any_count--; + + key_freereg(so); + } + error = raw_usrreqs.pru_detach(so); + splx(s); + return error; +} + +/* + * key_disconnect() + * derived from net/rtsock.c:key_disconnect() + */ +static int +key_disconnect(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_disconnect(so); + splx(s); + return error; +} + +/* + * key_peeraddr() + * derived from net/rtsock.c:rts_peeraddr() + */ +static int +key_peeraddr(struct socket *so, struct sockaddr **nam) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_peeraddr(so, nam); + splx(s); + return error; +} + +/* + * key_send() + * derived from net/rtsock.c:rts_send() + */ +static int +key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, + struct mbuf *control, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_send(so, flags, m, nam, control, p); + splx(s); + return error; +} + +/* + * key_shutdown() + * derived from net/rtsock.c:rts_shutdown() + */ +static int +key_shutdown(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_shutdown(so); + splx(s); + return error; +} + +/* + * key_sockaddr() + * derived from net/rtsock.c:rts_sockaddr() + */ +static int +key_sockaddr(struct socket *so, struct sockaddr **nam) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_sockaddr(so, nam); + splx(s); + return error; +} + +struct pr_usrreqs key_usrreqs = { + key_abort, pru_accept_notsupp, key_attach, key_bind, + key_connect, + pru_connect2_notsupp, pru_control_notsupp, key_detach, + key_disconnect, pru_listen_notsupp, key_peeraddr, + pru_rcvd_notsupp, + pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown, + key_sockaddr, sosend, soreceive, sopoll +}; + +/* + * key_output() + */ +int +key_output(struct mbuf *m, struct socket *so) +{ + struct sadb_msg *msg = NULL; + int len, error = 0; + int s; + int target; + + if (m == 0) + panic("key_output: NULL pointer was passed.\n"); + + if (m->m_len < sizeof(long) + && (m = m_pullup(m, 8)) == 0) { + printf("key_output: can't pullup mbuf\n"); + error = ENOBUFS; + goto end; + } + + if ((m->m_flags & M_PKTHDR) == 0) + panic("key_output: not M_PKTHDR ??"); + +#if defined(IPSEC_DEBUG) + KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m)); +#endif /* defined(IPSEC_DEBUG) */ + + len = m->m_pkthdr.len; + if (len < sizeof(struct sadb_msg) + || len != PFKEY_UNUNIT64(mtod(m, struct sadb_msg *)->sadb_msg_len)) { + printf("key_output: Invalid message length.\n"); + error = EINVAL; + goto end; + } + + /* + * allocate memory for sadb_msg, and copy to sadb_msg from mbuf + * XXX: To be processed directly without a copy. + */ + KMALLOC(msg, struct sadb_msg *, len); + if (msg == 0) { + printf("key_output: No more memory.\n"); + error = ENOBUFS; + goto end; + /* or do panic ? */ + } + m_copydata(m, 0, len, (caddr_t)msg); + + /*XXX giant lock*/ + s = splnet(); + if ((len = key_parse(&msg, so, &target)) == 0) { + /* discard. i.e. no need to reply. */ + error = 0; + splx(s); + goto end; + } + + /* send up message to the socket */ + error = key_sendup(so, msg, len, target); + splx(s); + KFREE(msg); +end: + m_freem(m); + return (error); +} + +/* + * send message to the socket. + */ +static int +key_sendup0(rp, m, promisc) + struct rawcb *rp; + struct mbuf *m; + int promisc; +{ + if (promisc) { + struct sadb_msg *pmsg; + + M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT); + if (m && m->m_len < sizeof(struct sadb_msg)) + m = m_pullup(m, sizeof(struct sadb_msg)); + if (!m) { + printf("key_sendup0: cannot pullup\n"); + m_freem(m); + return ENOBUFS; + } + m->m_pkthdr.len += sizeof(*pmsg); + + pmsg = mtod(m, struct sadb_msg *); + bzero(pmsg, sizeof(*pmsg)); + pmsg->sadb_msg_version = PF_KEY_V2; + pmsg->sadb_msg_type = SADB_X_PROMISC; + pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); + /* pid and seq? */ + } + + if (!sbappendaddr(&rp->rcb_socket->so_rcv, + (struct sockaddr *)&key_src, m, NULL)) { + printf("key_sendup0: sbappendaddr failed\n"); + m_freem(m); + return ENOBUFS; + } + sorwakeup(rp->rcb_socket); + return 0; +} + +int +key_sendup(so, msg, len, target) + struct socket *so; + struct sadb_msg *msg; + u_int len; + int target; /*target of the resulting message*/ +{ + struct mbuf *m, *n, *mprev; + struct keycb *kp; + int sendup; + struct rawcb *rp; + int error; + int tlen; + + /* sanity check */ + if (so == 0 || msg == 0) + panic("key_sendup: NULL pointer was passed.\n"); + + KEYDEBUG(KEYDEBUG_KEY_DUMP, + printf("key_sendup: \n"); + kdebug_sadb(msg)); + + /* + * Get mbuf chain whenever possible (not clusters), + * to save socket buffer. We'll be generating many SADB_ACQUIRE + * messages to listening key sockets. If we simmply allocate clusters, + * sbappendaddr() will raise ENOBUFS due to too little sbspace(). + * sbspace() computes # of actual data bytes AND mbuf region. + * + * TODO: SADB_ACQUIRE filters should be implemented. + */ + tlen = len; + m = mprev = NULL; + while (tlen > 0) { + if (tlen == len) { + MGETHDR(n, M_DONTWAIT, MT_DATA); + n->m_len = MHLEN; + } else { + MGET(n, M_DONTWAIT, MT_DATA); + n->m_len = MLEN; + } + if (!n) + return ENOBUFS; + if (tlen > MCLBYTES) { /*XXX better threshold? */ + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + m_freem(m); + return ENOBUFS; + } + n->m_len = MCLBYTES; + } + + if (tlen < n->m_len) + n->m_len = tlen; + n->m_next = NULL; + if (m == NULL) + m = mprev = n; + else { + mprev->m_next = n; + mprev = n; + } + tlen -= n->m_len; + n = NULL; + } + m->m_pkthdr.len = len; + m->m_pkthdr.rcvif = NULL; + m_copyback(m, 0, len, (caddr_t)msg); + + LIST_FOREACH(rp, &rawcb_list, list) + { + if (rp->rcb_proto.sp_family != PF_KEY) + continue; + if (rp->rcb_proto.sp_protocol + && rp->rcb_proto.sp_protocol != PF_KEY_V2) { + continue; + } + + kp = (struct keycb *)rp; + + /* + * If you are in promiscuous mode, and when you get broadcasted + * reply, you'll get two PF_KEY messages. + * (based on pf_key@inner.net message on 14 Oct 1998) + */ + if (((struct keycb *)rp)->kp_promisc) { + if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { + (void)key_sendup0(rp, n, 1); + n = NULL; + } + } + + /* the exact target will be processed later */ + if (sotorawcb(so) == rp) + continue; + + sendup = 0; + switch (target) { + case KEY_SENDUP_ONE: + /* the statement has no effect */ + if (sotorawcb(so) == rp) + sendup++; + break; + case KEY_SENDUP_ALL: + sendup++; + break; + case KEY_SENDUP_REGISTERED: + if (kp->kp_registered) + sendup++; + break; + } + + if (!sendup) + continue; + + if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { + printf("key_sendup: m_copy fail\n"); + m_freem(m); + return ENOBUFS; + } + + if ((error = key_sendup0(rp, n, 0)) != 0) { + m_freem(m); + return error; + } + + n = NULL; + } + + error = key_sendup0(sotorawcb(so), m, 0); + m = NULL; + return error; +} + +/* sysctl */ +SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family"); + +/* + * Definitions of protocols supported in the KEY domain. + */ + +extern struct domain keydomain; + +struct protosw keysw[] = { +{ SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR, + 0, key_output, raw_ctlinput, 0, + 0, + raw_init, 0, 0, 0, + &key_usrreqs +} +}; + +struct domain keydomain = + { PF_KEY, "key", key_init, 0, 0, + keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; + +DOMAIN_SET(key); diff --git a/sys/netkey/keysock.h b/sys/netkey/keysock.h index d71e5aa..2fb475f 100644 --- a/sys/netkey/keysock.h +++ b/sys/netkey/keysock.h @@ -41,7 +41,7 @@ struct keycb { int kp_registered; /* registered socket */ }; -extern int key_output __P((struct mbuf *, ...)); +extern int key_output __P((struct mbuf *, struct socket *)); extern int key_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); -- cgit v1.1