]> git.saurik.com Git - apple/ipsec.git/commitdiff
ipsec-34.tar.gz mac-os-x-105 mac-os-x-1051 mac-os-x-1052 mac-os-x-1053 v34
authorApple <opensource@apple.com>
Fri, 5 Oct 2007 21:23:48 +0000 (21:23 +0000)
committerApple <opensource@apple.com>
Fri, 5 Oct 2007 21:23:48 +0000 (21:23 +0000)
166 files changed:
ipsec-tools/Common/config.h [new file with mode: 0644]
ipsec-tools/Common/key_debug.c [new file with mode: 0644]
ipsec-tools/Common/libpfkey.h [new file with mode: 0644]
ipsec-tools/Common/pfkey.c [new file with mode: 0644]
ipsec-tools/Common/pfkey_dump.c [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_dump_policy.3 [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_dump_policy.c [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_get_policylen.3 [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_get_policylen.c [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_set_policy.3 [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_strerror.3 [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_strerror.c [new file with mode: 0644]
ipsec-tools/libipsec/ipsec_strerror.h [new file with mode: 0644]
ipsec-tools/libipsec/policy_parse.y [new file with mode: 0644]
ipsec-tools/libipsec/policy_token.l [new file with mode: 0644]
ipsec-tools/libipsec/test-policy.c [new file with mode: 0644]
ipsec-tools/racoon/Crypto/boxes-fst.dat [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael-alg-fst.c [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael-alg-fst.h [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael-api-fst.c [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael-api-fst.h [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael.h [new file with mode: 0644]
ipsec-tools/racoon/Crypto/rijndael_local.h [new file with mode: 0644]
ipsec-tools/racoon/Documents/FAQ [new file with mode: 0644]
ipsec-tools/racoon/Documents/README.certificate [new file with mode: 0644]
ipsec-tools/racoon/Documents/README.gssapi [new file with mode: 0644]
ipsec-tools/racoon/Documents/TODO [new file with mode: 0644]
ipsec-tools/racoon/Sample/anonymous.conf [new file with mode: 0644]
ipsec-tools/racoon/Sample/psk.txt [new file with mode: 0644]
ipsec-tools/racoon/Sample/racoon.conf [new file with mode: 0644]
ipsec-tools/racoon/admin.c [new file with mode: 0644]
ipsec-tools/racoon/admin.h [new file with mode: 0644]
ipsec-tools/racoon/admin_var.h [new file with mode: 0644]
ipsec-tools/racoon/algorithm.c [new file with mode: 0644]
ipsec-tools/racoon/algorithm.h [new file with mode: 0644]
ipsec-tools/racoon/arc4random.h [new file with mode: 0644]
ipsec-tools/racoon/backupsa.c [new file with mode: 0644]
ipsec-tools/racoon/backupsa.h [new file with mode: 0644]
ipsec-tools/racoon/cfparse.y [new file with mode: 0644]
ipsec-tools/racoon/cfparse_proto.h [new file with mode: 0644]
ipsec-tools/racoon/cftoken.l [new file with mode: 0644]
ipsec-tools/racoon/cftoken_proto.h [new file with mode: 0644]
ipsec-tools/racoon/crypto_cssm.c [new file with mode: 0644]
ipsec-tools/racoon/crypto_cssm.h [new file with mode: 0644]
ipsec-tools/racoon/crypto_openssl.c [new file with mode: 0644]
ipsec-tools/racoon/crypto_openssl.h [new file with mode: 0644]
ipsec-tools/racoon/debug.h [new file with mode: 0644]
ipsec-tools/racoon/debugrm.h [new file with mode: 0644]
ipsec-tools/racoon/dhgroup.h [new file with mode: 0644]
ipsec-tools/racoon/dnssec.c [new file with mode: 0644]
ipsec-tools/racoon/dnssec.h [new file with mode: 0644]
ipsec-tools/racoon/dump.h [new file with mode: 0644]
ipsec-tools/racoon/eaytest.c [new file with mode: 0644]
ipsec-tools/racoon/evt.c [new file with mode: 0644]
ipsec-tools/racoon/evt.h [new file with mode: 0644]
ipsec-tools/racoon/gcmalloc.h [new file with mode: 0644]
ipsec-tools/racoon/genlist.c [new file with mode: 0644]
ipsec-tools/racoon/genlist.h [new file with mode: 0644]
ipsec-tools/racoon/getcertsbyname.c [new file with mode: 0644]
ipsec-tools/racoon/gnuc.h [new file with mode: 0644]
ipsec-tools/racoon/grabmyaddr.c [new file with mode: 0644]
ipsec-tools/racoon/grabmyaddr.h [new file with mode: 0644]
ipsec-tools/racoon/gssapi.c [new file with mode: 0644]
ipsec-tools/racoon/gssapi.h [new file with mode: 0644]
ipsec-tools/racoon/handler.c [new file with mode: 0644]
ipsec-tools/racoon/handler.h [new file with mode: 0644]
ipsec-tools/racoon/ipsec_doi.c [new file with mode: 0644]
ipsec-tools/racoon/ipsec_doi.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_agg.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_agg.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_base.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_base.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_cfg.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_cfg.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_frag.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_frag.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_ident.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_ident.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_inf.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_inf.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_newg.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_newg.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_quick.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_quick.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_unity.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_unity.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_var.h [new file with mode: 0644]
ipsec-tools/racoon/isakmp_xauth.c [new file with mode: 0644]
ipsec-tools/racoon/isakmp_xauth.h [new file with mode: 0644]
ipsec-tools/racoon/kmpstat.c [new file with mode: 0644]
ipsec-tools/racoon/localconf.c [new file with mode: 0644]
ipsec-tools/racoon/localconf.h [new file with mode: 0644]
ipsec-tools/racoon/logger.c [new file with mode: 0644]
ipsec-tools/racoon/logger.h [new file with mode: 0644]
ipsec-tools/racoon/main.c [new file with mode: 0644]
ipsec-tools/racoon/misc.c [new file with mode: 0644]
ipsec-tools/racoon/misc.h [new file with mode: 0644]
ipsec-tools/racoon/nattraversal.c [new file with mode: 0644]
ipsec-tools/racoon/nattraversal.h [new file with mode: 0644]
ipsec-tools/racoon/netdb_dnssec.h [new file with mode: 0644]
ipsec-tools/racoon/oakley.c [new file with mode: 0644]
ipsec-tools/racoon/oakley.h [new file with mode: 0644]
ipsec-tools/racoon/open_dir.c [new file with mode: 0644]
ipsec-tools/racoon/open_dir.h [new file with mode: 0644]
ipsec-tools/racoon/pfkey.h [new file with mode: 0644]
ipsec-tools/racoon/pfkey_racoon.c [new file with mode: 0644]
ipsec-tools/racoon/plainrsa-gen.8 [new file with mode: 0644]
ipsec-tools/racoon/plainrsa-gen.c [new file with mode: 0644]
ipsec-tools/racoon/plog.c [new file with mode: 0644]
ipsec-tools/racoon/plog.h [new file with mode: 0644]
ipsec-tools/racoon/policy.c [new file with mode: 0644]
ipsec-tools/racoon/policy.h [new file with mode: 0644]
ipsec-tools/racoon/privsep.c [new file with mode: 0644]
ipsec-tools/racoon/privsep.h [new file with mode: 0644]
ipsec-tools/racoon/proposal.c [new file with mode: 0644]
ipsec-tools/racoon/proposal.h [new file with mode: 0644]
ipsec-tools/racoon/prsa_par.y [new file with mode: 0644]
ipsec-tools/racoon/prsa_tok.l [new file with mode: 0644]
ipsec-tools/racoon/racoon.8 [new file with mode: 0644]
ipsec-tools/racoon/racoon.conf.5 [new file with mode: 0644]
ipsec-tools/racoon/racoonctl.8 [new file with mode: 0644]
ipsec-tools/racoon/racoonctl.c [new file with mode: 0644]
ipsec-tools/racoon/racoonctl.h [new file with mode: 0644]
ipsec-tools/racoon/remoteconf.c [new file with mode: 0644]
ipsec-tools/racoon/remoteconf.h [new file with mode: 0644]
ipsec-tools/racoon/rsalist.c [new file with mode: 0644]
ipsec-tools/racoon/rsalist.h [new file with mode: 0644]
ipsec-tools/racoon/safefile.c [new file with mode: 0644]
ipsec-tools/racoon/safefile.h [new file with mode: 0644]
ipsec-tools/racoon/sainfo.c [new file with mode: 0644]
ipsec-tools/racoon/sainfo.h [new file with mode: 0644]
ipsec-tools/racoon/schedule.c [new file with mode: 0644]
ipsec-tools/racoon/schedule.h [new file with mode: 0644]
ipsec-tools/racoon/session.c [new file with mode: 0644]
ipsec-tools/racoon/session.h [new file with mode: 0644]
ipsec-tools/racoon/sockmisc.c [new file with mode: 0644]
ipsec-tools/racoon/sockmisc.h [new file with mode: 0644]
ipsec-tools/racoon/stats.pl [new file with mode: 0644]
ipsec-tools/racoon/str2val.c [new file with mode: 0644]
ipsec-tools/racoon/str2val.h [new file with mode: 0644]
ipsec-tools/racoon/strnames.c [new file with mode: 0644]
ipsec-tools/racoon/strnames.h [new file with mode: 0644]
ipsec-tools/racoon/throttle.c [new file with mode: 0644]
ipsec-tools/racoon/throttle.h [new file with mode: 0644]
ipsec-tools/racoon/var.h [new file with mode: 0644]
ipsec-tools/racoon/vendorid.c [new file with mode: 0644]
ipsec-tools/racoon/vendorid.h [new file with mode: 0644]
ipsec-tools/racoon/vmbuf.c [new file with mode: 0644]
ipsec-tools/racoon/vmbuf.h [new file with mode: 0644]
ipsec-tools/racoon/vpn_control.c [new file with mode: 0644]
ipsec-tools/racoon/vpn_control.h [new file with mode: 0644]
ipsec-tools/racoon/vpn_control_var.h [new file with mode: 0644]
ipsec-tools/setkey/Sample/sample-policy01.cf [new file with mode: 0644]
ipsec-tools/setkey/Sample/sample-policy02.cf [new file with mode: 0644]
ipsec-tools/setkey/Sample/sample.cf [new file with mode: 0644]
ipsec-tools/setkey/extern.h [new file with mode: 0644]
ipsec-tools/setkey/parse.y [new file with mode: 0644]
ipsec-tools/setkey/scriptdump.pl [new file with mode: 0644]
ipsec-tools/setkey/setkey.8 [new file with mode: 0644]
ipsec-tools/setkey/setkey.c [new file with mode: 0644]
ipsec-tools/setkey/test-pfkey.c [new file with mode: 0644]
ipsec-tools/setkey/token.l [new file with mode: 0644]
ipsec-tools/setkey/vchar.h [new file with mode: 0644]
ipsec.xcodeproj/project.pbxproj [new file with mode: 0644]

diff --git a/ipsec-tools/Common/config.h b/ipsec-tools/Common/config.h
new file mode 100644 (file)
index 0000000..be2c9ed
--- /dev/null
@@ -0,0 +1,256 @@
+
+
+/* If printf doesn't support %zu. */
+#undef BROKEN_PRINTF
+
+/* Enable admin port */
+#define ENABLE_ADMINPORT 1
+
+/* Enable VPN control port */
+#define ENABLE_VPNCONTROL_PORT 1
+
+/* Enable dead peer detection */
+#define ENABLE_DPD 1
+
+/* IKE fragmentation support */
+#undef ENABLE_FRAG
+
+/* Hybrid authentication support */
+#define ENABLE_HYBRID 1
+
+/* Enable NAT-Traversal */
+#define ENABLE_NATT 1
+
+#ifndef __APPLE__
+/* our kernel does not have support for versions 00 or 01 */
+/* Enable NAT-Traversal draft 00 */
+#undef ENABLE_NATT_00
+
+/* Enable NAT-Traversal draft 01 */
+#undef ENABLE_NATT_01
+#endif /* __APPLE__ */
+
+/* Enable NAT-Traversal draft 02 */
+#define ENABLE_NATT_02 1
+
+/* Enable NAT-Traversal draft 03 */
+#define ENABLE_NATT_03 1
+
+/* Enable NAT-Traversal draft 04 */
+#define ENABLE_NATT_04 1
+
+/* Enable NAT-Traversal draft 05 */
+#define ENABLE_NATT_05 1
+
+/* Enable NAT-Traversal draft 06 */
+#define ENABLE_NATT_06 1
+
+/* Enable NAT-Traversal draft 07 */
+#define ENABLE_NATT_07 1
+
+/* Enable NAT-Traversal draft 08 */
+#define ENABLE_NATT_08 1
+
+/* Enable NAT-Traversal APPLE version */
+#define ENABLE_NATT_APPLE 1
+
+/* Enable NAT-Traversal RFC version */
+#define ENABLE_NATT_RFC 1
+
+/* Enable samode-unspec */
+#undef ENABLE_SAMODE_UNSPECIFIED
+
+/* Enable statictics */
+//#define ENABLE_STATS 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Have __func__ macro */
+#define HAVE_FUNC_MACRO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Enable GSS API */
+#define HAVE_GSSAPI 1
+
+/* Have iconv using const */
+#define HAVE_ICONV_2ND_CONST 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Have ipsec_policy_t */
+#undef HAVE_IPSEC_POLICY_T
+
+/* Hybrid authentication uses PAM */
+#define HAVE_LIBPAM 1
+
+/* Hybrid authentication uses RADIUS */
+#undef HAVE_LIBRADIUS
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Use <netinet6/ipsec.h> */
+#define HAVE_NETINET6_IPSEC 1
+
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the <openssl/aes.h> header file. */
+#define HAVE_OPENSSL_AES_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/idea.h> header file. */
+#undef HAVE_OPENSSL_IDEA_H
+
+/* Define to 1 if you have the <openssl/rc5.h> header file. */
+#define HAVE_OPENSSL_RC5_H 1
+
+/* Define to 1 if you have the `pam_start' function. */
+#define HAVE_PAM_START 1
+
+/* Are PF_KEY policy priorities supported? */
+#undef HAVE_PFKEY_POLICY_PRIORITY
+
+/* Have forward policy */
+#undef HAVE_POLICY_FWD
+
+/* Define to 1 if you have the `rad_create_request' function. */
+#undef HAVE_RAD_CREATE_REQUEST
+
+/* Is readline available? */
+#undef HAVE_READLINE
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* sha2 is defined in sha.h */
+#define HAVE_SHA2_IN_SHA_H 1
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <varargs.h> header file. */
+#define HAVE_VARARGS_H 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Support IPv6 */
+#define INET6 1
+
+/* Use advanced IPv6 API */
+#define INET6_ADVAPI 1
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE int
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#define TM_IN_SYS_TIME 1
+
+/* A 'va_copy' style function */
+#undef VA_COPY
+
+/* Version number of package */
+#undef VERSION
+
+/* SHA2 support */
+#define WITH_SHA2 1
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/ipsec-tools/Common/key_debug.c b/ipsec-tools/Common/key_debug.c
new file mode 100644 (file)
index 0000000..06a9d4b
--- /dev/null
@@ -0,0 +1,819 @@
+/*     $KAME: key_debug.c,v 1.29 2001/08/16 14:25:41 itojun Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _KERNEL
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipsec.h"
+#endif
+#ifdef __NetBSD__
+#include "opt_inet.h"
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/queue.h>
+#endif
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#ifndef _KERNEL
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#endif /* !_KERNEL */
+
+#include "config.h"
+#include "libpfkey.h"
+
+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 *));
+static void kdebug_sadb_x_sa2 __P((struct sadb_ext *));
+static void kdebug_sadb_x_policy __P((struct sadb_ext *ext));
+static void kdebug_sockaddr __P((struct sockaddr *addr));
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static void kdebug_sadb_x_nat_t_type __P((struct sadb_ext *ext));
+static void kdebug_sadb_x_nat_t_port __P((struct sadb_ext *ext));
+#endif
+
+#ifdef _KERNEL
+static void kdebug_secreplay __P((struct secreplay *));
+#endif
+
+#ifndef _KERNEL
+#define panic(param)   { printf(param); exit(1); }
+#endif
+
+#include "libpfkey.h"
+/* NOTE: host byte order */
+
+/* %%%: about struct sadb_msg */
+void
+kdebug_sadb(base)
+       struct sadb_msg *base;
+{
+       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 reserved=%u seq=%u pid=%u\n",
+           base->sadb_msg_len, base->sadb_msg_reserved,
+           base->sadb_msg_seq, base->sadb_msg_pid);
+
+       tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg);
+       ext = (void *)((caddr_t)(void *)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;
+               }
+               if (ext->sadb_ext_len > tlen) {
+                       printf("kdebug_sadb: ext_len exceeds end of buffer.\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;
+               case SADB_X_EXT_SA2:
+                       kdebug_sadb_x_sa2(ext);
+                       break;
+#ifdef SADB_X_EXT_NAT_T_TYPE
+               case SADB_X_EXT_NAT_T_TYPE:
+                       kdebug_sadb_x_nat_t_type(ext);
+                       break;
+               case SADB_X_EXT_NAT_T_SPORT:
+               case SADB_X_EXT_NAT_T_DPORT:
+                       kdebug_sadb_x_nat_t_port(ext);
+                       break;
+               case SADB_X_EXT_NAT_T_OA:
+                       kdebug_sadb_address(ext);
+                       break;
+#endif
+               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 = (void *)((caddr_t)(void *)ext + extlen);
+       }
+
+       return;
+}
+
+static void
+kdebug_sadb_prop(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_prop *prop = (void *)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 = (void *)(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;
+}
+
+static void
+kdebug_sadb_identity(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_ident *id = (void *)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");
+       switch (id->sadb_ident_type) {
+       default:
+               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 = (void *)(id + 1);
+                       ep = p + len;
+                       for (/*nothing*/; *p && p < ep; p++) {
+                               if (isprint((int)*p))
+                                       printf("%c", *p & 0xff);
+                               else
+                                       printf("\\%03o", *p & 0xff);
+                       }
+#endif
+                       printf("\"");
+               }
+               break;
+       }
+
+       printf(" }\n");
+
+       return;
+}
+
+static void
+kdebug_sadb_supported(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_supported *sup = (void *)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 = (void *)(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;
+}
+
+static void
+kdebug_sadb_lifetime(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_lifetime *lft = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               printf("kdebug_sadb_lifetime: NULL pointer was passed.\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);
+
+       return;
+}
+
+static void
+kdebug_sadb_sa(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_sa *sa = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_sa: NULL pointer was passed.\n");
+
+       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);
+
+       return;
+}
+
+static void
+kdebug_sadb_address(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_address *addr = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_address: NULL pointer was passed.\n");
+
+       printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n",
+           addr->sadb_address_proto, addr->sadb_address_prefixlen,
+           ((u_char *)(void *)&addr->sadb_address_reserved)[0],
+           ((u_char *)(void *)&addr->sadb_address_reserved)[1]);
+
+       kdebug_sockaddr((void *)((caddr_t)(void *)ext + sizeof(*addr)));
+
+       return;
+}
+
+static void
+kdebug_sadb_key(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_key *key = (void *)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 (((uint32_t)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",
+                       (uint32_t)key->sadb_key_bits >> 3,
+                       (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key));
+       }
+
+       ipsec_hexdump(key + sizeof(struct sadb_key),
+                     (int)((uint32_t)key->sadb_key_bits >> 3));
+       printf(" }\n");
+       return;
+}
+
+static void
+kdebug_sadb_x_sa2(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_x_sa2 *sa2 = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n");
+
+       printf("sadb_x_sa2{ mode=%u reqid=%u\n",
+           sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid);
+       printf("  reserved1=%u reserved2=%u sequence=%u }\n",
+           sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved2,
+           sa2->sadb_x_sa2_sequence);
+
+       return;
+}
+
+void
+kdebug_sadb_x_policy(ext)
+       struct sadb_ext *ext;
+{
+       struct sadb_x_policy *xpl = (void *)ext;
+       struct sockaddr *addr;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_x_policy: NULL pointer was passed.\n");
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       printf("sadb_x_policy{ type=%u dir=%u id=%x priority=%u }\n",
+#else
+       printf("sadb_x_policy{ type=%u dir=%u id=%x }\n",
+#endif
+               xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir,
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+               xpl->sadb_x_policy_id, xpl->sadb_x_policy_priority);
+#else
+               xpl->sadb_x_policy_id);
+#endif
+
+       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 = (void *)(xpl + 1);
+
+               while (tlen > 0) {
+                       printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n",
+                               xisr->sadb_x_ipsecrequest_len,
+                               xisr->sadb_x_ipsecrequest_proto,
+                               xisr->sadb_x_ipsecrequest_mode,
+                               xisr->sadb_x_ipsecrequest_level,
+                               xisr->sadb_x_ipsecrequest_reqid);
+
+                       if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+                               addr = (void *)(xisr + 1);
+                               kdebug_sockaddr(addr);
+                               addr = (void *)((caddr_t)(void *)addr
+                                                       + sysdep_sa_len(addr));
+                               kdebug_sockaddr(addr);
+                       }
+
+                       printf(" }\n");
+
+                       /* prevent infinite loop */
+                       if (xisr->sadb_x_ipsecrequest_len == 0) {
+                               printf("kdebug_sadb_x_policy: wrong policy struct.\n");
+                               return;
+                       }
+                       /* prevent overflow */
+                       if (xisr->sadb_x_ipsecrequest_len > tlen) {
+                               printf("invalid ipsec policy length\n");
+                               return;
+                       }
+
+                       tlen -= xisr->sadb_x_ipsecrequest_len;
+
+                       xisr = (void *)((caddr_t)(void *)xisr
+                                       + xisr->sadb_x_ipsecrequest_len);
+               }
+
+               if (tlen != 0)
+                       panic("kdebug_sadb_x_policy: wrong policy struct.\n");
+       }
+
+       return;
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static void
+kdebug_sadb_x_nat_t_type(struct sadb_ext *ext)
+{
+       struct sadb_x_nat_t_type *ntt = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_x_nat_t_type: NULL pointer was passed.\n");
+
+       printf("sadb_x_nat_t_type{ type=%u }\n", ntt->sadb_x_nat_t_type_type);
+
+       return;
+}
+
+static void
+kdebug_sadb_x_nat_t_port(struct sadb_ext *ext)
+{
+       struct sadb_x_nat_t_port *ntp = (void *)ext;
+
+       /* sanity check */
+       if (ext == NULL)
+               panic("kdebug_sadb_x_nat_t_port: NULL pointer was passed.\n");
+
+       printf("sadb_x_nat_t_port{ port=%u }\n", ntohs(ntp->sadb_x_nat_t_port_port));
+
+       return;
+}
+#endif
+
+#ifdef _KERNEL
+/* %%%: about SPD and SAD */
+void
+kdebug_secpolicy(sp)
+       struct secpolicy *sp;
+{
+       /* 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_GENERATE:
+               printf("  type=generate }\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;
+}
+
+void
+kdebug_secpolicyindex(spidx)
+       struct secpolicyindex *spidx;
+{
+       /* 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,
+               sysdep_sa_len((struct sockaddr *)&spidx->src));
+       printf("\n");
+       ipsec_hexdump((caddr_t)&spidx->dst,
+               sysdep_sa_len((struct sockaddr *)&spidx->dst));
+       printf("}\n");
+
+       return;
+}
+
+void
+kdebug_secasindex(saidx)
+       struct secasindex *saidx;
+{
+       /* 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,
+               sysdep_sa_len((struct sockaddr *)&saidx->src));
+       printf("\n");
+       ipsec_hexdump((caddr_t)&saidx->dst,
+               sysdep_sa_len((struct sockaddr *)&saidx->dst));
+       printf("\n");
+
+       return;
+}
+
+void
+kdebug_secasv(sav)
+       struct secasvar *sav;
+{
+       /* 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);
+
+#if notyet
+       /* XXX: misc[123] ? */
+#endif
+
+       return;
+}
+
+static void
+kdebug_secreplay(rpl)
+       struct secreplay *rpl;
+{
+       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;
+}
+
+void
+kdebug_mbufhdr(m)
+       struct mbuf *m;
+{
+       /* sanity check */
+       if (m == NULL)
+               return;
+
+       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);
+       }
+
+#ifdef __FreeBSD__
+       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);
+       }
+#endif
+
+       return;
+}
+
+void
+kdebug_mbuf(m0)
+       struct mbuf *m0;
+{
+       struct mbuf *m = m0;
+       int i, j;
+
+       for (j = 0; m; m = m->m_next) {
+               kdebug_mbufhdr(m);
+               printf("  m_data:\n");
+               for (i = 0; i < m->m_len; i++) {
+                       if (i && i % 32 == 0)
+                               printf("\n");
+                       if (i % 4 == 0)
+                               printf(" ");
+                       printf("%02x", mtod(m, u_char *)[i]);
+                       j++;
+               }
+               printf("\n");
+       }
+
+       return;
+}
+#endif /* _KERNEL */
+
+static void
+kdebug_sockaddr(addr)
+       struct sockaddr *addr;
+{
+       struct sockaddr_in *sin4;
+#ifdef INET6
+       struct sockaddr_in6 *sin6;
+#endif
+
+       /* sanity check */
+       if (addr == NULL)
+               panic("kdebug_sockaddr: NULL pointer was passed.\n");
+
+       /* NOTE: We deal with port number as host byte order. */
+       printf("sockaddr{ len=%u family=%u", sysdep_sa_len(addr), addr->sa_family);
+
+       switch (addr->sa_family) {
+       case AF_INET:
+               sin4 = (void *)addr;
+               printf(" port=%u\n", ntohs(sin4->sin_port));
+               ipsec_hexdump(&sin4->sin_addr, sizeof(sin4->sin_addr));
+               break;
+#ifdef INET6
+       case AF_INET6:
+               sin6 = (void *)addr;
+               printf(" port=%u\n", ntohs(sin6->sin6_port));
+               printf("  flowinfo=0x%08x, scope_id=0x%08x\n",
+                   sin6->sin6_flowinfo, sin6->sin6_scope_id);
+               ipsec_hexdump(&sin6->sin6_addr, sizeof(sin6->sin6_addr));
+               break;
+#endif
+       }
+
+       printf("  }\n");
+
+       return;
+}
+
+void
+ipsec_bindump(buf, len)
+       caddr_t buf;
+       int len;
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               printf("%c", (unsigned char)buf[i]);
+
+       return;
+}
+
+
+void
+ipsec_hexdump(buf, len)
+       const void *buf;
+       int len;
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               if (i != 0 && i % 32 == 0) printf("\n");
+               if (i % 4 == 0) printf(" ");
+               printf("%02x", ((const unsigned char *)buf)[i]);
+       }
+#if 0
+       if (i % 32 != 0) printf("\n");
+#endif
+
+       return;
+}
diff --git a/ipsec-tools/Common/libpfkey.h b/ipsec-tools/Common/libpfkey.h
new file mode 100644 (file)
index 0000000..628c835
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: libpfkey.h,v 1.8.2.4 2005/12/04 20:41:47 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBPFKEY_H
+#define _LIBPFKEY_H
+
+#ifndef KAME_LIBPFKEY_H
+#define KAME_LIBPFKEY_H
+
+#include "config.h"
+
+#define PRIORITY_LOW        0xC0000000
+#define PRIORITY_DEFAULT    0x80000000
+#define PRIORITY_HIGH       0x40000000
+
+#define PRIORITY_OFFSET_POSITIVE_MAX   0x3fffffff
+#define PRIORITY_OFFSET_NEGATIVE_MAX   0x40000000
+
+struct sadb_msg;
+extern void pfkey_sadump __P((struct sadb_msg *));
+extern void pfkey_sadump_withports __P((struct sadb_msg *));
+extern void pfkey_spdump __P((struct sadb_msg *));
+extern void pfkey_spdump_withports __P((struct sadb_msg *));
+
+struct sockaddr;
+struct sadb_alg;
+
+/* Accomodate different prototypes in <netinet6/ipsec.h> */
+#include <sys/types.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+
+#ifndef HAVE_IPSEC_POLICY_T
+typedef caddr_t ipsec_policy_t;
+#define __ipsec_const
+#else
+#define __ipsec_const const
+#endif
+
+/* IPsec Library Routines */
+
+int ipsec_check_keylen __P((u_int, u_int, u_int));
+int ipsec_check_keylen2 __P((u_int, u_int, u_int));
+int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *));
+char *ipsec_dump_policy_withports __P((void *, const char *));
+void ipsec_hexdump __P((const void *, int));
+const char *ipsec_strerror __P((void));
+void kdebug_sadb __P((struct sadb_msg *));
+ipsec_policy_t ipsec_set_policy __P((__ipsec_const char *, int));
+int  ipsec_get_policylen __P((ipsec_policy_t));
+char *ipsec_dump_policy __P((ipsec_policy_t, __ipsec_const char *));
+
+/* PFKey Routines */
+
+u_int pfkey_set_softrate __P((u_int, u_int));
+u_int pfkey_get_softrate __P((u_int));
+int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+#ifdef __APPLE__
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t, u_int16_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t, u_int16_t));
+#else
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_update_nat __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t,
+       u_int8_t, u_int16_t, u_int16_t, struct sockaddr *, u_int16_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_add_nat __P((int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+       u_int64_t, u_int64_t, u_int32_t,
+       u_int8_t, u_int16_t, u_int16_t, struct sockaddr *, u_int16_t));
+#endif /*__APPLE__ */
+
+int pfkey_send_delete __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_delete_all __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *));
+int pfkey_send_get __P((int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_register __P((int, u_int));
+int pfkey_recv_register __P((int));
+int pfkey_set_supported __P((struct sadb_msg *, int));
+int pfkey_send_flush __P((int, u_int));
+int pfkey_send_dump __P((int, u_int));
+int pfkey_send_promisc_toggle __P((int, int));
+int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       caddr_t, int, u_int32_t));
+int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete2 __P((int, u_int32_t));
+int pfkey_send_spdget __P((int, u_int32_t));
+int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdflush __P((int));
+int pfkey_send_spddump __P((int));
+
+int pfkey_open __P((void));
+void pfkey_close __P((int));
+struct sadb_msg *pfkey_recv __P((int));
+int pfkey_send __P((int, struct sadb_msg *, int));
+int pfkey_align __P((struct sadb_msg *, caddr_t *));
+int pfkey_check __P((caddr_t *));
+
+#ifndef __SYSDEP_SA_LEN__
+#define __SYSDEP_SA_LEN__
+#include <netinet/in.h>
+
+#ifndef IPPROTO_IPV4
+#define IPPROTO_IPV4 IPPROTO_IPIP
+#endif
+
+#ifndef IPPROTO_IPCOMP
+#define IPPROTO_IPCOMP IPPROTO_COMP
+#endif
+
+static __inline u_int8_t
+sysdep_sa_len (const struct sockaddr *sa)
+{
+#ifdef __linux__
+  switch (sa->sa_family)
+    {
+    case AF_INET:
+      return sizeof (struct sockaddr_in);
+    case AF_INET6:
+      return sizeof (struct sockaddr_in6);
+    }
+  // log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family);
+  return sizeof (struct sockaddr_in);
+#else
+  return sa->sa_len;
+#endif
+}
+#endif
+
+#endif /* KAME_LIBPFKEY_H */
+
+#endif /* _LIBPFKEY_H */
diff --git a/ipsec-tools/Common/pfkey.c b/ipsec-tools/Common/pfkey.c
new file mode 100644 (file)
index 0000000..0e566a4
--- /dev/null
@@ -0,0 +1,2739 @@
+/*     $KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int findsupportedmap __P((int));
+static int setsupportedmap __P((struct sadb_supported *));
+static struct sadb_alg *findsupportedalg __P((u_int, u_int));
+#ifdef __APPLE__
+static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+       u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+       u_int32_t, u_int32_t, u_int32_t, u_int16_t));
+#else
+static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
+       struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+       u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+       u_int32_t, u_int32_t, u_int32_t,
+       u_int8_t, u_int16_t, u_int16_t, struct sockaddr *, u_int16_t));
+#endif
+static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t));
+static int pfkey_send_x3 __P((int, u_int, u_int));
+static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
+       struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+       char *, int, u_int32_t));
+static int pfkey_send_x5 __P((int, u_int, u_int32_t));
+
+static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
+       u_int, u_int32_t, pid_t));
+#ifdef __APPLE__
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
+       u_int, u_int, u_int32_t, u_int16_t));
+#else
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
+       u_int, u_int, u_int32_t));
+#endif
+static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
+       struct sockaddr *, u_int, u_int));
+static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
+static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
+       u_int32_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static caddr_t pfkey_set_natt_type __P((caddr_t, caddr_t, u_int, u_int8_t));
+static caddr_t pfkey_set_natt_port __P((caddr_t, caddr_t, u_int, u_int16_t));
+#endif
+#ifdef SADB_X_EXT_NAT_T_FRAG
+static caddr_t pfkey_set_natt_frag __P((caddr_t, caddr_t, u_int, u_int16_t));
+#endif
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, 
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+    NULL,
+#endif
+};
+
+static int supported_map[] = {
+       SADB_SATYPE_AH,
+       SADB_SATYPE_ESP,
+       SADB_X_SATYPE_IPCOMP,
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+       SADB_X_SATYPE_TCPSIGNATURE,
+#endif
+};
+
+static int
+findsupportedmap(satype)
+       int satype;
+{
+       int i;
+
+       for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+               if (supported_map[i] == satype)
+                       return i;
+       return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+       u_int satype, alg_id;
+{
+       int algno;
+       int tlen;
+       caddr_t p;
+
+       /* validity check */
+       algno = findsupportedmap((int)satype);
+       if (algno == -1) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return NULL;
+       }
+       if (ipsec_supported[algno] == NULL) {
+               __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+               return NULL;
+       }
+
+       tlen = ipsec_supported[algno]->sadb_supported_len
+               - sizeof(struct sadb_supported);
+       p = (void *)(ipsec_supported[algno] + 1);
+       while (tlen > 0) {
+               if (tlen < sizeof(struct sadb_alg)) {
+                       /* invalid format */
+                       break;
+               }
+               if (((struct sadb_alg *)(void *)p)->sadb_alg_id == alg_id)
+                       return (void *)p;
+
+               tlen -= sizeof(struct sadb_alg);
+               p += sizeof(struct sadb_alg);
+       }
+
+       __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+       return NULL;
+}
+
+static int
+setsupportedmap(sup)
+       struct sadb_supported *sup;
+{
+       struct sadb_supported **ipsup;
+
+       switch (sup->sadb_supported_exttype) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       if (*ipsup)
+               free(*ipsup);
+
+       *ipsup = malloc((size_t)sup->sadb_supported_len);
+       if (!*ipsup) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       memcpy(*ipsup, sup, (size_t)sup->sadb_supported_len);
+
+       return 0;
+}
+
+/*
+ * check key length against algorithm specified.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+       u_int supported;
+       u_int alg_id;
+       u_int keylen;
+{
+       u_int satype;
+
+       /* validity check */
+       switch (supported) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               satype = SADB_SATYPE_AH;
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               satype = SADB_SATYPE_ESP;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       return ipsec_check_keylen2(satype, alg_id, keylen);
+}
+
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+       u_int satype;
+       u_int alg_id;
+       u_int keylen;
+{
+       struct sadb_alg *alg;
+
+       alg = findsupportedalg(satype, alg_id);
+       if (!alg)
+               return -1;
+
+       if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+               fprintf(stderr, "%d %d %d\n", keylen, alg->sadb_alg_minbits,
+                       alg->sadb_alg_maxbits);
+               __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ *     -1: invalid.
+ *      0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+       u_int supported, alg_id;
+       struct sadb_alg *alg0;
+{
+       struct sadb_alg *alg;
+       u_int satype;
+
+       /* validity check */
+       if (!alg0) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       switch (supported) {
+       case SADB_EXT_SUPPORTED_AUTH:
+               satype = SADB_SATYPE_AH;
+               break;
+       case SADB_EXT_SUPPORTED_ENCRYPT:
+               satype = SADB_SATYPE_ESP;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       alg = findsupportedalg(satype, alg_id);
+       if (!alg)
+               return -1;
+
+       memcpy(alg0, alg, sizeof(*alg0));
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+       u_int type, rate;
+{
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       if (rate > 100 || rate == 0)
+               rate = 100;
+
+       switch (type) {
+       case SADB_X_LIFETIME_ALLOCATIONS:
+               soft_lifetime_allocations_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_BYTES:
+               soft_lifetime_bytes_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_ADDTIME:
+               soft_lifetime_addtime_rate = rate;
+               return 0;
+       case SADB_X_LIFETIME_USETIME:
+               soft_lifetime_usetime_rate = rate;
+               return 0;
+       }
+
+       __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+       return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+       u_int type;
+{
+       switch (type) {
+       case SADB_X_LIFETIME_ALLOCATIONS:
+               return soft_lifetime_allocations_rate;
+       case SADB_X_LIFETIME_BYTES:
+               return soft_lifetime_bytes_rate;
+       case SADB_X_LIFETIME_ADDTIME:
+               return soft_lifetime_addtime_rate;
+       case SADB_X_LIFETIME_USETIME:
+               return soft_lifetime_usetime_rate;
+       }
+
+       return (u_int)~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t min, max, reqid, seq;
+{
+       struct sadb_msg *newmsg;
+       caddr_t ep;
+       int len;
+       int need_spirange = 0;
+       caddr_t p;
+       int plen;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       if (min > max || (min > 0 && min <= 255)) {
+               __ipsec_errcode = EIPSEC_INVAL_SPI;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to send. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_x_sa2)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(dst));
+
+       if (min > 255 && max < (u_int)~0) {
+               need_spirange++;
+               len += sizeof(struct sadb_spirange);
+       }
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_GETSPI,
+           (u_int)len, satype, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* set sadb_address for source */
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* set sadb_address for destination */
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* proccessing spi range */
+       if (need_spirange) {
+               struct sadb_spirange spirange;
+
+               if (p + sizeof(spirange) > ep) {
+                       free(newmsg);
+                       return -1;
+               }
+
+               memset(&spirange, 0, sizeof(spirange));
+               spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+               spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+               spirange.sadb_spirange_min = min;
+               spirange.sadb_spirange_max = max;
+
+               memcpy(p, &spirange, sizeof(spirange));
+
+               p += sizeof(spirange);
+       }
+       if (p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+
+#ifdef __APPLE__
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq, port)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+       u_int16_t port;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, port)) < 0)
+               return -1;
+
+       return len;
+}
+
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq, port)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+       u_int16_t port;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, port)) < 0)
+               return -1;
+
+       return len;
+}
+
+
+#else /* __APPLE__ */
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, 0, 0, 0, NULL, 0)) < 0)
+               return -1;
+
+       return len;
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+int
+pfkey_send_update_nat(so, satype, mode, src, dst, spi, reqid, wsize,
+                     keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                     l_alloc, l_bytes, l_addtime, l_usetime, seq,
+                     l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa,
+                     l_natt_frag)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+       u_int8_t l_natt_type;
+       u_int16_t l_natt_sport, l_natt_dport;
+       struct sockaddr *l_natt_oa;
+       u_int16_t l_natt_frag;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, l_natt_type, l_natt_sport, 
+                       l_natt_dport, l_natt_oa, l_natt_frag)) < 0)
+               return -1;
+
+       return len;
+}
+#endif
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, 0, 0, 0, NULL, 0)) < 0)
+               return -1;
+
+       return len;
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+int
+pfkey_send_add_nat(so, satype, mode, src, dst, spi, reqid, wsize,
+                  keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                  l_alloc, l_bytes, l_addtime, l_usetime, seq,
+                  l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa,
+                  l_natt_frag)
+       int so;
+       u_int satype, mode, wsize;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc;
+       u_int64_t l_bytes, l_addtime, l_usetime;
+       u_int32_t seq;
+       u_int8_t l_natt_type;
+       u_int16_t l_natt_sport, l_natt_dport;
+       struct sockaddr *l_natt_oa;
+       u_int16_t l_natt_frag;
+{
+       int len;
+       if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+                       reqid, wsize,
+                       keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                       l_alloc, (u_int)l_bytes, (u_int)l_addtime, 
+                       (u_int)l_usetime, seq, l_natt_type, l_natt_sport, 
+                       l_natt_dport, l_natt_oa, l_natt_frag)) < 0)
+               return -1;
+
+       return len;
+}
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       int len;
+       if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_DELETE without spi to the kernel.  This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ *     positive: success and return length sent
+ *     -1      : error occured, and set errno
+ */
+/*ARGSUSED*/
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(dst));
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_DELETE, (u_int)len, 
+           satype, 0, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+       int so;
+       u_int satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       int len;
+       if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+       int so;
+       u_int satype;
+{
+       int len, algno;
+
+       if (satype == PF_UNSPEC) {
+               for (algno = 0;
+                    algno < sizeof(supported_map)/sizeof(supported_map[0]);
+                    algno++) {
+                       if (ipsec_supported[algno]) {
+                               free(ipsec_supported[algno]);
+                               ipsec_supported[algno] = NULL;
+                       }
+               }
+       } else {
+               algno = findsupportedmap((int)satype);
+               if (algno == -1) {
+                       __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+                       return -1;
+               }
+
+               if (ipsec_supported[algno]) {
+                       free(ipsec_supported[algno]);
+                       ipsec_supported[algno] = NULL;
+               }
+       }
+
+       if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ *      0: success and return length sent.
+ *     -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+       int so;
+{
+       pid_t pid = getpid();
+       struct sadb_msg *newmsg;
+       int error = -1;
+
+       /* receive message */
+       for (;;) {
+               if ((newmsg = pfkey_recv(so)) == NULL)
+                       return -1;
+               if (newmsg->sadb_msg_type == SADB_REGISTER &&
+                   newmsg->sadb_msg_pid == pid)
+                       break;
+               free(newmsg);
+       }
+
+       /* check and fix */
+       newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+       error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+       free(newmsg);
+
+       if (error == 0)
+               __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ *     tlen: msg length, it's to makeing sure.
+ * OUT:
+ *      0: success and return length sent.
+ *     -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+       struct sadb_msg *msg;
+       int tlen;
+{
+       struct sadb_supported *sup;
+       caddr_t p;
+       caddr_t ep;
+
+       /* validity */
+       if (msg->sadb_msg_len != tlen) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       p = (void *)msg;
+       ep = p + tlen;
+
+       p += sizeof(struct sadb_msg);
+
+       while (p < ep) {
+               sup = (void *)p;
+               if (ep < p + sizeof(*sup) ||
+                   PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+                   ep < p + sup->sadb_supported_len) {
+                       /* invalid format */
+                       break;
+               }
+
+               switch (sup->sadb_supported_exttype) {
+               case SADB_EXT_SUPPORTED_AUTH:
+               case SADB_EXT_SUPPORTED_ENCRYPT:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+
+               /* fixed length */
+               sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+               /* set supported map */
+               if (setsupportedmap(sup) != 0)
+                       return -1;
+
+               p += sup->sadb_supported_len;
+       }
+
+       if (p != ep) {
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+       int so;
+       u_int satype;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+       int so;
+       u_int satype;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ *     flag:   set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ *     0     : error occured, and set errno.
+ *     others: a pointer to new allocated buffer in which supported
+ *             algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+       int so;
+       int flag;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_PROMISC, 
+           (u_int)(flag ? 1 : 0))) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+                               src, prefs, dst, prefd, proto,
+                               (u_int64_t)0, (u_int64_t)0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+               policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+                               src, prefs, dst, prefd, proto,
+                               ltime, vtime,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+                               src, prefs, dst, prefd, proto,
+                               (u_int64_t)0, (u_int64_t)0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+               policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+                               src, prefs, dst, prefd, proto,
+                               ltime, vtime,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if (policylen != sizeof(struct sadb_x_policy)) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
+                               src, prefs, dst, prefd, proto,
+                               (u_int64_t)0, (u_int64_t)0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete2(so, spid)
+       int so;
+       u_int32_t spid;
+{
+       int len;
+
+       if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDGET message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdget(so, spid)
+       int so;
+       u_int32_t spid;
+{
+       int len;
+
+       if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_X_SPDSETIDX message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int prefs, prefd, proto;
+       caddr_t policy;
+       int policylen;
+       u_int32_t seq;
+{
+       int len;
+
+       if (policylen != sizeof(struct sadb_x_policy)) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
+                               src, prefs, dst, prefd, proto,
+                               (u_int64_t)0, (u_int64_t)0,
+                               policy, policylen, seq)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+       int so;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+               return -1;
+
+       return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ *     positive: success and return length sent.
+ *     -1      : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+       int so;
+{
+       int len;
+
+       if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+               return -1;
+
+       return len;
+}
+
+#ifdef __APPLE__
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq, port)
+       int so;
+       u_int type, satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi, reqid;
+       u_int wsize;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+       u_int16_t port;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       switch (satype) {
+       case SADB_SATYPE_ESP:
+               if (e_type == SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_AH:
+               if (e_type != SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type == SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_X_SATYPE_IPCOMP:
+               if (e_type == SADB_X_CALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type != SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+#ifdef SADB_X_AALG_TCP_MD5
+       case SADB_X_SATYPE_TCPSIGNATURE:
+               if (e_type != SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type != SADB_X_AALG_TCP_MD5) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               break;
+#endif
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_sa_2)
+               + sizeof(struct sadb_x_sa2)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(dst))
+               + sizeof(struct sadb_lifetime)
+               + sizeof(struct sadb_lifetime);
+               
+       if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+       if (a_type != SADB_AALG_NONE)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
+                            satype, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags, port);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+                                  keymat, e_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+       if (a_type != SADB_AALG_NONE) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+                                  keymat + e_keylen, a_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+
+       /* set sadb_lifetime for destination */
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       
+       if (p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+#else /* __APPLE__ */
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+               keymat, e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, l_bytes, l_addtime, l_usetime, seq,
+               l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa, 
+               l_natt_frag)
+       int so;
+       u_int type, satype, mode;
+       struct sockaddr *src, *dst, *l_natt_oa;
+       u_int32_t spi, reqid;
+       u_int wsize;
+       caddr_t keymat;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+       u_int16_t l_natt_sport, l_natt_dport;
+       u_int8_t l_natt_type;
+       u_int16_t l_natt_frag;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       switch (satype) {
+       case SADB_SATYPE_ESP:
+               if (e_type == SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_AH:
+               if (e_type != SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type == SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+       case SADB_X_SATYPE_IPCOMP:
+               if (e_type == SADB_X_CALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type != SADB_AALG_NONE) {
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+               break;
+#ifdef SADB_X_AALG_TCP_MD5
+       case SADB_X_SATYPE_TCPSIGNATURE:
+               if (e_type != SADB_EALG_NONE) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               if (a_type != SADB_X_AALG_TCP_MD5) {
+                       __ipsec_errcode = EIPSEC_INVAL_ALGS;
+                       return -1;
+               }
+               break;
+#endif
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_sa)
+               + sizeof(struct sadb_x_sa2)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(dst))
+               + sizeof(struct sadb_lifetime)
+               + sizeof(struct sadb_lifetime);
+
+       if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+       if (a_type != SADB_AALG_NONE)
+               len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       /* add nat-t packets */
+       if (l_natt_type) {
+               switch(satype) {
+               case SADB_SATYPE_ESP:
+               case SADB_X_SATYPE_IPCOMP:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_NO_ALGS;
+                       return -1;
+               }
+
+               len += sizeof(struct sadb_x_nat_t_type);
+               len += sizeof(struct sadb_x_nat_t_port);
+               len += sizeof(struct sadb_x_nat_t_port);
+               if (l_natt_oa)
+                       len += sizeof(struct sadb_address) +
+                         PFKEY_ALIGN8(sysdep_sa_len(l_natt_oa));
+#ifdef SADB_X_EXT_NAT_T_FRAG
+               if (l_natt_frag)
+                       len += sizeof(struct sadb_x_nat_t_frag);
+#endif
+       }
+#endif
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
+                            satype, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+                                  keymat, e_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+       if (a_type != SADB_AALG_NONE) {
+               p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+                                  keymat + e_keylen, a_keylen);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+       }
+
+       /* set sadb_lifetime for destination */
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+                       l_alloc, l_bytes, l_addtime, l_usetime);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       /* Add nat-t messages */
+       if (l_natt_type) {
+               p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE, l_natt_type);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+
+               p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT,
+                                       l_natt_sport);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+
+               p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT,
+                                       l_natt_dport);
+               if (!p) {
+                       free(newmsg);
+                       return -1;
+               }
+
+               if (l_natt_oa) {
+                       p = pfkey_setsadbaddr(p, ep, SADB_X_EXT_NAT_T_OA,
+                                             l_natt_oa,
+                                             (u_int)PFKEY_ALIGN8(sysdep_sa_len(l_natt_oa)),
+                                             IPSEC_ULPROTO_ANY);
+                       if (!p) {
+                               free(newmsg);
+                               return -1;
+                       }
+               }
+
+               if (l_natt_frag) {
+#ifdef SADB_X_EXT_NAT_T_FRAG
+                       p = pfkey_set_natt_frag(p, ep, SADB_X_EXT_NAT_T_FRAG,
+                                       l_natt_frag);
+                       if (!p) {
+                               free(newmsg);
+                               return -1;
+                       }
+#endif
+               }
+       }
+#endif
+
+       if (p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+#endif /* __APPLE__ */
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+/*ARGSUSED*/
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+       int so;
+       u_int type, satype, mode;
+       struct sockaddr *src, *dst;
+       u_int32_t spi;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_sa)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(dst));
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0,
+           getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+#ifdef __APPLE__
+       p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0, 0);
+#else
+       p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+#endif
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
+           IPSEC_ULPROTO_ANY);
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+       int so;
+       u_int type, satype;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       caddr_t ep;
+
+       /* validity check */
+       switch (type) {
+       case SADB_X_PROMISC:
+               if (satype != 0 && satype != 1) {
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+               break;
+       default:
+               switch (satype) {
+               case SADB_SATYPE_UNSPEC:
+               case SADB_SATYPE_AH:
+               case SADB_SATYPE_ESP:
+               case SADB_X_SATYPE_IPCOMP:
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+               case SADB_X_SATYPE_TCPSIGNATURE:
+#endif
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+       }
+
+       /* create new sadb_msg to send. */
+       len = sizeof(struct sadb_msg);
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0,
+           getpid());
+       if (!p || p != ep) {
+               free(newmsg);
+               return -1;
+       }
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/* sending SADB_X_SPDADD message to the kernel */
+static int
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+               ltime, vtime, policy, policylen, seq)
+       int so;
+       struct sockaddr *src, *dst;
+       u_int type, prefs, prefd, proto;
+       u_int64_t ltime, vtime;
+       char *policy;
+       int policylen;
+       u_int32_t seq;
+{
+       struct sadb_msg *newmsg;
+       int len;
+       caddr_t p;
+       int plen;
+       caddr_t ep;
+
+       /* validity check */
+       if (src == NULL || dst == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+       if (src->sa_family != dst->sa_family) {
+               __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+               return -1;
+       }
+
+       switch (src->sa_family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+               return -1;
+       }
+       if (prefs > plen || prefd > plen) {
+               __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+               return -1;
+       }
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_address)
+               + PFKEY_ALIGN8(sysdep_sa_len(src))
+               + sizeof(struct sadb_lifetime)
+               + policylen;
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
+           SADB_SATYPE_UNSPEC, seq, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+       p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+                       0, 0, (u_int)ltime, (u_int)vtime);
+       if (!p || p + policylen != ep) {
+               free(newmsg);
+               return -1;
+       }
+       memcpy(p, policy, (size_t)policylen);
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
+static int
+pfkey_send_x5(so, type, spid)
+       int so;
+       u_int type;
+       u_int32_t spid;
+{
+       struct sadb_msg *newmsg;
+       struct sadb_x_policy xpl;
+       int len;
+       caddr_t p;
+       caddr_t ep;
+
+       /* create new sadb_msg to reply. */
+       len = sizeof(struct sadb_msg)
+               + sizeof(xpl);
+
+       if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+       ep = ((caddr_t)(void *)newmsg) + len;
+
+       p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
+           SADB_SATYPE_UNSPEC, 0, getpid());
+       if (!p) {
+               free(newmsg);
+               return -1;
+       }
+
+       if (p + sizeof(xpl) != ep) {
+               free(newmsg);
+               return -1;
+       }
+       memset(&xpl, 0, sizeof(xpl));
+       xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl));
+       xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+       xpl.sadb_x_policy_id = spid;
+       memcpy(p, &xpl, sizeof(xpl));
+
+       /* send message */
+       len = pfkey_send(so, newmsg, len);
+       free(newmsg);
+
+       if (len < 0)
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ *     -1: fail.
+ *     others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+       int so;
+       int bufsiz = 0; /* Max allowed by default */
+       const unsigned long newbufk = 1536;
+       unsigned long oldmax;
+       size_t  oldmaxsize = sizeof(oldmax);
+       unsigned long newmax = newbufk * (1024 + 128);
+
+       if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+
+       /*
+        * This is a temporary workaround for KAME PR 154.
+        * Don't really care even if it fails.
+        */
+       if (sysctlbyname("kern.ipc.maxsockbuf", &oldmax, &oldmaxsize, &newmax, sizeof(newmax)) != 0)
+               bufsiz = 233016;        /* Max allowed by default */
+       else
+               bufsiz = newbufk * 1024;
+       
+       setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+       setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+       
+       if (bufsiz == newbufk * 1024)
+               sysctlbyname("kern.ipc.maxsockbuf", NULL, NULL, &oldmax, oldmaxsize);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ *      0: success.
+ *     -1: fail.
+ */
+void
+pfkey_close(so)
+       int so;
+{
+       (void)close(so);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ *     NULL    : error occured.
+ *     others  : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
+ */
+struct sadb_msg *
+pfkey_recv(so)
+       int so;
+{
+       struct sadb_msg buf, *newmsg;
+       int len, reallen;
+
+       while ((len = recv(so, (void *)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       if (len < sizeof(buf)) {
+               recv(so, (void *)&buf, sizeof(buf), 0);
+               __ipsec_errcode = EIPSEC_MAX;
+               return NULL;
+       }
+
+       /* read real message */
+       reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+       if ((newmsg = CALLOC((size_t)reallen, struct sadb_msg *)) == 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       while ((len = recv(so, (void *)newmsg, (socklen_t)reallen, 0)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               __ipsec_set_strerror(strerror(errno));
+               free(newmsg);
+               return NULL;
+       }
+
+       if (len != reallen) {
+               __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+               free(newmsg);
+               return NULL;
+       }
+
+       /* don't trust what the kernel says, validate! */
+       if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+               __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+               free(newmsg);
+               return NULL;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ *      others: success and return length sent.
+ *     -1     : fail.
+ */
+int
+pfkey_send(so, msg, len)
+       int so;
+       struct sadb_msg *msg;
+       int len;
+{
+       if ((len = send(so, (void *)msg, (socklen_t)len, 0)) < 0) {
+               __ipsec_set_strerror(strerror(errno));
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ *     mhp: pointer to the buffer initialized like below:
+ *             caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT:        -1: invalid.
+ *      0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
+ */
+int
+pfkey_align(msg, mhp)
+       struct sadb_msg *msg;
+       caddr_t *mhp;
+{
+       struct sadb_ext *ext;
+       int i;
+       caddr_t p;
+       caddr_t ep;     /* XXX should be passed from upper layer */
+
+       /* validity check */
+       if (msg == NULL || mhp == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       /* initialize */
+       for (i = 0; i < SADB_EXT_MAX + 1; i++)
+               mhp[i] = NULL;
+
+       mhp[0] = (void *)msg;
+
+       /* initialize */
+       p = (void *) msg;
+       ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+       /* skip base header */
+       p += sizeof(struct sadb_msg);
+
+       while (p < ep) {
+               ext = (void *)p;
+               if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+                   ep < p + PFKEY_EXTLEN(ext)) {
+                       /* invalid format */
+                       break;
+               }
+
+               /* duplicate check */
+               /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+               if (mhp[ext->sadb_ext_type] != NULL) {
+                       __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+                       return -1;
+               }
+
+               /* 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:
+                       /* XXX should to be check weak keys. */
+               case SADB_EXT_KEY_ENCRYPT:
+                       /* XXX should to be check 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:
+               case SADB_X_EXT_SA2:
+#ifdef SADB_X_EXT_NAT_T_TYPE
+               case SADB_X_EXT_NAT_T_TYPE:
+               case SADB_X_EXT_NAT_T_SPORT:
+               case SADB_X_EXT_NAT_T_DPORT:
+               case SADB_X_EXT_NAT_T_OA:
+#endif
+#ifdef SADB_X_EXT_TAG
+               case SADB_X_EXT_TAG:
+#endif
+#ifdef SADB_X_EXT_PACKET
+               case SADB_X_EXT_PACKET:
+#endif
+
+                       mhp[ext->sadb_ext_type] = (void *)ext;
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+                       return -1;
+               }
+
+               p += PFKEY_EXTLEN(ext);
+       }
+
+       if (p != ep) {
+               __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+               return -1;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ *     mhp: pointer to the buffer initialized like below:
+ *
+ *             caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT:        -1: invalid.
+ *      0: valid.
+ */
+int
+pfkey_check(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+
+       /* validity check */
+       if (mhp == NULL || mhp[0] == NULL) {
+               __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return -1;
+       }
+
+       msg = (void *)mhp[0];
+
+       /* check version */
+       if (msg->sadb_msg_version != PF_KEY_V2) {
+               __ipsec_errcode = EIPSEC_INVAL_VERSION;
+               return -1;
+       }
+
+       /* check type */
+       if (msg->sadb_msg_type > SADB_MAX) {
+               __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+               return -1;
+       }
+
+       /* 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:
+#ifdef SADB_X_NAT_T_NEW_MAPPING
+               case SADB_X_NAT_T_NEW_MAPPING:
+#endif
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+               break;
+       case SADB_SATYPE_ESP:
+       case SADB_SATYPE_AH:
+       case SADB_X_SATYPE_IPCOMP:
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+       case SADB_X_SATYPE_TCPSIGNATURE:
+#endif
+               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:
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+#ifdef SADB_X_NAT_T_NEW_MAPPING
+               if (msg->sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING &&
+                   msg->sadb_msg_satype != SADB_SATYPE_ESP) {
+                       __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+                       return -1;
+               }
+#endif
+               break;
+       case SADB_SATYPE_RSVP:
+       case SADB_SATYPE_OSPFV2:
+       case SADB_SATYPE_RIPV2:
+       case SADB_SATYPE_MIP:
+               __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+               return -1;
+       case 1: /* XXX: What does it do ? */
+               if (msg->sadb_msg_type == SADB_X_PROMISC)
+                       break;
+               /*FALLTHROUGH*/
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+               return -1;
+       }
+
+       /* 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;
+
+               src0 = (void *)(mhp[SADB_EXT_ADDRESS_SRC]);
+               dst0 = (void *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+               if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+                       __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+                       return -1;
+               }
+
+               if (PFKEY_ADDR_SADDR(src0)->sa_family
+                != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+                       __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+                       return -1;
+               }
+
+               switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+               case AF_INET:
+               case AF_INET6:
+                       break;
+               default:
+                       __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+                       return -1;
+               }
+
+               /*
+                * prefixlen == 0 is valid because there must be the case
+                * all addresses are matched.
+                */
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type, satype;
+       u_int tlen;
+       u_int32_t seq;
+       pid_t pid;
+{
+       struct sadb_msg *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_msg);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, 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_reserved = 0;
+       p->sadb_msg_seq = seq;
+       p->sadb_msg_pid = (u_int32_t)pid;
+
+       return(buf + len);
+}
+
+#ifdef __APPLE__
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags, port)
+       caddr_t buf;
+       caddr_t lim;
+       u_int32_t spi, flags;
+       u_int wsize, auth, enc;
+       u_int16_t port;
+{
+       struct sadb_sa_2 *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_sa_2);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sa.sadb_sa_len = PFKEY_UNIT64(len);
+       p->sa.sadb_sa_exttype = SADB_EXT_SA;
+       p->sa.sadb_sa_spi = spi;
+       p->sa.sadb_sa_replay = wsize;
+       p->sa.sadb_sa_state = SADB_SASTATE_LARVAL;
+       p->sa.sadb_sa_auth = auth;
+       p->sa.sadb_sa_encrypt = enc;
+       p->sa.sadb_sa_flags = flags;
+       p->sadb_sa_natt_port = port;
+
+       return(buf + len);
+}
+#else
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
+       caddr_t buf;
+       caddr_t lim;
+       u_int32_t spi, flags;
+       u_int wsize, auth, enc;
+{
+       struct sadb_sa *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_sa);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_sa_len = PFKEY_UNIT64(len);
+       p->sadb_sa_exttype = SADB_EXT_SA;
+       p->sadb_sa_spi = spi;
+       p->sadb_sa_replay = wsize;
+       p->sadb_sa_state = SADB_SASTATE_LARVAL;
+       p->sadb_sa_auth = auth;
+       p->sadb_sa_encrypt = enc;
+       p->sadb_sa_flags = flags;
+       p->sadb_sa_natt_port = port;
+
+       return(buf + len);
+}
+#endif
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
+       caddr_t buf;
+       caddr_t lim;
+       u_int exttype;
+       struct sockaddr *saddr;
+       u_int prefixlen;
+       u_int ul_proto;
+{
+       struct sadb_address *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_address) + PFKEY_ALIGN8(sysdep_sa_len(saddr));
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_address_len = PFKEY_UNIT64(len);
+       p->sadb_address_exttype = exttype & 0xffff;
+       p->sadb_address_proto = ul_proto & 0xff;
+       p->sadb_address_prefixlen = prefixlen;
+       p->sadb_address_reserved = 0;
+
+       memcpy(p + 1, saddr, (size_t)sysdep_sa_len(saddr));
+
+       return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+       caddr_t buf;
+       caddr_t lim;
+       caddr_t key;
+       u_int type, keylen;
+{
+       struct sadb_key *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_key_len = PFKEY_UNIT64(len);
+       p->sadb_key_exttype = type;
+       p->sadb_key_bits = keylen << 3;
+       p->sadb_key_reserved = 0;
+
+       memcpy(p + 1, key, keylen);
+
+       return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type;
+       u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+       struct sadb_lifetime *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_lifetime);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_lifetime_len = PFKEY_UNIT64(len);
+       p->sadb_lifetime_exttype = type;
+
+       switch (type) {
+       case SADB_EXT_LIFETIME_SOFT:
+               p->sadb_lifetime_allocations
+                       = (l_alloc * soft_lifetime_allocations_rate) /100;
+               p->sadb_lifetime_bytes
+                       = (l_bytes * soft_lifetime_bytes_rate) /100;
+               p->sadb_lifetime_addtime
+                       = (l_addtime * soft_lifetime_addtime_rate) /100;
+               p->sadb_lifetime_usetime
+                       = (l_usetime * soft_lifetime_usetime_rate) /100;
+               break;
+       case SADB_EXT_LIFETIME_HARD:
+               p->sadb_lifetime_allocations = l_alloc;
+               p->sadb_lifetime_bytes = l_bytes;
+               p->sadb_lifetime_addtime = l_addtime;
+               p->sadb_lifetime_usetime = l_usetime;
+               break;
+       }
+
+       return buf + len;
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
+       caddr_t buf;
+       caddr_t lim;
+       u_int32_t mode0;
+       u_int32_t reqid;
+{
+       struct sadb_x_sa2 *p;
+       u_int8_t mode = mode0 & 0xff;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_x_sa2);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+       p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+       p->sadb_x_sa2_mode = mode;
+       p->sadb_x_sa2_reqid = reqid;
+
+       return(buf + len);
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static caddr_t
+pfkey_set_natt_type(buf, lim, type, l_natt_type)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type;
+       u_int8_t l_natt_type;
+{
+       struct sadb_x_nat_t_type *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_x_nat_t_type);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
+       p->sadb_x_nat_t_type_exttype = type;
+       p->sadb_x_nat_t_type_type = l_natt_type;
+
+       return(buf + len);
+}
+
+static caddr_t
+pfkey_set_natt_port(buf, lim, type, l_natt_port)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type;
+       u_int16_t l_natt_port;
+{
+       struct sadb_x_nat_t_port *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_x_nat_t_port);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
+       p->sadb_x_nat_t_port_exttype = type;
+       p->sadb_x_nat_t_port_port = htons(l_natt_port);
+
+       return(buf + len);
+}
+#endif
+
+#ifdef SADB_X_EXT_NAT_T_FRAG
+static caddr_t
+pfkey_set_natt_frag(buf, lim, type, l_natt_frag)
+       caddr_t buf;
+       caddr_t lim;
+       u_int type;
+       u_int16_t l_natt_frag;
+{
+       struct sadb_x_nat_t_frag *p;
+       u_int len;
+
+       p = (void *)buf;
+       len = sizeof(struct sadb_x_nat_t_frag);
+
+       if (buf + len > lim)
+               return NULL;
+
+       memset(p, 0, len);
+       p->sadb_x_nat_t_frag_len = PFKEY_UNIT64(len);
+       p->sadb_x_nat_t_frag_exttype = type;
+       p->sadb_x_nat_t_frag_fraglen = l_natt_frag;
+
+       return(buf + len);
+}
+#endif
diff --git a/ipsec-tools/Common/pfkey_dump.c b/ipsec-tools/Common/pfkey_dump.c
new file mode 100644 (file)
index 0000000..5c8cd26
--- /dev/null
@@ -0,0 +1,784 @@
+/*     $KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $     */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+/* cope with old kame headers - ugly */
+#ifndef SADB_X_AALG_MD5
+#define SADB_X_AALG_MD5                SADB_AALG_MD5   
+#endif
+#ifndef SADB_X_AALG_SHA
+#define SADB_X_AALG_SHA                SADB_AALG_SHA
+#endif
+#ifndef SADB_X_AALG_NULL
+#define SADB_X_AALG_NULL       SADB_AALG_NULL
+#endif
+
+#ifndef SADB_X_EALG_BLOWFISHCBC
+#define SADB_X_EALG_BLOWFISHCBC        SADB_EALG_BLOWFISHCBC
+#endif
+#ifndef SADB_X_EALG_CAST128CBC
+#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC
+#endif
+#ifndef SADB_X_EALG_RC5CBC
+#ifdef SADB_EALG_RC5CBC
+#define SADB_X_EALG_RC5CBC     SADB_EALG_RC5CBC
+#endif
+#endif
+
+#define GETMSGSTR(str, num) \
+do { \
+       /*CONSTCOND*/ \
+       if (sizeof((str)[0]) == 0 \
+        || num >= sizeof(str)/sizeof((str)[0])) \
+               printf("%u ", (num)); \
+       else if (strlen((str)[(num)]) == 0) \
+               printf("%u ", (num)); \
+       else \
+               printf("%s ", (str)[(num)]); \
+} while (/*CONSTCOND*/0)
+
+#define GETMSGV2S(v2s, num) \
+do { \
+       struct val2str *p;  \
+       for (p = (v2s); p && p->str; p++) { \
+               if (p->val == (num)) \
+                       break; \
+       } \
+       if (p && p->str) \
+               printf("%s ", p->str); \
+       else \
+               printf("%u ", (num)); \
+} while (/*CONSTCOND*/0)
+
+static char *str_ipaddr __P((struct sockaddr *));
+static char *str_ipport __P((struct sockaddr *));
+static char *str_prefport __P((u_int, u_int, u_int, u_int));
+static void str_upperspec __P((u_int, u_int, u_int));
+static char *str_time __P((time_t));
+static void str_lifetime_byte __P((struct sadb_lifetime *, char *));
+static void pfkey_sadump1(struct sadb_msg *, int);
+static void pfkey_spdump1(struct sadb_msg *, int);
+
+struct val2str {
+       int val;
+       const char *str;
+};
+
+/*
+ * Must to be re-written about following strings.
+ */
+static char *str_satype[] = {
+       "unspec",
+       "unknown",
+       "ah",
+       "esp",
+       "unknown",
+       "rsvp",
+       "ospfv2",
+       "ripv2",
+       "mip",
+       "ipcomp",
+       "policy",
+       "tcp",
+};
+
+static char *str_mode[] = {
+       "any",
+       "transport",
+       "tunnel",
+};
+
+static char *str_state[] = {
+       "larval",
+       "mature",
+       "dying",
+       "dead",
+};
+
+static struct val2str str_alg_auth[] = {
+       { SADB_AALG_NONE, "none", },
+       { SADB_AALG_MD5HMAC, "hmac-md5", },
+       { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+       { SADB_X_AALG_MD5, "md5", },
+       { SADB_X_AALG_SHA, "sha", },
+       { SADB_X_AALG_NULL, "null", },
+#ifdef SADB_X_AALG_TCP_MD5
+       { SADB_X_AALG_TCP_MD5, "tcp-md5", },
+#endif
+#ifdef SADB_X_AALG_SHA2_256
+       { SADB_X_AALG_SHA2_256, "hmac-sha256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+       { SADB_X_AALG_SHA2_384, "hmac-sha384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+       { SADB_X_AALG_SHA2_512, "hmac-sha512", },
+#endif
+#ifdef SADB_X_AALG_RIPEMD160HMAC
+       { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", },
+#endif
+#ifdef SADB_X_AALG_AES_XCBC_MAC
+       { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", },
+#endif
+       { -1, NULL, },
+};
+
+static struct val2str str_alg_enc[] = {
+       { SADB_EALG_NONE, "none", },
+       { SADB_EALG_DESCBC, "des-cbc", },
+       { SADB_EALG_3DESCBC, "3des-cbc", },
+       { SADB_EALG_NULL, "null", },
+#ifdef SADB_X_EALG_RC5CBC
+       { SADB_X_EALG_RC5CBC, "rc5-cbc", },
+#endif
+       { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+       { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_AESCBC
+       { SADB_X_EALG_AESCBC, "aes-cbc", },
+#endif
+#ifdef SADB_X_EALG_TWOFISHCBC
+       { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", },
+#endif
+#ifdef SADB_X_EALG_AESCTR
+       { SADB_X_EALG_AESCTR, "aes-ctr", },
+#endif
+       { -1, NULL, },
+};
+
+static struct val2str str_alg_comp[] = {
+       { SADB_X_CALG_NONE, "none", },
+       { SADB_X_CALG_OUI, "oui", },
+       { SADB_X_CALG_DEFLATE, "deflate", },
+       { SADB_X_CALG_LZS, "lzs", },
+       { -1, NULL, },
+};
+
+/*
+ * dump SADB_MSG formated.  For debugging, you should use kdebug_sadb().
+ */
+
+void
+pfkey_sadump(m)
+       struct sadb_msg *m;
+{
+       pfkey_sadump1(m, 0);
+}
+
+void
+pfkey_sadump_withports(m)
+       struct sadb_msg *m;
+{
+       pfkey_sadump1(m, 1);
+}
+
+void
+pfkey_sadump1(m, withports)
+       struct sadb_msg *m;
+       int withports;
+{
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       struct sadb_sa *m_sa;
+       struct sadb_x_sa2 *m_sa2;
+       struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts;
+       struct sadb_address *m_saddr, *m_daddr;
+#ifdef notdef
+       struct sadb_address *m_paddr;
+#endif
+       struct sadb_key *m_auth, *m_enc;
+#ifdef notdef
+       struct sadb_ident *m_sid, *m_did;
+       struct sadb_sens *m_sens;
+#endif
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       struct sadb_x_nat_t_type *natt_type;
+       struct sadb_x_nat_t_port *natt_sport, *natt_dport;
+       struct sadb_address *natt_oa;
+
+       int use_natt = 0;
+#endif
+       struct sockaddr *sa;
+
+       /* check pfkey message. */
+       if (pfkey_align(m, mhp)) {
+               printf("%s\n", ipsec_strerror());
+               return;
+       }
+       if (pfkey_check(mhp)) {
+               printf("%s\n", ipsec_strerror());
+               return;
+       }
+
+       m_sa = (void *)mhp[SADB_EXT_SA];
+       m_sa2 = (void *)mhp[SADB_X_EXT_SA2];
+       m_lftc = (void *)mhp[SADB_EXT_LIFETIME_CURRENT];
+       m_lfth = (void *)mhp[SADB_EXT_LIFETIME_HARD];
+       m_lfts = (void *)mhp[SADB_EXT_LIFETIME_SOFT];
+       m_saddr = (void *)mhp[SADB_EXT_ADDRESS_SRC];
+       m_daddr = (void *)mhp[SADB_EXT_ADDRESS_DST];
+#ifdef notdef
+       m_paddr = (void *)mhp[SADB_EXT_ADDRESS_PROXY];
+#endif
+       m_auth = (void *)mhp[SADB_EXT_KEY_AUTH];
+       m_enc = (void *)mhp[SADB_EXT_KEY_ENCRYPT];
+#ifdef notdef
+       m_sid = (void *)mhp[SADB_EXT_IDENTITY_SRC];
+       m_did = (void *)mhp[SADB_EXT_IDENTITY_DST];
+       m_sens = (void *)mhp[SADB_EXT_SENSITIVITY];
+#endif
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       natt_type = (void *)mhp[SADB_X_EXT_NAT_T_TYPE];
+       natt_sport = (void *)mhp[SADB_X_EXT_NAT_T_SPORT];
+       natt_dport = (void *)mhp[SADB_X_EXT_NAT_T_DPORT];
+       natt_oa = (void *)mhp[SADB_X_EXT_NAT_T_OA];
+
+       if (natt_type && natt_type->sadb_x_nat_t_type_type)
+               use_natt = 1;
+#endif
+       /* source address */
+       if (m_saddr == NULL) {
+               printf("no ADDRESS_SRC extension.\n");
+               return;
+       }
+       sa = (void *)(m_saddr + 1);
+       if (withports)
+               printf("%s[%s]", str_ipaddr(sa), str_ipport(sa));
+       else
+               printf("%s", str_ipaddr(sa));
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       if (use_natt && natt_sport)
+               printf("[%u]", ntohs(natt_sport->sadb_x_nat_t_port_port));
+#endif
+       printf(" ");
+
+       /* destination address */
+       if (m_daddr == NULL) {
+               printf(" no ADDRESS_DST extension.\n");
+               return;
+       }
+       sa = (void *)(m_daddr + 1);
+       if (withports)
+               printf("%s[%s]", str_ipaddr(sa), str_ipport(sa));
+       else
+               printf("%s", str_ipaddr(sa));
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       if (use_natt && natt_dport)
+               printf("[%u]", ntohs(natt_dport->sadb_x_nat_t_port_port));
+#endif
+       printf(" ");
+
+       /* SA type */
+       if (m_sa == NULL) {
+               printf("no SA extension.\n");
+               return;
+       }
+       if (m_sa2 == NULL) {
+               printf("no SA2 extension.\n");
+               return;
+       }
+       printf("\n\t");
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       if (use_natt && m->sadb_msg_satype == SADB_SATYPE_ESP)
+               printf("esp-udp ");
+       else if (use_natt)
+               printf("natt+");
+
+       if (!use_natt || m->sadb_msg_satype != SADB_SATYPE_ESP)
+#endif
+       GETMSGSTR(str_satype, m->sadb_msg_satype);
+
+       printf("mode=");
+       GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode);
+
+       printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n",
+               (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+               (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+               (u_int32_t)m_sa2->sadb_x_sa2_reqid,
+               (u_int32_t)m_sa2->sadb_x_sa2_reqid);
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       /* other NAT-T information */
+       if (use_natt && natt_oa)
+               printf("\tNAT OA=%s\n",
+                      str_ipaddr((void *)(natt_oa + 1)));
+#endif
+
+       /* encryption key */
+       if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
+               printf("\tC: ");
+               GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt);
+       } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) {
+               if (m_enc != NULL) {
+                       printf("\tE: ");
+                       GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt);
+                       ipsec_hexdump((caddr_t)(void *)m_enc + sizeof(*m_enc),
+                                     m_enc->sadb_key_bits / 8);
+                       printf("\n");
+               }
+       }
+
+       /* authentication key */
+       if (m_auth != NULL) {
+               printf("\tA: ");
+               GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth);
+               ipsec_hexdump((caddr_t)(void *)m_auth + sizeof(*m_auth),
+                             m_auth->sadb_key_bits / 8);
+               printf("\n");
+       }
+
+       /* replay windoe size & flags */
+       printf("\tseq=0x%08x replay=%u flags=0x%08x ",
+               m_sa2->sadb_x_sa2_sequence,
+               m_sa->sadb_sa_replay,
+               m_sa->sadb_sa_flags);
+
+       /* state */
+       printf("state=");
+       GETMSGSTR(str_state, m_sa->sadb_sa_state);
+       printf("\n");
+
+       /* lifetime */
+       if (m_lftc != NULL) {
+               time_t tmp_time = time(0);
+
+               printf("\tcreated: %s",
+                       str_time((long)m_lftc->sadb_lifetime_addtime));
+               printf("\tcurrent: %s\n", str_time(tmp_time));
+               printf("\tdiff: %lu(s)",
+                       (u_long)(m_lftc->sadb_lifetime_addtime == 0 ?
+                       0 : (tmp_time - m_lftc->sadb_lifetime_addtime)));
+
+               printf("\thard: %lu(s)",
+                       (u_long)(m_lfth == NULL ?
+                       0 : m_lfth->sadb_lifetime_addtime));
+               printf("\tsoft: %lu(s)\n",
+                       (u_long)(m_lfts == NULL ?
+                       0 : m_lfts->sadb_lifetime_addtime));
+
+               printf("\tlast: %s",
+                       str_time((long)m_lftc->sadb_lifetime_usetime));
+               printf("\thard: %lu(s)",
+                       (u_long)(m_lfth == NULL ?
+                       0 : m_lfth->sadb_lifetime_usetime));
+               printf("\tsoft: %lu(s)\n",
+                       (u_long)(m_lfts == NULL ?
+                       0 : m_lfts->sadb_lifetime_usetime));
+
+               str_lifetime_byte(m_lftc, "current");
+               str_lifetime_byte(m_lfth, "hard");
+               str_lifetime_byte(m_lfts, "soft");
+               printf("\n");
+
+               printf("\tallocated: %lu",
+                       (unsigned long)m_lftc->sadb_lifetime_allocations);
+               printf("\thard: %lu",
+                       (u_long)(m_lfth == NULL ?
+                       0 : m_lfth->sadb_lifetime_allocations));
+               printf("\tsoft: %lu\n",
+                       (u_long)(m_lfts == NULL ?
+                       0 : m_lfts->sadb_lifetime_allocations));
+       }
+
+       printf("\tsadb_seq=%lu pid=%lu ",
+               (u_long)m->sadb_msg_seq,
+               (u_long)m->sadb_msg_pid);
+
+       /* XXX DEBUG */
+       printf("refcnt=%u\n", m->sadb_msg_reserved);
+
+       return;
+}
+
+void
+pfkey_spdump(m)
+       struct sadb_msg *m;
+{
+       pfkey_spdump1(m, 0);
+}
+
+void
+pfkey_spdump_withports(m)
+       struct sadb_msg *m;
+{
+       pfkey_spdump1(m, 1);
+}
+
+static void
+pfkey_spdump1(m, withports)
+       struct sadb_msg *m;
+       int withports;
+{
+       char pbuf[NI_MAXSERV];
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       struct sadb_address *m_saddr, *m_daddr;
+#ifdef SADB_X_EXT_TAG
+       struct sadb_x_tag *m_tag;
+#endif
+       struct sadb_x_policy *m_xpl;
+       struct sadb_lifetime *m_lftc = NULL, *m_lfth = NULL;
+       struct sockaddr *sa;
+       u_int16_t sport = 0, dport = 0;
+
+       /* check pfkey message. */
+       if (pfkey_align(m, mhp)) {
+               printf("%s\n", ipsec_strerror());
+               return;
+       }
+       if (pfkey_check(mhp)) {
+               printf("%s\n", ipsec_strerror());
+               return;
+       }
+
+       m_saddr = (void *)mhp[SADB_EXT_ADDRESS_SRC];
+       m_daddr = (void *)mhp[SADB_EXT_ADDRESS_DST];
+#ifdef SADB_X_EXT_TAG
+       m_tag = (void *)mhp[SADB_X_EXT_TAG];
+#endif
+       m_xpl = (void *)mhp[SADB_X_EXT_POLICY];
+       m_lftc = (void *)mhp[SADB_EXT_LIFETIME_CURRENT];
+       m_lfth = (void *)mhp[SADB_EXT_LIFETIME_HARD];
+
+#ifdef __linux__
+       /* *bsd indicates per-socket policies by omiting src and dst 
+        * extensions. Linux always includes them, but we can catch it
+        * by checkin for policy id.
+        */
+       if (m_xpl->sadb_x_policy_id % 8 >= 3) {
+               printf("(per-socket policy) ");
+       } else
+#endif
+       if (m_saddr && m_daddr) {
+               /* source address */
+               sa = (void *)(m_saddr + 1);
+               switch (sa->sa_family) {
+               case AF_INET:
+               case AF_INET6:
+                       if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL,
+                           0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0)
+                               sport = 0;      /*XXX*/
+                       else
+                               sport = atoi(pbuf);
+                       printf("%s%s ", str_ipaddr(sa),
+                               str_prefport((u_int)sa->sa_family,
+                                   (u_int)m_saddr->sadb_address_prefixlen, 
+                                   (u_int)sport,
+                                   (u_int)m_saddr->sadb_address_proto));
+                       break;
+               default:
+                       printf("unknown-af ");
+                       break;
+               }
+
+               /* destination address */
+               sa = (void *)(m_daddr + 1);
+               switch (sa->sa_family) {
+               case AF_INET:
+               case AF_INET6:
+                       if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL,
+                           0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0)
+                               dport = 0;      /*XXX*/
+                       else
+                               dport = atoi(pbuf);
+                       printf("%s%s ", str_ipaddr(sa),
+                               str_prefport((u_int)sa->sa_family,
+                                   (u_int)m_daddr->sadb_address_prefixlen, 
+                                   (u_int)dport,
+                                   (u_int)m_saddr->sadb_address_proto));
+                       break;
+               default:
+                       printf("unknown-af ");
+                       break;
+               }
+
+               /* upper layer protocol */
+               if (m_saddr->sadb_address_proto !=
+                   m_daddr->sadb_address_proto) {
+                       printf("upper layer protocol mismatched.\n");
+                       return;
+               }
+               str_upperspec((u_int)m_saddr->sadb_address_proto, (u_int)sport,
+                   (u_int)dport);
+       }
+#ifdef SADB_X_EXT_TAG
+       else if (m_tag)
+               printf("tagged \"%s\" ", m_tag->sadb_x_tag_name);
+#endif
+       else
+               printf("(no selector, probably per-socket policy) ");
+
+       /* policy */
+    {
+       char *d_xpl;
+
+       if (m_xpl == NULL) {
+               printf("no X_POLICY extension.\n");
+               return;
+       }
+       if (withports)
+               d_xpl = ipsec_dump_policy_withports(m_xpl, "\n\t");
+       else
+               d_xpl = ipsec_dump_policy((ipsec_policy_t)m_xpl, "\n\t");
+               
+       if (!d_xpl)
+               printf("\n\tPolicy:[%s]\n", ipsec_strerror());
+       else {
+               /* dump SPD */
+               printf("\n\t%s\n", d_xpl);
+               free(d_xpl);
+       }
+    }
+
+       /* lifetime */
+       if (m_lftc) {
+               printf("\tcreated: %s  ",
+                       str_time((long)m_lftc->sadb_lifetime_addtime));
+               printf("lastused: %s\n",
+                       str_time((long)m_lftc->sadb_lifetime_usetime));
+       }
+       if (m_lfth) {
+               printf("\tlifetime: %lu(s) ",
+                       (u_long)m_lfth->sadb_lifetime_addtime);
+               printf("validtime: %lu(s)\n",
+                       (u_long)m_lfth->sadb_lifetime_usetime);
+       }
+
+
+       printf("\tspid=%ld seq=%ld pid=%ld\n",
+               (u_long)m_xpl->sadb_x_policy_id,
+               (u_long)m->sadb_msg_seq,
+               (u_long)m->sadb_msg_pid);
+
+       /* XXX TEST */
+       printf("\trefcnt=%u\n", m->sadb_msg_reserved);
+
+       return;
+}
+
+/*
+ * set "ipaddress" to buffer.
+ */
+static char *
+str_ipaddr(sa)
+       struct sockaddr *sa;
+{
+       static char buf[NI_MAXHOST];
+       const int niflag = NI_NUMERICHOST;
+
+       if (sa == NULL)
+               return "";
+
+       if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), buf, sizeof(buf), 
+           NULL, 0, niflag) == 0)
+               return buf;
+       return NULL;
+}
+
+/*
+ * set "port" to buffer.
+ */
+static char *
+str_ipport(sa)
+       struct sockaddr *sa;
+{
+       static char buf[NI_MAXHOST];
+       const int niflag = NI_NUMERICSERV;
+
+       if (sa == NULL)
+               return "";
+
+       if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL, 0, 
+           buf, sizeof(buf), niflag) == 0)
+               return buf;
+       return NULL;
+}
+
+
+/*
+ * set "/prefix[port number]" to buffer.
+ */
+static char *
+str_prefport(family, pref, port, ulp)
+       u_int family, pref, port, ulp;
+{
+       static char buf[128];
+       char prefbuf[128];
+       char portbuf[128];
+       int plen;
+
+       switch (family) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               return "?";
+       }
+
+       if (pref == plen)
+               prefbuf[0] = '\0';
+       else
+               snprintf(prefbuf, sizeof(prefbuf), "/%u", pref);
+
+       if (ulp == IPPROTO_ICMPV6)
+               memset(portbuf, 0, sizeof(portbuf));
+       else {
+               if (port == IPSEC_PORT_ANY)
+                       snprintf(portbuf, sizeof(portbuf), "[%s]", "any");
+               else
+                       snprintf(portbuf, sizeof(portbuf), "[%u]", port);
+       }
+
+       snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf);
+
+       return buf;
+}
+
+static void
+str_upperspec(ulp, p1, p2)
+       u_int ulp, p1, p2;
+{
+       if (ulp == IPSEC_ULPROTO_ANY)
+               printf("any");
+       else if (ulp == IPPROTO_ICMPV6) {
+               printf("icmp6");
+               if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY))
+                       printf(" %u,%u", p1, p2);
+       } else {
+               struct protoent *ent;
+
+               switch (ulp) {
+               case IPPROTO_IPV4:
+                       printf("ip4");
+                       break;
+               default:
+                       ent = getprotobynumber((int)ulp);
+                       if (ent)
+                               printf("%s", ent->p_name);
+                       else
+                               printf("%u", ulp);
+
+                       endprotoent();
+                       break;
+               }
+       }
+}
+
+/*
+ * set "Mon Day Time Year" to buffer
+ */
+static char *
+str_time(t)
+       time_t t;
+{
+       static char buf[128];
+
+       if (t == 0) {
+               int i = 0;
+               for (;i < 20;) buf[i++] = ' ';
+       } else {
+               char *t0;
+               t0 = ctime(&t);
+               memcpy(buf, t0 + 4, 20);
+       }
+
+       buf[20] = '\0';
+
+       return(buf);
+}
+
+static void
+str_lifetime_byte(x, str)
+       struct sadb_lifetime *x;
+       char *str;
+{
+       double y;
+       char *unit;
+       int w;
+
+       if (x == NULL) {
+               printf("\t%s: 0(bytes)", str);
+               return;
+       }
+
+#if 0
+       if ((x->sadb_lifetime_bytes) / 1024 / 1024) {
+               y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024;
+               unit = "M";
+               w = 1;
+       } else if ((x->sadb_lifetime_bytes) / 1024) {
+               y = (x->sadb_lifetime_bytes) * 1.0 / 1024;
+               unit = "K";
+               w = 1;
+       } else {
+               y = (x->sadb_lifetime_bytes) * 1.0;
+               unit = "";
+               w = 0;
+       }
+#else
+       y = (x->sadb_lifetime_bytes) * 1.0;
+       unit = "";
+       w = 0;
+#endif
+       printf("\t%s: %.*f(%sbytes)", str, w, y, unit);
+}
diff --git a/ipsec-tools/libipsec/ipsec_dump_policy.3 b/ipsec-tools/libipsec/ipsec_dump_policy.3
new file mode 100644 (file)
index 0000000..fe6f5ad
--- /dev/null
@@ -0,0 +1 @@
+.so man3/ipsec_set_policy.3
diff --git a/ipsec-tools/libipsec/ipsec_dump_policy.c b/ipsec-tools/libipsec/ipsec_dump_policy.c
new file mode 100644 (file)
index 0000000..d69776b
--- /dev/null
@@ -0,0 +1,419 @@
+/* $Id: ipsec_dump_policy.c,v 1.7.4.2 2005/06/29 13:01:27 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+static const char *ipsp_dir_strs[] = {
+       "any", "in", "out", "fwd"
+};
+
+static const char *ipsp_policy_strs[] = {
+       "discard", "none", "ipsec", "entrust", "bypass", "generate",
+};
+
+static char *ipsec_dump_ipsecrequest __P((char *, size_t,
+       struct sadb_x_ipsecrequest *, size_t, int));
+static char *ipsec_dump_policy1 __P((void *, const char *, int));
+static int set_addresses __P((char *, size_t, struct sockaddr *,
+       struct sockaddr *, int));
+static char *set_address __P((char *, size_t, struct sockaddr *, int));
+
+/*
+ * policy is sadb_x_policy buffer.
+ * Must call free() later.
+ * When delimiter == NULL, alternatively ' '(space) is applied.
+ */
+char *
+ipsec_dump_policy(policy, delimiter)
+       ipsec_policy_t policy;
+       __ipsec_const char *delimiter;
+{
+       return ipsec_dump_policy1(policy, delimiter, 0);
+}
+
+char *
+ipsec_dump_policy_withports(policy, delimiter)
+       void *policy;
+       const char *delimiter;
+{
+       return ipsec_dump_policy1(policy, delimiter, 1);
+}
+
+static char *
+ipsec_dump_policy1(policy, delimiter, withports)
+       void *policy;
+       const char *delimiter;
+       int withports;
+{
+       struct sadb_x_policy *xpl = policy;
+       struct sadb_x_ipsecrequest *xisr;
+       size_t off, buflen;
+       char *buf;
+       char isrbuf[1024];
+       char *newbuf;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       int32_t priority_offset;
+       char *priority_str;
+       char operator;
+#endif
+
+       /* sanity check */
+       if (policy == NULL)
+               return NULL;
+       if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
+               __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+               return NULL;
+       }
+
+       /* set delimiter */
+       if (delimiter == NULL)
+               delimiter = " ";
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       if (xpl->sadb_x_policy_priority == 0)
+       {
+               priority_offset = 0;
+               priority_str = "";
+       }
+       /* find which constant the priority is closest to */
+       else if (xpl->sadb_x_policy_priority < 
+                (u_int32_t) (PRIORITY_DEFAULT / 4) * 3)
+       {
+               priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH;
+               priority_str = "prio high";
+       }
+       else if (xpl->sadb_x_policy_priority >= 
+                (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 &&
+                xpl->sadb_x_policy_priority < 
+                (u_int32_t) (PRIORITY_DEFAULT / 4) * 5)
+       {
+               priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT;
+               priority_str = "prio def";
+       }
+       else
+       {
+               priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW;
+               priority_str = "prio low";
+       }
+
+       /* fix sign to match the way it is input */
+       priority_offset *= -1;
+       if (priority_offset < 0)
+       {
+               operator = '-';
+               priority_offset *= -1;
+       }
+       else
+       {
+               operator = '+';
+       }
+#endif
+       
+       switch (xpl->sadb_x_policy_dir) {
+       case IPSEC_DIR_ANY:
+       case IPSEC_DIR_INBOUND:
+       case IPSEC_DIR_OUTBOUND:
+#ifdef HAVE_POLICY_FWD
+       case IPSEC_DIR_FWD:
+#endif
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_DIR;
+               return NULL;
+       }
+
+       switch (xpl->sadb_x_policy_type) {
+       case IPSEC_POLICY_DISCARD:
+       case IPSEC_POLICY_GENERATE:
+       case IPSEC_POLICY_NONE:
+       case IPSEC_POLICY_IPSEC:
+       case IPSEC_POLICY_BYPASS:
+       case IPSEC_POLICY_ENTRUST:
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_POLICY;
+               return NULL;
+       }
+
+       buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
+               + 1     /* space */
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+               + strlen(priority_str)
+               + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */
+               + ((strlen(priority_str) != 0) ? 1 : 0) /* space */
+#endif
+               + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
+               + 1;    /* NUL */
+
+       if ((buf = malloc(buflen)) == NULL) {
+               __ipsec_errcode = EIPSEC_NO_BUFS;
+               return NULL;
+       }
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       if (priority_offset != 0)
+       {
+               snprintf(buf, buflen, "%s %s %c %u %s", 
+               ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, 
+                       priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]);
+       }
+       else if (strlen (priority_str) != 0)
+       {
+               snprintf(buf, buflen, "%s %s %s", 
+               ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, 
+                       ipsp_policy_strs[xpl->sadb_x_policy_type]);
+       }
+       else
+       {
+               snprintf(buf, buflen, "%s %s", 
+               ipsp_dir_strs[xpl->sadb_x_policy_dir],
+                       ipsp_policy_strs[xpl->sadb_x_policy_type]);
+       }
+#else
+       snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
+           ipsp_policy_strs[xpl->sadb_x_policy_type]);
+#endif
+
+       if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
+               __ipsec_errcode = EIPSEC_NO_ERROR;
+               return buf;
+       }
+
+       /* count length of buffer for use */
+       off = sizeof(*xpl);
+       while (off < PFKEY_EXTLEN(xpl)) {
+               xisr = (void *)((caddr_t)(void *)xpl + off);
+               off += xisr->sadb_x_ipsecrequest_len;
+       }
+
+       /* validity check */
+       if (off != PFKEY_EXTLEN(xpl)) {
+               __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+               free(buf);
+               return NULL;
+       }
+
+       off = sizeof(*xpl);
+       while (off < PFKEY_EXTLEN(xpl)) {
+               int offset;
+               xisr = (void *)((caddr_t)(void *)xpl + off);
+
+               if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
+                   PFKEY_EXTLEN(xpl) - off, withports) == NULL) {
+                       free(buf);
+                       return NULL;
+               }
+
+               offset = strlen(buf);
+               buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1;
+               newbuf = (char *)realloc(buf, buflen);
+               if (newbuf == NULL) {
+                       __ipsec_errcode = EIPSEC_NO_BUFS;
+                       free(buf);
+                       return NULL;
+               }
+               buf = newbuf;
+               snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf);
+
+               off += xisr->sadb_x_ipsecrequest_len;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return buf;
+}
+
+static char *
+ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports)
+       char *buf;
+       size_t len;
+       struct sadb_x_ipsecrequest *xisr;
+       size_t bound;   /* boundary */
+       int withports;
+{
+       const char *proto, *mode, *level;
+       char abuf[NI_MAXHOST * 2 + 2];
+
+       if (xisr->sadb_x_ipsecrequest_len > bound) {
+               __ipsec_errcode = EIPSEC_INVAL_PROTO;
+               return NULL;
+       }
+
+       switch (xisr->sadb_x_ipsecrequest_proto) {
+       case IPPROTO_ESP:
+               proto = "esp";
+               break;
+       case IPPROTO_AH:
+               proto = "ah";
+               break;
+       case IPPROTO_IPCOMP:
+               proto = "ipcomp";
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_PROTO;
+               return NULL;
+       }
+
+       switch (xisr->sadb_x_ipsecrequest_mode) {
+       case IPSEC_MODE_ANY:
+               mode = "any";
+               break;
+       case IPSEC_MODE_TRANSPORT:
+               mode = "transport";
+               break;
+       case IPSEC_MODE_TUNNEL:
+               mode = "tunnel";
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_MODE;
+               return NULL;
+       }
+
+       abuf[0] = '\0';
+       if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+               struct sockaddr *sa1, *sa2;
+               caddr_t p;
+
+               p = (void *)(xisr + 1);
+               sa1 = (void *)p;
+               sa2 = (void *)(p + sysdep_sa_len(sa1));
+               if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) !=
+                   xisr->sadb_x_ipsecrequest_len) {
+                       __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+                       return NULL;
+               }
+               if (set_addresses(abuf, sizeof(abuf), 
+                   sa1, sa2, withports) != 0) {
+                       __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+                       return NULL;
+               }
+       }
+
+       switch (xisr->sadb_x_ipsecrequest_level) {
+       case IPSEC_LEVEL_DEFAULT:
+               level = "default";
+               break;
+       case IPSEC_LEVEL_USE:
+               level = "use";
+               break;
+       case IPSEC_LEVEL_REQUIRE:
+               level = "require";
+               break;
+       case IPSEC_LEVEL_UNIQUE:
+               level = "unique";
+               break;
+       default:
+               __ipsec_errcode = EIPSEC_INVAL_LEVEL;
+               return NULL;
+       }
+
+       if (xisr->sadb_x_ipsecrequest_reqid == 0)
+               snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
+       else {
+               int ch;
+
+               if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
+                       ch = '#';
+               else
+                       ch = ':';
+               snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level,
+                   ch, xisr->sadb_x_ipsecrequest_reqid);
+       }
+
+       return buf;
+}
+
+static int
+set_addresses(buf, len, sa1, sa2, withports)
+       char *buf;
+       size_t len;
+       struct sockaddr *sa1;
+       struct sockaddr *sa2;
+       int withports;
+{
+       char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
+
+       if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL ||
+           set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL)
+               return -1;
+       if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
+               return -1;
+       snprintf(buf, len, "%s-%s", tmp1, tmp2);
+       return 0;
+}
+
+static char *
+set_address(buf, len, sa, withports)
+       char *buf;
+       size_t len;
+       struct sockaddr *sa;
+       int withports;
+{
+       const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+       char host[NI_MAXHOST];
+       char serv[NI_MAXSERV];
+
+       if (len < 1)
+               return NULL;
+       buf[0] = '\0';
+       if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host), 
+           serv, sizeof(serv), niflags) != 0)
+               return NULL;
+
+       if (withports)
+               snprintf(buf, len, "%s[%s]", host, serv);
+       else
+               snprintf(buf, len, "%s", host);
+
+       return buf;
+}
diff --git a/ipsec-tools/libipsec/ipsec_get_policylen.3 b/ipsec-tools/libipsec/ipsec_get_policylen.3
new file mode 100644 (file)
index 0000000..fe6f5ad
--- /dev/null
@@ -0,0 +1 @@
+.so man3/ipsec_set_policy.3
diff --git a/ipsec-tools/libipsec/ipsec_get_policylen.c b/ipsec-tools/libipsec/ipsec_get_policylen.c
new file mode 100644 (file)
index 0000000..1dca6d2
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $     */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#ifdef __APPPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include "libpfkey.h"
+#include "ipsec_strerror.h"
+
+int
+ipsec_get_policylen(policy)
+       ipsec_policy_t policy;
+{
+       return policy ? PFKEY_EXTLEN(policy) : -1;
+}
diff --git a/ipsec-tools/libipsec/ipsec_set_policy.3 b/ipsec-tools/libipsec/ipsec_set_policy.3
new file mode 100644 (file)
index 0000000..6b278f9
--- /dev/null
@@ -0,0 +1,334 @@
+.\"    $KAME: ipsec_set_policy.3,v 1.16 2003/01/06 21:59:03 sumikawa Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+.\"
+.Dd May 5, 1998
+.Dt IPSEC_SET_POLICY 3
+.Os
+.Sh NAME
+.Nm ipsec_dump_policy ,
+.Nm ipsec_get_policylen ,
+.Nm ipsec_set_policy
+.Nd manipulate IPsec policy specification structure from human-readable policy string
+.\"
+.Sh LIBRARY
+.Lb libipsec
+.Sh SYNOPSIS
+.In netinet6/ipsec.h
+.Ft "char *"
+.Fo ipsec_dump_policy
+.Fa "caddr_t buf"
+.Fa "char *delim"
+.Fc
+.Ft int
+.Fo ipsec_get_policylen
+.Fa "caddr_t buf"
+.Fc
+.Ft "char *"
+.Fo ipsec_set_policy
+.Fa "char *policy"
+.Fa "int len"
+.Fc
+.Sh DESCRIPTION
+.Fn ipsec_set_policy
+generates an IPsec policy specification structure, namely
+.Li struct sadb_x_policy
+and/or
+.Li struct sadb_x_ipsecrequest
+from a human-readable policy specification.
+The policy specification must be given as a C string
+.Fa policy
+and its length
+.Fa len .
+.Fn ipsec_set_policy
+will return a buffer with the corresponding IPsec policy specification structure.
+The buffer is dynamically allocated, and must be
+.Xr free 3 Ap d
+by the caller.
+.Pp
+You can get the length of the generated buffer with
+.Fn ipsec_get_policylen
+(i.e. for calling
+.Xr setsockopt 2 ) .
+.Pp
+.Fn ipsec_dump_policy
+converts an IPsec policy structure into human-readable form.
+Therefore,
+.Fn ipsec_dump_policy
+can be regarded as the inverse function to
+.Fn ipsec_set_policy .
+.Fa buf
+points to an IPsec policy structure,
+.Li struct sadb_x_policy .
+.Fa delim
+is a delimiter string, which is usually a blank character.
+If you set
+.Fa delim
+to
+.Dv NULL ,
+a single whitespace is assumed.
+.Fn ipsec_dump_policy
+returns a pointer to a dynamically allocated string.
+It is the caller's responsibility to
+.Xr free 3
+it.
+.Pp
+.Fa policy
+is formatted as either of the following:
+.Bl -tag  -width "discard"
+.It Ar direction [priority specification] Li discard
+.Ar direction
+must be
+.Li in ,
+.Li out ,
+or
+.Li fwd .
+.Ar direction
+specifies in which direction the policy needs to be applied.
+The non-standard direction
+.Li fwd
+is substituted with
+.Li in
+on platforms which do not support forward policies.
+.Pp
+.Ar priority specification
+is used to control the placement of the policy within the SPD.
+The policy position is determined by
+a signed integer where higher priorities indicate the policy is placed
+closer to the beginning of the list and lower priorities indicate the
+policy is placed closer to the end of the list.
+Policies with equal
+priorities are added at the end of the group of such policies.
+.Pp
+Priority can only
+be specified when libipsec has been compiled against kernel headers that
+support policy priorities (Linux \*[Gt]= 2.6.6).
+It takes one of the following formats:
+.Bl -tag  -width "discard"
+.It Xo
+.Ar {priority,prio} offset
+.Xc
+.Ar offset
+is an integer in the range -2147483647..214783648.
+.It Xo
+.Ar {priority,prio} base {+,-} offset
+.Xc
+.Ar base
+is either
+.Li low (-1073741824) ,
+.Li def (0) ,
+or
+.Li high (1073741824) .
+.Pp
+.Ar offset
+is an unsigned integer.
+It can be up to 1073741824 for
+positive offsets, and up to 1073741823 for negative offsets.
+.El
+.Pp
+The interpretation of policy priority in these functions and the
+kernel DOES differ.
+The relationship between the two can be described as
+p(kernel) = 0x80000000 - p(func)
+.Pp
+With
+.Li discard
+policy, packets will be dropped if they match the policy.
+.It Ar direction [priority specification] Li entrust
+.Li entrust
+means to consult the SPD defined by
+.Xr setkey 8 .
+.It Ar direction [priority specification] Li bypass
+.Li bypass
+means to bypass the IPsec processing.
+.Pq the packet will be transmitted in clear .
+This is for privileged sockets.
+.It Xo
+.Ar direction
+.Bq Ar priority specification
+.Li ipsec
+.Ar request ...
+.Xc
+.Li ipsec
+means that the matching packets are subject to IPsec processing.
+.Li ipsec
+can be followed by one or more
+.Ar request
+strings, which are formatted as below:
+.Bl -tag  -width "discard"
+.It Xo
+.Ar protocol
+.Li /
+.Ar mode
+.Li /
+.Ar src
+.Li -
+.Ar dst
+.Op Ar /level
+.Xc
+.Ar protocol
+is either
+.Li ah ,
+.Li esp ,
+or
+.Li ipcomp .
+.Pp
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel .
+.Pp
+.Ar src
+and
+.Ar dst
+specifies the IPsec endpoint.
+.Ar src
+always means the
+.Dq sending node
+and
+.Ar dst
+always means the
+.Dq receiving node .
+Therefore, when
+.Ar direction
+is
+.Li in ,
+.Ar dst
+is this node
+and
+.Ar src
+is the other node
+.Pq peer .
+If
+.Ar mode
+is
+.Li transport ,
+Both
+.Ar src
+and
+.Ar dst
+can be omitted.
+.Pp
+.Ar level
+must be set to one of the following:
+.Li default , use , require ,
+or
+.Li unique .
+.Li default
+means that the kernel should consult the system default policy
+defined by
+.Xr sysctl 8 ,
+such as
+.Li net.inet.ipsec.esp_trans_deflev .
+See
+.Xr ipsec 4
+regarding the system default.
+.Li use
+means that a relevant SA can be used when available,
+since the kernel may perform IPsec operation against packets when possible.
+In this case, packets can be transmitted in clear
+.Pq when SA is not available ,
+or encrypted
+.Pq when SA is available .
+.Li require
+means that a relevant SA is required,
+since the kernel must perform IPsec operation against packets.
+.Li unique
+is the same as
+.Li require ,
+but adds the restriction that the SA for outbound traffic is used
+only for this policy.
+You may need the identifier in order to relate the policy and the SA
+when you define the SA by manual keying.
+You can put the decimal number as the identifier after
+.Li unique
+like
+.Li unique : number .
+.Li number
+must be between 1 and 32767 .
+If the
+.Ar request
+string is kept unambiguous,
+.Ar level
+and slash prior to
+.Ar level
+can be omitted.
+However, it is encouraged to specify them explicitly
+to avoid unintended behavior.
+If
+.Ar level
+is omitted, it will be interpreted as
+.Li default .
+.El
+.Pp
+Note that there are slight differences to the specification of
+.Xr setkey 8 .
+In the specification of
+.Xr setkey 8 ,
+both
+.Li entrust
+and
+.Li bypass
+are not used.
+Refer to
+.Xr setkey 8
+for details.
+.Pp
+Here are several examples
+.Pq long lines are wrapped for readability :
+.Bd -literal -offset indent
+in discard
+out ipsec esp/transport//require
+in ipsec ah/transport//require
+out ipsec esp/tunnel/10.1.1.2-10.1.1.1/use
+in ipsec ipcomp/transport//use
+        esp/transport//use
+.Ed
+.El
+.Sh RETURN VALUES
+.Fn ipsec_set_policy
+returns a pointer to the allocated buffer with the policy specification
+if successful; otherwise a
+.Dv NULL
+pointer is returned.
+.Fn ipsec_get_policylen
+returns a positive value
+.Pq meaning the buffer size
+on success, and a negative value on errors.
+.Fn ipsec_dump_policy
+returns a pointer to a dynamically allocated region on success,
+and
+.Dv NULL
+on errors.
+.Sh SEE ALSO
+.Xr ipsec_strerror 3 ,
+.Xr ipsec 4 ,
+.Xr setkey 8
+.Sh HISTORY
+The functions first appeared in the WIDE/KAME IPv6 protocol stack kit.
diff --git a/ipsec-tools/libipsec/ipsec_strerror.3 b/ipsec-tools/libipsec/ipsec_strerror.3
new file mode 100644 (file)
index 0000000..718eb50
--- /dev/null
@@ -0,0 +1,88 @@
+.\"    $KAME: ipsec_strerror.3,v 1.9 2001/08/17 07:21:36 itojun Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+.\"
+.Dd May 6, 1998
+.Dt IPSEC_STRERROR 3
+.Os
+.\"
+.Sh NAME
+.Nm ipsec_strerror
+.Nd error messages for the IPsec policy manipulation library
+.\"
+.Sh LIBRARY
+.Lb libipsec
+.Sh SYNOPSIS
+.In netinet6/ipsec.h
+.Ft "const char *"
+.Fo ipsec_strerror
+.Fa void
+.Fc
+.\"
+.Sh DESCRIPTION
+.Pa netinet6/ipsec.h
+declares
+.Pp
+.Dl extern int ipsec_errcode ;
+.Pp
+which is used to pass an error code from the IPsec policy manipulation
+library to a program.
+.Fn ipsec_strerror
+can be used to obtain the error message string for the error code.
+.Pp
+The array pointed to is not to be modified by the calling program.
+Since
+.Fn ipsec_strerror
+uses
+.Xr strerror 3
+as underlying function, calling
+.Xr strerror 3
+after
+.Fn ipsec_strerror
+will make the return value from
+.Fn ipsec_strerror
+invalid or overwritten.
+.\"
+.Sh RETURN VALUES
+.Fn ipsec_strerror
+always returns a pointer to a C string.
+The C string must not be overwritten by the calling program.
+.\"
+.Sh SEE ALSO
+.Xr ipsec_set_policy 3
+.\"
+.Sh HISTORY
+.Fn ipsec_strerror
+first appeared in the WIDE/KAME IPv6 protocol stack kit.
+.\"
+.Sh BUGS
+.Fn ipsec_strerror
+will return its result which may be overwritten by subsequent calls.
+.Pp
+.Va ipsec_errcode
+is not thread safe.
diff --git a/ipsec-tools/libipsec/ipsec_strerror.c b/ipsec-tools/libipsec/ipsec_strerror.c
new file mode 100644 (file)
index 0000000..e9fda58
--- /dev/null
@@ -0,0 +1,98 @@
+/*     $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <string.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include "ipsec_strerror.h"
+
+int __ipsec_errcode;
+
+static const char *ipsec_errlist[] = {
+"Success",                                     /*EIPSEC_NO_ERROR*/
+"Not supported",                               /*EIPSEC_NOT_SUPPORTED*/
+"Invalid argument",                            /*EIPSEC_INVAL_ARGUMENT*/
+"Invalid sadb message",                                /*EIPSEC_INVAL_SADBMSG*/
+"Invalid version",                             /*EIPSEC_INVAL_VERSION*/
+"Invalid security policy",                     /*EIPSEC_INVAL_POLICY*/
+"Invalid address specification",               /*EIPSEC_INVAL_ADDRESS*/
+"Invalid ipsec protocol",                      /*EIPSEC_INVAL_PROTO*/
+"Invalid ipsec mode",                          /*EIPSEC_INVAL_MODE*/
+"Invalid ipsec level",                         /*EIPSEC_INVAL_LEVEL*/
+"Invalid SA type",                             /*EIPSEC_INVAL_SATYPE*/
+"Invalid message type",                                /*EIPSEC_INVAL_MSGTYPE*/
+"Invalid extension type",                      /*EIPSEC_INVAL_EXTTYPE*/
+"Invalid algorithm type",                      /*EIPSEC_INVAL_ALGS*/
+"Invalid key length",                          /*EIPSEC_INVAL_KEYLEN*/
+"Invalid address family",                      /*EIPSEC_INVAL_FAMILY*/
+"Invalid prefix length",                       /*EIPSEC_INVAL_PREFIXLEN*/
+"Invalid direciton",                           /*EIPSEC_INVAL_DIR*/
+"SPI range violation",                         /*EIPSEC_INVAL_SPI*/
+"No protocol specified",                       /*EIPSEC_NO_PROTO*/
+"No algorithm specified",                      /*EIPSEC_NO_ALGS*/
+"No buffers available",                                /*EIPSEC_NO_BUFS*/
+"Must get supported algorithms list first",    /*EIPSEC_DO_GET_SUPP_LIST*/
+"Protocol mismatch",                           /*EIPSEC_PROTO_MISMATCH*/
+"Family mismatch",                             /*EIPSEC_FAMILY_MISMATCH*/
+"Too few arguments",                           /*EIPSEC_FEW_ARGUMENTS*/
+NULL,                                          /*EIPSEC_SYSTEM_ERROR*/
+"Priority offset not in valid range [-2147483647, 2147483648]",        /*EIPSEC_INVAL_PRIORITY_OFFSET*/
+"Priority offset from base not in valid range [0, 1073741823] for negative offsets and [0, 1073741824] for positive offsets", /* EIPSEC_INVAL_PRIORITY_OFFSET */
+"Policy priority not compiled in",     /*EIPSEC_PRIORITY_NOT_COMPILED*/
+"Unknown error",                               /*EIPSEC_MAX*/
+};
+
+const char *ipsec_strerror(void)
+{
+       if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX)
+               __ipsec_errcode = EIPSEC_MAX;
+
+       return ipsec_errlist[__ipsec_errcode];
+}
+
+void __ipsec_set_strerror(const char *str)
+{
+       __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+       ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str;
+
+       return;
+}
diff --git a/ipsec-tools/libipsec/ipsec_strerror.h b/ipsec-tools/libipsec/ipsec_strerror.h
new file mode 100644 (file)
index 0000000..7c8c6dd
--- /dev/null
@@ -0,0 +1,71 @@
+/* $Id: ipsec_strerror.h,v 1.4 2004/06/07 09:18:46 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifndef _IPSEC_STRERROR_H
+#define _IPSEC_STRERROR_H
+
+extern int __ipsec_errcode;
+extern void __ipsec_set_strerror __P((const char *));
+
+#define EIPSEC_NO_ERROR                0       /*success*/
+#define EIPSEC_NOT_SUPPORTED   1       /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT  2       /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG   3       /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION   4       /*invalid version*/
+#define EIPSEC_INVAL_POLICY    5       /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS   6       /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO     7       /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE      8       /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL     9       /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE    10      /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE   11      /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE   12      /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS      13      /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN    14      /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY    15      /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16      /*SPI range violation*/
+#define EIPSEC_INVAL_DIR       17      /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI       18      /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO                19      /*no protocol specified*/
+#define EIPSEC_NO_ALGS         20      /*No algorithm specified*/
+#define EIPSEC_NO_BUFS         21      /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST        22      /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH  23      /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24      /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS   25      /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR    26      /*system error*/
+#define EIPSEC_INVAL_PRIORITY_OFFSET   27      /*priority offset out of range*/
+#define EIPSEC_INVAL_PRIORITY_BASE_OFFSET      28      /* priority base offset too
+                                                   large */
+#define EIPSEC_PRIORITY_NOT_COMPILED   29      /*no priority support in libipsec*/
+#define EIPSEC_MAX             30      /*unknown error*/
+
+#endif /* _IPSEC_STRERROR_H */
diff --git a/ipsec-tools/libipsec/policy_parse.y b/ipsec-tools/libipsec/policy_parse.y
new file mode 100644 (file)
index 0000000..51fb115
--- /dev/null
@@ -0,0 +1,653 @@
+/*     $KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 itojun Exp $   */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+/*
+ * IN/OUT bound policy configuration take place such below:
+ *     in <priority> <policy>
+ *     out <priority> <policy>
+ *
+ * <priority> is one of the following:
+ * priority <signed int> where the integer is an offset from the default
+ *                       priority, where negative numbers indicate lower
+ *                       priority (towards end of list) and positive numbers 
+ *                       indicate higher priority (towards beginning of list)
+ *
+ * priority {low,def,high} {+,-} <unsigned int>  where low and high are
+ *                                               constants which are closer
+ *                                               to the end of the list and
+ *                                               beginning of the list,
+ *                                               respectively
+ *
+ * <policy> is one of following:
+ *     "discard", "none", "ipsec <requests>", "entrust", "bypass",
+ *
+ * The following requests are accepted as <requests>:
+ *
+ *     protocol/mode/src-dst/level
+ *     protocol/mode/src-dst           parsed as protocol/mode/src-dst/default
+ *     protocol/mode/src-dst/          parsed as protocol/mode/src-dst/default
+ *     protocol/transport              parsed as protocol/mode/any-any/default
+ *     protocol/transport//level       parsed as protocol/mode/any-any/level
+ *
+ * You can concatenate these requests with either ' '(single space) or '\n'.
+ */
+
+%{
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+
+#include <errno.h>
+
+#include "config.h"
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+#ifndef INT32_MAX
+#define INT32_MAX      (0xffffffff)
+#endif
+
+#ifndef INT32_MIN
+#define INT32_MIN      (-INT32_MAX-1)
+#endif
+
+#define ATOX(c) \
+  (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
+
+static u_int8_t *pbuf = NULL;          /* sadb_x_policy buffer */
+static int tlen = 0;                   /* total length of pbuf */
+static int offset = 0;                 /* offset of pbuf */
+static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
+static u_int32_t p_priority = 0;
+static long p_priority_offset = 0;
+static struct sockaddr *p_src = NULL;
+static struct sockaddr *p_dst = NULL;
+
+struct _val;
+extern void yyerror __P((char *msg));
+static struct sockaddr *parse_sockaddr __P((struct _val *addrbuf,
+    struct _val *portbuf));
+static int rule_check __P((void));
+static int init_x_policy __P((void));
+static int set_x_request __P((struct sockaddr *, struct sockaddr *));
+static int set_sockaddr __P((struct sockaddr *));
+static void policy_parse_request_init __P((void));
+static void *policy_parse __P((const char *, int));
+
+extern void __policy__strbuffer__init__ __P((const char *));
+extern void __policy__strbuffer__free__ __P((void));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+
+extern char *__libipsectext;   /*XXX*/
+
+%}
+
+%union {
+       u_int num;
+       u_int32_t num32;
+       struct _val {
+               int len;
+               char *buf;
+       } val;
+}
+
+%token DIR 
+%token PRIORITY PLUS
+%token <num32> PRIO_BASE 
+%token <val> PRIO_OFFSET 
+%token ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY IPADDRESS PORT
+%token ME ANY
+%token SLASH HYPHEN
+%type <num> DIR PRIORITY ACTION PROTOCOL MODE LEVEL
+%type <val> IPADDRESS LEVEL_SPECIFY PORT
+
+%%
+policy_spec
+       :       DIR ACTION
+               {
+                       p_dir = $1;
+                       p_type = $2;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+                       p_priority = PRIORITY_DEFAULT;
+#else
+                       p_priority = 0;
+#endif
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR PRIORITY PRIO_OFFSET ACTION
+               {
+                       char *offset_buf;
+
+                       p_dir = $1;
+                       p_type = $4;
+
+                       /* buffer big enough to hold a prepended negative sign */
+                       offset_buf = malloc($3.len + 2);
+                       if (offset_buf == NULL) 
+                       {
+                               __ipsec_errcode = EIPSEC_NO_BUFS;
+                               return -1;
+                       }
+
+                       /* positive input value means higher priority, therefore lower
+                          actual value so that is closer to the beginning of the list */
+                       snprintf (offset_buf, $3.len + 2, "-%s", $3.buf);
+
+                       errno = 0;
+                       p_priority_offset = atol(offset_buf);
+
+                       free(offset_buf);
+
+                       if (errno != 0 || p_priority_offset < INT32_MIN)
+                       {
+                               __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
+                               return -1;
+                       }
+
+                       p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR PRIORITY HYPHEN PRIO_OFFSET ACTION
+               {
+                       p_dir = $1;
+                       p_type = $5;
+
+                       errno = 0;
+                       p_priority_offset = atol($4.buf);
+
+                       if (errno != 0 || p_priority_offset > INT32_MAX)
+                       {
+                               __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
+                               return -1;
+                       }
+
+                       /* negative input value means lower priority, therefore higher
+                          actual value so that is closer to the end of the list */
+                       p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR PRIORITY PRIO_BASE ACTION
+               {
+                       p_dir = $1;
+                       p_type = $4;
+
+                       p_priority = $3;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION
+               {
+                       p_dir = $1;
+                       p_type = $6;
+
+                       errno = 0;
+                       p_priority_offset = atol($5.buf);
+
+                       if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX)
+                       {
+                               __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
+                               return -1;
+                       }
+
+                       /* adding value means higher priority, therefore lower
+                          actual value so that is closer to the beginning of the list */
+                       p_priority = $3 - (u_int32_t) p_priority_offset;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION
+               {
+                       p_dir = $1;
+                       p_type = $6;
+
+                       errno = 0;
+                       p_priority_offset = atol($5.buf);
+
+                       if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX)
+                       {
+                               __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
+                               return -1;
+                       }
+
+                       /* subtracting value means lower priority, therefore higher
+                          actual value so that is closer to the end of the list */
+                       p_priority = $3 + (u_int32_t) p_priority_offset;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+               rules
+       |       DIR
+               {
+                       p_dir = $1;
+                       p_type = 0;     /* ignored it by kernel */
+
+                       p_priority = 0;
+
+                       if (init_x_policy())
+                               return -1;
+               }
+       ;
+
+rules
+       :       /*NOTHING*/
+       |       rules rule {
+                       if (rule_check() < 0)
+                               return -1;
+
+                       if (set_x_request(p_src, p_dst) < 0)
+                               return -1;
+
+                       policy_parse_request_init();
+               }
+       ;
+
+rule
+       :       protocol SLASH mode SLASH addresses SLASH level
+       |       protocol SLASH mode SLASH addresses SLASH
+       |       protocol SLASH mode SLASH addresses
+       |       protocol SLASH mode SLASH
+       |       protocol SLASH mode SLASH SLASH level
+       |       protocol SLASH mode
+       |       protocol SLASH {
+                       __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+                       return -1;
+               }
+       |       protocol {
+                       __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+                       return -1;
+               }
+       ;
+
+protocol
+       :       PROTOCOL { p_protocol = $1; }
+       ;
+
+mode
+       :       MODE { p_mode = $1; }
+       ;
+
+level
+       :       LEVEL {
+                       p_level = $1;
+                       p_reqid = 0;
+               }
+       |       LEVEL_SPECIFY {
+                       p_level = IPSEC_LEVEL_UNIQUE;
+                       p_reqid = atol($1.buf); /* atol() is good. */
+               }
+       ;
+
+addresses
+       :       IPADDRESS {
+                       p_src = parse_sockaddr(&$1, NULL);
+                       if (p_src == NULL)
+                               return -1;
+               }
+               HYPHEN
+               IPADDRESS {
+                       p_dst = parse_sockaddr(&$4, NULL);
+                       if (p_dst == NULL)
+                               return -1;
+               }
+       |       IPADDRESS PORT {
+                       p_src = parse_sockaddr(&$1, &$2);
+                       if (p_src == NULL)
+                               return -1;
+               }
+               HYPHEN
+               IPADDRESS PORT {
+                       p_dst = parse_sockaddr(&$5, &$6);
+                       if (p_dst == NULL)
+                               return -1;
+               }
+       |       ME HYPHEN ANY {
+                       if (p_dir != IPSEC_DIR_OUTBOUND) {
+                               __ipsec_errcode = EIPSEC_INVAL_DIR;
+                               return -1;
+                       }
+               }
+       |       ANY HYPHEN ME {
+                       if (p_dir != IPSEC_DIR_INBOUND) {
+                               __ipsec_errcode = EIPSEC_INVAL_DIR;
+                               return -1;
+                       }
+               }
+               /*
+       |       ME HYPHEN ME
+               */
+       ;
+
+%%
+
+void
+yyerror(msg)
+       char *msg;
+{
+       fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
+               msg, __libipsectext);
+
+       return;
+}
+
+static struct sockaddr *
+parse_sockaddr(addrbuf, portbuf)
+       struct _val *addrbuf;
+       struct _val *portbuf;
+{
+       struct addrinfo hints, *res;
+       char *addr;
+       char *serv = NULL;
+       int error;
+       struct sockaddr *newaddr = NULL;
+
+       if ((addr = malloc(addrbuf->len + 1)) == NULL) {
+               yyerror("malloc failed");
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       if (portbuf && ((serv = malloc(portbuf->len + 1)) == NULL)) {
+               free(addr);
+               yyerror("malloc failed");
+               __ipsec_set_strerror(strerror(errno));
+               return NULL;
+       }
+
+       strncpy(addr, addrbuf->buf, addrbuf->len);
+       addr[addrbuf->len] = '\0';
+
+       if (portbuf) {
+               strncpy(serv, portbuf->buf, portbuf->len);
+               serv[portbuf->len] = '\0';
+       }
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_flags = AI_NUMERICHOST;
+       hints.ai_socktype = SOCK_DGRAM;
+       error = getaddrinfo(addr, serv, &hints, &res);
+       free(addr);
+       if (serv != NULL)
+               free(serv);
+       if (error != 0) {
+               yyerror("invalid IP address");
+               __ipsec_set_strerror(gai_strerror(error));
+               return NULL;
+       }
+
+       if (res->ai_addr == NULL) {
+               yyerror("invalid IP address");
+               __ipsec_set_strerror(gai_strerror(error));
+               return NULL;
+       }
+
+       newaddr = malloc(res->ai_addrlen);
+       if (newaddr == NULL) {
+               __ipsec_errcode = EIPSEC_NO_BUFS;
+               freeaddrinfo(res);
+               return NULL;
+       }
+       memcpy(newaddr, res->ai_addr, res->ai_addrlen);
+
+       freeaddrinfo(res);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return newaddr;
+}
+
+static int
+rule_check()
+{
+       if (p_type == IPSEC_POLICY_IPSEC) {
+               if (p_protocol == IPPROTO_IP) {
+                       __ipsec_errcode = EIPSEC_NO_PROTO;
+                       return -1;
+               }
+
+               if (p_mode != IPSEC_MODE_TRANSPORT
+                && p_mode != IPSEC_MODE_TUNNEL) {
+                       __ipsec_errcode = EIPSEC_INVAL_MODE;
+                       return -1;
+               }
+
+               if (p_src == NULL && p_dst == NULL) {
+                        if (p_mode != IPSEC_MODE_TRANSPORT) {
+                               __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+                               return -1;
+                       }
+               }
+               else if (p_src->sa_family != p_dst->sa_family) {
+                       __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+                       return -1;
+               }
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+static int
+init_x_policy()
+{
+       struct sadb_x_policy *p;
+
+       if (pbuf) {
+               free(pbuf);
+               tlen = 0;
+       }
+       pbuf = malloc(sizeof(struct sadb_x_policy));
+       if (pbuf == NULL) {
+               __ipsec_errcode = EIPSEC_NO_BUFS;
+               return -1;
+       }
+       tlen = sizeof(struct sadb_x_policy);
+
+       memset(pbuf, 0, tlen);
+       p = (struct sadb_x_policy *)pbuf;
+       p->sadb_x_policy_len = 0;       /* must update later */
+       p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+       p->sadb_x_policy_type = p_type;
+       p->sadb_x_policy_dir = p_dir;
+       p->sadb_x_policy_id = 0;
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       p->sadb_x_policy_priority = p_priority;
+#else
+    /* fail if given a priority and libipsec was not compiled with 
+          priority support */
+       if (p_priority != 0)
+       {
+               __ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED;
+               return -1;
+       }
+#endif
+
+       offset = tlen;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+static int
+set_x_request(src, dst)
+       struct sockaddr *src, *dst;
+{
+       struct sadb_x_ipsecrequest *p;
+       int reqlen;
+       u_int8_t *n;
+
+       reqlen = sizeof(*p)
+               + (src ? sysdep_sa_len(src) : 0)
+               + (dst ? sysdep_sa_len(dst) : 0);
+       tlen += reqlen;         /* increment to total length */
+
+       n = realloc(pbuf, tlen);
+       if (n == NULL) {
+               __ipsec_errcode = EIPSEC_NO_BUFS;
+               return -1;
+       }
+       pbuf = n;
+
+       p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
+       p->sadb_x_ipsecrequest_len = reqlen;
+       p->sadb_x_ipsecrequest_proto = p_protocol;
+       p->sadb_x_ipsecrequest_mode = p_mode;
+       p->sadb_x_ipsecrequest_level = p_level;
+       p->sadb_x_ipsecrequest_reqid = p_reqid;
+       offset += sizeof(*p);
+
+       if (set_sockaddr(src) || set_sockaddr(dst))
+               return -1;
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+static int
+set_sockaddr(addr)
+       struct sockaddr *addr;
+{
+       if (addr == NULL) {
+               __ipsec_errcode = EIPSEC_NO_ERROR;
+               return 0;
+       }
+
+       /* tlen has already incremented */
+
+       memcpy(&pbuf[offset], addr, sysdep_sa_len(addr));
+
+       offset += sysdep_sa_len(addr);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return 0;
+}
+
+static void
+policy_parse_request_init()
+{
+       p_protocol = IPPROTO_IP;
+       p_mode = IPSEC_MODE_ANY;
+       p_level = IPSEC_LEVEL_DEFAULT;
+       p_reqid = 0;
+       if (p_src != NULL) {
+               free(p_src);
+               p_src = NULL;
+       }
+       if (p_dst != NULL) {
+               free(p_dst);
+               p_dst = NULL;
+       }
+
+       return;
+}
+
+static void *
+policy_parse(msg, msglen)
+       const char *msg;
+       int msglen;
+{
+       int error;
+
+       pbuf = NULL;
+       tlen = 0;
+
+       /* initialize */
+       p_dir = IPSEC_DIR_INVALID;
+       p_type = IPSEC_POLICY_DISCARD;
+       policy_parse_request_init();
+       __policy__strbuffer__init__(msg);
+
+       error = yyparse();      /* it must be set errcode. */
+       __policy__strbuffer__free__();
+
+       if (error) {
+               if (pbuf != NULL)
+                       free(pbuf);
+               return NULL;
+       }
+
+       /* update total length */
+       ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+
+       return pbuf;
+}
+
+ipsec_policy_t
+ipsec_set_policy(msg, msglen)
+       __ipsec_const char *msg;
+       int msglen;
+{
+       caddr_t policy;
+
+       policy = policy_parse(msg, msglen);
+       if (policy == NULL) {
+               if (__ipsec_errcode == EIPSEC_NO_ERROR)
+                       __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+               return NULL;
+       }
+
+       __ipsec_errcode = EIPSEC_NO_ERROR;
+       return policy;
+}
diff --git a/ipsec-tools/libipsec/policy_token.l b/ipsec-tools/libipsec/policy_token.l
new file mode 100644 (file)
index 0000000..3351855
--- /dev/null
@@ -0,0 +1,198 @@
+/* $Id: policy_token.l,v 1.10.4.1 2005/05/07 14:30:38 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+%{
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "libpfkey.h"
+
+#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__linux__)
+#include "y.tab.h"
+#else
+#include "policy_parse.h"
+#endif
+#define yylval __libipseclval  /* XXX */
+
+int yylex __P((void));
+%}
+
+%option noyywrap
+%option nounput
+
+/* common section */
+nl             \n
+ws             [ \t]+
+digit          [0-9]
+hexdigit       [0-9A-Fa-f]
+special                [()+\|\?\*,]
+dot            \.
+comma          \,
+hyphen         \-
+colon          \:
+slash          \/
+bcl            \{
+ecl            \}
+blcl           \[
+elcl           \]
+percent                \%
+semi           \;
+plus   \+
+usec           {dot}{digit}{1,6}
+comment                \#.*
+ccomment       "/*"
+bracketstring  \<[^>]*\>
+quotedstring   \"[^"]*\"
+decstring      {digit}+
+hexpair                {hexdigit}{hexdigit}
+hexstring      0[xX]{hexdigit}+
+octetstring    {octet}({dot}{octet})+
+ipaddress      [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%[a-zA-Z0-9]+)?
+
+%%
+
+in             { yylval.num = IPSEC_DIR_INBOUND; return(DIR); }
+out            { yylval.num = IPSEC_DIR_OUTBOUND; return(DIR); }
+fwd            { 
+#ifdef HAVE_POLICY_FWD
+                 yylval.num = IPSEC_DIR_FWD; return(DIR); 
+#else
+                 yylval.num = IPSEC_DIR_INBOUND; return(DIR); 
+#endif
+               }
+
+priority       { return(PRIORITY); }
+prio   { return(PRIORITY); }
+low    { yylval.num32 = PRIORITY_LOW; return(PRIO_BASE); }
+def { yylval.num32 = PRIORITY_DEFAULT; return(PRIO_BASE); }
+high   { yylval.num32 = PRIORITY_HIGH; return(PRIO_BASE); }
+{plus} { return(PLUS); }
+{decstring}    {
+                       yylval.val.len = strlen(yytext);
+                       yylval.val.buf = yytext;
+                       return(PRIO_OFFSET);
+}
+
+discard                { yylval.num = IPSEC_POLICY_DISCARD; return(ACTION); }
+generate       { yylval.num = IPSEC_POLICY_GENERATE; return(ACTION); }
+none           { yylval.num = IPSEC_POLICY_NONE; return(ACTION); }
+ipsec          { yylval.num = IPSEC_POLICY_IPSEC; return(ACTION); }
+bypass         { yylval.num = IPSEC_POLICY_BYPASS; return(ACTION); }
+entrust                { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); }
+
+esp            { yylval.num = IPPROTO_ESP; return(PROTOCOL); }
+ah             { yylval.num = IPPROTO_AH; return(PROTOCOL); }
+ipcomp         { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); }
+
+transport      { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel         { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } 
+
+me             { return(ME); }
+any            { return(ANY); }
+
+default                { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); }
+use            { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); }
+require                { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); }
+unique{colon}{decstring} {
+                       yylval.val.len = strlen(yytext + 7);
+                       yylval.val.buf = yytext + 7;
+                       return(LEVEL_SPECIFY);
+               }
+unique         { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); }
+{slash}                { return(SLASH); }
+
+{ipaddress}    {
+                       yylval.val.len = strlen(yytext);
+                       yylval.val.buf = yytext;
+                       return(IPADDRESS);
+               }
+
+{hyphen}       { return(HYPHEN); }
+
+{blcl}{decstring}{elcl} {
+                       /* Remove leading '[' and trailing ']' */
+                       yylval.val.buf = yytext + 1;
+                       yylval.val.len = strlen(yytext) - 2;
+
+                       return(PORT);
+               }
+
+{ws}           { ; }
+{nl}           { ; }
+
+%%
+
+void __policy__strbuffer__init__ __P((char *));
+void __policy__strbuffer__free__ __P((void));
+
+static YY_BUFFER_STATE strbuffer;
+
+void
+__policy__strbuffer__init__(msg)
+       char *msg;
+{
+       if (YY_CURRENT_BUFFER)
+               yy_delete_buffer(YY_CURRENT_BUFFER);
+       strbuffer = (YY_BUFFER_STATE)yy_scan_string(msg);
+       yy_switch_to_buffer(strbuffer);
+
+       return;
+}
+
+void
+__policy__strbuffer__free__()
+{
+       yy_delete_buffer(strbuffer);
+
+       return;
+}
diff --git a/ipsec-tools/libipsec/test-policy.c b/ipsec-tools/libipsec/test-policy.c
new file mode 100644 (file)
index 0000000..c6bf4f2
--- /dev/null
@@ -0,0 +1,334 @@
+/*     $KAME: test-policy.c,v 1.16 2003/08/26 03:24:08 itojun Exp $    */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet6/ipsec.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+
+#include "libpfkey.h"
+
+struct req_t {
+       int result;     /* expected result; 0:ok 1:ng */
+       char *str;
+} reqs[] = {
+{ 0, "out ipsec" },
+{ 1, "must_error" },
+{ 1, "in ipsec must_error" },
+{ 1, "out ipsec esp/must_error" },
+{ 1, "out discard" },
+{ 1, "out none" },
+{ 0, "in entrust" },
+{ 0, "out entrust" },
+{ 1, "out ipsec esp" },
+{ 0, "in ipsec ah/transport" },
+{ 1, "in ipsec ah/tunnel" },
+{ 0, "out ipsec ah/transport/" },
+{ 1, "out ipsec ah/tunnel/" },
+{ 0, "in ipsec esp / transport / 10.0.0.1-10.0.0.2" },
+{ 0, "in ipsec esp/tunnel/::1-::2" },
+{ 1, "in ipsec esp/tunnel/10.0.0.1-::2" },
+{ 0, "in ipsec esp/tunnel/::1-::2/require" },
+{ 0, "out ipsec ah/transport//use" },
+{ 1, "out ipsec ah/transport esp/use" },
+{ 1, "in ipsec ah/transport esp/tunnel" },
+{ 0, "in ipsec ah/transport esp/tunnel/::1-::1" },
+{ 0, "in ipsec ah / transport esp / tunnel / ::1-::2" },
+{ 0, "out ipsec \
+        ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \
+        ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \
+        ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \
+       " },
+{ 0, "out ipsec esp/transport/fec0::10-fec0::11/use" },
+};
+
+int test1 __P((void));
+int test1sub1 __P((struct req_t *));
+int test1sub2 __P((char *, int));
+int test2 __P((void));
+int test2sub __P((int));
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       test1();
+       test2();
+
+       exit(0);
+}
+
+int
+test1()
+{
+       int i;
+       int result;
+
+       printf("TEST1\n");
+       for (i = 0; i < sizeof(reqs)/sizeof(reqs[0]); i++) {
+               printf("#%d [%s]\n", i + 1, reqs[i].str);
+
+               result = test1sub1(&reqs[i]);
+               if (result == 0 && reqs[i].result == 1) {
+                       warnx("ERROR: expecting failure.");
+               } else if (result == 1 && reqs[i].result == 0) {
+                       warnx("ERROR: expecting success.");
+               }
+       }
+
+       return 0;
+}
+
+int
+test1sub1(req)
+       struct req_t *req;
+{
+       char *buf;
+
+       buf = ipsec_set_policy(req->str, strlen(req->str));
+       if (buf == NULL) {
+               printf("ipsec_set_policy: %s\n", ipsec_strerror());
+               return 1;
+       }
+
+       if (test1sub2(buf, PF_INET) != 0
+        || test1sub2(buf, PF_INET6) != 0) {
+               free(buf);
+               return 1;
+       }
+#if 0
+       kdebug_sadb_x_policy((struct sadb_ext *)buf);
+#endif
+
+       free(buf);
+       return 0;
+}
+
+int
+test1sub2(policy, family)
+       char *policy;
+       int family;
+{
+       int so;
+       int proto = 0, optname = 0;
+       int len;
+       char getbuf[1024];
+
+       switch (family) {
+       case PF_INET:
+               proto = IPPROTO_IP;
+               optname = IP_IPSEC_POLICY;
+               break;
+       case PF_INET6:
+               proto = IPPROTO_IPV6;
+               optname = IPV6_IPSEC_POLICY;
+               break;
+       }
+
+       if ((so = socket(family, SOCK_DGRAM, 0)) < 0)
+               err(1, "socket");
+
+       len = ipsec_get_policylen(policy);
+#if 0
+       printf("\tsetlen:%d\n", len);
+#endif
+
+       if (setsockopt(so, proto, optname, policy, len) < 0) {
+               printf("fail to set sockopt; %s\n", strerror(errno));
+               close(so);
+               return 1;
+       }
+
+       memset(getbuf, 0, sizeof(getbuf));
+       memcpy(getbuf, policy, sizeof(struct sadb_x_policy));
+       if (getsockopt(so, proto, optname, getbuf, &len) < 0) {
+               printf("fail to get sockopt; %s\n", strerror(errno));
+               close(so);
+               return 1;
+       }
+
+    {
+       char *buf = NULL;
+
+#if 0
+       printf("\tgetlen:%d\n", len);
+#endif
+
+       if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) {
+               printf("%s\n", ipsec_strerror());
+               close(so);
+               return 1;
+       }
+#if 0
+       printf("\t[%s]\n", buf);
+#endif
+       free(buf);
+    }
+
+       close (so);
+       return 0;
+}
+
+char addr[] = {
+       28, 28, 0, 0,
+       0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+       0, 0, 0, 0,
+};
+
+int
+test2()
+{
+       int so;
+       char *pol1 = "out ipsec";
+       char *pol2 = "out ipsec ah/transport//use";
+       char *sp1, *sp2;
+       int splen1, splen2;
+       int spid;
+       struct sadb_msg *m;
+
+       printf("TEST2\n");
+       if (getuid() != 0)
+               errx(1, "root privilege required.");
+
+       sp1 = ipsec_set_policy(pol1, strlen(pol1));
+       splen1 = ipsec_get_policylen(sp1);
+       sp2 = ipsec_set_policy(pol2, strlen(pol2));
+       splen2 = ipsec_get_policylen(sp2);
+
+       if ((so = pfkey_open()) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+
+       printf("spdflush()\n");
+       if (pfkey_send_spdflush(so) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+
+       printf("spdsetidx()\n");
+       if (pfkey_send_spdsetidx(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, sp1, splen1, 0) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+       
+       printf("spdupdate()\n");
+       if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, sp2, splen2, 0) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+
+       printf("sleep(4)\n");
+       sleep(4);
+
+       printf("spddelete()\n");
+       if (pfkey_send_spddelete(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, sp1, splen1, 0) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+
+       printf("spdadd()\n");
+       if (pfkey_send_spdadd(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, sp2, splen2, 0) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       spid = test2sub(so);
+
+       printf("spdget(%u)\n", spid);
+       if (pfkey_send_spdget(so, spid) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+
+       printf("sleep(4)\n");
+       sleep(4);
+
+       printf("spddelete2()\n");
+       if (pfkey_send_spddelete2(so, spid) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       m = pfkey_recv(so);
+       free(m);
+
+       printf("spdadd() with lifetime's 10(s)\n");
+       if (pfkey_send_spdadd2(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, 0, 10, sp2, splen2, 0) < 0)
+               errx(1, "ERROR: %s", ipsec_strerror());
+       spid = test2sub(so);
+
+       /* expecting failure */
+       printf("spdupdate()\n");
+       if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128,
+                               (struct sockaddr *)addr, 128,
+                               255, sp2, splen2, 0) == 0) {
+               warnx("ERROR: expecting failure.");
+       }
+
+       return 0;
+}
+
+int
+test2sub(so)
+       int so;
+{
+       struct sadb_msg *msg;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+
+       if ((msg = pfkey_recv(so)) == NULL)
+               errx(1, "ERROR: pfkey_recv failure.");
+       if (pfkey_align(msg, mhp) < 0)
+               errx(1, "ERROR: pfkey_align failure.");
+
+       return ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id;
+}
+
diff --git a/ipsec-tools/racoon/Crypto/boxes-fst.dat b/ipsec-tools/racoon/Crypto/boxes-fst.dat
new file mode 100644 (file)
index 0000000..50e6cb3
--- /dev/null
@@ -0,0 +1,957 @@
+/*     $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $     */
+
+const word8 S[256] = {
+ 99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 118, 
+202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 
+183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 216,  49,  21, 
+  4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 235,  39, 178, 117, 
+  9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 179,  41, 227,  47, 132, 
+ 83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 190,  57,  74,  76,  88, 207, 
+208, 239, 170, 251,  67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 159, 168, 
+ 81, 163,  64, 143, 146, 157,  56, 245, 188, 182, 218,  33,  16, 255, 243, 210, 
+205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 126,  61, 100,  93,  25, 115, 
+ 96, 129,  79, 220,  34,  42, 144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 
+224,  50,  58,  10,  73,   6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 
+231, 200,  55, 109, 141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 
+186, 120,  37,  46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 
+112,  62, 181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 
+225, 248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223, 
+140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  22
+};
+
+#ifdef INTERMEDIATE_VALUE_KAT
+static const word8 Si[256] = {
+ 82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 251, 
+124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 233, 203, 
+ 84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 250, 195,  78, 
+  8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 109, 139, 209,  37, 
+114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 204,  93, 101, 182, 146, 
+108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  70,  87, 167, 141, 157, 132, 
+144, 216, 171,   0, 140, 188, 211,  10, 247, 228,  88,   5, 184, 179,  69,   6, 
+208,  44,  30, 143, 202,  63,  15,   2, 193, 175, 189,   3,   1,  19, 138, 107, 
+ 58, 145,  17,  65,  79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 
+150, 172, 116,  34, 231, 173,  53, 133, 226, 249,  55, 232,  28, 117, 223, 110, 
+ 71, 241,  26, 113,  29,  41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 
+252,  86,  62,  75, 198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244, 
+ 31, 221, 168,  51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95, 
+ 96,  81, 127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 
+160, 224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97, 
+ 23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12, 125
+};
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+union xtab {
+       word32  xt32[256];
+       word8   xt8[256][4];
+};
+
+static const union xtab xT1 = {
+       .xt8 = {
+{0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d},
+{0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54},
+{0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d},
+{0xe7,0xfe,0xfe,0x19}, {0xb5,0xd7,0xd7,0x62}, {0x4d,0xab,0xab,0xe6}, {0xec,0x76,0x76,0x9a},
+{0x8f,0xca,0xca,0x45}, {0x1f,0x82,0x82,0x9d}, {0x89,0xc9,0xc9,0x40}, {0xfa,0x7d,0x7d,0x87},
+{0xef,0xfa,0xfa,0x15}, {0xb2,0x59,0x59,0xeb}, {0x8e,0x47,0x47,0xc9}, {0xfb,0xf0,0xf0,0x0b},
+{0x41,0xad,0xad,0xec}, {0xb3,0xd4,0xd4,0x67}, {0x5f,0xa2,0xa2,0xfd}, {0x45,0xaf,0xaf,0xea},
+{0x23,0x9c,0x9c,0xbf}, {0x53,0xa4,0xa4,0xf7}, {0xe4,0x72,0x72,0x96}, {0x9b,0xc0,0xc0,0x5b},
+{0x75,0xb7,0xb7,0xc2}, {0xe1,0xfd,0xfd,0x1c}, {0x3d,0x93,0x93,0xae}, {0x4c,0x26,0x26,0x6a},
+{0x6c,0x36,0x36,0x5a}, {0x7e,0x3f,0x3f,0x41}, {0xf5,0xf7,0xf7,0x02}, {0x83,0xcc,0xcc,0x4f},
+{0x68,0x34,0x34,0x5c}, {0x51,0xa5,0xa5,0xf4}, {0xd1,0xe5,0xe5,0x34}, {0xf9,0xf1,0xf1,0x08},
+{0xe2,0x71,0x71,0x93}, {0xab,0xd8,0xd8,0x73}, {0x62,0x31,0x31,0x53}, {0x2a,0x15,0x15,0x3f},
+{0x08,0x04,0x04,0x0c}, {0x95,0xc7,0xc7,0x52}, {0x46,0x23,0x23,0x65}, {0x9d,0xc3,0xc3,0x5e},
+{0x30,0x18,0x18,0x28}, {0x37,0x96,0x96,0xa1}, {0x0a,0x05,0x05,0x0f}, {0x2f,0x9a,0x9a,0xb5},
+{0x0e,0x07,0x07,0x09}, {0x24,0x12,0x12,0x36}, {0x1b,0x80,0x80,0x9b}, {0xdf,0xe2,0xe2,0x3d},
+{0xcd,0xeb,0xeb,0x26}, {0x4e,0x27,0x27,0x69}, {0x7f,0xb2,0xb2,0xcd}, {0xea,0x75,0x75,0x9f},
+{0x12,0x09,0x09,0x1b}, {0x1d,0x83,0x83,0x9e}, {0x58,0x2c,0x2c,0x74}, {0x34,0x1a,0x1a,0x2e},
+{0x36,0x1b,0x1b,0x2d}, {0xdc,0x6e,0x6e,0xb2}, {0xb4,0x5a,0x5a,0xee}, {0x5b,0xa0,0xa0,0xfb},
+{0xa4,0x52,0x52,0xf6}, {0x76,0x3b,0x3b,0x4d}, {0xb7,0xd6,0xd6,0x61}, {0x7d,0xb3,0xb3,0xce},
+{0x52,0x29,0x29,0x7b}, {0xdd,0xe3,0xe3,0x3e}, {0x5e,0x2f,0x2f,0x71}, {0x13,0x84,0x84,0x97},
+{0xa6,0x53,0x53,0xf5}, {0xb9,0xd1,0xd1,0x68}, {0x00,0x00,0x00,0x00}, {0xc1,0xed,0xed,0x2c},
+{0x40,0x20,0x20,0x60}, {0xe3,0xfc,0xfc,0x1f}, {0x79,0xb1,0xb1,0xc8}, {0xb6,0x5b,0x5b,0xed},
+{0xd4,0x6a,0x6a,0xbe}, {0x8d,0xcb,0xcb,0x46}, {0x67,0xbe,0xbe,0xd9}, {0x72,0x39,0x39,0x4b},
+{0x94,0x4a,0x4a,0xde}, {0x98,0x4c,0x4c,0xd4}, {0xb0,0x58,0x58,0xe8}, {0x85,0xcf,0xcf,0x4a},
+{0xbb,0xd0,0xd0,0x6b}, {0xc5,0xef,0xef,0x2a}, {0x4f,0xaa,0xaa,0xe5}, {0xed,0xfb,0xfb,0x16},
+{0x86,0x43,0x43,0xc5}, {0x9a,0x4d,0x4d,0xd7}, {0x66,0x33,0x33,0x55}, {0x11,0x85,0x85,0x94},
+{0x8a,0x45,0x45,0xcf}, {0xe9,0xf9,0xf9,0x10}, {0x04,0x02,0x02,0x06}, {0xfe,0x7f,0x7f,0x81},
+{0xa0,0x50,0x50,0xf0}, {0x78,0x3c,0x3c,0x44}, {0x25,0x9f,0x9f,0xba}, {0x4b,0xa8,0xa8,0xe3},
+{0xa2,0x51,0x51,0xf3}, {0x5d,0xa3,0xa3,0xfe}, {0x80,0x40,0x40,0xc0}, {0x05,0x8f,0x8f,0x8a},
+{0x3f,0x92,0x92,0xad}, {0x21,0x9d,0x9d,0xbc}, {0x70,0x38,0x38,0x48}, {0xf1,0xf5,0xf5,0x04},
+{0x63,0xbc,0xbc,0xdf}, {0x77,0xb6,0xb6,0xc1}, {0xaf,0xda,0xda,0x75}, {0x42,0x21,0x21,0x63},
+{0x20,0x10,0x10,0x30}, {0xe5,0xff,0xff,0x1a}, {0xfd,0xf3,0xf3,0x0e}, {0xbf,0xd2,0xd2,0x6d},
+{0x81,0xcd,0xcd,0x4c}, {0x18,0x0c,0x0c,0x14}, {0x26,0x13,0x13,0x35}, {0xc3,0xec,0xec,0x2f},
+{0xbe,0x5f,0x5f,0xe1}, {0x35,0x97,0x97,0xa2}, {0x88,0x44,0x44,0xcc}, {0x2e,0x17,0x17,0x39},
+{0x93,0xc4,0xc4,0x57}, {0x55,0xa7,0xa7,0xf2}, {0xfc,0x7e,0x7e,0x82}, {0x7a,0x3d,0x3d,0x47},
+{0xc8,0x64,0x64,0xac}, {0xba,0x5d,0x5d,0xe7}, {0x32,0x19,0x19,0x2b}, {0xe6,0x73,0x73,0x95},
+{0xc0,0x60,0x60,0xa0}, {0x19,0x81,0x81,0x98}, {0x9e,0x4f,0x4f,0xd1}, {0xa3,0xdc,0xdc,0x7f},
+{0x44,0x22,0x22,0x66}, {0x54,0x2a,0x2a,0x7e}, {0x3b,0x90,0x90,0xab}, {0x0b,0x88,0x88,0x83},
+{0x8c,0x46,0x46,0xca}, {0xc7,0xee,0xee,0x29}, {0x6b,0xb8,0xb8,0xd3}, {0x28,0x14,0x14,0x3c},
+{0xa7,0xde,0xde,0x79}, {0xbc,0x5e,0x5e,0xe2}, {0x16,0x0b,0x0b,0x1d}, {0xad,0xdb,0xdb,0x76},
+{0xdb,0xe0,0xe0,0x3b}, {0x64,0x32,0x32,0x56}, {0x74,0x3a,0x3a,0x4e}, {0x14,0x0a,0x0a,0x1e},
+{0x92,0x49,0x49,0xdb}, {0x0c,0x06,0x06,0x0a}, {0x48,0x24,0x24,0x6c}, {0xb8,0x5c,0x5c,0xe4},
+{0x9f,0xc2,0xc2,0x5d}, {0xbd,0xd3,0xd3,0x6e}, {0x43,0xac,0xac,0xef}, {0xc4,0x62,0x62,0xa6},
+{0x39,0x91,0x91,0xa8}, {0x31,0x95,0x95,0xa4}, {0xd3,0xe4,0xe4,0x37}, {0xf2,0x79,0x79,0x8b},
+{0xd5,0xe7,0xe7,0x32}, {0x8b,0xc8,0xc8,0x43}, {0x6e,0x37,0x37,0x59}, {0xda,0x6d,0x6d,0xb7},
+{0x01,0x8d,0x8d,0x8c}, {0xb1,0xd5,0xd5,0x64}, {0x9c,0x4e,0x4e,0xd2}, {0x49,0xa9,0xa9,0xe0},
+{0xd8,0x6c,0x6c,0xb4}, {0xac,0x56,0x56,0xfa}, {0xf3,0xf4,0xf4,0x07}, {0xcf,0xea,0xea,0x25},
+{0xca,0x65,0x65,0xaf}, {0xf4,0x7a,0x7a,0x8e}, {0x47,0xae,0xae,0xe9}, {0x10,0x08,0x08,0x18},
+{0x6f,0xba,0xba,0xd5}, {0xf0,0x78,0x78,0x88}, {0x4a,0x25,0x25,0x6f}, {0x5c,0x2e,0x2e,0x72},
+{0x38,0x1c,0x1c,0x24}, {0x57,0xa6,0xa6,0xf1}, {0x73,0xb4,0xb4,0xc7}, {0x97,0xc6,0xc6,0x51},
+{0xcb,0xe8,0xe8,0x23}, {0xa1,0xdd,0xdd,0x7c}, {0xe8,0x74,0x74,0x9c}, {0x3e,0x1f,0x1f,0x21},
+{0x96,0x4b,0x4b,0xdd}, {0x61,0xbd,0xbd,0xdc}, {0x0d,0x8b,0x8b,0x86}, {0x0f,0x8a,0x8a,0x85},
+{0xe0,0x70,0x70,0x90}, {0x7c,0x3e,0x3e,0x42}, {0x71,0xb5,0xb5,0xc4}, {0xcc,0x66,0x66,0xaa},
+{0x90,0x48,0x48,0xd8}, {0x06,0x03,0x03,0x05}, {0xf7,0xf6,0xf6,0x01}, {0x1c,0x0e,0x0e,0x12},
+{0xc2,0x61,0x61,0xa3}, {0x6a,0x35,0x35,0x5f}, {0xae,0x57,0x57,0xf9}, {0x69,0xb9,0xb9,0xd0},
+{0x17,0x86,0x86,0x91}, {0x99,0xc1,0xc1,0x58}, {0x3a,0x1d,0x1d,0x27}, {0x27,0x9e,0x9e,0xb9},
+{0xd9,0xe1,0xe1,0x38}, {0xeb,0xf8,0xf8,0x13}, {0x2b,0x98,0x98,0xb3}, {0x22,0x11,0x11,0x33},
+{0xd2,0x69,0x69,0xbb}, {0xa9,0xd9,0xd9,0x70}, {0x07,0x8e,0x8e,0x89}, {0x33,0x94,0x94,0xa7},
+{0x2d,0x9b,0x9b,0xb6}, {0x3c,0x1e,0x1e,0x22}, {0x15,0x87,0x87,0x92}, {0xc9,0xe9,0xe9,0x20},
+{0x87,0xce,0xce,0x49}, {0xaa,0x55,0x55,0xff}, {0x50,0x28,0x28,0x78}, {0xa5,0xdf,0xdf,0x7a},
+{0x03,0x8c,0x8c,0x8f}, {0x59,0xa1,0xa1,0xf8}, {0x09,0x89,0x89,0x80}, {0x1a,0x0d,0x0d,0x17},
+{0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8},
+{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11},
+{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a}
+       }
+};
+#define        T1      xT1.xt8
+
+static const union xtab xT2 = {
+       .xt8 = {
+{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b},
+{0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5},
+{0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b},
+{0x19,0xe7,0xfe,0xfe}, {0x62,0xb5,0xd7,0xd7}, {0xe6,0x4d,0xab,0xab}, {0x9a,0xec,0x76,0x76},
+{0x45,0x8f,0xca,0xca}, {0x9d,0x1f,0x82,0x82}, {0x40,0x89,0xc9,0xc9}, {0x87,0xfa,0x7d,0x7d},
+{0x15,0xef,0xfa,0xfa}, {0xeb,0xb2,0x59,0x59}, {0xc9,0x8e,0x47,0x47}, {0x0b,0xfb,0xf0,0xf0},
+{0xec,0x41,0xad,0xad}, {0x67,0xb3,0xd4,0xd4}, {0xfd,0x5f,0xa2,0xa2}, {0xea,0x45,0xaf,0xaf},
+{0xbf,0x23,0x9c,0x9c}, {0xf7,0x53,0xa4,0xa4}, {0x96,0xe4,0x72,0x72}, {0x5b,0x9b,0xc0,0xc0},
+{0xc2,0x75,0xb7,0xb7}, {0x1c,0xe1,0xfd,0xfd}, {0xae,0x3d,0x93,0x93}, {0x6a,0x4c,0x26,0x26},
+{0x5a,0x6c,0x36,0x36}, {0x41,0x7e,0x3f,0x3f}, {0x02,0xf5,0xf7,0xf7}, {0x4f,0x83,0xcc,0xcc},
+{0x5c,0x68,0x34,0x34}, {0xf4,0x51,0xa5,0xa5}, {0x34,0xd1,0xe5,0xe5}, {0x08,0xf9,0xf1,0xf1},
+{0x93,0xe2,0x71,0x71}, {0x73,0xab,0xd8,0xd8}, {0x53,0x62,0x31,0x31}, {0x3f,0x2a,0x15,0x15},
+{0x0c,0x08,0x04,0x04}, {0x52,0x95,0xc7,0xc7}, {0x65,0x46,0x23,0x23}, {0x5e,0x9d,0xc3,0xc3},
+{0x28,0x30,0x18,0x18}, {0xa1,0x37,0x96,0x96}, {0x0f,0x0a,0x05,0x05}, {0xb5,0x2f,0x9a,0x9a},
+{0x09,0x0e,0x07,0x07}, {0x36,0x24,0x12,0x12}, {0x9b,0x1b,0x80,0x80}, {0x3d,0xdf,0xe2,0xe2},
+{0x26,0xcd,0xeb,0xeb}, {0x69,0x4e,0x27,0x27}, {0xcd,0x7f,0xb2,0xb2}, {0x9f,0xea,0x75,0x75},
+{0x1b,0x12,0x09,0x09}, {0x9e,0x1d,0x83,0x83}, {0x74,0x58,0x2c,0x2c}, {0x2e,0x34,0x1a,0x1a},
+{0x2d,0x36,0x1b,0x1b}, {0xb2,0xdc,0x6e,0x6e}, {0xee,0xb4,0x5a,0x5a}, {0xfb,0x5b,0xa0,0xa0},
+{0xf6,0xa4,0x52,0x52}, {0x4d,0x76,0x3b,0x3b}, {0x61,0xb7,0xd6,0xd6}, {0xce,0x7d,0xb3,0xb3},
+{0x7b,0x52,0x29,0x29}, {0x3e,0xdd,0xe3,0xe3}, {0x71,0x5e,0x2f,0x2f}, {0x97,0x13,0x84,0x84},
+{0xf5,0xa6,0x53,0x53}, {0x68,0xb9,0xd1,0xd1}, {0x00,0x00,0x00,0x00}, {0x2c,0xc1,0xed,0xed},
+{0x60,0x40,0x20,0x20}, {0x1f,0xe3,0xfc,0xfc}, {0xc8,0x79,0xb1,0xb1}, {0xed,0xb6,0x5b,0x5b},
+{0xbe,0xd4,0x6a,0x6a}, {0x46,0x8d,0xcb,0xcb}, {0xd9,0x67,0xbe,0xbe}, {0x4b,0x72,0x39,0x39},
+{0xde,0x94,0x4a,0x4a}, {0xd4,0x98,0x4c,0x4c}, {0xe8,0xb0,0x58,0x58}, {0x4a,0x85,0xcf,0xcf},
+{0x6b,0xbb,0xd0,0xd0}, {0x2a,0xc5,0xef,0xef}, {0xe5,0x4f,0xaa,0xaa}, {0x16,0xed,0xfb,0xfb},
+{0xc5,0x86,0x43,0x43}, {0xd7,0x9a,0x4d,0x4d}, {0x55,0x66,0x33,0x33}, {0x94,0x11,0x85,0x85},
+{0xcf,0x8a,0x45,0x45}, {0x10,0xe9,0xf9,0xf9}, {0x06,0x04,0x02,0x02}, {0x81,0xfe,0x7f,0x7f},
+{0xf0,0xa0,0x50,0x50}, {0x44,0x78,0x3c,0x3c}, {0xba,0x25,0x9f,0x9f}, {0xe3,0x4b,0xa8,0xa8},
+{0xf3,0xa2,0x51,0x51}, {0xfe,0x5d,0xa3,0xa3}, {0xc0,0x80,0x40,0x40}, {0x8a,0x05,0x8f,0x8f},
+{0xad,0x3f,0x92,0x92}, {0xbc,0x21,0x9d,0x9d}, {0x48,0x70,0x38,0x38}, {0x04,0xf1,0xf5,0xf5},
+{0xdf,0x63,0xbc,0xbc}, {0xc1,0x77,0xb6,0xb6}, {0x75,0xaf,0xda,0xda}, {0x63,0x42,0x21,0x21},
+{0x30,0x20,0x10,0x10}, {0x1a,0xe5,0xff,0xff}, {0x0e,0xfd,0xf3,0xf3}, {0x6d,0xbf,0xd2,0xd2},
+{0x4c,0x81,0xcd,0xcd}, {0x14,0x18,0x0c,0x0c}, {0x35,0x26,0x13,0x13}, {0x2f,0xc3,0xec,0xec},
+{0xe1,0xbe,0x5f,0x5f}, {0xa2,0x35,0x97,0x97}, {0xcc,0x88,0x44,0x44}, {0x39,0x2e,0x17,0x17},
+{0x57,0x93,0xc4,0xc4}, {0xf2,0x55,0xa7,0xa7}, {0x82,0xfc,0x7e,0x7e}, {0x47,0x7a,0x3d,0x3d},
+{0xac,0xc8,0x64,0x64}, {0xe7,0xba,0x5d,0x5d}, {0x2b,0x32,0x19,0x19}, {0x95,0xe6,0x73,0x73},
+{0xa0,0xc0,0x60,0x60}, {0x98,0x19,0x81,0x81}, {0xd1,0x9e,0x4f,0x4f}, {0x7f,0xa3,0xdc,0xdc},
+{0x66,0x44,0x22,0x22}, {0x7e,0x54,0x2a,0x2a}, {0xab,0x3b,0x90,0x90}, {0x83,0x0b,0x88,0x88},
+{0xca,0x8c,0x46,0x46}, {0x29,0xc7,0xee,0xee}, {0xd3,0x6b,0xb8,0xb8}, {0x3c,0x28,0x14,0x14},
+{0x79,0xa7,0xde,0xde}, {0xe2,0xbc,0x5e,0x5e}, {0x1d,0x16,0x0b,0x0b}, {0x76,0xad,0xdb,0xdb},
+{0x3b,0xdb,0xe0,0xe0}, {0x56,0x64,0x32,0x32}, {0x4e,0x74,0x3a,0x3a}, {0x1e,0x14,0x0a,0x0a},
+{0xdb,0x92,0x49,0x49}, {0x0a,0x0c,0x06,0x06}, {0x6c,0x48,0x24,0x24}, {0xe4,0xb8,0x5c,0x5c},
+{0x5d,0x9f,0xc2,0xc2}, {0x6e,0xbd,0xd3,0xd3}, {0xef,0x43,0xac,0xac}, {0xa6,0xc4,0x62,0x62},
+{0xa8,0x39,0x91,0x91}, {0xa4,0x31,0x95,0x95}, {0x37,0xd3,0xe4,0xe4}, {0x8b,0xf2,0x79,0x79},
+{0x32,0xd5,0xe7,0xe7}, {0x43,0x8b,0xc8,0xc8}, {0x59,0x6e,0x37,0x37}, {0xb7,0xda,0x6d,0x6d},
+{0x8c,0x01,0x8d,0x8d}, {0x64,0xb1,0xd5,0xd5}, {0xd2,0x9c,0x4e,0x4e}, {0xe0,0x49,0xa9,0xa9},
+{0xb4,0xd8,0x6c,0x6c}, {0xfa,0xac,0x56,0x56}, {0x07,0xf3,0xf4,0xf4}, {0x25,0xcf,0xea,0xea},
+{0xaf,0xca,0x65,0x65}, {0x8e,0xf4,0x7a,0x7a}, {0xe9,0x47,0xae,0xae}, {0x18,0x10,0x08,0x08},
+{0xd5,0x6f,0xba,0xba}, {0x88,0xf0,0x78,0x78}, {0x6f,0x4a,0x25,0x25}, {0x72,0x5c,0x2e,0x2e},
+{0x24,0x38,0x1c,0x1c}, {0xf1,0x57,0xa6,0xa6}, {0xc7,0x73,0xb4,0xb4}, {0x51,0x97,0xc6,0xc6},
+{0x23,0xcb,0xe8,0xe8}, {0x7c,0xa1,0xdd,0xdd}, {0x9c,0xe8,0x74,0x74}, {0x21,0x3e,0x1f,0x1f},
+{0xdd,0x96,0x4b,0x4b}, {0xdc,0x61,0xbd,0xbd}, {0x86,0x0d,0x8b,0x8b}, {0x85,0x0f,0x8a,0x8a},
+{0x90,0xe0,0x70,0x70}, {0x42,0x7c,0x3e,0x3e}, {0xc4,0x71,0xb5,0xb5}, {0xaa,0xcc,0x66,0x66},
+{0xd8,0x90,0x48,0x48}, {0x05,0x06,0x03,0x03}, {0x01,0xf7,0xf6,0xf6}, {0x12,0x1c,0x0e,0x0e},
+{0xa3,0xc2,0x61,0x61}, {0x5f,0x6a,0x35,0x35}, {0xf9,0xae,0x57,0x57}, {0xd0,0x69,0xb9,0xb9},
+{0x91,0x17,0x86,0x86}, {0x58,0x99,0xc1,0xc1}, {0x27,0x3a,0x1d,0x1d}, {0xb9,0x27,0x9e,0x9e},
+{0x38,0xd9,0xe1,0xe1}, {0x13,0xeb,0xf8,0xf8}, {0xb3,0x2b,0x98,0x98}, {0x33,0x22,0x11,0x11},
+{0xbb,0xd2,0x69,0x69}, {0x70,0xa9,0xd9,0xd9}, {0x89,0x07,0x8e,0x8e}, {0xa7,0x33,0x94,0x94},
+{0xb6,0x2d,0x9b,0x9b}, {0x22,0x3c,0x1e,0x1e}, {0x92,0x15,0x87,0x87}, {0x20,0xc9,0xe9,0xe9},
+{0x49,0x87,0xce,0xce}, {0xff,0xaa,0x55,0x55}, {0x78,0x50,0x28,0x28}, {0x7a,0xa5,0xdf,0xdf},
+{0x8f,0x03,0x8c,0x8c}, {0xf8,0x59,0xa1,0xa1}, {0x80,0x09,0x89,0x89}, {0x17,0x1a,0x0d,0x0d},
+{0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68},
+{0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f},
+{0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16}
+       }
+};
+#define        T2      xT2.xt8
+
+static const union xtab xT3 = {
+       .xt8 = {
+{0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b},
+{0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5},
+{0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b},
+{0xfe,0x19,0xe7,0xfe}, {0xd7,0x62,0xb5,0xd7}, {0xab,0xe6,0x4d,0xab}, {0x76,0x9a,0xec,0x76},
+{0xca,0x45,0x8f,0xca}, {0x82,0x9d,0x1f,0x82}, {0xc9,0x40,0x89,0xc9}, {0x7d,0x87,0xfa,0x7d},
+{0xfa,0x15,0xef,0xfa}, {0x59,0xeb,0xb2,0x59}, {0x47,0xc9,0x8e,0x47}, {0xf0,0x0b,0xfb,0xf0},
+{0xad,0xec,0x41,0xad}, {0xd4,0x67,0xb3,0xd4}, {0xa2,0xfd,0x5f,0xa2}, {0xaf,0xea,0x45,0xaf},
+{0x9c,0xbf,0x23,0x9c}, {0xa4,0xf7,0x53,0xa4}, {0x72,0x96,0xe4,0x72}, {0xc0,0x5b,0x9b,0xc0},
+{0xb7,0xc2,0x75,0xb7}, {0xfd,0x1c,0xe1,0xfd}, {0x93,0xae,0x3d,0x93}, {0x26,0x6a,0x4c,0x26},
+{0x36,0x5a,0x6c,0x36}, {0x3f,0x41,0x7e,0x3f}, {0xf7,0x02,0xf5,0xf7}, {0xcc,0x4f,0x83,0xcc},
+{0x34,0x5c,0x68,0x34}, {0xa5,0xf4,0x51,0xa5}, {0xe5,0x34,0xd1,0xe5}, {0xf1,0x08,0xf9,0xf1},
+{0x71,0x93,0xe2,0x71}, {0xd8,0x73,0xab,0xd8}, {0x31,0x53,0x62,0x31}, {0x15,0x3f,0x2a,0x15},
+{0x04,0x0c,0x08,0x04}, {0xc7,0x52,0x95,0xc7}, {0x23,0x65,0x46,0x23}, {0xc3,0x5e,0x9d,0xc3},
+{0x18,0x28,0x30,0x18}, {0x96,0xa1,0x37,0x96}, {0x05,0x0f,0x0a,0x05}, {0x9a,0xb5,0x2f,0x9a},
+{0x07,0x09,0x0e,0x07}, {0x12,0x36,0x24,0x12}, {0x80,0x9b,0x1b,0x80}, {0xe2,0x3d,0xdf,0xe2},
+{0xeb,0x26,0xcd,0xeb}, {0x27,0x69,0x4e,0x27}, {0xb2,0xcd,0x7f,0xb2}, {0x75,0x9f,0xea,0x75},
+{0x09,0x1b,0x12,0x09}, {0x83,0x9e,0x1d,0x83}, {0x2c,0x74,0x58,0x2c}, {0x1a,0x2e,0x34,0x1a},
+{0x1b,0x2d,0x36,0x1b}, {0x6e,0xb2,0xdc,0x6e}, {0x5a,0xee,0xb4,0x5a}, {0xa0,0xfb,0x5b,0xa0},
+{0x52,0xf6,0xa4,0x52}, {0x3b,0x4d,0x76,0x3b}, {0xd6,0x61,0xb7,0xd6}, {0xb3,0xce,0x7d,0xb3},
+{0x29,0x7b,0x52,0x29}, {0xe3,0x3e,0xdd,0xe3}, {0x2f,0x71,0x5e,0x2f}, {0x84,0x97,0x13,0x84},
+{0x53,0xf5,0xa6,0x53}, {0xd1,0x68,0xb9,0xd1}, {0x00,0x00,0x00,0x00}, {0xed,0x2c,0xc1,0xed},
+{0x20,0x60,0x40,0x20}, {0xfc,0x1f,0xe3,0xfc}, {0xb1,0xc8,0x79,0xb1}, {0x5b,0xed,0xb6,0x5b},
+{0x6a,0xbe,0xd4,0x6a}, {0xcb,0x46,0x8d,0xcb}, {0xbe,0xd9,0x67,0xbe}, {0x39,0x4b,0x72,0x39},
+{0x4a,0xde,0x94,0x4a}, {0x4c,0xd4,0x98,0x4c}, {0x58,0xe8,0xb0,0x58}, {0xcf,0x4a,0x85,0xcf},
+{0xd0,0x6b,0xbb,0xd0}, {0xef,0x2a,0xc5,0xef}, {0xaa,0xe5,0x4f,0xaa}, {0xfb,0x16,0xed,0xfb},
+{0x43,0xc5,0x86,0x43}, {0x4d,0xd7,0x9a,0x4d}, {0x33,0x55,0x66,0x33}, {0x85,0x94,0x11,0x85},
+{0x45,0xcf,0x8a,0x45}, {0xf9,0x10,0xe9,0xf9}, {0x02,0x06,0x04,0x02}, {0x7f,0x81,0xfe,0x7f},
+{0x50,0xf0,0xa0,0x50}, {0x3c,0x44,0x78,0x3c}, {0x9f,0xba,0x25,0x9f}, {0xa8,0xe3,0x4b,0xa8},
+{0x51,0xf3,0xa2,0x51}, {0xa3,0xfe,0x5d,0xa3}, {0x40,0xc0,0x80,0x40}, {0x8f,0x8a,0x05,0x8f},
+{0x92,0xad,0x3f,0x92}, {0x9d,0xbc,0x21,0x9d}, {0x38,0x48,0x70,0x38}, {0xf5,0x04,0xf1,0xf5},
+{0xbc,0xdf,0x63,0xbc}, {0xb6,0xc1,0x77,0xb6}, {0xda,0x75,0xaf,0xda}, {0x21,0x63,0x42,0x21},
+{0x10,0x30,0x20,0x10}, {0xff,0x1a,0xe5,0xff}, {0xf3,0x0e,0xfd,0xf3}, {0xd2,0x6d,0xbf,0xd2},
+{0xcd,0x4c,0x81,0xcd}, {0x0c,0x14,0x18,0x0c}, {0x13,0x35,0x26,0x13}, {0xec,0x2f,0xc3,0xec},
+{0x5f,0xe1,0xbe,0x5f}, {0x97,0xa2,0x35,0x97}, {0x44,0xcc,0x88,0x44}, {0x17,0x39,0x2e,0x17},
+{0xc4,0x57,0x93,0xc4}, {0xa7,0xf2,0x55,0xa7}, {0x7e,0x82,0xfc,0x7e}, {0x3d,0x47,0x7a,0x3d},
+{0x64,0xac,0xc8,0x64}, {0x5d,0xe7,0xba,0x5d}, {0x19,0x2b,0x32,0x19}, {0x73,0x95,0xe6,0x73},
+{0x60,0xa0,0xc0,0x60}, {0x81,0x98,0x19,0x81}, {0x4f,0xd1,0x9e,0x4f}, {0xdc,0x7f,0xa3,0xdc},
+{0x22,0x66,0x44,0x22}, {0x2a,0x7e,0x54,0x2a}, {0x90,0xab,0x3b,0x90}, {0x88,0x83,0x0b,0x88},
+{0x46,0xca,0x8c,0x46}, {0xee,0x29,0xc7,0xee}, {0xb8,0xd3,0x6b,0xb8}, {0x14,0x3c,0x28,0x14},
+{0xde,0x79,0xa7,0xde}, {0x5e,0xe2,0xbc,0x5e}, {0x0b,0x1d,0x16,0x0b}, {0xdb,0x76,0xad,0xdb},
+{0xe0,0x3b,0xdb,0xe0}, {0x32,0x56,0x64,0x32}, {0x3a,0x4e,0x74,0x3a}, {0x0a,0x1e,0x14,0x0a},
+{0x49,0xdb,0x92,0x49}, {0x06,0x0a,0x0c,0x06}, {0x24,0x6c,0x48,0x24}, {0x5c,0xe4,0xb8,0x5c},
+{0xc2,0x5d,0x9f,0xc2}, {0xd3,0x6e,0xbd,0xd3}, {0xac,0xef,0x43,0xac}, {0x62,0xa6,0xc4,0x62},
+{0x91,0xa8,0x39,0x91}, {0x95,0xa4,0x31,0x95}, {0xe4,0x37,0xd3,0xe4}, {0x79,0x8b,0xf2,0x79},
+{0xe7,0x32,0xd5,0xe7}, {0xc8,0x43,0x8b,0xc8}, {0x37,0x59,0x6e,0x37}, {0x6d,0xb7,0xda,0x6d},
+{0x8d,0x8c,0x01,0x8d}, {0xd5,0x64,0xb1,0xd5}, {0x4e,0xd2,0x9c,0x4e}, {0xa9,0xe0,0x49,0xa9},
+{0x6c,0xb4,0xd8,0x6c}, {0x56,0xfa,0xac,0x56}, {0xf4,0x07,0xf3,0xf4}, {0xea,0x25,0xcf,0xea},
+{0x65,0xaf,0xca,0x65}, {0x7a,0x8e,0xf4,0x7a}, {0xae,0xe9,0x47,0xae}, {0x08,0x18,0x10,0x08},
+{0xba,0xd5,0x6f,0xba}, {0x78,0x88,0xf0,0x78}, {0x25,0x6f,0x4a,0x25}, {0x2e,0x72,0x5c,0x2e},
+{0x1c,0x24,0x38,0x1c}, {0xa6,0xf1,0x57,0xa6}, {0xb4,0xc7,0x73,0xb4}, {0xc6,0x51,0x97,0xc6},
+{0xe8,0x23,0xcb,0xe8}, {0xdd,0x7c,0xa1,0xdd}, {0x74,0x9c,0xe8,0x74}, {0x1f,0x21,0x3e,0x1f},
+{0x4b,0xdd,0x96,0x4b}, {0xbd,0xdc,0x61,0xbd}, {0x8b,0x86,0x0d,0x8b}, {0x8a,0x85,0x0f,0x8a},
+{0x70,0x90,0xe0,0x70}, {0x3e,0x42,0x7c,0x3e}, {0xb5,0xc4,0x71,0xb5}, {0x66,0xaa,0xcc,0x66},
+{0x48,0xd8,0x90,0x48}, {0x03,0x05,0x06,0x03}, {0xf6,0x01,0xf7,0xf6}, {0x0e,0x12,0x1c,0x0e},
+{0x61,0xa3,0xc2,0x61}, {0x35,0x5f,0x6a,0x35}, {0x57,0xf9,0xae,0x57}, {0xb9,0xd0,0x69,0xb9},
+{0x86,0x91,0x17,0x86}, {0xc1,0x58,0x99,0xc1}, {0x1d,0x27,0x3a,0x1d}, {0x9e,0xb9,0x27,0x9e},
+{0xe1,0x38,0xd9,0xe1}, {0xf8,0x13,0xeb,0xf8}, {0x98,0xb3,0x2b,0x98}, {0x11,0x33,0x22,0x11},
+{0x69,0xbb,0xd2,0x69}, {0xd9,0x70,0xa9,0xd9}, {0x8e,0x89,0x07,0x8e}, {0x94,0xa7,0x33,0x94},
+{0x9b,0xb6,0x2d,0x9b}, {0x1e,0x22,0x3c,0x1e}, {0x87,0x92,0x15,0x87}, {0xe9,0x20,0xc9,0xe9},
+{0xce,0x49,0x87,0xce}, {0x55,0xff,0xaa,0x55}, {0x28,0x78,0x50,0x28}, {0xdf,0x7a,0xa5,0xdf},
+{0x8c,0x8f,0x03,0x8c}, {0xa1,0xf8,0x59,0xa1}, {0x89,0x80,0x09,0x89}, {0x0d,0x17,0x1a,0x0d},
+{0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68},
+{0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f},
+{0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16}
+       }
+};
+#define        T3      xT3.xt8
+
+static const union xtab xT4 = {
+       .xt8 = {
+{0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6},
+{0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91},
+{0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56},
+{0xfe,0xfe,0x19,0xe7}, {0xd7,0xd7,0x62,0xb5}, {0xab,0xab,0xe6,0x4d}, {0x76,0x76,0x9a,0xec},
+{0xca,0xca,0x45,0x8f}, {0x82,0x82,0x9d,0x1f}, {0xc9,0xc9,0x40,0x89}, {0x7d,0x7d,0x87,0xfa},
+{0xfa,0xfa,0x15,0xef}, {0x59,0x59,0xeb,0xb2}, {0x47,0x47,0xc9,0x8e}, {0xf0,0xf0,0x0b,0xfb},
+{0xad,0xad,0xec,0x41}, {0xd4,0xd4,0x67,0xb3}, {0xa2,0xa2,0xfd,0x5f}, {0xaf,0xaf,0xea,0x45},
+{0x9c,0x9c,0xbf,0x23}, {0xa4,0xa4,0xf7,0x53}, {0x72,0x72,0x96,0xe4}, {0xc0,0xc0,0x5b,0x9b},
+{0xb7,0xb7,0xc2,0x75}, {0xfd,0xfd,0x1c,0xe1}, {0x93,0x93,0xae,0x3d}, {0x26,0x26,0x6a,0x4c},
+{0x36,0x36,0x5a,0x6c}, {0x3f,0x3f,0x41,0x7e}, {0xf7,0xf7,0x02,0xf5}, {0xcc,0xcc,0x4f,0x83},
+{0x34,0x34,0x5c,0x68}, {0xa5,0xa5,0xf4,0x51}, {0xe5,0xe5,0x34,0xd1}, {0xf1,0xf1,0x08,0xf9},
+{0x71,0x71,0x93,0xe2}, {0xd8,0xd8,0x73,0xab}, {0x31,0x31,0x53,0x62}, {0x15,0x15,0x3f,0x2a},
+{0x04,0x04,0x0c,0x08}, {0xc7,0xc7,0x52,0x95}, {0x23,0x23,0x65,0x46}, {0xc3,0xc3,0x5e,0x9d},
+{0x18,0x18,0x28,0x30}, {0x96,0x96,0xa1,0x37}, {0x05,0x05,0x0f,0x0a}, {0x9a,0x9a,0xb5,0x2f},
+{0x07,0x07,0x09,0x0e}, {0x12,0x12,0x36,0x24}, {0x80,0x80,0x9b,0x1b}, {0xe2,0xe2,0x3d,0xdf},
+{0xeb,0xeb,0x26,0xcd}, {0x27,0x27,0x69,0x4e}, {0xb2,0xb2,0xcd,0x7f}, {0x75,0x75,0x9f,0xea},
+{0x09,0x09,0x1b,0x12}, {0x83,0x83,0x9e,0x1d}, {0x2c,0x2c,0x74,0x58}, {0x1a,0x1a,0x2e,0x34},
+{0x1b,0x1b,0x2d,0x36}, {0x6e,0x6e,0xb2,0xdc}, {0x5a,0x5a,0xee,0xb4}, {0xa0,0xa0,0xfb,0x5b},
+{0x52,0x52,0xf6,0xa4}, {0x3b,0x3b,0x4d,0x76}, {0xd6,0xd6,0x61,0xb7}, {0xb3,0xb3,0xce,0x7d},
+{0x29,0x29,0x7b,0x52}, {0xe3,0xe3,0x3e,0xdd}, {0x2f,0x2f,0x71,0x5e}, {0x84,0x84,0x97,0x13},
+{0x53,0x53,0xf5,0xa6}, {0xd1,0xd1,0x68,0xb9}, {0x00,0x00,0x00,0x00}, {0xed,0xed,0x2c,0xc1},
+{0x20,0x20,0x60,0x40}, {0xfc,0xfc,0x1f,0xe3}, {0xb1,0xb1,0xc8,0x79}, {0x5b,0x5b,0xed,0xb6},
+{0x6a,0x6a,0xbe,0xd4}, {0xcb,0xcb,0x46,0x8d}, {0xbe,0xbe,0xd9,0x67}, {0x39,0x39,0x4b,0x72},
+{0x4a,0x4a,0xde,0x94}, {0x4c,0x4c,0xd4,0x98}, {0x58,0x58,0xe8,0xb0}, {0xcf,0xcf,0x4a,0x85},
+{0xd0,0xd0,0x6b,0xbb}, {0xef,0xef,0x2a,0xc5}, {0xaa,0xaa,0xe5,0x4f}, {0xfb,0xfb,0x16,0xed},
+{0x43,0x43,0xc5,0x86}, {0x4d,0x4d,0xd7,0x9a}, {0x33,0x33,0x55,0x66}, {0x85,0x85,0x94,0x11},
+{0x45,0x45,0xcf,0x8a}, {0xf9,0xf9,0x10,0xe9}, {0x02,0x02,0x06,0x04}, {0x7f,0x7f,0x81,0xfe},
+{0x50,0x50,0xf0,0xa0}, {0x3c,0x3c,0x44,0x78}, {0x9f,0x9f,0xba,0x25}, {0xa8,0xa8,0xe3,0x4b},
+{0x51,0x51,0xf3,0xa2}, {0xa3,0xa3,0xfe,0x5d}, {0x40,0x40,0xc0,0x80}, {0x8f,0x8f,0x8a,0x05},
+{0x92,0x92,0xad,0x3f}, {0x9d,0x9d,0xbc,0x21}, {0x38,0x38,0x48,0x70}, {0xf5,0xf5,0x04,0xf1},
+{0xbc,0xbc,0xdf,0x63}, {0xb6,0xb6,0xc1,0x77}, {0xda,0xda,0x75,0xaf}, {0x21,0x21,0x63,0x42},
+{0x10,0x10,0x30,0x20}, {0xff,0xff,0x1a,0xe5}, {0xf3,0xf3,0x0e,0xfd}, {0xd2,0xd2,0x6d,0xbf},
+{0xcd,0xcd,0x4c,0x81}, {0x0c,0x0c,0x14,0x18}, {0x13,0x13,0x35,0x26}, {0xec,0xec,0x2f,0xc3},
+{0x5f,0x5f,0xe1,0xbe}, {0x97,0x97,0xa2,0x35}, {0x44,0x44,0xcc,0x88}, {0x17,0x17,0x39,0x2e},
+{0xc4,0xc4,0x57,0x93}, {0xa7,0xa7,0xf2,0x55}, {0x7e,0x7e,0x82,0xfc}, {0x3d,0x3d,0x47,0x7a},
+{0x64,0x64,0xac,0xc8}, {0x5d,0x5d,0xe7,0xba}, {0x19,0x19,0x2b,0x32}, {0x73,0x73,0x95,0xe6},
+{0x60,0x60,0xa0,0xc0}, {0x81,0x81,0x98,0x19}, {0x4f,0x4f,0xd1,0x9e}, {0xdc,0xdc,0x7f,0xa3},
+{0x22,0x22,0x66,0x44}, {0x2a,0x2a,0x7e,0x54}, {0x90,0x90,0xab,0x3b}, {0x88,0x88,0x83,0x0b},
+{0x46,0x46,0xca,0x8c}, {0xee,0xee,0x29,0xc7}, {0xb8,0xb8,0xd3,0x6b}, {0x14,0x14,0x3c,0x28},
+{0xde,0xde,0x79,0xa7}, {0x5e,0x5e,0xe2,0xbc}, {0x0b,0x0b,0x1d,0x16}, {0xdb,0xdb,0x76,0xad},
+{0xe0,0xe0,0x3b,0xdb}, {0x32,0x32,0x56,0x64}, {0x3a,0x3a,0x4e,0x74}, {0x0a,0x0a,0x1e,0x14},
+{0x49,0x49,0xdb,0x92}, {0x06,0x06,0x0a,0x0c}, {0x24,0x24,0x6c,0x48}, {0x5c,0x5c,0xe4,0xb8},
+{0xc2,0xc2,0x5d,0x9f}, {0xd3,0xd3,0x6e,0xbd}, {0xac,0xac,0xef,0x43}, {0x62,0x62,0xa6,0xc4},
+{0x91,0x91,0xa8,0x39}, {0x95,0x95,0xa4,0x31}, {0xe4,0xe4,0x37,0xd3}, {0x79,0x79,0x8b,0xf2},
+{0xe7,0xe7,0x32,0xd5}, {0xc8,0xc8,0x43,0x8b}, {0x37,0x37,0x59,0x6e}, {0x6d,0x6d,0xb7,0xda},
+{0x8d,0x8d,0x8c,0x01}, {0xd5,0xd5,0x64,0xb1}, {0x4e,0x4e,0xd2,0x9c}, {0xa9,0xa9,0xe0,0x49},
+{0x6c,0x6c,0xb4,0xd8}, {0x56,0x56,0xfa,0xac}, {0xf4,0xf4,0x07,0xf3}, {0xea,0xea,0x25,0xcf},
+{0x65,0x65,0xaf,0xca}, {0x7a,0x7a,0x8e,0xf4}, {0xae,0xae,0xe9,0x47}, {0x08,0x08,0x18,0x10},
+{0xba,0xba,0xd5,0x6f}, {0x78,0x78,0x88,0xf0}, {0x25,0x25,0x6f,0x4a}, {0x2e,0x2e,0x72,0x5c},
+{0x1c,0x1c,0x24,0x38}, {0xa6,0xa6,0xf1,0x57}, {0xb4,0xb4,0xc7,0x73}, {0xc6,0xc6,0x51,0x97},
+{0xe8,0xe8,0x23,0xcb}, {0xdd,0xdd,0x7c,0xa1}, {0x74,0x74,0x9c,0xe8}, {0x1f,0x1f,0x21,0x3e},
+{0x4b,0x4b,0xdd,0x96}, {0xbd,0xbd,0xdc,0x61}, {0x8b,0x8b,0x86,0x0d}, {0x8a,0x8a,0x85,0x0f},
+{0x70,0x70,0x90,0xe0}, {0x3e,0x3e,0x42,0x7c}, {0xb5,0xb5,0xc4,0x71}, {0x66,0x66,0xaa,0xcc},
+{0x48,0x48,0xd8,0x90}, {0x03,0x03,0x05,0x06}, {0xf6,0xf6,0x01,0xf7}, {0x0e,0x0e,0x12,0x1c},
+{0x61,0x61,0xa3,0xc2}, {0x35,0x35,0x5f,0x6a}, {0x57,0x57,0xf9,0xae}, {0xb9,0xb9,0xd0,0x69},
+{0x86,0x86,0x91,0x17}, {0xc1,0xc1,0x58,0x99}, {0x1d,0x1d,0x27,0x3a}, {0x9e,0x9e,0xb9,0x27},
+{0xe1,0xe1,0x38,0xd9}, {0xf8,0xf8,0x13,0xeb}, {0x98,0x98,0xb3,0x2b}, {0x11,0x11,0x33,0x22},
+{0x69,0x69,0xbb,0xd2}, {0xd9,0xd9,0x70,0xa9}, {0x8e,0x8e,0x89,0x07}, {0x94,0x94,0xa7,0x33},
+{0x9b,0x9b,0xb6,0x2d}, {0x1e,0x1e,0x22,0x3c}, {0x87,0x87,0x92,0x15}, {0xe9,0xe9,0x20,0xc9},
+{0xce,0xce,0x49,0x87}, {0x55,0x55,0xff,0xaa}, {0x28,0x28,0x78,0x50}, {0xdf,0xdf,0x7a,0xa5},
+{0x8c,0x8c,0x8f,0x03}, {0xa1,0xa1,0xf8,0x59}, {0x89,0x89,0x80,0x09}, {0x0d,0x0d,0x17,0x1a},
+{0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0},
+{0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e},
+{0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c}
+       }
+};
+#define        T4      xT4.xt8
+
+static const union xtab xT5 = {
+       .xt8 = {
+{0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96},
+{0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93},
+{0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25},
+{0x4f,0xe5,0xd7,0xfc}, {0xc5,0x2a,0xcb,0xd7}, {0x26,0x35,0x44,0x80}, {0xb5,0x62,0xa3,0x8f},
+{0xde,0xb1,0x5a,0x49}, {0x25,0xba,0x1b,0x67}, {0x45,0xea,0x0e,0x98}, {0x5d,0xfe,0xc0,0xe1},
+{0xc3,0x2f,0x75,0x02}, {0x81,0x4c,0xf0,0x12}, {0x8d,0x46,0x97,0xa3}, {0x6b,0xd3,0xf9,0xc6},
+{0x03,0x8f,0x5f,0xe7}, {0x15,0x92,0x9c,0x95}, {0xbf,0x6d,0x7a,0xeb}, {0x95,0x52,0x59,0xda},
+{0xd4,0xbe,0x83,0x2d}, {0x58,0x74,0x21,0xd3}, {0x49,0xe0,0x69,0x29}, {0x8e,0xc9,0xc8,0x44},
+{0x75,0xc2,0x89,0x6a}, {0xf4,0x8e,0x79,0x78}, {0x99,0x58,0x3e,0x6b}, {0x27,0xb9,0x71,0xdd},
+{0xbe,0xe1,0x4f,0xb6}, {0xf0,0x88,0xad,0x17}, {0xc9,0x20,0xac,0x66}, {0x7d,0xce,0x3a,0xb4},
+{0x63,0xdf,0x4a,0x18}, {0xe5,0x1a,0x31,0x82}, {0x97,0x51,0x33,0x60}, {0x62,0x53,0x7f,0x45},
+{0xb1,0x64,0x77,0xe0}, {0xbb,0x6b,0xae,0x84}, {0xfe,0x81,0xa0,0x1c}, {0xf9,0x08,0x2b,0x94},
+{0x70,0x48,0x68,0x58}, {0x8f,0x45,0xfd,0x19}, {0x94,0xde,0x6c,0x87}, {0x52,0x7b,0xf8,0xb7},
+{0xab,0x73,0xd3,0x23}, {0x72,0x4b,0x02,0xe2}, {0xe3,0x1f,0x8f,0x57}, {0x66,0x55,0xab,0x2a},
+{0xb2,0xeb,0x28,0x07}, {0x2f,0xb5,0xc2,0x03}, {0x86,0xc5,0x7b,0x9a}, {0xd3,0x37,0x08,0xa5},
+{0x30,0x28,0x87,0xf2}, {0x23,0xbf,0xa5,0xb2}, {0x02,0x03,0x6a,0xba}, {0xed,0x16,0x82,0x5c},
+{0x8a,0xcf,0x1c,0x2b}, {0xa7,0x79,0xb4,0x92}, {0xf3,0x07,0xf2,0xf0}, {0x4e,0x69,0xe2,0xa1},
+{0x65,0xda,0xf4,0xcd}, {0x06,0x05,0xbe,0xd5}, {0xd1,0x34,0x62,0x1f}, {0xc4,0xa6,0xfe,0x8a},
+{0x34,0x2e,0x53,0x9d}, {0xa2,0xf3,0x55,0xa0}, {0x05,0x8a,0xe1,0x32}, {0xa4,0xf6,0xeb,0x75},
+{0x0b,0x83,0xec,0x39}, {0x40,0x60,0xef,0xaa}, {0x5e,0x71,0x9f,0x06}, {0xbd,0x6e,0x10,0x51},
+{0x3e,0x21,0x8a,0xf9}, {0x96,0xdd,0x06,0x3d}, {0xdd,0x3e,0x05,0xae}, {0x4d,0xe6,0xbd,0x46},
+{0x91,0x54,0x8d,0xb5}, {0x71,0xc4,0x5d,0x05}, {0x04,0x06,0xd4,0x6f}, {0x60,0x50,0x15,0xff},
+{0x19,0x98,0xfb,0x24}, {0xd6,0xbd,0xe9,0x97}, {0x89,0x40,0x43,0xcc}, {0x67,0xd9,0x9e,0x77},
+{0xb0,0xe8,0x42,0xbd}, {0x07,0x89,0x8b,0x88}, {0xe7,0x19,0x5b,0x38}, {0x79,0xc8,0xee,0xdb},
+{0xa1,0x7c,0x0a,0x47}, {0x7c,0x42,0x0f,0xe9}, {0xf8,0x84,0x1e,0xc9}, {0x00,0x00,0x00,0x00},
+{0x09,0x80,0x86,0x83}, {0x32,0x2b,0xed,0x48}, {0x1e,0x11,0x70,0xac}, {0x6c,0x5a,0x72,0x4e},
+{0xfd,0x0e,0xff,0xfb}, {0x0f,0x85,0x38,0x56}, {0x3d,0xae,0xd5,0x1e}, {0x36,0x2d,0x39,0x27},
+{0x0a,0x0f,0xd9,0x64}, {0x68,0x5c,0xa6,0x21}, {0x9b,0x5b,0x54,0xd1}, {0x24,0x36,0x2e,0x3a},
+{0x0c,0x0a,0x67,0xb1}, {0x93,0x57,0xe7,0x0f}, {0xb4,0xee,0x96,0xd2}, {0x1b,0x9b,0x91,0x9e},
+{0x80,0xc0,0xc5,0x4f}, {0x61,0xdc,0x20,0xa2}, {0x5a,0x77,0x4b,0x69}, {0x1c,0x12,0x1a,0x16},
+{0xe2,0x93,0xba,0x0a}, {0xc0,0xa0,0x2a,0xe5}, {0x3c,0x22,0xe0,0x43}, {0x12,0x1b,0x17,0x1d},
+{0x0e,0x09,0x0d,0x0b}, {0xf2,0x8b,0xc7,0xad}, {0x2d,0xb6,0xa8,0xb9}, {0x14,0x1e,0xa9,0xc8},
+{0x57,0xf1,0x19,0x85}, {0xaf,0x75,0x07,0x4c}, {0xee,0x99,0xdd,0xbb}, {0xa3,0x7f,0x60,0xfd},
+{0xf7,0x01,0x26,0x9f}, {0x5c,0x72,0xf5,0xbc}, {0x44,0x66,0x3b,0xc5}, {0x5b,0xfb,0x7e,0x34},
+{0x8b,0x43,0x29,0x76}, {0xcb,0x23,0xc6,0xdc}, {0xb6,0xed,0xfc,0x68}, {0xb8,0xe4,0xf1,0x63},
+{0xd7,0x31,0xdc,0xca}, {0x42,0x63,0x85,0x10}, {0x13,0x97,0x22,0x40}, {0x84,0xc6,0x11,0x20},
+{0x85,0x4a,0x24,0x7d}, {0xd2,0xbb,0x3d,0xf8}, {0xae,0xf9,0x32,0x11}, {0xc7,0x29,0xa1,0x6d},
+{0x1d,0x9e,0x2f,0x4b}, {0xdc,0xb2,0x30,0xf3}, {0x0d,0x86,0x52,0xec}, {0x77,0xc1,0xe3,0xd0},
+{0x2b,0xb3,0x16,0x6c}, {0xa9,0x70,0xb9,0x99}, {0x11,0x94,0x48,0xfa}, {0x47,0xe9,0x64,0x22},
+{0xa8,0xfc,0x8c,0xc4}, {0xa0,0xf0,0x3f,0x1a}, {0x56,0x7d,0x2c,0xd8}, {0x22,0x33,0x90,0xef},
+{0x87,0x49,0x4e,0xc7}, {0xd9,0x38,0xd1,0xc1}, {0x8c,0xca,0xa2,0xfe}, {0x98,0xd4,0x0b,0x36},
+{0xa6,0xf5,0x81,0xcf}, {0xa5,0x7a,0xde,0x28}, {0xda,0xb7,0x8e,0x26}, {0x3f,0xad,0xbf,0xa4},
+{0x2c,0x3a,0x9d,0xe4}, {0x50,0x78,0x92,0x0d}, {0x6a,0x5f,0xcc,0x9b}, {0x54,0x7e,0x46,0x62},
+{0xf6,0x8d,0x13,0xc2}, {0x90,0xd8,0xb8,0xe8}, {0x2e,0x39,0xf7,0x5e}, {0x82,0xc3,0xaf,0xf5},
+{0x9f,0x5d,0x80,0xbe}, {0x69,0xd0,0x93,0x7c}, {0x6f,0xd5,0x2d,0xa9}, {0xcf,0x25,0x12,0xb3},
+{0xc8,0xac,0x99,0x3b}, {0x10,0x18,0x7d,0xa7}, {0xe8,0x9c,0x63,0x6e}, {0xdb,0x3b,0xbb,0x7b},
+{0xcd,0x26,0x78,0x09}, {0x6e,0x59,0x18,0xf4}, {0xec,0x9a,0xb7,0x01}, {0x83,0x4f,0x9a,0xa8},
+{0xe6,0x95,0x6e,0x65}, {0xaa,0xff,0xe6,0x7e}, {0x21,0xbc,0xcf,0x08}, {0xef,0x15,0xe8,0xe6},
+{0xba,0xe7,0x9b,0xd9}, {0x4a,0x6f,0x36,0xce}, {0xea,0x9f,0x09,0xd4}, {0x29,0xb0,0x7c,0xd6},
+{0x31,0xa4,0xb2,0xaf}, {0x2a,0x3f,0x23,0x31}, {0xc6,0xa5,0x94,0x30}, {0x35,0xa2,0x66,0xc0},
+{0x74,0x4e,0xbc,0x37}, {0xfc,0x82,0xca,0xa6}, {0xe0,0x90,0xd0,0xb0}, {0x33,0xa7,0xd8,0x15},
+{0xf1,0x04,0x98,0x4a}, {0x41,0xec,0xda,0xf7}, {0x7f,0xcd,0x50,0x0e}, {0x17,0x91,0xf6,0x2f},
+{0x76,0x4d,0xd6,0x8d}, {0x43,0xef,0xb0,0x4d}, {0xcc,0xaa,0x4d,0x54}, {0xe4,0x96,0x04,0xdf},
+{0x9e,0xd1,0xb5,0xe3}, {0x4c,0x6a,0x88,0x1b}, {0xc1,0x2c,0x1f,0xb8}, {0x46,0x65,0x51,0x7f},
+{0x9d,0x5e,0xea,0x04}, {0x01,0x8c,0x35,0x5d}, {0xfa,0x87,0x74,0x73}, {0xfb,0x0b,0x41,0x2e},
+{0xb3,0x67,0x1d,0x5a}, {0x92,0xdb,0xd2,0x52}, {0xe9,0x10,0x56,0x33}, {0x6d,0xd6,0x47,0x13},
+{0x9a,0xd7,0x61,0x8c}, {0x37,0xa1,0x0c,0x7a}, {0x59,0xf8,0x14,0x8e}, {0xeb,0x13,0x3c,0x89},
+{0xce,0xa9,0x27,0xee}, {0xb7,0x61,0xc9,0x35}, {0xe1,0x1c,0xe5,0xed}, {0x7a,0x47,0xb1,0x3c},
+{0x9c,0xd2,0xdf,0x59}, {0x55,0xf2,0x73,0x3f}, {0x18,0x14,0xce,0x79}, {0x73,0xc7,0x37,0xbf},
+{0x53,0xf7,0xcd,0xea}, {0x5f,0xfd,0xaa,0x5b}, {0xdf,0x3d,0x6f,0x14}, {0x78,0x44,0xdb,0x86},
+{0xca,0xaf,0xf3,0x81}, {0xb9,0x68,0xc4,0x3e}, {0x38,0x24,0x34,0x2c}, {0xc2,0xa3,0x40,0x5f},
+{0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41},
+{0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90},
+{0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42}
+       }
+};
+#define        T5      xT5.xt8
+
+static const union xtab xT6 = {
+       .xt8 = {
+{0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e},
+{0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03},
+{0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c},
+{0xfc,0x4f,0xe5,0xd7}, {0xd7,0xc5,0x2a,0xcb}, {0x80,0x26,0x35,0x44}, {0x8f,0xb5,0x62,0xa3},
+{0x49,0xde,0xb1,0x5a}, {0x67,0x25,0xba,0x1b}, {0x98,0x45,0xea,0x0e}, {0xe1,0x5d,0xfe,0xc0},
+{0x02,0xc3,0x2f,0x75}, {0x12,0x81,0x4c,0xf0}, {0xa3,0x8d,0x46,0x97}, {0xc6,0x6b,0xd3,0xf9},
+{0xe7,0x03,0x8f,0x5f}, {0x95,0x15,0x92,0x9c}, {0xeb,0xbf,0x6d,0x7a}, {0xda,0x95,0x52,0x59},
+{0x2d,0xd4,0xbe,0x83}, {0xd3,0x58,0x74,0x21}, {0x29,0x49,0xe0,0x69}, {0x44,0x8e,0xc9,0xc8},
+{0x6a,0x75,0xc2,0x89}, {0x78,0xf4,0x8e,0x79}, {0x6b,0x99,0x58,0x3e}, {0xdd,0x27,0xb9,0x71},
+{0xb6,0xbe,0xe1,0x4f}, {0x17,0xf0,0x88,0xad}, {0x66,0xc9,0x20,0xac}, {0xb4,0x7d,0xce,0x3a},
+{0x18,0x63,0xdf,0x4a}, {0x82,0xe5,0x1a,0x31}, {0x60,0x97,0x51,0x33}, {0x45,0x62,0x53,0x7f},
+{0xe0,0xb1,0x64,0x77}, {0x84,0xbb,0x6b,0xae}, {0x1c,0xfe,0x81,0xa0}, {0x94,0xf9,0x08,0x2b},
+{0x58,0x70,0x48,0x68}, {0x19,0x8f,0x45,0xfd}, {0x87,0x94,0xde,0x6c}, {0xb7,0x52,0x7b,0xf8},
+{0x23,0xab,0x73,0xd3}, {0xe2,0x72,0x4b,0x02}, {0x57,0xe3,0x1f,0x8f}, {0x2a,0x66,0x55,0xab},
+{0x07,0xb2,0xeb,0x28}, {0x03,0x2f,0xb5,0xc2}, {0x9a,0x86,0xc5,0x7b}, {0xa5,0xd3,0x37,0x08},
+{0xf2,0x30,0x28,0x87}, {0xb2,0x23,0xbf,0xa5}, {0xba,0x02,0x03,0x6a}, {0x5c,0xed,0x16,0x82},
+{0x2b,0x8a,0xcf,0x1c}, {0x92,0xa7,0x79,0xb4}, {0xf0,0xf3,0x07,0xf2}, {0xa1,0x4e,0x69,0xe2},
+{0xcd,0x65,0xda,0xf4}, {0xd5,0x06,0x05,0xbe}, {0x1f,0xd1,0x34,0x62}, {0x8a,0xc4,0xa6,0xfe},
+{0x9d,0x34,0x2e,0x53}, {0xa0,0xa2,0xf3,0x55}, {0x32,0x05,0x8a,0xe1}, {0x75,0xa4,0xf6,0xeb},
+{0x39,0x0b,0x83,0xec}, {0xaa,0x40,0x60,0xef}, {0x06,0x5e,0x71,0x9f}, {0x51,0xbd,0x6e,0x10},
+{0xf9,0x3e,0x21,0x8a}, {0x3d,0x96,0xdd,0x06}, {0xae,0xdd,0x3e,0x05}, {0x46,0x4d,0xe6,0xbd},
+{0xb5,0x91,0x54,0x8d}, {0x05,0x71,0xc4,0x5d}, {0x6f,0x04,0x06,0xd4}, {0xff,0x60,0x50,0x15},
+{0x24,0x19,0x98,0xfb}, {0x97,0xd6,0xbd,0xe9}, {0xcc,0x89,0x40,0x43}, {0x77,0x67,0xd9,0x9e},
+{0xbd,0xb0,0xe8,0x42}, {0x88,0x07,0x89,0x8b}, {0x38,0xe7,0x19,0x5b}, {0xdb,0x79,0xc8,0xee},
+{0x47,0xa1,0x7c,0x0a}, {0xe9,0x7c,0x42,0x0f}, {0xc9,0xf8,0x84,0x1e}, {0x00,0x00,0x00,0x00},
+{0x83,0x09,0x80,0x86}, {0x48,0x32,0x2b,0xed}, {0xac,0x1e,0x11,0x70}, {0x4e,0x6c,0x5a,0x72},
+{0xfb,0xfd,0x0e,0xff}, {0x56,0x0f,0x85,0x38}, {0x1e,0x3d,0xae,0xd5}, {0x27,0x36,0x2d,0x39},
+{0x64,0x0a,0x0f,0xd9}, {0x21,0x68,0x5c,0xa6}, {0xd1,0x9b,0x5b,0x54}, {0x3a,0x24,0x36,0x2e},
+{0xb1,0x0c,0x0a,0x67}, {0x0f,0x93,0x57,0xe7}, {0xd2,0xb4,0xee,0x96}, {0x9e,0x1b,0x9b,0x91},
+{0x4f,0x80,0xc0,0xc5}, {0xa2,0x61,0xdc,0x20}, {0x69,0x5a,0x77,0x4b}, {0x16,0x1c,0x12,0x1a},
+{0x0a,0xe2,0x93,0xba}, {0xe5,0xc0,0xa0,0x2a}, {0x43,0x3c,0x22,0xe0}, {0x1d,0x12,0x1b,0x17},
+{0x0b,0x0e,0x09,0x0d}, {0xad,0xf2,0x8b,0xc7}, {0xb9,0x2d,0xb6,0xa8}, {0xc8,0x14,0x1e,0xa9},
+{0x85,0x57,0xf1,0x19}, {0x4c,0xaf,0x75,0x07}, {0xbb,0xee,0x99,0xdd}, {0xfd,0xa3,0x7f,0x60},
+{0x9f,0xf7,0x01,0x26}, {0xbc,0x5c,0x72,0xf5}, {0xc5,0x44,0x66,0x3b}, {0x34,0x5b,0xfb,0x7e},
+{0x76,0x8b,0x43,0x29}, {0xdc,0xcb,0x23,0xc6}, {0x68,0xb6,0xed,0xfc}, {0x63,0xb8,0xe4,0xf1},
+{0xca,0xd7,0x31,0xdc}, {0x10,0x42,0x63,0x85}, {0x40,0x13,0x97,0x22}, {0x20,0x84,0xc6,0x11},
+{0x7d,0x85,0x4a,0x24}, {0xf8,0xd2,0xbb,0x3d}, {0x11,0xae,0xf9,0x32}, {0x6d,0xc7,0x29,0xa1},
+{0x4b,0x1d,0x9e,0x2f}, {0xf3,0xdc,0xb2,0x30}, {0xec,0x0d,0x86,0x52}, {0xd0,0x77,0xc1,0xe3},
+{0x6c,0x2b,0xb3,0x16}, {0x99,0xa9,0x70,0xb9}, {0xfa,0x11,0x94,0x48}, {0x22,0x47,0xe9,0x64},
+{0xc4,0xa8,0xfc,0x8c}, {0x1a,0xa0,0xf0,0x3f}, {0xd8,0x56,0x7d,0x2c}, {0xef,0x22,0x33,0x90},
+{0xc7,0x87,0x49,0x4e}, {0xc1,0xd9,0x38,0xd1}, {0xfe,0x8c,0xca,0xa2}, {0x36,0x98,0xd4,0x0b},
+{0xcf,0xa6,0xf5,0x81}, {0x28,0xa5,0x7a,0xde}, {0x26,0xda,0xb7,0x8e}, {0xa4,0x3f,0xad,0xbf},
+{0xe4,0x2c,0x3a,0x9d}, {0x0d,0x50,0x78,0x92}, {0x9b,0x6a,0x5f,0xcc}, {0x62,0x54,0x7e,0x46},
+{0xc2,0xf6,0x8d,0x13}, {0xe8,0x90,0xd8,0xb8}, {0x5e,0x2e,0x39,0xf7}, {0xf5,0x82,0xc3,0xaf},
+{0xbe,0x9f,0x5d,0x80}, {0x7c,0x69,0xd0,0x93}, {0xa9,0x6f,0xd5,0x2d}, {0xb3,0xcf,0x25,0x12},
+{0x3b,0xc8,0xac,0x99}, {0xa7,0x10,0x18,0x7d}, {0x6e,0xe8,0x9c,0x63}, {0x7b,0xdb,0x3b,0xbb},
+{0x09,0xcd,0x26,0x78}, {0xf4,0x6e,0x59,0x18}, {0x01,0xec,0x9a,0xb7}, {0xa8,0x83,0x4f,0x9a},
+{0x65,0xe6,0x95,0x6e}, {0x7e,0xaa,0xff,0xe6}, {0x08,0x21,0xbc,0xcf}, {0xe6,0xef,0x15,0xe8},
+{0xd9,0xba,0xe7,0x9b}, {0xce,0x4a,0x6f,0x36}, {0xd4,0xea,0x9f,0x09}, {0xd6,0x29,0xb0,0x7c},
+{0xaf,0x31,0xa4,0xb2}, {0x31,0x2a,0x3f,0x23}, {0x30,0xc6,0xa5,0x94}, {0xc0,0x35,0xa2,0x66},
+{0x37,0x74,0x4e,0xbc}, {0xa6,0xfc,0x82,0xca}, {0xb0,0xe0,0x90,0xd0}, {0x15,0x33,0xa7,0xd8},
+{0x4a,0xf1,0x04,0x98}, {0xf7,0x41,0xec,0xda}, {0x0e,0x7f,0xcd,0x50}, {0x2f,0x17,0x91,0xf6},
+{0x8d,0x76,0x4d,0xd6}, {0x4d,0x43,0xef,0xb0}, {0x54,0xcc,0xaa,0x4d}, {0xdf,0xe4,0x96,0x04},
+{0xe3,0x9e,0xd1,0xb5}, {0x1b,0x4c,0x6a,0x88}, {0xb8,0xc1,0x2c,0x1f}, {0x7f,0x46,0x65,0x51},
+{0x04,0x9d,0x5e,0xea}, {0x5d,0x01,0x8c,0x35}, {0x73,0xfa,0x87,0x74}, {0x2e,0xfb,0x0b,0x41},
+{0x5a,0xb3,0x67,0x1d}, {0x52,0x92,0xdb,0xd2}, {0x33,0xe9,0x10,0x56}, {0x13,0x6d,0xd6,0x47},
+{0x8c,0x9a,0xd7,0x61}, {0x7a,0x37,0xa1,0x0c}, {0x8e,0x59,0xf8,0x14}, {0x89,0xeb,0x13,0x3c},
+{0xee,0xce,0xa9,0x27}, {0x35,0xb7,0x61,0xc9}, {0xed,0xe1,0x1c,0xe5}, {0x3c,0x7a,0x47,0xb1},
+{0x59,0x9c,0xd2,0xdf}, {0x3f,0x55,0xf2,0x73}, {0x79,0x18,0x14,0xce}, {0xbf,0x73,0xc7,0x37},
+{0xea,0x53,0xf7,0xcd}, {0x5b,0x5f,0xfd,0xaa}, {0x14,0xdf,0x3d,0x6f}, {0x86,0x78,0x44,0xdb},
+{0x81,0xca,0xaf,0xf3}, {0x3e,0xb9,0x68,0xc4}, {0x2c,0x38,0x24,0x34}, {0x5f,0xc2,0xa3,0x40},
+{0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95},
+{0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1},
+{0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57}
+       }
+};
+#define        T6      xT6.xt8
+
+static const union xtab xT7 = {
+       .xt8 = {
+{0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27},
+{0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3},
+{0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02},
+{0xd7,0xfc,0x4f,0xe5}, {0xcb,0xd7,0xc5,0x2a}, {0x44,0x80,0x26,0x35}, {0xa3,0x8f,0xb5,0x62},
+{0x5a,0x49,0xde,0xb1}, {0x1b,0x67,0x25,0xba}, {0x0e,0x98,0x45,0xea}, {0xc0,0xe1,0x5d,0xfe},
+{0x75,0x02,0xc3,0x2f}, {0xf0,0x12,0x81,0x4c}, {0x97,0xa3,0x8d,0x46}, {0xf9,0xc6,0x6b,0xd3},
+{0x5f,0xe7,0x03,0x8f}, {0x9c,0x95,0x15,0x92}, {0x7a,0xeb,0xbf,0x6d}, {0x59,0xda,0x95,0x52},
+{0x83,0x2d,0xd4,0xbe}, {0x21,0xd3,0x58,0x74}, {0x69,0x29,0x49,0xe0}, {0xc8,0x44,0x8e,0xc9},
+{0x89,0x6a,0x75,0xc2}, {0x79,0x78,0xf4,0x8e}, {0x3e,0x6b,0x99,0x58}, {0x71,0xdd,0x27,0xb9},
+{0x4f,0xb6,0xbe,0xe1}, {0xad,0x17,0xf0,0x88}, {0xac,0x66,0xc9,0x20}, {0x3a,0xb4,0x7d,0xce},
+{0x4a,0x18,0x63,0xdf}, {0x31,0x82,0xe5,0x1a}, {0x33,0x60,0x97,0x51}, {0x7f,0x45,0x62,0x53},
+{0x77,0xe0,0xb1,0x64}, {0xae,0x84,0xbb,0x6b}, {0xa0,0x1c,0xfe,0x81}, {0x2b,0x94,0xf9,0x08},
+{0x68,0x58,0x70,0x48}, {0xfd,0x19,0x8f,0x45}, {0x6c,0x87,0x94,0xde}, {0xf8,0xb7,0x52,0x7b},
+{0xd3,0x23,0xab,0x73}, {0x02,0xe2,0x72,0x4b}, {0x8f,0x57,0xe3,0x1f}, {0xab,0x2a,0x66,0x55},
+{0x28,0x07,0xb2,0xeb}, {0xc2,0x03,0x2f,0xb5}, {0x7b,0x9a,0x86,0xc5}, {0x08,0xa5,0xd3,0x37},
+{0x87,0xf2,0x30,0x28}, {0xa5,0xb2,0x23,0xbf}, {0x6a,0xba,0x02,0x03}, {0x82,0x5c,0xed,0x16},
+{0x1c,0x2b,0x8a,0xcf}, {0xb4,0x92,0xa7,0x79}, {0xf2,0xf0,0xf3,0x07}, {0xe2,0xa1,0x4e,0x69},
+{0xf4,0xcd,0x65,0xda}, {0xbe,0xd5,0x06,0x05}, {0x62,0x1f,0xd1,0x34}, {0xfe,0x8a,0xc4,0xa6},
+{0x53,0x9d,0x34,0x2e}, {0x55,0xa0,0xa2,0xf3}, {0xe1,0x32,0x05,0x8a}, {0xeb,0x75,0xa4,0xf6},
+{0xec,0x39,0x0b,0x83}, {0xef,0xaa,0x40,0x60}, {0x9f,0x06,0x5e,0x71}, {0x10,0x51,0xbd,0x6e},
+{0x8a,0xf9,0x3e,0x21}, {0x06,0x3d,0x96,0xdd}, {0x05,0xae,0xdd,0x3e}, {0xbd,0x46,0x4d,0xe6},
+{0x8d,0xb5,0x91,0x54}, {0x5d,0x05,0x71,0xc4}, {0xd4,0x6f,0x04,0x06}, {0x15,0xff,0x60,0x50},
+{0xfb,0x24,0x19,0x98}, {0xe9,0x97,0xd6,0xbd}, {0x43,0xcc,0x89,0x40}, {0x9e,0x77,0x67,0xd9},
+{0x42,0xbd,0xb0,0xe8}, {0x8b,0x88,0x07,0x89}, {0x5b,0x38,0xe7,0x19}, {0xee,0xdb,0x79,0xc8},
+{0x0a,0x47,0xa1,0x7c}, {0x0f,0xe9,0x7c,0x42}, {0x1e,0xc9,0xf8,0x84}, {0x00,0x00,0x00,0x00},
+{0x86,0x83,0x09,0x80}, {0xed,0x48,0x32,0x2b}, {0x70,0xac,0x1e,0x11}, {0x72,0x4e,0x6c,0x5a},
+{0xff,0xfb,0xfd,0x0e}, {0x38,0x56,0x0f,0x85}, {0xd5,0x1e,0x3d,0xae}, {0x39,0x27,0x36,0x2d},
+{0xd9,0x64,0x0a,0x0f}, {0xa6,0x21,0x68,0x5c}, {0x54,0xd1,0x9b,0x5b}, {0x2e,0x3a,0x24,0x36},
+{0x67,0xb1,0x0c,0x0a}, {0xe7,0x0f,0x93,0x57}, {0x96,0xd2,0xb4,0xee}, {0x91,0x9e,0x1b,0x9b},
+{0xc5,0x4f,0x80,0xc0}, {0x20,0xa2,0x61,0xdc}, {0x4b,0x69,0x5a,0x77}, {0x1a,0x16,0x1c,0x12},
+{0xba,0x0a,0xe2,0x93}, {0x2a,0xe5,0xc0,0xa0}, {0xe0,0x43,0x3c,0x22}, {0x17,0x1d,0x12,0x1b},
+{0x0d,0x0b,0x0e,0x09}, {0xc7,0xad,0xf2,0x8b}, {0xa8,0xb9,0x2d,0xb6}, {0xa9,0xc8,0x14,0x1e},
+{0x19,0x85,0x57,0xf1}, {0x07,0x4c,0xaf,0x75}, {0xdd,0xbb,0xee,0x99}, {0x60,0xfd,0xa3,0x7f},
+{0x26,0x9f,0xf7,0x01}, {0xf5,0xbc,0x5c,0x72}, {0x3b,0xc5,0x44,0x66}, {0x7e,0x34,0x5b,0xfb},
+{0x29,0x76,0x8b,0x43}, {0xc6,0xdc,0xcb,0x23}, {0xfc,0x68,0xb6,0xed}, {0xf1,0x63,0xb8,0xe4},
+{0xdc,0xca,0xd7,0x31}, {0x85,0x10,0x42,0x63}, {0x22,0x40,0x13,0x97}, {0x11,0x20,0x84,0xc6},
+{0x24,0x7d,0x85,0x4a}, {0x3d,0xf8,0xd2,0xbb}, {0x32,0x11,0xae,0xf9}, {0xa1,0x6d,0xc7,0x29},
+{0x2f,0x4b,0x1d,0x9e}, {0x30,0xf3,0xdc,0xb2}, {0x52,0xec,0x0d,0x86}, {0xe3,0xd0,0x77,0xc1},
+{0x16,0x6c,0x2b,0xb3}, {0xb9,0x99,0xa9,0x70}, {0x48,0xfa,0x11,0x94}, {0x64,0x22,0x47,0xe9},
+{0x8c,0xc4,0xa8,0xfc}, {0x3f,0x1a,0xa0,0xf0}, {0x2c,0xd8,0x56,0x7d}, {0x90,0xef,0x22,0x33},
+{0x4e,0xc7,0x87,0x49}, {0xd1,0xc1,0xd9,0x38}, {0xa2,0xfe,0x8c,0xca}, {0x0b,0x36,0x98,0xd4},
+{0x81,0xcf,0xa6,0xf5}, {0xde,0x28,0xa5,0x7a}, {0x8e,0x26,0xda,0xb7}, {0xbf,0xa4,0x3f,0xad},
+{0x9d,0xe4,0x2c,0x3a}, {0x92,0x0d,0x50,0x78}, {0xcc,0x9b,0x6a,0x5f}, {0x46,0x62,0x54,0x7e},
+{0x13,0xc2,0xf6,0x8d}, {0xb8,0xe8,0x90,0xd8}, {0xf7,0x5e,0x2e,0x39}, {0xaf,0xf5,0x82,0xc3},
+{0x80,0xbe,0x9f,0x5d}, {0x93,0x7c,0x69,0xd0}, {0x2d,0xa9,0x6f,0xd5}, {0x12,0xb3,0xcf,0x25},
+{0x99,0x3b,0xc8,0xac}, {0x7d,0xa7,0x10,0x18}, {0x63,0x6e,0xe8,0x9c}, {0xbb,0x7b,0xdb,0x3b},
+{0x78,0x09,0xcd,0x26}, {0x18,0xf4,0x6e,0x59}, {0xb7,0x01,0xec,0x9a}, {0x9a,0xa8,0x83,0x4f},
+{0x6e,0x65,0xe6,0x95}, {0xe6,0x7e,0xaa,0xff}, {0xcf,0x08,0x21,0xbc}, {0xe8,0xe6,0xef,0x15},
+{0x9b,0xd9,0xba,0xe7}, {0x36,0xce,0x4a,0x6f}, {0x09,0xd4,0xea,0x9f}, {0x7c,0xd6,0x29,0xb0},
+{0xb2,0xaf,0x31,0xa4}, {0x23,0x31,0x2a,0x3f}, {0x94,0x30,0xc6,0xa5}, {0x66,0xc0,0x35,0xa2},
+{0xbc,0x37,0x74,0x4e}, {0xca,0xa6,0xfc,0x82}, {0xd0,0xb0,0xe0,0x90}, {0xd8,0x15,0x33,0xa7},
+{0x98,0x4a,0xf1,0x04}, {0xda,0xf7,0x41,0xec}, {0x50,0x0e,0x7f,0xcd}, {0xf6,0x2f,0x17,0x91},
+{0xd6,0x8d,0x76,0x4d}, {0xb0,0x4d,0x43,0xef}, {0x4d,0x54,0xcc,0xaa}, {0x04,0xdf,0xe4,0x96},
+{0xb5,0xe3,0x9e,0xd1}, {0x88,0x1b,0x4c,0x6a}, {0x1f,0xb8,0xc1,0x2c}, {0x51,0x7f,0x46,0x65},
+{0xea,0x04,0x9d,0x5e}, {0x35,0x5d,0x01,0x8c}, {0x74,0x73,0xfa,0x87}, {0x41,0x2e,0xfb,0x0b},
+{0x1d,0x5a,0xb3,0x67}, {0xd2,0x52,0x92,0xdb}, {0x56,0x33,0xe9,0x10}, {0x47,0x13,0x6d,0xd6},
+{0x61,0x8c,0x9a,0xd7}, {0x0c,0x7a,0x37,0xa1}, {0x14,0x8e,0x59,0xf8}, {0x3c,0x89,0xeb,0x13},
+{0x27,0xee,0xce,0xa9}, {0xc9,0x35,0xb7,0x61}, {0xe5,0xed,0xe1,0x1c}, {0xb1,0x3c,0x7a,0x47},
+{0xdf,0x59,0x9c,0xd2}, {0x73,0x3f,0x55,0xf2}, {0xce,0x79,0x18,0x14}, {0x37,0xbf,0x73,0xc7},
+{0xcd,0xea,0x53,0xf7}, {0xaa,0x5b,0x5f,0xfd}, {0x6f,0x14,0xdf,0x3d}, {0xdb,0x86,0x78,0x44},
+{0xf3,0x81,0xca,0xaf}, {0xc4,0x3e,0xb9,0x68}, {0x34,0x2c,0x38,0x24}, {0x40,0x5f,0xc2,0xa3},
+{0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d},
+{0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56},
+{0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8}
+       }
+};
+#define        T7      xT7.xt8
+
+static const union xtab xT8 = {
+       .xt8 = {
+{0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a},
+{0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b},
+{0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5},
+{0xe5,0xd7,0xfc,0x4f}, {0x2a,0xcb,0xd7,0xc5}, {0x35,0x44,0x80,0x26}, {0x62,0xa3,0x8f,0xb5},
+{0xb1,0x5a,0x49,0xde}, {0xba,0x1b,0x67,0x25}, {0xea,0x0e,0x98,0x45}, {0xfe,0xc0,0xe1,0x5d},
+{0x2f,0x75,0x02,0xc3}, {0x4c,0xf0,0x12,0x81}, {0x46,0x97,0xa3,0x8d}, {0xd3,0xf9,0xc6,0x6b},
+{0x8f,0x5f,0xe7,0x03}, {0x92,0x9c,0x95,0x15}, {0x6d,0x7a,0xeb,0xbf}, {0x52,0x59,0xda,0x95},
+{0xbe,0x83,0x2d,0xd4}, {0x74,0x21,0xd3,0x58}, {0xe0,0x69,0x29,0x49}, {0xc9,0xc8,0x44,0x8e},
+{0xc2,0x89,0x6a,0x75}, {0x8e,0x79,0x78,0xf4}, {0x58,0x3e,0x6b,0x99}, {0xb9,0x71,0xdd,0x27},
+{0xe1,0x4f,0xb6,0xbe}, {0x88,0xad,0x17,0xf0}, {0x20,0xac,0x66,0xc9}, {0xce,0x3a,0xb4,0x7d},
+{0xdf,0x4a,0x18,0x63}, {0x1a,0x31,0x82,0xe5}, {0x51,0x33,0x60,0x97}, {0x53,0x7f,0x45,0x62},
+{0x64,0x77,0xe0,0xb1}, {0x6b,0xae,0x84,0xbb}, {0x81,0xa0,0x1c,0xfe}, {0x08,0x2b,0x94,0xf9},
+{0x48,0x68,0x58,0x70}, {0x45,0xfd,0x19,0x8f}, {0xde,0x6c,0x87,0x94}, {0x7b,0xf8,0xb7,0x52},
+{0x73,0xd3,0x23,0xab}, {0x4b,0x02,0xe2,0x72}, {0x1f,0x8f,0x57,0xe3}, {0x55,0xab,0x2a,0x66},
+{0xeb,0x28,0x07,0xb2}, {0xb5,0xc2,0x03,0x2f}, {0xc5,0x7b,0x9a,0x86}, {0x37,0x08,0xa5,0xd3},
+{0x28,0x87,0xf2,0x30}, {0xbf,0xa5,0xb2,0x23}, {0x03,0x6a,0xba,0x02}, {0x16,0x82,0x5c,0xed},
+{0xcf,0x1c,0x2b,0x8a}, {0x79,0xb4,0x92,0xa7}, {0x07,0xf2,0xf0,0xf3}, {0x69,0xe2,0xa1,0x4e},
+{0xda,0xf4,0xcd,0x65}, {0x05,0xbe,0xd5,0x06}, {0x34,0x62,0x1f,0xd1}, {0xa6,0xfe,0x8a,0xc4},
+{0x2e,0x53,0x9d,0x34}, {0xf3,0x55,0xa0,0xa2}, {0x8a,0xe1,0x32,0x05}, {0xf6,0xeb,0x75,0xa4},
+{0x83,0xec,0x39,0x0b}, {0x60,0xef,0xaa,0x40}, {0x71,0x9f,0x06,0x5e}, {0x6e,0x10,0x51,0xbd},
+{0x21,0x8a,0xf9,0x3e}, {0xdd,0x06,0x3d,0x96}, {0x3e,0x05,0xae,0xdd}, {0xe6,0xbd,0x46,0x4d},
+{0x54,0x8d,0xb5,0x91}, {0xc4,0x5d,0x05,0x71}, {0x06,0xd4,0x6f,0x04}, {0x50,0x15,0xff,0x60},
+{0x98,0xfb,0x24,0x19}, {0xbd,0xe9,0x97,0xd6}, {0x40,0x43,0xcc,0x89}, {0xd9,0x9e,0x77,0x67},
+{0xe8,0x42,0xbd,0xb0}, {0x89,0x8b,0x88,0x07}, {0x19,0x5b,0x38,0xe7}, {0xc8,0xee,0xdb,0x79},
+{0x7c,0x0a,0x47,0xa1}, {0x42,0x0f,0xe9,0x7c}, {0x84,0x1e,0xc9,0xf8}, {0x00,0x00,0x00,0x00},
+{0x80,0x86,0x83,0x09}, {0x2b,0xed,0x48,0x32}, {0x11,0x70,0xac,0x1e}, {0x5a,0x72,0x4e,0x6c},
+{0x0e,0xff,0xfb,0xfd}, {0x85,0x38,0x56,0x0f}, {0xae,0xd5,0x1e,0x3d}, {0x2d,0x39,0x27,0x36},
+{0x0f,0xd9,0x64,0x0a}, {0x5c,0xa6,0x21,0x68}, {0x5b,0x54,0xd1,0x9b}, {0x36,0x2e,0x3a,0x24},
+{0x0a,0x67,0xb1,0x0c}, {0x57,0xe7,0x0f,0x93}, {0xee,0x96,0xd2,0xb4}, {0x9b,0x91,0x9e,0x1b},
+{0xc0,0xc5,0x4f,0x80}, {0xdc,0x20,0xa2,0x61}, {0x77,0x4b,0x69,0x5a}, {0x12,0x1a,0x16,0x1c},
+{0x93,0xba,0x0a,0xe2}, {0xa0,0x2a,0xe5,0xc0}, {0x22,0xe0,0x43,0x3c}, {0x1b,0x17,0x1d,0x12},
+{0x09,0x0d,0x0b,0x0e}, {0x8b,0xc7,0xad,0xf2}, {0xb6,0xa8,0xb9,0x2d}, {0x1e,0xa9,0xc8,0x14},
+{0xf1,0x19,0x85,0x57}, {0x75,0x07,0x4c,0xaf}, {0x99,0xdd,0xbb,0xee}, {0x7f,0x60,0xfd,0xa3},
+{0x01,0x26,0x9f,0xf7}, {0x72,0xf5,0xbc,0x5c}, {0x66,0x3b,0xc5,0x44}, {0xfb,0x7e,0x34,0x5b},
+{0x43,0x29,0x76,0x8b}, {0x23,0xc6,0xdc,0xcb}, {0xed,0xfc,0x68,0xb6}, {0xe4,0xf1,0x63,0xb8},
+{0x31,0xdc,0xca,0xd7}, {0x63,0x85,0x10,0x42}, {0x97,0x22,0x40,0x13}, {0xc6,0x11,0x20,0x84},
+{0x4a,0x24,0x7d,0x85}, {0xbb,0x3d,0xf8,0xd2}, {0xf9,0x32,0x11,0xae}, {0x29,0xa1,0x6d,0xc7},
+{0x9e,0x2f,0x4b,0x1d}, {0xb2,0x30,0xf3,0xdc}, {0x86,0x52,0xec,0x0d}, {0xc1,0xe3,0xd0,0x77},
+{0xb3,0x16,0x6c,0x2b}, {0x70,0xb9,0x99,0xa9}, {0x94,0x48,0xfa,0x11}, {0xe9,0x64,0x22,0x47},
+{0xfc,0x8c,0xc4,0xa8}, {0xf0,0x3f,0x1a,0xa0}, {0x7d,0x2c,0xd8,0x56}, {0x33,0x90,0xef,0x22},
+{0x49,0x4e,0xc7,0x87}, {0x38,0xd1,0xc1,0xd9}, {0xca,0xa2,0xfe,0x8c}, {0xd4,0x0b,0x36,0x98},
+{0xf5,0x81,0xcf,0xa6}, {0x7a,0xde,0x28,0xa5}, {0xb7,0x8e,0x26,0xda}, {0xad,0xbf,0xa4,0x3f},
+{0x3a,0x9d,0xe4,0x2c}, {0x78,0x92,0x0d,0x50}, {0x5f,0xcc,0x9b,0x6a}, {0x7e,0x46,0x62,0x54},
+{0x8d,0x13,0xc2,0xf6}, {0xd8,0xb8,0xe8,0x90}, {0x39,0xf7,0x5e,0x2e}, {0xc3,0xaf,0xf5,0x82},
+{0x5d,0x80,0xbe,0x9f}, {0xd0,0x93,0x7c,0x69}, {0xd5,0x2d,0xa9,0x6f}, {0x25,0x12,0xb3,0xcf},
+{0xac,0x99,0x3b,0xc8}, {0x18,0x7d,0xa7,0x10}, {0x9c,0x63,0x6e,0xe8}, {0x3b,0xbb,0x7b,0xdb},
+{0x26,0x78,0x09,0xcd}, {0x59,0x18,0xf4,0x6e}, {0x9a,0xb7,0x01,0xec}, {0x4f,0x9a,0xa8,0x83},
+{0x95,0x6e,0x65,0xe6}, {0xff,0xe6,0x7e,0xaa}, {0xbc,0xcf,0x08,0x21}, {0x15,0xe8,0xe6,0xef},
+{0xe7,0x9b,0xd9,0xba}, {0x6f,0x36,0xce,0x4a}, {0x9f,0x09,0xd4,0xea}, {0xb0,0x7c,0xd6,0x29},
+{0xa4,0xb2,0xaf,0x31}, {0x3f,0x23,0x31,0x2a}, {0xa5,0x94,0x30,0xc6}, {0xa2,0x66,0xc0,0x35},
+{0x4e,0xbc,0x37,0x74}, {0x82,0xca,0xa6,0xfc}, {0x90,0xd0,0xb0,0xe0}, {0xa7,0xd8,0x15,0x33},
+{0x04,0x98,0x4a,0xf1}, {0xec,0xda,0xf7,0x41}, {0xcd,0x50,0x0e,0x7f}, {0x91,0xf6,0x2f,0x17},
+{0x4d,0xd6,0x8d,0x76}, {0xef,0xb0,0x4d,0x43}, {0xaa,0x4d,0x54,0xcc}, {0x96,0x04,0xdf,0xe4},
+{0xd1,0xb5,0xe3,0x9e}, {0x6a,0x88,0x1b,0x4c}, {0x2c,0x1f,0xb8,0xc1}, {0x65,0x51,0x7f,0x46},
+{0x5e,0xea,0x04,0x9d}, {0x8c,0x35,0x5d,0x01}, {0x87,0x74,0x73,0xfa}, {0x0b,0x41,0x2e,0xfb},
+{0x67,0x1d,0x5a,0xb3}, {0xdb,0xd2,0x52,0x92}, {0x10,0x56,0x33,0xe9}, {0xd6,0x47,0x13,0x6d},
+{0xd7,0x61,0x8c,0x9a}, {0xa1,0x0c,0x7a,0x37}, {0xf8,0x14,0x8e,0x59}, {0x13,0x3c,0x89,0xeb},
+{0xa9,0x27,0xee,0xce}, {0x61,0xc9,0x35,0xb7}, {0x1c,0xe5,0xed,0xe1}, {0x47,0xb1,0x3c,0x7a},
+{0xd2,0xdf,0x59,0x9c}, {0xf2,0x73,0x3f,0x55}, {0x14,0xce,0x79,0x18}, {0xc7,0x37,0xbf,0x73},
+{0xf7,0xcd,0xea,0x53}, {0xfd,0xaa,0x5b,0x5f}, {0x3d,0x6f,0x14,0xdf}, {0x44,0xdb,0x86,0x78},
+{0xaf,0xf3,0x81,0xca}, {0x68,0xc4,0x3e,0xb9}, {0x24,0x34,0x2c,0x38}, {0xa3,0x40,0x5f,0xc2},
+{0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff},
+{0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64},
+{0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0}
+       }
+};
+#define        T8      xT8.xt8
+
+static const word8 S5[256] = {
+0x52,0x09,0x6a,0xd5,
+0x30,0x36,0xa5,0x38,
+0xbf,0x40,0xa3,0x9e,
+0x81,0xf3,0xd7,0xfb,
+0x7c,0xe3,0x39,0x82,
+0x9b,0x2f,0xff,0x87,
+0x34,0x8e,0x43,0x44,
+0xc4,0xde,0xe9,0xcb,
+0x54,0x7b,0x94,0x32,
+0xa6,0xc2,0x23,0x3d,
+0xee,0x4c,0x95,0x0b,
+0x42,0xfa,0xc3,0x4e,
+0x08,0x2e,0xa1,0x66,
+0x28,0xd9,0x24,0xb2,
+0x76,0x5b,0xa2,0x49,
+0x6d,0x8b,0xd1,0x25,
+0x72,0xf8,0xf6,0x64,
+0x86,0x68,0x98,0x16,
+0xd4,0xa4,0x5c,0xcc,
+0x5d,0x65,0xb6,0x92,
+0x6c,0x70,0x48,0x50,
+0xfd,0xed,0xb9,0xda,
+0x5e,0x15,0x46,0x57,
+0xa7,0x8d,0x9d,0x84,
+0x90,0xd8,0xab,0x00,
+0x8c,0xbc,0xd3,0x0a,
+0xf7,0xe4,0x58,0x05,
+0xb8,0xb3,0x45,0x06,
+0xd0,0x2c,0x1e,0x8f,
+0xca,0x3f,0x0f,0x02,
+0xc1,0xaf,0xbd,0x03,
+0x01,0x13,0x8a,0x6b,
+0x3a,0x91,0x11,0x41,
+0x4f,0x67,0xdc,0xea,
+0x97,0xf2,0xcf,0xce,
+0xf0,0xb4,0xe6,0x73,
+0x96,0xac,0x74,0x22,
+0xe7,0xad,0x35,0x85,
+0xe2,0xf9,0x37,0xe8,
+0x1c,0x75,0xdf,0x6e,
+0x47,0xf1,0x1a,0x71,
+0x1d,0x29,0xc5,0x89,
+0x6f,0xb7,0x62,0x0e,
+0xaa,0x18,0xbe,0x1b,
+0xfc,0x56,0x3e,0x4b,
+0xc6,0xd2,0x79,0x20,
+0x9a,0xdb,0xc0,0xfe,
+0x78,0xcd,0x5a,0xf4,
+0x1f,0xdd,0xa8,0x33,
+0x88,0x07,0xc7,0x31,
+0xb1,0x12,0x10,0x59,
+0x27,0x80,0xec,0x5f,
+0x60,0x51,0x7f,0xa9,
+0x19,0xb5,0x4a,0x0d,
+0x2d,0xe5,0x7a,0x9f,
+0x93,0xc9,0x9c,0xef,
+0xa0,0xe0,0x3b,0x4d,
+0xae,0x2a,0xf5,0xb0,
+0xc8,0xeb,0xbb,0x3c,
+0x83,0x53,0x99,0x61,
+0x17,0x2b,0x04,0x7e,
+0xba,0x77,0xd6,0x26,
+0xe1,0x69,0x14,0x63,
+0x55,0x21,0x0c,0x7d
+};
+
+static const union xtab xU1 = {
+       .xt8 = {
+{0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d},
+{0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31},
+{0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45},
+{0x48,0x6c,0x5c,0x74}, {0x46,0x65,0x51,0x7f}, {0x54,0x7e,0x46,0x62}, {0x5a,0x77,0x4b,0x69},
+{0xe0,0x90,0xd0,0xb0}, {0xee,0x99,0xdd,0xbb}, {0xfc,0x82,0xca,0xa6}, {0xf2,0x8b,0xc7,0xad},
+{0xd8,0xb4,0xe4,0x9c}, {0xd6,0xbd,0xe9,0x97}, {0xc4,0xa6,0xfe,0x8a}, {0xca,0xaf,0xf3,0x81},
+{0x90,0xd8,0xb8,0xe8}, {0x9e,0xd1,0xb5,0xe3}, {0x8c,0xca,0xa2,0xfe}, {0x82,0xc3,0xaf,0xf5},
+{0xa8,0xfc,0x8c,0xc4}, {0xa6,0xf5,0x81,0xcf}, {0xb4,0xee,0x96,0xd2}, {0xba,0xe7,0x9b,0xd9},
+{0xdb,0x3b,0xbb,0x7b}, {0xd5,0x32,0xb6,0x70}, {0xc7,0x29,0xa1,0x6d}, {0xc9,0x20,0xac,0x66},
+{0xe3,0x1f,0x8f,0x57}, {0xed,0x16,0x82,0x5c}, {0xff,0x0d,0x95,0x41}, {0xf1,0x04,0x98,0x4a},
+{0xab,0x73,0xd3,0x23}, {0xa5,0x7a,0xde,0x28}, {0xb7,0x61,0xc9,0x35}, {0xb9,0x68,0xc4,0x3e},
+{0x93,0x57,0xe7,0x0f}, {0x9d,0x5e,0xea,0x04}, {0x8f,0x45,0xfd,0x19}, {0x81,0x4c,0xf0,0x12},
+{0x3b,0xab,0x6b,0xcb}, {0x35,0xa2,0x66,0xc0}, {0x27,0xb9,0x71,0xdd}, {0x29,0xb0,0x7c,0xd6},
+{0x03,0x8f,0x5f,0xe7}, {0x0d,0x86,0x52,0xec}, {0x1f,0x9d,0x45,0xf1}, {0x11,0x94,0x48,0xfa},
+{0x4b,0xe3,0x03,0x93}, {0x45,0xea,0x0e,0x98}, {0x57,0xf1,0x19,0x85}, {0x59,0xf8,0x14,0x8e},
+{0x73,0xc7,0x37,0xbf}, {0x7d,0xce,0x3a,0xb4}, {0x6f,0xd5,0x2d,0xa9}, {0x61,0xdc,0x20,0xa2},
+{0xad,0x76,0x6d,0xf6}, {0xa3,0x7f,0x60,0xfd}, {0xb1,0x64,0x77,0xe0}, {0xbf,0x6d,0x7a,0xeb},
+{0x95,0x52,0x59,0xda}, {0x9b,0x5b,0x54,0xd1}, {0x89,0x40,0x43,0xcc}, {0x87,0x49,0x4e,0xc7},
+{0xdd,0x3e,0x05,0xae}, {0xd3,0x37,0x08,0xa5}, {0xc1,0x2c,0x1f,0xb8}, {0xcf,0x25,0x12,0xb3},
+{0xe5,0x1a,0x31,0x82}, {0xeb,0x13,0x3c,0x89}, {0xf9,0x08,0x2b,0x94}, {0xf7,0x01,0x26,0x9f},
+{0x4d,0xe6,0xbd,0x46}, {0x43,0xef,0xb0,0x4d}, {0x51,0xf4,0xa7,0x50}, {0x5f,0xfd,0xaa,0x5b},
+{0x75,0xc2,0x89,0x6a}, {0x7b,0xcb,0x84,0x61}, {0x69,0xd0,0x93,0x7c}, {0x67,0xd9,0x9e,0x77},
+{0x3d,0xae,0xd5,0x1e}, {0x33,0xa7,0xd8,0x15}, {0x21,0xbc,0xcf,0x08}, {0x2f,0xb5,0xc2,0x03},
+{0x05,0x8a,0xe1,0x32}, {0x0b,0x83,0xec,0x39}, {0x19,0x98,0xfb,0x24}, {0x17,0x91,0xf6,0x2f},
+{0x76,0x4d,0xd6,0x8d}, {0x78,0x44,0xdb,0x86}, {0x6a,0x5f,0xcc,0x9b}, {0x64,0x56,0xc1,0x90},
+{0x4e,0x69,0xe2,0xa1}, {0x40,0x60,0xef,0xaa}, {0x52,0x7b,0xf8,0xb7}, {0x5c,0x72,0xf5,0xbc},
+{0x06,0x05,0xbe,0xd5}, {0x08,0x0c,0xb3,0xde}, {0x1a,0x17,0xa4,0xc3}, {0x14,0x1e,0xa9,0xc8},
+{0x3e,0x21,0x8a,0xf9}, {0x30,0x28,0x87,0xf2}, {0x22,0x33,0x90,0xef}, {0x2c,0x3a,0x9d,0xe4},
+{0x96,0xdd,0x06,0x3d}, {0x98,0xd4,0x0b,0x36}, {0x8a,0xcf,0x1c,0x2b}, {0x84,0xc6,0x11,0x20},
+{0xae,0xf9,0x32,0x11}, {0xa0,0xf0,0x3f,0x1a}, {0xb2,0xeb,0x28,0x07}, {0xbc,0xe2,0x25,0x0c},
+{0xe6,0x95,0x6e,0x65}, {0xe8,0x9c,0x63,0x6e}, {0xfa,0x87,0x74,0x73}, {0xf4,0x8e,0x79,0x78},
+{0xde,0xb1,0x5a,0x49}, {0xd0,0xb8,0x57,0x42}, {0xc2,0xa3,0x40,0x5f}, {0xcc,0xaa,0x4d,0x54},
+{0x41,0xec,0xda,0xf7}, {0x4f,0xe5,0xd7,0xfc}, {0x5d,0xfe,0xc0,0xe1}, {0x53,0xf7,0xcd,0xea},
+{0x79,0xc8,0xee,0xdb}, {0x77,0xc1,0xe3,0xd0}, {0x65,0xda,0xf4,0xcd}, {0x6b,0xd3,0xf9,0xc6},
+{0x31,0xa4,0xb2,0xaf}, {0x3f,0xad,0xbf,0xa4}, {0x2d,0xb6,0xa8,0xb9}, {0x23,0xbf,0xa5,0xb2},
+{0x09,0x80,0x86,0x83}, {0x07,0x89,0x8b,0x88}, {0x15,0x92,0x9c,0x95}, {0x1b,0x9b,0x91,0x9e},
+{0xa1,0x7c,0x0a,0x47}, {0xaf,0x75,0x07,0x4c}, {0xbd,0x6e,0x10,0x51}, {0xb3,0x67,0x1d,0x5a},
+{0x99,0x58,0x3e,0x6b}, {0x97,0x51,0x33,0x60}, {0x85,0x4a,0x24,0x7d}, {0x8b,0x43,0x29,0x76},
+{0xd1,0x34,0x62,0x1f}, {0xdf,0x3d,0x6f,0x14}, {0xcd,0x26,0x78,0x09}, {0xc3,0x2f,0x75,0x02},
+{0xe9,0x10,0x56,0x33}, {0xe7,0x19,0x5b,0x38}, {0xf5,0x02,0x4c,0x25}, {0xfb,0x0b,0x41,0x2e},
+{0x9a,0xd7,0x61,0x8c}, {0x94,0xde,0x6c,0x87}, {0x86,0xc5,0x7b,0x9a}, {0x88,0xcc,0x76,0x91},
+{0xa2,0xf3,0x55,0xa0}, {0xac,0xfa,0x58,0xab}, {0xbe,0xe1,0x4f,0xb6}, {0xb0,0xe8,0x42,0xbd},
+{0xea,0x9f,0x09,0xd4}, {0xe4,0x96,0x04,0xdf}, {0xf6,0x8d,0x13,0xc2}, {0xf8,0x84,0x1e,0xc9},
+{0xd2,0xbb,0x3d,0xf8}, {0xdc,0xb2,0x30,0xf3}, {0xce,0xa9,0x27,0xee}, {0xc0,0xa0,0x2a,0xe5},
+{0x7a,0x47,0xb1,0x3c}, {0x74,0x4e,0xbc,0x37}, {0x66,0x55,0xab,0x2a}, {0x68,0x5c,0xa6,0x21},
+{0x42,0x63,0x85,0x10}, {0x4c,0x6a,0x88,0x1b}, {0x5e,0x71,0x9f,0x06}, {0x50,0x78,0x92,0x0d},
+{0x0a,0x0f,0xd9,0x64}, {0x04,0x06,0xd4,0x6f}, {0x16,0x1d,0xc3,0x72}, {0x18,0x14,0xce,0x79},
+{0x32,0x2b,0xed,0x48}, {0x3c,0x22,0xe0,0x43}, {0x2e,0x39,0xf7,0x5e}, {0x20,0x30,0xfa,0x55},
+{0xec,0x9a,0xb7,0x01}, {0xe2,0x93,0xba,0x0a}, {0xf0,0x88,0xad,0x17}, {0xfe,0x81,0xa0,0x1c},
+{0xd4,0xbe,0x83,0x2d}, {0xda,0xb7,0x8e,0x26}, {0xc8,0xac,0x99,0x3b}, {0xc6,0xa5,0x94,0x30},
+{0x9c,0xd2,0xdf,0x59}, {0x92,0xdb,0xd2,0x52}, {0x80,0xc0,0xc5,0x4f}, {0x8e,0xc9,0xc8,0x44},
+{0xa4,0xf6,0xeb,0x75}, {0xaa,0xff,0xe6,0x7e}, {0xb8,0xe4,0xf1,0x63}, {0xb6,0xed,0xfc,0x68},
+{0x0c,0x0a,0x67,0xb1}, {0x02,0x03,0x6a,0xba}, {0x10,0x18,0x7d,0xa7}, {0x1e,0x11,0x70,0xac},
+{0x34,0x2e,0x53,0x9d}, {0x3a,0x27,0x5e,0x96}, {0x28,0x3c,0x49,0x8b}, {0x26,0x35,0x44,0x80},
+{0x7c,0x42,0x0f,0xe9}, {0x72,0x4b,0x02,0xe2}, {0x60,0x50,0x15,0xff}, {0x6e,0x59,0x18,0xf4},
+{0x44,0x66,0x3b,0xc5}, {0x4a,0x6f,0x36,0xce}, {0x58,0x74,0x21,0xd3}, {0x56,0x7d,0x2c,0xd8},
+{0x37,0xa1,0x0c,0x7a}, {0x39,0xa8,0x01,0x71}, {0x2b,0xb3,0x16,0x6c}, {0x25,0xba,0x1b,0x67},
+{0x0f,0x85,0x38,0x56}, {0x01,0x8c,0x35,0x5d}, {0x13,0x97,0x22,0x40}, {0x1d,0x9e,0x2f,0x4b},
+{0x47,0xe9,0x64,0x22}, {0x49,0xe0,0x69,0x29}, {0x5b,0xfb,0x7e,0x34}, {0x55,0xf2,0x73,0x3f},
+{0x7f,0xcd,0x50,0x0e}, {0x71,0xc4,0x5d,0x05}, {0x63,0xdf,0x4a,0x18}, {0x6d,0xd6,0x47,0x13},
+{0xd7,0x31,0xdc,0xca}, {0xd9,0x38,0xd1,0xc1}, {0xcb,0x23,0xc6,0xdc}, {0xc5,0x2a,0xcb,0xd7},
+{0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb},
+{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f},
+{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3}
+       }
+};
+#define        U1      xU1.xt8
+
+static const union xtab xU2 = {
+       .xt8 = {
+{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17},
+{0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23},
+{0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f},
+{0x74,0x48,0x6c,0x5c}, {0x7f,0x46,0x65,0x51}, {0x62,0x54,0x7e,0x46}, {0x69,0x5a,0x77,0x4b},
+{0xb0,0xe0,0x90,0xd0}, {0xbb,0xee,0x99,0xdd}, {0xa6,0xfc,0x82,0xca}, {0xad,0xf2,0x8b,0xc7},
+{0x9c,0xd8,0xb4,0xe4}, {0x97,0xd6,0xbd,0xe9}, {0x8a,0xc4,0xa6,0xfe}, {0x81,0xca,0xaf,0xf3},
+{0xe8,0x90,0xd8,0xb8}, {0xe3,0x9e,0xd1,0xb5}, {0xfe,0x8c,0xca,0xa2}, {0xf5,0x82,0xc3,0xaf},
+{0xc4,0xa8,0xfc,0x8c}, {0xcf,0xa6,0xf5,0x81}, {0xd2,0xb4,0xee,0x96}, {0xd9,0xba,0xe7,0x9b},
+{0x7b,0xdb,0x3b,0xbb}, {0x70,0xd5,0x32,0xb6}, {0x6d,0xc7,0x29,0xa1}, {0x66,0xc9,0x20,0xac},
+{0x57,0xe3,0x1f,0x8f}, {0x5c,0xed,0x16,0x82}, {0x41,0xff,0x0d,0x95}, {0x4a,0xf1,0x04,0x98},
+{0x23,0xab,0x73,0xd3}, {0x28,0xa5,0x7a,0xde}, {0x35,0xb7,0x61,0xc9}, {0x3e,0xb9,0x68,0xc4},
+{0x0f,0x93,0x57,0xe7}, {0x04,0x9d,0x5e,0xea}, {0x19,0x8f,0x45,0xfd}, {0x12,0x81,0x4c,0xf0},
+{0xcb,0x3b,0xab,0x6b}, {0xc0,0x35,0xa2,0x66}, {0xdd,0x27,0xb9,0x71}, {0xd6,0x29,0xb0,0x7c},
+{0xe7,0x03,0x8f,0x5f}, {0xec,0x0d,0x86,0x52}, {0xf1,0x1f,0x9d,0x45}, {0xfa,0x11,0x94,0x48},
+{0x93,0x4b,0xe3,0x03}, {0x98,0x45,0xea,0x0e}, {0x85,0x57,0xf1,0x19}, {0x8e,0x59,0xf8,0x14},
+{0xbf,0x73,0xc7,0x37}, {0xb4,0x7d,0xce,0x3a}, {0xa9,0x6f,0xd5,0x2d}, {0xa2,0x61,0xdc,0x20},
+{0xf6,0xad,0x76,0x6d}, {0xfd,0xa3,0x7f,0x60}, {0xe0,0xb1,0x64,0x77}, {0xeb,0xbf,0x6d,0x7a},
+{0xda,0x95,0x52,0x59}, {0xd1,0x9b,0x5b,0x54}, {0xcc,0x89,0x40,0x43}, {0xc7,0x87,0x49,0x4e},
+{0xae,0xdd,0x3e,0x05}, {0xa5,0xd3,0x37,0x08}, {0xb8,0xc1,0x2c,0x1f}, {0xb3,0xcf,0x25,0x12},
+{0x82,0xe5,0x1a,0x31}, {0x89,0xeb,0x13,0x3c}, {0x94,0xf9,0x08,0x2b}, {0x9f,0xf7,0x01,0x26},
+{0x46,0x4d,0xe6,0xbd}, {0x4d,0x43,0xef,0xb0}, {0x50,0x51,0xf4,0xa7}, {0x5b,0x5f,0xfd,0xaa},
+{0x6a,0x75,0xc2,0x89}, {0x61,0x7b,0xcb,0x84}, {0x7c,0x69,0xd0,0x93}, {0x77,0x67,0xd9,0x9e},
+{0x1e,0x3d,0xae,0xd5}, {0x15,0x33,0xa7,0xd8}, {0x08,0x21,0xbc,0xcf}, {0x03,0x2f,0xb5,0xc2},
+{0x32,0x05,0x8a,0xe1}, {0x39,0x0b,0x83,0xec}, {0x24,0x19,0x98,0xfb}, {0x2f,0x17,0x91,0xf6},
+{0x8d,0x76,0x4d,0xd6}, {0x86,0x78,0x44,0xdb}, {0x9b,0x6a,0x5f,0xcc}, {0x90,0x64,0x56,0xc1},
+{0xa1,0x4e,0x69,0xe2}, {0xaa,0x40,0x60,0xef}, {0xb7,0x52,0x7b,0xf8}, {0xbc,0x5c,0x72,0xf5},
+{0xd5,0x06,0x05,0xbe}, {0xde,0x08,0x0c,0xb3}, {0xc3,0x1a,0x17,0xa4}, {0xc8,0x14,0x1e,0xa9},
+{0xf9,0x3e,0x21,0x8a}, {0xf2,0x30,0x28,0x87}, {0xef,0x22,0x33,0x90}, {0xe4,0x2c,0x3a,0x9d},
+{0x3d,0x96,0xdd,0x06}, {0x36,0x98,0xd4,0x0b}, {0x2b,0x8a,0xcf,0x1c}, {0x20,0x84,0xc6,0x11},
+{0x11,0xae,0xf9,0x32}, {0x1a,0xa0,0xf0,0x3f}, {0x07,0xb2,0xeb,0x28}, {0x0c,0xbc,0xe2,0x25},
+{0x65,0xe6,0x95,0x6e}, {0x6e,0xe8,0x9c,0x63}, {0x73,0xfa,0x87,0x74}, {0x78,0xf4,0x8e,0x79},
+{0x49,0xde,0xb1,0x5a}, {0x42,0xd0,0xb8,0x57}, {0x5f,0xc2,0xa3,0x40}, {0x54,0xcc,0xaa,0x4d},
+{0xf7,0x41,0xec,0xda}, {0xfc,0x4f,0xe5,0xd7}, {0xe1,0x5d,0xfe,0xc0}, {0xea,0x53,0xf7,0xcd},
+{0xdb,0x79,0xc8,0xee}, {0xd0,0x77,0xc1,0xe3}, {0xcd,0x65,0xda,0xf4}, {0xc6,0x6b,0xd3,0xf9},
+{0xaf,0x31,0xa4,0xb2}, {0xa4,0x3f,0xad,0xbf}, {0xb9,0x2d,0xb6,0xa8}, {0xb2,0x23,0xbf,0xa5},
+{0x83,0x09,0x80,0x86}, {0x88,0x07,0x89,0x8b}, {0x95,0x15,0x92,0x9c}, {0x9e,0x1b,0x9b,0x91},
+{0x47,0xa1,0x7c,0x0a}, {0x4c,0xaf,0x75,0x07}, {0x51,0xbd,0x6e,0x10}, {0x5a,0xb3,0x67,0x1d},
+{0x6b,0x99,0x58,0x3e}, {0x60,0x97,0x51,0x33}, {0x7d,0x85,0x4a,0x24}, {0x76,0x8b,0x43,0x29},
+{0x1f,0xd1,0x34,0x62}, {0x14,0xdf,0x3d,0x6f}, {0x09,0xcd,0x26,0x78}, {0x02,0xc3,0x2f,0x75},
+{0x33,0xe9,0x10,0x56}, {0x38,0xe7,0x19,0x5b}, {0x25,0xf5,0x02,0x4c}, {0x2e,0xfb,0x0b,0x41},
+{0x8c,0x9a,0xd7,0x61}, {0x87,0x94,0xde,0x6c}, {0x9a,0x86,0xc5,0x7b}, {0x91,0x88,0xcc,0x76},
+{0xa0,0xa2,0xf3,0x55}, {0xab,0xac,0xfa,0x58}, {0xb6,0xbe,0xe1,0x4f}, {0xbd,0xb0,0xe8,0x42},
+{0xd4,0xea,0x9f,0x09}, {0xdf,0xe4,0x96,0x04}, {0xc2,0xf6,0x8d,0x13}, {0xc9,0xf8,0x84,0x1e},
+{0xf8,0xd2,0xbb,0x3d}, {0xf3,0xdc,0xb2,0x30}, {0xee,0xce,0xa9,0x27}, {0xe5,0xc0,0xa0,0x2a},
+{0x3c,0x7a,0x47,0xb1}, {0x37,0x74,0x4e,0xbc}, {0x2a,0x66,0x55,0xab}, {0x21,0x68,0x5c,0xa6},
+{0x10,0x42,0x63,0x85}, {0x1b,0x4c,0x6a,0x88}, {0x06,0x5e,0x71,0x9f}, {0x0d,0x50,0x78,0x92},
+{0x64,0x0a,0x0f,0xd9}, {0x6f,0x04,0x06,0xd4}, {0x72,0x16,0x1d,0xc3}, {0x79,0x18,0x14,0xce},
+{0x48,0x32,0x2b,0xed}, {0x43,0x3c,0x22,0xe0}, {0x5e,0x2e,0x39,0xf7}, {0x55,0x20,0x30,0xfa},
+{0x01,0xec,0x9a,0xb7}, {0x0a,0xe2,0x93,0xba}, {0x17,0xf0,0x88,0xad}, {0x1c,0xfe,0x81,0xa0},
+{0x2d,0xd4,0xbe,0x83}, {0x26,0xda,0xb7,0x8e}, {0x3b,0xc8,0xac,0x99}, {0x30,0xc6,0xa5,0x94},
+{0x59,0x9c,0xd2,0xdf}, {0x52,0x92,0xdb,0xd2}, {0x4f,0x80,0xc0,0xc5}, {0x44,0x8e,0xc9,0xc8},
+{0x75,0xa4,0xf6,0xeb}, {0x7e,0xaa,0xff,0xe6}, {0x63,0xb8,0xe4,0xf1}, {0x68,0xb6,0xed,0xfc},
+{0xb1,0x0c,0x0a,0x67}, {0xba,0x02,0x03,0x6a}, {0xa7,0x10,0x18,0x7d}, {0xac,0x1e,0x11,0x70},
+{0x9d,0x34,0x2e,0x53}, {0x96,0x3a,0x27,0x5e}, {0x8b,0x28,0x3c,0x49}, {0x80,0x26,0x35,0x44},
+{0xe9,0x7c,0x42,0x0f}, {0xe2,0x72,0x4b,0x02}, {0xff,0x60,0x50,0x15}, {0xf4,0x6e,0x59,0x18},
+{0xc5,0x44,0x66,0x3b}, {0xce,0x4a,0x6f,0x36}, {0xd3,0x58,0x74,0x21}, {0xd8,0x56,0x7d,0x2c},
+{0x7a,0x37,0xa1,0x0c}, {0x71,0x39,0xa8,0x01}, {0x6c,0x2b,0xb3,0x16}, {0x67,0x25,0xba,0x1b},
+{0x56,0x0f,0x85,0x38}, {0x5d,0x01,0x8c,0x35}, {0x40,0x13,0x97,0x22}, {0x4b,0x1d,0x9e,0x2f},
+{0x22,0x47,0xe9,0x64}, {0x29,0x49,0xe0,0x69}, {0x34,0x5b,0xfb,0x7e}, {0x3f,0x55,0xf2,0x73},
+{0x0e,0x7f,0xcd,0x50}, {0x05,0x71,0xc4,0x5d}, {0x18,0x63,0xdf,0x4a}, {0x13,0x6d,0xd6,0x47},
+{0xca,0xd7,0x31,0xdc}, {0xc1,0xd9,0x38,0xd1}, {0xdc,0xcb,0x23,0xc6}, {0xd7,0xc5,0x2a,0xcb},
+{0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff},
+{0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3},
+{0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97}
+       }
+};
+#define        U2      xU2.xt8
+
+static const union xtab xU3 = {
+       .xt8 = {
+{0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b},
+{0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f},
+{0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53},
+{0x5c,0x74,0x48,0x6c}, {0x51,0x7f,0x46,0x65}, {0x46,0x62,0x54,0x7e}, {0x4b,0x69,0x5a,0x77},
+{0xd0,0xb0,0xe0,0x90}, {0xdd,0xbb,0xee,0x99}, {0xca,0xa6,0xfc,0x82}, {0xc7,0xad,0xf2,0x8b},
+{0xe4,0x9c,0xd8,0xb4}, {0xe9,0x97,0xd6,0xbd}, {0xfe,0x8a,0xc4,0xa6}, {0xf3,0x81,0xca,0xaf},
+{0xb8,0xe8,0x90,0xd8}, {0xb5,0xe3,0x9e,0xd1}, {0xa2,0xfe,0x8c,0xca}, {0xaf,0xf5,0x82,0xc3},
+{0x8c,0xc4,0xa8,0xfc}, {0x81,0xcf,0xa6,0xf5}, {0x96,0xd2,0xb4,0xee}, {0x9b,0xd9,0xba,0xe7},
+{0xbb,0x7b,0xdb,0x3b}, {0xb6,0x70,0xd5,0x32}, {0xa1,0x6d,0xc7,0x29}, {0xac,0x66,0xc9,0x20},
+{0x8f,0x57,0xe3,0x1f}, {0x82,0x5c,0xed,0x16}, {0x95,0x41,0xff,0x0d}, {0x98,0x4a,0xf1,0x04},
+{0xd3,0x23,0xab,0x73}, {0xde,0x28,0xa5,0x7a}, {0xc9,0x35,0xb7,0x61}, {0xc4,0x3e,0xb9,0x68},
+{0xe7,0x0f,0x93,0x57}, {0xea,0x04,0x9d,0x5e}, {0xfd,0x19,0x8f,0x45}, {0xf0,0x12,0x81,0x4c},
+{0x6b,0xcb,0x3b,0xab}, {0x66,0xc0,0x35,0xa2}, {0x71,0xdd,0x27,0xb9}, {0x7c,0xd6,0x29,0xb0},
+{0x5f,0xe7,0x03,0x8f}, {0x52,0xec,0x0d,0x86}, {0x45,0xf1,0x1f,0x9d}, {0x48,0xfa,0x11,0x94},
+{0x03,0x93,0x4b,0xe3}, {0x0e,0x98,0x45,0xea}, {0x19,0x85,0x57,0xf1}, {0x14,0x8e,0x59,0xf8},
+{0x37,0xbf,0x73,0xc7}, {0x3a,0xb4,0x7d,0xce}, {0x2d,0xa9,0x6f,0xd5}, {0x20,0xa2,0x61,0xdc},
+{0x6d,0xf6,0xad,0x76}, {0x60,0xfd,0xa3,0x7f}, {0x77,0xe0,0xb1,0x64}, {0x7a,0xeb,0xbf,0x6d},
+{0x59,0xda,0x95,0x52}, {0x54,0xd1,0x9b,0x5b}, {0x43,0xcc,0x89,0x40}, {0x4e,0xc7,0x87,0x49},
+{0x05,0xae,0xdd,0x3e}, {0x08,0xa5,0xd3,0x37}, {0x1f,0xb8,0xc1,0x2c}, {0x12,0xb3,0xcf,0x25},
+{0x31,0x82,0xe5,0x1a}, {0x3c,0x89,0xeb,0x13}, {0x2b,0x94,0xf9,0x08}, {0x26,0x9f,0xf7,0x01},
+{0xbd,0x46,0x4d,0xe6}, {0xb0,0x4d,0x43,0xef}, {0xa7,0x50,0x51,0xf4}, {0xaa,0x5b,0x5f,0xfd},
+{0x89,0x6a,0x75,0xc2}, {0x84,0x61,0x7b,0xcb}, {0x93,0x7c,0x69,0xd0}, {0x9e,0x77,0x67,0xd9},
+{0xd5,0x1e,0x3d,0xae}, {0xd8,0x15,0x33,0xa7}, {0xcf,0x08,0x21,0xbc}, {0xc2,0x03,0x2f,0xb5},
+{0xe1,0x32,0x05,0x8a}, {0xec,0x39,0x0b,0x83}, {0xfb,0x24,0x19,0x98}, {0xf6,0x2f,0x17,0x91},
+{0xd6,0x8d,0x76,0x4d}, {0xdb,0x86,0x78,0x44}, {0xcc,0x9b,0x6a,0x5f}, {0xc1,0x90,0x64,0x56},
+{0xe2,0xa1,0x4e,0x69}, {0xef,0xaa,0x40,0x60}, {0xf8,0xb7,0x52,0x7b}, {0xf5,0xbc,0x5c,0x72},
+{0xbe,0xd5,0x06,0x05}, {0xb3,0xde,0x08,0x0c}, {0xa4,0xc3,0x1a,0x17}, {0xa9,0xc8,0x14,0x1e},
+{0x8a,0xf9,0x3e,0x21}, {0x87,0xf2,0x30,0x28}, {0x90,0xef,0x22,0x33}, {0x9d,0xe4,0x2c,0x3a},
+{0x06,0x3d,0x96,0xdd}, {0x0b,0x36,0x98,0xd4}, {0x1c,0x2b,0x8a,0xcf}, {0x11,0x20,0x84,0xc6},
+{0x32,0x11,0xae,0xf9}, {0x3f,0x1a,0xa0,0xf0}, {0x28,0x07,0xb2,0xeb}, {0x25,0x0c,0xbc,0xe2},
+{0x6e,0x65,0xe6,0x95}, {0x63,0x6e,0xe8,0x9c}, {0x74,0x73,0xfa,0x87}, {0x79,0x78,0xf4,0x8e},
+{0x5a,0x49,0xde,0xb1}, {0x57,0x42,0xd0,0xb8}, {0x40,0x5f,0xc2,0xa3}, {0x4d,0x54,0xcc,0xaa},
+{0xda,0xf7,0x41,0xec}, {0xd7,0xfc,0x4f,0xe5}, {0xc0,0xe1,0x5d,0xfe}, {0xcd,0xea,0x53,0xf7},
+{0xee,0xdb,0x79,0xc8}, {0xe3,0xd0,0x77,0xc1}, {0xf4,0xcd,0x65,0xda}, {0xf9,0xc6,0x6b,0xd3},
+{0xb2,0xaf,0x31,0xa4}, {0xbf,0xa4,0x3f,0xad}, {0xa8,0xb9,0x2d,0xb6}, {0xa5,0xb2,0x23,0xbf},
+{0x86,0x83,0x09,0x80}, {0x8b,0x88,0x07,0x89}, {0x9c,0x95,0x15,0x92}, {0x91,0x9e,0x1b,0x9b},
+{0x0a,0x47,0xa1,0x7c}, {0x07,0x4c,0xaf,0x75}, {0x10,0x51,0xbd,0x6e}, {0x1d,0x5a,0xb3,0x67},
+{0x3e,0x6b,0x99,0x58}, {0x33,0x60,0x97,0x51}, {0x24,0x7d,0x85,0x4a}, {0x29,0x76,0x8b,0x43},
+{0x62,0x1f,0xd1,0x34}, {0x6f,0x14,0xdf,0x3d}, {0x78,0x09,0xcd,0x26}, {0x75,0x02,0xc3,0x2f},
+{0x56,0x33,0xe9,0x10}, {0x5b,0x38,0xe7,0x19}, {0x4c,0x25,0xf5,0x02}, {0x41,0x2e,0xfb,0x0b},
+{0x61,0x8c,0x9a,0xd7}, {0x6c,0x87,0x94,0xde}, {0x7b,0x9a,0x86,0xc5}, {0x76,0x91,0x88,0xcc},
+{0x55,0xa0,0xa2,0xf3}, {0x58,0xab,0xac,0xfa}, {0x4f,0xb6,0xbe,0xe1}, {0x42,0xbd,0xb0,0xe8},
+{0x09,0xd4,0xea,0x9f}, {0x04,0xdf,0xe4,0x96}, {0x13,0xc2,0xf6,0x8d}, {0x1e,0xc9,0xf8,0x84},
+{0x3d,0xf8,0xd2,0xbb}, {0x30,0xf3,0xdc,0xb2}, {0x27,0xee,0xce,0xa9}, {0x2a,0xe5,0xc0,0xa0},
+{0xb1,0x3c,0x7a,0x47}, {0xbc,0x37,0x74,0x4e}, {0xab,0x2a,0x66,0x55}, {0xa6,0x21,0x68,0x5c},
+{0x85,0x10,0x42,0x63}, {0x88,0x1b,0x4c,0x6a}, {0x9f,0x06,0x5e,0x71}, {0x92,0x0d,0x50,0x78},
+{0xd9,0x64,0x0a,0x0f}, {0xd4,0x6f,0x04,0x06}, {0xc3,0x72,0x16,0x1d}, {0xce,0x79,0x18,0x14},
+{0xed,0x48,0x32,0x2b}, {0xe0,0x43,0x3c,0x22}, {0xf7,0x5e,0x2e,0x39}, {0xfa,0x55,0x20,0x30},
+{0xb7,0x01,0xec,0x9a}, {0xba,0x0a,0xe2,0x93}, {0xad,0x17,0xf0,0x88}, {0xa0,0x1c,0xfe,0x81},
+{0x83,0x2d,0xd4,0xbe}, {0x8e,0x26,0xda,0xb7}, {0x99,0x3b,0xc8,0xac}, {0x94,0x30,0xc6,0xa5},
+{0xdf,0x59,0x9c,0xd2}, {0xd2,0x52,0x92,0xdb}, {0xc5,0x4f,0x80,0xc0}, {0xc8,0x44,0x8e,0xc9},
+{0xeb,0x75,0xa4,0xf6}, {0xe6,0x7e,0xaa,0xff}, {0xf1,0x63,0xb8,0xe4}, {0xfc,0x68,0xb6,0xed},
+{0x67,0xb1,0x0c,0x0a}, {0x6a,0xba,0x02,0x03}, {0x7d,0xa7,0x10,0x18}, {0x70,0xac,0x1e,0x11},
+{0x53,0x9d,0x34,0x2e}, {0x5e,0x96,0x3a,0x27}, {0x49,0x8b,0x28,0x3c}, {0x44,0x80,0x26,0x35},
+{0x0f,0xe9,0x7c,0x42}, {0x02,0xe2,0x72,0x4b}, {0x15,0xff,0x60,0x50}, {0x18,0xf4,0x6e,0x59},
+{0x3b,0xc5,0x44,0x66}, {0x36,0xce,0x4a,0x6f}, {0x21,0xd3,0x58,0x74}, {0x2c,0xd8,0x56,0x7d},
+{0x0c,0x7a,0x37,0xa1}, {0x01,0x71,0x39,0xa8}, {0x16,0x6c,0x2b,0xb3}, {0x1b,0x67,0x25,0xba},
+{0x38,0x56,0x0f,0x85}, {0x35,0x5d,0x01,0x8c}, {0x22,0x40,0x13,0x97}, {0x2f,0x4b,0x1d,0x9e},
+{0x64,0x22,0x47,0xe9}, {0x69,0x29,0x49,0xe0}, {0x7e,0x34,0x5b,0xfb}, {0x73,0x3f,0x55,0xf2},
+{0x50,0x0e,0x7f,0xcd}, {0x5d,0x05,0x71,0xc4}, {0x4a,0x18,0x63,0xdf}, {0x47,0x13,0x6d,0xd6},
+{0xdc,0xca,0xd7,0x31}, {0xd1,0xc1,0xd9,0x38}, {0xc6,0xdc,0xcb,0x23}, {0xcb,0xd7,0xc5,0x2a},
+{0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e},
+{0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62},
+{0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46}
+       }
+};
+#define        U3      xU3.xt8
+
+static const union xtab xU4 = {
+       .xt8 = {
+{0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12},
+{0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a},
+{0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62},
+{0x6c,0x5c,0x74,0x48}, {0x65,0x51,0x7f,0x46}, {0x7e,0x46,0x62,0x54}, {0x77,0x4b,0x69,0x5a},
+{0x90,0xd0,0xb0,0xe0}, {0x99,0xdd,0xbb,0xee}, {0x82,0xca,0xa6,0xfc}, {0x8b,0xc7,0xad,0xf2},
+{0xb4,0xe4,0x9c,0xd8}, {0xbd,0xe9,0x97,0xd6}, {0xa6,0xfe,0x8a,0xc4}, {0xaf,0xf3,0x81,0xca},
+{0xd8,0xb8,0xe8,0x90}, {0xd1,0xb5,0xe3,0x9e}, {0xca,0xa2,0xfe,0x8c}, {0xc3,0xaf,0xf5,0x82},
+{0xfc,0x8c,0xc4,0xa8}, {0xf5,0x81,0xcf,0xa6}, {0xee,0x96,0xd2,0xb4}, {0xe7,0x9b,0xd9,0xba},
+{0x3b,0xbb,0x7b,0xdb}, {0x32,0xb6,0x70,0xd5}, {0x29,0xa1,0x6d,0xc7}, {0x20,0xac,0x66,0xc9},
+{0x1f,0x8f,0x57,0xe3}, {0x16,0x82,0x5c,0xed}, {0x0d,0x95,0x41,0xff}, {0x04,0x98,0x4a,0xf1},
+{0x73,0xd3,0x23,0xab}, {0x7a,0xde,0x28,0xa5}, {0x61,0xc9,0x35,0xb7}, {0x68,0xc4,0x3e,0xb9},
+{0x57,0xe7,0x0f,0x93}, {0x5e,0xea,0x04,0x9d}, {0x45,0xfd,0x19,0x8f}, {0x4c,0xf0,0x12,0x81},
+{0xab,0x6b,0xcb,0x3b}, {0xa2,0x66,0xc0,0x35}, {0xb9,0x71,0xdd,0x27}, {0xb0,0x7c,0xd6,0x29},
+{0x8f,0x5f,0xe7,0x03}, {0x86,0x52,0xec,0x0d}, {0x9d,0x45,0xf1,0x1f}, {0x94,0x48,0xfa,0x11},
+{0xe3,0x03,0x93,0x4b}, {0xea,0x0e,0x98,0x45}, {0xf1,0x19,0x85,0x57}, {0xf8,0x14,0x8e,0x59},
+{0xc7,0x37,0xbf,0x73}, {0xce,0x3a,0xb4,0x7d}, {0xd5,0x2d,0xa9,0x6f}, {0xdc,0x20,0xa2,0x61},
+{0x76,0x6d,0xf6,0xad}, {0x7f,0x60,0xfd,0xa3}, {0x64,0x77,0xe0,0xb1}, {0x6d,0x7a,0xeb,0xbf},
+{0x52,0x59,0xda,0x95}, {0x5b,0x54,0xd1,0x9b}, {0x40,0x43,0xcc,0x89}, {0x49,0x4e,0xc7,0x87},
+{0x3e,0x05,0xae,0xdd}, {0x37,0x08,0xa5,0xd3}, {0x2c,0x1f,0xb8,0xc1}, {0x25,0x12,0xb3,0xcf},
+{0x1a,0x31,0x82,0xe5}, {0x13,0x3c,0x89,0xeb}, {0x08,0x2b,0x94,0xf9}, {0x01,0x26,0x9f,0xf7},
+{0xe6,0xbd,0x46,0x4d}, {0xef,0xb0,0x4d,0x43}, {0xf4,0xa7,0x50,0x51}, {0xfd,0xaa,0x5b,0x5f},
+{0xc2,0x89,0x6a,0x75}, {0xcb,0x84,0x61,0x7b}, {0xd0,0x93,0x7c,0x69}, {0xd9,0x9e,0x77,0x67},
+{0xae,0xd5,0x1e,0x3d}, {0xa7,0xd8,0x15,0x33}, {0xbc,0xcf,0x08,0x21}, {0xb5,0xc2,0x03,0x2f},
+{0x8a,0xe1,0x32,0x05}, {0x83,0xec,0x39,0x0b}, {0x98,0xfb,0x24,0x19}, {0x91,0xf6,0x2f,0x17},
+{0x4d,0xd6,0x8d,0x76}, {0x44,0xdb,0x86,0x78}, {0x5f,0xcc,0x9b,0x6a}, {0x56,0xc1,0x90,0x64},
+{0x69,0xe2,0xa1,0x4e}, {0x60,0xef,0xaa,0x40}, {0x7b,0xf8,0xb7,0x52}, {0x72,0xf5,0xbc,0x5c},
+{0x05,0xbe,0xd5,0x06}, {0x0c,0xb3,0xde,0x08}, {0x17,0xa4,0xc3,0x1a}, {0x1e,0xa9,0xc8,0x14},
+{0x21,0x8a,0xf9,0x3e}, {0x28,0x87,0xf2,0x30}, {0x33,0x90,0xef,0x22}, {0x3a,0x9d,0xe4,0x2c},
+{0xdd,0x06,0x3d,0x96}, {0xd4,0x0b,0x36,0x98}, {0xcf,0x1c,0x2b,0x8a}, {0xc6,0x11,0x20,0x84},
+{0xf9,0x32,0x11,0xae}, {0xf0,0x3f,0x1a,0xa0}, {0xeb,0x28,0x07,0xb2}, {0xe2,0x25,0x0c,0xbc},
+{0x95,0x6e,0x65,0xe6}, {0x9c,0x63,0x6e,0xe8}, {0x87,0x74,0x73,0xfa}, {0x8e,0x79,0x78,0xf4},
+{0xb1,0x5a,0x49,0xde}, {0xb8,0x57,0x42,0xd0}, {0xa3,0x40,0x5f,0xc2}, {0xaa,0x4d,0x54,0xcc},
+{0xec,0xda,0xf7,0x41}, {0xe5,0xd7,0xfc,0x4f}, {0xfe,0xc0,0xe1,0x5d}, {0xf7,0xcd,0xea,0x53},
+{0xc8,0xee,0xdb,0x79}, {0xc1,0xe3,0xd0,0x77}, {0xda,0xf4,0xcd,0x65}, {0xd3,0xf9,0xc6,0x6b},
+{0xa4,0xb2,0xaf,0x31}, {0xad,0xbf,0xa4,0x3f}, {0xb6,0xa8,0xb9,0x2d}, {0xbf,0xa5,0xb2,0x23},
+{0x80,0x86,0x83,0x09}, {0x89,0x8b,0x88,0x07}, {0x92,0x9c,0x95,0x15}, {0x9b,0x91,0x9e,0x1b},
+{0x7c,0x0a,0x47,0xa1}, {0x75,0x07,0x4c,0xaf}, {0x6e,0x10,0x51,0xbd}, {0x67,0x1d,0x5a,0xb3},
+{0x58,0x3e,0x6b,0x99}, {0x51,0x33,0x60,0x97}, {0x4a,0x24,0x7d,0x85}, {0x43,0x29,0x76,0x8b},
+{0x34,0x62,0x1f,0xd1}, {0x3d,0x6f,0x14,0xdf}, {0x26,0x78,0x09,0xcd}, {0x2f,0x75,0x02,0xc3},
+{0x10,0x56,0x33,0xe9}, {0x19,0x5b,0x38,0xe7}, {0x02,0x4c,0x25,0xf5}, {0x0b,0x41,0x2e,0xfb},
+{0xd7,0x61,0x8c,0x9a}, {0xde,0x6c,0x87,0x94}, {0xc5,0x7b,0x9a,0x86}, {0xcc,0x76,0x91,0x88},
+{0xf3,0x55,0xa0,0xa2}, {0xfa,0x58,0xab,0xac}, {0xe1,0x4f,0xb6,0xbe}, {0xe8,0x42,0xbd,0xb0},
+{0x9f,0x09,0xd4,0xea}, {0x96,0x04,0xdf,0xe4}, {0x8d,0x13,0xc2,0xf6}, {0x84,0x1e,0xc9,0xf8},
+{0xbb,0x3d,0xf8,0xd2}, {0xb2,0x30,0xf3,0xdc}, {0xa9,0x27,0xee,0xce}, {0xa0,0x2a,0xe5,0xc0},
+{0x47,0xb1,0x3c,0x7a}, {0x4e,0xbc,0x37,0x74}, {0x55,0xab,0x2a,0x66}, {0x5c,0xa6,0x21,0x68},
+{0x63,0x85,0x10,0x42}, {0x6a,0x88,0x1b,0x4c}, {0x71,0x9f,0x06,0x5e}, {0x78,0x92,0x0d,0x50},
+{0x0f,0xd9,0x64,0x0a}, {0x06,0xd4,0x6f,0x04}, {0x1d,0xc3,0x72,0x16}, {0x14,0xce,0x79,0x18},
+{0x2b,0xed,0x48,0x32}, {0x22,0xe0,0x43,0x3c}, {0x39,0xf7,0x5e,0x2e}, {0x30,0xfa,0x55,0x20},
+{0x9a,0xb7,0x01,0xec}, {0x93,0xba,0x0a,0xe2}, {0x88,0xad,0x17,0xf0}, {0x81,0xa0,0x1c,0xfe},
+{0xbe,0x83,0x2d,0xd4}, {0xb7,0x8e,0x26,0xda}, {0xac,0x99,0x3b,0xc8}, {0xa5,0x94,0x30,0xc6},
+{0xd2,0xdf,0x59,0x9c}, {0xdb,0xd2,0x52,0x92}, {0xc0,0xc5,0x4f,0x80}, {0xc9,0xc8,0x44,0x8e},
+{0xf6,0xeb,0x75,0xa4}, {0xff,0xe6,0x7e,0xaa}, {0xe4,0xf1,0x63,0xb8}, {0xed,0xfc,0x68,0xb6},
+{0x0a,0x67,0xb1,0x0c}, {0x03,0x6a,0xba,0x02}, {0x18,0x7d,0xa7,0x10}, {0x11,0x70,0xac,0x1e},
+{0x2e,0x53,0x9d,0x34}, {0x27,0x5e,0x96,0x3a}, {0x3c,0x49,0x8b,0x28}, {0x35,0x44,0x80,0x26},
+{0x42,0x0f,0xe9,0x7c}, {0x4b,0x02,0xe2,0x72}, {0x50,0x15,0xff,0x60}, {0x59,0x18,0xf4,0x6e},
+{0x66,0x3b,0xc5,0x44}, {0x6f,0x36,0xce,0x4a}, {0x74,0x21,0xd3,0x58}, {0x7d,0x2c,0xd8,0x56},
+{0xa1,0x0c,0x7a,0x37}, {0xa8,0x01,0x71,0x39}, {0xb3,0x16,0x6c,0x2b}, {0xba,0x1b,0x67,0x25},
+{0x85,0x38,0x56,0x0f}, {0x8c,0x35,0x5d,0x01}, {0x97,0x22,0x40,0x13}, {0x9e,0x2f,0x4b,0x1d},
+{0xe9,0x64,0x22,0x47}, {0xe0,0x69,0x29,0x49}, {0xfb,0x7e,0x34,0x5b}, {0xf2,0x73,0x3f,0x55},
+{0xcd,0x50,0x0e,0x7f}, {0xc4,0x5d,0x05,0x71}, {0xdf,0x4a,0x18,0x63}, {0xd6,0x47,0x13,0x6d},
+{0x31,0xdc,0xca,0xd7}, {0x38,0xd1,0xc1,0xd9}, {0x23,0xc6,0xdc,0xcb}, {0x2a,0xcb,0xd7,0xc5},
+{0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd},
+{0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5},
+{0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d}
+       }
+};
+#define        U4      xU4.xt8
+
+static const word32 rcon[30] = { 
+  0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+};
diff --git a/ipsec-tools/racoon/Crypto/rijndael-alg-fst.c b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.c
new file mode 100644 (file)
index 0000000..8ccf9e1
--- /dev/null
@@ -0,0 +1,492 @@
+/*     $KAME: rijndael-alg-fst.c,v 1.9 2001/06/19 15:21:05 itojun Exp $        */
+
+/*
+ * rijndael-alg-fst.c   v2.3   April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * authors: v1.0: Antoon Bosselaers
+ *          v2.0: Vincent Rijmen
+ *          v2.3: Paulo Barreto
+ *
+ * This code is placed in the public domain.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+#include <rijndael-alg-fst.h>
+#include <rijndael_local.h>
+
+#include "boxes-fst.dat"
+
+#include <err.h>
+#define bcopy(a, b, c) memcpy((b), (a), (c))
+#define bzero(a, b) memset((a), 0, (b))
+#define panic(a) err(1, (a))
+
+int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
+       /* Calculate the necessary round keys
+        * The number of calculations depends on keyBits and blockBits
+        */ 
+       int j, r, t, rconpointer = 0;
+       union {
+               word8   x8[MAXKC][4];
+               word32  x32[MAXKC];
+       } xtk;
+#define        tk      xtk.x8
+       int KC = ROUNDS - 6;
+
+       for (j = KC-1; j >= 0; j--) {
+               *((word32*)tk[j]) = *((word32*)k[j]);
+       }
+       r = 0;
+       t = 0;
+       /* copy values into round key array */
+       for (j = 0; (j < KC) && (r < ROUNDS + 1); ) {
+               for (; (j < KC) && (t < 4); j++, t++) {
+                       *((word32*)W[r][t]) = *((word32*)tk[j]);
+               }
+               if (t == 4) {
+                       r++;
+                       t = 0;
+               }
+       }
+               
+       while (r < ROUNDS + 1) { /* while not enough round key material calculated */
+               /* calculate new values */
+               tk[0][0] ^= S[tk[KC-1][1]];
+               tk[0][1] ^= S[tk[KC-1][2]];
+               tk[0][2] ^= S[tk[KC-1][3]];
+               tk[0][3] ^= S[tk[KC-1][0]];
+               tk[0][0] ^= rcon[rconpointer++];
+
+               if (KC != 8) {
+                       for (j = 1; j < KC; j++) {
+                               *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+                       }
+               } else {
+                       for (j = 1; j < KC/2; j++) {
+                               *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+                       }
+                       tk[KC/2][0] ^= S[tk[KC/2 - 1][0]];
+                       tk[KC/2][1] ^= S[tk[KC/2 - 1][1]];
+                       tk[KC/2][2] ^= S[tk[KC/2 - 1][2]];
+                       tk[KC/2][3] ^= S[tk[KC/2 - 1][3]];
+                       for (j = KC/2 + 1; j < KC; j++) {
+                               *((word32*)tk[j]) ^= *((word32*)tk[j-1]);
+                       }
+               }
+               /* copy values into round key array */
+               for (j = 0; (j < KC) && (r < ROUNDS + 1); ) {
+                       for (; (j < KC) && (t < 4); j++, t++) {
+                               *((word32*)W[r][t]) = *((word32*)tk[j]);
+                       }
+                       if (t == 4) {
+                               r++;
+                               t = 0;
+                       }
+               }
+       }               
+       return 0;
+#undef tk
+}
+
+int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
+       int r;
+       word8 *w;
+
+       for (r = 1; r < ROUNDS; r++) {
+               w = W[r][0];
+               *((word32*)w) =
+                         *((const word32*)U1[w[0]])
+                       ^ *((const word32*)U2[w[1]])
+                       ^ *((const word32*)U3[w[2]])
+                       ^ *((const word32*)U4[w[3]]);
+
+               w = W[r][1];
+               *((word32*)w) =
+                         *((const word32*)U1[w[0]])
+                       ^ *((const word32*)U2[w[1]])
+                       ^ *((const word32*)U3[w[2]])
+                       ^ *((const word32*)U4[w[3]]);
+
+               w = W[r][2];
+               *((word32*)w) =
+                         *((const word32*)U1[w[0]])
+                       ^ *((const word32*)U2[w[1]])
+                       ^ *((const word32*)U3[w[2]])
+                       ^ *((const word32*)U4[w[3]]);
+
+               w = W[r][3];
+               *((word32*)w) =
+                         *((const word32*)U1[w[0]])
+                       ^ *((const word32*)U2[w[1]])
+                       ^ *((const word32*)U3[w[2]])
+                       ^ *((const word32*)U4[w[3]]);
+       }
+       return 0;
+}      
+
+/**
+ * Encrypt a single block. 
+ */
+int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
+       int r;
+       union {
+               word8   x8[16];
+               word32  x32[4];
+       } xa, xb;
+#define        a       xa.x8
+#define        b       xb.x8
+       union {
+               word8   x8[4][4];
+               word32  x32[4];
+       } xtemp;
+#define        temp    xtemp.x8
+
+    memcpy(a, in, sizeof a);
+
+    *((word32*)temp[0]) = *((word32*)(a   )) ^ *((word32*)rk[0][0]);
+    *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]);
+    *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]);
+    *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]);
+    *((word32*)(b    )) = *((const word32*)T1[temp[0][0]])
+                                       ^ *((const word32*)T2[temp[1][1]])
+                                       ^ *((const word32*)T3[temp[2][2]]) 
+                                       ^ *((const word32*)T4[temp[3][3]]);
+    *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]])
+                                       ^ *((const word32*)T2[temp[2][1]])
+                                       ^ *((const word32*)T3[temp[3][2]]) 
+                                       ^ *((const word32*)T4[temp[0][3]]);
+    *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]])
+                                       ^ *((const word32*)T2[temp[3][1]])
+                                       ^ *((const word32*)T3[temp[0][2]]) 
+                                       ^ *((const word32*)T4[temp[1][3]]);
+    *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]])
+                                       ^ *((const word32*)T2[temp[0][1]])
+                                       ^ *((const word32*)T3[temp[1][2]]) 
+                                       ^ *((const word32*)T4[temp[2][3]]);
+       for (r = 1; r < ROUNDS-1; r++) {
+               *((word32*)temp[0]) = *((word32*)(b   )) ^ *((word32*)rk[r][0]);
+               *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
+               *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
+               *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
+
+               *((word32*)(b    )) = *((const word32*)T1[temp[0][0]])
+                                       ^ *((const word32*)T2[temp[1][1]])
+                                       ^ *((const word32*)T3[temp[2][2]]) 
+                                       ^ *((const word32*)T4[temp[3][3]]);
+               *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]])
+                                       ^ *((const word32*)T2[temp[2][1]])
+                                       ^ *((const word32*)T3[temp[3][2]]) 
+                                       ^ *((const word32*)T4[temp[0][3]]);
+               *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]])
+                                       ^ *((const word32*)T2[temp[3][1]])
+                                       ^ *((const word32*)T3[temp[0][2]]) 
+                                       ^ *((const word32*)T4[temp[1][3]]);
+               *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]])
+                                       ^ *((const word32*)T2[temp[0][1]])
+                                       ^ *((const word32*)T3[temp[1][2]]) 
+                                       ^ *((const word32*)T4[temp[2][3]]);
+       }
+       /* last round is special */   
+       *((word32*)temp[0]) = *((word32*)(b   )) ^ *((word32*)rk[ROUNDS-1][0]);
+       *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]);
+       *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]);
+       *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]);
+       b[ 0] = T1[temp[0][0]][1];
+       b[ 1] = T1[temp[1][1]][1];
+       b[ 2] = T1[temp[2][2]][1];
+       b[ 3] = T1[temp[3][3]][1];
+       b[ 4] = T1[temp[1][0]][1];
+       b[ 5] = T1[temp[2][1]][1];
+       b[ 6] = T1[temp[3][2]][1];
+       b[ 7] = T1[temp[0][3]][1];
+       b[ 8] = T1[temp[2][0]][1];
+       b[ 9] = T1[temp[3][1]][1];
+       b[10] = T1[temp[0][2]][1];
+       b[11] = T1[temp[1][3]][1];
+       b[12] = T1[temp[3][0]][1];
+       b[13] = T1[temp[0][1]][1];
+       b[14] = T1[temp[1][2]][1];
+       b[15] = T1[temp[2][3]][1];
+       *((word32*)(b   )) ^= *((word32*)rk[ROUNDS][0]);
+       *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]);
+       *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]);
+       *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]);
+
+       memcpy(out, b, sizeof b /* XXX out */);
+
+       return 0;
+#undef a
+#undef b
+#undef temp
+}
+
+#ifdef INTERMEDIATE_VALUE_KAT
+/**
+ * Encrypt only a certain number of rounds.
+ * Only used in the Intermediate Value Known Answer Test.
+ */
+int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) {
+       int r;
+       word8 temp[4][4];
+
+       /* make number of rounds sane */
+       if (rounds > ROUNDS) {
+               rounds = ROUNDS;
+       }
+
+       *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]);
+       *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]);
+       *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]);
+       *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]);
+
+       for (r = 1; (r <= rounds) && (r < ROUNDS); r++) {
+               *((word32*)temp[0]) = *((const word32*)T1[a[0][0]])
+                                          ^ *((const word32*)T2[a[1][1]])
+                                          ^ *((const word32*)T3[a[2][2]]) 
+                                          ^ *((const word32*)T4[a[3][3]]);
+               *((word32*)temp[1]) = *((const word32*)T1[a[1][0]])
+                                          ^ *((const word32*)T2[a[2][1]])
+                                          ^ *((const word32*)T3[a[3][2]]) 
+                                          ^ *((const word32*)T4[a[0][3]]);
+               *((word32*)temp[2]) = *((const word32*)T1[a[2][0]])
+                                          ^ *((const word32*)T2[a[3][1]])
+                                          ^ *((const word32*)T3[a[0][2]]) 
+                                          ^ *((const word32*)T4[a[1][3]]);
+               *((word32*)temp[3]) = *((const word32*)T1[a[3][0]])
+                                          ^ *((const word32*)T2[a[0][1]])
+                                          ^ *((const word32*)T3[a[1][2]]) 
+                                          ^ *((const word32*)T4[a[2][3]]);
+               *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]);
+               *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]);
+               *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]);
+               *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]);
+       }
+       if (rounds == ROUNDS) {
+               /* last round is special */   
+               temp[0][0] = T1[a[0][0]][1];
+               temp[0][1] = T1[a[1][1]][1];
+               temp[0][2] = T1[a[2][2]][1]; 
+               temp[0][3] = T1[a[3][3]][1];
+               temp[1][0] = T1[a[1][0]][1];
+               temp[1][1] = T1[a[2][1]][1];
+               temp[1][2] = T1[a[3][2]][1]; 
+               temp[1][3] = T1[a[0][3]][1];
+               temp[2][0] = T1[a[2][0]][1];
+               temp[2][1] = T1[a[3][1]][1];
+               temp[2][2] = T1[a[0][2]][1]; 
+               temp[2][3] = T1[a[1][3]][1];
+               temp[3][0] = T1[a[3][0]][1];
+               temp[3][1] = T1[a[0][1]][1];
+               temp[3][2] = T1[a[1][2]][1]; 
+               temp[3][3] = T1[a[2][3]][1];
+               *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]);
+               *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]);
+               *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]);
+               *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]);
+       }
+
+       return 0;
+}   
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+/**
+ * Decrypt a single block.
+ */
+int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
+       int r;
+       union {
+               word8   x8[16];
+               word32  x32[4];
+       } xa, xb;
+#define        a       xa.x8
+#define        b       xb.x8
+       union {
+               word8   x8[4][4];
+               word32  x32[4];
+       } xtemp;
+#define        temp    xtemp.x8
+       
+    memcpy(a, in, sizeof a);
+
+    *((word32*)temp[0]) = *((word32*)(a   )) ^ *((word32*)rk[ROUNDS][0]);
+    *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]);
+    *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]);
+    *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]);
+
+    *((word32*)(b   )) = *((const word32*)T5[temp[0][0]])
+           ^ *((const word32*)T6[temp[3][1]])
+           ^ *((const word32*)T7[temp[2][2]]) 
+           ^ *((const word32*)T8[temp[1][3]]);
+       *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]])
+           ^ *((const word32*)T6[temp[0][1]])
+           ^ *((const word32*)T7[temp[3][2]]) 
+           ^ *((const word32*)T8[temp[2][3]]);
+       *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]])
+           ^ *((const word32*)T6[temp[1][1]])
+           ^ *((const word32*)T7[temp[0][2]]) 
+           ^ *((const word32*)T8[temp[3][3]]);
+       *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]])
+           ^ *((const word32*)T6[temp[2][1]])
+           ^ *((const word32*)T7[temp[1][2]]) 
+           ^ *((const word32*)T8[temp[0][3]]);
+       for (r = ROUNDS-1; r > 1; r--) {
+               *((word32*)temp[0]) = *((word32*)(b   )) ^ *((word32*)rk[r][0]);
+               *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
+               *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
+               *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
+               *((word32*)(b   )) = *((const word32*)T5[temp[0][0]])
+                  ^ *((const word32*)T6[temp[3][1]])
+                  ^ *((const word32*)T7[temp[2][2]]) 
+                  ^ *((const word32*)T8[temp[1][3]]);
+               *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]])
+                  ^ *((const word32*)T6[temp[0][1]])
+                  ^ *((const word32*)T7[temp[3][2]]) 
+                  ^ *((const word32*)T8[temp[2][3]]);
+               *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]])
+                  ^ *((const word32*)T6[temp[1][1]])
+                  ^ *((const word32*)T7[temp[0][2]]) 
+                  ^ *((const word32*)T8[temp[3][3]]);
+               *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]])
+                  ^ *((const word32*)T6[temp[2][1]])
+                  ^ *((const word32*)T7[temp[1][2]]) 
+                  ^ *((const word32*)T8[temp[0][3]]);
+       }
+       /* last round is special */   
+       *((word32*)temp[0]) = *((word32*)(b   )) ^ *((word32*)rk[1][0]);
+       *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]);
+       *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]);
+       *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]);
+       b[ 0] = S5[temp[0][0]];
+       b[ 1] = S5[temp[3][1]];
+       b[ 2] = S5[temp[2][2]];
+       b[ 3] = S5[temp[1][3]];
+       b[ 4] = S5[temp[1][0]];
+       b[ 5] = S5[temp[0][1]];
+       b[ 6] = S5[temp[3][2]];
+       b[ 7] = S5[temp[2][3]];
+       b[ 8] = S5[temp[2][0]];
+       b[ 9] = S5[temp[1][1]];
+       b[10] = S5[temp[0][2]];
+       b[11] = S5[temp[3][3]];
+       b[12] = S5[temp[3][0]];
+       b[13] = S5[temp[2][1]];
+       b[14] = S5[temp[1][2]];
+       b[15] = S5[temp[0][3]];
+       *((word32*)(b   )) ^= *((word32*)rk[0][0]);
+       *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]);
+       *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]);
+       *((word32*)(b+12)) ^= *((word32*)rk[0][3]);
+
+       memcpy(out, b, sizeof b /* XXX out */);
+
+       return 0;
+#undef a
+#undef b
+#undef temp
+}
+
+
+#ifdef INTERMEDIATE_VALUE_KAT
+/**
+ * Decrypt only a certain number of rounds.
+ * Only used in the Intermediate Value Known Answer Test.
+ * Operations rearranged such that the intermediate values
+ * of decryption correspond with the intermediate values
+ * of encryption.
+ */
+int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) {
+       int r, i;
+       word8 temp[4], shift;
+
+       /* make number of rounds sane */
+       if (rounds > ROUNDS) {
+               rounds = ROUNDS;
+       }
+    /* first round is special: */
+       *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0];
+       *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1];
+       *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2];
+       *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3];
+       for (i = 0; i < 4; i++) {
+               a[i][0] = Si[a[i][0]];
+               a[i][1] = Si[a[i][1]];
+               a[i][2] = Si[a[i][2]];
+               a[i][3] = Si[a[i][3]];
+       }
+       for (i = 1; i < 4; i++) {
+               shift = (4 - i) & 3;
+               temp[0] = a[(0 + shift) & 3][i];
+               temp[1] = a[(1 + shift) & 3][i];
+               temp[2] = a[(2 + shift) & 3][i];
+               temp[3] = a[(3 + shift) & 3][i];
+               a[0][i] = temp[0];
+               a[1][i] = temp[1];
+               a[2][i] = temp[2];
+               a[3][i] = temp[3];
+       }
+       /* ROUNDS-1 ordinary rounds */
+       for (r = ROUNDS-1; r > rounds; r--) {
+               *(word32 *)a[0] ^= *(word32 *)rk[r][0];
+               *(word32 *)a[1] ^= *(word32 *)rk[r][1];
+               *(word32 *)a[2] ^= *(word32 *)rk[r][2];
+               *(word32 *)a[3] ^= *(word32 *)rk[r][3];
+
+               *((word32*)a[0]) =
+                         *((const word32*)U1[a[0][0]])
+                       ^ *((const word32*)U2[a[0][1]])
+                       ^ *((const word32*)U3[a[0][2]])
+                       ^ *((const word32*)U4[a[0][3]]);
+
+               *((word32*)a[1]) =
+                         *((const word32*)U1[a[1][0]])
+                       ^ *((const word32*)U2[a[1][1]])
+                       ^ *((const word32*)U3[a[1][2]])
+                       ^ *((const word32*)U4[a[1][3]]);
+
+               *((word32*)a[2]) =
+                         *((const word32*)U1[a[2][0]])
+                       ^ *((const word32*)U2[a[2][1]])
+                       ^ *((const word32*)U3[a[2][2]])
+                       ^ *((const word32*)U4[a[2][3]]);
+
+               *((word32*)a[3]) =
+                         *((const word32*)U1[a[3][0]])
+                       ^ *((const word32*)U2[a[3][1]])
+                       ^ *((const word32*)U3[a[3][2]])
+                       ^ *((const word32*)U4[a[3][3]]);
+               for (i = 0; i < 4; i++) {
+                       a[i][0] = Si[a[i][0]];
+                       a[i][1] = Si[a[i][1]];
+                       a[i][2] = Si[a[i][2]];
+                       a[i][3] = Si[a[i][3]];
+               }
+               for (i = 1; i < 4; i++) {
+                       shift = (4 - i) & 3;
+                       temp[0] = a[(0 + shift) & 3][i];
+                       temp[1] = a[(1 + shift) & 3][i];
+                       temp[2] = a[(2 + shift) & 3][i];
+                       temp[3] = a[(3 + shift) & 3][i];
+                       a[0][i] = temp[0];
+                       a[1][i] = temp[1];
+                       a[2][i] = temp[2];
+                       a[3][i] = temp[3];
+               }
+       }
+       if (rounds == 0) {
+               /* End with the extra key addition */   
+               *(word32 *)a[0] ^= *(word32 *)rk[0][0];
+               *(word32 *)a[1] ^= *(word32 *)rk[0][1];
+               *(word32 *)a[2] ^= *(word32 *)rk[0][2];
+               *(word32 *)a[3] ^= *(word32 *)rk[0][3];
+       }    
+       return 0;
+}
+#endif /* INTERMEDIATE_VALUE_KAT */
diff --git a/ipsec-tools/racoon/Crypto/rijndael-alg-fst.h b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.h
new file mode 100644 (file)
index 0000000..7a725ae
--- /dev/null
@@ -0,0 +1,34 @@
+/*     $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $        */
+
+/*
+ * rijndael-alg-fst.h   v2.3   April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test.
+ */
+
+#ifndef __RIJNDAEL_ALG_FST_H__
+#define __RIJNDAEL_ALG_FST_H__
+
+#define RIJNDAEL_MAXKC                 (256/32)
+#define RIJNDAEL_MAXROUNDS             14
+
+int rijndaelKeySched(u_int8_t k[RIJNDAEL_MAXKC][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+int rijndaelKeyEncToDec(u_int8_t W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+int rijndaelEncrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int rijndaelEncryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+int rijndaelDecrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int rijndaelDecryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+#endif /* __RIJNDAEL_ALG_FST_H__ */
+
diff --git a/ipsec-tools/racoon/Crypto/rijndael-api-fst.c b/ipsec-tools/racoon/Crypto/rijndael-api-fst.c
new file mode 100644 (file)
index 0000000..a3104c2
--- /dev/null
@@ -0,0 +1,495 @@
+/*     $KAME: rijndael-api-fst.c,v 1.1.1.1 2001/08/08 09:56:23 sakane Exp $    */
+
+/*
+ * rijndael-api-fst.c   v2.3   April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * authors: v1.0: Antoon Bosselaers
+ *          v2.0: Vincent Rijmen
+ *          v2.1: Vincent Rijmen
+ *          v2.2: Vincent Rijmen
+ *          v2.3: Paulo Barreto
+ *          v2.4: Vincent Rijmen
+ *
+ * This code is placed in the public domain.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/time.h>
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+#include <rijndael-alg-fst.h>
+#include <rijndael-api-fst.h>
+#include <rijndael_local.h>
+
+#include <err.h>
+#define bcopy(a, b, c) memcpy(b, a, c)
+#define bzero(a, b) memset(a, 0, b)
+#define panic(a) err(1, (a))
+
+int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) {
+       word8 k[MAXKC][4];
+       int i;
+       char *keyMat;
+       
+       if (key == NULL) {
+               return BAD_KEY_INSTANCE;
+       }
+
+       if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
+               key->direction = direction;
+       } else {
+               return BAD_KEY_DIR;
+       }
+
+       if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { 
+               key->keyLen = keyLen;
+       } else {
+               return BAD_KEY_MAT;
+       }
+
+       if (keyMaterial != NULL) {
+               bcopy(keyMaterial, key->keyMaterial, keyLen/8);
+       }
+
+       key->ROUNDS = keyLen/32 + 6;
+
+       /* initialize key schedule: */
+       keyMat = key->keyMaterial;
+       for (i = 0; i < key->keyLen/8; i++) {
+               k[i >> 2][i & 3] = (word8)keyMat[i]; 
+       }
+       rijndaelKeySched(k, key->keySched, key->ROUNDS);
+       if (direction == DIR_DECRYPT) {
+               rijndaelKeyEncToDec(key->keySched, key->ROUNDS);
+       }
+
+       return TRUE;
+}
+
+int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) {
+       if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
+               cipher->mode = mode;
+       } else {
+               return BAD_CIPHER_MODE;
+       }
+       if (IV != NULL) {
+               bcopy(IV, cipher->IV, MAX_IV_SIZE);
+       } else {
+               bzero(cipher->IV, MAX_IV_SIZE);
+       }
+       return TRUE;
+}
+
+int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
+               BYTE *input, int inputLen, BYTE *outBuffer) {
+       int i, k, numBlocks;
+       word8 block[16], iv[4][4];
+
+       if (cipher == NULL ||
+               key == NULL ||
+               key->direction == DIR_DECRYPT) {
+               return BAD_CIPHER_STATE;
+       }
+       if (input == NULL || inputLen <= 0) {
+               return 0; /* nothing to do */
+       }
+
+       numBlocks = inputLen/128;
+       
+       switch (cipher->mode) {
+       case MODE_ECB: 
+               for (i = numBlocks; i > 0; i--) {
+                       rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS);
+                       input += 16;
+                       outBuffer += 16;
+               }
+               break;
+               
+       case MODE_CBC:
+#if 0 /*STRICT_ALIGN*/
+               bcopy(cipher->IV, block, 16);
+               bcopy(input, iv, 16);
+               ((word32*)block)[0] ^= ((word32*)iv)[0];
+               ((word32*)block)[1] ^= ((word32*)iv)[1];
+               ((word32*)block)[2] ^= ((word32*)iv)[2];
+               ((word32*)block)[3] ^= ((word32*)iv)[3];
+#else
+               ((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0];
+               ((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1];
+               ((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2];
+               ((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3];
+#endif
+               rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
+               input += 16;
+               for (i = numBlocks - 1; i > 0; i--) {
+#if 0 /*STRICT_ALIGN*/
+                       bcopy(outBuffer, block, 16);
+                       ((word32*)block)[0] ^= ((word32*)iv)[0];
+                       ((word32*)block)[1] ^= ((word32*)iv)[1];
+                       ((word32*)block)[2] ^= ((word32*)iv)[2];
+                       ((word32*)block)[3] ^= ((word32*)iv)[3];
+#else
+                       ((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0];
+                       ((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1];
+                       ((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2];
+                       ((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3];
+#endif
+                       outBuffer += 16;
+                       rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
+                       input += 16;
+               }
+               break;
+       
+       case MODE_CFB1:
+#if 0 /*STRICT_ALIGN*/
+               bcopy(cipher->IV, iv, 16); 
+#else  /* !STRICT_ALIGN */
+               *((word32*)iv[0]) = *((word32*)(cipher->IV   ));
+               *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
+               *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
+               *((word32*)iv[3]) = *((word32*)(cipher->IV+12));
+#endif /* ?STRICT_ALIGN */
+               for (i = numBlocks; i > 0; i--) {
+                       for (k = 0; k < 128; k++) {
+                               *((word32*) block    ) = *((word32*)iv[0]);
+                               *((word32*)(block+ 4)) = *((word32*)iv[1]);
+                               *((word32*)(block+ 8)) = *((word32*)iv[2]);
+                               *((word32*)(block+12)) = *((word32*)iv[3]);
+                               rijndaelEncrypt(block, block, key->keySched, key->ROUNDS);
+                               outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
+                               iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
+                               iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
+                               iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
+                               iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
+                               iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
+                               iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
+                               iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
+                               iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
+                               iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
+                               iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
+                               iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
+                               iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
+                               iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
+                               iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
+                               iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
+                               iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1);
+                       }
+               }
+               break;
+       
+       default:
+               return BAD_CIPHER_STATE;
+       }
+       
+       return 128*numBlocks;
+}
+
+/**
+ * Encrypt data partitioned in octets, using RFC 2040-like padding.
+ *
+ * @param   input           data to be encrypted (octet sequence)
+ * @param   inputOctets                input length in octets (not bits)
+ * @param   outBuffer       encrypted output data
+ *
+ * @return     length in octets (not bits) of the encrypted output buffer.
+ */
+int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
+               BYTE *input, int inputOctets, BYTE *outBuffer) {
+       int i, numBlocks, padLen;
+       word8 block[16], *iv, *cp;
+
+       if (cipher == NULL ||
+               key == NULL ||
+               key->direction == DIR_DECRYPT) {
+               return BAD_CIPHER_STATE;
+       }
+       if (input == NULL || inputOctets <= 0) {
+               return 0; /* nothing to do */
+       }
+
+       numBlocks = inputOctets/16;
+
+       switch (cipher->mode) {
+       case MODE_ECB: 
+               for (i = numBlocks; i > 0; i--) {
+                       rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS);
+                       input += 16;
+                       outBuffer += 16;
+               }
+               padLen = 16 - (inputOctets - 16*numBlocks);
+               if (padLen > 0 && padLen <= 16)
+                       panic("rijndael_padEncrypt(ECB)");
+               bcopy(input, block, 16 - padLen);
+               for (cp = block + 16 - padLen; cp < block + 16; cp++)
+                       *cp = padLen;
+               rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
+               break;
+
+       case MODE_CBC:
+               iv = cipher->IV;
+               for (i = numBlocks; i > 0; i--) {
+                       ((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0];
+                       ((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1];
+                       ((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2];
+                       ((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3];
+                       rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
+                       iv = outBuffer;
+                       input += 16;
+                       outBuffer += 16;
+               }
+#if 0  /*XXX i'm not sure that is correct. sakane@kame.net */
+               padLen = 16 - (inputOctets - 16*numBlocks);
+#else
+               padLen = 16 - inputOctets % 16;
+               if (padLen == 16)
+                       padLen = 0;
+#endif
+               if (padLen > 0 && padLen <= 16)
+                       panic("rijndael_padEncrypt(CBC)");
+               for (i = 0; i < 16 - padLen; i++) {
+                       block[i] = input[i] ^ iv[i];
+               }
+               for (i = 16 - padLen; i < 16; i++) {
+                       block[i] = (BYTE)padLen ^ iv[i];
+               }
+               rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
+               break;
+
+       default:
+               return BAD_CIPHER_STATE;
+       }
+
+       return 16*(numBlocks + 1);
+}
+
+int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
+               BYTE *input, int inputLen, BYTE *outBuffer) {
+       int i, k, numBlocks;
+       word8 block[16], iv[4][4];
+
+       if (cipher == NULL ||
+               key == NULL ||
+               (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
+               return BAD_CIPHER_STATE;
+       }
+       if (input == NULL || inputLen <= 0) {
+               return 0; /* nothing to do */
+       }
+
+       numBlocks = inputLen/128;
+
+       switch (cipher->mode) {
+       case MODE_ECB: 
+               for (i = numBlocks; i > 0; i--) { 
+                       rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS);
+                       input += 16;
+                       outBuffer += 16;
+               }
+               break;
+               
+       case MODE_CBC:
+#if 0 /*STRICT_ALIGN */
+               bcopy(cipher->IV, iv, 16); 
+#else
+               *((word32*)iv[0]) = *((word32*)(cipher->IV   ));
+               *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
+               *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
+               *((word32*)iv[3]) = *((word32*)(cipher->IV+12));
+#endif
+               for (i = numBlocks; i > 0; i--) {
+                       rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
+                       ((word32*)block)[0] ^= *((word32*)iv[0]);
+                       ((word32*)block)[1] ^= *((word32*)iv[1]);
+                       ((word32*)block)[2] ^= *((word32*)iv[2]);
+                       ((word32*)block)[3] ^= *((word32*)iv[3]);
+#if 0 /*STRICT_ALIGN*/
+                       bcopy(input, iv, 16);
+                       bcopy(block, outBuffer, 16);
+#else
+                       *((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0];
+                       *((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1];
+                       *((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2];
+                       *((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3];
+#endif
+                       input += 16;
+                       outBuffer += 16;
+               }
+               break;
+       
+       case MODE_CFB1:
+#if 0 /*STRICT_ALIGN */
+               bcopy(cipher->IV, iv, 16); 
+#else
+               *((word32*)iv[0]) = *((word32*)(cipher->IV));
+               *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
+               *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
+               *((word32*)iv[3]) = *((word32*)(cipher->IV+12));
+#endif
+               for (i = numBlocks; i > 0; i--) {
+                       for (k = 0; k < 128; k++) {
+                               *((word32*) block    ) = *((word32*)iv[0]);
+                               *((word32*)(block+ 4)) = *((word32*)iv[1]);
+                               *((word32*)(block+ 8)) = *((word32*)iv[2]);
+                               *((word32*)(block+12)) = *((word32*)iv[3]);
+                               rijndaelEncrypt(block, block, key->keySched, key->ROUNDS);
+                               iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
+                               iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
+                               iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
+                               iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
+                               iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
+                               iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
+                               iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
+                               iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
+                               iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
+                               iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
+                               iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
+                               iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
+                               iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
+                               iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
+                               iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
+                               iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1);
+                               outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
+                       }
+               }
+               break;
+
+       default:
+               return BAD_CIPHER_STATE;
+       }
+       
+       return 128*numBlocks;
+}
+
+int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
+               BYTE *input, int inputOctets, BYTE *outBuffer) {
+       int i, numBlocks, padLen;
+       word8 block[16];
+       word32 iv[4];
+
+       if (cipher == NULL ||
+               key == NULL ||
+               key->direction == DIR_ENCRYPT) {
+               return BAD_CIPHER_STATE;
+       }
+       if (input == NULL || inputOctets <= 0) {
+               return 0; /* nothing to do */
+       }
+       if (inputOctets % 16 != 0) {
+               return BAD_DATA;
+       }
+
+       numBlocks = inputOctets/16;
+
+       switch (cipher->mode) {
+       case MODE_ECB:
+               /* all blocks but last */
+               for (i = numBlocks - 1; i > 0; i--) { 
+                       rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS);
+                       input += 16;
+                       outBuffer += 16;
+               }
+               /* last block */
+               rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
+               padLen = block[15];
+               if (padLen >= 16) {
+                       return BAD_DATA;
+               }
+               for (i = 16 - padLen; i < 16; i++) {
+                       if (block[i] != padLen) {
+                               return BAD_DATA;
+                       }
+               }
+               bcopy(block, outBuffer, 16 - padLen);
+               break;
+               
+       case MODE_CBC:
+               bcopy(cipher->IV, iv, 16);
+               /* all blocks but last */
+               for (i = numBlocks - 1; i > 0; i--) {
+                       rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
+                       ((word32*)block)[0] ^= iv[0];
+                       ((word32*)block)[1] ^= iv[1];
+                       ((word32*)block)[2] ^= iv[2];
+                       ((word32*)block)[3] ^= iv[3];
+                       bcopy(input, iv, 16);
+                       bcopy(block, outBuffer, 16);
+                       input += 16;
+                       outBuffer += 16;
+               }
+               /* last block */
+               rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
+               ((word32*)block)[0] ^= iv[0];
+               ((word32*)block)[1] ^= iv[1];
+               ((word32*)block)[2] ^= iv[2];
+               ((word32*)block)[3] ^= iv[3];
+               padLen = block[15];
+               if (padLen <= 0 || padLen > 16) {
+                       return BAD_DATA;
+               }
+               for (i = 16 - padLen; i < 16; i++) {
+                       if (block[i] != padLen) {
+                               return BAD_DATA;
+                       }
+               }
+               bcopy(block, outBuffer, 16 - padLen);
+               break;
+       
+       default:
+               return BAD_CIPHER_STATE;
+       }
+       
+       return 16*numBlocks - padLen;
+}
+
+#ifdef INTERMEDIATE_VALUE_KAT
+/**
+ *     cipherUpdateRounds:
+ *
+ *     Encrypts/Decrypts exactly one full block a specified number of rounds.
+ *     Only used in the Intermediate Value Known Answer Test.  
+ *
+ *     Returns:
+ *             TRUE - on success
+ *             BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized)
+ */
+int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key,
+               BYTE *input, int inputLen, BYTE *outBuffer, int rounds) {
+       int j;
+       word8 block[4][4];
+
+       if (cipher == NULL || key == NULL) {
+               return BAD_CIPHER_STATE;
+       }
+
+       for (j = 3; j >= 0; j--) {
+               /* parse input stream into rectangular array */
+               *((word32*)block[j]) = *((word32*)(input+4*j));
+       }
+
+       switch (key->direction) {
+       case DIR_ENCRYPT:
+               rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds);
+               break;
+               
+       case DIR_DECRYPT:
+               rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds);
+               break;
+               
+       default:
+               return BAD_KEY_DIR;
+       } 
+
+       for (j = 3; j >= 0; j--) {
+               /* parse rectangular array into output ciphertext bytes */
+               *((word32*)(outBuffer+4*j)) = *((word32*)block[j]);
+       }
+       
+       return TRUE;
+}
+#endif /* INTERMEDIATE_VALUE_KAT */
diff --git a/ipsec-tools/racoon/Crypto/rijndael-api-fst.h b/ipsec-tools/racoon/Crypto/rijndael-api-fst.h
new file mode 100644 (file)
index 0000000..9e0ed3a
--- /dev/null
@@ -0,0 +1,104 @@
+/*     $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $        */
+
+/*
+ * rijndael-api-fst.h   v2.3   April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test.
+ */
+
+#ifndef __RIJNDAEL_API_FST_H__
+#define __RIJNDAEL_API_FST_H__
+
+#include <rijndael-alg-fst.h>
+
+/*  Defines:
+       Add any additional defines you need
+*/
+
+#define     DIR_ENCRYPT           0 /*  Are we encrpyting?  */
+#define     DIR_DECRYPT           1 /*  Are we decrpyting?  */
+#define     MODE_ECB              1 /*  Are we ciphering in ECB mode?   */
+#define     MODE_CBC              2 /*  Are we ciphering in CBC mode?   */
+#define     MODE_CFB1             3 /*  Are we ciphering in 1-bit CFB mode? */
+#define     TRUE                  1
+#define     FALSE                 0
+#define     BITSPERBLOCK        128 /* Default number of bits in a cipher block */
+
+/*  Error Codes - CHANGE POSSIBLE: inclusion of additional error codes  */
+#define     BAD_KEY_DIR          -1 /*  Key direction is invalid, e.g., unknown value */
+#define     BAD_KEY_MAT          -2 /*  Key material not of correct length */
+#define     BAD_KEY_INSTANCE     -3 /*  Key passed is not valid */
+#define     BAD_CIPHER_MODE      -4 /*  Params struct passed to cipherInit invalid */
+#define     BAD_CIPHER_STATE     -5 /*  Cipher in wrong state (e.g., not initialized) */
+#define     BAD_BLOCK_LENGTH     -6
+#define     BAD_CIPHER_INSTANCE  -7
+#define     BAD_DATA             -8 /*  Data contents are invalid, e.g., invalid padding */
+#define     BAD_OTHER            -9 /*  Unknown error */
+
+/*  CHANGE POSSIBLE:  inclusion of algorithm specific defines  */
+#define     MAX_KEY_SIZE         64 /* # of ASCII char's needed to represent a key */
+#define     MAX_IV_SIZE          16 /* # bytes needed to represent an IV  */
+
+/*  Typedefs:
+
+       Typedef'ed data storage elements.  Add any algorithm specific 
+parameters at the bottom of the structs as appropriate.
+*/
+
+/*  The structure for key information */
+typedef struct {
+    u_int8_t  direction;            /* Key used for encrypting or decrypting? */
+    int   keyLen;                   /* Length of the key  */
+    char  keyMaterial[MAX_KEY_SIZE+1];  /* Raw key data in ASCII, e.g., user input or KAT values */
+        /*  The following parameters are algorithm dependent, replace or add as necessary  */
+       int   ROUNDS;                   /* key-length-dependent number of rounds */
+    int   blockLen;                 /* block length */
+    union {
+       u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4];      /* key schedule         */
+       u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4];       /* key schedule         */
+    } xKeySched;
+#define        keySched        xKeySched.xkS8
+} keyInstance;
+
+/*  The structure for cipher information */
+typedef struct {                    /* changed order of the components */
+    u_int8_t mode;                  /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
+    u_int8_t IV[MAX_IV_SIZE];       /* A possible Initialization Vector for ciphering */
+        /*  Add any algorithm specific parameters needed here  */
+    int   blockLen;                 /* Sample: Handles non-128 bit block sizes (if available) */
+} cipherInstance;
+
+/*  Function prototypes  */
+/*  CHANGED: nothing
+       TODO: implement the following extensions to setup 192-bit and 256-bit block lengths:
+        makeKeyEx():    parameter blockLen added
+                        -- this parameter is absolutely necessary if you want to
+                        setup the round keys in a variable block length setting 
+           cipherInitEx(): parameter blockLen added (for obvious reasons)              
+ */
+
+int rijndael_makeKey(keyInstance *key, u_int8_t direction, int keyLen, char *keyMaterial);
+
+int rijndael_cipherInit(cipherInstance *cipher, u_int8_t mode, char *IV);
+
+int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
+        u_int8_t *input, int inputLen, u_int8_t *outBuffer);
+
+int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
+               u_int8_t *input, int inputOctets, u_int8_t *outBuffer);
+
+int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
+        u_int8_t *input, int inputLen, u_int8_t *outBuffer);
+
+int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
+               u_int8_t *input, int inputOctets, u_int8_t *outBuffer);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key,
+        u_int8_t *input, int inputLen, u_int8_t *outBuffer, int Rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+#endif /*  __RIJNDAEL_API_FST_H__ */
+
diff --git a/ipsec-tools/racoon/Crypto/rijndael.h b/ipsec-tools/racoon/Crypto/rijndael.h
new file mode 100644 (file)
index 0000000..6af4aa0
--- /dev/null
@@ -0,0 +1,10 @@
+/*     $KAME: rijndael.h,v 1.2 2000/10/02 17:14:27 itojun Exp $        */
+
+#ifndef __RIJNDAEL_H__
+#define __RIJNDAEL_H__
+
+#include <rijndael-api-fst.h>
+
+
+#endif /* __RIJNDAEL_H__ */
+
diff --git a/ipsec-tools/racoon/Crypto/rijndael_local.h b/ipsec-tools/racoon/Crypto/rijndael_local.h
new file mode 100644 (file)
index 0000000..652b328
--- /dev/null
@@ -0,0 +1,17 @@
+/*     $KAME: rijndael_local.h,v 1.3 2000/10/02 17:14:27 itojun Exp $  */
+
+#ifndef __RIJNDAEL_LOCAL_H__
+#define __RIJNDAEL_LOCAL_H__
+
+/* the file should not be used from outside */
+typedef u_int8_t               BYTE;
+typedef u_int8_t               word8;  
+typedef u_int16_t              word16; 
+typedef u_int32_t              word32;
+
+#define MAXKC          RIJNDAEL_MAXKC
+#define MAXROUNDS      RIJNDAEL_MAXROUNDS
+
+
+#endif /* __RIJNDAEL_LOCAL_H__ */
+
diff --git a/ipsec-tools/racoon/Documents/FAQ b/ipsec-tools/racoon/Documents/FAQ
new file mode 100644 (file)
index 0000000..924c73f
--- /dev/null
@@ -0,0 +1,106 @@
+This document is derived from the KAME racoon FAQ. Some answers do not
+apply to ipsec-tools (they are obsolete or not up to date). They are
+tagged [KAME]
+
+Q: With what other IKE/IPsec implementation racoon is known to be interoperable?
+
+A: [KAME]
+       See "IMPLEMENTATION" document supplied with KAME kit, or:
+       http://www.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION
+       As we have tested/got test reports in the past, and our end and
+       the other end may have changed their implemenations, we are not sure
+       if we can interoperate with them today (we hope them to interoperate,
+       but we are not sure).
+       Also note that, IKE interoperability highly depends on configuration
+       on both ends.  You must configure both ends exactly the same.
+
+Q: How can I make racoon interoperate with <IKE/IPsec implementation>?
+
+A:
+       Configure both ends exactly the same.  With just a tiny little
+       differnce, you will be in trouble.
+
+Q: How to build racoon on my platform?
+
+A: 
+       As usual: configure && make && make install
+       ipsec-tools is also available as a package in the NetBSD pkgsrc
+
+Q: Describe me the options to "configure".
+
+A:
+       --enable-adminport:
+               Lets racoon to listen to racoon admin port, which is to
+               be contacted by racoonctl(8).
+       --enable-natt:
+               Enable NAT-Traversal. This needs kernel support, which is
+               available on Linux. On NetBSD, NAT-Traversal kernel support
+               has not been integrated yet, you can get it from here:
+               http://ipsec-tools.sourceforge.net/netbsd_nat-t.diff
+               If you live in a country where software patents are legal,
+               using NAT-Traversal might infringe a patent. 
+       --enable-frag:
+               Enable IKE fragmentation, which is a workaround for 
+               broken routers that drop fragmented packets
+       --enable-hybrid:
+               Enable hybrid authentication, and ISAKMP mode config and
+               Xauth as well. Note that plain Xauth (without hybrid auth)
+               is not implemented.
+       --with-libradius:
+               Enable the use of RADIUS with hybrid authentication on the
+               server side. RADIUS is used for authentication, configuration
+               and accounting.
+       --with-libpam:
+               Enable the use of PAM with hybrid authentication on the 
+               server side. PAM can be used for authentication and accounting.
+       --enable-gssapi:
+               Enable GSS-API, for Kerberos V support.
+       --enable-stats: 
+               Enable statistics logging function.
+       --enable-samode-unspec: 
+               Enable to use unspecified a mode of SA.
+       --enable-ipv6:
+               Enable IPv6 support.
+       --with-kernel-headers:
+               Supply the location of Linux kernel headers.
+       --with-readline:
+               Support readline input (yes by default).
+       --with-openssl:
+               Specify OpenSSL directory.
+       --sysconfdir:
+               Where racoon config file goes. Default is /etc, which means
+               that racoon will look for /etc/racoon.conf
+       --localstatedir:
+               Where is the directory where racoon stores the control socket
+               (when using --enable-adminport). Default is /var, which 
+               means racoon will use /var/racoon/racoon.sock
+       --prefix:
+               Where racoon gets installed. 
+
+Q: How can I get help?
+
+A: 
+       Always identify your operating system platforms, the versions you are
+       using (like "ipsec-tools-0.5"), and information to repeat the
+       problem.  The more revelant information you supply, the better your 
+       chances of getting help are. Useful informations include, depending
+       of the problem: 
+       - version identification
+       - trace from racoon, taken by "racoon -d 0xffffffff"
+               (maximum debug level)
+       - configuration file you are using
+       - probabaly, tcpdump trace
+       http://orange.kame.net/dev/send-pr.html has the guideline.
+
+       If your question is not confidential, send your questions to:
+       <ipsec-tools-devel@lists.sourceforge.net>
+
+       If your question is confidential, send your questions to:
+       <ipsec-tools-core@lists.sourceforge.net>
+
+Q: Other documents to look at?
+
+A:
+       http://www.netbsd.org/Documentation/network/ipsec/
+       http://www.kame.net/
+       http://www.kame.net/newsletter/
diff --git a/ipsec-tools/racoon/Documents/README.certificate b/ipsec-tools/racoon/Documents/README.certificate
new file mode 100644 (file)
index 0000000..a8bbfa2
--- /dev/null
@@ -0,0 +1 @@
+See http://www.kame.net/newsletter/20001119b/
diff --git a/ipsec-tools/racoon/Documents/README.gssapi b/ipsec-tools/racoon/Documents/README.gssapi
new file mode 100644 (file)
index 0000000..9cb3fbb
--- /dev/null
@@ -0,0 +1,106 @@
+The gss-api authentication mechanism implementation for racoon was
+based on the ietf draft draft-ietf-ipsec-isakmp-gss-auth-06.txt.
+
+The implementation uses the Heimdal gss-api library, i.e. gss-api
+on top of Kerberos 5. The Heimdal gss-api library had to be modified
+to meet the requirements of using gss-api in a daemon. More specifically,
+the gss_acquire_cred() call did not work for other cases than
+GSS_C_NO_CREDENTIAL ("use default creds"). Daemons are often started
+as root, and have no Kerberos 5 credentials, so racoon explicitly
+needs to acquire its credentials. The usual method (already used
+by login authentication daemons) in these situations is to add
+a set of special credentials to be used. For example, authentication
+by daemons concerned with login credentials, uses 'host/fqdn' as
+its credential, where fqdn is the hostname on the interface that
+is being used. These special credentials need to be extracted into
+a local keytab from the kdc. The default value used in racoon
+is 'ike/fqdn', but it can be overridden in the racoon config file.
+
+The modification to the Heimdal gss-api library implements the
+mechanism above. If a credential other than GSS_C_NO_CREDENTIAL
+is specified to gss_acquire_cred(), it first looks in the default
+credential cache if it its principal matches the desired credential.
+If not, it extracts it from the default keytab file, and stores
+it in a memory-based credential cache, part of the gss credential
+structure.
+
+
+
+The modifcations to racoon itself are as follows:
+
+       * The racoon.conf config file accepts a new keyword, "gssapi_id",
+         to be used inside a proposal specification. It specifies
+         a string (a Kerberos 5 principal in this case), specifying the
+         credential that racoon will try to acquire. The default value
+         is 'ike/fqdn', where fqdn is the hostname for the interface
+         being used for the exchange. If the id is not specified, no
+         GSS endpoint attribute will be specified in the first SA sent.
+         However, if the initiator does specify a GSS endpoint attribute,
+         racoon will always respond with its own GSS endpoint name
+         in the SA (the default one if not specified by this option).
+
+       * The racoon.conf file accepts "gssapi_krb" as authentication
+         method inside a proposal specification. The number used
+         for this method is 65001, which is a temporary number as
+         specified in the draft.
+
+       * The cftoken.l and cfparse.y source files were modified to
+         pick up the configuration options. The original sources
+         stored algorithms in bitmask, which unfortunately meant
+         that the maximum value was 32, clearly not enough for 65001.
+         After consulting with the author (sakane@kame.net), it turned
+         out that method was a leftover, and no longer needed. I replaced
+         it with plain integers.
+
+       * The gss-api specific code was concentrated as much as possible
+         in gssapi.c and gssapi.h. The code to call functions defined
+         in these files is conditional on HAVE_GSSAPI, except for the
+         config scan code. Specifying this flag on the compiler commandline
+         is conditional on the --enable-gssapi option to the configure
+         script.
+
+       * Racoon seems to want to send accepted SA proposals back to
+         the initiator in a verbatim fashion, leaving no room to
+         insert the (variable-length) GSS endpoint name attribute.
+         I worked around this by re-assembling the extracted SA
+         into a new SA if the gssapi_krb method is used, and the
+         initiator sent the name attribute. This scheme should
+         possibly be re-examined by the racoon maintainers, storing
+         the SAs (the transformations, to be more precise) in a different
+         fashion to allow for variable-length attributes to be
+         re-inserted would be a good change, but I considered it to be
+         beyond the scope of this project.
+
+       * The various state functions for aggressive and main mode
+         (in isakmp_agg.c and isakmp_ident.c respectively) were
+         changed to conditionally change their behavior if the
+         gssapi_krb method is specified.
+
+
+This implementation tried to follow the specification in the ietf draft
+as close as possible. However, it has not been tested against other
+IKE daemon implementations. The only other one I know of is Windows 2000,
+and it has some caveats. I attempted to be Windows 2000 compatible.
+Should racoon be tried against Windows 2000, the gssapi_id option in
+the config file must be used, as Windows 2000 expects the GSS endpoint
+name to be sent at all times. I have my doubts as to the W2K compatibility,
+because the spec describes the GSS endpoint name sent by W2K as
+an unicode string 'xxx@domain', which doesn't seem to match the
+required standard for gss-api + kerberos 5 (i.e. I am fairly certain
+that such a string will be rejected by the Heimdal gss-api library, as it
+is not a valid Kerberos 5 principal).
+
+With the Heimdal gss-api implementation, the gssapi_krb authentication
+method will only work in main mode. Aggressive mode does not allow
+for the extra round-trips needed by gss_init_sec_context and
+gss_accept_sec_context when mutual authentication is requested.
+The draft specifies that the a fallback should be done to main mode,
+through the return of INVALID-EXCHANGE-TYPE if it turns out that
+the gss-api mechanisms needs more roundtrips. This is implemented.
+Unfortunately, racoon does not seem to properly fall back to
+its next mode, and this is not specific to the gssapi_krb method.
+So, to avoid problems, only specify main mode in the config file.
+
+
+       -- Frank van der Linden <fvdl@wasabisystems.com>
+
diff --git a/ipsec-tools/racoon/Documents/TODO b/ipsec-tools/racoon/Documents/TODO
new file mode 100644 (file)
index 0000000..1507167
--- /dev/null
@@ -0,0 +1,131 @@
+$KAME: TODO,v 1.36 2001/09/19 09:41:39 sakane Exp $
+
+Please send any questions or bug reports to snap-users@kame.net.
+
+TODO list
+
+URGENT
+o The documents for users convenience.
+o split log file based on client.  printf-like config directive, i.e.
+  "logfile racoon.%s.log", should be useful here.
+  -> beware of possible security issue, don't use sprintf() directly!
+     make validation before giving a string to sprintf().
+o save decrypted IKE packet in tcpdump format
+o IPComp SA with wellknown CPI in CPI field.  how to handle it?
+o better rekey
+
+MUST
+o multiple certificate payload handling.
+o To consider the use with certificate infrastructure.  PXIX ???
+o kmstat should be improved.
+o Informational Exchange processing properly.
+o require less configuration.  phase 2 is easier (as kernel presents racoon
+  some hints), phase 1 is harder.  for example,
+  - grab phase 2 lifetime and algorith configuration from sadb_comb payloads in
+    ACQUIRE message.
+  - give reasonable default behavior when no configuration file is present.
+  - difficult items:
+       how to guess a reasonable phase 1 SA lifetime
+               (hardcoded default?  guess from phase 2 lifetime?)
+       guess what kind of ID payload to use
+       guess what kind of authentication to be used
+       guess phase 1 DH group (for aggressive mode, we cannot negotiate it)
+       guess if we need phase 2 PFS or not (we cannot negotiate it. so
+               we may need to pick from "no PFS" or "same as phase 1 DH group")
+       guess how we should negotiate lifetime
+               (is "strict" a reasonable default?)
+       guess which mode to use for phase 1 negotiation (is main mode useful?
+               is base mode popular enough?)
+o more acceptable check.
+
+SHOULD
+o psk.txt should be a database? (psk.db?)  psk_mkdb?
+o Dynamically retry to exchange and resend the packet per nodes.
+o To make the list of supported algorithm by sadb_supported payload
+  in the SADB_REGISTER message which happens asynchronously.
+o fix the structure of ph2handle.
+  We can handle the below case.
+
+  node A                            node B
+    +--------------SA1----------------+
+    +--------------SA2----------------+
+
+  at node A:
+  kernel
+    acquire(A-B) ------> ph2handle(A=B) -----> ph1handle
+                              |
+                            policy
+                             A=B
+                             A=B
+
+  But we can not handle the below case because there is no x?handle.
+
+  node A                            node B                           node C
+    +--------------SA1----------------+
+    +------------------------------------------------SA2---------------+
+
+  at node A:
+  kernel
+    acquire(A-C) ---+---> x?handle ---+---> ph2handle(A=B) -------> ph1handle
+                    |        |        |
+    acquire(A-B) ---+      policy     +---> ph2handle(A=C) -------> ph1handle
+                            A=B
+                            A=C
+
+o consistency of function name.
+o deep copy configuration entry to hander.  It's easy to reload configuration.
+o don't keep to hold keymat values, do it ?
+o local address's field in isakmpsa handler must be kicked out to rmconf.
+o responder policy and initiator policy should be separated.
+o for lifetime and key length, something like this should be useful.
+  - propose N
+  - accept between X and Y
+o wildcard "accept any proposal" policy should be allowed.
+o replay prevention
+  - limited total number of session
+  - limited session per peer
+  - number of proposal
+o full support for variable length SPI.  quickhack support for IPComp is done.
+
+MAY
+o Effective code.
+o interaction between IKE/IPsec and socket layer.
+  at this moment, IKE/IPsec failure is modeled as total packet loss to other
+  part of network subsystem, including socket layer.  this presents the
+  following behaviors:
+  - annoyingly long timeouts on tcp connection attempt, and IKE failure;
+    need to wait till tcp socket timeouts.
+  - blackhole if there's mismatching SAs.
+  we may be able to give socket layer some feedback from IKE/IPsec layer.
+  still not sure if those make sense or not.
+  for example:
+  - send PRU_HOSTDEAD to sockets if IKE negotiation failed
+    (sys/netkey/key.c:key_acquire2)
+    to do this, we need to remember which ACQUIRE was caused by which socket,
+    possibly into larval SAs.
+  - PRU_QUENCH on "no SA found on output"
+  - kick tcp retransmission timer on first SA establishment
+o IKE daemon should handle situations where peer does not run IKE daemon
+  (UDP port unreach for port 500) better.
+  should use connected UDP sockets for sending IKE datagrams.
+o rate-limit log messages from kernel IPsec errors, like "no SA found".
+
+TO BE TESTED.
+o IKE retransmit behavior
+       see, draft-*-ipsec-rekeying*.txt
+o Reboot recovery (peer reboot losing it's security associations)
+       see, draft-*-ipsec-rekeying*.txt
+o Scenarios
+       - End-to-End transport long lived security associations
+         (over night, data transfer >1Gb) with frequent dynamic rekey
+       - End-to-GW tunnel long lived security associations
+         (over night, data transfer >1Gb) with frequent dynamic rekey
+       - Policy change events while under SA load
+       - End-to-End SA through IPsec tunnels, initiation both ways
+       - Client End-to-End through client-to-GW tunnel SA, initiate from
+         client for tunnel, then initiation both ways for end-to-end
+       - Client-to-GW transport SA for secure management
+o behavior to receive multiple auth method proposals and AND proposal
+
+and to be written many many.
+
diff --git a/ipsec-tools/racoon/Sample/anonymous.conf b/ipsec-tools/racoon/Sample/anonymous.conf
new file mode 100644 (file)
index 0000000..70b0ed4
--- /dev/null
@@ -0,0 +1,34 @@
+remote anonymous
+{
+        #exchange_mode main,aggressive;
+        exchange_mode aggressive,main;
+        doi ipsec_doi;
+        situation identity_only;
+
+        #my_identifier address;
+        my_identifier user_fqdn "macuser@localhost";
+        peers_identifier user_fqdn "macuser@localhost";
+        #certificate_type x509 "mycert" "mypriv";
+
+        nonce_size 16;
+        lifetime time 1 min;    # sec,min,hour
+        initial_contact on;
+        support_mip6 on;
+        proposal_check obey;    # obey, strict or claim
+
+        proposal {
+                encryption_algorithm 3des;
+                hash_algorithm sha1;
+                authentication_method pre_shared_key ;
+                dh_group 2 ;
+        }
+}
+
+sainfo anonymous
+{
+       pfs_group 1;
+       lifetime time 30 sec;
+       encryption_algorithm aes, 3des ;
+       authentication_algorithm hmac_sha1;
+       compression_algorithm deflate ;
+}
diff --git a/ipsec-tools/racoon/Sample/psk.txt b/ipsec-tools/racoon/Sample/psk.txt
new file mode 100644 (file)
index 0000000..d7de289
--- /dev/null
@@ -0,0 +1,10 @@
+# IPv4/v6 addresses
+# 10.160.94.3  asecretkeygoeshere
+# 172.16.1.133 asecretkeygoeshere
+# 3ffe:501:410:ffff:200:86ff:fe05:80fa asecretkeygoeshere
+# 3ffe:501:410:ffff:210:4bff:fea2:8baa asecretkeygoeshere
+
+# USER_FQDN
+# macuser@localhost    somethingsecret
+# FQDN
+# kame         hoge
diff --git a/ipsec-tools/racoon/Sample/racoon.conf b/ipsec-tools/racoon/Sample/racoon.conf
new file mode 100644 (file)
index 0000000..2a6112b
--- /dev/null
@@ -0,0 +1,137 @@
+# $KAME: racoon.conf.in,v 1.17 2001/08/14 12:10:22 sakane Exp $
+
+# "path" must be placed before it should be used.
+# You can overwrite which you defined, but it should not use due to confusing.
+path include "/etc/racoon" ;
+
+# Allow third parties the ability to specify remote and sainfo entries
+# by including all files matching /etc/racoon/remote/*.conf
+include "/etc/racoon/remote/*.conf" ;
+
+# search this file for pre_shared_key with various ID key.
+path pre_shared_key "/etc/racoon/psk.txt" ;
+
+# racoon will look for certificate file in the directory,
+# if the certificate/certificate request payload is received.
+path certificate "/etc/cert" ;
+
+# "log" specifies logging level.  It is followed by either "notify", "debug"
+# or "debug2".
+#log debug;
+
+# "padding" defines some parameter of padding.  You should not touch these.
+padding
+{
+       maximum_length 20;      # maximum padding length.
+       randomize off;          # enable randomize length.
+       strict_check off;       # enable strict check.
+       exclusive_tail off;     # extract last one octet.
+}
+
+# if no listen directive is specified, racoon will listen to all
+# available interface addresses.
+listen
+{
+       #isakmp ::1 [7000];
+       #isakmp 202.249.11.124 [500];
+       #admin [7002];          # administrative's port by kmpstat.
+       #strict_address;        # required all addresses must be bound.
+}
+
+# Specification of default various timer.
+timer
+{
+       # These value can be changed per remote node.
+       counter 10;             # maximum trying count to send.
+       interval 3 sec; # interval to resend (retransmit)
+       persend 1;              # the number of packets per a send.
+
+       # timer for waiting to complete each phase.
+       phase1 30 sec;
+       phase2 30 sec;
+       
+       # Auto exit delay timer - for use when controlled by VPN socket
+       auto_exit_delay 3 sec;
+}
+
+#
+# anonymous entry is defined in /etc/racoon/remote/anonymous.conf
+#
+#remote anonymous
+#{
+#      #exchange_mode main,aggressive;
+#      exchange_mode aggressive,main;
+#      doi ipsec_doi;
+#      situation identity_only;
+#
+#      #my_identifier address;
+#      my_identifier user_fqdn "macuser@localhost";
+#      peers_identifier user_fqdn "macuser@localhost";
+#      #certificate_type x509 "mycert" "mypriv";
+#
+#      nonce_size 16;
+#      lifetime time 1 min;    # sec,min,hour
+#      initial_contact on;
+#      support_mip6 on;
+#      proposal_check obey;    # obey, strict or claim
+#
+#      proposal {
+#              encryption_algorithm 3des;
+#              hash_algorithm sha1;
+#              authentication_method pre_shared_key ;
+#              dh_group 2 ;
+#      }
+#}
+
+remote ::1 [8000]
+{
+       #exchange_mode main,aggressive;
+       exchange_mode aggressive,main;
+       doi ipsec_doi;
+       situation identity_only;
+
+       my_identifier user_fqdn "macuser@localhost";
+       peers_identifier user_fqdn "macuser@localhost";
+       #certificate_type x509 "mycert" "mypriv";
+
+       nonce_size 16;
+       lifetime time 1 min;    # sec,min,hour
+
+       proposal {
+               encryption_algorithm 3des;
+               hash_algorithm sha1;
+               authentication_method pre_shared_key ;
+               dh_group 2 ;
+       }
+}
+
+#
+# anonymous entry is defined in /etc/racoon/remote/anonymous.conf
+#
+#sainfo anonymous
+#{
+#      pfs_group 1;
+#      lifetime time 30 sec;
+#      encryption_algorithm aes, 3des ;
+#      authentication_algorithm hmac_sha1;
+#      compression_algorithm deflate ;
+#}
+
+# sainfo address 203.178.141.209 any address 203.178.141.218 any
+# {
+#      pfs_group 1;
+#      lifetime time 30 sec;
+#      encryption_algorithm des ;
+#      authentication_algorithm hmac_md5;
+#      compression_algorithm deflate ;
+# }
+
+sainfo address ::1 icmp6 address ::1 icmp6
+{
+       pfs_group 1;
+       lifetime time 60 sec;
+       encryption_algorithm 3des, cast128, blowfish 448, des ;
+       authentication_algorithm hmac_sha1, hmac_md5 ;
+       compression_algorithm deflate ;
+}
+
diff --git a/ipsec-tools/racoon/admin.c b/ipsec-tools/racoon/admin.c
new file mode 100644 (file)
index 0000000..344e2f4
--- /dev/null
@@ -0,0 +1,640 @@
+/* $Id: admin.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include <netinet/in.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else 
+#include <netinet6/ipsec.h>
+#endif
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "grabmyaddr.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "handler.h"
+#include "evt.h"
+#include "pfkey.h"
+#include "ipsec_doi.h"
+#include "admin.h"
+#include "admin_var.h"
+#include "isakmp_inf.h"
+#include "session.h"
+#include "gcmalloc.h"
+
+#ifdef ENABLE_ADMINPORT
+char *adminsock_path = ADMINSOCK_PATH;
+uid_t adminsock_owner = 0;
+gid_t adminsock_group = 0;
+mode_t adminsock_mode = 0600;
+
+static struct sockaddr_un sunaddr;
+static int admin_process __P((int, char *));
+static int admin_reply __P((int, struct admin_com *, vchar_t *));
+
+int
+admin_handler()
+{
+       int so2;
+       struct sockaddr_storage from;
+       socklen_t fromlen = sizeof(from);
+       struct admin_com com;
+       char *combuf = NULL;
+       pid_t pid = -1;
+       int len, error = -1;
+
+       so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
+       if (so2 < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to accept admin command: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+
+       /* get buffer length */
+       while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to recv admin command: %s\n",
+                       strerror(errno));
+               goto end;
+       }
+
+       /* sanity check */
+       if (len < sizeof(com)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid header length of admin command\n");
+               goto end;
+       }
+
+       /* get buffer to receive */
+       if ((combuf = racoon_malloc(com.ac_len)) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to alloc buffer for admin command\n");
+               goto end;
+       }
+
+       /* get real data */
+       while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to recv admin command: %s\n",
+                       strerror(errno));
+               goto end;
+       }
+
+       if (com.ac_cmd == ADMIN_RELOAD_CONF) {
+               /* reload does not work at all! */
+               signal_handler(SIGHUP);
+               goto end;
+       }
+
+       error = admin_process(so2, combuf);
+
+    end:
+       (void)close(so2);
+       if (combuf)
+               racoon_free(combuf);
+
+       /* exit if child's process. */
+       if (pid == 0 && !f_foreground)
+               exit(error);
+
+       return error;
+}
+
+/*
+ * main child's process.
+ */
+static int
+admin_process(so2, combuf)
+       int so2;
+       char *combuf;
+{
+       struct admin_com *com = (struct admin_com *)combuf;
+       vchar_t *buf = NULL;
+       vchar_t *id = NULL;
+       vchar_t *key = NULL;
+       int idtype = 0;
+       int error = 0;
+
+       com->ac_errno = 0;
+
+       switch (com->ac_cmd) {
+       case ADMIN_RELOAD_CONF:
+               /* don't entered because of proccessing it in other place. */
+               plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
+               goto bad;
+
+       case ADMIN_SHOW_SCHED:
+       {
+               caddr_t p;
+               int len;
+               if (sched_dump(&p, &len) == -1)
+                       com->ac_errno = -1;
+               buf = vmalloc(len);
+               if (buf == NULL)
+                       com->ac_errno = -1;
+               else
+                       memcpy(buf->v, p, len);
+       }
+               break;
+
+       case ADMIN_SHOW_EVT:
+               /* It's not really an error, don't force racoonctl to quit */
+               if ((buf = evt_dump()) == NULL)
+                       com->ac_errno = 0; 
+               break;
+
+       case ADMIN_SHOW_SA:
+       case ADMIN_FLUSH_SA:
+           {
+               switch (com->ac_proto) {
+               case ADMIN_PROTO_ISAKMP:
+                       switch (com->ac_cmd) {
+                       case ADMIN_SHOW_SA:
+                               buf = dumpph1();
+                               if (buf == NULL)
+                                       com->ac_errno = -1;
+                               break;
+                       case ADMIN_FLUSH_SA:
+                               flushph1();
+                               break;
+                       }
+                       break;
+               case ADMIN_PROTO_IPSEC:
+               case ADMIN_PROTO_AH:
+               case ADMIN_PROTO_ESP:
+                       switch (com->ac_cmd) {
+                       case ADMIN_SHOW_SA:
+                           {
+                               u_int p;
+                               p = admin2pfkey_proto(com->ac_proto);
+                               if (p == -1)
+                                       goto bad;
+                               buf = pfkey_dump_sadb(p);
+                               if (buf == NULL)
+                                       com->ac_errno = -1;
+                           }
+                               break;
+                       case ADMIN_FLUSH_SA:
+                               pfkey_flush_sadb(com->ac_proto);
+                               break;
+                       }
+                       break;
+
+               case ADMIN_PROTO_INTERNAL:
+                       switch (com->ac_cmd) {
+                       case ADMIN_SHOW_SA:
+                               buf = NULL; /*XXX dumpph2(&error);*/
+                               if (buf == NULL)
+                                       com->ac_errno = error;
+                               break;
+                       case ADMIN_FLUSH_SA:
+                               /*XXX flushph2();*/
+                               com->ac_errno = 0;
+                               break;
+                       }
+                       break;
+
+               default:
+                       /* ignore */
+                       com->ac_errno = -1;
+               }
+           }
+               break;
+
+       case ADMIN_DELETE_SA: {
+               struct ph1handle *iph1;
+               struct sockaddr *dst;
+               struct sockaddr *src;
+               char *loc, *rem;
+
+               src = (struct sockaddr *)
+                       &((struct admin_com_indexes *)
+                           ((caddr_t)com + sizeof(*com)))->src;
+               dst = (struct sockaddr *)
+                       &((struct admin_com_indexes *)
+                           ((caddr_t)com + sizeof(*com)))->dst;
+
+               if ((loc = strdup(saddrwop2str(src))) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "cannot allocate memory\n");
+                       break;
+               }
+               if ((rem = strdup(saddrwop2str(dst))) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "cannot allocate memory\n");
+                       break;
+               }
+
+               if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "phase 1 for %s -> %s not found\n", loc, rem);
+               } else {
+                       if (iph1->status == PHASE1ST_ESTABLISHED)
+                               isakmp_info_send_d1(iph1);
+                       purge_remote(iph1);
+               }
+
+               racoon_free(loc);
+               racoon_free(rem);
+
+               break;
+       }
+
+       case ADMIN_DELETE_ALL_SA_DST: {
+               struct ph1handle *iph1;
+               struct sockaddr *dst;
+               char *loc, *rem;
+
+               dst = (struct sockaddr *)
+                       &((struct admin_com_indexes *)
+                           ((caddr_t)com + sizeof(*com)))->dst;
+
+               if ((rem = strdup(saddrwop2str(dst))) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "cannot allocate memory\n");
+                       break;
+               }
+
+               plog(LLV_INFO, LOCATION, NULL, 
+                   "Flushing all SAs for peer %s\n", rem);
+
+               while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
+                       if ((loc = strdup(saddrwop2str(iph1->local))) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "cannot allocate memory\n");
+                               break;
+                       }
+
+                       if (iph1->status == PHASE1ST_ESTABLISHED)
+                               isakmp_info_send_d1(iph1);
+                       purge_remote(iph1);
+
+                       racoon_free(loc);
+               }
+               
+               racoon_free(rem);
+
+               break;
+       }
+
+       case ADMIN_ESTABLISH_SA_PSK: {
+               struct admin_com_psk *acp;
+               char *data;
+
+               com->ac_cmd = ADMIN_ESTABLISH_SA;
+
+               acp = (struct admin_com_psk *)
+                   ((char *)com + sizeof(*com) + 
+                   sizeof(struct admin_com_indexes));
+
+               idtype = acp->id_type;
+
+               if ((id = vmalloc(acp->id_len)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "cannot allocate memory: %s\n", 
+                           strerror(errno));
+                       break;
+               }
+               data = (char *)(acp + 1);
+               memcpy(id->v, data, id->l);
+
+               if ((key = vmalloc(acp->key_len)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "cannot allocate memory: %s\n", 
+                           strerror(errno));
+                       vfree(id);
+                       break;
+               }
+               data = (char *)(data + acp->id_len);
+               memcpy(key->v, data, key->l);
+       }
+       /* FALLTHROUGH */
+       case ADMIN_ESTABLISH_SA:
+           {
+               struct sockaddr *dst;
+               struct sockaddr *src;
+               src = (struct sockaddr *)
+                       &((struct admin_com_indexes *)
+                           ((caddr_t)com + sizeof(*com)))->src;
+               dst = (struct sockaddr *)
+                       &((struct admin_com_indexes *)
+                           ((caddr_t)com + sizeof(*com)))->dst;
+
+               switch (com->ac_proto) {
+               case ADMIN_PROTO_ISAKMP:
+                   {
+                       struct remoteconf *rmconf;
+                       struct sockaddr *remote;
+                       struct sockaddr *local;
+
+                       /* search appropreate configuration */
+                       rmconf = getrmconf(dst);
+                       if (rmconf == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no configuration found "
+                                       "for %s\n", saddrwop2str(dst));
+                               com->ac_errno = -1;
+                               break;
+                       }
+
+                       /* get remote IP address and port number. */
+                       remote = dupsaddr(dst);
+                       if (remote == NULL) {
+                               com->ac_errno = -1;
+                               break;
+                       }
+                       switch (remote->sa_family) {
+                       case AF_INET:
+                               ((struct sockaddr_in *)remote)->sin_port =
+                                       ((struct sockaddr_in *)rmconf->remote)->sin_port;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)remote)->sin6_port =
+                                       ((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
+                               break;
+#endif
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid family: %d\n",
+                                       remote->sa_family);
+                               com->ac_errno = -1;
+                               break;
+                       }
+
+                       /* get local address */
+                       local = dupsaddr(src);
+                       if (local == NULL) {
+                               com->ac_errno = -1;
+                               break;
+                       }
+                       switch (local->sa_family) {
+                       case AF_INET:
+                               ((struct sockaddr_in *)local)->sin_port =
+                                       getmyaddrsport(local);
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)local)->sin6_port =
+                                       getmyaddrsport(local);
+                               break;
+#endif
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid family: %d\n",
+                                       local->sa_family);
+                               com->ac_errno = -1;
+                               break;
+                       }
+
+                       /* Set the id and key */
+                       if (id && key) {
+                               if (rmconf->idv != NULL) {
+                                       vfree(rmconf->idv);
+                                       rmconf->idv = NULL;
+                               }
+                               if (rmconf->key != NULL) {
+                                       vfree(rmconf->key);
+                                       rmconf->key = NULL;
+                               }
+
+                               rmconf->idvtype = idtype;
+                               rmconf->idv = id;
+                               rmconf->key = key;
+                       }
+                       plog(LLV_INFO, LOCATION, NULL,
+                               "accept a request to establish IKE-SA: "
+                               "%s\n", saddrwop2str(remote));
+
+                       /* begin ident mode */
+                       if (isakmp_ph1begin_i(rmconf, remote, local) < 0) {
+                               com->ac_errno = -1;
+                               break;
+                       }
+                   }
+                       break;
+               case ADMIN_PROTO_AH:
+               case ADMIN_PROTO_ESP:
+                       break;
+               default:
+                       /* ignore */
+                       com->ac_errno = -1;
+               }
+           }
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid command: %d\n", com->ac_cmd);
+               com->ac_errno = -1;
+       }
+
+       if (admin_reply(so2, com, buf) < 0)
+               goto bad;
+
+       if (buf != NULL)
+               vfree(buf);
+
+       return 0;
+
+    bad:
+       if (buf != NULL)
+               vfree(buf);
+       return -1;
+}
+
+static int
+admin_reply(so, combuf, buf)
+       int so;
+       struct admin_com *combuf;
+       vchar_t *buf;
+{
+       int tlen;
+       char *retbuf = NULL;
+
+       if (buf != NULL)
+               tlen = sizeof(*combuf) + buf->l;
+       else
+               tlen = sizeof(*combuf);
+
+       retbuf = racoon_calloc(1, tlen);
+       if (retbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate admin buffer\n");
+               return -1;
+       }
+
+       memcpy(retbuf, combuf, sizeof(*combuf));
+       ((struct admin_com *)retbuf)->ac_len = tlen;
+
+       if (buf != NULL)
+               memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
+
+       tlen = send(so, retbuf, tlen, 0);
+       racoon_free(retbuf);
+       if (tlen < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to send admin command: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+/* ADMIN_PROTO -> SADB_SATYPE */
+int
+admin2pfkey_proto(proto)
+       u_int proto;
+{
+       switch (proto) {
+       case ADMIN_PROTO_IPSEC:
+               return SADB_SATYPE_UNSPEC;
+       case ADMIN_PROTO_AH:
+               return SADB_SATYPE_AH;
+       case ADMIN_PROTO_ESP:
+               return SADB_SATYPE_ESP;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unsupported proto for admin: %d\n", proto);
+               return -1;
+       }
+       /*NOTREACHED*/
+}
+
+int
+admin_init()
+{
+       if (adminsock_path == NULL) {
+               lcconf->sock_admin = -1;
+               return 0;
+       }
+
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
+               "%s", adminsock_path);
+
+       lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (lcconf->sock_admin == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "socket: %s\n", strerror(errno));
+               return -1;
+       }
+
+       unlink(sunaddr.sun_path);
+       if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
+                       sizeof(sunaddr)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "bind(sockname:%s): %s\n",
+                       sunaddr.sun_path, strerror(errno));
+               (void)close(lcconf->sock_admin);
+               return -1;
+       }
+
+       if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "chown(%s, %d, %d): %s\n", 
+                   sunaddr.sun_path, adminsock_owner, 
+                   adminsock_group, strerror(errno));
+               (void)close(lcconf->sock_admin);
+               return -1;
+       }
+
+       if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "chmod(%s, 0%03o): %s\n", 
+                   sunaddr.sun_path, adminsock_mode, strerror(errno));
+               (void)close(lcconf->sock_admin);
+               return -1;
+       }
+
+       if (listen(lcconf->sock_admin, 5) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "listen(sockname:%s): %s\n",
+                       sunaddr.sun_path, strerror(errno));
+               (void)close(lcconf->sock_admin);
+               return -1;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "open %s as racoon management.\n", sunaddr.sun_path);
+
+       return 0;
+}
+
+int
+admin_close()
+{
+       close(lcconf->sock_admin);
+       return 0;
+}
+#endif
diff --git a/ipsec-tools/racoon/admin.h b/ipsec-tools/racoon/admin.h
new file mode 100644 (file)
index 0000000..e07616d
--- /dev/null
@@ -0,0 +1,107 @@
+/* $Id: admin.h,v 1.10 2004/12/30 13:45:49 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ADMIN_H
+#define _ADMIN_H
+
+#define ADMINSOCK_PATH ADMINPORTDIR "/racoon.sock"
+
+extern char *adminsock_path;
+extern uid_t adminsock_owner;
+extern gid_t adminsock_group;
+extern mode_t adminsock_mode;
+
+/* command for administration. */
+/* NOTE: host byte order. */
+struct admin_com {
+       u_int16_t ac_len;       /* total packet length including data */
+       u_int16_t ac_cmd;
+       int16_t ac_errno;
+       u_int16_t ac_proto;
+};
+
+/*
+ * No data follows as the data.
+ * These don't use proto field.
+ */
+#define ADMIN_RELOAD_CONF      0x0001
+#define ADMIN_SHOW_SCHED       0x0002
+#define ADMIN_SHOW_EVT         0x0003
+
+/*
+ * No data follows as the data.
+ * These use proto field.
+ */
+#define ADMIN_SHOW_SA          0x0101
+#define ADMIN_FLUSH_SA         0x0102
+
+/*
+ * The admin_com_indexes follows, see below.
+ */
+#define ADMIN_DELETE_SA                0x0201
+#define ADMIN_ESTABLISH_SA     0x0202
+#define ADMIN_DELETE_ALL_SA_DST        0x0204  /* All SA for a given peer */
+
+/*
+ * The admin_com_indexes and admin_com_psk follow, see below.
+ */
+#define ADMIN_ESTABLISH_SA_PSK 0x0203
+
+/*
+ * Range 0x08xx is reserved for privilege separation, see privsep.h 
+ */
+
+/* the value of proto */
+#define ADMIN_PROTO_ISAKMP     0x01ff
+#define ADMIN_PROTO_IPSEC      0x02ff
+#define ADMIN_PROTO_AH         0x0201
+#define ADMIN_PROTO_ESP                0x0202
+#define ADMIN_PROTO_INTERNAL   0x0301
+
+struct admin_com_indexes {
+       u_int8_t prefs;
+       u_int8_t prefd;
+       u_int8_t ul_proto;
+       u_int8_t reserved;
+       struct sockaddr_storage src;
+       struct sockaddr_storage dst;
+};
+
+struct admin_com_psk { 
+       int id_type;
+       size_t id_len;
+       size_t key_len;
+       /* Followed by id and key */
+}; 
+
+extern int admin2pfkey_proto __P((u_int));
+
+#endif /* _ADMIN_H */
diff --git a/ipsec-tools/racoon/admin_var.h b/ipsec-tools/racoon/admin_var.h
new file mode 100644 (file)
index 0000000..4054695
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: admin_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ADMIN_VAR_H
+#define _ADMIN_VAR_H
+
+extern int admin_handler __P((void));
+extern int admin_init __P((void));
+extern int admin_close __P((void));
+
+#endif /* _ADMIN_VAR_H */
diff --git a/ipsec-tools/racoon/algorithm.c b/ipsec-tools/racoon/algorithm.c
new file mode 100644 (file)
index 0000000..1af0150
--- /dev/null
@@ -0,0 +1,915 @@
+/* $Id: algorithm.c,v 1.11.4.1 2005/06/28 22:38:02 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "crypto_openssl.h"
+#include "dhgroup.h"
+#include "algorithm.h"
+#include "oakley.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "gcmalloc.h"
+
+static struct hash_algorithm oakley_hashdef[] = {
+{ "md5",       algtype_md5,            OAKLEY_ATTR_HASH_ALG_MD5,
+               eay_md5_init,           eay_md5_update,
+               eay_md5_final,          eay_md5_hashlen,
+               eay_md5_one, },
+{ "sha1",      algtype_sha1,           OAKLEY_ATTR_HASH_ALG_SHA,
+               eay_sha1_init,          eay_sha1_update,
+               eay_sha1_final,         eay_sha1_hashlen,
+               eay_sha1_one, },
+#ifdef WITH_SHA2
+{ "sha2_256",  algtype_sha2_256,       OAKLEY_ATTR_HASH_ALG_SHA2_256,
+               eay_sha2_256_init,      eay_sha2_256_update,
+               eay_sha2_256_final,     eay_sha2_256_hashlen,
+               eay_sha2_256_one, },
+{ "sha2_384",  algtype_sha2_384,       OAKLEY_ATTR_HASH_ALG_SHA2_384,
+               eay_sha2_384_init,      eay_sha2_384_update,
+               eay_sha2_384_final,     eay_sha2_384_hashlen,
+               eay_sha2_384_one, },
+{ "sha2_512",  algtype_sha2_512,       OAKLEY_ATTR_HASH_ALG_SHA2_512,
+               eay_sha2_512_init,      eay_sha2_512_update,
+               eay_sha2_512_final,     eay_sha2_512_hashlen,
+               eay_sha2_512_one, },
+#endif
+};
+
+static struct hmac_algorithm oakley_hmacdef[] = {
+{ "hmac_md5",  algtype_md5,            OAKLEY_ATTR_HASH_ALG_MD5,
+               eay_hmacmd5_init,       eay_hmacmd5_update,
+               eay_hmacmd5_final,      NULL,
+               eay_hmacmd5_one, },
+{ "hmac_sha1", algtype_sha1,           OAKLEY_ATTR_HASH_ALG_SHA,
+               eay_hmacsha1_init,      eay_hmacsha1_update,
+               eay_hmacsha1_final,     NULL,
+               eay_hmacsha1_one, },
+#ifdef WITH_SHA2
+{ "hmac_sha2_256",     algtype_sha2_256,       OAKLEY_ATTR_HASH_ALG_SHA2_256,
+               eay_hmacsha2_256_init,  eay_hmacsha2_256_update,
+               eay_hmacsha2_256_final, NULL,
+               eay_hmacsha2_256_one, },
+{ "hmac_sha2_384",     algtype_sha2_384,       OAKLEY_ATTR_HASH_ALG_SHA2_384,
+               eay_hmacsha2_384_init,  eay_hmacsha2_384_update,
+               eay_hmacsha2_384_final, NULL,
+               eay_hmacsha2_384_one, },
+{ "hmac_sha2_512",     algtype_sha2_512,       OAKLEY_ATTR_HASH_ALG_SHA2_512,
+               eay_hmacsha2_512_init,  eay_hmacsha2_512_update,
+               eay_hmacsha2_512_final, NULL,
+               eay_hmacsha2_512_one, },
+#endif
+};
+
+static struct enc_algorithm oakley_encdef[] = {
+{ "des",       algtype_des,            OAKLEY_ATTR_ENC_ALG_DES,        8,
+               eay_des_encrypt,        eay_des_decrypt,
+               eay_des_weakkey,        eay_des_keylen, },
+#ifdef HAVE_OPENSSL_IDEA_H
+{ "idea",      algtype_idea,           OAKLEY_ATTR_ENC_ALG_IDEA,       8,
+               eay_idea_encrypt,       eay_idea_decrypt,
+               eay_idea_weakkey,       eay_idea_keylen, },
+#endif
+{ "blowfish",  algtype_blowfish,       OAKLEY_ATTR_ENC_ALG_BLOWFISH,   8,
+               eay_bf_encrypt,         eay_bf_decrypt,
+               eay_bf_weakkey,         eay_bf_keylen, },
+#ifdef HAVE_OPENSSL_RC5_H
+{ "rc5",       algtype_rc5,            OAKLEY_ATTR_ENC_ALG_RC5,        8,
+               eay_rc5_encrypt,        eay_rc5_decrypt,
+               eay_rc5_weakkey,        eay_rc5_keylen, },
+#endif
+{ "3des",      algtype_3des,           OAKLEY_ATTR_ENC_ALG_3DES,       8,
+               eay_3des_encrypt,       eay_3des_decrypt,
+               eay_3des_weakkey,       eay_3des_keylen, },
+{ "cast",      algtype_cast128,        OAKLEY_ATTR_ENC_ALG_CAST,       8,
+               eay_cast_encrypt,       eay_cast_decrypt,
+               eay_cast_weakkey,       eay_cast_keylen, },
+{ "aes",       algtype_aes,    OAKLEY_ATTR_ENC_ALG_AES,        16,
+               eay_aes_encrypt,        eay_aes_decrypt,
+               eay_aes_weakkey,        eay_aes_keylen, },
+};
+
+static struct enc_algorithm ipsec_encdef[] = {
+{ "des-iv64",  algtype_des_iv64,       IPSECDOI_ESP_DES_IV64,          8,
+               NULL,                   NULL,
+               NULL,                   eay_des_keylen, },
+{ "des",       algtype_des,            IPSECDOI_ESP_DES,               8,
+               NULL,                   NULL,
+               NULL,                   eay_des_keylen, },
+{ "3des",      algtype_3des,           IPSECDOI_ESP_3DES,              8,
+               NULL,                   NULL,
+               NULL,                   eay_3des_keylen, },
+#ifdef HAVE_OPENSSL_RC5_H
+{ "rc5",       algtype_rc5,            IPSECDOI_ESP_RC5,               8,
+               NULL,                   NULL,
+               NULL,                   eay_rc5_keylen, },
+#endif
+{ "cast",      algtype_cast128,        IPSECDOI_ESP_CAST,              8,
+               NULL,                   NULL,
+               NULL,                   eay_cast_keylen, },
+{ "blowfish",  algtype_blowfish,       IPSECDOI_ESP_BLOWFISH,          8,
+               NULL,                   NULL,
+               NULL,                   eay_bf_keylen, },
+{ "des-iv32",  algtype_des_iv32,       IPSECDOI_ESP_DES_IV32,          8,
+               NULL,                   NULL,
+               NULL,                   eay_des_keylen, },
+{ "null",      algtype_null_enc,       IPSECDOI_ESP_NULL,              8,
+               NULL,                   NULL,
+               NULL,                   eay_null_keylen, },
+{ "aes",       algtype_aes,            IPSECDOI_ESP_AES,               16,
+               NULL,                   NULL,
+               NULL,                   eay_aes_keylen, },
+{ "twofish",   algtype_twofish,        IPSECDOI_ESP_TWOFISH,           16,
+               NULL,                   NULL,
+               NULL,                   eay_twofish_keylen, },
+#ifdef HAVE_OPENSSL_IDEA_H
+{ "3idea",     algtype_3idea,          IPSECDOI_ESP_3IDEA,             8,
+               NULL,                   NULL,
+               NULL,                   NULL, },
+{ "idea",      algtype_idea,           IPSECDOI_ESP_IDEA,              8,
+               NULL,                   NULL,
+               NULL,                   NULL, },
+#endif
+{ "rc4",       algtype_rc4,            IPSECDOI_ESP_RC4,               8,
+               NULL,                   NULL,
+               NULL,                   NULL, },
+};
+
+static struct hmac_algorithm ipsec_hmacdef[] = {
+{ "md5",       algtype_hmac_md5,       IPSECDOI_ATTR_AUTH_HMAC_MD5,
+               NULL,                   NULL,
+               NULL,                   eay_md5_hashlen,
+               NULL, },
+{ "sha1",      algtype_hmac_sha1,      IPSECDOI_ATTR_AUTH_HMAC_SHA1,
+               NULL,                   NULL,
+               NULL,                   eay_sha1_hashlen,
+               NULL, },
+{ "kpdk",      algtype_kpdk,           IPSECDOI_ATTR_AUTH_KPDK,
+               NULL,                   NULL,
+               NULL,                   eay_kpdk_hashlen,
+               NULL, },
+{ "null",      algtype_non_auth,       IPSECDOI_ATTR_AUTH_NONE,
+               NULL,                   NULL,
+               NULL,                   eay_null_hashlen,
+               NULL, },
+#ifdef WITH_SHA2
+{ "hmac_sha2_256",     algtype_hmac_sha2_256,IPSECDOI_ATTR_AUTH_HMAC_SHA2_256,
+               NULL,                   NULL,
+               NULL,                   eay_sha2_256_hashlen,
+               NULL, },
+{ "hmac_sha2_384",     algtype_hmac_sha2_384,IPSECDOI_ATTR_AUTH_HMAC_SHA2_384,
+               NULL,                   NULL,
+               NULL,                   eay_sha2_384_hashlen,
+               NULL, },
+{ "hmac_sha2_512",     algtype_hmac_sha2_512,IPSECDOI_ATTR_AUTH_HMAC_SHA2_512,
+               NULL,                   NULL,
+               NULL,                   eay_sha2_512_hashlen,
+               NULL, },
+#endif
+};
+
+static struct misc_algorithm ipsec_compdef[] = {
+{ "oui",       algtype_oui,            IPSECDOI_IPCOMP_OUI, },
+{ "deflate",   algtype_deflate,        IPSECDOI_IPCOMP_DEFLATE, },
+{ "lzs",       algtype_lzs,            IPSECDOI_IPCOMP_LZS, },
+};
+
+static struct misc_algorithm oakley_authdef[] = {
+{ "pre_shared_key",    algtype_psk,            OAKLEY_ATTR_AUTH_METHOD_PSKEY, },
+{ "dsssig",    algtype_dsssig,         OAKLEY_ATTR_AUTH_METHOD_DSSSIG, },
+{ "rsasig",    algtype_rsasig,         OAKLEY_ATTR_AUTH_METHOD_RSASIG, },
+{ "rsaenc",    algtype_rsaenc,         OAKLEY_ATTR_AUTH_METHOD_RSAENC, },
+{ "rsarev",    algtype_rsarev,         OAKLEY_ATTR_AUTH_METHOD_RSAREV, },
+{ "gssapi_krb",        algtype_gssapikrb,      OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, },
+#ifdef ENABLE_HYBRID
+{ "hybrid_rsa_server",        algtype_hybrid_rsa_s,
+       OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I, },
+{ "hybrid_dss_server",        algtype_hybrid_dss_s,
+       OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I, },
+{ "hybrid_rsa_client",        algtype_hybrid_rsa_c,
+       OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R, },
+{ "hybrid_dss_client",        algtype_hybrid_dss_c,
+       OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R, },
+#endif
+};
+
+static struct dh_algorithm oakley_dhdef[] = {
+{ "modp768",   algtype_modp768,        OAKLEY_ATTR_GRP_DESC_MODP768,
+               &dh_modp768, },
+{ "modp1024",  algtype_modp1024,       OAKLEY_ATTR_GRP_DESC_MODP1024,
+               &dh_modp1024, },
+{ "modp1536",  algtype_modp1536,       OAKLEY_ATTR_GRP_DESC_MODP1536,
+               &dh_modp1536, },
+{ "modp2048",  algtype_modp2048,       OAKLEY_ATTR_GRP_DESC_MODP2048,
+               &dh_modp2048, },
+{ "modp3072",  algtype_modp3072,       OAKLEY_ATTR_GRP_DESC_MODP3072,
+               &dh_modp3072, },
+{ "modp4096",  algtype_modp4096,       OAKLEY_ATTR_GRP_DESC_MODP4096,
+               &dh_modp4096, },
+{ "modp6144",  algtype_modp6144,       OAKLEY_ATTR_GRP_DESC_MODP6144,
+               &dh_modp6144, },
+{ "modp8192",  algtype_modp8192,       OAKLEY_ATTR_GRP_DESC_MODP8192,
+               &dh_modp8192, },
+};
+
+static struct hash_algorithm *alg_oakley_hashdef __P((int));
+static struct hmac_algorithm *alg_oakley_hmacdef __P((int));
+static struct enc_algorithm *alg_oakley_encdef __P((int));
+static struct enc_algorithm *alg_ipsec_encdef __P((int));
+static struct hmac_algorithm *alg_ipsec_hmacdef __P((int));
+static struct dh_algorithm *alg_oakley_dhdef __P((int));
+
+/* oakley hash algorithm */
+static struct hash_algorithm *
+alg_oakley_hashdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(oakley_hashdef); i++)
+               if (doi == oakley_hashdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "hash(%s)\n",
+                               oakley_hashdef[i].name);
+                       return &oakley_hashdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_oakley_hashdef_ok(doi)
+       int doi;
+{
+       struct hash_algorithm *f;
+
+       f = alg_oakley_hashdef(doi);
+       if (f == NULL)
+               return 0;
+
+       return 1;
+}
+
+int
+alg_oakley_hashdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(oakley_hashdef); i++)
+               if (type == oakley_hashdef[i].type) {
+                       res = oakley_hashdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+int
+alg_oakley_hashdef_hashlen(doi)
+       int doi;
+{
+       struct hash_algorithm *f;
+
+       f = alg_oakley_hashdef(doi);
+       if (f == NULL || f->hashlen == NULL)
+               return 0;
+
+       return (f->hashlen)();
+}
+
+const char *
+alg_oakley_hashdef_name (doi)
+       int doi;
+{
+       struct hash_algorithm *f;
+
+       f = alg_oakley_hashdef(doi);
+       if (f == NULL)
+               return "*UNKNOWN*";
+
+       return f->name;
+}
+
+vchar_t *
+alg_oakley_hashdef_one(doi, buf)
+       int doi;
+       vchar_t *buf;
+{
+       struct hash_algorithm *f;
+
+       f = alg_oakley_hashdef(doi);
+       if (f == NULL || f->hashlen == NULL)
+               return NULL;
+
+       return (f->one)(buf);
+}
+
+/* oakley hmac algorithm */
+static struct hmac_algorithm *
+alg_oakley_hmacdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++)
+               if (doi == oakley_hmacdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+                               oakley_hmacdef[i].name);
+                       return &oakley_hmacdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_oakley_hmacdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++)
+               if (type == oakley_hmacdef[i].type) {
+                       res = oakley_hmacdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+vchar_t *
+alg_oakley_hmacdef_one(doi, key, buf)
+       int doi;
+       vchar_t *key, *buf;
+{
+       struct hmac_algorithm *f;
+       vchar_t *res;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       f = alg_oakley_hmacdef(doi);
+       if (f == NULL || f->one == NULL)
+               return NULL;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+
+       res = (f->one)(key, buf);
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s size=%d): %8.6f", __func__,
+               f->name, buf->l, timedelta(&start, &end));
+#endif
+
+       return res;
+}
+
+/* oakley encryption algorithm */
+static struct enc_algorithm *
+alg_oakley_encdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(oakley_encdef); i++)
+               if (doi == oakley_encdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n",
+                               oakley_encdef[i].name);
+                       return &oakley_encdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_oakley_encdef_ok(doi)
+       int doi;
+{
+       struct enc_algorithm *f;
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL)
+               return 0;
+
+       return 1;
+}
+
+int
+alg_oakley_encdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(oakley_encdef); i++)
+               if (type == oakley_encdef[i].type) {
+                       res = oakley_encdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+int
+alg_oakley_encdef_keylen(doi, len)
+       int doi, len;
+{
+       struct enc_algorithm *f;
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL || f->keylen == NULL)
+               return -1;
+
+       return (f->keylen)(len);
+}
+
+int
+alg_oakley_encdef_blocklen(doi)
+       int doi;
+{
+       struct enc_algorithm *f;
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL)
+               return -1;
+
+       return f->blocklen;
+}
+
+const char *
+alg_oakley_encdef_name (doi)
+       int doi;
+{
+       struct enc_algorithm *f;
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL)
+               return "*UNKNOWN*";
+
+       return f->name;
+}
+
+vchar_t *
+alg_oakley_encdef_decrypt(doi, buf, key, iv)
+       int doi;
+       vchar_t *buf, *key, *iv;
+{
+       vchar_t *res;
+       struct enc_algorithm *f;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL || f->decrypt == NULL)
+               return NULL;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+
+       res = (f->decrypt)(buf, key, iv);
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __func__,
+               f->name, key->l << 3, buf->l, timedelta(&start, &end));
+#endif
+       return res;
+}
+
+vchar_t *
+alg_oakley_encdef_encrypt(doi, buf, key, iv)
+       int doi;
+       vchar_t *buf, *key, *iv;
+{
+       vchar_t *res;
+       struct enc_algorithm *f;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       f = alg_oakley_encdef(doi);
+       if (f == NULL || f->encrypt == NULL)
+               return NULL;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+
+       res = (f->encrypt)(buf, key, iv);
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __func__,
+               f->name, key->l << 3, buf->l, timedelta(&start, &end));
+#endif
+       return res;
+}
+
+/* ipsec encryption algorithm */
+static struct enc_algorithm *
+alg_ipsec_encdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(ipsec_encdef); i++)
+               if (doi == ipsec_encdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n",
+                               ipsec_encdef[i].name);
+                       return &ipsec_encdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_ipsec_encdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(ipsec_encdef); i++)
+               if (type == ipsec_encdef[i].type) {
+                       res = ipsec_encdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+int
+alg_ipsec_encdef_keylen(doi, len)
+       int doi, len;
+{
+       struct enc_algorithm *f;
+
+       f = alg_ipsec_encdef(doi);
+       if (f == NULL || f->keylen == NULL)
+               return -1;
+
+       return (f->keylen)(len);
+}
+
+/* ipsec hmac algorithm */
+static struct hmac_algorithm *
+alg_ipsec_hmacdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++)
+               if (doi == ipsec_hmacdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+                               oakley_hmacdef[i].name);
+                       return &ipsec_hmacdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_ipsec_hmacdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++)
+               if (type == ipsec_hmacdef[i].type) {
+                       res = ipsec_hmacdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+int
+alg_ipsec_hmacdef_hashlen(doi)
+       int doi;
+{
+       struct hmac_algorithm *f;
+
+       f = alg_ipsec_hmacdef(doi);
+       if (f == NULL || f->hashlen == NULL)
+               return -1;
+
+       return (f->hashlen)();
+}
+
+/* ip compression */
+int
+alg_ipsec_compdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(ipsec_compdef); i++)
+               if (type == ipsec_compdef[i].type) {
+                       res = ipsec_compdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+/* dh algorithm */
+static struct dh_algorithm *
+alg_oakley_dhdef(doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(oakley_dhdef); i++)
+               if (doi == oakley_dhdef[i].doi) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+                               oakley_dhdef[i].name);
+                       return &oakley_dhdef[i];
+               }
+       return NULL;
+}
+
+int
+alg_oakley_dhdef_ok(doi)
+       int doi;
+{
+       struct dh_algorithm *f;
+
+       f = alg_oakley_dhdef(doi);
+       if (f == NULL)
+               return 0;
+
+       return 1;
+}
+
+int
+alg_oakley_dhdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(oakley_dhdef); i++)
+               if (type == oakley_dhdef[i].type) {
+                       res = oakley_dhdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+struct dhgroup *
+alg_oakley_dhdef_group(doi)
+       int doi;
+{
+       struct dh_algorithm *f;
+
+       f = alg_oakley_dhdef(doi);
+       if (f == NULL || f->dhgroup == NULL)
+               return NULL;
+
+       return f->dhgroup;
+}
+
+const char *
+alg_oakley_dhdef_name (doi)
+       int doi;
+{
+       struct dh_algorithm *f;
+       
+       f = alg_oakley_dhdef(doi);
+       if (f == NULL)
+               return "*UNKNOWN*";
+       return f->name;
+}
+
+/* authentication method */
+int
+alg_oakley_authdef_doi(type)
+       int type;
+{
+       int i, res = -1;
+
+       for (i = 0; i < ARRAYLEN(oakley_authdef); i++)
+               if (type == oakley_authdef[i].type) {
+                       res = oakley_authdef[i].doi;
+                       break;
+               }
+       return res;
+}
+
+const char *
+alg_oakley_authdef_name (doi)
+       int doi;
+{
+       int i;
+
+       for (i = 0; i < ARRAYLEN(oakley_authdef); i++)
+               if (doi == oakley_authdef[i].doi) {
+                       return oakley_authdef[i].name;
+               }
+       return "*UNKNOWN*";
+}
+
+/*
+ * give the default key length
+ * OUT:        -1:             NG
+ *     0:              fixed key cipher, key length not allowed
+ *     positive:       default key length
+ */
+int
+default_keylen(class, type)
+       int class, type;
+{
+
+       switch (class) {
+       case algclass_isakmp_enc:
+       case algclass_ipsec_enc:
+               break;
+       default:
+               return 0;
+       }
+
+       switch (type) {
+       case algtype_blowfish:
+       case algtype_rc5:
+       case algtype_cast128:
+       case algtype_aes:
+       case algtype_twofish:
+               return 128;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * check key length
+ * OUT:        -1:     NG
+ *     0:      OK
+ */
+int
+check_keylen(class, type, len)
+       int class, type, len;
+{
+       int badrange;
+
+       switch (class) {
+       case algclass_isakmp_enc:
+       case algclass_ipsec_enc:
+               break;
+       default:
+               /* unknown class, punt */
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unknown algclass %d\n", class);
+               return -1;
+       }
+
+       /* key length must be multiple of 8 bytes - RFC2451 2.2 */
+       switch (type) {
+       case algtype_blowfish:
+       case algtype_rc5:
+       case algtype_cast128:
+       case algtype_aes:
+       case algtype_twofish:
+               if (len % 8 != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "key length %d is not multiple of 8\n", len);
+                       return -1;
+               }
+               break;
+       }
+
+       /* key length range */
+       badrange = 0;
+       switch (type) {
+       case algtype_blowfish:
+               if (len < 40 || 448 < len)
+                       badrange++;
+               break;
+       case algtype_rc5:
+               if (len < 40 || 2040 < len)
+                       badrange++;
+               break;
+       case algtype_cast128:
+               if (len < 40 || 128 < len)
+                       badrange++;
+               break;
+       case algtype_aes:
+               if (!(len == 128 || len == 192 || len == 256))
+                       badrange++;
+               break;
+       case algtype_twofish:
+               if (len < 40 || 256 < len)
+                       badrange++;
+               break;
+       default:
+               if (len) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "key length is not allowed");
+                       return -1;
+               }
+               break;
+       }
+       if (badrange) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "key length out of range\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * convert algorithm type to DOI value.
+ * OUT -1   : NG
+ *     other: converted.
+ */
+int
+algtype2doi(class, type)
+       int class, type;
+{
+       int res = -1;
+
+       switch (class) {
+       case algclass_ipsec_enc:
+               res = alg_ipsec_encdef_doi(type);
+               break;
+       case algclass_ipsec_auth:
+               res = alg_ipsec_hmacdef_doi(type);
+               break;
+       case algclass_ipsec_comp:
+               res = alg_ipsec_compdef_doi(type);
+               break;
+       case algclass_isakmp_enc:
+               res =  alg_oakley_encdef_doi(type);
+               break;
+       case algclass_isakmp_hash:
+               res = alg_oakley_hashdef_doi(type);
+               break;
+       case algclass_isakmp_dh:
+               res = alg_oakley_dhdef_doi(type);
+               break;
+       case algclass_isakmp_ameth:
+               res = alg_oakley_authdef_doi(type);
+               break;
+       }
+       return res;
+}
+
+/*
+ * convert algorithm class to DOI value.
+ * OUT -1   : NG
+ *     other: converted.
+ */
+int
+algclass2doi(class)
+       int class;
+{
+       switch (class) {
+       case algclass_ipsec_enc:
+               return IPSECDOI_PROTO_IPSEC_ESP;
+       case algclass_ipsec_auth:
+               return IPSECDOI_ATTR_AUTH;
+       case algclass_ipsec_comp:
+               return IPSECDOI_PROTO_IPCOMP;
+       case algclass_isakmp_enc:
+               return OAKLEY_ATTR_ENC_ALG;
+       case algclass_isakmp_hash:
+               return OAKLEY_ATTR_HASH_ALG;
+       case algclass_isakmp_dh:
+               return OAKLEY_ATTR_GRP_DESC;
+       case algclass_isakmp_ameth:
+               return OAKLEY_ATTR_AUTH_METHOD;
+       default:
+               return -1;
+       }
+       /*NOTREACHED*/
+       return -1;
+}
diff --git a/ipsec-tools/racoon/algorithm.h b/ipsec-tools/racoon/algorithm.h
new file mode 100644 (file)
index 0000000..e4fc1fe
--- /dev/null
@@ -0,0 +1,209 @@
+/* $Id: algorithm.h,v 1.8 2004/11/18 15:14:44 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ALGORITHM_H
+#define _ALGORITHM_H
+
+#include <gnuc.h>
+
+/* algorithm class */
+enum {
+       algclass_ipsec_enc,
+       algclass_ipsec_auth,
+       algclass_ipsec_comp,
+       algclass_isakmp_enc,
+       algclass_isakmp_hash,
+       algclass_isakmp_dh,
+       algclass_isakmp_ameth,  /* authentication method. */
+#define MAXALGCLASS    7
+};
+
+#define ALG_DEFAULT_KEYLEN     64
+
+#define ALGTYPE_NOTHING                0
+
+/* algorithm type */
+enum algtype {
+       algtype_nothing = 0,
+
+       /* enc */
+       algtype_des_iv64,
+       algtype_des,
+       algtype_3des,
+       algtype_rc5,
+       algtype_idea,
+       algtype_cast128,
+       algtype_blowfish,
+       algtype_3idea,
+       algtype_des_iv32,
+       algtype_rc4,
+       algtype_null_enc,
+       algtype_aes,
+       algtype_twofish,
+
+       /* ipsec auth */
+       algtype_hmac_md5,
+       algtype_hmac_sha1,
+       algtype_des_mac,
+       algtype_kpdk,
+       algtype_non_auth,
+       algtype_hmac_sha2_256,
+       algtype_hmac_sha2_384,
+       algtype_hmac_sha2_512,
+
+       /* ipcomp */
+       algtype_oui,
+       algtype_deflate,
+       algtype_lzs,
+
+       /* hash */
+       algtype_md5,
+       algtype_sha1,
+       algtype_tiger,
+       algtype_sha2_256,
+       algtype_sha2_384,
+       algtype_sha2_512,
+
+       /* dh_group */
+       algtype_modp768,
+       algtype_modp1024,
+       algtype_ec2n155,
+       algtype_ec2n185,
+       algtype_modp1536,
+       algtype_modp2048,
+       algtype_modp3072,
+       algtype_modp4096,
+       algtype_modp6144,
+       algtype_modp8192,
+
+       /* authentication method. */
+       algtype_psk,
+       algtype_dsssig,
+       algtype_rsasig,
+       algtype_rsaenc,
+       algtype_rsarev,
+       algtype_gssapikrb,
+#ifdef ENABLE_HYBRID
+       algtype_hybrid_rsa_s,
+       algtype_hybrid_dss_s,
+       algtype_hybrid_rsa_c,
+       algtype_hybrid_dss_c,
+#endif
+};
+
+struct hmac_algorithm {
+       char *name;
+       int type;
+       int doi;
+       caddr_t (*init) __P((vchar_t *));
+       void (*update) __P((caddr_t, vchar_t *));
+       vchar_t *(*final) __P((caddr_t));
+       int (*hashlen) __P((void));
+       vchar_t *(*one) __P((vchar_t *, vchar_t *));
+};
+
+struct hash_algorithm {
+       char *name;
+       int type;
+       int doi;
+       caddr_t (*init) __P((void));
+       void (*update) __P((caddr_t, vchar_t *));
+       vchar_t *(*final) __P((caddr_t));
+       int (*hashlen) __P((void));
+       vchar_t *(*one) __P((vchar_t *));
+};
+
+struct enc_algorithm {
+       char *name;
+       int type;
+       int doi;
+       int blocklen;
+       vchar_t *(*encrypt) __P((vchar_t *, vchar_t *, vchar_t *));
+       vchar_t *(*decrypt) __P((vchar_t *, vchar_t *, vchar_t *));
+       int (*weakkey) __P((vchar_t *));
+       int (*keylen) __P((int));
+};
+
+/* dh group */
+struct dh_algorithm {
+       char *name;
+       int type;
+       int doi;
+       struct dhgroup *dhgroup;
+};
+
+/* ipcomp, auth meth, dh group */
+struct misc_algorithm {
+       char *name;
+       int type;
+       int doi;
+};
+
+extern int alg_oakley_hashdef_ok __P((int));
+extern int alg_oakley_hashdef_doi __P((int));
+extern int alg_oakley_hashdef_hashlen __P((int));
+extern vchar_t *alg_oakley_hashdef_one __P((int, vchar_t *));
+
+extern int alg_oakley_hmacdef_doi __P((int));
+extern vchar_t *alg_oakley_hmacdef_one __P((int, vchar_t *, vchar_t *));
+
+extern int alg_oakley_encdef_ok __P((int));
+extern int alg_oakley_encdef_doi __P((int));
+extern int alg_oakley_encdef_keylen __P((int, int));
+extern int alg_oakley_encdef_blocklen __P((int));
+extern vchar_t *alg_oakley_encdef_decrypt __P((int, vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *alg_oakley_encdef_encrypt __P((int, vchar_t *, vchar_t *, vchar_t *));
+
+extern int alg_ipsec_encdef_doi __P((int));
+extern int alg_ipsec_encdef_keylen __P((int, int));
+
+extern int alg_ipsec_hmacdef_doi __P((int));
+extern int alg_ipsec_hmacdef_hashlen __P((int));
+
+extern int alg_ipsec_compdef_doi __P((int));
+
+extern int alg_oakley_dhdef_doi __P((int));
+extern int alg_oakley_dhdef_ok __P((int));
+extern struct dhgroup *alg_oakley_dhdef_group __P((int));
+
+extern int alg_oakley_authdef_doi __P((int));
+
+extern int default_keylen __P((int, int));
+extern int check_keylen __P((int, int, int));
+extern int algtype2doi __P((int, int));
+extern int algclass2doi __P((int));
+
+extern const char *alg_oakley_encdef_name __P((int));
+extern const char *alg_oakley_hashdef_name __P((int));
+extern const char *alg_oakley_dhdef_name __P((int));
+extern const char *alg_oakley_authdef_name __P((int));
+
+#endif /* _ALGORITHM_H */
diff --git a/ipsec-tools/racoon/arc4random.h b/ipsec-tools/racoon/arc4random.h
new file mode 100644 (file)
index 0000000..1957945
--- /dev/null
@@ -0,0 +1,39 @@
+/*     $KAME: arc4random.h,v 1.1 2002/06/04 05:23:26 itojun Exp $      */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#ifndef __ARC4RANDOM_H__
+#define __ARC4RANDOM_H__
+
+extern u_int32_t arc4random __P((void));
+
+
+#endif /* __ARC4RANDOM_H__ */
+
diff --git a/ipsec-tools/racoon/backupsa.c b/ipsec-tools/racoon/backupsa.c
new file mode 100644 (file)
index 0000000..1b9f1f8
--- /dev/null
@@ -0,0 +1,505 @@
+/*     $KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <netinet/in.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "str2val.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "sockmisc.h"
+#include "safefile.h"
+#include "backupsa.h"
+#include "libpfkey.h"
+
+/*
+ * (time string)%(sa parameter)
+ * (time string) := ex. Nov 24 18:22:48 1986
+ * (sa parameter) :=
+ *    src dst satype spi mode reqid wsize \
+ *    e_type e_keylen a_type a_keylen flags \
+ *    l_alloc l_bytes l_addtime l_usetime seq keymat
+ */
+static char *format = "%b %d %T %Y";   /* time format */
+static char *strmon[12] = {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static char *str2tmx __P((char *, struct tm *));
+static int str2num __P((char *, int));
+
+/*
+ * output the sa parameter.
+ */
+int
+backupsa_to_file(satype, mode, src, dst, spi, reqid, wsize,
+                keymat, e_type, e_keylen, a_type, a_keylen, flags,
+                l_alloc, l_bytes, l_addtime, l_usetime, seq)
+        u_int satype, mode, wsize;
+        struct sockaddr *src, *dst;
+        u_int32_t spi, reqid;
+        caddr_t keymat;
+        u_int e_type, e_keylen, a_type, a_keylen, flags;
+        u_int32_t l_alloc;
+        u_int64_t l_bytes, l_addtime, l_usetime;
+        u_int32_t seq;
+{
+       char buf[1024];
+       struct tm *tm;
+       time_t t;
+       char *p, *k;
+       int len, l, i;
+       FILE *fp;
+
+       p = buf;
+       len = sizeof(buf);
+
+       t = time(NULL);
+       tm = localtime(&t);
+       l = strftime(p, len, format, tm);
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+       l = snprintf(p, len, "%%");
+       if (l < 0 || l >= len)
+               goto err;
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+        i = getnameinfo(src, sysdep_sa_len(src), p, len, NULL, 0, NIFLAGS);
+       if (i != 0)
+               goto err;
+       l = strlen(p);
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+       l = snprintf(p, len, " ");
+       if (l < 0 || l >= len)
+               goto err;
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+        i = getnameinfo(dst, sysdep_sa_len(dst), p, len, NULL, 0, NIFLAGS);
+       if (i != 0)
+               goto err;
+       l = strlen(p);
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+       l = snprintf(p, len,
+               " %u %lu %u %u %u "
+               "%u %u %u %u %u "
+               "%u %llu %llu %llu %u",
+               satype, (unsigned long)ntohl(spi), mode, reqid, wsize,
+               e_type, e_keylen, a_type, a_keylen, flags,
+               l_alloc, (unsigned long long)l_bytes,
+               (unsigned long long)l_addtime, (unsigned long long)l_usetime,
+               seq);
+       if (l < 0 || l >= len)
+               goto err;
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+       k = val2str(keymat, e_keylen + a_keylen);
+       l = snprintf(p, len, " %s", k);
+       if (l < 0 || l >= len)
+               goto err;
+       racoon_free(k);
+       p += l;
+       len -= l;
+       if (len < 0)
+               goto err;
+
+       /* open the file and write the SA parameter */
+       if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) != 0 ||
+           (fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "a")) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to open the backup file %s.\n",
+                       lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
+               return -1;
+       }
+       fprintf(fp, "%s\n", buf);
+       fclose(fp);
+
+       return 0;
+
+err:
+       plog(LLV_ERROR, LOCATION, NULL,
+               "SA cannot be saved to a file.\n");
+       return -1;
+}
+
+int
+backupsa_from_file()
+{
+       FILE *fp;
+       char buf[512];
+       struct tm tm;
+       time_t created, current;
+       char *p, *q;
+        u_int satype, mode;
+        struct sockaddr *src, *dst;
+        u_int32_t spi, reqid;
+        caddr_t keymat;
+       size_t keymatlen;
+        u_int wsize, e_type, e_keylen, a_type, a_keylen, flags;
+        u_int32_t l_alloc;
+        u_int64_t l_bytes, l_addtime, l_usetime;
+        u_int32_t seq;
+       int line;
+
+       if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) == 0)
+               fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "r");
+       else
+               fp = NULL;
+       if (fp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to open the backup file %s.\n",
+                       lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
+               return -1;
+       }
+
+       current = time(NULL);
+
+       for(line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) {
+               /* comment line */
+               if (buf[0] == '#')
+                       continue;
+
+               memset(&tm, 0, sizeof(tm));
+               p = str2tmx(buf, &tm);
+               if (*p != '%') {
+       err:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "illegal format line#%d in %s: %s\n",
+                               line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf);
+                       continue;
+               }
+               created = mktime(&tm);
+               p++;
+
+               for (q = p; *q != '\0' && !isspace((int)*q); q++)
+                       ;
+               *q = '\0';
+               src = str2saddr(p, NULL);
+               if (src == NULL)
+                       goto err;
+               p = q + 1;
+
+               for (q = p; *q != '\0' && !isspace((int)*q); q++)
+                       ;
+               *q = '\0';
+               dst = str2saddr(p, NULL);
+               if (dst == NULL) {
+                       racoon_free(src);
+                       goto err;
+               }
+               p = q + 1;
+
+#define GETNEXTNUM(value, function) \
+do { \
+       char *y; \
+       for (q = p; *q != '\0' && !isspace((int)*q); q++) \
+               ; \
+       *q = '\0'; \
+       (value) = function(p, &y, 10); \
+       if ((value) == 0 && *y != '\0') \
+               goto err; \
+       p = q + 1; \
+} while (0);
+
+               GETNEXTNUM(satype, strtoul);
+               GETNEXTNUM(spi, strtoul);
+               spi = ntohl(spi);
+               GETNEXTNUM(mode, strtoul);
+               GETNEXTNUM(reqid, strtoul);
+               GETNEXTNUM(wsize, strtoul);
+               GETNEXTNUM(e_type, strtoul);
+               GETNEXTNUM(e_keylen, strtoul);
+               GETNEXTNUM(a_type, strtoul);
+               GETNEXTNUM(a_keylen, strtoul);
+               GETNEXTNUM(flags, strtoul);
+               GETNEXTNUM(l_alloc, strtoul);
+               GETNEXTNUM(l_bytes, strtouq);
+               GETNEXTNUM(l_addtime, strtouq);
+               GETNEXTNUM(l_usetime, strtouq);
+               GETNEXTNUM(seq, strtoul);
+
+#undef GETNEXTNUM
+
+               keymat = str2val(p, 16, &keymatlen);
+               if (keymat == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "illegal format(keymat) line#%d in %s: %s\n",
+                               line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf);
+                       racoon_free(src);
+                       racoon_free(dst);
+                       continue;
+               }
+
+               if (created + l_addtime < current) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "ignore this line#%d in %s due to expiration\n",
+                               line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
+                       racoon_free(src);
+                       racoon_free(dst);
+                       racoon_free(keymat);
+                       continue;
+               }
+               l_addtime -= current - created;
+#ifdef __APPLE__
+               if (pfkey_send_add(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               spi,
+                               reqid,
+                               wsize,
+                               keymat,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, l_bytes, l_addtime, 0, seq, 0) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "restore SA filed line#%d in %s: %s\n",
+                               line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror());
+               }
+#else
+               if (pfkey_send_add(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               spi,
+                               reqid,
+                               wsize,
+                               keymat,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, l_bytes, l_addtime, 0, seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "restore SA filed line#%d in %s: %s\n",
+                               line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror());
+               }
+#endif
+               racoon_free(src);
+               racoon_free(dst);
+               racoon_free(keymat);
+       }
+
+       fclose(fp);
+
+       /*
+        * There is a possibility that an abnormal system down will happen
+        * again before new negotiation will be started.  so racoon clears
+        * the backup file here.  it's ok that old SAs are remained in the
+        * file.  any old SA will not be installed because racoon checks the
+        * lifetime and compare with current time.
+        */
+
+       return 0;
+}
+
+int
+backupsa_clean()
+{
+       FILE *fp;
+
+       /* simply return if the file is not defined. */
+       if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
+               return 0;
+
+       fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "w+");
+       if (fp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to clean the backup file %s.\n",
+                       lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]);
+               return -1;
+       }
+       fclose(fp);
+       return 0;
+}
+
+/*
+ * convert fixed string into the tm structure.
+ * The fixed string is like 'Nov 24 18:22:48 1986'.
+ * static char *format = "%b %d %T %Y";
+ */
+static char *
+str2tmx(char *p, struct tm *tm)
+{
+       int i, len;
+
+       /* Month */
+        for (i = 0; i < sizeof(strmon)/sizeof(strmon[0]); i++) {
+               if (strncasecmp(p, strmon[i], strlen(strmon[i])) == 0) {
+                       tm->tm_mon = i;
+                       break;
+               }
+       }
+       if (i == sizeof(strmon)/sizeof(strmon[0]))
+               return 0;
+       p += strlen(strmon[i]);
+       if (*p++ != ' ')
+               return 0;
+
+       /* Day */
+       len = 2;
+       tm->tm_mday = str2num(p, len);
+       if (tm->tm_mday == -1 || tm->tm_mday > 31)
+               return 0;
+       p += len;
+       if (*p++ != ' ')
+               return 0;
+
+       /* Hour */
+       len = 2;
+       tm->tm_hour = str2num(p, len);
+       if (tm->tm_hour == -1 || tm->tm_hour > 24)
+               return 0;
+       p += len;
+       if (*p++ != ':')
+               return 0;
+
+       /* Min */
+       len = 2;
+       tm->tm_min = str2num(p, len);
+       if (tm->tm_min == -1 || tm->tm_min > 60)
+               return 0;
+       p += len;
+       if (*p++ != ':')
+               return 0;
+
+       /* Sec */
+       len = 2;
+       tm->tm_sec = str2num(p, len);
+       if (tm->tm_sec == -1 || tm->tm_sec > 60)
+               return 0;
+       p += len;
+       if (*p++ != ' ')
+               return 0;
+
+       /* Year */
+       len = 4;
+       tm->tm_year = str2num(p, len);
+       if (tm->tm_year == -1 || tm->tm_year < 1900)
+               return 0;
+       tm->tm_year -= 1900;
+       p += len;
+
+       return p;
+}
+
+static int
+str2num(p, len)
+       char *p;
+       int len;
+{
+       int res, i;
+
+       res = 0;
+        for (i = len; i > 0; i--) {
+               if (!isdigit((int)*p))
+                       return -1;
+               res *= 10;
+               res += *p - '0';
+               p++;
+       }
+
+       return res;
+}
+
+#ifdef TEST
+#include <stdio.h>
+int
+main()
+{
+       struct tm tm;
+       time_t t;
+       char *buf = "Nov 24 18:22:48 1986 ";
+       char *p;
+
+       memset(&tm, 0, sizeof(tm));
+       p = str2tmx(buf, &tm);
+       printf("[%x]\n", *p);
+       t = mktime(&tm);
+       if (t == -1)
+               printf("mktime failed.");
+       p = ctime(&t);
+       printf("[%s]\n", p);
+
+       exit(0);
+}
+#endif
diff --git a/ipsec-tools/racoon/backupsa.h b/ipsec-tools/racoon/backupsa.h
new file mode 100644 (file)
index 0000000..67cb67c
--- /dev/null
@@ -0,0 +1,42 @@
+/* $Id: backupsa.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BACKUPSA_H
+#define _BACKUPSA_H
+
+extern int backupsa_to_file __P((u_int, u_int,
+       struct sockaddr *, struct sockaddr *, u_int32_t, u_int32_t, u_int,
+       caddr_t, u_int, u_int, u_int, u_int, u_int,
+       u_int32_t, u_int64_t, u_int64_t, u_int64_t, u_int32_t));
+extern int backupsa_from_file __P((void));
+extern int backupsa_clean __P((void));
+
+#endif /* _BACKUPSA_H */
diff --git a/ipsec-tools/racoon/cfparse.y b/ipsec-tools/racoon/cfparse.y
new file mode 100644 (file)
index 0000000..d9ac8a4
--- /dev/null
@@ -0,0 +1,2158 @@
+/* $Id: cfparse.y,v 1.37.2.7 2006/02/02 14:37:17 vanhu Exp $ */
+
+%{
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 and 2003 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#ifdef ENABLE_HYBRID
+#include <arpa/inet.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "str2val.h"
+#include "genlist.h"
+#include "debug.h"
+
+#include "admin.h"
+#include "privsep.h"
+#include "cfparse_proto.h"
+#include "cftoken_proto.h"
+#include "algorithm.h"
+#include "localconf.h"
+#include "policy.h"
+#include "sainfo.h"
+#include "oakley.h"
+#include "pfkey.h"
+#include "remoteconf.h"
+#include "grabmyaddr.h"
+#include "isakmp_var.h"
+#include "handler.h"
+#include "isakmp.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
+#include "ipsec_doi.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+#ifdef HAVE_GSSAPI
+#include "gssapi.h"
+#endif
+#include "vendorid.h"
+#include "rsalist.h"
+
+
+static int num2dhgroup[] = {
+       0,
+       OAKLEY_ATTR_GRP_DESC_MODP768,
+       OAKLEY_ATTR_GRP_DESC_MODP1024,
+       OAKLEY_ATTR_GRP_DESC_EC2N155,
+       OAKLEY_ATTR_GRP_DESC_EC2N185,
+       OAKLEY_ATTR_GRP_DESC_MODP1536,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       OAKLEY_ATTR_GRP_DESC_MODP2048,
+       OAKLEY_ATTR_GRP_DESC_MODP3072,
+       OAKLEY_ATTR_GRP_DESC_MODP4096,
+       OAKLEY_ATTR_GRP_DESC_MODP6144,
+       OAKLEY_ATTR_GRP_DESC_MODP8192
+};
+
+static struct remoteconf *cur_rmconf;
+static int tmpalgtype[MAXALGCLASS];
+static struct sainfo *cur_sainfo;
+static int cur_algclass;
+
+static struct proposalspec *newprspec __P((void));
+static void insprspec __P((struct proposalspec *, struct proposalspec **));
+static struct secprotospec *newspspec __P((void));
+static void insspspec __P((struct secprotospec *, struct proposalspec **));
+static void adminsock_conf __P((vchar_t *, vchar_t *, vchar_t *, int));
+
+static int set_isakmp_proposal
+       __P((struct remoteconf *, struct proposalspec *));
+static void clean_tmpalgtype __P((void));
+static int expand_isakmpspec __P((int, int, int *,
+       int, int, time_t, int, int, int, char *, struct remoteconf *));
+static int listen_addr __P((struct sockaddr *addr, int udp_encap));
+
+void freeetypes (struct etypes **etypes);
+
+#if 0
+static int fix_lifebyte __P((u_long));
+#endif
+%}
+
+%union {
+       unsigned long num;
+       vchar_t *val;
+       struct remoteconf *rmconf;
+       struct sockaddr *saddr;
+       struct sainfoalg *alg;
+}
+
+       /* privsep */
+%token PRIVSEP USER GROUP CHROOT
+       /* path */
+%token PATH PATHTYPE
+       /* include */
+%token INCLUDE
+       /* self information */
+%token IDENTIFIER VENDORID
+       /* logging */
+%token LOGGING LOGLEV
+       /* padding */
+%token PADDING PAD_RANDOMIZE PAD_RANDOMIZELEN PAD_MAXLEN PAD_STRICT PAD_EXCLTAIL
+       /* listen */
+%token LISTEN X_ISAKMP X_ISAKMP_NATT X_ADMIN STRICT_ADDRESS ADMINSOCK DISABLED
+       /* modecfg */
+%token MODECFG CFG_NET4 CFG_MASK4 CFG_DNS4 CFG_NBNS4
+%token CFG_AUTH_SOURCE CFG_SYSTEM CFG_RADIUS CFG_PAM CFG_LOCAL CFG_NONE
+%token CFG_ACCOUNTING CFG_CONF_SOURCE CFG_MOTD CFG_POOL_SIZE CFG_AUTH_THROTTLE
+%token CFG_PFS_GROUP CFG_SAVE_PASSWD
+       /* timer */
+%token RETRY RETRY_COUNTER RETRY_INTERVAL RETRY_PERSEND
+%token RETRY_PHASE1 RETRY_PHASE2 NATT_KA AUTO_EXIT_DELAY
+       /* algorithm */
+%token ALGORITHM_CLASS ALGORITHMTYPE STRENGTHTYPE
+       /* sainfo */
+%token SAINFO FROM
+       /* remote */
+%token REMOTE ANONYMOUS INHERIT
+%token EXCHANGE_MODE EXCHANGETYPE DOI DOITYPE SITUATION SITUATIONTYPE
+%token CERTIFICATE_TYPE CERTTYPE PEERS_CERTFILE CA_TYPE
+%token VERIFY_CERT SEND_CERT SEND_CR
+%token IDENTIFIERTYPE MY_IDENTIFIER PEERS_IDENTIFIER VERIFY_IDENTIFIER
+%token SHARED_SECRET SECRETTYPE
+%token OPEN_DIR_AUTH_GROUP IN_KEYCHAIN
+%token CERTIFICATE_VERIFICATION VERIFICATION_MODULE VERIFICATION_OPTION
+%token DNSSEC CERT_X509 CERT_PLAINRSA
+%token NONCE_SIZE DH_GROUP KEEPALIVE PASSIVE INITIAL_CONTACT
+%token NAT_TRAVERSAL NAT_TRAVERSAL_LEVEL NAT_TRAVERSAL_MULTI_USER
+%token PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL
+%token GENERATE_POLICY SUPPORT_PROXY
+%token PROPOSAL
+%token EXEC_PATH EXEC_COMMAND EXEC_SUCCESS EXEC_FAILURE
+%token GSS_ID GSS_ID_ENC GSS_ID_ENCTYPE
+%token COMPLEX_BUNDLE
+%token DPD DPD_DELAY DPD_RETRY DPD_MAXFAIL
+%token XAUTH_LOGIN
+
+%token PREFIX PORT PORTANY UL_PROTO ANY IKE_FRAG ESP_FRAG MODE_CFG
+%token PFS_GROUP LIFETIME LIFETYPE_TIME LIFETYPE_BYTE STRENGTH
+
+%token SCRIPT PHASE1_UP PHASE1_DOWN
+
+%token NUMBER SWITCH BOOLEAN
+%token HEXSTRING QUOTEDSTRING ADDRSTRING
+%token UNITTYPE_BYTE UNITTYPE_KBYTES UNITTYPE_MBYTES UNITTYPE_TBYTES
+%token UNITTYPE_SEC UNITTYPE_MIN UNITTYPE_HOUR
+%token EOS BOC EOC COMMA
+
+%type <num> NUMBER BOOLEAN SWITCH keylength
+%type <num> PATHTYPE IDENTIFIERTYPE LOGLEV GSS_ID_ENCTYPE
+%type <num> SECRETTYPE
+%type <num> ALGORITHM_CLASS dh_group_num
+%type <num> ALGORITHMTYPE STRENGTHTYPE
+%type <num> PREFIX prefix PORT port ike_port
+%type <num> ul_proto UL_PROTO
+%type <num> EXCHANGETYPE DOITYPE SITUATIONTYPE
+%type <num> CERTTYPE CERT_X509 CERT_PLAINRSA PROPOSAL_CHECK_LEVEL NAT_TRAVERSAL_LEVEL
+%type <num> VERIFICATION_MODULE VERIFICATION_OPTION
+%type <num> unittype_time unittype_byte
+%type <val> QUOTEDSTRING HEXSTRING ADDRSTRING sainfo_id
+%type <val> identifierstring
+%type <saddr> remote_index ike_addrinfo_port
+%type <alg> algorithm
+
+%%
+
+statements
+       :       /* nothing */
+       |       statements statement
+       ;
+statement
+       :       privsep_statement
+       |       path_statement
+       |       include_statement
+       |       gssenc_statement
+       |       identifier_statement
+       |       logging_statement
+       |       padding_statement
+       |       listen_statement
+       |       modecfg_statement
+       |       timer_statement
+       |       sainfo_statement
+       |       remote_statement
+       |       special_statement
+       ;
+
+       /* privsep */
+privsep_statement
+       :       PRIVSEP BOC privsep_stmts EOC
+       ;
+privsep_stmts
+       :       /* nothing */
+       |       privsep_stmts privsep_stmt
+       ;
+privsep_stmt
+       :       USER QUOTEDSTRING
+               {
+                       struct passwd *pw;
+
+                       if ((pw = getpwnam($2->v)) == NULL) {
+                               yyerror("unkown user \"%s\"", $2->v);
+                               return -1;
+                       }
+                       lcconf->uid = pw->pw_uid;
+               } 
+               EOS
+       |       USER NUMBER { lcconf->uid = $2; } EOS
+       |       GROUP QUOTEDSTRING
+               {
+                       struct group *gr;
+
+                       if ((gr = getgrnam($2->v)) == NULL) {
+                               yyerror("unkown group \"%s\"", $2->v);
+                               return -1;
+                       }
+                       lcconf->gid = gr->gr_gid;
+               }
+               EOS
+       |       GROUP NUMBER { lcconf->gid = $2; } EOS
+       |       CHROOT QUOTEDSTRING { lcconf->chroot = $2->v; } EOS
+       ;
+
+       /* path */
+path_statement
+       :       PATH PATHTYPE QUOTEDSTRING
+               {
+                       if ($2 >= LC_PATHTYPE_MAX) {
+                               yyerror("invalid path type %d", $2);
+                               return -1;
+                       }
+
+                       /* free old pathinfo */
+                       if (lcconf->pathinfo[$2])
+                               racoon_free(lcconf->pathinfo[$2]);
+
+                       /* set new pathinfo */
+                       lcconf->pathinfo[$2] = strdup($3->v);
+                       vfree($3);
+               }
+               EOS
+       ;
+
+       /* special */
+special_statement
+       :       COMPLEX_BUNDLE SWITCH { lcconf->complex_bundle = $2; } EOS
+       ;
+
+       /* include */
+include_statement
+       :       INCLUDE QUOTEDSTRING EOS
+               {
+                       char path[MAXPATHLEN];
+
+                       getpathname(path, sizeof(path),
+                               LC_PATHTYPE_INCLUDE, $2->v);
+                       vfree($2);
+                       if (yycf_switch_buffer(path) != 0)
+                               return -1;
+               }
+       ;
+
+       /* gss_id_enc */
+gssenc_statement
+       :       GSS_ID_ENC GSS_ID_ENCTYPE EOS
+               {
+                       if ($2 >= LC_GSSENC_MAX) {
+                               yyerror("invalid GSS ID encoding %d", $2);
+                               return -1;
+                       }
+                       lcconf->gss_id_enc = $2;
+               }
+       ;
+
+       /* self infomation */
+identifier_statement
+       :       IDENTIFIER identifier_stmt
+       ;
+identifier_stmt
+       :       VENDORID
+               {
+                       /*XXX to be deleted */
+               }
+               QUOTEDSTRING EOS
+       |       IDENTIFIERTYPE QUOTEDSTRING
+               {
+                       /*XXX to be deleted */
+                       $2->l--;        /* nuke '\0' */
+                       lcconf->ident[$1] = $2;
+                       if (lcconf->ident[$1] == NULL) {
+                               yyerror("failed to set my ident: %s",
+                                       strerror(errno));
+                               return -1;
+                       }
+               }
+               EOS
+       ;
+
+       /* logging */
+logging_statement
+       :       LOGGING log_level EOS
+       ;
+log_level
+       :       HEXSTRING
+               {
+                       /*
+                        * XXX ignore it because this specification
+                        * will be obsoleted.
+                        */
+                       yywarn("see racoon.conf(5), such a log specification will be obsoleted.");
+                       vfree($1);
+               }
+       |       LOGLEV
+               {
+                       /*
+                        * set the loglevel by configuration file only when
+                        * the command line did not specify any loglevel.
+                        */
+                       if (loglevel <= LLV_BASE)
+                               loglevel += $1;
+               }
+       ;
+
+       /* padding */
+padding_statement
+       :       PADDING BOC padding_stmts EOC
+       ;
+padding_stmts
+       :       /* nothing */
+       |       padding_stmts padding_stmt
+       ;
+padding_stmt
+       :       PAD_RANDOMIZE SWITCH { lcconf->pad_random = $2; } EOS
+       |       PAD_RANDOMIZELEN SWITCH { lcconf->pad_randomlen = $2; } EOS
+       |       PAD_MAXLEN NUMBER { lcconf->pad_maxsize = $2; } EOS
+       |       PAD_STRICT SWITCH { lcconf->pad_strict = $2; } EOS
+       |       PAD_EXCLTAIL SWITCH { lcconf->pad_excltail = $2; } EOS
+       ;
+
+       /* listen */
+listen_statement
+       :       LISTEN BOC listen_stmts EOC
+       ;
+listen_stmts
+       :       /* nothing */
+       |       listen_stmts listen_stmt
+       ;
+listen_stmt
+       :       X_ISAKMP ike_addrinfo_port
+               {
+                       listen_addr ($2, 0);
+               }
+               EOS
+       |       X_ISAKMP_NATT ike_addrinfo_port
+               {
+#ifdef ENABLE_NATT
+                       listen_addr ($2, 1);
+#else
+                       yyerror("NAT-T support not compiled in.");
+#endif
+               }
+               EOS
+       |       X_ADMIN
+               {
+                       yyerror("admin directive is obsoleted.");
+               }
+               PORT EOS
+       |       ADMINSOCK QUOTEDSTRING QUOTEDSTRING QUOTEDSTRING NUMBER 
+               {
+#ifdef ENABLE_ADMINPORT
+                       adminsock_conf($2, $3, $4, $5);
+#else
+                       yywarn("admin port support not compiled in");
+#endif
+               }
+               EOS
+       |       ADMINSOCK QUOTEDSTRING
+               {
+#ifdef ENABLE_ADMINPORT
+                       adminsock_conf($2, NULL, NULL, -1);
+#else
+                       yywarn("admin port support not compiled in");
+#endif
+               }
+               EOS
+       |       ADMINSOCK DISABLED
+               {
+#ifdef ENABLE_ADMINPORT
+                       adminsock_path = NULL;
+#else
+                       yywarn("admin port support not compiled in");
+#endif
+               }
+               EOS
+       |       STRICT_ADDRESS { lcconf->strict_address = TRUE; } EOS
+       ;
+ike_addrinfo_port
+       :       ADDRSTRING ike_port
+               {
+                       char portbuf[10];
+
+                       snprintf(portbuf, sizeof(portbuf), "%ld", $2);
+                       $$ = str2saddr($1->v, portbuf);
+                       vfree($1);
+                       if (!$$)
+                               return -1;
+               }
+       ;
+ike_port
+       :       /* nothing */   { $$ = PORT_ISAKMP; }
+       |       PORT            { $$ = $1; }
+       ;
+       /* modecfg */
+modecfg_statement
+       :       MODECFG BOC modecfg_stmts EOC
+       ;
+modecfg_stmts
+       :       /* nothing */
+       |       modecfg_stmts modecfg_stmt
+       ;
+modecfg_stmt
+       :       CFG_NET4 ADDRSTRING
+               {
+#ifdef ENABLE_HYBRID
+                if (inet_pton(AF_INET, $2->v,
+                    &isakmp_cfg_config.network4) != 1)
+                       yyerror("bad IPv4 network address.");
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_MASK4 ADDRSTRING
+               {
+#ifdef ENABLE_HYBRID
+                       if (inet_pton(AF_INET, $2->v,
+                           &isakmp_cfg_config.netmask4) != 1)
+                               yyerror("bad IPv4 netmask address.");
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_DNS4 ADDRSTRING
+               {
+#ifdef ENABLE_HYBRID
+                       if (inet_pton(AF_INET, $2->v,
+                           &isakmp_cfg_config.dns4) != 1)
+                               yyerror("bad IPv4 DNS address.");
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_NBNS4 ADDRSTRING
+               {
+#ifdef ENABLE_HYBRID
+                       if (inet_pton(AF_INET, $2->v,
+                           &isakmp_cfg_config.nbns4) != 1)
+                               yyerror("bad IPv4 WINS address.");
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_AUTH_SOURCE CFG_SYSTEM
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_SYSTEM;
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_AUTH_SOURCE CFG_RADIUS
+               {
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+                       isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_RADIUS;
+#else /* HAVE_LIBRADIUS */
+                       yyerror("racoon not configured with --with-libradius");
+#endif /* HAVE_LIBRADIUS */
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_AUTH_SOURCE CFG_PAM
+               {
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBPAM
+                       isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_PAM;
+#else /* HAVE_LIBPAM */
+                       yyerror("racoon not configured with --with-libpam");
+#endif /* HAVE_LIBPAM */
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_ACCOUNTING CFG_NONE
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_NONE;
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       CFG_ACCOUNTING CFG_RADIUS
+               {
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+                       isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_RADIUS;
+#else /* HAVE_LIBRADIUS */
+                       yyerror("racoon not configured with --with-libradius");
+#endif /* HAVE_LIBRADIUS */
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_ACCOUNTING CFG_PAM
+               {
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBPAM
+                       isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_PAM;
+#else /* HAVE_LIBPAM */
+                       yyerror("racoon not configured with --with-libpam");
+#endif /* HAVE_LIBPAM */
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_POOL_SIZE NUMBER
+               {
+#ifdef ENABLE_HYBRID
+                       size_t len;
+
+                       isakmp_cfg_config.pool_size = $2;
+
+                       len = $2 * sizeof(*isakmp_cfg_config.port_pool);
+                       isakmp_cfg_config.port_pool = racoon_malloc(len);
+                       if (isakmp_cfg_config.port_pool == NULL)
+                               yyerror("cannot allocate memory for pool");
+                       bzero(isakmp_cfg_config.port_pool, len);
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_PFS_GROUP NUMBER
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.pfs_group = $2;
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_SAVE_PASSWD SWITCH
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.save_passwd = $2;
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_AUTH_THROTTLE NUMBER
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.auth_throttle = $2;
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_CONF_SOURCE CFG_LOCAL
+               {
+#ifdef ENABLE_HYBRID
+                       isakmp_cfg_config.confsource = ISAKMP_CFG_CONF_LOCAL;
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_CONF_SOURCE CFG_RADIUS
+               {
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+                       isakmp_cfg_config.confsource = ISAKMP_CFG_CONF_RADIUS;
+#else /* HAVE_LIBRADIUS */
+                       yyerror("racoon not configured with --with-libradius");
+#endif /* HAVE_LIBRADIUS */
+#else /* ENABLE_HYBRID */
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif /* ENABLE_HYBRID */
+               }
+               EOS
+       |       CFG_MOTD QUOTEDSTRING
+               {
+#ifdef ENABLE_HYBRID
+                       strncpy(&isakmp_cfg_config.motd[0], $2->v, MAXPATHLEN);
+                       isakmp_cfg_config.motd[MAXPATHLEN] = '\0';
+                       vfree($2);
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       ;
+
+       /* timer */
+timer_statement
+       :       RETRY BOC timer_stmts EOC
+       ;
+timer_stmts
+       :       /* nothing */
+       |       timer_stmts timer_stmt
+       ;
+timer_stmt
+       :       RETRY_COUNTER NUMBER
+               {
+                       lcconf->retry_counter = $2;
+               }
+               EOS
+       |       RETRY_INTERVAL NUMBER unittype_time
+               {
+                       lcconf->retry_interval = $2 * $3;
+               }
+               EOS
+       |       RETRY_PERSEND NUMBER
+               {
+                       lcconf->count_persend = $2;
+               }
+               EOS
+       |       RETRY_PHASE1 NUMBER unittype_time
+               {
+                       lcconf->retry_checkph1 = $2 * $3;
+               }
+               EOS
+       |       RETRY_PHASE2 NUMBER unittype_time
+               {
+                       lcconf->wait_ph2complete = $2 * $3;
+               }
+               EOS
+       |       AUTO_EXIT_DELAY NUMBER unittype_time
+               {
+                       lcconf->auto_exit_delay = $2 * $3;
+                       lcconf->auto_exit_state |= LC_AUTOEXITSTATE_SET;
+               }
+               EOS
+
+       |       NATT_KA NUMBER unittype_time
+               {
+#ifdef ENABLE_NATT
+                       lcconf->natt_ka_interval = $2 * $3;
+#else
+                       yyerror("NAT-T support not compiled in.");
+#endif
+               }
+               EOS
+       ;
+
+       /* sainfo */
+sainfo_statement
+       :       SAINFO
+               {
+                       cur_sainfo = newsainfo();
+                       if (cur_sainfo == NULL) {
+                               yyerror("failed to allocate sainfo");
+                               return -1;
+                       }
+               }
+               sainfo_name sainfo_peer BOC sainfo_specs
+               {
+                       struct sainfo *check;
+
+                       /* default */
+                       if (cur_sainfo->algs[algclass_ipsec_enc] == 0) {
+                               yyerror("no encryption algorithm at %s",
+                                       sainfo2str(cur_sainfo));
+                               return -1;
+                       }
+                       if (cur_sainfo->algs[algclass_ipsec_auth] == 0) {
+                               yyerror("no authentication algorithm at %s",
+                                       sainfo2str(cur_sainfo));
+                               return -1;
+                       }
+                       if (cur_sainfo->algs[algclass_ipsec_comp] == 0) {
+                               yyerror("no compression algorithm at %s",
+                                       sainfo2str(cur_sainfo));
+                               return -1;
+                       }
+
+                       /* duplicate check */
+                       check = getsainfo(cur_sainfo->idsrc,
+                                         cur_sainfo->iddst,
+                                         cur_sainfo->id_i);
+                       if (check && (!check->idsrc && !cur_sainfo->idsrc)) {
+                               yyerror("duplicated sainfo: %s",
+                                       sainfo2str(cur_sainfo));
+                               return -1;
+                       }
+                       inssainfo(cur_sainfo);
+               }
+               EOC
+       ;
+sainfo_name
+       :       ANONYMOUS
+               {
+                       cur_sainfo->idsrc = NULL;
+                       cur_sainfo->iddst = NULL;
+               }
+       |       sainfo_id sainfo_id
+               {
+                       cur_sainfo->idsrc = $1;
+                       cur_sainfo->iddst = $2;
+               }
+       ;
+sainfo_id
+       :       IDENTIFIERTYPE ADDRSTRING prefix port ul_proto
+               {
+                       char portbuf[10];
+                       struct sockaddr *saddr;
+
+                       if (($5 == IPPROTO_ICMP || $5 == IPPROTO_ICMPV6)
+                        && ($4 != IPSEC_PORT_ANY || $4 != IPSEC_PORT_ANY)) {
+                               yyerror("port number must be \"any\".");
+                               return -1;
+                       }
+
+                       snprintf(portbuf, sizeof(portbuf), "%lu", $4);
+                       saddr = str2saddr($2->v, portbuf);
+                       vfree($2);
+                       if (saddr == NULL)
+                               return -1;
+
+                       switch (saddr->sa_family) {
+                       case AF_INET:
+                               if ($5 == IPPROTO_ICMPV6) {
+                                       yyerror("upper layer protocol mismatched.\n");
+                                       racoon_free(saddr);
+                                       return -1;
+                               }
+                               $$ = ipsecdoi_sockaddr2id(saddr,
+#if 0
+                                       $3 == (sizeof(struct in_addr) << 3) &&
+                                               $1 == IDTYPE_ADDRESS
+                                         ? ~0 : $3,
+#else
+                                       $3 == ~0 ? (sizeof(struct in_addr) << 3): $3,
+#endif
+                                       $5);
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               if ($5 == IPPROTO_ICMP) {
+                                       yyerror("upper layer protocol mismatched.\n");
+                                       racoon_free(saddr);
+                                       return -1;
+                               }
+                               $$ = ipsecdoi_sockaddr2id(saddr,
+#if 0
+                                       $3 == (sizeof(struct in6_addr) << 3) &&
+                                               $1 == IDTYPE_ADDRESS
+                                         ? ~0 : $3,
+#else
+                               $3 == ~0 ? (sizeof(struct in6_addr) << 3): $3,
+#endif
+                                       $5);
+                               break;
+#endif
+                       default:
+                               yyerror("invalid family: %d", saddr->sa_family);
+                               $$ = NULL;
+                               break;
+                       }
+                       racoon_free(saddr);
+                       if ($$ == NULL)
+                               return -1;
+               }
+       |       IDENTIFIERTYPE QUOTEDSTRING
+               {
+                       struct ipsecdoi_id_b *id_b;
+
+                       if ($1 == IDTYPE_ASN1DN) {
+                               yyerror("id type forbidden: %d", $1);
+                               $$ = NULL;
+                               return -1;
+                       }
+
+                       $2->l--;
+
+                       $$ = vmalloc(sizeof(*id_b) + $2->l);
+                       if ($$ == NULL) {
+                               yyerror("failed to allocate identifier");
+                               return -1;
+                       }
+
+                       id_b = (struct ipsecdoi_id_b *)$$->v;
+                       id_b->type = idtype2doi($1);
+
+                       id_b->proto_id = 0;
+                       id_b->port = 0;
+
+                       memcpy($$->v + sizeof(*id_b), $2->v, $2->l);
+               }
+       ;
+sainfo_peer
+       :       /* nothing */
+               {
+                       cur_sainfo->id_i = NULL;
+               }
+
+       |       FROM IDENTIFIERTYPE identifierstring
+               {
+                       struct ipsecdoi_id_b *id_b;
+                       vchar_t *idv;
+
+                       if (set_identifier(&idv, $2, $3) != 0) {
+                               yyerror("failed to set identifer.\n");
+                               return -1;
+                       }
+                       cur_sainfo->id_i = vmalloc(sizeof(*id_b) + idv->l);
+                       if (cur_sainfo->id_i == NULL) {
+                               yyerror("failed to allocate identifier");
+                               return -1;
+                       }
+
+                       id_b = (struct ipsecdoi_id_b *)cur_sainfo->id_i->v;
+                       id_b->type = idtype2doi($2);
+
+                       id_b->proto_id = 0;
+                       id_b->port = 0;
+
+                       memcpy(cur_sainfo->id_i->v + sizeof(*id_b),
+                              idv->v, idv->l);
+                       vfree(idv);
+               }
+       ;
+sainfo_specs
+       :       /* nothing */
+       |       sainfo_specs sainfo_spec
+       ;
+sainfo_spec
+       :       PFS_GROUP dh_group_num
+               {
+                       cur_sainfo->pfs_group = $2;
+               }
+               EOS
+       |       LIFETIME LIFETYPE_TIME NUMBER unittype_time
+               {
+                       cur_sainfo->lifetime = $3 * $4;
+               }
+               EOS
+       |       LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
+               {
+#if 1
+                       yyerror("byte lifetime support is deprecated");
+                       return -1;
+#else
+                       cur_sainfo->lifebyte = fix_lifebyte($3 * $4);
+                       if (cur_sainfo->lifebyte == 0)
+                               return -1;
+#endif
+               }
+               EOS
+       |       ALGORITHM_CLASS {
+                       cur_algclass = $1;
+               }
+               algorithms EOS
+       |       IDENTIFIER IDENTIFIERTYPE
+               {
+                       yyerror("it's deprecated to specify a identifier in phase 2");
+               }
+               EOS
+       |       MY_IDENTIFIER IDENTIFIERTYPE QUOTEDSTRING
+               {
+                       yyerror("it's deprecated to specify a identifier in phase 2");
+               }
+               EOS
+       ;
+
+algorithms
+       :       algorithm
+               {
+                       inssainfoalg(&cur_sainfo->algs[cur_algclass], $1);
+               }
+       |       algorithm
+               {
+                       inssainfoalg(&cur_sainfo->algs[cur_algclass], $1);
+               }
+               COMMA algorithms
+       ;
+algorithm
+       :       ALGORITHMTYPE keylength
+               {
+                       int defklen;
+
+                       $$ = newsainfoalg();
+                       if ($$ == NULL) {
+                               yyerror("failed to get algorithm allocation");
+                               return -1;
+                       }
+
+                       $$->alg = algtype2doi(cur_algclass, $1);
+                       if ($$->alg == -1) {
+                               yyerror("algorithm mismatched");
+                               racoon_free($$);
+                               $$ = NULL;
+                               return -1;
+                       }
+
+                       defklen = default_keylen(cur_algclass, $1);
+                       if (defklen == 0) {
+                               if ($2) {
+                                       yyerror("keylen not allowed");
+                                       racoon_free($$);
+                                       $$ = NULL;
+                                       return -1;
+                               }
+                       } else {
+                               if ($2 && check_keylen(cur_algclass, $1, $2) < 0) {
+                                       yyerror("invalid keylen %d", $2);
+                                       racoon_free($$);
+                                       $$ = NULL;
+                                       return -1;
+                               }
+                       }
+
+                       if ($2)
+                               $$->encklen = $2;
+                       else
+                               $$->encklen = defklen;
+
+                       /* check if it's supported algorithm by kernel */
+                       if (!(cur_algclass == algclass_ipsec_auth && $1 == algtype_non_auth)
+                        && pk_checkalg(cur_algclass, $1, $$->encklen)) {
+                               int a = algclass2doi(cur_algclass);
+                               int b = algtype2doi(cur_algclass, $1);
+                               if (a == IPSECDOI_ATTR_AUTH)
+                                       a = IPSECDOI_PROTO_IPSEC_AH;
+                               yyerror("algorithm %s not supported by the kernel (missing module?)",
+                                       s_ipsecdoi_trns(a, b));
+                               racoon_free($$);
+                               $$ = NULL;
+                               return -1;
+                       }
+               }
+       ;
+prefix
+       :       /* nothing */ { $$ = ~0; }
+       |       PREFIX { $$ = $1; }
+       ;
+port
+       :       /* nothing */ { $$ = IPSEC_PORT_ANY; }
+       |       PORT { $$ = $1; }
+       |       PORTANY { $$ = IPSEC_PORT_ANY; }
+       ;
+ul_proto
+       :       NUMBER { $$ = $1; }
+       |       UL_PROTO { $$ = $1; }
+       |       ANY { $$ = IPSEC_ULPROTO_ANY; }
+       ;
+keylength
+       :       /* nothing */ { $$ = 0; }
+       |       NUMBER { $$ = $1; }
+       ;
+
+       /* remote */
+remote_statement
+       :       REMOTE remote_index INHERIT remote_index
+               {
+                       struct remoteconf *new;
+                       struct proposalspec *prspec;
+
+                       new = copyrmconf($4);
+                       if (new == NULL) {
+                               yyerror("failed to get remoteconf for %s.", saddr2str ($4));
+                               return -1;
+                       }
+
+                       new->remote = $2;
+                       new->inherited_from = getrmconf_strict($4, 1);
+                       new->proposal = NULL;
+                       new->prhead = NULL;
+                       cur_rmconf = new;
+
+                       prspec = newprspec();
+                       if (prspec == NULL || !cur_rmconf->inherited_from 
+                               || !cur_rmconf->inherited_from->proposal)
+                               return -1;
+                       prspec->lifetime = cur_rmconf->inherited_from->proposal->lifetime;
+                       prspec->lifebyte = cur_rmconf->inherited_from->proposal->lifebyte;
+                       insprspec(prspec, &cur_rmconf->prhead);
+               }
+               remote_specs_block
+       |       REMOTE remote_index
+               {
+                       struct remoteconf *new;
+                       struct proposalspec *prspec;
+
+                       new = newrmconf();
+                       if (new == NULL) {
+                               yyerror("failed to get new remoteconf.");
+                               return -1;
+                       }
+
+                       new->remote = $2;
+                       cur_rmconf = new;
+
+                       prspec = newprspec();
+                       if (prspec == NULL)
+                               return -1;
+                       prspec->lifetime = oakley_get_defaultlifetime();
+                       insprspec(prspec, &cur_rmconf->prhead);
+               }
+               remote_specs_block
+       ;
+
+remote_specs_block
+       :       BOC remote_specs EOC
+               {
+                       /* check a exchange mode */
+                       if (cur_rmconf->etypes == NULL) {
+                               yyerror("no exchange mode specified.\n");
+                               return -1;
+                       }
+
+                       if (cur_rmconf->idvtype == IDTYPE_UNDEFINED)
+                               cur_rmconf->idvtype = IDTYPE_ADDRESS;
+
+
+                       if (cur_rmconf->idvtype == IDTYPE_ASN1DN) {
+                               if (cur_rmconf->mycertfile 
+#ifdef __APPLE__
+                                       || cur_rmconf->identity_in_keychain) 
+#endif
+                               {
+                                       if (cur_rmconf->idv)
+                                               yywarn("Both CERT and ASN1 ID "
+                                                      "are set. Hope this is OK.\n");
+                                       /* TODO: Preparse the DN here */
+                               } else if (cur_rmconf->idv) {
+                                       /* OK, using asn1dn without X.509. */
+                               } else {
+                                       yyerror("ASN1 ID not specified "
+                                               "and no CERT defined!\n");
+                                       return -1;
+                               }
+                       }
+
+#ifdef __APPLE__                       
+                       if (cur_rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER) {
+                               struct genlist_entry *gpb;
+                               if (genlist_next(cur_rmconf->idvl_p, &gpb) == NULL) {
+                                       yyerror("peers_identifier required for specified certificate "
+                                               "verification option.\n");
+                                               return -1;
+                               }
+                       }
+#endif
+
+                       if (cur_rmconf->prhead->spspec == NULL
+                               && cur_rmconf->inherited_from
+                               && cur_rmconf->inherited_from->prhead) {
+                               cur_rmconf->prhead->spspec = cur_rmconf->inherited_from->prhead->spspec;
+                       }
+                       if (set_isakmp_proposal(cur_rmconf, cur_rmconf->prhead) != 0)
+                               return -1;
+
+                       /* DH group settting if aggressive mode is there. */
+                       if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) {
+                               struct isakmpsa *p;
+                               int b = 0;
+
+                               /* DH group */
+                               for (p = cur_rmconf->proposal; p; p = p->next) {
+                                       if (b == 0 || (b && b == p->dh_group)) {
+                                               b = p->dh_group;
+                                               continue;
+                                       }
+                                       yyerror("DH group must be equal "
+                                               "in all proposals "
+                                               "when aggressive mode is "
+                                               "used.\n");
+                                       return -1;
+                               }
+                               cur_rmconf->dh_group = b;
+
+                               if (cur_rmconf->dh_group == 0) {
+                                       yyerror("DH group must be set in the proposal.\n");
+                                       return -1;
+                               }
+
+                               /* DH group settting if PFS is required. */
+                               if (oakley_setdhgroup(cur_rmconf->dh_group,
+                                               &cur_rmconf->dhgrp) < 0) {
+                                       yyerror("failed to set DH value.\n");
+                                       return -1;
+                               }
+                       }
+
+                       insrmconf(cur_rmconf);
+               }
+       ;
+remote_index
+       :       ANONYMOUS ike_port
+               {
+                       $$ = newsaddr(sizeof(struct sockaddr));
+                       $$->sa_family = AF_UNSPEC;
+                       ((struct sockaddr_in *)$$)->sin_port = htons($2);
+               }
+       |       ike_addrinfo_port
+               {
+                       $$ = $1;
+                       if ($$ == NULL) {
+                               yyerror("failed to allocate sockaddr");
+                               return -1;
+                       }
+               }
+       ;
+remote_specs
+       :       /* nothing */
+       |       remote_specs remote_spec
+       ;
+remote_spec
+       :       EXCHANGE_MODE
+               {
+                       cur_rmconf->etypes = NULL;
+               }
+               exchange_types EOS
+       |       DOI DOITYPE { cur_rmconf->doitype = $2; } EOS
+       |       SITUATION SITUATIONTYPE { cur_rmconf->sittype = $2; } EOS
+       |       CERTIFICATE_TYPE cert_spec
+       |       PEERS_CERTFILE QUOTEDSTRING
+               {
+                       yywarn("This directive without certtype will be removed!\n");
+                       yywarn("Please use 'peers_certfile x509 \"%s\";' instead\n", $2->v);
+                       cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
+                       cur_rmconf->peerscertfile = strdup($2->v);
+                       vfree($2);
+               }
+               EOS
+       |       CA_TYPE CERT_X509 QUOTEDSTRING
+               {
+                       cur_rmconf->cacerttype = $2;
+                       cur_rmconf->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
+                       cur_rmconf->cacertfile = strdup($3->v);
+                       vfree($3);
+               }
+               EOS
+       |       PEERS_CERTFILE CERT_X509 QUOTEDSTRING
+               {
+                       cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
+                       cur_rmconf->peerscertfile = strdup($3->v);
+                       vfree($3);
+               }
+               EOS
+       |       PEERS_CERTFILE CERT_PLAINRSA QUOTEDSTRING
+               {
+                       char path[MAXPATHLEN];
+                       int ret = 0;
+
+                       getpathname(path, sizeof(path),
+                               LC_PATHTYPE_CERT, $3->v);
+                       vfree($3);
+
+                       if (cur_rmconf->getcert_method == ISAKMP_GETCERT_DNS) {
+                               yyerror("Different peers_certfile method "
+                                       "already defined: %d!\n",
+                                       cur_rmconf->getcert_method);
+                               return -1;
+                       }
+                       cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
+                       if (rsa_parse_file(cur_rmconf->rsa_public, path, RSA_TYPE_PUBLIC)) {
+                               yyerror("Couldn't parse keyfile.\n", path);
+                               return -1;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL, "Public PlainRSA keyfile parsed: %s\n", path);
+               }
+               EOS
+       |       PEERS_CERTFILE DNSSEC
+               {
+                       if (cur_rmconf->getcert_method) {
+                               yyerror("Different peers_certfile method already defined!\n");
+                               return -1;
+                       }
+                       cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS;
+                       cur_rmconf->peerscertfile = NULL;
+               }
+               EOS
+       |       VERIFY_CERT SWITCH { cur_rmconf->verify_cert = $2; } EOS
+       |       SEND_CERT SWITCH { cur_rmconf->send_cert = $2; } EOS
+       |       SEND_CR SWITCH { cur_rmconf->send_cr = $2; } EOS
+       |       CERTIFICATE_VERIFICATION VERIFICATION_MODULE 
+               { 
+#ifdef __APPLE__
+                       cur_rmconf->cert_verification = $2; 
+#else
+                       yyerror("Apple specific features not compiled in.");
+                       return -1;
+#endif
+               } EOS
+       |       CERTIFICATE_VERIFICATION VERIFICATION_MODULE VERIFICATION_OPTION
+               {
+#ifdef __APPLE__                       
+                       cur_rmconf->cert_verification = $2;
+                       cur_rmconf->cert_verification_option = $3;
+#else
+                       yyerror("Apple specific features not compiled in.");
+                       return -1;
+#endif
+               }
+               EOS
+       |       OPEN_DIR_AUTH_GROUP QUOTEDSTRING 
+               { 
+#ifdef __APPLE__
+                       cur_rmconf->open_dir_auth_group = $2; 
+#else
+                       yyerror("Apple specific features not compiled in.");
+                       return -1;
+#endif
+               } EOS
+       |       MY_IDENTIFIER IDENTIFIERTYPE identifierstring
+               {
+                       if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) {
+                               yyerror("failed to set identifer.\n");
+                               vfree($3);      //%%% BUG FIX - memory leak
+                               return -1;
+                       }
+                       vfree($3);      //%%% BUG FIX - memory leak
+                       cur_rmconf->idvtype = $2;
+               }
+               EOS
+       |       XAUTH_LOGIN identifierstring
+               {
+#ifdef ENABLE_HYBRID
+                       /* formerly identifier type login */
+                       cur_rmconf->idvtype = IDTYPE_LOGIN;
+                       if (set_identifier(&cur_rmconf->idv, IDTYPE_LOGIN, $2) != 0) {
+                               yyerror("failed to set identifer.\n");
+                               return -1;
+                       }
+                       /* cur_rmconf->use_xauth = 1; */
+#else
+                       yyerror("racoon not configured with --enable-hybrid");
+#endif
+               }
+               EOS
+       |       PEERS_IDENTIFIER IDENTIFIERTYPE identifierstring
+               {
+                       struct idspec  *id;
+                       id = newidspec();
+                       if (id == NULL) {
+                               yyerror("failed to allocate idspec");
+                               return -1;
+                       }
+                       if (set_identifier(&id->id, $2, $3) != 0) {
+                               yyerror("failed to set identifer.\n");
+                               racoon_free(id);
+                               vfree($3);      //%%% BUG FIX - memory leak
+                               return -1;
+                       }
+                       vfree($3);      //%%% BUG FIX - memory leak
+                       id->idtype = $2;
+                       genlist_append (cur_rmconf->idvl_p, id);
+               }
+               EOS
+       |       VERIFY_IDENTIFIER SWITCH { cur_rmconf->verify_identifier = $2; } EOS
+       |       SHARED_SECRET SECRETTYPE QUOTEDSTRING 
+               {
+#ifdef __APPLE__
+                       cur_rmconf->secrettype = $2; 
+                       cur_rmconf->shared_secret = $3; 
+#else
+                       yyerror("Apple specific features not compiled in.");
+                       return -1;
+#endif
+               } EOS
+       |       SHARED_SECRET SECRETTYPE
+               {
+#ifdef __APPLE__
+                       if ($2 != SECRETTYPE_KEYCHAIN_BY_ID) {
+                               yyerror("shared secret value missing.\n");
+                               return -1;
+                       }
+                       cur_rmconf->secrettype = $2;
+#else
+                       yyerror("Apple specific features not compiled in.");
+                       return -1;
+#endif
+
+               } EOS
+       |       NONCE_SIZE NUMBER { cur_rmconf->nonce_size = $2; } EOS
+       |       DH_GROUP
+               {
+                       yyerror("dh_group cannot be defined here.");
+                       return -1;
+               }
+               dh_group_num EOS
+       |       PASSIVE SWITCH { cur_rmconf->passive = $2; } EOS
+       |       IKE_FRAG SWITCH { cur_rmconf->ike_frag = $2; } EOS
+       |       ESP_FRAG NUMBER { 
+#ifdef SADB_X_EXT_NAT_T_FRAG
+                       cur_rmconf->esp_frag = $2; 
+#else
+                       yywarn("Your kernel does not support esp_frag");
+#endif
+               } EOS
+       |       SCRIPT QUOTEDSTRING PHASE1_UP { 
+                       cur_rmconf->script[SCRIPT_PHASE1_UP] = 
+                           script_path_add(vdup($2));
+               } EOS
+       |       SCRIPT QUOTEDSTRING PHASE1_DOWN { 
+                       cur_rmconf->script[SCRIPT_PHASE1_DOWN] = 
+                           script_path_add(vdup($2));
+               } EOS
+       |       MODE_CFG SWITCH { cur_rmconf->mode_cfg = $2; } EOS
+       |       GENERATE_POLICY SWITCH { cur_rmconf->gen_policy = $2; } EOS
+       |       SUPPORT_PROXY SWITCH { cur_rmconf->support_proxy = $2; } EOS
+       |       INITIAL_CONTACT SWITCH { cur_rmconf->ini_contact = $2; } EOS
+       |       NAT_TRAVERSAL SWITCH
+               {
+#ifdef ENABLE_NATT
+                       cur_rmconf->nat_traversal = $2;
+#else
+                       yyerror("NAT-T support not compiled in.");
+#endif
+               } EOS
+       |       NAT_TRAVERSAL NAT_TRAVERSAL_LEVEL
+               {
+#ifdef ENABLE_NATT
+                       cur_rmconf->nat_traversal = $2;
+#else
+                       yyerror("NAT-T support not compiled in.");
+#endif
+               } EOS
+       |       NAT_TRAVERSAL_MULTI_USER SWITCH
+               {
+#ifdef ENABLE_NATT
+#ifdef __APPLE__
+                       cur_rmconf->natt_multiple_user = $2;
+#else
+                       yyerror("Apple specific features not compiled in.");
+#endif
+#else
+                       yyerror("NAT-T support not compiled in.");
+#endif
+               } EOS
+       |       DPD SWITCH
+               {
+#ifdef ENABLE_DPD
+                       cur_rmconf->dpd = $2;
+#else
+                       yyerror("DPD support not compiled in.");
+#endif
+               } EOS
+       |       DPD_DELAY NUMBER
+               {
+#ifdef ENABLE_DPD
+                       cur_rmconf->dpd_interval = $2;
+#else
+                       yyerror("DPD support not compiled in.");
+#endif
+               }
+               EOS
+       |       DPD_RETRY NUMBER
+               {
+#ifdef ENABLE_DPD
+                       cur_rmconf->dpd_retry = $2;
+#else
+                       yyerror("DPD support not compiled in.");
+#endif
+               }
+               EOS
+       |       DPD_MAXFAIL NUMBER
+               {
+#ifdef ENABLE_DPD
+                       cur_rmconf->dpd_maxfails = $2;
+#else
+                       yyerror("DPD support not compiled in.");
+#endif
+               }
+               EOS
+       |       LIFETIME LIFETYPE_TIME NUMBER unittype_time
+               {
+                       cur_rmconf->prhead->lifetime = $3 * $4;
+               }
+               EOS
+       |       PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS
+       |       LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
+               {
+#if 1
+                       yyerror("byte lifetime support is deprecated in Phase1");
+                       return -1;
+#else
+                       yywarn("the lifetime of bytes in phase 1 "
+                               "will be ignored at the moment.");
+                       cur_rmconf->prhead->lifebyte = fix_lifebyte($3 * $4);
+                       if (cur_rmconf->prhead->lifebyte == 0)
+                               return -1;
+#endif
+               }
+               EOS
+       |       PROPOSAL
+               {
+                       struct secprotospec *spspec;
+
+                       spspec = newspspec();
+                       if (spspec == NULL)
+                               return -1;
+                       insspspec(spspec, &cur_rmconf->prhead);
+               }
+               BOC isakmpproposal_specs EOC
+       ;
+exchange_types
+       :       /* nothing */
+       |       exchange_types EXCHANGETYPE
+               {
+                       struct etypes *new;
+                       new = racoon_malloc(sizeof(struct etypes));
+                       if (new == NULL) {
+                               yyerror("filed to allocate etypes");
+                               return -1;
+                       }
+                       new->type = $2;
+                       new->next = NULL;
+                       if (cur_rmconf->etypes == NULL)
+                               cur_rmconf->etypes = new;
+                       else {
+                               struct etypes *p;
+                               for (p = cur_rmconf->etypes;
+                                    p->next != NULL;
+                                    p = p->next)
+                                       ;
+                               p->next = new;
+                       }
+               }
+       ;
+cert_spec
+       :       CERT_X509 QUOTEDSTRING QUOTEDSTRING
+               {
+                       cur_rmconf->certtype = $1;
+                       cur_rmconf->mycertfile = strdup($2->v);
+                       vfree($2);
+                       cur_rmconf->myprivfile = strdup($3->v);
+                       vfree($3);
+               }
+               EOS
+       |       CERT_X509 IN_KEYCHAIN
+               {
+#ifdef __APPLE__
+                       cur_rmconf->certtype = $1;
+                       cur_rmconf->identity_in_keychain = 1;
+                       cur_rmconf->keychainCertRef = NULL;
+#endif
+               }
+               EOS
+       ;
+       |       CERT_X509 IN_KEYCHAIN QUOTEDSTRING
+               {
+#ifdef __APPLE__
+                       
+                       cur_rmconf->certtype = $1;
+                       cur_rmconf->identity_in_keychain = 1;
+                       cur_rmconf->keychainCertRef = $3;
+#endif
+               }
+               EOS
+       ;
+       |       CERT_PLAINRSA QUOTEDSTRING
+               {
+                       char path[MAXPATHLEN];
+                       int ret = 0;
+
+                       getpathname(path, sizeof(path),
+                               LC_PATHTYPE_CERT, $2->v);
+                       vfree($2);
+
+                       cur_rmconf->certtype = $1;
+                       cur_rmconf->send_cr = FALSE;
+                       cur_rmconf->send_cert = FALSE;
+                       cur_rmconf->verify_cert = FALSE;
+                       if (rsa_parse_file(cur_rmconf->rsa_private, path, RSA_TYPE_PRIVATE)) {
+                               yyerror("Couldn't parse keyfile.\n", path);
+                               return -1;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL, "Private PlainRSA keyfile parsed: %s\n", path);
+               }
+               EOS
+       ;
+dh_group_num
+       :       ALGORITHMTYPE
+               {
+                       $$ = algtype2doi(algclass_isakmp_dh, $1);
+                       if ($$ == -1) {
+                               yyerror("must be DH group");
+                               return -1;
+                       }
+               }
+       |       NUMBER
+               {
+                       if (ARRAYLEN(num2dhgroup) > $1 && num2dhgroup[$1] != 0) {
+                               $$ = num2dhgroup[$1];
+                       } else {
+                               yyerror("must be DH group");
+                               $$ = 0;
+                               return -1;
+                       }
+               }
+       ;
+identifierstring
+       :       /* nothing */ { $$ = NULL; }
+       |       ADDRSTRING { $$ = $1; }
+       |       QUOTEDSTRING { $$ = $1; }
+       ;
+isakmpproposal_specs
+       :       /* nothing */
+       |       isakmpproposal_specs isakmpproposal_spec
+       ;
+isakmpproposal_spec
+       :       STRENGTH
+               {
+                       yyerror("strength directive is obsoleted.");
+               } STRENGTHTYPE EOS
+       |       LIFETIME LIFETYPE_TIME NUMBER unittype_time
+               {
+                       cur_rmconf->prhead->spspec->lifetime = $3 * $4;
+               }
+               EOS
+       |       LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
+               {
+#if 1
+                       yyerror("byte lifetime support is deprecated");
+                       return -1;
+#else
+                       cur_rmconf->prhead->spspec->lifebyte = fix_lifebyte($3 * $4);
+                       if (cur_rmconf->prhead->spspec->lifebyte == 0)
+                               return -1;
+#endif
+               }
+               EOS
+       |       DH_GROUP dh_group_num
+               {
+                       cur_rmconf->prhead->spspec->algclass[algclass_isakmp_dh] = $2;
+               }
+               EOS
+       |       GSS_ID QUOTEDSTRING
+               {
+                       if (cur_rmconf->prhead->spspec->vendorid != VENDORID_GSSAPI) {
+                               yyerror("wrong Vendor ID for gssapi_id");
+                               return -1;
+                       }
+                       cur_rmconf->prhead->spspec->gssid = strdup($2->v);
+               }
+               EOS
+       |       ALGORITHM_CLASS ALGORITHMTYPE keylength
+               {
+                       int doi;
+                       int defklen;
+
+                       doi = algtype2doi($1, $2);
+                       if (doi == -1) {
+                               yyerror("algorithm mismatched 1");
+                               return -1;
+                       }
+
+                       switch ($1) {
+                       case algclass_isakmp_enc:
+                       /* reject suppressed algorithms */
+#ifndef HAVE_OPENSSL_RC5_H
+                               if ($2 == algtype_rc5) {
+                                       yyerror("algorithm %s not supported",
+                                           s_attr_isakmp_enc(doi));
+                                       return -1;
+                               }
+#endif
+#ifndef HAVE_OPENSSL_IDEA_H
+                               if ($2 == algtype_idea) {
+                                       yyerror("algorithm %s not supported",
+                                           s_attr_isakmp_enc(doi));
+                                       return -1;
+                               }
+#endif
+
+                               cur_rmconf->prhead->spspec->algclass[algclass_isakmp_enc] = doi;
+                               defklen = default_keylen($1, $2);
+                               if (defklen == 0) {
+                                       if ($3) {
+                                               yyerror("keylen not allowed");
+                                               return -1;
+                                       }
+                               } else {
+                                       if ($3 && check_keylen($1, $2, $3) < 0) {
+                                               yyerror("invalid keylen %d", $3);
+                                               return -1;
+                                       }
+                               }
+                               if ($3)
+                                       cur_rmconf->prhead->spspec->encklen = $3;
+                               else
+                                       cur_rmconf->prhead->spspec->encklen = defklen;
+                               break;
+                       case algclass_isakmp_hash:
+                               cur_rmconf->prhead->spspec->algclass[algclass_isakmp_hash] = doi;
+                               break;
+                       case algclass_isakmp_ameth:
+                               cur_rmconf->prhead->spspec->algclass[algclass_isakmp_ameth] = doi;
+                               /*
+                                * We may have to set the Vendor ID for the
+                                * authentication method we're using.
+                                */
+                               switch ($2) {
+                               case algtype_gssapikrb:
+                                       if (cur_rmconf->prhead->spspec->vendorid !=
+                                           VENDORID_UNKNOWN) {
+                                               yyerror("Vendor ID mismatch "
+                                                   "for auth method");
+                                               return -1;
+                                       }
+                                       /*
+                                        * For interoperability with Win2k,
+                                        * we set the Vendor ID to "GSSAPI".
+                                        */
+                                       cur_rmconf->prhead->spspec->vendorid =
+                                           VENDORID_GSSAPI;
+                                       break;
+                               case algtype_rsasig:
+                                       if (cur_rmconf->certtype == ISAKMP_CERT_PLAINRSA) {
+                                               if (rsa_list_count(cur_rmconf->rsa_private) == 0) {
+                                                       yyerror ("Private PlainRSA key not set. "
+                                                               "Use directive 'certificate_type plainrsa ...'\n");
+                                                       return -1;
+                                               }
+                                               if (rsa_list_count(cur_rmconf->rsa_public) == 0) {
+                                                       yyerror ("Public PlainRSA keys not set. "
+                                                               "Use directive 'peers_certfile plainrsa ...'\n");
+                                                       return -1;
+                                               }
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               yyerror("algorithm mismatched 2");
+                               return -1;
+                       }
+               }
+               EOS
+       ;
+
+unittype_time
+       :       UNITTYPE_SEC    { $$ = 1; }
+       |       UNITTYPE_MIN    { $$ = 60; }
+       |       UNITTYPE_HOUR   { $$ = (60 * 60); }
+       ;
+unittype_byte
+       :       UNITTYPE_BYTE   { $$ = 1; }
+       |       UNITTYPE_KBYTES { $$ = 1024; }
+       |       UNITTYPE_MBYTES { $$ = (1024 * 1024); }
+       |       UNITTYPE_TBYTES { $$ = (1024 * 1024 * 1024); }
+       ;
+%%
+
+static struct proposalspec *
+newprspec()
+{
+       struct proposalspec *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               yyerror("failed to allocate proposal");
+
+       return new;
+}
+
+/*
+ * insert into head of list.
+ */
+static void
+insprspec(prspec, head)
+       struct proposalspec *prspec;
+       struct proposalspec **head;
+{
+       if (*head != NULL)
+               (*head)->prev = prspec;
+       prspec->next = *head;
+       *head = prspec;
+}
+
+static struct secprotospec *
+newspspec()
+{
+       struct secprotospec *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL) {
+               yyerror("failed to allocate spproto");
+               return NULL;
+       }
+
+       new->encklen = 0;       /*XXX*/
+
+       /*
+        * Default to "uknown" vendor -- we will override this
+        * as necessary.  When we send a Vendor ID payload, an
+        * "unknown" will be translated to a KAME/racoon ID.
+        */
+       new->vendorid = VENDORID_UNKNOWN;
+
+       return new;
+}
+
+/*
+ * insert into head of list.
+ */
+static void
+insspspec(spspec, head)
+       struct secprotospec *spspec;
+       struct proposalspec **head;
+{
+       spspec->back = *head;
+
+       if ((*head)->spspec != NULL)
+               (*head)->spspec->prev = spspec;
+       spspec->next = (*head)->spspec;
+       (*head)->spspec = spspec;
+}
+
+/* set final acceptable proposal */
+static int
+set_isakmp_proposal(rmconf, prspec)
+       struct remoteconf *rmconf;
+       struct proposalspec *prspec;
+{
+       struct proposalspec *p;
+       struct secprotospec *s;
+       int prop_no = 1; 
+       int trns_no = 1;
+       int32_t types[MAXALGCLASS];
+
+       p = prspec;
+       if (p->next != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "multiple proposal definition.\n");
+               return -1;
+       }
+
+       /* mandatory check */
+       if (p->spspec == NULL) {
+               yyerror("no remote specification found: %s.\n",
+                       saddr2str(rmconf->remote));
+               return -1;
+       }
+       for (s = p->spspec; s != NULL; s = s->next) {
+               /* XXX need more to check */
+               if (s->algclass[algclass_isakmp_enc] == 0) {
+                       yyerror("encryption algorithm required.");
+                       return -1;
+               }
+               if (s->algclass[algclass_isakmp_hash] == 0) {
+                       yyerror("hash algorithm required.");
+                       return -1;
+               }
+               if (s->algclass[algclass_isakmp_dh] == 0) {
+                       yyerror("DH group required.");
+                       return -1;
+               }
+               if (s->algclass[algclass_isakmp_ameth] == 0) {
+                       yyerror("authentication method required.");
+                       return -1;
+               }
+       }
+
+       /* skip to last part */
+       for (s = p->spspec; s->next != NULL; s = s->next)
+               ;
+
+       while (s != NULL) {
+               plog(LLV_DEBUG2, LOCATION, NULL,
+                       "lifetime = %ld\n", (long)
+                       (s->lifetime ? s->lifetime : p->lifetime));
+               plog(LLV_DEBUG2, LOCATION, NULL,
+                       "lifebyte = %d\n",
+                       s->lifebyte ? s->lifebyte : p->lifebyte);
+               plog(LLV_DEBUG2, LOCATION, NULL,
+                       "encklen=%d\n", s->encklen);
+
+               memset(types, 0, ARRAYLEN(types));
+               types[algclass_isakmp_enc] = s->algclass[algclass_isakmp_enc];
+               types[algclass_isakmp_hash] = s->algclass[algclass_isakmp_hash];
+               types[algclass_isakmp_dh] = s->algclass[algclass_isakmp_dh];
+               types[algclass_isakmp_ameth] =
+                   s->algclass[algclass_isakmp_ameth];
+
+               /* expanding spspec */
+               clean_tmpalgtype();
+               trns_no = expand_isakmpspec(prop_no, trns_no, types,
+                               algclass_isakmp_enc, algclass_isakmp_ameth + 1,
+                               s->lifetime ? s->lifetime : p->lifetime,
+                               s->lifebyte ? s->lifebyte : p->lifebyte,
+                               s->encklen, s->vendorid, s->gssid,
+                               rmconf);
+               if (trns_no == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to expand isakmp proposal.\n");
+                       return -1;
+               }
+
+               s = s->prev;
+       }
+
+       if (rmconf->proposal == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no proposal found.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void
+clean_tmpalgtype()
+{
+       int i;
+       for (i = 0; i < MAXALGCLASS; i++)
+               tmpalgtype[i] = 0;      /* means algorithm undefined. */
+}
+
+static int
+expand_isakmpspec(prop_no, trns_no, types,
+               class, last, lifetime, lifebyte, encklen, vendorid, gssid,
+               rmconf)
+       int prop_no, trns_no;
+       int *types, class, last;
+       time_t lifetime;
+       int lifebyte;
+       int encklen;
+       int vendorid;
+       char *gssid;
+       struct remoteconf *rmconf;
+{
+       struct isakmpsa *new;
+
+       /* debugging */
+    {
+       int j;
+       char tb[10];
+       plog(LLV_DEBUG2, LOCATION, NULL,
+               "p:%d t:%d\n", prop_no, trns_no);
+       for (j = class; j < MAXALGCLASS; j++) {
+               snprintf(tb, sizeof(tb), "%d", types[j]);
+               plog(LLV_DEBUG2, LOCATION, NULL,
+                       "%s%s%s%s\n",
+                       s_algtype(j, types[j]),
+                       types[j] ? "(" : "",
+                       tb[0] == '0' ? "" : tb,
+                       types[j] ? ")" : "");
+       }
+       plog(LLV_DEBUG2, LOCATION, NULL, "\n");
+    }
+
+#define TMPALGTYPE2STR(n) \
+       s_algtype(algclass_isakmp_##n, types[algclass_isakmp_##n])
+               /* check mandatory values */
+               if (types[algclass_isakmp_enc] == 0
+                || types[algclass_isakmp_ameth] == 0
+                || types[algclass_isakmp_hash] == 0
+                || types[algclass_isakmp_dh] == 0) {
+                       yyerror("few definition of algorithm "
+                               "enc=%s ameth=%s hash=%s dhgroup=%s.\n",
+                               TMPALGTYPE2STR(enc),
+                               TMPALGTYPE2STR(ameth),
+                               TMPALGTYPE2STR(hash),
+                               TMPALGTYPE2STR(dh));
+                       return -1;
+               }
+#undef TMPALGTYPE2STR
+
+       /* set new sa */
+       new = newisakmpsa();
+       if (new == NULL) {
+               yyerror("failed to allocate isakmp sa");
+               return -1;
+       }
+       new->prop_no = prop_no;
+       new->trns_no = trns_no++;
+       new->lifetime = lifetime;
+       new->lifebyte = lifebyte;
+       new->enctype = types[algclass_isakmp_enc];
+       new->encklen = encklen;
+       new->authmethod = types[algclass_isakmp_ameth];
+       new->hashtype = types[algclass_isakmp_hash];
+       new->dh_group = types[algclass_isakmp_dh];
+       new->vendorid = vendorid;
+#ifdef HAVE_GSSAPI
+       if (new->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+               if (gssid != NULL) {
+                       new->gssid = vmalloc(strlen(gssid));
+                       memcpy(new->gssid->v, gssid, new->gssid->l);
+                       racoon_free(gssid);
+               } else {
+                       /*
+                        * Allocate the default ID so that it gets put
+                        * into a GSS ID attribute during the Phase 1
+                        * exchange.
+                        */
+                       new->gssid = gssapi_get_default_gss_id();
+               }
+       }
+#endif
+       insisakmpsa(new, rmconf);
+
+       return trns_no;
+}
+
+static int
+listen_addr (struct sockaddr *addr, int udp_encap)
+{
+       struct myaddrs *p;
+
+       p = newmyaddr();
+       if (p == NULL) {
+               yyerror("failed to allocate myaddrs");
+               return -1;
+       }
+       p->addr = addr;
+       if (p->addr == NULL) {
+               yyerror("failed to copy sockaddr ");
+               delmyaddr(p);
+               return -1;
+       }
+       p->udp_encap = udp_encap;
+#ifdef __APPLE__
+       /* These need to be initialized for Apple modifications
+        * to open code for isakmp sockets 
+     */
+       p->sock = -1;
+       p->in_use = 1;
+#endif
+
+       insmyaddr(p, &lcconf->myaddrs);
+
+       lcconf->autograbaddr = 0;
+       return 0;
+}
+
+#if 0
+/*
+ * fix lifebyte.
+ * Must be more than 1024B because its unit is kilobytes.
+ * That is defined RFC2407.
+ */
+static int
+fix_lifebyte(t)
+       unsigned long t;
+{
+       if (t < 1024) {
+               yyerror("byte size should be more than 1024B.");
+               return 0;
+       }
+
+       return(t / 1024);
+}
+#endif
+
+int
+cfparse()
+{
+       int error;
+       
+       plog(LLV_DEBUG, LOCATION, NULL, "===== parse config\n");
+
+       yycf_init_buffer();
+
+       if (yycf_switch_buffer(lcconf->racoon_conf) != 0)
+               return -1;
+
+       error = yyparse();
+       if (error != 0) {
+               if (yyerrorcount) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "fatal parse failure (%d errors)\n",
+                               yyerrorcount);
+               } else {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "fatal parse failure.\n");
+               }
+               return -1;
+       }
+
+       if (error == 0 && yyerrorcount) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "parse error is nothing, but yyerrorcount is %d.\n",
+                               yyerrorcount);
+               exit(1);
+       }
+
+       yycf_clean_buffer();
+
+       plog(LLV_DEBUG2, LOCATION, NULL, "parse successed.\n");
+
+       return 0;
+}
+
+int
+cfreparse()
+{
+       plog(LLV_DEBUG, LOCATION, NULL, "==== Got HUP signal - re-parsing.\n");
+       flushph2();
+       flushph1();
+       flushrmconf();
+       flushsainfo();
+       flushlcconf();
+       check_auto_exit();      /* check/change state of auto exit */
+       clean_tmpalgtype();
+
+       return(cfparse());
+}
+
+
+#ifdef ENABLE_ADMINPORT
+static void
+adminsock_conf(path, owner, group, mode_dec)
+       vchar_t *path;
+       vchar_t *owner;
+       vchar_t *group;
+       int mode_dec;
+{
+       struct passwd *pw = NULL;
+       struct group *gr = NULL;
+       mode_t mode = 0;
+       uid_t uid;
+       gid_t gid;
+       int isnum;
+
+       adminsock_path = path->v;
+
+       if (owner == NULL)
+               return;
+
+       errno = 0;
+       uid = atoi(owner->v);
+       isnum = !errno;
+       if (((pw = getpwnam(owner->v)) == NULL) && !isnum)
+               yyerror("User \"%s\" does not exist", owner->v);
+
+       if (pw)
+               adminsock_owner = pw->pw_uid;
+       else
+               adminsock_owner = uid;
+
+       if (group == NULL)
+               return;
+
+       errno = 0;
+       gid = atoi(group->v);
+       isnum = !errno;
+       if (((gr = getgrnam(group->v)) == NULL) && !isnum)
+               yyerror("Group \"%s\" does not exist", group->v);
+
+       if (gr)
+               adminsock_group = gr->gr_gid;
+       else
+               adminsock_group = gid;
+
+       if (mode_dec == -1)
+               return;
+
+       if (mode_dec > 777)
+               yyerror("Mode 0%03o is invalid", mode_dec);
+       if (mode_dec >= 400) { mode += 0400; mode_dec -= 400; }
+       if (mode_dec >= 200) { mode += 0200; mode_dec -= 200; }
+       if (mode_dec >= 100) { mode += 0200; mode_dec -= 100; }
+
+       if (mode_dec > 77)
+               yyerror("Mode 0%03o is invalid", mode_dec);
+       if (mode_dec >= 40) { mode += 040; mode_dec -= 40; }
+       if (mode_dec >= 20) { mode += 020; mode_dec -= 20; }
+       if (mode_dec >= 10) { mode += 020; mode_dec -= 10; }
+
+       if (mode_dec > 7)
+               yyerror("Mode 0%03o is invalid", mode_dec);
+       if (mode_dec >= 4) { mode += 04; mode_dec -= 4; }
+       if (mode_dec >= 2) { mode += 02; mode_dec -= 2; }
+       if (mode_dec >= 1) { mode += 02; mode_dec -= 1; }
+       
+       adminsock_mode = mode;
+
+       return;
+}
+#endif
diff --git a/ipsec-tools/racoon/cfparse_proto.h b/ipsec-tools/racoon/cfparse_proto.h
new file mode 100644 (file)
index 0000000..73c824e
--- /dev/null
@@ -0,0 +1,40 @@
+/* $Id: cfparse_proto.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CFPARSE_PROTO_H
+#define _CFPARSE_PROTO_H
+
+/* cfparse.y */
+extern int yyparse __P((void));
+extern int cfparse __P((void));
+extern int cfreparse __P((void));
+
+#endif /* _CFPARSE_PROTO_H */
diff --git a/ipsec-tools/racoon/cftoken.l b/ipsec-tools/racoon/cftoken.l
new file mode 100644 (file)
index 0000000..861e836
--- /dev/null
@@ -0,0 +1,854 @@
+/* $Id: cftoken.l,v 1.31.2.7 2005/11/06 17:18:26 monas Exp $ */
+%option noyywrap
+%{
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 and 2003 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC 
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+#include <glob.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+//%%% BUG FIX - 2 missing include files when not using
+// the bison files
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "algorithm.h"
+#include "cfparse_proto.h"
+#include "cftoken_proto.h"
+#include "localconf.h"
+#include "oakley.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "proposal.h"
+#include "nattraversal.h"
+#ifdef GC
+#include "gcmalloc.h"
+#endif
+
+#ifdef __APPLE__
+#include "y.tab.h"
+#else
+#include "cfparse.h"
+#endif
+
+int yyerrorcount = 0;
+
+#if defined(YIPS_DEBUG)
+#  define YYDB plog(LLV_DEBUG2, LOCATION, NULL,                                \
+               "begin <%d>%s\n", yy_start, yytext);
+#  define YYD {                                                                \
+       plog(LLV_DEBUG2, LOCATION, NULL, "<%d>%s",                             \
+           yy_start, loglevel >= LLV_DEBUG2 ? "\n" : "");                     \
+}
+#else
+#  define YYDB
+#  define YYD
+#endif /* defined(YIPS_DEBUG) */
+
+#define MAX_INCLUDE_DEPTH 10
+
+static struct include_stack {
+       char *path;
+       FILE *fp;
+       YY_BUFFER_STATE prevstate;
+       int lineno;
+       glob_t matches;
+       int matchon;
+} incstack[MAX_INCLUDE_DEPTH];
+static int incstackp = 0;
+
+static int yy_first_time = 1;
+%}
+
+/* common section */
+nl             \n
+ws             [ \t]+
+digit          [0-9]
+letter         [A-Za-z]
+hexdigit       [0-9A-Fa-f]
+/*octet                (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5]))) */
+special                [()+\|\?\*]
+comma          \,
+dot            \.
+slash          \/
+bcl            \{
+ecl            \}
+blcl           \[
+elcl           \]
+percent                \%
+semi           \;
+comment                \#.*
+ccomment       "/*"
+bracketstring  \<[^>]*\>
+quotedstring   \"[^"]*\"
+addrstring     [a-fA-F0-9:]([a-fA-F0-9:\.]*|[a-fA-F0-9:\.]*%[a-zA-Z0-9]*)
+decstring      {digit}+
+hexstring      0x{hexdigit}+
+
+%s S_INI S_PRIV S_PTH S_INF S_LOG S_PAD S_LST S_RTRY S_CFG
+%s S_ALGST S_ALGCL
+%s S_SAINF S_SAINFS
+%s S_RMT S_RMTS S_RMTP
+%s S_SA
+%s S_GSSENC
+
+%%
+%{
+       if (yy_first_time) {
+               BEGIN S_INI;
+               yy_first_time = 0;
+       }
+%}
+
+       /* privsep */
+<S_INI>privsep         { BEGIN S_PRIV; YYDB; return(PRIVSEP); }
+<S_PRIV>{bcl}          { return(BOC); }
+<S_PRIV>user           { YYD; return(USER); }
+<S_PRIV>group          { YYD; return(GROUP); }
+<S_PRIV>chroot         { YYD; return(CHROOT); }
+<S_PRIV>{ecl}          { BEGIN S_INI; return(EOC); }
+
+       /* path */
+<S_INI>path            { BEGIN S_PTH; YYDB; return(PATH); }
+<S_PTH>include         { YYD; yylval.num = LC_PATHTYPE_INCLUDE;
+                               return(PATHTYPE); }
+<S_PTH>pre_shared_key  { YYD; yylval.num = LC_PATHTYPE_PSK;
+                               return(PATHTYPE); }
+<S_PTH>certificate     { YYD; yylval.num = LC_PATHTYPE_CERT;
+                               return(PATHTYPE); }
+<S_PTH>script          { YYD; yylval.num = LC_PATHTYPE_SCRIPT;
+                               return(PATHTYPE); }
+<S_PTH>backupsa                { YYD; yylval.num = LC_PATHTYPE_BACKUPSA;
+                               return(PATHTYPE); }
+<S_PTH>pidfile         { YYD; yylval.num = LC_PATHTYPE_PIDFILE;
+                               return(PATHTYPE); }
+<S_PTH>logfile         { YYD; yylval.num = LC_PATHTYPE_LOGFILE;
+                               return(PATHTYPE); }
+<S_PTH>{semi}          { BEGIN S_INI; YYDB; return(EOS); }
+
+       /* include */
+<S_INI>include         { YYDB; return(INCLUDE); }
+
+       /* self information */
+<S_INI>identifier      { BEGIN S_INF; YYDB; yywarn("it is obsoleted.  use \"my_identifier\" in each remote directives."); return(IDENTIFIER); }
+<S_INF>{semi}          { BEGIN S_INI; return(EOS); }
+
+       /* special */
+<S_INI>complex_bundle  { YYDB; return(COMPLEX_BUNDLE); }
+
+       /* logging */
+<S_INI>log             { BEGIN S_LOG; YYDB; return(LOGGING); }
+<S_LOG>info            { YYD; yywarn("it is obsoleted.  use \"notify\""); yylval.num = 0; return(LOGLEV); }
+<S_LOG>notify          { YYD; yylval.num = 0; return(LOGLEV); }
+<S_LOG>debug           { YYD; yylval.num = 1; return(LOGLEV); }
+<S_LOG>debug2          { YYD; yylval.num = 2; return(LOGLEV); }
+<S_LOG>debug3          { YYD; yywarn("it is osboleted.  use \"debug2\""); yylval.num = 2; return(LOGLEV); }
+<S_LOG>debug4          { YYD; yywarn("it is obsoleted.  use \"debug2\""); yylval.num = 2; return(LOGLEV); }
+<S_LOG>{semi}          { BEGIN S_INI; return(EOS); }
+
+       /* padding */
+<S_INI>padding         { BEGIN S_PAD; YYDB; return(PADDING); }
+<S_PAD>{bcl}           { return(BOC); }
+<S_PAD>randomize       { YYD; return(PAD_RANDOMIZE); }
+<S_PAD>randomize_length        { YYD; return(PAD_RANDOMIZELEN); }
+<S_PAD>maximum_length  { YYD; return(PAD_MAXLEN); }
+<S_PAD>strict_check    { YYD; return(PAD_STRICT); }
+<S_PAD>exclusive_tail  { YYD; return(PAD_EXCLTAIL); }
+<S_PAD>{ecl}           { BEGIN S_INI; return(EOC); }
+
+       /* listen */
+<S_INI>listen          { BEGIN S_LST; YYDB; return(LISTEN); }
+<S_LST>{bcl}           { return(BOC); }
+<S_LST>isakmp          { YYD; return(X_ISAKMP); }
+<S_LST>isakmp_natt     { YYD; return(X_ISAKMP_NATT); }
+<S_LST>admin           { YYD; return(X_ADMIN); }
+<S_LST>adminsock       { YYD; return(ADMINSOCK); }
+<S_LST>disabled                { YYD; return(DISABLED); }
+<S_LST>strict_address  { YYD; return(STRICT_ADDRESS); }
+<S_LST>{ecl}           { BEGIN S_INI; return(EOC); }
+
+       /* mode_cfg */
+<S_INI>mode_cfg                { BEGIN S_CFG; YYDB; return(MODECFG); }
+<S_CFG>{bcl}           { return(BOC); }
+<S_CFG>network4                { YYD; return(CFG_NET4); }
+<S_CFG>netmask4                { YYD; return(CFG_MASK4); }
+<S_CFG>dns4            { YYD; return(CFG_DNS4); }
+<S_CFG>wins4           { YYD; return(CFG_NBNS4); }
+<S_CFG>auth_source     { YYD; return(CFG_AUTH_SOURCE); }
+<S_CFG>conf_source     { YYD; return(CFG_CONF_SOURCE); }
+<S_CFG>accounting      { YYD; return(CFG_ACCOUNTING); }
+<S_CFG>system          { YYD; return(CFG_SYSTEM); }
+<S_CFG>local           { YYD; return(CFG_LOCAL); }
+<S_CFG>none            { YYD; return(CFG_NONE); }
+<S_CFG>radius          { YYD; return(CFG_RADIUS); }
+<S_CFG>pam             { YYD; return(CFG_PAM); }
+<S_CFG>pool_size       { YYD; return(CFG_POOL_SIZE); }
+<S_CFG>banner          { YYD; return(CFG_MOTD); }
+<S_CFG>auth_throttle   { YYD; return(CFG_AUTH_THROTTLE); }
+<S_CFG>pfs_group       { YYD; return(CFG_PFS_GROUP); }
+<S_CFG>save_passwd     { YYD; return(CFG_SAVE_PASSWD); }
+<S_CFG>{ecl}           { BEGIN S_INI; return(EOC); }
+
+       /* timer */
+<S_INI>timer           { BEGIN S_RTRY; YYDB; return(RETRY); }
+<S_RTRY>{bcl}          { return(BOC); }
+<S_RTRY>counter                { YYD; return(RETRY_COUNTER); }
+<S_RTRY>interval       { YYD; return(RETRY_INTERVAL); }
+<S_RTRY>persend                { YYD; return(RETRY_PERSEND); }
+<S_RTRY>phase1         { YYD; return(RETRY_PHASE1); }
+<S_RTRY>phase2         { YYD; return(RETRY_PHASE2); }
+<S_RTRY>natt_keepalive { YYD; return(NATT_KA); }
+<S_RTRY>auto_exit_delay        { YYD; return(AUTO_EXIT_DELAY); } 
+<S_RTRY>{ecl}          { BEGIN S_INI; return(EOC); }
+
+       /* sainfo */
+<S_INI>sainfo          { BEGIN S_SAINF; YYDB; return(SAINFO); }
+<S_SAINF>anonymous     { YYD; return(ANONYMOUS); }
+<S_SAINF>{blcl}any{elcl}       { YYD; return(PORTANY); }
+<S_SAINF>any           { YYD; return(ANY); }
+<S_SAINF>from          { YYD; return(FROM); }
+       /* sainfo spec */
+<S_SAINF>{bcl}         { BEGIN S_SAINFS; return(BOC); }
+<S_SAINF>{semi}                { BEGIN S_INI; return(EOS); }
+<S_SAINFS>{ecl}                { BEGIN S_INI; return(EOC); }
+<S_SAINFS>pfs_group    { YYD; return(PFS_GROUP); }
+<S_SAINFS>identifier   { YYD; yywarn("it is obsoleted.  use \"my_identifier\"."); return(IDENTIFIER); }
+<S_SAINFS>my_identifier        { YYD; return(MY_IDENTIFIER); }
+<S_SAINFS>lifetime     { YYD; return(LIFETIME); }
+<S_SAINFS>time         { YYD; return(LIFETYPE_TIME); }
+<S_SAINFS>byte         { YYD; return(LIFETYPE_BYTE); }
+<S_SAINFS>encryption_algorithm { YYD; yylval.num = algclass_ipsec_enc; return(ALGORITHM_CLASS); }
+<S_SAINFS>authentication_algorithm { YYD; yylval.num = algclass_ipsec_auth; return(ALGORITHM_CLASS); }
+<S_SAINFS>compression_algorithm        { YYD; yylval.num = algclass_ipsec_comp; return(ALGORITHM_CLASS); }
+<S_SAINFS>{comma}      { YYD; return(COMMA); }
+
+       /* remote */
+<S_INI>remote          { BEGIN S_RMT; YYDB; return(REMOTE); }
+<S_RMT>anonymous       { YYD; return(ANONYMOUS); }
+<S_RMT>inherit         { YYD; return(INHERIT); }
+       /* remote spec */
+<S_RMT>{bcl}           { BEGIN S_RMTS; return(BOC); }
+<S_RMTS>{ecl}          { BEGIN S_INI; return(EOC); }
+<S_RMTS>exchange_mode  { YYD; return(EXCHANGE_MODE); }
+<S_RMTS>{comma}                { YYD; /* XXX ignored, but to be handled. */ ; }
+<S_RMTS>base           { YYD; yylval.num = ISAKMP_ETYPE_BASE; return(EXCHANGETYPE); }
+<S_RMTS>main           { YYD; yylval.num = ISAKMP_ETYPE_IDENT; return(EXCHANGETYPE); }
+<S_RMTS>aggressive     { YYD; yylval.num = ISAKMP_ETYPE_AGG; return(EXCHANGETYPE); }
+<S_RMTS>doi            { YYD; return(DOI); }
+<S_RMTS>ipsec_doi      { YYD; yylval.num = IPSEC_DOI; return(DOITYPE); }
+<S_RMTS>situation      { YYD; return(SITUATION); }
+<S_RMTS>identity_only  { YYD; yylval.num = IPSECDOI_SIT_IDENTITY_ONLY; return(SITUATIONTYPE); }
+<S_RMTS>secrecy                { YYD; yylval.num = IPSECDOI_SIT_SECRECY; return(SITUATIONTYPE); }
+<S_RMTS>integrity      { YYD; yylval.num = IPSECDOI_SIT_INTEGRITY; return(SITUATIONTYPE); }
+<S_RMTS>identifier     { YYD; yywarn("it is obsoleted.  use \"my_identifier\"."); return(IDENTIFIER); }
+<S_RMTS>my_identifier  { YYD; return(MY_IDENTIFIER); }
+<S_RMTS>xauth_login    { YYD; return(XAUTH_LOGIN); /* formerly identifier type login */ }
+<S_RMTS>peers_identifier       { YYD; return(PEERS_IDENTIFIER); }
+<S_RMTS>verify_identifier      { YYD; return(VERIFY_IDENTIFIER); }
+<S_RMTS>certificate_type       { YYD; return(CERTIFICATE_TYPE); }
+<S_RMTS>ca_type                { YYD; return(CA_TYPE); }
+<S_RMTS>x509           { YYD; yylval.num = ISAKMP_CERT_X509SIGN; return(CERT_X509); }
+<S_RMTS>plain_rsa      { YYD; yylval.num = ISAKMP_CERT_PLAINRSA; return(CERT_PLAINRSA); }
+<S_RMTS>open_dir_auth_group    { 
+#ifdef __APPLE__
+       YYD; 
+       return(OPEN_DIR_AUTH_GROUP); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+<S_RMTS>shared_secret { 
+#ifdef __APPLE__
+       YYD; 
+       return(SHARED_SECRET); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+<S_RMTS>in_keychain { 
+#ifdef __APPLE__
+       YYD; 
+       return(IN_KEYCHAIN); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+<S_RMTS>certificate_verification { 
+#ifdef __APPLE__
+       YYD; 
+       return(CERTIFICATE_VERIFICATION); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+<S_RMTS>peers_certfile { YYD; return(PEERS_CERTFILE); }
+<S_RMTS>dnssec         { YYD; return(DNSSEC); }
+<S_RMTS>verify_cert    { YYD; return(VERIFY_CERT); }
+<S_RMTS>send_cert      { YYD; return(SEND_CERT); }
+<S_RMTS>send_cr                { YYD; return(SEND_CR); }
+<S_RMTS>dh_group       { YYD; return(DH_GROUP); }
+<S_RMTS>nonce_size     { YYD; return(NONCE_SIZE); }
+<S_RMTS>generate_policy        { YYD; return(GENERATE_POLICY); }
+<S_RMTS>support_mip6   { YYD; yywarn("it is obsoleted.  use \"support_proxy\"."); return(SUPPORT_PROXY); }
+<S_RMTS>support_proxy  { YYD; return(SUPPORT_PROXY); }
+<S_RMTS>initial_contact        { YYD; return(INITIAL_CONTACT); }
+<S_RMTS>nat_traversal  { YYD; return(NAT_TRAVERSAL); }
+<S_RMTS>force          { YYD; yylval.num = NATT_FORCE; return(NAT_TRAVERSAL_LEVEL); }
+<S_RMTS>nat_traversal_multi_user {
+#ifdef __APPLE__
+       YYD; 
+       return(NAT_TRAVERSAL_MULTI_USER);
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif 
+}
+<S_RMTS>proposal_check { YYD; return(PROPOSAL_CHECK); }
+<S_RMTS>obey           { YYD; yylval.num = PROP_CHECK_OBEY; return(PROPOSAL_CHECK_LEVEL); }
+<S_RMTS>strict         { YYD; yylval.num = PROP_CHECK_STRICT; return(PROPOSAL_CHECK_LEVEL); }
+<S_RMTS>exact          { YYD; yylval.num = PROP_CHECK_EXACT; return(PROPOSAL_CHECK_LEVEL); }
+<S_RMTS>claim          { YYD; yylval.num = PROP_CHECK_CLAIM; return(PROPOSAL_CHECK_LEVEL); }
+<S_RMTS>keepalive      { YYD; return(KEEPALIVE); }
+<S_RMTS>passive                { YYD; return(PASSIVE); }
+<S_RMTS>lifetime       { YYD; return(LIFETIME); }
+<S_RMTS>time           { YYD; return(LIFETYPE_TIME); }
+<S_RMTS>byte           { YYD; return(LIFETYPE_BYTE); }
+<S_RMTS>dpd                    { YYD; return(DPD); }
+<S_RMTS>dpd_delay      { YYD; return(DPD_DELAY); }
+<S_RMTS>dpd_retry      { YYD; return(DPD_RETRY); }
+<S_RMTS>dpd_maxfail    { YYD; return(DPD_MAXFAIL); }
+<S_RMTS>ike_frag       { YYD; return(IKE_FRAG); }
+<S_RMTS>esp_frag       { YYD; return(ESP_FRAG); }
+<S_RMTS>script         { YYD; return(SCRIPT); }
+<S_RMTS>phase1_up      { YYD; return(PHASE1_UP); }
+<S_RMTS>phase1_down    { YYD; return(PHASE1_DOWN); }
+<S_RMTS>mode_cfg       { YYD; return(MODE_CFG); }
+       /* remote proposal */
+<S_RMTS>proposal       { BEGIN S_RMTP; YYDB; return(PROPOSAL); }
+<S_RMTP>{bcl}          { return(BOC); }
+<S_RMTP>{ecl}          { BEGIN S_RMTS; return(EOC); }
+<S_RMTP>lifetime       { YYD; return(LIFETIME); }
+<S_RMTP>time           { YYD; return(LIFETYPE_TIME); }
+<S_RMTP>byte           { YYD; return(LIFETYPE_BYTE); }
+<S_RMTP>encryption_algorithm { YYD; yylval.num = algclass_isakmp_enc; return(ALGORITHM_CLASS); }
+<S_RMTP>authentication_method { YYD; yylval.num = algclass_isakmp_ameth; return(ALGORITHM_CLASS); }
+<S_RMTP>hash_algorithm { YYD; yylval.num = algclass_isakmp_hash; return(ALGORITHM_CLASS); }
+<S_RMTP>dh_group       { YYD; return(DH_GROUP); }
+<S_RMTP>gss_id         { YYD; return(GSS_ID); }
+<S_RMTP>gssapi_id      { YYD; return(GSS_ID); } /* for back compatibility */
+
+       /* GSS ID encoding type (global) */
+<S_INI>gss_id_enc      { BEGIN S_GSSENC; YYDB; return(GSS_ID_ENC); }
+<S_GSSENC>latin1       { YYD; yylval.num = LC_GSSENC_LATIN1;
+                               return(GSS_ID_ENCTYPE); }
+<S_GSSENC>utf-16le     { YYD; yylval.num = LC_GSSENC_UTF16LE;
+                               return(GSS_ID_ENCTYPE); }
+<S_GSSENC>{semi}       { BEGIN S_INI; YYDB; return(EOS); }
+
+       /* parameter */
+on             { YYD; yylval.num = TRUE; return(SWITCH); }
+off            { YYD; yylval.num = FALSE; return(SWITCH); }
+
+       /* prefix */
+{slash}({digit}{1,3}) {
+                       YYD;
+                       yytext++;
+                       yylval.num = atoi(yytext);
+                       return(PREFIX);
+               }
+
+       /* port number */
+{blcl}{decstring}{elcl}        {
+                       char *p = yytext;
+                       YYD;
+                       while (*++p != ']') ;
+                       *p = 0;
+                       yytext++;
+                       yylval.num = atoi(yytext);
+                       return(PORT);
+               }
+
+       /* upper protocol */
+esp            { YYD; yylval.num = IPPROTO_ESP; return(UL_PROTO); }
+ah             { YYD; yylval.num = IPPROTO_AH; return(UL_PROTO); }
+ipcomp         { YYD; yylval.num = IPPROTO_IPCOMP; return(UL_PROTO); }
+icmp           { YYD; yylval.num = IPPROTO_ICMP; return(UL_PROTO); }
+icmp6          { YYD; yylval.num = IPPROTO_ICMPV6; return(UL_PROTO); }
+tcp            { YYD; yylval.num = IPPROTO_TCP; return(UL_PROTO); }
+udp            { YYD; yylval.num = IPPROTO_UDP; return(UL_PROTO); }
+
+       /* algorithm type */
+des_iv64       { YYD; yylval.num = algtype_des_iv64;   return(ALGORITHMTYPE); }
+des            { YYD; yylval.num = algtype_des;        return(ALGORITHMTYPE); }
+3des           { YYD; yylval.num = algtype_3des;       return(ALGORITHMTYPE); }
+rc5            { YYD; yylval.num = algtype_rc5;        return(ALGORITHMTYPE); }
+idea           { YYD; yylval.num = algtype_idea;       return(ALGORITHMTYPE); }
+cast128                { YYD; yylval.num = algtype_cast128;    return(ALGORITHMTYPE); }
+blowfish       { YYD; yylval.num = algtype_blowfish;   return(ALGORITHMTYPE); }
+3idea          { YYD; yylval.num = algtype_3idea;      return(ALGORITHMTYPE); }
+des_iv32       { YYD; yylval.num = algtype_des_iv32;   return(ALGORITHMTYPE); }
+rc4            { YYD; yylval.num = algtype_rc4;        return(ALGORITHMTYPE); }
+null_enc       { YYD; yylval.num = algtype_null_enc;   return(ALGORITHMTYPE); }
+null           { YYD; yylval.num = algtype_null_enc;   return(ALGORITHMTYPE); }
+aes            { YYD; yylval.num = algtype_aes;        return(ALGORITHMTYPE); }
+rijndael       { YYD; yylval.num = algtype_aes;        return(ALGORITHMTYPE); }
+twofish                { YYD; yylval.num = algtype_twofish;    return(ALGORITHMTYPE); }
+non_auth       { YYD; yylval.num = algtype_non_auth;   return(ALGORITHMTYPE); }
+hmac_md5       { YYD; yylval.num = algtype_hmac_md5;   return(ALGORITHMTYPE); }
+hmac_sha1      { YYD; yylval.num = algtype_hmac_sha1;  return(ALGORITHMTYPE); }
+hmac_sha2_256  { YYD; yylval.num = algtype_hmac_sha2_256;      return(ALGORITHMTYPE); }
+hmac_sha256    { YYD; yylval.num = algtype_hmac_sha2_256;      return(ALGORITHMTYPE); }
+hmac_sha2_384  { YYD; yylval.num = algtype_hmac_sha2_384;      return(ALGORITHMTYPE); }
+hmac_sha384    { YYD; yylval.num = algtype_hmac_sha2_384;      return(ALGORITHMTYPE); }
+hmac_sha2_512  { YYD; yylval.num = algtype_hmac_sha2_512;      return(ALGORITHMTYPE); }
+hmac_sha512    { YYD; yylval.num = algtype_hmac_sha2_512;      return(ALGORITHMTYPE); }
+des_mac                { YYD; yylval.num = algtype_des_mac;    return(ALGORITHMTYPE); }
+kpdk           { YYD; yylval.num = algtype_kpdk;       return(ALGORITHMTYPE); }
+md5            { YYD; yylval.num = algtype_md5;        return(ALGORITHMTYPE); }
+sha1           { YYD; yylval.num = algtype_sha1;       return(ALGORITHMTYPE); }
+tiger          { YYD; yylval.num = algtype_tiger;      return(ALGORITHMTYPE); }
+sha2_256       { YYD; yylval.num = algtype_sha2_256;   return(ALGORITHMTYPE); }
+sha256         { YYD; yylval.num = algtype_sha2_256;   return(ALGORITHMTYPE); }
+sha2_384       { YYD; yylval.num = algtype_sha2_384;   return(ALGORITHMTYPE); }
+sha384         { YYD; yylval.num = algtype_sha2_384;   return(ALGORITHMTYPE); }
+sha2_512       { YYD; yylval.num = algtype_sha2_512;   return(ALGORITHMTYPE); }
+sha512         { YYD; yylval.num = algtype_sha2_512;   return(ALGORITHMTYPE); }
+oui            { YYD; yylval.num = algtype_oui;        return(ALGORITHMTYPE); }
+deflate                { YYD; yylval.num = algtype_deflate;    return(ALGORITHMTYPE); }
+lzs            { YYD; yylval.num = algtype_lzs;        return(ALGORITHMTYPE); }
+modp768                { YYD; yylval.num = algtype_modp768;    return(ALGORITHMTYPE); }
+modp1024       { YYD; yylval.num = algtype_modp1024;   return(ALGORITHMTYPE); }
+modp1536       { YYD; yylval.num = algtype_modp1536;   return(ALGORITHMTYPE); }
+ec2n155                { YYD; yylval.num = algtype_ec2n155;    return(ALGORITHMTYPE); }
+ec2n185                { YYD; yylval.num = algtype_ec2n185;    return(ALGORITHMTYPE); }
+modp2048       { YYD; yylval.num = algtype_modp2048;   return(ALGORITHMTYPE); }
+modp3072       { YYD; yylval.num = algtype_modp3072;   return(ALGORITHMTYPE); }
+modp4096       { YYD; yylval.num = algtype_modp4096;   return(ALGORITHMTYPE); }
+modp6144       { YYD; yylval.num = algtype_modp6144;   return(ALGORITHMTYPE); }
+modp8192       { YYD; yylval.num = algtype_modp8192;   return(ALGORITHMTYPE); }
+pre_shared_key { YYD; yylval.num = algtype_psk;        return(ALGORITHMTYPE); }
+rsasig         { YYD; yylval.num = algtype_rsasig;     return(ALGORITHMTYPE); }
+dsssig         { YYD; yylval.num = algtype_dsssig;     return(ALGORITHMTYPE); }
+rsaenc         { YYD; yylval.num = algtype_rsaenc;     return(ALGORITHMTYPE); }
+rsarev         { YYD; yylval.num = algtype_rsarev;     return(ALGORITHMTYPE); }
+gssapi_krb     { YYD; yylval.num = algtype_gssapikrb;  return(ALGORITHMTYPE); }
+hybrid_rsa_server {
+#ifdef ENABLE_HYBRID
+       YYD; yylval.num = algtype_hybrid_rsa_s; return(ALGORITHMTYPE);
+#else
+       yyerror("racoon not configured with --enable-hybrid");
+#endif
+}
+hybrid_dss_server {
+#ifdef ENABLE_HYBRID
+       YYD; yylval.num = algtype_hybrid_dss_s; return(ALGORITHMTYPE);
+#else
+       yyerror("racoon not configured with --enable-hybrid");
+#endif
+}
+hybrid_rsa_client {
+#ifdef ENABLE_HYBRID
+       YYD; yylval.num = algtype_hybrid_rsa_c; return(ALGORITHMTYPE);
+#else
+       yyerror("racoon not configured with --enable-hybrid");
+#endif
+}
+hybrid_dss_client {
+#ifdef ENABLE_HYBRID
+       YYD; yylval.num = algtype_hybrid_dss_c; return(ALGORITHMTYPE);
+#else
+       yyerror("racoon not configured with --enable-hybrid");
+#endif
+}
+
+
+       /* identifier type */
+vendor_id      { YYD; yywarn("it is obsoleted."); return(VENDORID); }
+user_fqdn      { YYD; yylval.num = IDTYPE_USERFQDN; return(IDENTIFIERTYPE); }
+fqdn           { YYD; yylval.num = IDTYPE_FQDN; return(IDENTIFIERTYPE); }
+keyid          { YYD; yylval.num = IDTYPE_KEYID; return(IDENTIFIERTYPE); }
+keyid_use      { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = IDTYPE_KEYIDUSE; 
+       return(IDENTIFIERTYPE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+address                { YYD; yylval.num = IDTYPE_ADDRESS; return(IDENTIFIERTYPE); }
+subnet         { YYD; yylval.num = IDTYPE_SUBNET; return(IDENTIFIERTYPE); }
+asn1dn         { YYD; yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); }
+certname       { YYD; yywarn("certname will be obsoleted in near future."); yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); }
+
+       /* shared secret type */
+use            { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = SECRETTYPE_USE; 
+       return(SECRETTYPE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+key            { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = SECRETTYPE_KEY; 
+       return(SECRETTYPE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+keychain       { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = SECRETTYPE_KEYCHAIN; 
+       return(SECRETTYPE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+keychain_by_id { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = SECRETTYPE_KEYCHAIN_BY_ID; 
+       return(SECRETTYPE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+
+       /* certificate verification */
+openssl                        { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = VERIFICATION_MODULE_OPENSSL; 
+       return(VERIFICATION_MODULE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+sec_framework  { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = VERIFICATION_MODULE_SEC_FRAMEWORK; 
+       return(VERIFICATION_MODULE); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+use_open_dir   { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = VERIFICATION_OPTION_OPEN_DIR; 
+       return(VERIFICATION_OPTION); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+use_peers_identifier   { 
+#ifdef __APPLE__
+       YYD; 
+       yylval.num = VERIFICATION_OPTION_PEERS_IDENTIFIER; 
+       return(VERIFICATION_OPTION); 
+#else
+       yyerror("Apple specific features not compiled in.");
+#endif
+}
+
+       /* units */
+B|byte|bytes           { YYD; return(UNITTYPE_BYTE); }
+KB                     { YYD; return(UNITTYPE_KBYTES); }
+MB                     { YYD; return(UNITTYPE_MBYTES); }
+TB                     { YYD; return(UNITTYPE_TBYTES); }
+sec|secs|second|seconds        { YYD; return(UNITTYPE_SEC); }
+min|mins|minute|minutes        { YYD; return(UNITTYPE_MIN); }
+hour|hours             { YYD; return(UNITTYPE_HOUR); }
+
+       /* boolean */
+yes            { YYD; yylval.num = TRUE; return(BOOLEAN); }
+no             { YYD; yylval.num = FALSE; return(BOOLEAN); }
+
+{decstring}    {
+                       char *bp;
+
+                       YYD;
+                       yylval.num = strtol(yytext, &bp, 10);
+                       return(NUMBER);
+               }
+
+{hexstring}    {
+                       char *p;
+
+                       YYD; 
+                       yylval.val = vmalloc(yyleng + (yyleng & 1) + 1);
+                       if (yylval.val == NULL) {
+                               yyerror("vmalloc failed");
+                               return -1;
+                       }
+
+                       p = yylval.val->v;
+                       *p++ = '0';
+                       *p++ = 'x';
+
+                       /* fixed string if length is odd. */
+                       if (yyleng & 1)
+                               *p++ = '0';
+                       memcpy(p, &yytext[2], yyleng - 1);
+
+                       return(HEXSTRING);
+               }
+
+{quotedstring} {
+                       char *p = yytext;
+
+                       YYD;
+                       while (*++p != '"') ;
+                       *p = '\0';
+
+                       yylval.val = vmalloc(yyleng - 1);
+                       if (yylval.val == NULL) {
+                               yyerror("vmalloc failed");
+                               return -1;
+                       }
+                       memcpy(yylval.val->v, &yytext[1], yylval.val->l);
+
+                       return(QUOTEDSTRING);
+               }
+
+{addrstring}   {
+                       YYD;
+
+                       yylval.val = vmalloc(yyleng + 1);
+                       if (yylval.val == NULL) {
+                               yyerror("vmalloc failed");
+                               return -1;
+                       }
+                       memcpy(yylval.val->v, yytext, yylval.val->l);
+
+                       return(ADDRSTRING);
+               }
+
+<<EOF>>                {
+                       yy_delete_buffer(YY_CURRENT_BUFFER);
+                       yycf_free_buffer(incstackp);
+                       incstackp--;
+    nextfile:
+                       if (incstack[incstackp].matchon <
+                           incstack[incstackp].matches.gl_pathc) {
+                               char* filepath = incstack[incstackp].matches.gl_pathv[incstack[incstackp].matchon];
+                               incstack[incstackp].matchon++;
+                               incstackp++;
+                               if (yycf_set_buffer(filepath) != 0) {
+                                       incstackp--;
+                                       goto nextfile;
+                               }
+                               yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+                               BEGIN(S_INI);
+                       } else {
+                               globfree(&incstack[incstackp].matches);
+                               if (incstackp == 0)
+                                       yyterminate();
+                               else
+                                       yy_switch_to_buffer(incstack[incstackp].prevstate);
+                       }
+               }
+
+       /* ... */
+{ws}           { ; }
+{nl}           { incstack[incstackp].lineno++; }
+{comment}      { YYD; }
+{semi}         { return(EOS); }
+.              { yymore(); }
+
+%%
+
+void
+yyerror(char *s, ...)
+{
+       char fmt[512];
+
+       va_list ap;
+#ifdef HAVE_STDARG_H
+       va_start(ap, s);
+#else
+       va_start(ap);
+#endif
+       snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n",
+               incstack[incstackp].path, incstack[incstackp].lineno,
+               yytext, s);
+       plogv(LLV_ERROR, LOCATION, NULL, fmt, ap);
+       va_end(ap);
+
+       yyerrorcount++;
+}
+
+void
+yywarn(char *s, ...)
+{
+       char fmt[512];
+
+       va_list ap;
+#ifdef HAVE_STDARG_H
+       va_start(ap, s);
+#else
+       va_start(ap);
+#endif
+       snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n",
+               incstack[incstackp].path, incstack[incstackp].lineno,
+               yytext, s);
+       plogv(LLV_WARNING, LOCATION, NULL, fmt, ap);
+       va_end(ap);
+}
+
+int
+yycf_switch_buffer(path)
+       char *path;
+{
+       char *filepath = NULL;
+
+       /* got the include file name */
+       if (incstackp >= MAX_INCLUDE_DEPTH) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Includes nested too deeply");
+               return -1;
+       }
+
+       if (glob(path, GLOB_TILDE, NULL, &incstack[incstackp].matches) != 0 ||
+           incstack[incstackp].matches.gl_pathc == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "glob found no matches for path");
+               return -1;
+       }
+       incstack[incstackp].matchon = 0;
+       incstack[incstackp].prevstate = YY_CURRENT_BUFFER;
+
+    nextmatch:
+       if (incstack[incstackp].matchon >= incstack[incstackp].matches.gl_pathc)
+               return -1;
+       filepath =
+           incstack[incstackp].matches.gl_pathv[incstack[incstackp].matchon];
+       incstack[incstackp].matchon++;
+       incstackp++;
+
+       if (yycf_set_buffer(filepath) != 0) {
+             incstackp--;
+             goto nextmatch;
+       }
+
+       yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+
+       BEGIN(S_INI);
+
+       return 0;
+}
+
+int
+yycf_set_buffer(path)
+       char *path;
+{
+       yyin = fopen(path, "r");
+       if (yyin == NULL) {
+               fprintf(stderr, "failed to open file %s (%s)\n",
+                       path, strerror(errno));
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to open file %s (%s)\n",
+                       path, strerror(errno));
+               return -1;
+       }
+
+       /* initialize */
+       incstack[incstackp].fp = yyin;
+       incstack[incstackp].path = strdup(path);
+       incstack[incstackp].lineno = 1;
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "reading config file %s\n", path);
+
+       return 0;
+}
+
+void
+yycf_init_buffer()
+{
+       int i;
+
+       for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+               memset(&incstack[i], 0, sizeof(incstack[i]));
+       incstackp = 0;
+}
+
+void
+yycf_free_buffer(index)
+       int index;
+{
+       fclose(incstack[index].fp);
+       racoon_free(incstack[index].path);
+       incstack[index].path = NULL;
+}
+
+void
+yycf_clean_buffer()
+{
+       int i;
+
+       for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+               if (incstack[i].path != NULL)
+                       yycf_free_buffer(i);
+}
+
diff --git a/ipsec-tools/racoon/cftoken_proto.h b/ipsec-tools/racoon/cftoken_proto.h
new file mode 100644 (file)
index 0000000..76156a6
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Id: cftoken_proto.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CFTOKEN_PROTO_H
+#define _CFTOKEN_PROTO_H
+
+extern int yyerrorcount;
+
+extern int yylex __P((void));
+extern void yyerror __P((char *, ...));
+extern void yywarn __P((char *, ...));
+
+extern int yycf_switch_buffer __P((char *));
+extern int yycf_set_buffer __P((char *));
+extern void yycf_init_buffer __P((void));
+extern void yycf_clean_buffer __P((void));
+extern void yycf_free_buffer __P((int));
+
+#endif /* _CFTOKEN_PROTO_H */
diff --git a/ipsec-tools/racoon/crypto_cssm.c b/ipsec-tools/racoon/crypto_cssm.c
new file mode 100644 (file)
index 0000000..9b0e349
--- /dev/null
@@ -0,0 +1,536 @@
+
+/*
+ * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Racoon module for verifying and signing certificates through Security
+ * Framework and CSSM
+ */
+
+#include <Security/SecBase.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecPolicy.h>
+#include <Security/SecIdentity.h>
+#include <Security/SecIdentityPriv.h>
+#include <Security/SecIdentitySearch.h>
+#include <Security/SecKeychain.h>
+#include <Security/SecKeychainItem.h>
+#include <Security/SecKeychainItemPriv.h>
+#include <Security/SecKey.h>
+#include <Security/SecKeyPriv.h>
+#include <Security/SecTrust.h>
+#include <Security/oidsalg.h>
+#include <Security/cssmapi.h>
+#include <Security/SecPolicySearch.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+#include "plog.h"
+#include "debug.h"
+#include "misc.h"
+
+#include "crypto_cssm.h"
+
+
+
+static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef);
+static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef);
+static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef);
+static const char *GetSecurityErrorString(OSStatus err);
+
+
+/*
+ * Verify cert using security framework
+ */
+int crypto_cssm_check_x509cert(vchar_t *cert)
+{
+       OSStatus                        status;
+       SecCertificateRef       certRef = 0;
+       CSSM_DATA                       certData;
+       CSSM_OID                        ourPolicyOID = CSSMOID_APPLE_TP_IP_SEC; 
+       SecPolicyRef            policyRef = 0;
+
+       // create cert ref
+       certData.Length = cert->l;
+       certData.Data = (uint8 *)cert->v;
+       status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
+               &certRef);
+       if (status != noErr)
+               goto end;
+       
+       // get our policy object
+       status = FindPolicy(&ourPolicyOID, &policyRef);
+       if (status != noErr)
+               goto end;
+               
+       // setup policy options ???
+       // no options used at present - verification of subjectAltName fields, etc.
+       // are done elsewhere in racoon in oakley_check_certid()
+       
+       // evaluate cert
+       status = EvaluateCert(certRef, policyRef);
+       
+       
+end:
+
+       if (certRef)
+               CFRelease(certRef);
+       if (policyRef)
+               CFRelease(policyRef);
+       
+       if (status != noErr && status != -1) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }               
+       return status;
+
+}
+
+/*
+ * Encrypt a hash via CSSM using the private key in the keychain
+ * from an identity.
+ */
+vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash)
+{
+
+       OSStatus                                                status;
+       SecCertificateRef                               certificateRef = NULL;
+       SecIdentityRef                                  identityRef = NULL;
+       SecIdentitySearchRef                    idSearchRef = NULL;
+       SecKeychainRef                                  keychainRef = NULL;
+       SecKeyRef                                               privateKeyRef = NULL;
+       const CSSM_KEY                                  *cssmKey = NULL;
+       CSSM_CSP_HANDLE                                 cspHandle = nil;
+       CSSM_CC_HANDLE                                  cssmContextHandle = nil;
+       const CSSM_ACCESS_CREDENTIALS   *credentials = NULL;
+       //CSSM_SIZE                                             bytesEncrypted = 0;     //%%%%HWR fix this - need new headers on Leopard
+       uint32                                                  bytesEncrypted = 0;
+       CSSM_DATA                                               clearData;
+       CSSM_DATA                                               cipherData;
+       CSSM_DATA                                               remData;
+       CSSM_CONTEXT_ATTRIBUTE                  newAttr;
+       vchar_t                                                 *sig = NULL;
+
+       remData.Length = 0;
+       remData.Data = 0;
+
+       if (persistentCertRef) {                        
+               // get cert from keychain
+               status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
+               if (status != noErr)
+                       goto end;
+       
+               // get keychain ref where cert is contained
+               status = SecKeychainItemCopyKeychain((SecKeychainItemRef)certificateRef, &keychainRef);
+               if (status != noErr)
+                       goto end;
+       
+               // get identity from the certificate
+               status = SecIdentityCreateWithCertificate(keychainRef, certificateRef, &identityRef);
+               if (status != noErr)
+                       goto end;       
+                       
+       } else {
+               // copy system keychain
+               status = CopySystemKeychain(&keychainRef);
+               if (status != noErr)
+                       goto end;
+
+               // serach for first identity in system keychain
+               status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
+               if (status != noErr)
+                       goto end;
+               
+               status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
+               if (status != noErr)
+                       goto end;
+
+               // get certificate from identity
+               status = SecIdentityCopyCertificate(identityRef, &certificateRef);
+               if (status != noErr)
+                       goto end;
+       }
+       
+                                       
+       // get private key from identity
+       status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef);
+       if (status != noErr)
+               goto end;
+               
+       // get CSSM_KEY pointer from key ref
+       status = SecKeyGetCSSMKey(privateKeyRef, &cssmKey);
+       if (status != noErr)
+               goto end;
+               
+       // get CSSM CSP handle
+       status = SecKeychainGetCSPHandle(keychainRef, &cspHandle);
+       if (status != noErr)
+               goto end;
+               
+       // create CSSM credentials to unlock private key for encryption - no UI to be used
+       status = SecKeyGetCredentials(privateKeyRef, CSSM_ACL_AUTHORIZATION_ENCRYPT,
+                               kSecCredentialTypeNoUI, &credentials);
+       if (status != noErr)
+               goto end;       
+
+       // create asymmetric context for encryption
+       status = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, credentials, cssmKey, 
+                       CSSM_PADDING_PKCS1, &cssmContextHandle);
+       if (status != noErr)
+               goto end;
+               
+       // add mode attribute to use private key for encryption
+       newAttr.AttributeType     = CSSM_ATTRIBUTE_MODE;
+       newAttr.AttributeLength   = sizeof(uint32);
+       newAttr.Attribute.Data    = (CSSM_DATA_PTR)CSSM_ALGMODE_PRIVATE_KEY;
+       status = CSSM_UpdateContextAttributes(cssmContextHandle, 1, &newAttr);
+       if(status != noErr)
+               goto end;
+                       
+       // and finally - encrypt data
+       clearData.Length = hash->l;
+       clearData.Data = (uint8 *)hash->v;
+       cipherData.Length = 0;
+       cipherData.Data = NULL;
+       status = CSSM_EncryptData(cssmContextHandle, &clearData, 1, &cipherData, 1, &bytesEncrypted, 
+                                               &remData);
+       if (status != noErr)
+               goto end;
+       
+       if (remData.Length != 0) {      // something didn't go right - should be zero
+               status = -1;
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "unencrypted data remaining after encrypting hash.\n");
+               goto end;
+       }
+
+       // alloc buffer for result
+       sig = vmalloc(0);
+       if (sig == NULL)
+               goto end;
+               
+       sig->l = cipherData.Length;
+       sig->v = (caddr_t)cipherData.Data;
+               
+end:
+       if (certificateRef)
+               CFRelease(certificateRef);
+       if (keychainRef)
+               CFRelease(keychainRef);
+       if (identityRef)
+               CFRelease(identityRef);
+       if (privateKeyRef)
+               CFRelease(privateKeyRef);
+       if (idSearchRef)
+               CFRelease(idSearchRef);
+       if (cssmContextHandle)
+               CSSM_DeleteContext(cssmContextHandle);
+       if (status != noErr) {
+               if (sig) {
+                       vfree(sig);
+                       sig = NULL;
+               }
+       }
+
+       if (status != noErr && status != -1) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }                       
+       return sig;
+       
+}
+
+
+/*
+ * Retrieve a cert from the keychain
+ */
+vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef)
+{
+
+       OSStatus                                status;
+       CSSM_DATA                               cssmData;
+       vchar_t                                 *cert = NULL;
+       SecIdentityRef                  identityRef = NULL;
+       SecIdentitySearchRef    idSearchRef = NULL;
+       SecKeychainRef                  keychainRef = NULL;
+       SecCertificateRef               certificateRef = NULL;
+
+
+       // get cert ref
+       if (persistentCertRef) {
+               status = SecKeychainItemCopyFromPersistentReference(persistentCertRef, (SecKeychainItemRef*)&certificateRef);
+               if (status != noErr)
+                       goto end;
+       } else {
+               // copy system keychain
+               status = CopySystemKeychain(&keychainRef);
+               if (status != noErr)
+                       goto end;
+
+               // find first identity in system keychain
+               status = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_SIGN, &idSearchRef);
+               if (status != noErr)
+                       goto end;
+               
+               status = SecIdentitySearchCopyNext(idSearchRef, &identityRef);
+               if (status != noErr)
+                       goto end;
+
+               // get certificate from identity
+               status = SecIdentityCopyCertificate(identityRef, &certificateRef);
+               if (status != noErr)
+                       goto end;
+               
+       }
+               
+       // get certificate data
+       cssmData.Length = 0;
+       cssmData.Data = NULL;
+       status = SecCertificateGetData(certificateRef, &cssmData);
+       if (status != noErr)
+               goto end;
+               
+       if (cssmData.Length == 0)
+               goto end;
+       
+       cert = vmalloc(cssmData.Length);
+       if (cert == NULL)
+               goto end;       
+       
+       // cssmData struct just points to the data
+       // data must be copied to be returned
+       memcpy(cert->v, cssmData.Data, cssmData.Length);        
+               
+end:
+       if (certificateRef)
+               CFRelease(certificateRef);
+       if (identityRef)
+               CFRelease(identityRef);
+       if (idSearchRef)
+               CFRelease(idSearchRef);
+       if (keychainRef)
+               CFRelease(keychainRef);
+
+       if (status != noErr && status != -1) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }                       
+       return cert;
+
+}
+
+
+/*
+ * Find a policy ref by OID
+ */
+static OSStatus FindPolicy(const CSSM_OID *policyOID, SecPolicyRef *policyRef)
+{
+       
+       OSStatus                        status;
+       SecPolicySearchRef      searchRef = nil;
+       
+       status = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &searchRef);
+       if (status != noErr)
+               goto end;
+               
+       status = SecPolicySearchCopyNext(searchRef, policyRef);
+       
+end:
+       if (searchRef)
+               CFRelease(searchRef);
+
+       if (status != noErr) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }                       
+       return status;
+}
+               
+
+/*
+ * Evaluate the trust of a cert using the policy provided
+ */
+static OSStatus EvaluateCert(SecCertificateRef cert, CFTypeRef policyRef)
+{
+       OSStatus                                        status;
+       SecTrustRef                                     trustRef = 0;
+       SecTrustResultType                      evalResult;
+       
+       SecCertificateRef                       evalCertArray[1] = { cert };
+       
+       CFArrayRef                      cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, 1,
+                                                                               &kCFTypeArrayCallBacks);
+                                                                               
+       if (!cfCertRef) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "unable to create CFArray.\n");         
+               return -1;
+       }
+               
+       status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef);
+       if (status != noErr)
+               goto end;
+               
+       status = SecTrustEvaluate(trustRef, &evalResult);
+       if (status != noErr)
+               goto end;
+       
+       if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error evaluating certificate.\n");
+               status = -1;
+       }
+                       
+       
+end:
+       if (cfCertRef)
+               CFRelease(cfCertRef);
+       if (trustRef)
+               CFRelease(trustRef);
+
+       if (status != noErr && status != -1) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }                       
+       return status;
+}
+
+
+/*
+ * Copy the system keychain
+ */
+static OSStatus CopySystemKeychain(SecKeychainRef *keychainRef)
+{
+
+       OSStatus status;
+
+       status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+       if (status != noErr)
+               goto end;
+
+       status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, keychainRef);
+       
+end:
+
+       if (status != noErr) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "error %d %s.\n", status, GetSecurityErrorString(status));
+               status = -1;
+       }                       
+       return status;
+
+}
+
+
+/* 
+ * Return string representation of Security-related OSStatus.
+ */
+const char *
+GetSecurityErrorString(OSStatus err)
+{
+    switch(err) {
+               case noErr:
+                       return "noErr";
+               case memFullErr:
+                       return "memFullErr";
+               case paramErr:
+                       return "paramErr";
+               case unimpErr:
+                       return "unimpErr";
+       
+               /* SecBase.h: */
+               case errSecNotAvailable:
+                       return "errSecNotAvailable";
+               case errSecReadOnly:
+                       return "errSecReadOnly";
+               case errSecAuthFailed:
+                       return "errSecAuthFailed";
+               case errSecNoSuchKeychain:
+                       return "errSecNoSuchKeychain";
+               case errSecInvalidKeychain:
+                       return "errSecInvalidKeychain";
+               case errSecDuplicateKeychain:
+                       return "errSecDuplicateKeychain";
+               case errSecDuplicateCallback:
+                       return "errSecDuplicateCallback";
+               case errSecInvalidCallback:
+                       return "errSecInvalidCallback";
+               case errSecDuplicateItem:
+                       return "errSecDuplicateItem";
+               case errSecItemNotFound:
+                       return "errSecItemNotFound";
+               case errSecBufferTooSmall:
+                       return "errSecBufferTooSmall";
+               case errSecDataTooLarge:
+                       return "errSecDataTooLarge";
+               case errSecNoSuchAttr:
+                       return "errSecNoSuchAttr";
+               case errSecInvalidItemRef:
+                       return "errSecInvalidItemRef";
+               case errSecInvalidSearchRef:
+                       return "errSecInvalidSearchRef";
+               case errSecNoSuchClass:
+                       return "errSecNoSuchClass";
+               case errSecNoDefaultKeychain:
+                       return "errSecNoDefaultKeychain";
+               case errSecInteractionNotAllowed:
+                       return "errSecInteractionNotAllowed";
+               case errSecReadOnlyAttr:
+                       return "errSecReadOnlyAttr";
+               case errSecWrongSecVersion:
+                       return "errSecWrongSecVersion";
+               case errSecKeySizeNotAllowed:
+                       return "errSecKeySizeNotAllowed";
+               case errSecNoStorageModule:
+                       return "errSecNoStorageModule";
+               case errSecNoCertificateModule:
+                       return "errSecNoCertificateModule";
+               case errSecNoPolicyModule:
+                       return "errSecNoPolicyModule";
+               case errSecInteractionRequired:
+                       return "errSecInteractionRequired";
+               case errSecDataNotAvailable:
+                       return "errSecDataNotAvailable";
+               case errSecDataNotModifiable:
+                       return "errSecDataNotModifiable";
+               case errSecCreateChainFailed:
+                       return "errSecCreateChainFailed";
+               case errSecACLNotSimple:
+                       return "errSecACLNotSimple";
+               case errSecPolicyNotFound:
+                       return "errSecPolicyNotFound";
+               case errSecInvalidTrustSetting:
+                       return "errSecInvalidTrustSetting";
+               case errSecNoAccessForItem:
+                       return "errSecNoAccessForItem";
+               case errSecInvalidOwnerEdit:
+                       return "errSecInvalidOwnerEdit";
+               default:
+                       return "<unknown>";
+    }
+}
+
diff --git a/ipsec-tools/racoon/crypto_cssm.h b/ipsec-tools/racoon/crypto_cssm.h
new file mode 100644 (file)
index 0000000..6152770
--- /dev/null
@@ -0,0 +1,41 @@
+
+/*
+ * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __CRYPTO_CSSM_H__
+#define __CRYPTO_CSSM_H__
+
+/*
+ * Racoon module for verifying and signing certificates through Security
+ * Framework and CSSM
+ */
+
+#include "vmbuf.h"
+
+
+extern int crypto_cssm_check_x509cert(vchar_t *cert);
+extern vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash);
+extern vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef);
+
+
+#endif /* __CRYPTO_CSSM_H__ */
+
diff --git a/ipsec-tools/racoon/crypto_openssl.c b/ipsec-tools/racoon/crypto_openssl.c
new file mode 100644 (file)
index 0000000..39e96b7
--- /dev/null
@@ -0,0 +1,2908 @@
+/* $Id: crypto_openssl.c,v 1.40.4.5 2005/07/12 11:50:15 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef __APPLE__
+#define COMMON_DIGEST_FOR_OPENSSL 1
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+/* get openssl/ssleay version number */
+#include <openssl/opensslv.h>
+
+#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090602fL)
+#error OpenSSL version 0.9.6 or later required.
+#endif
+
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#ifdef __APPLE__
+#include <CommonCrypto/CommonDigest.h>
+#include <CommonCrypto/CommonHMAC.h>
+#else
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#endif
+#include <openssl/des.h>
+#include <openssl/crypto.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#include <openssl/blowfish.h>
+#include <openssl/cast.h>
+#include <openssl/err.h>
+#ifdef HAVE_OPENSSL_RC5_H
+#include <openssl/rc5.h>
+#endif
+#ifdef HAVE_OPENSSL_IDEA_H
+#include <openssl/idea.h>
+#endif
+#if defined(HAVE_OPENSSL_AES_H)
+#include <openssl/aes.h>
+#elif defined(HAVE_OPENSSL_RIJNDAEL_H)
+#include <openssl/rijndael.h>
+#else
+#include "crypto/rijndael/rijndael-api-fst.h"
+#endif
+#ifdef WITH_SHA2
+#ifndef __APPLE__
+#ifdef HAVE_OPENSSL_SHA2_H
+#include <openssl/sha2.h>
+#endif
+#endif
+#endif
+
+/* 0.9.7 stuff? */
+#if OPENSSL_VERSION_NUMBER < 0x0090700fL
+typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
+#else
+#define USE_NEW_DES_API
+#endif
+
+#define OpenSSL_BUG()  do { plog(LLV_ERROR, LOCATION, NULL, "OpenSSL function failed\n"); } while(0)
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "crypto_openssl.h"
+#include "debug.h"
+#include "gcmalloc.h"
+
+
+/*
+ * I hate to cast every parameter to des_xx into void *, but it is
+ * necessary for SSLeay/OpenSSL portability.  It sucks.
+ */
+
+static int cb_check_cert_local __P((int, X509_STORE_CTX *));
+static int cb_check_cert_remote __P((int, X509_STORE_CTX *));
+static X509 *mem2x509 __P((vchar_t *));
+
+#ifdef __APPLE__
+static caddr_t eay_hmac_init __P((vchar_t *, CCHmacAlgorithm));
+#else
+static caddr_t eay_hmac_init __P((vchar_t *, const EVP_MD *));
+#endif
+
+/* X509 Certificate */
+/*
+ * convert the string of the subject name into DER
+ * e.g. str = "C=JP, ST=Kanagawa";
+ */
+vchar_t *
+eay_str2asn1dn(str, len)
+       const char *str;
+       int len;
+{
+       X509_NAME *name;
+       char *buf;
+       char *field, *value;
+       int i, j;
+       vchar_t *ret;
+       caddr_t p;
+
+       if (len == -1)
+               len = strlen(str);
+
+       buf = racoon_malloc(len + 1);
+       if (!buf) {
+               printf("failed to allocate buffer\n");
+               return NULL;
+       }
+       memcpy(buf, str, len);
+
+       name = X509_NAME_new();
+
+       field = &buf[0];
+       value = NULL;
+       for (i = 0; i < len; i++) {
+               if (!value && buf[i] == '=') {
+                       buf[i] = '\0';
+                       value = &buf[i + 1];
+                       continue;
+               } else if (buf[i] == ',' || buf[i] == '/') {
+                       buf[i] = '\0';
+
+                       plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n",
+                            field, value);
+
+                       if (!value) goto err;
+                       if (!X509_NAME_add_entry_by_txt(name, field,
+                                       (value[0] == '*' && value[1] == 0) ? 
+                                               V_ASN1_PRINTABLESTRING : MBSTRING_ASC,
+                                       (unsigned char *) value, -1, -1, 0)) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                    "Invalid DN field: %s=%s\n",
+                                    field, value);
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                    "%s\n", eay_strerror());
+                               goto err;
+                       }
+                       for (j = i + 1; j < len; j++) {
+                               if (buf[j] != ' ')
+                                       break;
+                       }
+                       field = &buf[j];
+                       value = NULL;
+                       continue;
+               }
+       }
+       buf[len] = '\0';
+
+       plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n",
+            field, value);
+
+       if (!value) goto err;
+       if (!X509_NAME_add_entry_by_txt(name, field,
+                       (value[0] == '*' && value[1] == 0) ? 
+                               V_ASN1_PRINTABLESTRING : MBSTRING_ASC,
+                       (unsigned char *) value, -1, -1, 0)) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                    "Invalid DN field: %s=%s\n",
+                    field, value);
+               plog(LLV_ERROR, LOCATION, NULL, 
+                    "%s\n", eay_strerror());
+               goto err;
+       }
+
+       i = i2d_X509_NAME(name, NULL);
+       if (!i)
+               goto err;
+       ret = vmalloc(i);
+       if (!ret)
+               goto err;
+       p = ret->v;
+       i = i2d_X509_NAME(name, (void *)&p);
+       if (!i)
+               goto err;
+
+       return ret;
+
+    err:
+       if (buf)
+               racoon_free(buf);
+       if (name)
+               X509_NAME_free(name);
+       return NULL;
+}
+
+/*
+ * convert the hex string of the subject name into DER
+ */
+vchar_t *
+eay_hex2asn1dn(const char *hex, int len)
+{
+       BIGNUM *bn = BN_new();
+       char *binbuf;
+       size_t binlen;
+       vchar_t *ret = NULL;
+       
+       if (len == -1)
+               len = strlen(hex);
+
+       if (BN_hex2bn(&bn, hex) != len) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                    "conversion of Hex-encoded ASN1 string to binary failed: %s\n",
+                    eay_strerror());
+               goto out;
+       }
+       
+       binlen = BN_num_bytes(bn);
+       ret = vmalloc(binlen);
+       if (!ret) {
+               printf("failed to allocate buffer\n");
+               return NULL;
+       }
+       binbuf = ret->v;
+
+       BN_bn2bin(bn, (unsigned char *) binbuf);
+
+out:
+       BN_free(bn);
+
+       return ret;
+}
+
+/*
+ * The following are derived from code in crypto/x509/x509_cmp.c
+ * in OpenSSL0.9.7c:
+ * X509_NAME_wildcmp() adds wildcard matching to the original
+ * X509_NAME_cmp(), nocase_cmp() and nocase_spacenorm_cmp() are as is.
+ */
+#include <ctype.h>
+/* Case insensitive string comparision */
+static int nocase_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
+{
+       int i;
+
+       if (a->length != b->length)
+               return (a->length - b->length);
+
+       for (i=0; i<a->length; i++)
+       {
+               int ca, cb;
+
+               ca = tolower(a->data[i]);
+               cb = tolower(b->data[i]);
+
+               if (ca != cb)
+                       return(ca-cb);
+       }
+       return 0;
+}
+
+/* Case insensitive string comparision with space normalization 
+ * Space normalization - ignore leading, trailing spaces, 
+ *       multiple spaces between characters are replaced by single space  
+ */
+static int nocase_spacenorm_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
+{
+       unsigned char *pa = NULL, *pb = NULL;
+       int la, lb;
+       
+       la = a->length;
+       lb = b->length;
+       pa = a->data;
+       pb = b->data;
+
+       /* skip leading spaces */
+       while (la > 0 && isspace(*pa))
+       {
+               la--;
+               pa++;
+       }
+       while (lb > 0 && isspace(*pb))
+       {
+               lb--;
+               pb++;
+       }
+
+       /* skip trailing spaces */
+       while (la > 0 && isspace(pa[la-1]))
+               la--;
+       while (lb > 0 && isspace(pb[lb-1]))
+               lb--;
+
+       /* compare strings with space normalization */
+       while (la > 0 && lb > 0)
+       {
+               int ca, cb;
+
+               /* compare character */
+               ca = tolower(*pa);
+               cb = tolower(*pb);
+               if (ca != cb)
+                       return (ca - cb);
+
+               pa++; pb++;
+               la--; lb--;
+
+               if (la <= 0 || lb <= 0)
+                       break;
+
+               /* is white space next character ? */
+               if (isspace(*pa) && isspace(*pb))
+               {
+                       /* skip remaining white spaces */
+                       while (la > 0 && isspace(*pa))
+                       {
+                               la--;
+                               pa++;
+                       }
+                       while (lb > 0 && isspace(*pb))
+                       {
+                               lb--;
+                               pb++;
+                       }
+               }
+       }
+       if (la > 0 || lb > 0)
+               return la - lb;
+
+       return 0;
+}
+
+static int X509_NAME_wildcmp(const X509_NAME *a, const X509_NAME *b)
+{
+    int i,j;
+    X509_NAME_ENTRY *na,*nb;
+
+    if (sk_X509_NAME_ENTRY_num(a->entries)
+       != sk_X509_NAME_ENTRY_num(b->entries))
+           return sk_X509_NAME_ENTRY_num(a->entries)
+             -sk_X509_NAME_ENTRY_num(b->entries);
+    for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--)
+    {
+           na=sk_X509_NAME_ENTRY_value(a->entries,i);
+           nb=sk_X509_NAME_ENTRY_value(b->entries,i);
+           j=OBJ_cmp(na->object,nb->object);
+           if (j) return(j);
+           if ((na->value->length == 1 && na->value->data[0] == '*')
+            || (nb->value->length == 1 && nb->value->data[0] == '*'))
+                   continue;
+           j=na->value->type-nb->value->type;
+           if (j) return(j);
+           if (na->value->type == V_ASN1_PRINTABLESTRING)
+                   j=nocase_spacenorm_cmp(na->value, nb->value);
+           else if (na->value->type == V_ASN1_IA5STRING
+                   && OBJ_obj2nid(na->object) == NID_pkcs9_emailAddress)
+                   j=nocase_cmp(na->value, nb->value);
+           else
+                   {
+                   j=na->value->length-nb->value->length;
+                   if (j) return(j);
+                   j=memcmp(na->value->data,nb->value->data,
+                           na->value->length);
+                   }
+           if (j) return(j);
+           j=na->set-nb->set;
+           if (j) return(j);
+    }
+
+    return(0);
+}
+
+/*
+ * compare two subjectNames.
+ * OUT:        0: equal
+ *     positive:
+ *           -1: other error.
+ */
+int
+eay_cmp_asn1dn(n1, n2)
+       vchar_t *n1, *n2;
+{
+       X509_NAME *a = NULL, *b = NULL;
+       caddr_t p;
+       int i = -1;
+
+       p = n1->v;
+       if (!d2i_X509_NAME(&a, (void *)&p, n1->l))
+               goto end;
+       p = n2->v;
+       if (!d2i_X509_NAME(&b, (void *)&p, n2->l))
+               goto end;
+
+       i = X509_NAME_wildcmp(a, b);
+
+    end:
+       if (a)
+               X509_NAME_free(a);
+       if (b)
+               X509_NAME_free(b);
+       return i;
+}
+
+/*
+ * this functions is derived from apps/verify.c in OpenSSL0.9.5
+ */
+int
+eay_check_x509cert(cert, CApath, CAfile, local)
+       vchar_t *cert;
+       char *CApath;
+       char *CAfile;
+       int local;
+{
+       X509_STORE *cert_ctx = NULL;
+       X509_LOOKUP *lookup = NULL;
+       X509 *x509 = NULL;
+       X509_STORE_CTX *csc;
+       int error = -1;
+
+       cert_ctx = X509_STORE_new();
+       if (cert_ctx == NULL)
+               goto end;
+
+       if (local)
+               X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert_local);
+       else 
+               X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert_remote);
+
+       lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
+       if (lookup == NULL)
+               goto end;
+
+       X509_LOOKUP_load_file(lookup, CAfile, 
+           (CAfile == NULL) ? X509_FILETYPE_DEFAULT : X509_FILETYPE_PEM);
+
+       lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
+       if (lookup == NULL)
+               goto end;
+       error = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM);
+       if(!error) {
+               error = -1;
+               goto end;
+       }
+       error = -1;     /* initialized */
+
+       /* read the certificate to be verified */
+       x509 = mem2x509(cert);
+       if (x509 == NULL)
+               goto end;
+
+       csc = X509_STORE_CTX_new();
+       if (csc == NULL)
+               goto end;
+       X509_STORE_CTX_init(csc, cert_ctx, x509, NULL);
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+       X509_STORE_CTX_set_flags (csc, X509_V_FLAG_CRL_CHECK);
+       X509_STORE_CTX_set_flags (csc, X509_V_FLAG_CRL_CHECK_ALL);
+#endif
+       error = X509_verify_cert(csc);
+       X509_STORE_CTX_cleanup(csc);
+
+       /*
+        * if x509_verify_cert() is successful then the value of error is
+        * set non-zero.
+        */
+       error = error ? 0 : -1;
+
+end:
+       if (error)
+               printf("%s\n", eay_strerror());
+       if (cert_ctx != NULL)
+               X509_STORE_free(cert_ctx);
+       if (x509 != NULL)
+               X509_free(x509);
+
+       return(error);
+}
+
+/*
+ * callback function for verifing certificate.
+ * this function is derived from cb() in openssl/apps/s_server.c
+ */
+static int
+cb_check_cert_local(ok, ctx)
+       int ok;
+       X509_STORE_CTX *ctx;
+{
+       char buf[256];
+       int log_tag;
+
+       if (!ok) {
+               X509_NAME_oneline(
+                               X509_get_subject_name(ctx->current_cert),
+                               buf,
+                               256);
+               /*
+                * since we are just checking the certificates, it is
+                * ok if they are self signed. But we should still warn
+                * the user.
+                */
+               switch (ctx->error) {
+               case X509_V_ERR_CERT_HAS_EXPIRED:
+               case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+               case X509_V_ERR_INVALID_CA:
+               case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+               case X509_V_ERR_INVALID_PURPOSE:
+               case X509_V_ERR_UNABLE_TO_GET_CRL:
+                       ok = 1;
+                       log_tag = LLV_WARNING;
+                       break;
+               default:
+                       log_tag = LLV_ERROR;
+               }
+               plog(log_tag, LOCATION, NULL,
+                       "%s(%d) at depth:%d SubjectName:%s\n",
+                       X509_verify_cert_error_string(ctx->error),
+                       ctx->error,
+                       ctx->error_depth,
+                       buf);
+       }
+       ERR_clear_error();
+
+       return ok;
+}
+
+/*
+ * callback function for verifing remote certificates.
+ * this function is derived from cb() in openssl/apps/s_server.c
+ */
+static int
+cb_check_cert_remote(ok, ctx)
+       int ok;
+       X509_STORE_CTX *ctx;
+{
+       char buf[256];
+       int log_tag;
+
+       if (!ok) {
+               X509_NAME_oneline(
+                               X509_get_subject_name(ctx->current_cert),
+                               buf,
+                               256);
+               switch (ctx->error) {
+               case X509_V_ERR_UNABLE_TO_GET_CRL:
+                       ok = 1;
+                       log_tag = LLV_WARNING;
+                       break;
+               default:
+                       log_tag = LLV_ERROR;
+               }
+               plog(log_tag, LOCATION, NULL,
+                       "%s(%d) at depth:%d SubjectName:%s\n",
+                       X509_verify_cert_error_string(ctx->error),
+                       ctx->error,
+                       ctx->error_depth,
+                       buf);
+       }
+       ERR_clear_error();
+
+       return ok;
+}
+
+/*
+ * get a subjectAltName from X509 certificate.
+ */
+vchar_t *
+eay_get_x509asn1subjectname(cert)
+       vchar_t *cert;
+{
+       X509 *x509 = NULL;
+       u_char *bp;
+       vchar_t *name = NULL;
+       int len;
+       int error = -1;
+
+       bp = (unsigned char *) cert->v;
+
+       x509 = mem2x509(cert);
+       if (x509 == NULL)
+               goto end;
+
+       /* get the length of the name */
+       len = i2d_X509_NAME(x509->cert_info->subject, NULL);
+       name = vmalloc(len);
+       if (!name)
+               goto end;
+       /* get the name */
+       bp = (unsigned char *) name->v;
+       len = i2d_X509_NAME(x509->cert_info->subject, &bp);
+
+       error = 0;
+
+   end:
+       if (error) {
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+               if (name) {
+                       vfree(name);
+                       name = NULL;
+               }
+       }
+       if (x509)
+               X509_free(x509);
+
+       return name;
+}
+
+#ifdef __APPLE__
+
+/*
+ * Get the common name from a cert
+ */
+#define EAY_MAX_CN_LEN 256
+vchar_t *
+eay_get_x509_common_name(cert)
+       vchar_t *cert;
+{
+       X509 *x509 = NULL;      
+       X509_NAME *name;
+       vchar_t *commonName = NULL;
+       
+       commonName = vmalloc(EAY_MAX_CN_LEN);
+       if (commonName == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "no memory\n");
+               return NULL;
+       }
+       
+       x509 = mem2x509(cert);
+       if (x509 == NULL) {
+               vfree(commonName);
+               return NULL;
+       }
+
+       name = X509_get_subject_name(x509);
+       X509_NAME_get_text_by_NID(name, NID_commonName, commonName->v, EAY_MAX_CN_LEN);
+       
+       commonName->l = strlen(commonName->v);
+       
+       if (x509)
+               X509_free(x509);
+       return commonName;
+}
+
+/*
+ * get the subjectAltName from X509 certificate.
+ * the name must be terminated by '\0'.
+ */
+int
+eay_get_x509subjectaltname(cert, altname, type, pos, len)
+       vchar_t *cert;
+       char **altname;
+       int *type;
+       int pos;
+       int *len;
+{
+       X509 *x509 = NULL;
+       int i;
+       GENERAL_NAMES   *gens;
+       GENERAL_NAME    *gen;
+       int error = -1;
+
+       *altname = NULL;
+       *type = GENT_OTHERNAME;
+
+       x509 = mem2x509(cert);
+       if (x509 == NULL)
+               goto end;
+
+       gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
+       if (gens == NULL)
+               goto end;
+
+       for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+               if (i + 1 != pos)
+                       continue;
+               break;
+       }
+       
+       /* there is no data at "pos" */
+       if (i == sk_GENERAL_NAME_num(gens))
+               goto end;
+               
+       gen = sk_GENERAL_NAME_value(gens, i);
+
+       /* make sure the data is terminated by '\0'. */
+       if (gen->d.ia5->data[gen->d.ia5->length] != '\0') {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "data is not terminated by 0.");
+               hexdump(gen->d.ia5->data, gen->d.ia5->length + 1);
+               goto end;
+       }
+
+       /* read DNSName / Email */
+       if (gen->type == GEN_DNS        ||
+               gen->type == GEN_EMAIL  ||
+               gen->type == GEN_URI) {
+       
+               *len = gen->d.ia5->length + 1;
+               *altname = racoon_malloc(*len);
+               if (!*altname)
+                       goto end;
+                       
+               strlcpy(*altname, (const char *)gen->d.ia5->data, *len);
+               *type = gen->type;
+               
+               error = 0;
+       } else if (gen->type == GEN_IPADD) {
+               
+               *len = gen->d.ia5->length + 1;
+               *altname = racoon_malloc(*len);
+               if (!*altname)
+                       goto end;
+                       
+               memcpy(*altname, (const char *)gen->d.ia5->data, *len);
+               *type = gen->type;
+               
+               error = 0;
+       }
+
+   end:
+       if (error) {
+               if (*altname) {
+                       racoon_free(*altname);
+                       *altname = NULL;
+               }
+#ifndef EAYDEBUG
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+#else
+               printf("%s\n", eay_strerror());
+#endif
+       }
+       if (x509)
+               X509_free(x509);
+
+       return error;
+}
+
+#else /* __APPLE__ */
+
+/*
+ * get the subjectAltName from X509 certificate.
+ * the name must be terminated by '\0'.
+ */
+int
+eay_get_x509subjectaltname(cert, altname, type, pos)
+       vchar_t *cert;
+       char **altname;
+       int *type;
+       int pos;
+{
+       X509 *x509 = NULL;
+       GENERAL_NAMES *gens = NULL;
+       GENERAL_NAME *gen;
+       int len;
+       int error = -1;
+
+       *altname = NULL;
+       *type = GENT_OTHERNAME;
+
+       x509 = mem2x509(cert);
+       if (x509 == NULL)
+               goto end;
+
+       gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
+       if (gens == NULL)
+               goto end;
+
+       /* there is no data at "pos" */
+       if (pos > sk_GENERAL_NAME_num(gens))
+               goto end;
+
+       gen = sk_GENERAL_NAME_value(gens, pos - 1);
+
+       /* read DNSName / Email */
+       if (gen->type == GEN_DNS        ||
+               gen->type == GEN_EMAIL  ||
+               gen->type == GEN_URI )
+       {
+               /* make sure if the data is terminated by '\0'. */
+               if (gen->d.ia5->data[gen->d.ia5->length] != '\0')
+               {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "data is not terminated by NUL.");
+                       hexdump(gen->d.ia5->data, gen->d.ia5->length + 1);
+                       goto end;
+               }
+               
+               len = gen->d.ia5->length + 1;
+               *altname = racoon_malloc(len);
+               if (!*altname)
+                       goto end;
+               
+               strlcpy(*altname, (char *) gen->d.ia5->data, len);
+               *type = gen->type;
+               error = 0;
+       }
+       /* read IP address */
+       else if (gen->type == GEN_IPADD)
+       {
+               unsigned char p[5], *ip;
+               const int maxaltnamelen = 20;
+               ip = p;
+               
+               /* only support IPv4 */
+               if (gen->d.ip->length != 4)
+                       goto end;
+               
+               /* convert Octet String to String
+                * XXX ???????
+                */
+               /*i2d_ASN1_OCTET_STRING(gen->d.ip,&ip);*/
+               ip = gen->d.ip->data;
+
+               /* XXX Magic, enough for an IPv4 address
+                */
+               *altname = racoon_malloc(maxaltnamelen);
+               if (!*altname)
+                       goto end;
+               
+               snprintf(*altname, maxaltnamelen, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+               *type = gen->type;
+               error = 0;
+       }
+       /* XXX other possible types ?
+        * For now, error will be -1 if unsupported type
+        */
+
+end:
+       if (error) {
+               if (*altname) {
+                       racoon_free(*altname);
+                       *altname = NULL;
+               }
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+       }
+       if (x509)
+               X509_free(x509);
+       if (gens)
+               /* free the whole stack. */
+               sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+
+       return error;
+}
+
+#endif
+
+/*
+ * decode a X509 certificate and make a readable text terminated '\n'.
+ * return the buffer allocated, so must free it later.
+ */
+char *
+eay_get_x509text(cert)
+       vchar_t *cert;
+{
+       X509 *x509 = NULL;
+       BIO *bio = NULL;
+       char *text = NULL;
+       u_char *bp = NULL;
+       int len = 0;
+       int error = -1;
+
+       x509 = mem2x509(cert);
+       if (x509 == NULL)
+               goto end;
+
+       bio = BIO_new(BIO_s_mem());
+       if (bio == NULL)
+               goto end;
+
+       error = X509_print(bio, x509);
+       if (error != 1) {
+               error = -1;
+               goto end;
+       }
+
+       len = BIO_get_mem_data(bio, &bp);
+       text = racoon_malloc(len + 1);
+       if (text == NULL)
+               goto end;
+       memcpy(text, bp, len);
+       text[len] = '\0';
+
+       error = 0;
+
+    end:
+       if (error) {
+               if (text) {
+                       racoon_free(text);
+                       text = NULL;
+               }
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+       }
+       if (bio)
+               BIO_free(bio);
+       if (x509)
+               X509_free(x509);
+
+       return text;
+}
+
+/* get X509 structure from buffer. */
+static X509 *
+mem2x509(cert)
+       vchar_t *cert;
+{
+       X509 *x509;
+
+#ifndef EAYDEBUG
+    {
+       u_char *bp;
+
+       bp = (unsigned char *) cert->v;
+
+       x509 = d2i_X509(NULL, (void *)&bp, cert->l);
+    }
+#else
+    {
+       BIO *bio;
+       int len;
+
+       bio = BIO_new(BIO_s_mem());
+       if (bio == NULL)
+               return NULL;
+       len = BIO_write(bio, cert->v, cert->l);
+       if (len == -1)
+               return NULL;
+       x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+       BIO_free(bio);
+    }
+#endif
+       return x509;
+}
+
+/*
+ * get a X509 certificate from local file.
+ * a certificate must be PEM format.
+ * Input:
+ *     path to a certificate.
+ * Output:
+ *     NULL if error occured
+ *     other is the cert.
+ */
+vchar_t *
+eay_get_x509cert(path)
+       char *path;
+{
+       FILE *fp;
+       X509 *x509;
+       vchar_t *cert;
+       u_char *bp;
+       int len;
+       int error;
+
+       /* Read private key */
+       fp = fopen(path, "r");
+       if (fp == NULL)
+               return NULL;
+       x509 = PEM_read_X509(fp, NULL, NULL, NULL);
+       fclose (fp);
+
+       if (x509 == NULL)
+               return NULL;
+
+       len = i2d_X509(x509, NULL);
+       cert = vmalloc(len);
+       if (cert == NULL) {
+               X509_free(x509);
+               return NULL;
+       }
+       bp = (unsigned char *) cert->v;
+       error = i2d_X509(x509, &bp);
+       X509_free(x509);
+
+       if (error == 0) {
+               vfree(cert);
+               return NULL;
+       }
+
+       return cert;
+}
+
+/*
+ * check a X509 signature
+ *     XXX: to be get hash type from my cert ?
+ *             to be handled EVP_dss().
+ * OUT: return -1 when error.
+ *     0
+ */
+int
+eay_check_x509sign(source, sig, cert)
+       vchar_t *source;
+       vchar_t *sig;
+       vchar_t *cert;
+{
+       X509 *x509;
+       u_char *bp;
+       EVP_PKEY *evp;
+       int res;
+
+       bp = (unsigned char *) cert->v;
+
+       x509 = d2i_X509(NULL, (void *)&bp, cert->l);
+       if (x509 == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "d2i_X509(): %s\n", eay_strerror());
+               return -1;
+       }
+
+       evp = X509_get_pubkey(x509);
+       if (! evp) {
+               plog(LLV_ERROR, LOCATION, NULL, "X509_get_pubkey(): %s\n", eay_strerror());
+               return -1;
+       }
+
+       res = eay_rsa_verify(source, sig, evp->pkey.rsa);
+
+       EVP_PKEY_free(evp);
+
+       return res;
+}
+
+/*
+ * check RSA signature
+ * OUT: return -1 when error.
+ *     0 on success
+ */
+int
+eay_check_rsasign(source, sig, rsa)
+       vchar_t *source;
+       vchar_t *sig;
+       RSA *rsa;
+{
+       return eay_rsa_verify(source, sig, rsa);
+}
+
+/*
+ * get PKCS#1 Private Key of PEM format from local file.
+ */
+vchar_t *
+eay_get_pkcs1privkey(path)
+       char *path;
+{
+       FILE *fp;
+       EVP_PKEY *evp = NULL;
+       vchar_t *pkey = NULL;
+       u_char *bp;
+       int pkeylen;
+       int error = -1;
+
+       /* Read private key */
+       fp = fopen(path, "r");
+       if (fp == NULL)
+               return NULL;
+
+       evp = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+
+       fclose (fp);
+
+       if (evp == NULL)
+               return NULL;
+
+       pkeylen = i2d_PrivateKey(evp, NULL);
+       if (pkeylen == 0)
+               goto end;
+       pkey = vmalloc(pkeylen);
+       if (pkey == NULL)
+               goto end;
+       bp = (unsigned char *) pkey->v;
+       pkeylen = i2d_PrivateKey(evp, &bp);
+       if (pkeylen == 0)
+               goto end;
+
+       error = 0;
+
+end:
+       if (evp != NULL)
+               EVP_PKEY_free(evp);
+       if (error != 0 && pkey != NULL) {
+               vfree(pkey);
+               pkey = NULL;
+       }
+
+       return pkey;
+}
+
+/*
+ * get PKCS#1 Public Key of PEM format from local file.
+ */
+vchar_t *
+eay_get_pkcs1pubkey(path)
+       char *path;
+{
+       FILE *fp;
+       EVP_PKEY *evp = NULL;
+       vchar_t *pkey = NULL;
+       X509 *x509 = NULL;
+       u_char *bp;
+       int pkeylen;
+       int error = -1;
+
+       /* Read private key */
+       fp = fopen(path, "r");
+       if (fp == NULL)
+               return NULL;
+
+       x509 = PEM_read_X509(fp, NULL, NULL, NULL);
+
+       fclose (fp);
+
+       if (x509 == NULL)
+               return NULL;
+  
+       /* Get public key - eay */
+       evp = X509_get_pubkey(x509);
+       if (evp == NULL)
+               return NULL;
+
+       pkeylen = i2d_PublicKey(evp, NULL);
+       if (pkeylen == 0)
+               goto end;
+       pkey = vmalloc(pkeylen);
+       if (pkey == NULL)
+               goto end;
+       bp = (unsigned char *) pkey->v;
+       pkeylen = i2d_PublicKey(evp, &bp);
+       if (pkeylen == 0)
+               goto end;
+
+       error = 0;
+end:
+       if (evp != NULL)
+               EVP_PKEY_free(evp);
+       if (error != 0 && pkey != NULL) {
+               vfree(pkey);
+               pkey = NULL;
+       }
+
+       return pkey;
+}
+
+vchar_t *
+eay_get_x509sign(src, privkey)
+       vchar_t *src, *privkey;
+{
+       EVP_PKEY *evp;
+       u_char *bp = (unsigned char *) privkey->v;
+       vchar_t *sig = NULL;
+       int len;
+       int pad = RSA_PKCS1_PADDING;
+
+       /* XXX to be handled EVP_PKEY_DSA */
+       evp = d2i_PrivateKey(EVP_PKEY_RSA, NULL, (void *)&bp, privkey->l);
+       if (evp == NULL)
+               return NULL;
+
+       sig = eay_rsa_sign(src, evp->pkey.rsa);
+
+       EVP_PKEY_free(evp);
+
+       return sig;
+}
+
+vchar_t *
+eay_get_rsasign(src, rsa)
+       vchar_t *src;
+       RSA *rsa;
+{
+       return eay_rsa_sign(src, rsa);
+}
+
+vchar_t *
+eay_rsa_sign(vchar_t *src, RSA *rsa)
+{
+       int len;
+       vchar_t *sig = NULL;
+       int pad = RSA_PKCS1_PADDING;
+
+       len = RSA_size(rsa);
+
+       sig = vmalloc(len);
+       if (sig == NULL)
+               return NULL;
+
+       len = RSA_private_encrypt(src->l, (unsigned char *) src->v, 
+                       (unsigned char *) sig->v, rsa, pad);
+
+       if (len == 0 || len != sig->l) {
+               vfree(sig);
+               sig = NULL;
+       }
+
+       return sig;
+}
+
+int
+eay_rsa_verify(src, sig, rsa)
+       vchar_t *src, *sig;
+       RSA *rsa;
+{
+       vchar_t *xbuf = NULL;
+       int pad = RSA_PKCS1_PADDING;
+       int len = 0;
+       int error;
+
+       len = RSA_size(rsa);
+       xbuf = vmalloc(len);
+       if (xbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+               return -1;
+       }
+
+       len = RSA_public_decrypt(sig->l, (unsigned char *) sig->v, 
+                       (unsigned char *) xbuf->v, rsa, pad);
+       if (len == 0 || len != src->l) {
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+               vfree(xbuf);
+               return -1;
+       }
+
+       error = memcmp(src->v, xbuf->v, src->l);
+       vfree(xbuf);
+       if (error != 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * get error string
+ * MUST load ERR_load_crypto_strings() first.
+ */
+char *
+eay_strerror()
+{
+       static char ebuf[512];
+       int len = 0, n;
+       unsigned long l;
+       char buf[200];
+       const char *file, *data;
+       int line, flags;
+       unsigned long es;
+
+       es = CRYPTO_thread_id();
+
+       while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0){
+               n = snprintf(ebuf + len, sizeof(ebuf) - len,
+                               "%lu:%s:%s:%d:%s ",
+                               es, ERR_error_string(l, buf), file, line,
+                               (flags & ERR_TXT_STRING) ? data : "");
+               if (n < 0 || n >= sizeof(ebuf) - len)
+                       break;
+               len += n;
+               if (sizeof(ebuf) < len)
+                       break;
+       }
+
+       return ebuf;
+}
+
+vchar_t *
+evp_crypt(vchar_t *data, vchar_t *key, vchar_t *iv, const EVP_CIPHER *e, int enc)
+{
+       vchar_t *res;
+       EVP_CIPHER_CTX ctx;
+
+       if (!e)
+               return NULL;
+
+       if (data->l % EVP_CIPHER_block_size(e))
+               return NULL;
+
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       EVP_CIPHER_CTX_init(&ctx);
+
+       switch(EVP_CIPHER_nid(e)){
+       case NID_bf_cbc:
+       case NID_bf_ecb:
+       case NID_bf_cfb64:
+       case NID_bf_ofb64:
+       case NID_cast5_cbc:
+       case NID_cast5_ecb:
+       case NID_cast5_cfb64:
+       case NID_cast5_ofb64:
+               /* XXX: can we do that also for algos with a fixed key size ?
+                */
+               /* init context without key/iv
+         */
+        if (!EVP_CipherInit(&ctx, e, NULL, NULL, enc))
+        {
+            OpenSSL_BUG();
+            vfree(res);
+            return NULL;
+        }
+               
+        /* update key size
+         */
+        if (!EVP_CIPHER_CTX_set_key_length(&ctx, key->l))
+        {
+            OpenSSL_BUG();
+            vfree(res);
+            return NULL;
+        }
+
+        /* finalize context init with desired key size
+         */
+        if (!EVP_CipherInit(&ctx, NULL, (u_char *) key->v,
+                                                       (u_char *) iv->v, enc))
+        {
+            OpenSSL_BUG();
+            vfree(res);
+            return NULL;
+               }
+               break;
+       default:
+               if (!EVP_CipherInit(&ctx, e, (u_char *) key->v, 
+                                                       (u_char *) iv->v, enc)) {
+                       OpenSSL_BUG();
+                       vfree(res);
+                       return NULL;
+               }
+       }
+
+       /* disable openssl padding */
+       EVP_CIPHER_CTX_set_padding(&ctx, 0); 
+       
+       if (!EVP_Cipher(&ctx, (u_char *) res->v, (u_char *) data->v, data->l)) {
+               OpenSSL_BUG();
+               vfree(res);
+               return NULL;
+       }
+
+       EVP_CIPHER_CTX_cleanup(&ctx);
+
+       return res;
+}
+
+int
+evp_weakkey(vchar_t *key, const EVP_CIPHER *e)
+{
+       return 0;
+}
+
+int
+evp_keylen(int len, const EVP_CIPHER *e)
+{
+       if (!e)
+               return -1;
+       /* EVP functions return lengths in bytes, ipsec-tools
+        * uses lengths in bits, therefore conversion is required. --AK
+        */
+       if (len != 0 && len != (EVP_CIPHER_key_length(e) << 3))
+               return -1;
+       
+       return EVP_CIPHER_key_length(e) << 3;
+}
+
+/*
+ * DES-CBC
+ */
+vchar_t *
+eay_des_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_des_cbc(), 1);
+}
+
+vchar_t *
+eay_des_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_des_cbc(), 0);
+}
+
+int
+eay_des_weakkey(key)
+       vchar_t *key;
+{
+#ifdef USE_NEW_DES_API
+       return DES_is_weak_key((void *)key->v);
+#else
+       return des_is_weak_key((void *)key->v);
+#endif
+}
+
+int
+eay_des_keylen(len)
+       int len;
+{
+       return evp_keylen(len, EVP_des_cbc());
+}
+
+#ifdef HAVE_OPENSSL_IDEA_H
+/*
+ * IDEA-CBC
+ */
+vchar_t *
+eay_idea_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       IDEA_KEY_SCHEDULE ks;
+
+       idea_set_encrypt_key(key->v, &ks);
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* decryption data */
+       idea_cbc_encrypt(data->v, res->v, data->l,
+                       &ks, iv->v, IDEA_ENCRYPT);
+
+       return res;
+}
+
+vchar_t *
+eay_idea_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       IDEA_KEY_SCHEDULE ks, dks;
+
+       idea_set_encrypt_key(key->v, &ks);
+       idea_set_decrypt_key(&ks, &dks);
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* decryption data */
+       idea_cbc_encrypt(data->v, res->v, data->l,
+                       &dks, iv->v, IDEA_DECRYPT);
+
+       return res;
+}
+
+int
+eay_idea_weakkey(key)
+       vchar_t *key;
+{
+       return 0;       /* XXX */
+}
+
+int
+eay_idea_keylen(len)
+       int len;
+{
+       if (len != 0 && len != 128)
+               return -1;
+       return 128;
+}
+#endif
+
+/*
+ * BLOWFISH-CBC
+ */
+vchar_t *
+eay_bf_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_bf_cbc(), 1);
+}
+
+vchar_t *
+eay_bf_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_bf_cbc(), 0);
+}
+
+int
+eay_bf_weakkey(key)
+       vchar_t *key;
+{
+       return 0;       /* XXX to be done. refer to RFC 2451 */
+}
+
+int
+eay_bf_keylen(len)
+       int len;
+{
+       if (len == 0)
+               return 448;
+       if (len < 40 || len > 448)
+               return -1;
+       return len;
+}
+
+#ifdef HAVE_OPENSSL_RC5_H
+/*
+ * RC5-CBC
+ */
+vchar_t *
+eay_rc5_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       RC5_32_KEY ks;
+
+       /* in RFC 2451, there is information about the number of round. */
+       RC5_32_set_key(&ks, key->l, key->v, 16);
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* decryption data */
+       RC5_32_cbc_encrypt(data->v, res->v, data->l,
+               &ks, iv->v, RC5_ENCRYPT);
+
+       return res;
+}
+
+vchar_t *
+eay_rc5_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       RC5_32_KEY ks;
+
+       /* in RFC 2451, there is information about the number of round. */
+       RC5_32_set_key(&ks, key->l, key->v, 16);
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* decryption data */
+       RC5_32_cbc_encrypt(data->v, res->v, data->l,
+               &ks, iv->v, RC5_DECRYPT);
+
+       return res;
+}
+
+int
+eay_rc5_weakkey(key)
+       vchar_t *key;
+{
+       return 0;       /* No known weak keys when used with 16 rounds. */
+
+}
+
+int
+eay_rc5_keylen(len)
+       int len;
+{
+       if (len == 0)
+               return 128;
+       if (len < 40 || len > 2040)
+               return -1;
+       return len;
+}
+#endif
+
+/*
+ * 3DES-CBC
+ */
+vchar_t *
+eay_3des_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_des_ede3_cbc(), 1);
+}
+
+vchar_t *
+eay_3des_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_des_ede3_cbc(), 0);
+}
+
+int
+eay_3des_weakkey(key)
+       vchar_t *key;
+{
+#ifdef USE_NEW_DES_API
+       return (DES_is_weak_key((void *)key->v) ||
+           DES_is_weak_key((void *)(key->v + 8)) ||
+           DES_is_weak_key((void *)(key->v + 16)));
+#else
+       if (key->l < 24)
+               return 0;
+
+       return (des_is_weak_key((void *)key->v) ||
+           des_is_weak_key((void *)(key->v + 8)) ||
+           des_is_weak_key((void *)(key->v + 16)));
+#endif
+}
+
+int
+eay_3des_keylen(len)
+       int len;
+{
+       if (len != 0 && len != 192)
+               return -1;
+       return 192;
+}
+
+/*
+ * CAST-CBC
+ */
+vchar_t *
+eay_cast_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_cast5_cbc(), 1);
+}
+
+vchar_t *
+eay_cast_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, EVP_cast5_cbc(), 0);
+}
+
+int
+eay_cast_weakkey(key)
+       vchar_t *key;
+{
+       return 0;       /* No known weak keys. */
+}
+
+int
+eay_cast_keylen(len)
+       int len;
+{
+       if (len == 0)
+               return 128;
+       if (len < 40 || len > 128)
+               return -1;
+       return len;
+}
+
+/*
+ * AES(RIJNDAEL)-CBC
+ */
+#ifndef HAVE_OPENSSL_AES_H
+vchar_t *
+eay_aes_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       keyInstance k;
+       cipherInstance c;
+
+       memset(&k, 0, sizeof(k));
+       if (rijndael_makeKey(&k, DIR_ENCRYPT, key->l << 3, key->v) < 0)
+               return NULL;
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* encryption data */
+       memset(&c, 0, sizeof(c));
+       if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0){
+               vfree(res);
+               return NULL;
+       }
+       if (rijndael_blockEncrypt(&c, &k, data->v, data->l << 3, res->v) < 0){
+               vfree(res);
+               return NULL;
+       }
+
+       return res;
+}
+
+vchar_t *
+eay_aes_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       vchar_t *res;
+       keyInstance k;
+       cipherInstance c;
+
+       memset(&k, 0, sizeof(k));
+       if (rijndael_makeKey(&k, DIR_DECRYPT, key->l << 3, key->v) < 0)
+               return NULL;
+
+       /* allocate buffer for result */
+       if ((res = vmalloc(data->l)) == NULL)
+               return NULL;
+
+       /* decryption data */
+       memset(&c, 0, sizeof(c));
+       if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0){
+               vfree(res);
+               return NULL;
+       }
+       if (rijndael_blockDecrypt(&c, &k, data->v, data->l << 3, res->v) < 0){
+               vfree(res);
+               return NULL;
+       }
+
+       return res;
+}
+#else
+static inline const EVP_CIPHER *
+aes_evp_by_keylen(int keylen)
+{
+       switch(keylen) {
+               case 16:
+               case 128:
+                       return EVP_aes_128_cbc();
+               case 24:
+               case 192:
+                       return EVP_aes_192_cbc();
+               case 32:
+               case 256:
+                       return EVP_aes_256_cbc();
+               default:
+                       return NULL;
+       }
+}
+
+vchar_t *
+eay_aes_encrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, aes_evp_by_keylen(key->l), 1);
+}
+
+vchar_t *
+eay_aes_decrypt(data, key, iv)
+       vchar_t *data, *key, *iv;
+{
+       return evp_crypt(data, key, iv, aes_evp_by_keylen(key->l), 0);
+}
+#endif
+
+int
+eay_aes_weakkey(key)
+       vchar_t *key;
+{
+       return 0;
+}
+
+int
+eay_aes_keylen(len)
+       int len;
+{
+       if (len == 0)
+               return 128;
+       if (len != 128 && len != 192 && len != 256)
+               return -1;
+       return len;
+}
+
+/* for ipsec part */
+int
+eay_null_hashlen()
+{
+       return 0;
+}
+
+int
+eay_kpdk_hashlen()
+{
+       return 0;
+}
+
+int
+eay_twofish_keylen(len)
+       int len;
+{
+       if (len < 0 || len > 256)
+               return -1;
+       return len;
+}
+
+int
+eay_null_keylen(len)
+       int len;
+{
+       return 0;
+}
+
+/*
+ * HMAC functions
+ */
+#ifdef __APPLE__
+static caddr_t
+eay_hmac_init(key, algorithm)
+       vchar_t *key;
+       CCHmacAlgorithm algorithm;
+{
+       CCHmacContext *c = racoon_malloc(sizeof(*c));
+
+       CCHmacInit(c, algorithm, key->v, key->l);
+
+       return (caddr_t)c;
+}
+#else
+static caddr_t
+eay_hmac_init(key, md)
+       vchar_t *key;
+       const EVP_MD *md;
+{
+       HMAC_CTX *c = racoon_malloc(sizeof(*c));
+
+       HMAC_Init(c, key->v, key->l, md);
+
+       return (caddr_t)c;
+}
+#endif /* __APPLE__ */
+
+#ifdef WITH_SHA2
+/*
+ * HMAC SHA2-512
+ */
+vchar_t *
+eay_hmacsha2_512_one(key, data)
+       vchar_t *key, *data;
+{
+       vchar_t *res;
+       caddr_t ctx;
+
+       ctx = eay_hmacsha2_512_init(key);
+       eay_hmacsha2_512_update(ctx, data);
+       res = eay_hmacsha2_512_final(ctx);
+
+       return(res);
+}
+
+caddr_t
+eay_hmacsha2_512_init(key)
+       vchar_t *key;
+{
+#ifdef __APPLE__
+       return eay_hmac_init(key, kCCHmacAlgSHA512);
+#else
+       return eay_hmac_init(key, EVP_sha2_512());
+#endif
+}
+
+void
+eay_hmacsha2_512_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+#ifdef __APPLE__
+       CCHmacUpdate((CCHmacContext *)c, data->v, data->l);
+#else
+       HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l);
+#endif
+}
+
+#ifdef __APPLE__
+vchar_t *
+eay_hmacsha2_512_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(CC_SHA512_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       CCHmacFinal((CCHmacContext *)c, res->v);
+       res->l = CC_SHA512_DIGEST_LENGTH;
+               
+       (void)racoon_free(c);
+       return(res);
+}
+#else
+vchar_t *
+eay_hmacsha2_512_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+       unsigned int l;
+
+       if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l);
+       res->l = l;
+       HMAC_cleanup((HMAC_CTX *)c);
+               
+       (void)racoon_free(c);
+
+       if (SHA512_DIGEST_LENGTH != res->l) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "hmac sha2_512 length mismatch %zd.\n", res->l);
+               vfree(res);
+               return NULL;
+       }
+
+       return(res);
+}
+#endif /* __APPLE__ */
+
+/*
+ * HMAC SHA2-384
+ */
+vchar_t *
+eay_hmacsha2_384_one(key, data)
+       vchar_t *key, *data;
+{
+       vchar_t *res;
+       caddr_t ctx;
+
+       ctx = eay_hmacsha2_384_init(key);
+       eay_hmacsha2_384_update(ctx, data);
+       res = eay_hmacsha2_384_final(ctx);
+
+       return(res);
+}
+
+caddr_t
+eay_hmacsha2_384_init(key)
+       vchar_t *key;
+{
+#ifdef __APPLE__
+       return eay_hmac_init(key, kCCHmacAlgSHA384);
+#else
+       return eay_hmac_init(key, EVP_sha2_384());
+#endif
+}
+
+void
+eay_hmacsha2_384_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+#ifdef __APPLE__
+       CCHmacUpdate((CCHmacContext *)c, data->v, data->l);
+#else
+       HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l);
+#endif
+}
+
+#ifdef __APPLE__
+vchar_t *
+eay_hmacsha2_384_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(CC_SHA384_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       CCHmacFinal((CCHmacContext *)c, res->v);
+       res->l = CC_SHA384_DIGEST_LENGTH;
+
+       (void)racoon_free(c);
+       return(res);
+}
+#else
+vchar_t *
+eay_hmacsha2_384_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+       unsigned int l;
+
+       if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l);
+       res->l = l;
+       HMAC_cleanup((HMAC_CTX *)c);
+
+       (void)racoon_free(c);
+
+       if (SHA384_DIGEST_LENGTH != res->l) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "hmac sha2_384 length mismatch %zd.\n", res->l);
+               vfree(res);
+               return NULL;
+       }
+
+       return(res);
+}
+#endif /* __APPLE__ */
+
+/*
+ * HMAC SHA2-256
+ */
+vchar_t *
+eay_hmacsha2_256_one(key, data)
+       vchar_t *key, *data;
+{
+       vchar_t *res;
+       caddr_t ctx;
+
+       ctx = eay_hmacsha2_256_init(key);
+       eay_hmacsha2_256_update(ctx, data);
+       res = eay_hmacsha2_256_final(ctx);
+
+       return(res);
+}
+
+caddr_t
+eay_hmacsha2_256_init(key)
+       vchar_t *key;
+{
+#ifdef __APPLE__
+       return eay_hmac_init(key, kCCHmacAlgSHA256);
+#else
+       return eay_hmac_init(key, EVP_sha2_256());
+#endif
+}
+
+void
+eay_hmacsha2_256_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+#ifdef __APPLE__
+       CCHmacUpdate((CCHmacContext *)c, data->v, data->l);
+#else
+       HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l);
+#endif
+}
+
+#ifdef __APPLE__
+vchar_t *
+eay_hmacsha2_256_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(CC_SHA256_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       CCHmacFinal((CCHmacContext *)c, res->v);
+       res->l = CC_SHA256_DIGEST_LENGTH;
+
+       (void)racoon_free(c);
+       return(res);
+}
+#else
+vchar_t *
+eay_hmacsha2_256_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+       unsigned int l;
+
+       if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l);
+       res->l = l;
+       HMAC_cleanup((HMAC_CTX *)c);
+
+       (void)racoon_free(c);
+
+       if (SHA256_DIGEST_LENGTH != res->l) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "hmac sha2_256 length mismatch %zd.\n", res->l);
+               vfree(res);
+               return NULL;
+       }
+
+       return(res);
+}
+#endif /* __APPLE__ */
+#endif /* WITH_SHA2 */
+
+/*
+ * HMAC SHA1
+ */
+vchar_t *
+eay_hmacsha1_one(key, data)
+       vchar_t *key, *data;
+{
+       vchar_t *res;
+       caddr_t ctx;
+
+       ctx = eay_hmacsha1_init(key);
+       eay_hmacsha1_update(ctx, data);
+       res = eay_hmacsha1_final(ctx);
+
+       return(res);
+}
+
+caddr_t
+eay_hmacsha1_init(key)
+       vchar_t *key;
+{
+#ifdef __APPLE__
+       return eay_hmac_init(key, kCCHmacAlgSHA1);
+#else
+       return eay_hmac_init(key, EVP_sha1());
+#endif
+}
+
+void
+eay_hmacsha1_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+#ifdef __APPLE__
+       CCHmacUpdate((CCHmacContext *)c, data->v, data->l);
+#else
+       HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l);
+#endif
+}
+
+#ifdef __APPLE__
+vchar_t *
+eay_hmacsha1_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(CC_SHA1_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       CCHmacFinal((CCHmacContext *)c, res->v);
+       res->l = CC_SHA1_DIGEST_LENGTH;
+
+       (void)racoon_free(c);
+       return(res);
+}
+#else
+vchar_t *
+eay_hmacsha1_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+       unsigned int l;
+
+       if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l);
+       res->l = l;
+       HMAC_cleanup((HMAC_CTX *)c);
+
+       (void)racoon_free(c);
+
+       if (SHA_DIGEST_LENGTH != res->l) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "hmac sha1 length mismatch %zd.\n", res->l);
+               vfree(res);
+               return NULL;
+       }
+
+       return(res);
+}
+#endif /* __APPLE__ */
+
+/*
+ * HMAC MD5
+ */
+vchar_t *
+eay_hmacmd5_one(key, data)
+       vchar_t *key, *data;
+{
+       vchar_t *res;
+       caddr_t ctx;
+
+       ctx = eay_hmacmd5_init(key);
+       eay_hmacmd5_update(ctx, data);
+       res = eay_hmacmd5_final(ctx);
+
+       return(res);
+}
+
+caddr_t
+eay_hmacmd5_init(key)
+       vchar_t *key;
+{
+#ifdef __APPLE__
+       return eay_hmac_init(key, kCCHmacAlgMD5);
+#else
+       return eay_hmac_init(key, EVP_md5());
+#endif
+}
+
+void
+eay_hmacmd5_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+#ifdef __APPLE__
+       CCHmacUpdate((CCHmacContext *)c, data->v, data->l);
+#else
+       HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l);
+#endif
+}
+
+#ifdef __APPLE__
+vchar_t *
+eay_hmacmd5_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(CC_MD5_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       CCHmacFinal((CCHmacContext *)c, res->v);
+       res->l = CC_MD5_DIGEST_LENGTH;
+       (void)racoon_free(c);
+
+       return(res);
+}
+#else
+vchar_t *
+eay_hmacmd5_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+       unsigned int l;
+
+       if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0)
+               return NULL;
+
+       HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l);
+       res->l = l;
+       HMAC_cleanup((HMAC_CTX *)c);
+       
+       (void)racoon_free(c);
+
+       if (MD5_DIGEST_LENGTH != res->l) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "hmac md5 length mismatch %zd.\n", res->l);
+               vfree(res);
+               return NULL;
+       }
+
+       return(res);
+}
+#endif /* __APPLE__ */
+
+#ifdef WITH_SHA2
+/*
+ * SHA2-512 functions
+ */
+caddr_t
+eay_sha2_512_init()
+{
+       SHA512_CTX *c = racoon_malloc(sizeof(*c));
+
+       SHA512_Init(c);
+
+       return((caddr_t)c);
+}
+
+void
+eay_sha2_512_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+       SHA512_Update((SHA512_CTX *)c, (unsigned char *) data->v, data->l);
+
+       return;
+}
+
+vchar_t *
+eay_sha2_512_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0)
+               return(0);
+
+       SHA512_Final((unsigned char *) res->v, (SHA512_CTX *)c);
+       (void)racoon_free(c);
+
+       return(res);
+}
+
+vchar_t *
+eay_sha2_512_one(data)
+       vchar_t *data;
+{
+       caddr_t ctx;
+       vchar_t *res;
+
+       ctx = eay_sha2_512_init();
+       eay_sha2_512_update(ctx, data);
+       res = eay_sha2_512_final(ctx);
+
+       return(res);
+}
+
+int
+eay_sha2_512_hashlen()
+{
+       return SHA512_DIGEST_LENGTH << 3;
+}
+#endif
+
+#ifdef WITH_SHA2
+/*
+ * SHA2-384 functions
+ */
+#ifdef __APPLE__
+typedef SHA512_CTX SHA384_CTX;
+#endif
+
+caddr_t
+eay_sha2_384_init()
+{
+       SHA384_CTX *c = racoon_malloc(sizeof(*c));
+
+       SHA384_Init(c);
+
+       return((caddr_t)c);
+}
+
+void
+eay_sha2_384_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+       SHA384_Update((SHA384_CTX *)c, (unsigned char *) data->v, data->l);
+
+       return;
+}
+
+vchar_t *
+eay_sha2_384_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0)
+               return(0);
+
+       SHA384_Final((unsigned char *) res->v, (SHA384_CTX *)c);
+       (void)racoon_free(c);
+
+       return(res);
+}
+
+vchar_t *
+eay_sha2_384_one(data)
+       vchar_t *data;
+{
+       caddr_t ctx;
+       vchar_t *res;
+
+       ctx = eay_sha2_384_init();
+       eay_sha2_384_update(ctx, data);
+       res = eay_sha2_384_final(ctx);
+
+       return(res);
+}
+
+int
+eay_sha2_384_hashlen()
+{
+       return SHA384_DIGEST_LENGTH << 3;
+}
+#endif
+
+#ifdef WITH_SHA2
+/*
+ * SHA2-256 functions
+ */
+caddr_t
+eay_sha2_256_init()
+{
+       SHA256_CTX *c = racoon_malloc(sizeof(*c));
+
+       SHA256_Init(c);
+
+       return((caddr_t)c);
+}
+
+void
+eay_sha2_256_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+       SHA256_Update((SHA256_CTX *)c, (unsigned char *) data->v, data->l);
+
+       return;
+}
+
+vchar_t *
+eay_sha2_256_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0)
+               return(0);
+
+       SHA256_Final((unsigned char *) res->v, (SHA256_CTX *)c);
+       (void)racoon_free(c);
+
+       return(res);
+}
+
+vchar_t *
+eay_sha2_256_one(data)
+       vchar_t *data;
+{
+       caddr_t ctx;
+       vchar_t *res;
+
+       ctx = eay_sha2_256_init();
+       eay_sha2_256_update(ctx, data);
+       res = eay_sha2_256_final(ctx);
+
+       return(res);
+}
+
+int
+eay_sha2_256_hashlen()
+{
+       return SHA256_DIGEST_LENGTH << 3;
+}
+#endif
+
+/*
+ * SHA functions
+ */
+caddr_t
+eay_sha1_init()
+{
+       SHA_CTX *c = racoon_malloc(sizeof(*c));
+
+       SHA1_Init(c);
+
+       return((caddr_t)c);
+}
+
+void
+eay_sha1_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+       SHA1_Update((SHA_CTX *)c, data->v, data->l);
+
+       return;
+}
+
+vchar_t *
+eay_sha1_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0)
+               return(0);
+
+       SHA1_Final((unsigned char *) res->v, (SHA_CTX *)c);
+       (void)racoon_free(c);
+
+       return(res);
+}
+
+vchar_t *
+eay_sha1_one(data)
+       vchar_t *data;
+{
+       caddr_t ctx;
+       vchar_t *res;
+
+       ctx = eay_sha1_init();
+       eay_sha1_update(ctx, data);
+       res = eay_sha1_final(ctx);
+
+       return(res);
+}
+
+int
+eay_sha1_hashlen()
+{
+       return SHA_DIGEST_LENGTH << 3;
+}
+
+/*
+ * MD5 functions
+ */
+caddr_t
+eay_md5_init()
+{
+       MD5_CTX *c = racoon_malloc(sizeof(*c));
+
+       MD5_Init(c);
+
+       return((caddr_t)c);
+}
+
+void
+eay_md5_update(c, data)
+       caddr_t c;
+       vchar_t *data;
+{
+       MD5_Update((MD5_CTX *)c, data->v, data->l);
+
+       return;
+}
+
+vchar_t *
+eay_md5_final(c)
+       caddr_t c;
+{
+       vchar_t *res;
+
+       if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0)
+               return(0);
+
+       MD5_Final((unsigned char *) res->v, (MD5_CTX *)c);
+       (void)racoon_free(c);
+
+       return(res);
+}
+
+vchar_t *
+eay_md5_one(data)
+       vchar_t *data;
+{
+       caddr_t ctx;
+       vchar_t *res;
+
+       ctx = eay_md5_init();
+       eay_md5_update(ctx, data);
+       res = eay_md5_final(ctx);
+
+       return(res);
+}
+
+int
+eay_md5_hashlen()
+{
+       return MD5_DIGEST_LENGTH << 3;
+}
+
+/*
+ * eay_set_random
+ *   size: number of bytes.
+ */
+vchar_t *
+eay_set_random(size)
+       u_int32_t size;
+{
+       BIGNUM *r = NULL;
+       vchar_t *res = 0;
+
+       if ((r = BN_new()) == NULL)
+               goto end;
+       BN_rand(r, size * 8, 0, 0);
+       eay_bn2v(&res, r);
+
+end:
+       if (r)
+               BN_free(r);
+       return(res);
+}
+
+/* DH */
+int
+eay_dh_generate(prime, g, publen, pub, priv)
+       vchar_t *prime, **pub, **priv;
+       u_int publen;
+       u_int32_t g;
+{
+       BIGNUM *p = NULL;
+       DH *dh = NULL;
+       int error = -1;
+
+       /* initialize */
+       /* pre-process to generate number */
+       if (eay_v2bn(&p, prime) < 0)
+               goto end;
+
+       if ((dh = DH_new()) == NULL)
+               goto end;
+       dh->p = p;
+       p = NULL;       /* p is now part of dh structure */
+       dh->g = NULL;
+       if ((dh->g = BN_new()) == NULL)
+               goto end;
+       if (!BN_set_word(dh->g, g))
+               goto end;
+
+       if (publen != 0)
+               dh->length = publen;
+
+       /* generate public and private number */
+       if (!DH_generate_key(dh))
+               goto end;
+
+       /* copy results to buffers */
+       if (eay_bn2v(pub, dh->pub_key) < 0)
+               goto end;
+       if (eay_bn2v(priv, dh->priv_key) < 0) {
+               vfree(*pub);
+               goto end;
+       }
+
+       error = 0;
+
+end:
+       if (dh != NULL)
+               DH_free(dh);
+       if (p != 0)
+               BN_free(p);
+       return(error);
+}
+
+int
+eay_dh_compute(prime, g, pub, priv, pub2, key)
+       vchar_t *prime, *pub, *priv, *pub2, **key;
+       u_int32_t g;
+{
+       BIGNUM *dh_pub = NULL;
+       DH *dh = NULL;
+       int l;
+       unsigned char *v = NULL;
+       int error = -1;
+
+       /* make public number to compute */
+       if (eay_v2bn(&dh_pub, pub2) < 0)
+               goto end;
+
+       /* make DH structure */
+       if ((dh = DH_new()) == NULL)
+               goto end;
+       if (eay_v2bn(&dh->p, prime) < 0)
+               goto end;
+       if (eay_v2bn(&dh->pub_key, pub) < 0)
+               goto end;
+       if (eay_v2bn(&dh->priv_key, priv) < 0)
+               goto end;
+       dh->length = pub2->l * 8;
+
+       dh->g = NULL;
+       if ((dh->g = BN_new()) == NULL)
+               goto end;
+       if (!BN_set_word(dh->g, g))
+               goto end;
+
+       if ((v = racoon_calloc(prime->l, sizeof(u_char))) == NULL)
+               goto end;
+       if ((l = DH_compute_key(v, dh_pub, dh)) == -1)
+               goto end;
+       memcpy((*key)->v + (prime->l - l), v, l);
+
+       error = 0;
+
+end:
+       if (dh_pub != NULL)
+               BN_free(dh_pub);
+       if (dh != NULL)
+               DH_free(dh);
+       if (v != NULL)
+               racoon_free(v);
+       return(error);
+}
+
+/*
+ * convert vchar_t <-> BIGNUM.
+ *
+ * vchar_t: unit is u_char, network endian, most significant byte first.
+ * BIGNUM: unit is BN_ULONG, each of BN_ULONG is in host endian,
+ *     least significant BN_ULONG must come first.
+ *
+ * hex value of "0x3ffe050104" is represented as follows:
+ *     vchar_t: 3f fe 05 01 04
+ *     BIGNUM (BN_ULONG = u_int8_t): 04 01 05 fe 3f
+ *     BIGNUM (BN_ULONG = u_int16_t): 0x0104 0xfe05 0x003f
+ *     BIGNUM (BN_ULONG = u_int32_t_t): 0xfe050104 0x0000003f
+ */
+int
+eay_v2bn(bn, var)
+       BIGNUM **bn;
+       vchar_t *var;
+{
+       if ((*bn = BN_bin2bn((unsigned char *) var->v, var->l, NULL)) == NULL)
+               return -1;
+
+       return 0;
+}
+
+int
+eay_bn2v(var, bn)
+       vchar_t **var;
+       BIGNUM *bn;
+{
+       *var = vmalloc(bn->top * BN_BYTES);
+       if (*var == NULL)
+               return(-1);
+
+       (*var)->l = BN_bn2bin(bn, (unsigned char *) (*var)->v);
+
+       return 0;
+}
+
+void
+eay_init()
+{
+       OpenSSL_add_all_algorithms();
+       ERR_load_crypto_strings();
+#ifdef HAVE_OPENSSL_ENGINE_H
+       ENGINE_load_builtin_engines();
+       ENGINE_register_all_complete();
+#endif
+}
+
+vchar_t *
+base64_decode(char *in, long inlen)
+{
+       BIO *bio=NULL, *b64=NULL;
+       vchar_t *res = NULL;
+       char out[inlen*2];
+       long outlen;
+
+       bio = BIO_new_mem_buf(in, inlen);
+       b64 = BIO_new(BIO_f_base64());
+       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+       bio = BIO_push(b64, bio);
+
+       outlen = BIO_read(bio, out, inlen * 2);
+       if (outlen <= 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+               goto out;
+       }
+
+       res = vmalloc(outlen);
+       if (!res)
+               goto out;
+
+       memcpy(res->v, out, outlen);
+
+out:
+       if (bio)
+               BIO_free_all(bio);
+
+       return res;
+}
+
+vchar_t *
+base64_encode(char *in, long inlen)
+{
+       BIO *bio=NULL, *b64=NULL;
+       char *ptr;
+       long plen = -1;
+       vchar_t *res = NULL;
+
+       bio = BIO_new(BIO_s_mem());
+       b64 = BIO_new(BIO_f_base64());
+       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+       bio = BIO_push(b64, bio);
+
+       BIO_write(bio, in, inlen);
+       BIO_flush(bio);
+
+       plen = BIO_get_mem_data(bio, &ptr);
+       res = vmalloc(plen+1);
+       if (!res)
+               goto out;
+       
+       memcpy (res->v, ptr, plen);
+       res->v[plen] = '\0';
+
+out:   
+       if (bio)
+               BIO_free_all(bio);
+
+       return res;
+}
+
+static RSA *
+binbuf_pubkey2rsa(vchar_t *binbuf)
+{
+       BIGNUM *exp, *mod;
+       RSA *rsa_pub = NULL;
+
+       if (binbuf->v[0] > binbuf->l - 1) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: decoded string doesn't make sense.\n");
+               goto out;
+       }
+
+       exp = BN_bin2bn((unsigned char *) (binbuf->v + 1), binbuf->v[0], NULL);
+       mod = BN_bin2bn((unsigned char *) (binbuf->v + binbuf->v[0] + 1), 
+                       binbuf->l - binbuf->v[0] - 1, NULL);
+       rsa_pub = RSA_new();
+
+       if (!exp || !mod || !rsa_pub) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey parsing error: %s\n", eay_strerror());
+               if (exp)
+                       BN_free(exp);
+               if (mod)
+                       BN_free(exp);
+               if (rsa_pub)
+                       RSA_free(rsa_pub);
+               rsa_pub = NULL;
+               goto out;
+       }
+       
+       rsa_pub->n = mod;
+       rsa_pub->e = exp;
+
+out:
+       return rsa_pub;
+}
+
+RSA *
+base64_pubkey2rsa(char *in)
+{
+       BIGNUM *exp, *mod;
+       RSA *rsa_pub = NULL;
+       vchar_t *binbuf;
+
+       if (strncmp(in, "0s", 2) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: doesn't start with '0s'\n");
+               return NULL;
+       }
+
+       binbuf = base64_decode(in + 2, strlen(in + 2));
+       if (!binbuf) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: Base64 decoding failed.\n");
+               return NULL;
+       }
+       
+       if (binbuf->v[0] > binbuf->l - 1) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: decoded string doesn't make sense.\n");
+               goto out;
+       }
+
+       rsa_pub = binbuf_pubkey2rsa(binbuf);
+
+out:
+       if (binbuf)
+               vfree(binbuf);
+
+       return rsa_pub;
+}
+
+RSA *
+bignum_pubkey2rsa(BIGNUM *in)
+{
+       RSA *rsa_pub = NULL;
+       vchar_t *binbuf;
+
+       binbuf = vmalloc(BN_num_bytes(in));
+       if (!binbuf) {
+               plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey conversion: memory allocation failed..\n");
+               return NULL;
+       }
+       
+       BN_bn2bin(in, (unsigned char *) binbuf->v);
+
+       rsa_pub = binbuf_pubkey2rsa(binbuf);
+
+out:
+       if (binbuf)
+               vfree(binbuf);
+
+       return rsa_pub;
+}
+
+u_int32_t
+eay_random()
+{
+       u_int32_t result;
+       vchar_t *vrand;
+
+       vrand = eay_set_random(sizeof(result));
+       memcpy(&result, vrand->v, sizeof(result));
+       vfree(vrand);
+
+       return result;
+}
+
+const char *
+eay_version()
+{
+       return SSLeay_version(SSLEAY_VERSION);
+}
diff --git a/ipsec-tools/racoon/crypto_openssl.h b/ipsec-tools/racoon/crypto_openssl.h
new file mode 100644 (file)
index 0000000..8b71a7d
--- /dev/null
@@ -0,0 +1,229 @@
+/* $Id: crypto_openssl.h,v 1.11 2004/11/13 11:28:01 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CRYPTO_OPENSSL_H
+#define _CRYPTO_OPENSSL_H
+
+#include "crypto_openssl.h"
+
+#include <openssl/x509v3.h>
+#include <openssl/rsa.h>
+
+#define GENT_OTHERNAME GEN_OTHERNAME
+#define GENT_EMAIL     GEN_EMAIL
+#define GENT_DNS       GEN_DNS
+#define GENT_X400      GEN_X400
+#define GENT_DIRNAME   GEN_DIRNAME
+#define GENT_EDIPARTY  GEN_EDIPARTY
+#define GENT_URI       GEN_URI
+#define GENT_IPADD     GEN_IPADD
+#define GENT_RID       GEN_RID
+
+extern vchar_t *eay_str2asn1dn __P((const char *, int));
+extern vchar_t *eay_hex2asn1dn __P((const char *, int));
+extern int eay_cmp_asn1dn __P((vchar_t *, vchar_t *));
+extern int eay_check_x509cert __P((vchar_t *, char *, char *, int));
+extern vchar_t *eay_get_x509asn1subjectname __P((vchar_t *));
+#ifdef __APPLE__
+extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int, int*));
+extern vchar_t *eay_get_x509_common_name __P((vchar_t *));
+#else
+extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int));
+#endif
+extern char *eay_get_x509text __P((vchar_t *));
+extern vchar_t *eay_get_x509cert __P((char *));
+extern vchar_t *eay_get_x509sign __P((vchar_t *, vchar_t *));
+extern int eay_check_x509sign __P((vchar_t *, vchar_t *, vchar_t *));
+
+extern int eay_check_rsasign __P((vchar_t *, vchar_t *, RSA *));
+extern vchar_t *eay_get_rsasign __P((vchar_t *, RSA *));
+
+/* RSA */
+extern vchar_t *eay_rsa_sign __P((vchar_t *, RSA *));
+extern int eay_rsa_verify __P((vchar_t *, vchar_t *, RSA *));
+
+/* ASN.1 */
+extern vchar_t *eay_get_pkcs1privkey __P((char *));
+extern vchar_t *eay_get_pkcs1pubkey __P((char *));
+
+/* string error */
+extern char *eay_strerror __P((void));
+
+/* OpenSSL initialization */
+extern void eay_init __P((void));
+
+/* Generic EVP */
+extern vchar_t *evp_crypt __P((vchar_t *data, vchar_t *key, vchar_t *iv,
+                              const EVP_CIPHER *e, int enc));
+extern int evp_weakkey __P((vchar_t *key, const EVP_CIPHER *e));
+extern int evp_keylen __P((int len, const EVP_CIPHER *e));
+
+/* DES */
+extern vchar_t *eay_des_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_des_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_des_weakkey __P((vchar_t *));
+extern int eay_des_keylen __P((int));
+
+/* IDEA */
+extern vchar_t *eay_idea_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_idea_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_idea_weakkey __P((vchar_t *));
+extern int eay_idea_keylen __P((int));
+
+/* blowfish */
+extern vchar_t *eay_bf_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_bf_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_bf_weakkey __P((vchar_t *));
+extern int eay_bf_keylen __P((int));
+
+/* RC5 */
+extern vchar_t *eay_rc5_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_rc5_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_rc5_weakkey __P((vchar_t *));
+extern int eay_rc5_keylen __P((int));
+
+/* 3DES */
+extern vchar_t *eay_3des_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_3des_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_3des_weakkey __P((vchar_t *));
+extern int eay_3des_keylen __P((int));
+
+/* CAST */
+extern vchar_t *eay_cast_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_cast_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_cast_weakkey __P((vchar_t *));
+extern int eay_cast_keylen __P((int));
+
+/* AES(RIJNDAEL) */
+extern vchar_t *eay_aes_encrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *eay_aes_decrypt __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_aes_weakkey __P((vchar_t *));
+extern int eay_aes_keylen __P((int));
+
+/* misc */
+extern int eay_null_keylen __P((int));
+extern int eay_null_hashlen __P((void));
+extern int eay_kpdk_hashlen __P((void));
+extern int eay_twofish_keylen __P((int));
+
+/* hash */
+#if defined(WITH_SHA2)
+/* HMAC SHA2 */
+extern vchar_t *eay_hmacsha2_512_one __P((vchar_t *, vchar_t *));
+extern caddr_t eay_hmacsha2_512_init __P((vchar_t *));
+extern void eay_hmacsha2_512_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_hmacsha2_512_final __P((caddr_t));
+extern vchar_t *eay_hmacsha2_384_one __P((vchar_t *, vchar_t *));
+extern caddr_t eay_hmacsha2_384_init __P((vchar_t *));
+extern void eay_hmacsha2_384_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_hmacsha2_384_final __P((caddr_t));
+extern vchar_t *eay_hmacsha2_256_one __P((vchar_t *, vchar_t *));
+extern caddr_t eay_hmacsha2_256_init __P((vchar_t *));
+extern void eay_hmacsha2_256_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_hmacsha2_256_final __P((caddr_t));
+#endif
+/* HMAC SHA1 */
+extern vchar_t *eay_hmacsha1_one __P((vchar_t *, vchar_t *));
+extern caddr_t eay_hmacsha1_init __P((vchar_t *));
+extern void eay_hmacsha1_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_hmacsha1_final __P((caddr_t));
+/* HMAC MD5 */
+extern vchar_t *eay_hmacmd5_one __P((vchar_t *, vchar_t *));
+extern caddr_t eay_hmacmd5_init __P((vchar_t *));
+extern void eay_hmacmd5_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_hmacmd5_final __P((caddr_t));
+
+#if defined(WITH_SHA2)
+/* SHA2 functions */
+extern caddr_t eay_sha2_512_init __P((void));
+extern void eay_sha2_512_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_sha2_512_final __P((caddr_t));
+extern vchar_t *eay_sha2_512_one __P((vchar_t *));
+#endif
+extern int eay_sha2_512_hashlen __P((void));
+
+#if defined(WITH_SHA2)
+extern caddr_t eay_sha2_384_init __P((void));
+extern void eay_sha2_384_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_sha2_384_final __P((caddr_t));
+extern vchar_t *eay_sha2_384_one __P((vchar_t *));
+#endif
+extern int eay_sha2_384_hashlen __P((void));
+
+#if defined(WITH_SHA2)
+extern caddr_t eay_sha2_256_init __P((void));
+extern void eay_sha2_256_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_sha2_256_final __P((caddr_t));
+extern vchar_t *eay_sha2_256_one __P((vchar_t *));
+#endif
+extern int eay_sha2_256_hashlen __P((void));
+
+/* SHA functions */
+extern caddr_t eay_sha1_init __P((void));
+extern void eay_sha1_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_sha1_final __P((caddr_t));
+extern vchar_t *eay_sha1_one __P((vchar_t *));
+extern int eay_sha1_hashlen __P((void));
+
+/* MD5 functions */
+extern caddr_t eay_md5_init __P((void));
+extern void eay_md5_update __P((caddr_t, vchar_t *));
+extern vchar_t *eay_md5_final __P((caddr_t));
+extern vchar_t *eay_md5_one __P((vchar_t *));
+extern int eay_md5_hashlen __P((void));
+
+/* RNG */
+extern vchar_t *eay_set_random __P((u_int32_t));
+extern u_int32_t eay_random __P((void));
+
+/* DH */
+extern int eay_dh_generate __P((vchar_t *, u_int32_t, u_int, vchar_t **, vchar_t **));
+extern int eay_dh_compute __P((vchar_t *, u_int32_t, vchar_t *, vchar_t *, vchar_t *, vchar_t **));
+
+/* Base 64 */
+vchar_t *base64_encode(char *in, long inlen);
+vchar_t *base64_decode(char *in, long inlen);
+
+RSA *base64_pubkey2rsa(char *in);
+RSA *bignum_pubkey2rsa(BIGNUM *in);
+
+/* misc */
+extern int eay_revbnl __P((vchar_t *));
+#include <openssl/bn.h>
+extern int eay_v2bn __P((BIGNUM **, vchar_t *));
+extern int eay_bn2v __P((vchar_t **, BIGNUM *));
+
+extern const char *eay_version __P((void));
+
+#define CBC_BLOCKLEN 8
+#define IPSEC_ENCRYPTKEYLEN 8
+
+#endif /* _CRYPTO_OPENSSL_H */
diff --git a/ipsec-tools/racoon/debug.h b/ipsec-tools/racoon/debug.h
new file mode 100644 (file)
index 0000000..7fd45f2
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: debug.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+/* define by main.c */
+extern int f_local;
+extern int vflag;
+
+#endif /* _DEBUG_H */
diff --git a/ipsec-tools/racoon/debugrm.h b/ipsec-tools/racoon/debugrm.h
new file mode 100644 (file)
index 0000000..3dec6cd
--- /dev/null
@@ -0,0 +1,92 @@
+/* $Id: debugrm.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEBUGRM_H
+#define _DEBUGRM_H
+
+#define DRMDUMPFILE    "/var/tmp/debugrm.dump"
+
+#ifdef NONEED_DRM
+#ifndef racoon_malloc
+#define        racoon_malloc(sz)       malloc((sz))
+#endif
+#ifndef racoon_calloc
+#define        racoon_calloc(cnt, sz)  calloc((cnt), (sz))
+#endif
+#ifndef racoon_realloc
+#define        racoon_realloc(old, sz) realloc((old), (sz))
+#endif
+#ifndef racoon_free
+#define        racoon_free(p)          free((p))
+#endif
+#else /*!NONEED_DRM*/
+#ifndef racoon_malloc
+#define        racoon_malloc(sz)       \
+       DRM_malloc(__FILE__, __LINE__, __func__, (sz))
+#endif
+#ifndef racoon_calloc
+#define        racoon_calloc(cnt, sz)  \
+       DRM_calloc(__FILE__, __LINE__, __func__, (cnt), (sz))
+#endif
+#ifndef racoon_realloc
+#define        racoon_realloc(old, sz) \
+       DRM_realloc(__FILE__, __LINE__, __func__, (old), (sz))
+#endif
+#ifndef racoon_free
+#define        racoon_free(p)          \
+       DRM_free(__FILE__, __LINE__, __func__, (p))
+#endif
+#endif /*NONEED_DRM*/
+
+extern void DRM_init __P((void));
+extern void DRM_dump __P((void));
+extern void *DRM_malloc __P((char *, int, char *, size_t));
+extern void *DRM_calloc __P((char *, int, char *, size_t, size_t));
+extern void *DRM_realloc __P((char *, int, char *, void *, size_t));
+extern void DRM_free __P((char *, int, char *, void *));
+
+#ifndef NONEED_DRM
+#define        vmalloc(sz)     \
+       DRM_vmalloc(__FILE__, __LINE__, __func__, (sz))
+#define        vdup(old)       \
+       DRM_vdup(__FILE__, __LINE__, __func__, (old))
+#define        vrealloc(old, sz)       \
+       DRM_vrealloc(__FILE__, __LINE__, __func__, (old), (sz))
+#define        vfree(p)                \
+       DRM_vfree(__FILE__, __LINE__, __func__, (p))
+#endif
+
+extern void *DRM_vmalloc __P((char *, int, char *, size_t));
+extern void *DRM_vrealloc __P((char *, int, char *, void *, size_t));
+extern void DRM_vfree __P((char *, int, char *, void *));
+extern void *DRM_vdup __P((char *, int, char *, void *));
+
+#endif /* _DEBUGRM_H */
diff --git a/ipsec-tools/racoon/dhgroup.h b/ipsec-tools/racoon/dhgroup.h
new file mode 100644 (file)
index 0000000..8f65583
--- /dev/null
@@ -0,0 +1,203 @@
+/* $Id: dhgroup.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DHGROUP_H
+#define _DHGROUP_H
+
+#define OAKLEY_PRIME_MODP768 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP1024 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" \
+       "FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP1536 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF"
+
+/* RFC 3526 */
+#define OAKLEY_PRIME_MODP2048 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+       "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+       "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+       "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP3072 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+       "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+       "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+       "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+       "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+       "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+       "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+       "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+       "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP4096 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+       "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+       "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+       "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+       "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+       "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+       "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+       "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+       "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+       "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+       "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+       "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+       "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+       "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \
+       "FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP6144 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+       "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+       "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+       "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+       "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+       "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+       "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+       "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+       "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+       "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+       "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+       "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+       "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+       "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+       "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \
+       "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \
+       "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \
+       "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \
+       "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \
+       "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \
+       "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+       "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \
+       "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \
+       "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \
+       "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF"
+
+#define OAKLEY_PRIME_MODP8192 \
+       "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+       "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+       "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+       "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+       "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+       "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+       "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+       "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+       "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+       "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+       "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+       "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+       "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+       "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+       "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+       "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+       "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+       "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+       "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+       "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+       "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+       "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \
+       "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \
+       "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \
+       "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \
+       "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \
+       "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \
+       "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+       "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \
+       "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \
+       "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \
+       "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \
+       "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \
+       "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \
+       "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \
+       "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \
+       "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \
+       "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \
+       "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \
+       "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \
+       "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \
+       "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \
+       "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF"
+
+extern struct dhgroup dh_modp768;
+extern struct dhgroup dh_modp1024;
+extern struct dhgroup dh_modp1536;
+extern struct dhgroup dh_modp2048;
+extern struct dhgroup dh_modp3072;
+extern struct dhgroup dh_modp4096;
+extern struct dhgroup dh_modp6144;
+extern struct dhgroup dh_modp8192;
+
+#endif /* _DHGROUP_H */
diff --git a/ipsec-tools/racoon/dnssec.c b/ipsec-tools/racoon/dnssec.c
new file mode 100644 (file)
index 0000000..2f1dc25
--- /dev/null
@@ -0,0 +1,149 @@
+/*     $KAME: dnssec.c,v 1.2 2001/08/05 18:46:07 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "var.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "netdb_dnssec.h"
+#include "strnames.h"
+#include "dnssec.h"
+#include "gcmalloc.h"
+
+extern int h_errno;
+
+cert_t *
+dnssec_getcert(id)
+       vchar_t *id;
+{
+       cert_t *cert = NULL;
+       struct certinfo *res = NULL;
+       struct ipsecdoi_id_b *id_b;
+       int type;
+       char *name = NULL;
+       int namelen;
+       int error;
+
+       id_b = (struct ipsecdoi_id_b *)id->v;
+
+       namelen = id->l - sizeof(*id_b);
+       name = racoon_malloc(namelen + 1);
+       if (!name) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer.\n");
+               return NULL;
+       }
+       memcpy(name, id_b + 1, namelen);
+       name[namelen] = '\0';
+
+       switch (id_b->type) {
+       case IPSECDOI_ID_FQDN:
+               error = getcertsbyname(name, &res);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "getcertsbyname(\"%s\") failed.\n", name);
+                       goto err;
+               }
+               break;
+       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV6_ADDR:
+               /* XXX should be processed to query PTR ? */
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "impropper ID type passed %s "
+                       "though getcert method is dnssec.\n",
+                       s_ipsecdoi_ident(id_b->type));
+               return NULL;
+       }
+
+       /* check response */
+       if (res->ci_next != NULL) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "not supported multiple CERT RR.\n");
+       }
+       switch (res->ci_type) {
+       case DNSSEC_TYPE_PKIX:
+               /* XXX is it enough condition to set this type ? */
+               type = ISAKMP_CERT_X509SIGN;
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not supported CERT RR type %d.\n", res->ci_type);
+               goto err;
+       }
+
+       /* create cert holder */
+       cert = oakley_newcert();
+       if (cert == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cert buffer.\n");
+               goto err;
+       }
+       cert->pl = vmalloc(res->ci_certlen + 1);
+       if (cert->pl == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cert buffer.\n");
+               goto err;
+       }
+       memcpy(cert->pl->v + 1, res->ci_cert, res->ci_certlen);
+       cert->pl->v[0] = type;
+       cert->cert.v = cert->pl->v + 1;
+       cert->cert.l = cert->pl->l - 1;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n");
+       plogdump(LLV_DEBUG, cert->pl->v, cert->pl->l);
+
+end:
+       if (res)
+               freecertinfo(res);
+
+       return cert;
+
+err:
+       if (name)
+               racoon_free(name);
+       if (cert)
+               oakley_delcert(cert);
+       goto end;
+}
diff --git a/ipsec-tools/racoon/dnssec.h b/ipsec-tools/racoon/dnssec.h
new file mode 100644 (file)
index 0000000..e43ed81
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id: dnssec.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DNSSEC_H
+#define _DNSSEC_H
+
+extern cert_t *dnssec_getcert __P((vchar_t *));
+
+#endif /* _DNSSEC_H */
diff --git a/ipsec-tools/racoon/dump.h b/ipsec-tools/racoon/dump.h
new file mode 100644 (file)
index 0000000..7473bbc
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: dump.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#ifndef _DUMP_H
+#define _DUMP_H
+
+extern int isakmp_dump_open __P((char *));
+extern int isakmp_dump_close __P((void));
+extern int isakmp_dump __P((vchar_t *, struct sockaddr *, struct sockaddr *));
+
+#endif /* _DUMP_H */
diff --git a/ipsec-tools/racoon/eaytest.c b/ipsec-tools/racoon/eaytest.c
new file mode 100644 (file)
index 0000000..3265546
--- /dev/null
@@ -0,0 +1,1077 @@
+/* $Id: eaytest.c,v 1.20.4.2 2005/06/28 22:38:02 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#include "var.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "debug.h"
+#include "str2val.h"
+#include "plog.h"
+
+#include "oakley.h"
+#include "dhgroup.h"
+#include "crypto_openssl.h"
+#include "gnuc.h"
+
+//#include "package_version.h"
+
+#define PVDUMP(var) hexdump((var)->v, (var)->l)
+
+/*#define CERTTEST_BROKEN */
+
+/* prototype */
+
+static vchar_t *pem_read_buf __P((char *));
+void Usage __P((void));
+
+int rsatest __P((int, char **));
+int ciphertest __P((int, char **));
+int hmactest __P((int, char **));
+int sha1test __P((int, char **));
+int md5test __P((int, char **));
+int dhtest __P((int, char **));
+int bntest __P((int, char **));
+#ifndef CERTTEST_BROKEN
+static char **getcerts __P((char *));
+int certtest __P((int, char **));
+#endif
+
+/* test */
+
+static int
+rsa_verify_with_pubkey(src, sig, pubkey_txt)
+       vchar_t *src, *sig;
+       char *pubkey_txt;
+{
+       BIO *bio;
+       EVP_PKEY *evp;
+       int error;
+
+       bio = BIO_new_mem_buf(pubkey_txt, strlen(pubkey_txt));
+       evp = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+       if (! evp) {
+               printf ("PEM_read_PUBKEY(): %s\n", eay_strerror());
+               return -1;
+       }
+       error = eay_check_rsasign(src, sig, evp->pkey.rsa);
+
+       return error;
+}
+
+int
+rsatest(ac, av)
+       int ac;
+       char **av;
+{
+       char *text = "this is test.";
+       vchar_t src;
+       vchar_t *priv, *sig;
+       int loglevel_saved;
+
+       char *pkcs1 =
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQChe5/Fzk9SA0vCKBOcu9jBcLb9oLv50PeuEfQojhakY+OH8A3Q\n"
+"M8A0qIDG6uhTNGPvzCWb/+mKeOB48n5HJpLxlDFyP3kyd2yXHIZ/MN8g1nh4FsB0\n"
+"iTkk8QUCJkkan6FCOBrIeLEsGA5AdodzuR+khnCMt8vO+NFHZYKAQeynyQIDAQAB\n"
+"AoGAOfDcnCHxjhDGrwyoNNWl6Yqi7hAtQm67YAbrH14UO7nnmxAENM9MyNgpFLaW\n"
+"07v5m8IZQIcradcDXAJOUwNBN8E06UflwEYCaScIwndvr5UpVlN3e2NC6Wyg2yC7\n"
+"GarxQput3zj35XNR5bK42UneU0H6zDxpHWqI1SwE+ToAHu0CQQDNl9gUJTpg0L09\n"
+"HkbE5jeb8bA5I20nKqBOBP0v5tnzpwu41umQwk9I7Ru0ucD7j+DW4k8otadW+FnI\n"
+"G1M1MpSjAkEAyRMt4bN8otfpOpsOQWzw4jQtouohOxRFCrQTntHhU20PrQnQLZWs\n"
+"pOVzqCjRytYtkPEUA1z8QK5gGcVPcOQsowJBALmt2rwPB1NrEo5Bat7noO+Zb3Ob\n"
+"WDiYWeE8xkHd95gDlSWiC53ur9aINo6ZeP556jGIgL+el/yHHecJLrQL84sCQH48\n"
+"zUxq/C/cb++8UzneJGlPqusiJNTLiAENR1gpmlZfHT1c8Nb9phMsfu0vG29GAfuC\n"
+"bzchVLljALCNQK+2gRMCQQCNIgN+R9mRWZhFAcC1sq++YnuSBlw4VwdL/fd1Yg9e\n"
+"Ul+U98yPl/NXt8Rs4TRBFcOZjkFI8xv0hQtevTgTmgz+\n"
+"-----END RSA PRIVATE KEY-----\n\n";
+       char *pubkey =
+"-----BEGIN PUBLIC KEY-----\n"
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChe5/Fzk9SA0vCKBOcu9jBcLb9\n"
+"oLv50PeuEfQojhakY+OH8A3QM8A0qIDG6uhTNGPvzCWb/+mKeOB48n5HJpLxlDFy\n"
+"P3kyd2yXHIZ/MN8g1nh4FsB0iTkk8QUCJkkan6FCOBrIeLEsGA5AdodzuR+khnCM\n"
+"t8vO+NFHZYKAQeynyQIDAQAB\n"
+"-----END PUBLIC KEY-----\n\n";
+       char *pubkey_wrong = 
+"-----BEGIN PUBLIC KEY-----\n"
+"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwDncG2tSokRBhK8la1mO\n"
+"QnUpxg6KvpoFUjEyRiIE1GRap5V6jCCEOmA9ZAz4Oa/97oxewwMWtchIxSBZVCia\n"
+"H9oGasbOFzrtSR+MKl6Cb/Ow3Fu+PKbHTsnfTk/nOOWyaQh91PRD7fdwHe8L9P7w\n"
+"2kFPmDW6+RNKIR4OErhXf1O0eSShPe0TO3vx43O7dWqhmh3Kgr4Jq7zAGqHtwu0B\n"
+"RFZnmsocOnVZb2yAHndp51/Mk1H37ThHwN7qMx7RqrS3ru3XtchpJd9IQJPBIRfY\n"
+"VYQ68u5ix/Z80Y6VkRf0qnAvel8B6D3N3Zyq5u7G60PfvvtCybeMn7nVrSMxqMW/\n"
+"xwIDAQAB\n"
+"-----END PUBLIC KEY-----\n\n";
+
+       printf ("%s", pkcs1);
+       printf ("%s", pubkey);
+       priv = pem_read_buf(pkcs1);
+
+       src.v = text;
+       src.l = strlen(text);
+
+       /* sign */
+       sig = eay_get_x509sign(&src, priv);
+       if (sig == NULL) {
+               printf("sign failed. %s\n", eay_strerror());
+               return -1;
+       }
+
+       printf("RSA signed data.\n");
+       PVDUMP(sig);
+
+       printf("Verification with correct pubkey: ");
+       if (rsa_verify_with_pubkey (&src, sig, pubkey) != 0) {
+               printf ("Failed.\n");
+               return -1;
+       }
+       else
+               printf ("Verified. Good.\n");
+
+       loglevel_saved = loglevel;
+       loglevel = 0;
+       printf("Verification with wrong pubkey: ");
+       if (rsa_verify_with_pubkey (&src, sig, pubkey_wrong) != 0)
+               printf ("Not verified. Good.\n");
+       else {
+               printf ("Verified. This is bad...\n");
+               loglevel = loglevel_saved;
+               return -1;
+       }
+       loglevel = loglevel_saved;
+
+       return 0;
+}
+
+static vchar_t *
+pem_read_buf(buf)
+       char *buf;
+{
+       BIO *bio;
+       char *nm = NULL, *header = NULL;
+       unsigned char *data = NULL;
+       long len;
+       vchar_t *ret;
+       int error;
+
+       bio = BIO_new_mem_buf(buf, strlen(buf));
+       error = PEM_read_bio(bio, &nm, &header, &data, &len);
+       if (error == 0)
+               errx(1, "%s", eay_strerror());
+       ret = vmalloc(len);
+       if (ret == NULL)
+               err(1, "vmalloc");
+       memcpy(ret->v, data, len);
+
+       return ret;
+}
+
+#ifndef CERTTEST_BROKEN
+int
+certtest(ac, av)
+       int ac;
+       char **av;
+{
+       char *certpath;
+       char **certs;
+       int type;
+       int error;
+
+       printf("\n**Test for Certificate.**\n");
+
+    {
+       vchar_t *asn1dn = NULL, asn1dn0;
+#ifdef ORIG_DN
+       char dnstr[] = "C=JP, ST=Kanagawa, L=Fujisawa, O=WIDE Project, OU=KAME Project, CN=Shoichi Sakane/Email=sakane@kame.net";
+       char *dnstr_w1 = 0;
+       char *dnstr_w2 = 0;
+       char dn0[] = {
+               0x30,0x81,0x9a,0x31,0x0b,0x30,0x09,0x06,
+               0x03,0x55,0x04,0x06,0x13,0x02,0x4a,0x50,
+               0x31,0x11,0x30,0x0f,0x06,0x03,0x55,0x04,
+               0x08,0x13,0x08,0x4b,0x61,0x6e,0x61,0x67,
+               0x61,0x77,0x61,0x31,0x11,0x30,0x0f,0x06,
+               0x03,0x55,0x04,0x07,0x13,0x08,0x46,0x75,
+               0x6a,0x69,0x73,0x61,0x77,0x61,0x31,0x15,
+               0x30,0x13,0x06,0x03,0x55,0x04,0x0a,0x13,
+               0x0c,0x57,0x49,0x44,0x45,0x20,0x50,0x72,
+               0x6f,0x6a,0x65,0x63,0x74,0x31,0x15,0x30,
+               0x13,0x06,0x03,0x55,0x04,0x0b,0x13,0x0c,
+               0x4b,0x41,0x4d,0x45,0x20,0x50,0x72,0x6f,
+               0x6a,0x65,0x63,0x74,0x31,0x17,0x30,0x15,
+               0x06,0x03,0x55,0x04,0x03,0x13,0x0e,0x53,
+               0x68,0x6f,0x69,0x63,0x68,0x69,0x20,0x53,
+               0x61,0x6b,0x61,0x6e,0x65,0x31,0x1e,0x30,
+               0x1c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+               0x0d,0x01,0x09,0x01,
+               0x0c,   /* <== XXX */
+               0x0f,0x73,0x61,
+               0x6b,0x61,0x6e,0x65,0x40,0x6b,0x61,0x6d,
+               0x65,0x2e,0x6e,0x65,0x74,
+       };
+#else /* not ORIG_DN */
+       char dnstr[] = "C=JP, ST=Kanagawa, L=Fujisawa, O=WIDE Project, OU=KAME Project, CN=Shoichi Sakane";
+       char dnstr_w1[] = "C=JP, ST=Kanagawa, L=Fujisawa, O=WIDE Project, OU=*, CN=Shoichi Sakane";
+       char dnstr_w2[] = "C=JP, ST=Kanagawa, L=Fujisawa, O=WIDE Project, OU=KAME Project, CN=*";
+       char dn0[] = {
+               0x30,0x7a,0x31,0x0b,0x30,0x09,0x06,0x03,
+               0x55,0x04,0x06,0x13,0x02,0x4a,0x50,0x31,
+               0x11,0x30,0x0f,0x06,0x03,0x55,0x04,0x08,
+               0x13,0x08,0x4b,0x61,0x6e,0x61,0x67,0x61,
+               0x77,0x61,0x31,0x11,0x30,0x0f,0x06,0x03,
+               0x55,0x04,0x07,0x13,0x08,0x46,0x75,0x6a,
+               0x69,0x73,0x61,0x77,0x61,0x31,0x15,0x30,
+               0x13,0x06,0x03,0x55,0x04,0x0a,0x13,0x0c,
+               0x57,0x49,0x44,0x45,0x20,0x50,0x72,0x6f,
+               0x6a,0x65,0x63,0x74,0x31,0x15,0x30,0x13,
+               0x06,0x03,0x55,0x04,0x0b,0x13,0x0c,0x4b,
+               0x41,0x4d,0x45,0x20,0x50,0x72,0x6f,0x6a,
+               0x65,0x63,0x74,0x31,0x17,0x30,0x15,0x06,
+               0x03,0x55,0x04,0x03,0x13,0x0e,0x53,0x68,
+               0x6f,0x69,0x63,0x68,0x69,0x20,0x53,0x61,
+               0x6b,0x61,0x6e,0x65,
+       };
+#endif /* ORIG_DN */
+
+       printf("check to convert the string into subjectName.\n");
+       printf("%s\n", dnstr);
+
+       asn1dn0.v = dn0;
+       asn1dn0.l = sizeof(dn0);
+
+       asn1dn = eay_str2asn1dn(dnstr, strlen(dnstr));
+       if (asn1dn == NULL || asn1dn->l != asn1dn0.l)
+#ifdef OUTPUT_VALID_ASN1DN
+       {
+               unsigned char *cp; int  i;
+               printf("asn1dn length mismatched (%zu != %zu).\n", asn1dn ? asn1dn->l : -1, asn1dn0.l);
+               for (cp = asn1dn->v, i = 0; i < asn1dn->l; i++)
+                   printf ("0x%02x,", *cp++);
+               exit (1);
+       }
+#else
+               errx(1, "asn1dn length mismatched (%zu != %zu).\n", asn1dn ? asn1dn->l : -1, asn1dn0.l);
+#endif
+
+       /*
+        * NOTE: The value pointed by "<==" above is different from the
+        * return of eay_str2asn1dn().  but eay_cmp_asn1dn() can distinguish
+        * both of the names are same name.
+        */
+       if (eay_cmp_asn1dn(&asn1dn0,  asn1dn))
+               errx(1, "asn1dn mismatched.\n");
+       vfree(asn1dn);
+
+       printf("exact match: succeed.\n");
+
+       if (dnstr_w1) {
+               asn1dn = eay_str2asn1dn(dnstr_w1, strlen(dnstr_w1));
+               if (asn1dn == NULL || asn1dn->l == asn1dn0.l)
+                       errx(1, "asn1dn length wrong for wildcard 1\n");
+               if (eay_cmp_asn1dn(&asn1dn0,  asn1dn))
+                       errx(1, "asn1dn mismatched for wildcard 1.\n");
+               vfree(asn1dn);
+               printf("wildcard 1 match: succeed.\n");
+       }
+
+       if (dnstr_w1) {
+               asn1dn = eay_str2asn1dn(dnstr_w2, strlen(dnstr_w2));
+               if (asn1dn == NULL || asn1dn->l == asn1dn0.l)
+                       errx(1, "asn1dn length wrong for wildcard 2\n");
+               if (eay_cmp_asn1dn(&asn1dn0,  asn1dn))
+                       errx(1, "asn1dn mismatched for wildcard 2.\n");
+               vfree(asn1dn);
+               printf("wildcard 2 match: succeed.\n");
+       }
+
+    }
+       eay_init();
+
+       /* get certs */
+       if (ac > 1) {
+               certpath = *(av + 1);
+               certs = getcerts(certpath);
+       } else {
+#ifdef ORIG_DN
+               printf("\nCAUTION: These certificates are probably invalid "
+                       "on your environment because you don't have their "
+                       "issuer's certs in your environment.\n\n");
+
+               certpath = "/usr/local/openssl/certs";
+               certs = getcerts(NULL);
+#else
+               printf("\nWARNING: The main certificates are probably invalid "
+                       "on your environment\nbecause you don't have their "
+                       "issuer's certs in your environment\nso not doing "
+                       "this test.\n\n");
+               return (0);
+#endif
+       }
+
+       while (*certs != NULL) {
+
+               vchar_t c;
+               char *str;
+               vchar_t *vstr;
+
+               printf("===CERT===\n");
+
+               c.v = *certs;
+               c.l = strlen(*certs);
+
+               /* print text */
+               str = eay_get_x509text(&c);
+               printf("%s", str);
+               racoon_free(str);
+
+               /* print ASN.1 of subject name */
+               vstr = eay_get_x509asn1subjectname(&c);
+               if (!vstr)
+                       return 0;
+               PVDUMP(vstr);
+               printf("\n");
+               vfree(vstr);
+
+#ifdef __APPLE__
+               /* print subject alt name */
+           {
+               int pos;
+               int len;
+               for (pos = 1; ; pos++) {
+                       error = eay_get_x509subjectaltname(&c, &str, &type, pos, &len);
+                       if (error) {
+                               printf("no subjectaltname found.\n");
+                               break;
+                       }
+                       if (!str)
+                               break;
+                       printf("SubjectAltName: %d: %s\n", type, str);
+                       racoon_free(str);
+               }
+           }
+#else
+               /* print subject alt name */
+           {
+               int pos;
+               for (pos = 1; ; pos++) {
+                       error = eay_get_x509subjectaltname(&c, &str, &type, pos);
+                       if (error) {
+                               printf("no subjectaltname found.\n");
+                               break;
+                       }
+                       if (!str)
+                               break;
+                       printf("SubjectAltName: %d: %s\n", type, str);
+                       racoon_free(str);
+               }
+           }
+#endif         
+
+               /* NULL => name of the certificate file */
+               error = eay_check_x509cert(&c, certpath, NULL, 1);
+               if (error)
+                       printf("ERROR: cert is invalid.\n");
+               printf("\n");
+
+               certs++;
+       }
+       return 0;
+}
+
+static char **
+getcerts(path)
+       char *path;
+{
+       char **certs = NULL, **p;
+       DIR *dirp;
+       struct dirent *dp;
+       struct stat sb;
+       char buf[512];
+       int len;
+       int n;
+       int fd;
+
+       static char *samplecerts[] = {
+/* self signed */
+"-----BEGIN CERTIFICATE-----\n"
+"MIICpTCCAg4CAQAwDQYJKoZIhvcNAQEEBQAwgZoxCzAJBgNVBAYTAkpQMREwDwYD\n"
+"VQQIEwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUg\n"
+"UHJvamVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hp\n"
+"IFNha2FuZTEeMBwGCSqGSIb3DQEJARYPc2FrYW5lQGthbWUubmV0MB4XDTAwMDgy\n"
+"NDAxMzc0NFoXDTAwMDkyMzAxMzc0NFowgZoxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n"
+"EwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUgUHJv\n"
+"amVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hpIFNh\n"
+"a2FuZTEeMBwGCSqGSIb3DQEJARYPc2FrYW5lQGthbWUubmV0MIGfMA0GCSqGSIb3\n"
+"DQEBAQUAA4GNADCBiQKBgQCpIQG/H3zn4czAmPBcbkDrYxE1A9vcpghpib3Of0Op\n"
+"SsiWIBOyIMiVAzK/I/JotWp3Vdn5fzGp/7DGAbWXAALas2xHkNmTMPpu6qhmNQ57\n"
+"kJHZHal24mgc1hwbrI9fb5olvIexx9a1riNPnKMRVHzXYizsyMbf+lJJmZ8QFhWN\n"
+"twIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACKs6X/BYycuHI3iop403R3XWMHHnNBN\n"
+"5XTHVWiWgR1cMWkq/dp51gn+nPftpdAaYGpqGkiHGhZcXLoBaX9uON3p+7av+sQN\n"
+"plXwnvUf2Zsgu+fojskS0gKcDlYiq1O8TOaBgJouFZgr1q6PiYjVEJGogAP28+HN\n"
+"M4o+GBFbFoqK\n"
+"-----END CERTIFICATE-----\n\n",
+/* signed by SSH testing CA + CA1 + CA2 */
+"-----BEGIN X509 CERTIFICATE-----\n"
+"MIICtTCCAj+gAwIBAgIEOaR8NjANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJG\n"
+"STEkMCIGA1UEChMbU1NIIENvbW11bmljYXRpb25zIFNlY3VyaXR5MREwDwYDVQQL\n"
+"EwhXZWIgdGVzdDEbMBkGA1UEAxMSVGVzdCBDQSAxIHN1YiBjYSAyMB4XDTAwMDgy\n"
+"NDAwMDAwMFoXDTAwMTAwMTAwMDAwMFowgZoxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n"
+"EwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUgUHJv\n"
+"amVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hpIFNh\n"
+"a2FuZTEeMBwGCSqGSIb3DQEJAQwPc2FrYW5lQGthbWUubmV0MIGfMA0GCSqGSIb3\n"
+"DQEBAQUAA4GNADCBiQKBgQCpIQG/H3zn4czAmPBcbkDrYxE1A9vcpghpib3Of0Op\n"
+"SsiWIBOyIMiVAzK/I/JotWp3Vdn5fzGp/7DGAbWXAALas2xHkNmTMPpu6qhmNQ57\n"
+"kJHZHal24mgc1hwbrI9fb5olvIexx9a1riNPnKMRVHzXYizsyMbf+lJJmZ8QFhWN\n"
+"twIDAQABo18wXTALBgNVHQ8EBAMCBaAwGgYDVR0RBBMwEYEPc2FrYW5lQGthbWUu\n"
+"bmV0MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9sZGFwLnNzaC5maS9jcmxzL2Nh\n"
+"MS0yLmNybDANBgkqhkiG9w0BAQUFAANhADtaqual41OWshF/rwCTuR6zySBJysGp\n"
+"+qjkp5efCiYKhAu1L4WXlMsV/SNdzspui5tHasPBvUw8gzFsU/VW/B2zuQZkimf1\n"
+"u6ZPjUb/vt8vLOPScP5MeH7xrTk9iigsqQ==\n"
+"-----END X509 CERTIFICATE-----\n\n",
+/* VP100 */
+"-----BEGIN CERTIFICATE-----\n"
+"MIICXzCCAcigAwIBAgIEOXGBIzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJG\n"
+"STEkMCIGA1UEChMbU1NIIENvbW11bmljYXRpb25zIFNlY3VyaXR5MREwDwYDVQQL\n"
+"EwhXZWIgdGVzdDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTAwMDcxNjAwMDAwMFoX\n"
+"DTAwMDkwMTAwMDAwMFowNTELMAkGA1UEBhMCanAxETAPBgNVBAoTCHRhaGl0ZXN0\n"
+"MRMwEQYDVQQDEwpmdXJ1a2F3YS0xMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKB\n"
+"gQDUmI2RaAuoLvtRDbASwRhbkj/Oq0BBIKgAqbFknc/EanJSQwZQu82gD88nf7gG\n"
+"VEioWmKPLDuEjz5JCuM+k5f7HYHI1wWmz1KFr7UA+avZm4Kp6YKnhuH7soZp7kBL\n"
+"hTiZEpL0jdmCWLW3ZXoro55rmPrBsCd+bt8VU6tRZm5dUwIBKaNZMFcwCwYDVR0P\n"
+"BAQDAgWgMBYGA1UdEQQPMA2CBVZQMTAwhwQKFIaFMDAGA1UdHwQpMCcwJaAjoCGG\n"
+"H2h0dHA6Ly9sZGFwLnNzaC5maS9jcmxzL2NhMS5jcmwwDQYJKoZIhvcNAQEFBQAD\n"
+"gYEAKJ/2Co/KYW65mwpGG3CBvsoRL8xyUMHGt6gQpFLHiiHuAdix1ADTL6uoFuYi\n"
+"4sE5omQm1wKVv2ZhS03zDtUfKoVEv0HZ7IY3AU/FZT/M5gQvbt43Dki/ma3ock2I\n"
+"PPhbLsvXm+GCVh3jvkYGk1zr7VERVeTPtmT+hW63lcxfFp4=\n"
+"-----END CERTIFICATE-----\n\n",
+/* IKED */
+"-----BEGIN CERTIFICATE-----\n"
+"MIIEFTCCA7+gAwIBAgIKYU5X6AAAAAAACTANBgkqhkiG9w0BAQUFADCBljEpMCcG\n"
+"CSqGSIb3DQEJARYaeS13YXRhbmFAc2RsLmhpdGFjaGkuY28uanAxCzAJBgNVBAYT\n"
+"AkpQMREwDwYDVQQIEwhLQU5BR0FXQTERMA8GA1UEBxMIWW9rb2hhbWExEDAOBgNV\n"
+"BAoTB0hJVEFDSEkxDDAKBgNVBAsTA1NETDEWMBQGA1UEAxMNSVBzZWMgVGVzdCBD\n"
+"QTAeFw0wMDA3MTUwMjUxNDdaFw0wMTA3MTUwMzAxNDdaMEUxCzAJBgNVBAYTAkpQ\n"
+"MREwDwYDVQQIEwhLQU5BR0FXQTEQMA4GA1UEChMHSElUQUNISTERMA8GA1UEAxMI\n"
+"V0FUQU5BQkUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA6Wja5A7Ldzrtx+rMWHEB\n"
+"Cyt+/ZoG0qdFQbuuUiU1vOSq+1f+ZSCYAdTq13Lrr6Xfz3jDVFEZLPID9PSTFwq+\n"
+"yQIDAQABo4ICPTCCAjkwDgYDVR0PAQH/BAQDAgTwMBMGA1UdJQQMMAoGCCsGAQUF\n"
+"CAICMB0GA1UdDgQWBBTkv7/MH5Ra+S1zBAmnUIH5w8ZTUTCB0gYDVR0jBIHKMIHH\n"
+"gBQsF2qoaTl5F3GFLKrttaxPJ8j4faGBnKSBmTCBljEpMCcGCSqGSIb3DQEJARYa\n"
+"eS13YXRhbmFAc2RsLmhpdGFjaGkuY28uanAxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n"
+"EwhLQU5BR0FXQTERMA8GA1UEBxMIWW9rb2hhbWExEDAOBgNVBAoTB0hJVEFDSEkx\n"
+"DDAKBgNVBAsTA1NETDEWMBQGA1UEAxMNSVBzZWMgVGVzdCBDQYIQeccIf4GYDIBA\n"
+"rS6HSUt8XjB7BgNVHR8EdDByMDagNKAyhjBodHRwOi8vZmxvcmEyMjAvQ2VydEVu\n"
+"cm9sbC9JUHNlYyUyMFRlc3QlMjBDQS5jcmwwOKA2oDSGMmZpbGU6Ly9cXGZsb3Jh\n"
+"MjIwXENlcnRFbnJvbGxcSVBzZWMlMjBUZXN0JTIwQ0EuY3JsMIGgBggrBgEFBQcB\n"
+"AQSBkzCBkDBFBggrBgEFBQcwAoY5aHR0cDovL2Zsb3JhMjIwL0NlcnRFbnJvbGwv\n"
+"ZmxvcmEyMjBfSVBzZWMlMjBUZXN0JTIwQ0EuY3J0MEcGCCsGAQUFBzAChjtmaWxl\n"
+"Oi8vXFxmbG9yYTIyMFxDZXJ0RW5yb2xsXGZsb3JhMjIwX0lQc2VjJTIwVGVzdCUy\n"
+"MENBLmNydDANBgkqhkiG9w0BAQUFAANBAG8yZAWHb6g3zba453Hw5loojVDZO6fD\n"
+"9lCsyaxeo9/+7x1JEEcdZ6qL7KKqe7ZBwza+hIN0ITkp2WEWo22gTz4=\n"
+"-----END CERTIFICATE-----\n\n",
+/* From Entrust */
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDXTCCAsagAwIBAgIEOb6khTANBgkqhkiG9w0BAQUFADA4MQswCQYDVQQGEwJV\n"
+"UzEQMA4GA1UEChMHRW50cnVzdDEXMBUGA1UECxMOVlBOIEludGVyb3AgUk8wHhcN\n"
+"MDAwOTE4MjMwMDM3WhcNMDMwOTE4MjMzMDM3WjBTMQswCQYDVQQGEwJVUzEQMA4G\n"
+"A1UEChMHRW50cnVzdDEXMBUGA1UECxMOVlBOIEludGVyb3AgUk8xGTAXBgNVBAMT\n"
+"EFNob2ljaGkgU2FrYW5lIDIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKj3\n"
+"eXSt1qXxFXzpa265B/NQYk5BZN7pNJg0tlTKBTVV3UgpQ92Bx5DoNfZh11oIv0Sw\n"
+"6YnG5p9F9ma36U9HDoD3hVTjAvQKy4ssCsnU1y6v5XOU1QvYQo6UTzgsXUTaIau4\n"
+"Lrccl+nyoiNzy3lG51tLR8CxuA+3OOAK9xPjszClAgMBAAGjggFXMIIBUzBABgNV\n"
+"HREEOTA3gQ9zYWthbmVAa2FtZS5uZXSHBM6vIHWCHjIwNi0xNzUtMzItMTE3LnZw\n"
+"bndvcmtzaG9wLmNvbTATBgNVHSUEDDAKBggrBgEFBQgCAjALBgNVHQ8EBAMCAKAw\n"
+"KwYDVR0QBCQwIoAPMjAwMDA5MTgyMzAwMzdagQ8yMDAyMTAyNTExMzAzN1owWgYD\n"
+"VR0fBFMwUTBPoE2gS6RJMEcxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFbnRydXN0\n"
+"MRcwFQYDVQQLEw5WUE4gSW50ZXJvcCBSTzENMAsGA1UEAxMEQ1JMMTAfBgNVHSME\n"
+"GDAWgBTzVmhu0tBoWKwkZE5mXpooE9630DAdBgNVHQ4EFgQUEgBHPtXggJqei5Xz\n"
+"92CrWXTJxfAwCQYDVR0TBAIwADAZBgkqhkiG9n0HQQAEDDAKGwRWNS4wAwIEsDAN\n"
+"BgkqhkiG9w0BAQUFAAOBgQCIFriNGMUE8GH5LuDrTJfA8uGx8vLy2seljuo694TR\n"
+"et/ojp9QnfOJ1PF9iAdGaEaSLfkwhY4fZNZzxic5HBoHLeo9BXLP7i7FByXjvOZC\n"
+"Y8++0dC8NVvendIILcJBM5nbDq1TqIbb8K3SP80XhO5JLVJkoZiQftAMjo0peZPO\n"
+"EQ==\n"
+"-----END CERTIFICATE-----\n\n",
+       NULL,
+       };
+
+       if (path == NULL)
+               return (char **)&samplecerts;
+
+       stat(path, &sb);
+       if (!(sb.st_mode & S_IFDIR)) {
+               printf("ERROR: %s is not directory.\n", path);
+               exit(0);
+       }
+
+       dirp = opendir(path);
+       if (dirp == NULL) {
+               printf("opendir failed.\n");
+               exit(0);
+       }
+
+       n = 0;
+       while ((dp = readdir(dirp)) != NULL) {
+               if (dp->d_type != DT_REG)
+                       continue;
+               if (strcmp(dp->d_name + strlen(dp->d_name) - 4, "cert"))
+                       continue;
+               snprintf(buf, sizeof(buf), "%s/%s", path, dp->d_name);
+               stat(buf, &sb);
+
+               p = (char **)realloc(certs, (n + 1) * sizeof(certs));
+               if (p == NULL)
+                       err(1, "realloc");
+               certs = p;
+
+               certs[n] = malloc(sb.st_size + 1);
+               if (certs[n] == NULL)
+                       err(1, "malloc");
+
+               fd = open(buf, O_RDONLY);
+               if (fd == -1)
+                       err(1, "open");
+               len = read(fd, certs[n], sb.st_size);
+               if (len == -1)
+                       err(1, "read");
+               if (len != sb.st_size)
+                       errx(1, "read: length mismatch");
+               certs[n][sb.st_size] = '\0';
+               close(fd);
+
+               printf("%s: %d\n", dp->d_name, (int)sb.st_size);
+
+               n++;
+       }
+
+       p = (char **)realloc(certs, (n + 1) * sizeof(certs));
+       if (p == NULL)
+               err(1, "realloc");
+       certs = p;
+       certs[n] = NULL;
+
+       return certs;
+}
+#endif /* CERTTEST_BROKEN */
+
+typedef vchar_t* (eay_func) (vchar_t *, vchar_t *, vchar_t *);
+
+static int 
+ciphertest_1 (const char *name,
+             vchar_t *data,
+             size_t data_align,
+             vchar_t *key,
+             size_t min_keysize,
+             vchar_t *iv0,
+             size_t iv_length,
+             eay_func encrypt,
+             eay_func decrypt)
+{
+       int padlen;
+       vchar_t *buf, *iv, *res1, *res2;
+       iv = vmalloc(iv_length);
+       
+       printf("Test for cipher %s\n", name);
+       printf("data:\n");
+       PVDUMP(data);
+
+       if (data_align <= 1 || (data->l % data_align) == 0)
+         padlen = 0;
+       else
+         padlen = data_align - data->l % data_align;
+
+       buf = vmalloc(data->l + padlen);
+       memcpy(buf->v, data->v, data->l);
+
+       memcpy(iv->v, iv0->v, iv_length);
+       res1 = (encrypt)(buf, key, iv);
+       if (res1 == NULL) {
+               printf("%s encryption failed.\n", name);
+               return -1;
+       }
+       printf("encrypted:\n");
+       PVDUMP(res1);
+
+       memcpy(iv->v, iv0->v, iv_length);
+       res2 = (decrypt)(res1, key, iv);
+       if (res2 == NULL) {
+               printf("%s decryption failed.\n", name);
+               return -1;
+       }
+       printf("decrypted:\n");
+       PVDUMP(res2);
+
+       if (memcmp(data->v, res2->v, data->l)) {
+               printf("XXXX NG (%s) XXXX\n", name);
+               return -1;
+       }
+       else
+               printf("%s cipher verified.\n", name);
+       vfree(res1);
+       vfree(res2);
+       vfree(buf);
+       vfree(iv);
+
+       return 0;
+}
+
+int
+ciphertest(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t data;
+       vchar_t key;
+       vchar_t iv0;
+
+       printf("\n**Testing CIPHERS**\n");
+
+       data.v = str2val("\
+06000017 03000000 73616b61 6e65406b 616d652e 6e657409 0002c104 308202b8 \
+04f05a90 \
+       ", 16, &data.l);
+       key.v = str2val("f59bd70f 81b9b9cc 2a32c7fd 229a4b37", 16, &key.l);
+       iv0.v = str2val("26b68c90 9467b4ab 7ec29fa0 0b696b55", 16, &iv0.l);
+
+       if (ciphertest_1 ("DES", 
+                         &data, 8, 
+                         &key, 8, 
+                         &iv0, 8, 
+                         eay_des_encrypt, eay_des_decrypt) < 0)
+         return -1;
+       
+       if (ciphertest_1 ("3DES",
+                         &data, 8,
+                         &key, 24,
+                         &iv0, 8,
+                         eay_3des_encrypt, eay_3des_decrypt) < 0)
+         return -1;
+       
+       if (ciphertest_1 ("AES",
+                         &data, 16,
+                         &key, key.l,
+                         &iv0, 16,
+                         eay_aes_encrypt, eay_aes_decrypt) < 0)
+         return -1;
+
+       if (ciphertest_1 ("BLOWFISH",
+                         &data, 8,
+                         &key, key.l,
+                         &iv0, 8,
+                         eay_bf_encrypt, eay_bf_decrypt) < 0)
+         return -1;
+
+       if (ciphertest_1 ("CAST",
+                         &data, 8,
+                         &key, key.l,
+                         &iv0, 8,
+                         eay_cast_encrypt, eay_cast_decrypt) < 0)
+         return -1;
+       
+#ifdef HAVE_OPENSSL_IDEA_H
+       if (ciphertest_1 ("IDEA",
+                         &data, 8,
+                         &key, key.l,
+                         &iv0, 8,
+                         eay_idea_encrypt, eay_idea_decrypt) < 0)
+         return -1;
+#endif
+
+#ifdef HAVE_OPENSSL_RC5_H
+       if (ciphertest_1 ("RC5",
+                         &data, 8,
+                         &key, key.l,
+                         &iv0, 8,
+                         eay_rc5_encrypt, eay_rc5_decrypt) < 0)
+         return -1;
+#endif
+       return 0;
+}
+
+int
+hmactest(ac, av)
+       int ac;
+       char **av;
+{
+       char *keyword = "hehehe test secret!";
+       char *object  = "d7e6a6c1876ef0488bb74958b9fee94e";
+       char *object1 = "d7e6a6c1876ef048";
+       char *object2 =                 "8bb74958b9fee94e";
+       char *r_hmd5  = "5702d7d1 fd1bfc7e 210fc9fa cda7d02c";
+       char *r_hsha1 = "309999aa 9779a43e ebdea839 1b4e7ee1 d8646874";
+#ifdef WITH_SHA2
+       char *r_hsha2 = "d47262d8 a5b6f39d d8686939 411b3e79 ed2e27f9 2c4ea89f dd0a06ae 0c0aa396";
+#endif
+       vchar_t *key, *data, *data1, *data2, *res;
+       vchar_t mod;
+       caddr_t ctx;
+
+#ifdef WITH_SHA2
+       printf("\n**Test for HMAC MD5, SHA1, and SHA256.**\n");
+#else
+       printf("\n**Test for HMAC MD5 & SHA1.**\n");
+#endif
+
+       key = vmalloc(strlen(keyword));
+       memcpy(key->v, keyword, key->l);
+
+       data = vmalloc(strlen(object));
+       data1 = vmalloc(strlen(object1));
+       data2 = vmalloc(strlen(object2));
+       memcpy(data->v, object, data->l);
+       memcpy(data1->v, object1, data1->l);
+       memcpy(data2->v, object2, data2->l);
+
+       /* HMAC MD5 */
+       printf("HMAC MD5 by eay_hmacmd5_one()\n");
+       res = eay_hmacmd5_one(key, data);
+       PVDUMP(res);
+       mod.v = str2val(r_hmd5, 16, &mod.l);
+       if (memcmp(res->v, mod.v, mod.l)) {
+               printf(" XXX NG XXX\n");
+               return -1;
+       }
+       free(mod.v);
+       vfree(res);
+
+       /* HMAC MD5 */
+       printf("HMAC MD5 by eay_hmacmd5_xxx()\n");
+       ctx = eay_hmacmd5_init(key);
+       eay_hmacmd5_update(ctx, data1);
+       eay_hmacmd5_update(ctx, data2);
+       res = eay_hmacmd5_final(ctx);
+       PVDUMP(res);
+       mod.v = str2val(r_hmd5, 16, &mod.l);
+       if (memcmp(res->v, mod.v, mod.l)) {
+               printf(" XXX NG XXX\n");
+               return -1;
+       }
+       free(mod.v);
+       vfree(res);
+
+       /* HMAC SHA1 */
+       printf("HMAC SHA1 by eay_hmacsha1_one()\n");
+       res = eay_hmacsha1_one(key, data);
+       PVDUMP(res);
+       mod.v = str2val(r_hsha1, 16, &mod.l);
+       if (memcmp(res->v, mod.v, mod.l)) {
+               printf(" XXX NG XXX\n");
+               return -1;
+       }
+       free(mod.v);
+       vfree(res);
+
+       /* HMAC SHA1 */
+       printf("HMAC SHA1 by eay_hmacsha1_xxx()\n");
+       ctx = eay_hmacsha1_init(key);
+       eay_hmacsha1_update(ctx, data1);
+       eay_hmacsha1_update(ctx, data2);
+       res = eay_hmacsha1_final(ctx);
+       PVDUMP(res);
+       mod.v = str2val(r_hsha1, 16, &mod.l);
+       if (memcmp(res->v, mod.v, mod.l)) {
+               printf(" XXX NG XXX\n");
+               return -1;
+       }
+       free(mod.v);
+       vfree(res);
+
+#ifdef WITH_SHA2
+       /* HMAC SHA2 */
+       printf("HMAC SHA2 by eay_hmacsha2_256_one()\n");
+       res = eay_hmacsha2_256_one(key, data);
+       PVDUMP(res);
+       mod.v = str2val(r_hsha2, 16, &mod.l);
+       if (memcmp(res->v, mod.v, mod.l)) {
+               printf(" XXX NG XXX\n");
+               return -1;
+       }
+       free(mod.v);
+       vfree(res);
+#endif
+
+       vfree(data);
+       vfree(data1);
+       vfree(data2);
+       vfree(key);
+
+       return 0;
+}
+
+int
+sha1test(ac, av)
+       int ac;
+       char **av;
+{
+       char *word1 = "1234567890", *word2 = "12345678901234567890";
+       caddr_t ctx;
+       vchar_t *buf, *res;
+
+       printf("\n**Test for SHA1.**\n");
+
+       ctx = eay_sha1_init();
+       buf = vmalloc(strlen(word1));
+       memcpy(buf->v, word1, buf->l);
+       eay_sha1_update(ctx, buf);
+       eay_sha1_update(ctx, buf);
+       res = eay_sha1_final(ctx);
+       PVDUMP(res);
+       vfree(res);
+       vfree(buf);
+
+       ctx = eay_sha1_init();
+       buf = vmalloc(strlen(word2));
+       memcpy(buf->v, word2, buf->l);
+       eay_sha1_update(ctx, buf);
+       res = eay_sha1_final(ctx);
+       PVDUMP(res);
+       vfree(res);
+
+       res = eay_sha1_one(buf);
+       PVDUMP(res);
+       vfree(res);
+       vfree(buf);
+
+       return 0;
+}
+
+int
+md5test(ac, av)
+       int ac;
+       char **av;
+{
+       char *word1 = "1234567890", *word2 = "12345678901234567890";
+       caddr_t ctx;
+       vchar_t *buf, *res;
+
+       printf("\n**Test for MD5.**\n");
+
+       ctx = eay_md5_init();
+       buf = vmalloc(strlen(word1));
+       memcpy(buf->v, word1, buf->l);
+       eay_md5_update(ctx, buf);
+       eay_md5_update(ctx, buf);
+       res = eay_md5_final(ctx);
+       PVDUMP(res);
+       vfree(res);
+       vfree(buf);
+
+       ctx = eay_md5_init();
+       buf = vmalloc(strlen(word2));
+       memcpy(buf->v, word2, buf->l);
+       eay_md5_update(ctx, buf);
+       res = eay_md5_final(ctx);
+       PVDUMP(res);
+       vfree(res);
+
+       res = eay_md5_one(buf);
+       PVDUMP(res);
+       vfree(res);
+       vfree(buf);
+
+       return 0;
+}
+
+int
+dhtest(ac, av)
+       int ac;
+       char **av;
+{
+       static struct {
+               char *name;
+               char *p;
+       } px[] = {
+               { "modp768",    OAKLEY_PRIME_MODP768, },
+               { "modp1024",   OAKLEY_PRIME_MODP1024, },
+               { "modp1536",   OAKLEY_PRIME_MODP1536, },
+               { "modp2048",   OAKLEY_PRIME_MODP2048, },
+               { "modp3072",   OAKLEY_PRIME_MODP3072, },
+               { "modp4096",   OAKLEY_PRIME_MODP4096, },
+               { "modp6144",   OAKLEY_PRIME_MODP6144, },
+               { "modp8192",   OAKLEY_PRIME_MODP8192, },
+       };
+       vchar_t p1, *pub1, *priv1, *gxy1;
+       vchar_t p2, *pub2, *priv2, *gxy2;
+       int i;
+
+       printf("\n**Test for DH.**\n");
+
+       for (i = 0; i < sizeof(px)/sizeof(px[0]); i++) {
+               printf("\n**Test for DH %s.**\n", px[i].name);
+
+               p1.v = str2val(px[i].p, 16, &p1.l);
+               p2.v = str2val(px[i].p, 16, &p2.l);
+               printf("prime number = \n"); PVDUMP(&p1);
+
+               if (eay_dh_generate(&p1, 2, 96, &pub1, &priv1) < 0) {
+                       printf("error\n");
+                       return -1;
+               }
+               printf("private key for user 1 = \n"); PVDUMP(priv1);
+               printf("public key for user 1  = \n"); PVDUMP(pub1);
+
+               if (eay_dh_generate(&p2, 2, 96, &pub2, &priv2) < 0) {
+                       printf("error\n");
+                       return -1;
+               }
+               printf("private key for user 2 = \n"); PVDUMP(priv2);
+               printf("public key for user 2  = \n"); PVDUMP(pub2);
+
+               /* process to generate key for user 1 */
+               gxy1 = vmalloc(p1.l);
+               memset(gxy1->v, 0, gxy1->l);
+               eay_dh_compute(&p1, 2, pub1, priv1, pub2, &gxy1);
+               printf("sharing gxy1 of user 1 = \n"); PVDUMP(gxy1);
+
+               /* process to generate key for user 2 */
+               gxy2 = vmalloc(p1.l);
+               memset(gxy2->v, 0, gxy2->l);
+               eay_dh_compute(&p2, 2, pub2, priv2, pub1, &gxy2);
+               printf("sharing gxy2 of user 2 = \n"); PVDUMP(gxy2);
+
+               if (memcmp(gxy1->v, gxy2->v, gxy1->l)) {
+                       printf("ERROR: sharing gxy mismatched.\n");
+                       return -1;
+               }
+
+               vfree(pub1);
+               vfree(pub2);
+               vfree(priv1);
+               vfree(priv2);
+               vfree(gxy1);
+               vfree(gxy2);
+       }
+
+       return 0;
+}
+
+int
+bntest(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *rn;
+
+       printf("\n**Test for generate a random number.**\n");
+
+       rn = eay_set_random((u_int32_t)96);
+       PVDUMP(rn);
+       vfree(rn);
+
+       return 0;
+}
+
+struct {
+       char *name;
+       int (*func) __P((int, char **));
+} func[] = {
+       { "random", bntest, },
+       { "dh", dhtest, },
+       { "md5", md5test, },
+       { "sha1", sha1test, },
+       { "hmac", hmactest, },
+       { "cipher", ciphertest, },
+#ifndef CERTTEST_BROKEN
+       { "cert", certtest, },
+#endif
+       { "rsa", rsatest, },
+};
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       int i;
+       int len = sizeof(func)/sizeof(func[0]);
+
+       f_foreground = 1;
+       ploginit();
+
+       //printf ("\nTestsuite of the %s\nlinked with %s\n\n", TOP_PACKAGE_STRING, eay_version());
+
+       if (strcmp(*av, "-h") == 0)
+               Usage();
+
+       ac--;
+       av++;
+
+       for (i = 0; i < len; i++) {
+               if ((ac == 0) || (strcmp(*av, func[i].name) == 0)) {
+                       if ((func[i].func)(ac, av) != 0) {
+                               printf ("\n!!!!! Test '%s' failed. !!!!!\n\n", func[i].name);
+                               exit(1);
+                       }
+                       if (ac)
+                               break;
+               }
+       }
+       if (ac && i == len)
+               Usage();
+
+       printf ("\n===== All tests passed =====\n\n");
+       exit(0);
+}
+
+void
+Usage()
+{
+       int i;
+       int len = sizeof(func)/sizeof(func[0]);
+
+       printf("Usage: eaytest [");
+       for (i = 0; i < len; i++)
+               printf("%s%s", func[i].name, (i<len-1)?"|":"");
+       printf("]\n");
+#ifndef CERTTEST_BROKEN
+       printf("       eaytest cert [cert_directory]\n");
+#endif
+       exit(1);
+}
+
diff --git a/ipsec-tools/racoon/evt.c b/ipsec-tools/racoon/evt.c
new file mode 100644 (file)
index 0000000..e21a82b
--- /dev/null
@@ -0,0 +1,149 @@
+/* $Id: evt.c,v 1.2.4.1 2005/09/26 17:49:38 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include "vmbuf.h"
+#include "plog.h"
+#include "misc.h"
+#include "gcmalloc.h"
+#include "evt.h"
+
+
+struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist);
+int evtlist_len = 0;
+
+void
+evt_push(src, dst, type, optdata)
+       struct sockaddr *src;
+       struct sockaddr *dst;
+       int type;
+       vchar_t *optdata;
+{
+       struct evtdump *evtdump;
+       struct evt *evt;
+       size_t len;
+
+       /* If we are above the limit, don't record anything */
+       if (evtlist_len > EVTLIST_MAX) {
+               plog(LLV_DEBUG, LOCATION, NULL, 
+                   "Cannot record event: event queue overflowed\n");
+               return;
+       }
+
+       /* If we hit the limit, record an overflow event instead */
+       if (evtlist_len == EVTLIST_MAX) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot record event: event queue overflow\n");
+               src = NULL;
+               dst = NULL;
+               type = EVTT_OVERFLOW;
+               optdata = NULL;
+       }
+
+       len = sizeof(*evtdump);
+       if (optdata)
+               len += optdata->l;
+
+       if ((evtdump = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n",
+                   strerror(errno));
+               return;
+       }
+
+       if ((evt = racoon_malloc(sizeof(*evt))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n",
+                   strerror(errno));
+               racoon_free(evtdump);
+               return;
+       }
+
+       if (src)
+               memcpy(&evtdump->src, src, sysdep_sa_len(src));
+       if (dst)
+               memcpy(&evtdump->dst, dst, sysdep_sa_len(dst));
+       evtdump->len = len;
+       evtdump->type = type;
+       time(&evtdump->timestamp);
+
+       if (optdata)
+               memcpy(evtdump + 1, optdata->v, optdata->l);
+
+       evt->dump = evtdump;
+       TAILQ_INSERT_TAIL(&evtlist, evt, next);
+
+       evtlist_len++;
+
+       return;
+}
+
+struct evtdump *
+evt_pop(void) {
+       struct evtdump *evtdump;
+       struct evt *evt;
+
+       if ((evt = TAILQ_FIRST(&evtlist)) == NULL)
+               return NULL;
+
+       evtdump = evt->dump;
+       TAILQ_REMOVE(&evtlist, evt, next);
+       racoon_free(evt);
+       evtlist_len--;
+
+       return evtdump;
+}
+
+vchar_t *
+evt_dump(void) {
+       struct evtdump *evtdump;
+       vchar_t *buf = NULL;
+
+       if ((evtdump = evt_pop()) != NULL) {
+               if ((buf = vmalloc(evtdump->len)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "evt_dump failed: %s\n", strerror(errno));
+                       return NULL;
+               }
+               memcpy(buf->v, evtdump, evtdump->len);  
+               racoon_free(evtdump);
+       }
+
+       return buf;
+}
diff --git a/ipsec-tools/racoon/evt.h b/ipsec-tools/racoon/evt.h
new file mode 100644 (file)
index 0000000..209c854
--- /dev/null
@@ -0,0 +1,84 @@
+/* $Id: evt.h,v 1.3 2004/11/29 23:30:39 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * 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.
+ */
+
+#ifndef _EVT_H
+#define _EVT_H
+
+struct evtdump {
+       size_t len;     
+       struct sockaddr_storage src;
+       struct sockaddr_storage dst;
+       time_t timestamp;
+       int type;
+       /* 
+        * Optionnal list of struct isakmp_data 
+        * for type EVTT_ISAKMP_CFG_DONE
+        */
+};
+
+/* type */
+#define EVTT_UNSEPC            0
+#define EVTT_PHASE1_UP         1
+#define EVTT_PHASE1_DOWN       2
+#define EVTT_XAUTH_SUCCESS     3
+#define EVTT_ISAKMP_CFG_DONE   4
+#define EVTT_PHASE2_UP         5
+#define EVTT_PHASE2_DOWN       6
+#define EVTT_DPD_TIMEOUT       7
+#define EVTT_PEER_NO_RESPONSE  8
+#define EVTT_PEER_DELETE       9
+#define EVTT_RACOON_QUIT       10
+#define EVTT_XAUTH_FAILED      11
+#define EVTT_OVERFLOW          12      /* Event queue overflowed */
+#define EVTT_PEERPH1AUTH_FAILED        13
+
+struct evt {
+       struct evtdump *dump;
+       TAILQ_ENTRY(evt) next;
+};
+
+TAILQ_HEAD(evtlist, evt);
+
+#define EVTLIST_MAX    32
+
+#ifdef ENABLE_ADMINPORT
+struct evtdump *evt_pop(void);
+vchar_t *evt_dump(void);
+void evt_push(struct sockaddr *, struct sockaddr *, int, vchar_t *);
+#endif
+
+#ifdef ENABLE_ADMINPORT
+#define EVT_PUSH(src, dst, type, optdata) evt_push(src, dst, type, optdata);
+#else
+#define EVT_PUSH(src, dst, type, optdata) ;
+#endif
+
+#endif /* _EVT_H */
diff --git a/ipsec-tools/racoon/gcmalloc.h b/ipsec-tools/racoon/gcmalloc.h
new file mode 100644 (file)
index 0000000..ca08528
--- /dev/null
@@ -0,0 +1,114 @@
+/*     $KAME: gcmalloc.h,v 1.4 2001/11/16 04:34:57 sakane Exp $        */
+
+/*
+ * Copyright (C) 2000, 2001 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.
+ */
+
+/*
+ * Debugging malloc glue for Racoon.
+ */
+
+#ifndef _GCMALLOC_H_DEFINED
+#define _GCMALLOC_H_DEFINED
+
+/* ElectricFence needs no special handling. */
+
+/*
+ * Boehm-GC provides GC_malloc(), GC_realloc(), GC_free() functions,
+ * but not the traditional entry points.  So what we do is provide  
+ * malloc(), calloc(), realloc(), and free() entry points in the main
+ * program and letting the linker do the rest.
+ */
+#ifdef GC
+#define GC_DEBUG
+#include <gc.h>
+
+#ifdef RACOON_MAIN_PROGRAM
+void *
+malloc(size_t size)
+{
+
+       return (GC_MALLOC(size));
+}
+
+void *
+calloc(size_t number, size_t size)
+{
+
+       /* GC_malloc() clears the storage. */
+       return (GC_MALLOC(number * size));
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+
+       return (GC_REALLOC(ptr, size));
+}
+
+void
+free(void *ptr)
+{
+
+       GC_FREE(ptr);
+}
+#endif /* RACOON_MAIN_PROGRAM */
+
+#define        racoon_malloc(sz)       GC_debug_malloc(sz, GC_EXTRAS)
+#define        racoon_calloc(cnt, sz)  GC_debug_malloc(cnt * sz, GC_EXTRAS)
+#define        racoon_realloc(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
+#define        racoon_free(p)          GC_debug_free(p)
+
+#endif /* GC */
+
+/*
+ * Dmalloc only requires that you pull in a header file and link
+ * against libdmalloc.
+ */
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif /* DMALLOC */
+
+#ifdef DEBUG_RECORD_MALLOCATION
+#include <debugrm.h>
+#else
+#ifndef racoon_malloc
+#define        racoon_malloc(sz)       malloc((sz))
+#endif
+#ifndef racoon_calloc
+#define        racoon_calloc(cnt, sz)  calloc((cnt), (sz))
+#endif
+#ifndef racoon_realloc
+#define        racoon_realloc(old, sz) realloc((old), (sz))
+#endif
+#ifndef racoon_free
+#define        racoon_free(p)          free((p))
+#endif
+#endif /* DEBUG_RECORD_MALLOCATION */
+
+#endif /* _GCMALLOC_H_DEFINED */
diff --git a/ipsec-tools/racoon/genlist.c b/ipsec-tools/racoon/genlist.c
new file mode 100644 (file)
index 0000000..0f9b195
--- /dev/null
@@ -0,0 +1,172 @@
+/* $Id: genlist.c,v 1.2 2004/07/12 20:43:50 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+#include "genlist.h"
+
+struct genlist *
+genlist_init (void)
+{
+       struct genlist *new = calloc(sizeof(struct genlist), 1);
+       TAILQ_INIT(new);
+       return new;
+}
+
+struct genlist_entry *
+genlist_insert (struct genlist *head, void *data)
+{
+       struct genlist_entry *entry = calloc(sizeof(struct genlist_entry), 1);
+       entry->data = data;
+       TAILQ_INSERT_HEAD(head, entry, chain);
+       return entry;
+}
+
+struct genlist_entry *
+genlist_append (struct genlist *head, void *data)
+{
+       struct genlist_entry *entry = calloc(sizeof(struct genlist_entry), 1);
+       entry->data = data;
+       TAILQ_INSERT_TAIL(head, entry, chain);
+       return entry;
+}
+
+void *
+genlist_foreach (struct genlist *head, genlist_func_t func, void *arg)
+{
+       struct genlist_entry *p;
+       void *ret = NULL;
+       TAILQ_FOREACH(p, head, chain) {
+               ret = (*func)(p->data, arg);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+void *
+genlist_next (struct genlist *head, struct genlist_entry **buf)
+{
+       struct genlist_entry *p;
+
+       if (head)
+               p = TAILQ_FIRST(head);
+       else
+               p = (buf && *buf) ? TAILQ_NEXT(*buf, chain) : NULL;
+       if (buf)
+               *buf = p;
+       return (p ? p->data : NULL);
+}
+
+void
+genlist_free (struct genlist *head, genlist_freedata_t func)
+{
+       struct genlist_entry *p;
+
+       while ((p = TAILQ_LAST(head, genlist)) != NULL) {
+               TAILQ_REMOVE(head, p, chain);
+               if (func)
+                       func(p->data);
+               free(p);
+       }
+       free(head);
+}
+
+
+#if 0
+/* Here comes the example... */
+struct conf {
+       struct genlist  *l1, *l2;
+};
+
+void *
+print_entry(void *entry, void *arg)
+{
+       if (!entry)
+               return NULL;
+       printf("%s\n", (char *)entry);
+       return NULL;
+}
+
+void
+dump_list(struct genlist *head)
+{
+       genlist_foreach(head, print_entry, NULL);
+}
+
+void
+free_data(void *data)
+{
+       printf ("removing %s\n", (char *)data);
+}
+
+int main()
+{
+       struct conf *cf;
+       char *cp;
+       struct genlist_entry *gpb;
+
+       cf = calloc(sizeof(struct conf), 1);
+       cf->l1 = genlist_init();
+       cf->l2 = genlist_init();
+       
+       genlist_insert(cf->l1, "Ahoj");
+       genlist_insert(cf->l1, "Cau");
+       genlist_insert(cf->l1, "Nazdar");
+       genlist_insert(cf->l1, "Te buch");
+
+       genlist_append(cf->l2, "Curak");
+       genlist_append(cf->l2, "Kozy");
+       genlist_append(cf->l2, "Pica");
+       genlist_append(cf->l2, "Prdel");
+
+       printf("List 2\n");
+       dump_list(cf->l2);
+       printf("\nList 1\n");
+       dump_list(cf->l1);
+
+       printf("\nList 2 - using genlist_next()\n");
+       for (cp = genlist_next (cf->l2, &gpb); cp; cp = genlist_next (0, &gpb))
+           printf("%s\n", cp);
+
+       printf("\nFreeing List 1\n");
+       /* the data here isn't actually alloc'd so we would really call
+        * genlist_free (cf->l1, 0);    but to illustrate the idea */
+       genlist_free (cf->l1, free_data);
+       cf->l1 = 0;
+
+       return 0;
+}
+#endif
diff --git a/ipsec-tools/racoon/genlist.h b/ipsec-tools/racoon/genlist.h
new file mode 100644 (file)
index 0000000..089e624
--- /dev/null
@@ -0,0 +1,80 @@
+/* $Id: genlist.h,v 1.2 2004/07/12 20:43:50 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+#ifndef _GENLIST_H
+#define _GENLIST_H
+
+#include <sys/queue.h>
+
+/* See the bottom of genlist.c for example use. */
+
+/* This declares 'struct genlist' */
+TAILQ_HEAD(genlist, genlist_entry);
+
+/* This is where the data are actually stored. */
+struct genlist_entry {
+       void *data;
+       TAILQ_ENTRY(genlist_entry) chain;
+};
+
+/* This function returns an initialized list head. */
+struct genlist *genlist_init (void);
+
+/* Insert an entry at the beginning/end og the list. */
+struct genlist_entry *genlist_insert (struct genlist *head, void *data);
+struct genlist_entry *genlist_append (struct genlist *head, void *data);
+
+/* Create a function with this prototype for use with genlist_foreach().
+ * See genlist_foreach() description below for details. */
+typedef void *(genlist_func_t)(void *entry, void *arg);
+
+/* Traverse the list and call 'func' for each entry.  As long as func() returns
+ * NULL the list traversal continues, once it returns non-NULL (usually the
+ * 'entry' arg), the list traversal exits and the return value is returned
+ * further from genlist_foreach(). Optional 'arg' may be passed to func(), e.g.
+ * for some lookup purposes, etc. */
+void *genlist_foreach (struct genlist *head, genlist_func_t func, void *arg);
+
+/* Get first entry in list if head is not NULL, otherwise get next
+ * entry based on saved position in list from previous call as stored in buf.
+ * If buf is NULL no position is saved */
+void *genlist_next (struct genlist *head, struct genlist_entry **buf);
+
+/* Create a function with this prototype for use with genlist_free()
+ * to free any storage associated with genlist_entry.data */
+typedef void (genlist_freedata_t)(void *entry);
+
+/* Free all storage associated with list at head using func to free any
+ * alloc()d data in data field of genlist_entry */
+void genlist_free (struct genlist *head, genlist_freedata_t func);
+
+#endif /* _GENLIST_H */
diff --git a/ipsec-tools/racoon/getcertsbyname.c b/ipsec-tools/racoon/getcertsbyname.c
new file mode 100644 (file)
index 0000000..890f067
--- /dev/null
@@ -0,0 +1,416 @@
+/*     $KAME: getcertsbyname.c,v 1.7 2001/11/16 04:12:59 sakane Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+//%%%HWR Do we need this?
+#define BIND_8_COMPAT
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifdef HAVE_LWRES_GETRRSETBYNAME
+#include <lwres/netdb.h>
+#include <lwres/lwres.h>
+#else
+#include <netdb.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef DNSSEC_DEBUG
+#include <stdio.h>
+#include <strings.h>
+#endif
+
+#include "netdb_dnssec.h"
+
+/* XXX should it use ci_errno to hold errno instead of h_errno ? */
+extern int h_errno;
+
+static struct certinfo *getnewci __P((int, int, int, int, int, 
+                       unsigned char *));
+
+static struct certinfo *
+getnewci(qtype, keytag, algorithm, flags, certlen, cert)
+       int qtype, keytag, algorithm, flags, certlen;
+       unsigned char *cert;
+{
+       struct certinfo *res;
+
+       res = malloc(sizeof(*res));
+       if (!res)
+               return NULL;
+
+       memset(res, 0, sizeof(*res));
+       res->ci_type = qtype;
+       res->ci_keytag = keytag;
+       res->ci_algorithm = algorithm;
+       res->ci_flags = flags;
+       res->ci_certlen = certlen;
+       res->ci_cert = malloc(certlen);
+       if (!res->ci_cert) {
+               free(res);
+               return NULL;
+       }
+       memcpy(res->ci_cert, cert, certlen);
+
+       return res;
+}
+
+void
+freecertinfo(ci)
+       struct certinfo *ci;
+{
+       struct certinfo *next;
+
+       do {
+               next = ci->ci_next;
+               if (ci->ci_cert)
+                       free(ci->ci_cert);
+               free(ci);
+               ci = next;
+       } while (ci);
+}
+
+/*
+ * get CERT RR by FQDN and create certinfo structure chain.
+ */
+#ifdef HAVE_LWRES_GETRRSETBYNAME
+#define getrrsetbyname lwres_getrrsetbyname
+#define freerrset lwres_freerrset
+#define hstrerror lwres_hstrerror
+#endif
+#if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(HAVE_GETRRSETBYNAME)         //%%% BUG FIX - HAVE misspelled
+int
+getcertsbyname(name, res)
+       char *name;
+       struct certinfo **res;
+{
+       int rdlength;
+       char *cp;
+       int type, keytag, algorithm;
+       struct certinfo head, *cur;
+       struct rrsetinfo *rr = NULL;
+       int i;
+       int error = -1;
+
+       /* initialize res */
+       *res = NULL;
+
+       memset(&head, 0, sizeof(head));
+       cur = &head;
+
+       error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr);
+       if (error) {
+#ifdef DNSSEC_DEBUG
+               printf("getrrsetbyname: %s\n", hstrerror(error));
+#endif
+               h_errno = NO_RECOVERY;
+               goto end;
+       }
+
+       if (rr->rri_rdclass != C_IN
+        || rr->rri_rdtype != T_CERT
+        || rr->rri_nrdatas == 0) {
+#ifdef DNSSEC_DEBUG
+               printf("getrrsetbyname: %s", hstrerror(error));
+#endif
+               h_errno = NO_RECOVERY;
+               goto end;
+       }
+#ifdef DNSSEC_DEBUG
+       if (!(rr->rri_flags & LWRDATA_VALIDATED))
+               printf("rr is not valid");
+#endif
+
+       for (i = 0; i < rr->rri_nrdatas; i++) {
+               rdlength = rr->rri_rdatas[i].rdi_length;
+               cp = rr->rri_rdatas[i].rdi_data;
+
+               GETSHORT(type, cp);     /* type */
+               rdlength -= INT16SZ;
+               GETSHORT(keytag, cp);   /* key tag */
+               rdlength -= INT16SZ;
+               algorithm = *cp++;      /* algorithm */
+               rdlength -= 1;
+
+#ifdef DNSSEC_DEBUG
+               printf("type=%d keytag=%d alg=%d len=%d\n",
+                       type, keytag, algorithm, rdlength);
+#endif
+
+               /* create new certinfo */
+               cur->ci_next = getnewci(type, keytag, algorithm,
+                                       rr->rri_flags, rdlength, cp);
+               if (!cur->ci_next) {
+#ifdef DNSSEC_DEBUG
+                       printf("getnewci: %s", strerror(errno));
+#endif
+                       h_errno = NO_RECOVERY;
+                       goto end;
+               }
+               cur = cur->ci_next;
+       }
+
+       *res = head.ci_next;
+       error = 0;
+
+end:
+       if (rr)
+               freerrset(rr);
+       if (error && head.ci_next)
+               freecertinfo(head.ci_next);
+
+       return error;
+}
+#else  /*!HAVE_LWRES_GETRRSETBYNAME*/
+int
+getcertsbyname(name, res)
+       char *name;
+       struct certinfo **res;
+{
+       unsigned char *answer = NULL, *p;
+       int buflen, anslen, len;
+       HEADER *hp;
+       int qdcount, ancount, rdlength;
+       unsigned char *cp, *eom;
+       char hostbuf[1024];     /* XXX */
+       int qtype, qclass, keytag, algorithm;
+       struct certinfo head, *cur;
+       int error = -1;
+
+       /* initialize res */
+       *res = NULL;
+
+       memset(&head, 0, sizeof(head));
+       cur = &head;
+
+       /* get CERT RR */
+       buflen = 512;
+       do {
+
+               buflen *= 2;
+               p = realloc(answer, buflen);
+               if (!p) {
+#ifdef DNSSEC_DEBUG
+                       printf("realloc: %s", strerror(errno));
+#endif
+                       h_errno = NO_RECOVERY;
+                       goto end;
+               }
+               answer = p;
+
+               anslen = res_query(name,  C_IN, T_CERT, answer, buflen);
+               if (anslen == -1)
+                       goto end;
+
+       } while (buflen < anslen);
+
+#ifdef DNSSEC_DEBUG
+       printf("get a DNS packet len=%d\n", anslen);
+#endif
+
+       /* parse CERT RR */
+       eom = answer + anslen;
+
+       hp = (HEADER *)answer;
+       qdcount = ntohs(hp->qdcount);
+       ancount = ntohs(hp->ancount);
+
+       /* question section */
+       if (qdcount != 1) {
+#ifdef DNSSEC_DEBUG
+               printf("query count is not 1.\n");
+#endif
+               h_errno = NO_RECOVERY;
+               goto end;
+       }
+       cp = (unsigned char *)(hp + 1);
+       len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
+       if (len < 0) {
+#ifdef DNSSEC_DEBUG
+               printf("dn_expand failed.\n");
+#endif
+               goto end;
+       }
+       cp += len;
+       GETSHORT(qtype, cp);            /* QTYPE */
+       GETSHORT(qclass, cp);           /* QCLASS */
+
+       /* answer section */
+       while (ancount-- && cp < eom) {
+               len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
+               if (len < 0) {
+#ifdef DNSSEC_DEBUG
+                       printf("dn_expand failed.\n");
+#endif
+                       goto end;
+               }
+               cp += len;
+               GETSHORT(qtype, cp);    /* TYPE */
+               GETSHORT(qclass, cp);   /* CLASS */
+               cp += INT32SZ;          /* TTL */
+               GETSHORT(rdlength, cp); /* RDLENGTH */
+
+               /* CERT RR */
+               if (qtype != T_CERT) {
+#ifdef DNSSEC_DEBUG
+                       printf("not T_CERT\n");
+#endif
+                       h_errno = NO_RECOVERY;
+                       goto end;
+               }
+               GETSHORT(qtype, cp);    /* type */
+               rdlength -= INT16SZ;
+               GETSHORT(keytag, cp);   /* key tag */
+               rdlength -= INT16SZ;
+               algorithm = *cp++;      /* algorithm */
+               rdlength -= 1;
+               if (cp + rdlength > eom) {
+#ifdef DNSSEC_DEBUG
+                       printf("rdlength is too long.\n");
+#endif
+                       h_errno = NO_RECOVERY;
+                       goto end;
+               }
+#ifdef DNSSEC_DEBUG
+               printf("type=%d keytag=%d alg=%d len=%d\n",
+                       qtype, keytag, algorithm, rdlength);
+#endif
+
+               /* create new certinfo */
+               cur->ci_next = getnewci(qtype, keytag, algorithm,
+                                       0, rdlength, cp);
+               if (!cur->ci_next) {
+#ifdef DNSSEC_DEBUG
+                       printf("getnewci: %s", strerror(errno));
+#endif
+                       h_errno = NO_RECOVERY;
+                       goto end;
+               }
+               cur = cur->ci_next;
+
+               cp += rdlength;
+       }
+
+       *res = head.ci_next;
+       error = 0;
+
+end:
+       if (answer)
+               free(answer);
+       if (error && head.ci_next)
+               freecertinfo(head.ci_next);
+
+       return error;
+}
+#endif
+
+#ifdef DNSSEC_DEBUG
+int
+b64encode(p, len)
+       char *p;
+       int len;
+{
+       static const char b64t[] =
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "abcdefghijklmnopqrstuvwxyz"
+               "0123456789+/=";
+
+       while (len > 2) {
+                printf("%c", b64t[(p[0] >> 2) & 0x3f]);
+                printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]);
+                printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]);
+                printf("%c", b64t[p[2] & 0x3f]);
+               len -= 3;
+               p += 3;
+       }
+
+       if (len == 2) {
+                printf("%c", b64t[(p[0] >> 2) & 0x3f]);
+                printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]);
+                printf("%c", b64t[((p[1] << 2) & 0x3c)]);
+                printf("%c", '=');
+        } else if (len == 1) {
+                printf("%c", b64t[(p[0] >> 2) & 0x3f]);
+                printf("%c", b64t[((p[0] << 4) & 0x30)]);
+                printf("%c", '=');
+                printf("%c", '=');
+       }
+
+       return 0;
+}
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       struct certinfo *res, *p;
+       int i;
+
+       if (ac < 2) {
+               printf("Usage: a.out (FQDN)\n");
+               exit(1);
+       }
+
+       i = getcertsbyname(*(av + 1), &res);
+       if (i != 0) {
+               herror("getcertsbyname");
+               exit(1);
+       }
+       printf("getcertsbyname succeeded.\n");
+
+       i = 0;
+       for (p = res; p; p = p->ci_next) {
+               printf("certinfo[%d]:\n", i);
+               printf("\tci_type=%d\n", p->ci_type);
+               printf("\tci_keytag=%d\n", p->ci_keytag);
+               printf("\tci_algorithm=%d\n", p->ci_algorithm);
+               printf("\tci_flags=%d\n", p->ci_flags);
+               printf("\tci_certlen=%d\n", p->ci_certlen);
+               printf("\tci_cert: ");
+               b64encode(p->ci_cert, p->ci_certlen);
+               printf("\n");
+               i++;
+       }
+
+       freecertinfo(res);
+
+       exit(0);
+}
+#endif
diff --git a/ipsec-tools/racoon/gnuc.h b/ipsec-tools/racoon/gnuc.h
new file mode 100644 (file)
index 0000000..a923f77
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id: gnuc.h,v 1.4 2004/11/18 15:14:44 ludvigm Exp $ */
+
+/* Define __P() macro, if necessary */
+#undef __P
+#ifndef __P
+#if __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+/* inline foo */
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ *     __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2  || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/ipsec-tools/racoon/grabmyaddr.c b/ipsec-tools/racoon/grabmyaddr.c
new file mode 100644 (file)
index 0000000..98f2d4c
--- /dev/null
@@ -0,0 +1,824 @@
+/* $Id: grabmyaddr.c,v 1.23.4.2 2005/07/16 04:41:01 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <net/if_var.h>
+#endif
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#endif
+#include <net/route.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#include <net/if.h>
+#endif 
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "handler.h"
+#include "grabmyaddr.h"
+#include "sockmisc.h"
+#include "isakmp_var.h"
+#include "gcmalloc.h"
+#include "nattraversal.h"
+
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+#ifndef HAVE_GETIFADDRS
+#define HAVE_GETIFADDRS
+#define NEED_LINUX_GETIFADDRS
+#endif
+#endif
+
+#ifndef HAVE_GETIFADDRS
+static unsigned int if_maxindex __P((void));
+#endif
+#ifdef __APPLE__
+static struct myaddrs *find_myaddr __P((struct myaddrs *, struct sockaddr *, int));
+#else
+static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *));
+#endif
+static int suitable_ifaddr __P((const char *, const struct sockaddr *));
+#ifdef INET6
+static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
+#endif
+
+#ifdef NEED_LINUX_GETIFADDRS
+
+/* We could do this _much_ better. kame racoon in its current form
+ * will esentially die at frequent changes of address configuration.
+ */
+
+struct ifaddrs
+{
+       struct ifaddrs *ifa_next;
+       char            ifa_name[16];
+       int             ifa_ifindex;
+       struct sockaddr *ifa_addr;
+       struct sockaddr_storage ifa_addrbuf;
+};
+
+static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+       while (RTA_OK(rta, len)) {
+               if (rta->rta_type <= max)
+                       tb[rta->rta_type] = rta;
+               rta = RTA_NEXT(rta,len);
+       }
+       return 0;
+}
+
+static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
+{
+       char    buf[8192];
+       struct sockaddr_nl nladdr;
+       struct iovec iov = { buf, sizeof(buf) };
+       struct ifaddrmsg *m;
+       struct rtattr * rta_tb[IFA_MAX+1];
+       struct ifaddrs *I;
+
+       while (1) {
+               int status;
+               struct nlmsghdr *h;
+
+               struct msghdr msg = {
+                       (void*)&nladdr, sizeof(nladdr),
+                       &iov,   1,
+                       NULL,   0,
+                       0
+               };
+
+               status = recvmsg(fd, &msg, 0);
+
+               if (status < 0)
+                       continue;
+
+               if (status == 0)
+                       return;
+
+               if (nladdr.nl_pid) /* Message not from kernel */
+                       continue;
+
+               h = (struct nlmsghdr*)buf;
+               while (NLMSG_OK(h, status)) {
+                       if (h->nlmsg_seq != seq)
+                               goto skip_it;
+
+                       if (h->nlmsg_type == NLMSG_DONE)
+                               return;
+
+                       if (h->nlmsg_type == NLMSG_ERROR)
+                               return;
+
+                       if (h->nlmsg_type != RTM_NEWADDR)
+                               goto skip_it;
+
+                       m = NLMSG_DATA(h);
+
+                       if (m->ifa_family != AF_INET &&
+                           m->ifa_family != AF_INET6)
+                               goto skip_it;
+
+                       if (m->ifa_flags&IFA_F_TENTATIVE)
+                               goto skip_it;
+
+                       memset(rta_tb, 0, sizeof(rta_tb));
+                       parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
+
+                       if (rta_tb[IFA_LOCAL] == NULL)
+                               rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+                       if (rta_tb[IFA_LOCAL] == NULL)
+                               goto skip_it;
+                       
+                       I = malloc(sizeof(struct ifaddrs));
+                       if (!I)
+                               return;
+                       memset(I, 0, sizeof(*I));
+
+                       I->ifa_ifindex = m->ifa_index;
+                       I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
+                       I->ifa_addr->sa_family = m->ifa_family;
+                       if (m->ifa_family == AF_INET) {
+                               struct sockaddr_in *sin = (void*)I->ifa_addr;
+                               memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
+                       } else {
+                               struct sockaddr_in6 *sin = (void*)I->ifa_addr;
+                               memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
+                               if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+                                       sin->sin6_scope_id = I->ifa_ifindex;
+                       }
+                       I->ifa_next = *ifa;
+                       *ifa = I;
+
+skip_it:
+                       h = NLMSG_NEXT(h, status);
+               }
+               if (msg.msg_flags & MSG_TRUNC)
+                       continue;
+       }
+       return;
+}
+
+static int getifaddrs(struct ifaddrs **ifa0)
+{
+       struct {
+               struct nlmsghdr nlh;
+               struct rtgenmsg g;
+       } req;
+       struct sockaddr_nl nladdr;
+       static __u32 seq;
+       struct ifaddrs *i;
+       int fd;
+
+       fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (fd < 0)
+               return -1;
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+
+       req.nlh.nlmsg_len = sizeof(req);
+       req.nlh.nlmsg_type = RTM_GETADDR;
+       req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+       req.nlh.nlmsg_pid = 0;
+       req.nlh.nlmsg_seq = ++seq;
+       req.g.rtgen_family = AF_UNSPEC;
+
+       if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       *ifa0 = NULL;
+
+       recvaddrs(fd, ifa0, seq);
+
+       close(fd);
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+       for (i=*ifa0; i; i = i->ifa_next) {
+               struct ifreq ifr;
+               ifr.ifr_ifindex = i->ifa_ifindex;
+               ioctl(fd, SIOCGIFNAME, (void*)&ifr);
+               memcpy(i->ifa_name, ifr.ifr_name, 16);
+       }
+       close(fd);
+
+       return 0;
+}
+
+static void freeifaddrs(struct ifaddrs *ifa0)
+{
+        struct ifaddrs *i;
+
+        while (ifa0) {
+                i = ifa0;
+                ifa0 = i->ifa_next;
+                free(i);
+        }
+}
+
+#endif
+
+#ifndef HAVE_GETIFADDRS
+static unsigned int
+if_maxindex()
+{
+       struct if_nameindex *p, *p0;
+       unsigned int max = 0;
+
+       p0 = if_nameindex();
+       for (p = p0; p && p->if_index && p->if_name; p++) {
+               if (max < p->if_index)
+                       max = p->if_index;
+       }
+       if_freenameindex(p0);
+       return max;
+}
+#endif
+
+
+void
+clear_myaddr()
+{
+       struct myaddrs *p, *next;
+
+       for (p = lcconf->myaddrs; p; p = next) {
+               next = p->next;
+
+               if (p->addr)
+                       racoon_free(p->addr);
+               racoon_free(p);
+       }
+
+       lcconf->myaddrs = NULL;
+
+}
+
+
+static struct myaddrs *
+find_myaddr(db, addr, udp_encap)
+       struct myaddrs *db;
+       struct sockaddr *addr;
+       int udp_encap;
+{
+       struct myaddrs *q;
+       char h1[NI_MAXHOST], h2[NI_MAXHOST];
+
+       if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0,
+           NI_NUMERICHOST | niflags) != 0)
+               return NULL;
+
+       for (q = db; q; q = q->next) {
+               if (!q->addr)
+                       continue;
+               if (q->udp_encap && !udp_encap
+                       || !q->udp_encap && udp_encap)
+                       continue;
+               if (addr->sa_family != q->addr->sa_family)
+                       continue;
+               if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2),
+                   NULL, 0, NI_NUMERICHOST | niflags) != 0)
+                       return NULL;
+               if (strcmp(h1, h2) == 0)
+                       return q;
+       }
+
+       return NULL;
+}
+
+
+// modified to avoid closing and opening sockets for
+// all interfaces each time an interface change occurs.
+// on return:  addrcount = zero indicates address no longer used
+//                             sock = -1 indicates a new address - no socket opened yet.
+void
+grab_myaddrs()
+{
+#ifdef HAVE_GETIFADDRS
+       struct myaddrs *p, *q;
+       struct ifaddrs *ifa0, *ifap;
+#ifdef INET6
+       struct sockaddr_in6 *sin6;
+#endif
+
+       char addr1[NI_MAXHOST];
+
+       if (getifaddrs(&ifa0)) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "getifaddrs failed: %s\n", strerror(errno));
+               exit(1);
+               /*NOTREACHED*/
+       }
+
+       // clear the in_use flag for each address in the list
+       for (p = lcconf->myaddrs; p; p = p->next)
+               p->in_use = 0;
+
+       for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
+
+               if (ifap->ifa_addr->sa_family != AF_INET
+#ifdef INET6
+                && ifap->ifa_addr->sa_family != AF_INET6
+#endif
+               )
+                       continue;
+
+               if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "unsuitable address: %s %s\n",
+                               ifap->ifa_name,
+                               saddrwop2str(ifap->ifa_addr));
+                       continue;
+               }
+
+               p = find_myaddr(lcconf->myaddrs, ifap->ifa_addr, 0);
+               if (p) {
+                       p->in_use = 1;
+#ifdef ENABLE_NATT
+                       q = find_myaddr(lcconf->myaddrs, ifap->ifa_addr, 1);
+                       if (q)
+                               q->in_use = 1;
+#endif                         
+               } else {        
+                       p = newmyaddr();
+                       if (p == NULL) {
+                               plog(LLV_ERROR2, LOCATION, NULL,
+                                       "unable to allocate space for addr.\n");
+                               exit(1);
+                               /*NOTREACHED*/
+                       }
+                       p->addr = dupsaddr(ifap->ifa_addr);
+                       if (p->addr == NULL) {
+                               plog(LLV_ERROR2, LOCATION, NULL,
+                                       "unable to duplicate addr.\n");
+                               exit(1);
+                               /*NOTREACHED*/
+                       }
+                       p->sock = -1;
+                       p->in_use = 1;
+
+                       if (getnameinfo(p->addr, p->addr->sa_len,
+                                       addr1, sizeof(addr1),
+                                       NULL, 0,
+                                       NI_NUMERICHOST | niflags))
+                               strlcpy(addr1, "(invalid)", sizeof(addr1));
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "my interface: %s (%s)\n",
+                               addr1, ifap->ifa_name);
+               
+                       p->next = lcconf->myaddrs;
+                       lcconf->myaddrs = p;
+                       
+#ifdef ENABLE_NATT
+                       if (natt_enabled_in_rmconf ()) {
+                               q = dupmyaddr(p);
+                               if (q == NULL) {
+                                       plog(LLV_ERROR2, LOCATION, NULL,
+                                               "unable to allocate space for natt addr.\n");
+                                       exit(1);
+                               }
+                               q->udp_encap = 1;
+                       }
+#endif
+
+               }
+       }
+
+       freeifaddrs(ifa0);
+
+
+#else /*!HAVE_GETIFADDRS*/
+#error "NOT SUPPORTED"
+#endif /*HAVE_GETIFADDRS*/
+}
+
+
+/*
+ * check the interface is suitable or not
+ */
+static int
+suitable_ifaddr(ifname, ifaddr)
+       const char *ifname;
+       const struct sockaddr *ifaddr;
+{
+#ifdef ENABLE_HYBRID
+       /* Exclude any address we got through ISAKMP mode config */
+       if (exclude_cfg_addr(ifaddr) == 0)
+               return 0;
+#endif
+       switch(ifaddr->sa_family) {
+       case AF_INET:
+               return 1;
+#ifdef INET6
+       case AF_INET6:
+               return suitable_ifaddr6(ifname, ifaddr);
+#endif
+       default:
+               return 0;
+       }
+       /*NOTREACHED*/
+}
+
+#ifdef INET6
+static int
+suitable_ifaddr6(ifname, ifaddr)
+       const char *ifname;
+       const struct sockaddr *ifaddr;
+{
+#ifndef __linux__
+       struct in6_ifreq ifr6;
+       int s;
+#endif
+
+       if (ifaddr->sa_family != AF_INET6)
+               return 0;
+
+#ifndef __linux__
+       s = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (s == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
+               return 0;
+       }
+
+       memset(&ifr6, 0, sizeof(ifr6));
+       strncpy(ifr6.ifr_name, ifname, strlen(ifname));
+
+       ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
+
+       if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
+               close(s);
+               return 0;
+       }
+
+       close(s);
+
+       if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
+        || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
+        || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
+               return 0;
+#endif
+
+       /* suitable */
+       return 1;
+}
+#endif
+
+int
+update_myaddrs()
+{
+#ifdef __linux__
+       char msg[BUFSIZ];
+       int len;
+       struct nlmsghdr *h = (void*)msg;
+       len = read(lcconf->rtsock, msg, sizeof(msg));
+       if (len < 0)
+               return errno == ENOBUFS;
+       if (len < sizeof(*h))
+               return 0;
+       if (h->nlmsg_pid) /* not from kernel! */
+               return 0;
+       if (h->nlmsg_type == RTM_NEWLINK)
+               return 0;
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "netlink signals update interface address list\n");
+       return 1;
+#else
+       char msg[BUFSIZ];
+       int len;
+       struct rt_msghdr *rtm;
+
+       len = read(lcconf->rtsock, msg, sizeof(msg));
+       if (len < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "read(PF_ROUTE) failed: %s\n",
+                       strerror(errno));
+               return 0;
+       }
+       rtm = (struct rt_msghdr *)msg;
+       if (len < rtm->rtm_msglen) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "read(PF_ROUTE) short read\n");
+               return 0;
+       }
+       if (rtm->rtm_version != RTM_VERSION) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "routing socket version mismatch\n");
+               close(lcconf->rtsock);
+               lcconf->rtsock = -1;
+               return 0;
+       }
+       switch (rtm->rtm_type) {
+       case RTM_NEWADDR:
+       case RTM_DELADDR:
+       case RTM_DELETE:
+       case RTM_IFINFO:
+               break;
+       case RTM_MISS:
+               /* ignore this message silently */
+               return 0;
+       default:
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "msg %d not interesting\n", rtm->rtm_type);
+               return 0;
+       }
+       /* XXX more filters here? */
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "caught rtm:%d, need update interface address list\n",
+               rtm->rtm_type);
+
+       return 1;
+#endif /* __linux__ */
+}
+
+/*
+ * initialize default port for ISAKMP to send, if no "listen"
+ * directive is specified in config file.
+ *
+ * DO NOT listen to wildcard addresses.  if you receive packets to
+ * wildcard address, you'll be in trouble (DoS attack possible by
+ * broadcast storm).
+ */
+int
+autoconf_myaddrsport()
+{
+       struct myaddrs *p;
+       int n;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "configuring default isakmp port.\n");
+
+       for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
+               set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
+       }
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "%d addrs are configured successfully\n", n);
+
+       return 0;
+}
+
+/*
+ * get a port number to which racoon binded.
+ * NOTE: network byte order returned.
+ */
+u_short
+getmyaddrsport(local)
+       struct sockaddr *local;
+{
+       struct myaddrs *p, *bestmatch = NULL;
+       u_short bestmatch_port = PORT_ISAKMP;
+
+       /* get a relative port */
+       for (p = lcconf->myaddrs; p; p = p->next) {
+               if (!p->addr)
+                       continue;
+               if (!cmpsaddrwop(local, p->addr)) {
+                       if (! bestmatch) {
+                               bestmatch = p;
+                               continue;
+                       }
+                       
+                       switch (p->addr->sa_family) {
+                       case AF_INET:
+                               if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) {
+                                       bestmatch = p;
+                                       bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port;
+                                       break;
+                               }
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) {
+                                       bestmatch = p;
+                                       bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port;
+                                       break;
+                               }
+                               break;
+#endif
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                    "unsupported AF %d\n", p->addr->sa_family);
+                               continue;
+                       }
+               }
+       }
+
+       return htons(bestmatch_port);
+}
+
+struct myaddrs *
+newmyaddr()
+{
+       struct myaddrs *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer for myaddrs.\n");
+               return NULL;
+       }
+
+       new->next = NULL;
+       new->addr = NULL;
+
+       return new;
+}
+
+struct myaddrs *
+dupmyaddr(struct myaddrs *old)
+{
+       struct myaddrs *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer for myaddrs.\n");
+               return NULL;
+       }
+
+       /* Copy the whole structure and set the differences.  */
+       memcpy (new, old, sizeof (*new));
+       new->addr = dupsaddr (old->addr);
+       if (new->addr == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer for duplicate addr.\n");
+               racoon_free(new);
+               return NULL;
+       }
+       new->next = old->next;
+       old->next = new;
+
+       return new;
+}
+
+void
+insmyaddr(new, head)
+       struct myaddrs *new;
+       struct myaddrs **head;
+{
+       new->next = *head;
+       *head = new;
+}
+
+void
+delmyaddr(myaddr)
+       struct myaddrs *myaddr;
+{
+       if (myaddr->addr)
+               racoon_free(myaddr->addr);
+       racoon_free(myaddr);
+}
+
+int
+initmyaddr()
+{
+       /* initialize routing socket */
+       lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
+       if (lcconf->rtsock < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "socket(PF_ROUTE) failed: %s",
+                       strerror(errno));
+               return -1;
+       }
+
+#ifdef __linux__
+   {
+       struct sockaddr_nl nl;
+       u_int addr_len;
+
+       memset(&nl, 0, sizeof(nl));
+       nl.nl_family = AF_NETLINK;
+       nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK;
+
+       if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                    "bind(PF_NETLINK) failed: %s\n",
+                    strerror(errno));
+               return -1;
+       }
+       addr_len = sizeof(nl);
+       if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                    "getsockname(PF_NETLINK) failed: %s\n",
+                    strerror(errno));
+               return -1;
+       }
+   }
+#endif
+
+       if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
+               grab_myaddrs();
+
+               if (autoconf_myaddrsport() < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* select the socket to be sent */
+/* should implement other method. */
+int
+getsockmyaddr(my)
+       struct sockaddr *my;
+{
+       struct myaddrs *p, *lastresort = NULL;
+#if defined(INET6) && defined(__linux__)
+       struct myaddrs *match_wo_scope_id = NULL;
+       int check_wo_scope_id = (my->sa_family == AF_INET6) && 
+               IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr);
+#endif
+
+       for (p = lcconf->myaddrs; p; p = p->next) {
+               if (p->addr == NULL)
+                       continue;
+               if (my->sa_family == p->addr->sa_family) {
+                       lastresort = p;
+               } else continue;
+               if (sysdep_sa_len(my) == sysdep_sa_len(p->addr)
+                && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
+                       break;
+               }
+#if defined(INET6) && defined(__linux__)
+               if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) &&
+                       /* XXX: this depends on sin6_scope_id to be last
+                        * item in struct sockaddr_in6 */
+                       memcmp(my, p->addr, 
+                               sysdep_sa_len(my) - sizeof(uint32_t)) == 0) {
+                       match_wo_scope_id = p;
+               }
+#endif
+       }
+#if defined(INET6) && defined(__linux__)
+       if (!p)
+               p = match_wo_scope_id;
+#endif
+       if (!p)
+               p = lastresort;
+       if (!p) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no socket matches address family %d\n",
+                       my->sa_family);
+               return -1;
+       }
+
+       return p->sock;
+}
diff --git a/ipsec-tools/racoon/grabmyaddr.h b/ipsec-tools/racoon/grabmyaddr.h
new file mode 100644 (file)
index 0000000..a237cb5
--- /dev/null
@@ -0,0 +1,57 @@
+/* $Id: grabmyaddr.h,v 1.5 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GRABMYADDR_H
+#define _GRABMYADDR_H
+
+struct myaddrs {
+       struct myaddrs *next;
+       struct sockaddr *addr;
+       int sock;
+       int udp_encap;
+#ifdef __APPLE__
+       int     in_use;
+#endif
+};
+
+extern void clear_myaddr __P((void));
+extern void grab_myaddrs __P((void));
+extern int update_myaddrs __P((void));
+extern int autoconf_myaddrsport __P((void));
+extern u_short getmyaddrsport __P((struct sockaddr *));
+extern struct myaddrs *newmyaddr __P((void));
+extern struct myaddrs *dupmyaddr __P((struct myaddrs *));
+extern void insmyaddr __P((struct myaddrs *, struct myaddrs **));
+extern void delmyaddr __P((struct myaddrs *));
+extern int initmyaddr __P((void));
+extern int getsockmyaddr __P((struct sockaddr *));
+
+#endif /* _GRABMYADDR_H */
diff --git a/ipsec-tools/racoon/gssapi.c b/ipsec-tools/racoon/gssapi.c
new file mode 100644 (file)
index 0000000..0a11f83
--- /dev/null
@@ -0,0 +1,745 @@
+/*     $KAME: gssapi.c,v 1.19 2001/04/03 15:51:55 thorpej Exp $        */
+
+/*
+ * Copyright 2000 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * This software was written by Frank van der Linden of Wasabi Systems
+ * for Zembu Labs, Inc. http://www.zembu.com/
+ *
+ * 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. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_GSSAPI
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "isakmp_ident.h"
+#include "isakmp_inf.h"
+#include "vendorid.h"
+#include "gcmalloc.h"
+
+#include "gssapi.h"
+
+static void
+gssapi_error(OM_uint32 status_code, const char *where,
+            const char *fmt, ...)
+{
+       OM_uint32 message_context, maj_stat, min_stat;
+       gss_buffer_desc status_string;
+       va_list ap;
+
+       va_start(ap, fmt);
+       plogv(LLV_ERROR, where, NULL, fmt, ap);
+       va_end(ap);
+
+       message_context = 0;
+
+       do {
+               maj_stat = gss_display_status(&min_stat, status_code,
+                   GSS_C_MECH_CODE, GSS_C_NO_OID, &message_context,
+                   &status_string);
+               if (GSS_ERROR(maj_stat))
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "UNABLE TO GET GSSAPI ERROR CODE\n");
+               else {
+                       plog(LLV_ERROR, where, NULL,
+                           "%s\n", (char *)status_string.value);
+                       gss_release_buffer(&min_stat, &status_string);
+               }
+       } while (message_context != 0);
+}
+
+/*
+ * vmbufs and gss_buffer_descs are really just the same on NetBSD, but
+ * this is to be portable.
+ */
+static int
+gssapi_vm2gssbuf(vchar_t *vmbuf, gss_buffer_t gsstoken)
+{
+
+       gsstoken->value = racoon_malloc(vmbuf->l);
+       if (gsstoken->value == NULL)
+               return -1;
+       memcpy(gsstoken->value, vmbuf->v, vmbuf->l);
+       gsstoken->length = vmbuf->l;
+
+       return 0;
+}
+
+static int
+gssapi_gss2vmbuf(gss_buffer_t gsstoken, vchar_t **vmbuf)
+{
+
+       *vmbuf = vmalloc(gsstoken->length);
+       if (*vmbuf == NULL)
+               return -1;
+       memcpy((*vmbuf)->v, gsstoken->value, gsstoken->length);
+       (*vmbuf)->l = gsstoken->length;
+
+       return 0;
+}
+
+vchar_t *
+gssapi_get_default_gss_id(void)
+{
+       char name[NI_MAXHOST];
+       vchar_t *gssid;
+
+       if (gethostname(name, sizeof(name)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "gethostname failed: %s\n",
+                   strerror(errno));
+               return (NULL);
+       }
+       name[sizeof(name) - 1] = '\0';
+
+       gssid = racoon_malloc(sizeof(*gssid));
+       gssid->l = asprintf(&gssid->v, "%s/%s", GSSAPI_DEF_NAME, name);
+
+       return (gssid);
+}
+
+static int
+gssapi_get_default_name(struct ph1handle *iph1, int remote, gss_name_t *service)
+{
+       char name[NI_MAXHOST];
+       struct sockaddr *sa;
+       gss_buffer_desc name_token;
+       OM_uint32 min_stat, maj_stat;
+
+       sa = remote ? iph1->remote : iph1->local;
+
+       if (getnameinfo(sa, sysdep_sa_len(sa), name, NI_MAXHOST, NULL, 0, 0) != 0)
+               return -1;
+
+       name_token.length = asprintf((char **)&name_token.value,
+           "%s@%s", GSSAPI_DEF_NAME, name);  
+       maj_stat = gss_import_name(&min_stat, &name_token,
+           GSS_C_NT_HOSTBASED_SERVICE, service);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "import name\n");
+               maj_stat = gss_release_buffer(&min_stat, &name_token);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION, "release name_token");
+               return -1;
+       }
+       maj_stat = gss_release_buffer(&min_stat, &name_token);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release name_token");
+
+       return 0;
+}
+
+static int
+gssapi_init(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+       gss_buffer_desc id_token, cred_token;
+       gss_buffer_t cred = &cred_token;
+       gss_name_t princ, canon_princ;
+       OM_uint32 maj_stat, min_stat;
+
+       gps = racoon_calloc(1, sizeof (struct gssapi_ph1_state));
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "racoon_calloc failed\n");
+               return -1;
+       }
+       gps->gss_context = GSS_C_NO_CONTEXT;
+       gps->gss_cred = GSS_C_NO_CREDENTIAL;
+
+       gssapi_set_state(iph1, gps);
+
+       if (iph1->rmconf->proposal->gssid != NULL) {
+               id_token.length = iph1->rmconf->proposal->gssid->l;
+               id_token.value = iph1->rmconf->proposal->gssid->v;
+               maj_stat = gss_import_name(&min_stat, &id_token, GSS_C_NO_OID,
+                   &princ);
+               if (GSS_ERROR(maj_stat)) {
+                       gssapi_error(min_stat, LOCATION, "import name\n");
+                       gssapi_free_state(iph1);
+                       return -1;
+               }
+       } else
+               gssapi_get_default_name(iph1, 0, &princ);
+
+       maj_stat = gss_canonicalize_name(&min_stat, princ, GSS_C_NO_OID,
+           &canon_princ);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "canonicalize name\n");
+               maj_stat = gss_release_name(&min_stat, &princ);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION, "release princ\n");
+               gssapi_free_state(iph1);
+               return -1;
+       }
+       maj_stat = gss_release_name(&min_stat, &princ);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release princ\n");
+
+       maj_stat = gss_export_name(&min_stat, canon_princ, cred);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "export name\n");
+               maj_stat = gss_release_name(&min_stat, &canon_princ);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release canon_princ\n");
+               gssapi_free_state(iph1);
+               return -1;
+       }
+
+#if 0
+       /*
+        * XXXJRT Did this debug message ever work?  This is a GSS name
+        * blob at this point.
+        */
+       plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
+           cred->length, cred->value);
+#endif
+
+       maj_stat = gss_release_buffer(&min_stat, cred);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release cred buffer\n");
+
+       maj_stat = gss_acquire_cred(&min_stat, canon_princ, GSS_C_INDEFINITE,
+           GSS_C_NO_OID_SET, GSS_C_BOTH, &gps->gss_cred, NULL, NULL);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "acquire cred\n");
+               maj_stat = gss_release_name(&min_stat, &canon_princ);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release canon_princ\n");
+               gssapi_free_state(iph1);
+               return -1;
+       }
+       maj_stat = gss_release_name(&min_stat, &canon_princ);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release canon_princ\n");
+
+       return 0;
+}
+
+int
+gssapi_get_itoken(struct ph1handle *iph1, int *lenp)
+{
+       struct gssapi_ph1_state *gps;
+       gss_buffer_desc empty, name_token;
+       gss_buffer_t itoken, rtoken, dummy;
+       OM_uint32 maj_stat, min_stat;
+       gss_name_t partner;
+
+       if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
+               return -1;
+
+       gps = gssapi_get_state(iph1);
+
+       empty.length = 0;
+       empty.value = NULL;
+       dummy = &empty;
+
+       if (iph1->approval != NULL && iph1->approval->gssid != NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                   "using provided service '%.*s'\n",
+                   iph1->approval->gssid->l, iph1->approval->gssid->v);
+               name_token.length = iph1->approval->gssid->l;
+               name_token.value = iph1->approval->gssid->v;
+               maj_stat = gss_import_name(&min_stat, &name_token,
+                   GSS_C_NO_OID, &partner);
+               if (GSS_ERROR(maj_stat)) {
+                       gssapi_error(min_stat, LOCATION, "import of %.*s\n",
+                           name_token.length, name_token.value);
+                       return -1;
+               }
+       } else
+               if (gssapi_get_default_name(iph1, 1, &partner) < 0)
+                       return -1;
+
+       rtoken = gps->gsscnt_p == 0 ? dummy : &gps->gss_p[gps->gsscnt_p - 1];
+       itoken = &gps->gss[gps->gsscnt];
+
+       gps->gss_status = gss_init_sec_context(&min_stat, gps->gss_cred,
+           &gps->gss_context, partner, GSS_C_NO_OID,
+           GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG |
+               GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG,
+           0, GSS_C_NO_CHANNEL_BINDINGS, rtoken, NULL,
+           itoken, NULL, NULL);
+
+       if (GSS_ERROR(gps->gss_status)) {
+               gssapi_error(min_stat, LOCATION, "init_sec_context\n");
+               maj_stat = gss_release_name(&min_stat, &partner);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION, "release name\n");
+               return -1;
+       }
+       maj_stat = gss_release_name(&min_stat, &partner);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release name\n");
+
+       plog(LLV_DEBUG, LOCATION, NULL, "gss_init_sec_context status %x\n",
+           gps->gss_status);
+
+       if (lenp)
+               *lenp = itoken->length;
+
+       if (itoken->length != 0)
+               gps->gsscnt++;
+
+       return 0;
+}
+
+/*
+ * Call gss_accept_context, with token just read from the wire.
+ */
+int
+gssapi_get_rtoken(struct ph1handle *iph1, int *lenp)
+{
+       struct gssapi_ph1_state *gps;
+       gss_buffer_desc name_token;
+       gss_buffer_t itoken, rtoken;
+       OM_uint32 min_stat, maj_stat;
+       gss_name_t client_name;
+
+       if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
+               return -1;
+
+       gps = gssapi_get_state(iph1);
+
+       rtoken = &gps->gss_p[gps->gsscnt_p - 1];
+       itoken = &gps->gss[gps->gsscnt];
+
+       gps->gss_status = gss_accept_sec_context(&min_stat, &gps->gss_context,
+           gps->gss_cred, rtoken, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
+           NULL, itoken, NULL, NULL, NULL);
+
+       if (GSS_ERROR(gps->gss_status)) {
+               gssapi_error(min_stat, LOCATION, "accept_sec_context\n");
+               return -1;
+       }
+
+       maj_stat = gss_display_name(&min_stat, client_name, &name_token, NULL);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "gss_display_name\n");
+               maj_stat = gss_release_name(&min_stat, &client_name);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release client_name\n");
+               return -1;
+       }
+       maj_stat = gss_release_name(&min_stat, &client_name);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release client_name\n");
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "gss_accept_sec_context: other side is %s\n",
+               (char *)name_token.value);
+       maj_stat = gss_release_buffer(&min_stat, &name_token);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release name buffer\n");
+
+       if (itoken->length != 0)
+               gps->gsscnt++;
+
+       if (lenp)
+               *lenp = itoken->length;
+
+       return 0;
+}
+
+int
+gssapi_save_received_token(struct ph1handle *iph1, vchar_t *token)
+{
+       struct gssapi_ph1_state *gps;
+       gss_buffer_t gsstoken;
+       int ret;
+
+       if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
+               return -1;
+
+       gps = gssapi_get_state(iph1);
+
+       gsstoken = &gps->gss_p[gps->gsscnt_p];
+
+       ret = gssapi_vm2gssbuf(token, gsstoken);
+       if (ret < 0)
+               return ret;
+       gps->gsscnt_p++;
+
+       return 0;
+}
+
+int
+gssapi_get_token_to_send(struct ph1handle *iph1, vchar_t **token)
+{
+       struct gssapi_ph1_state *gps;
+       gss_buffer_t gsstoken;
+       int ret;
+
+       gps = gssapi_get_state(iph1);
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi not yet initialized?\n");
+               return -1;
+       }
+       gsstoken = &gps->gss[gps->gsscnt - 1];
+       ret = gssapi_gss2vmbuf(gsstoken, token);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+int
+gssapi_get_itokens(struct ph1handle *iph1, vchar_t **tokens)
+{
+       struct gssapi_ph1_state *gps;
+       int len, i;
+       vchar_t *toks;
+       char *p;
+
+       gps = gssapi_get_state(iph1);
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi not yet initialized?\n");
+               return -1;
+       }
+
+       for (i = len = 0; i < gps->gsscnt; i++)
+               len += gps->gss[i].length;
+
+       toks = vmalloc(len);
+       if (toks == 0)
+               return -1;
+       p = (char *)toks->v;
+       for (i = 0; i < gps->gsscnt; i++) {
+               memcpy(p, gps->gss[i].value, gps->gss[i].length);
+               p += gps->gss[i].length;
+       }
+
+       *tokens = toks;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "%d itokens of length %d\n", gps->gsscnt, (*tokens)->l);
+
+       return 0;
+}
+
+int
+gssapi_get_rtokens(struct ph1handle *iph1, vchar_t **tokens)
+{
+       struct gssapi_ph1_state *gps;
+       int len, i;
+       vchar_t *toks;
+       char *p;
+
+       gps = gssapi_get_state(iph1);
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi not yet initialized?\n");
+               return -1;
+       }
+
+       if (gssapi_more_tokens(iph1)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi roundtrips not complete\n");
+               return -1;
+       }
+
+       for (i = len = 0; i < gps->gsscnt_p; i++)
+               len += gps->gss_p[i].length;
+
+       toks = vmalloc(len);
+       if (toks == 0)
+               return -1;
+       p = (char *)toks->v;
+       for (i = 0; i < gps->gsscnt_p; i++) {
+               memcpy(p, gps->gss_p[i].value, gps->gss_p[i].length);
+               p += gps->gss_p[i].length;
+       }
+
+       *tokens = toks;
+
+       return 0;
+}
+
+vchar_t *
+gssapi_wraphash(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+       OM_uint32 maj_stat, min_stat;
+       gss_buffer_desc hash_in_buf, hash_out_buf;
+       gss_buffer_t hash_in = &hash_in_buf, hash_out = &hash_out_buf;
+       vchar_t *outbuf;
+
+       gps = gssapi_get_state(iph1);
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi not yet initialized?\n");
+               return NULL;
+       }
+
+       if (gssapi_more_tokens(iph1)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi roundtrips not complete\n");
+               return NULL;
+       }
+
+       if (gssapi_vm2gssbuf(iph1->hash, hash_in) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "vm2gssbuf failed\n");
+               return NULL;
+       }
+
+       maj_stat = gss_wrap(&min_stat, gps->gss_context, 1, GSS_C_QOP_DEFAULT,
+           hash_in, NULL, hash_out);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "wrapping hash value\n");
+               maj_stat = gss_release_buffer(&min_stat, hash_in);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release hash_in buffer\n");
+               return NULL;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "wrapped HASH, ilen %d olen %d\n",
+           hash_in->length, hash_out->length);
+
+       maj_stat = gss_release_buffer(&min_stat, hash_in);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release hash_in buffer\n");
+
+       if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
+               maj_stat = gss_release_buffer(&min_stat, hash_out);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release hash_out buffer\n");
+               return NULL;
+       }
+       maj_stat = gss_release_buffer(&min_stat, hash_out);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
+
+       return outbuf;
+}
+
+vchar_t *
+gssapi_unwraphash(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+       OM_uint32 maj_stat, min_stat;
+       gss_buffer_desc hashbuf, hash_outbuf;
+       gss_buffer_t hash_in = &hashbuf, hash_out = &hash_outbuf;
+       vchar_t *outbuf;
+
+       gps = gssapi_get_state(iph1);
+       if (gps == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "gssapi not yet initialized?\n");
+               return NULL;
+       }
+
+
+       hashbuf.length = ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash);
+       hashbuf.value = (char *)(iph1->pl_hash + 1);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "unwrapping HASH of len %d\n",
+           hashbuf.length);
+
+       maj_stat = gss_unwrap(&min_stat, gps->gss_context, hash_in, hash_out,
+           NULL, NULL);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "unwrapping hash value\n");
+               return NULL;
+       }
+
+       if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
+               maj_stat = gss_release_buffer(&min_stat, hash_out);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release hash_out buffer\n");
+               return NULL;
+       }
+       maj_stat = gss_release_buffer(&min_stat, hash_out);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");
+
+       return outbuf;
+}
+
+void
+gssapi_set_id_sent(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+
+       gps = gssapi_get_state(iph1);
+
+       gps->gss_flags |= GSSFLAG_ID_SENT;
+}
+
+int
+gssapi_id_sent(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+
+       gps = gssapi_get_state(iph1);
+
+       return (gps->gss_flags & GSSFLAG_ID_SENT) != 0;
+}
+
+void
+gssapi_set_id_rcvd(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+
+       gps = gssapi_get_state(iph1);
+
+       gps->gss_flags |= GSSFLAG_ID_RCVD;
+}
+
+int
+gssapi_id_rcvd(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+
+       gps = gssapi_get_state(iph1);
+
+       return (gps->gss_flags & GSSFLAG_ID_RCVD) != 0;
+}
+
+void
+gssapi_free_state(struct ph1handle *iph1)
+{
+       struct gssapi_ph1_state *gps;
+       OM_uint32 maj_stat, min_stat;
+
+       gps = gssapi_get_state(iph1);
+
+       if (gps == NULL)
+               return;
+
+       gssapi_set_state(iph1, NULL);
+
+       if (gps->gss_cred != GSS_C_NO_CREDENTIAL) {
+               maj_stat = gss_release_cred(&min_stat, &gps->gss_cred);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "releasing credentials\n");
+       }
+       racoon_free(gps);
+}
+
+vchar_t *
+gssapi_get_id(struct ph1handle *iph1)
+{
+       gss_buffer_desc id_buffer;
+       gss_buffer_t id = &id_buffer;
+       gss_name_t defname, canon_name;
+       OM_uint32 min_stat, maj_stat;
+       vchar_t *vmbuf;
+
+       if (iph1->rmconf->proposal->gssid != NULL)
+               return (vdup(iph1->rmconf->proposal->gssid));
+
+       if (gssapi_get_default_name(iph1, 0, &defname) < 0)
+               return NULL;
+
+       maj_stat = gss_canonicalize_name(&min_stat, defname, GSS_C_NO_OID,
+           &canon_name);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "canonicalize name\n");
+               maj_stat = gss_release_name(&min_stat, &defname);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release default name\n");
+               return NULL;
+       }
+       maj_stat = gss_release_name(&min_stat, &defname);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release default name\n");
+
+       maj_stat = gss_export_name(&min_stat, canon_name, id);
+       if (GSS_ERROR(maj_stat)) {
+               gssapi_error(min_stat, LOCATION, "export name\n");
+               maj_stat = gss_release_name(&min_stat, &canon_name);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION,
+                           "release canonical name\n");
+               return NULL;
+       }
+       maj_stat = gss_release_name(&min_stat, &canon_name);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release canonical name\n");
+
+#if 0
+       /*
+        * XXXJRT Did this debug message ever work?  This is a GSS name
+        * blob at this point.
+        */
+       plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%.*s' creds\n",
+           id->length, id->value);
+#endif
+
+       if (gssapi_gss2vmbuf(id, &vmbuf) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
+               maj_stat = gss_release_buffer(&min_stat, id);
+               if (GSS_ERROR(maj_stat))
+                       gssapi_error(min_stat, LOCATION, "release id buffer\n");
+               return NULL;
+       }
+       maj_stat = gss_release_buffer(&min_stat, id);
+       if (GSS_ERROR(maj_stat))
+               gssapi_error(min_stat, LOCATION, "release id buffer\n");
+
+       return vmbuf;
+}
+#else
+int __gssapi_dUmMy;
+#endif
diff --git a/ipsec-tools/racoon/gssapi.h b/ipsec-tools/racoon/gssapi.h
new file mode 100644 (file)
index 0000000..8994281
--- /dev/null
@@ -0,0 +1,95 @@
+/* $Id: gssapi.h,v 1.5 2005/02/11 06:59:01 manubsd Exp $ */
+
+/*
+ * Copyright 2000 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * This software was written by Frank van der Linden of Wasabi Systems
+ * for Zembu Labs, Inc. http://www.zembu.com/
+ *
+ * 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. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+#ifndef __GSSAPI_H__
+#define __GSSAPI_H__
+
+#ifdef __FreeBSD__
+#include "/usr/include/gssapi.h"
+#else
+#include <gssapi/gssapi.h>
+#endif
+
+#define GSSAPI_DEF_NAME         "host"
+
+struct ph1handle;
+struct isakmpsa;
+
+struct gssapi_ph1_state {
+       int gsscnt;                     /* # of token we're working on */
+       int gsscnt_p;                   /* # of token we're working on */
+
+       gss_buffer_desc gss[3];         /* gss-api tokens. */
+                                       /* NOTE: XXX this restricts the max # */
+                                       /* to 3. More should never happen */
+
+       gss_buffer_desc gss_p[3];
+
+       gss_ctx_id_t gss_context;       /* context for gss_init_sec_context */
+
+       OM_uint32 gss_status;           /* retval from gss_init_sec_context */
+       gss_cred_id_t gss_cred;         /* acquired credentials */
+
+       int gss_flags;
+#define GSSFLAG_ID_SENT                0x0001
+#define GSSFLAG_ID_RCVD                0x0001
+};
+
+#define        gssapi_get_state(ph)                                            \
+       ((struct gssapi_ph1_state *)((ph)->gssapi_state))
+
+#define        gssapi_set_state(ph, st)                                        \
+       (ph)->gssapi_state = (st)
+
+#define        gssapi_more_tokens(ph)                                          \
+       ((gssapi_get_state(ph)->gss_status & GSS_S_CONTINUE_NEEDED) != 0)
+
+int gssapi_get_itoken __P((struct ph1handle *, int *));
+int gssapi_get_rtoken __P((struct ph1handle *, int *));
+int gssapi_save_received_token __P((struct ph1handle *, vchar_t *));
+int gssapi_get_token_to_send __P((struct ph1handle *, vchar_t **));
+int gssapi_get_itokens __P((struct ph1handle *, vchar_t **));
+int gssapi_get_rtokens __P((struct ph1handle *, vchar_t **));
+vchar_t *gssapi_wraphash __P((struct ph1handle *));
+vchar_t *gssapi_unwraphash __P((struct ph1handle *));
+void gssapi_set_id_sent __P((struct ph1handle *));
+int gssapi_id_sent __P((struct ph1handle *));
+void gssapi_set_id_rcvd __P((struct ph1handle *));
+int gssapi_id_rcvd __P((struct ph1handle *));
+void gssapi_free_state __P((struct ph1handle *));
+vchar_t *gssapi_get_id __P((struct ph1handle *));
+vchar_t *gssapi_get_default_gss_id __P((void));
+
+#endif /* __GSSAPI_H__ */
+
diff --git a/ipsec-tools/racoon/handler.c b/ipsec-tools/racoon/handler.c
new file mode 100644 (file)
index 0000000..4082bb5
--- /dev/null
@@ -0,0 +1,1040 @@
+/* $Id: handler.c,v 1.13.4.4 2005/07/14 12:00:36 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "grabmyaddr.h"
+#include "algorithm.h"
+#include "crypto_openssl.h"
+#include "policy.h"
+#include "proposal.h"
+#include "isakmp_var.h"
+#include "evt.h"
+#include "isakmp.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"  
+#include "isakmp_cfg.h"
+#endif
+#include "isakmp_inf.h"
+#include "oakley.h"
+#include "remoteconf.h"
+#include "localconf.h"
+#include "handler.h"
+#include "gcmalloc.h"
+#include "nattraversal.h"
+
+#ifdef HAVE_GSSAPI
+#include "gssapi.h"
+#endif
+
+static LIST_HEAD(_ph1tree_, ph1handle) ph1tree;
+static LIST_HEAD(_ph2tree_, ph2handle) ph2tree;
+static LIST_HEAD(_ctdtree_, contacted) ctdtree;
+static LIST_HEAD(_rcptree_, recvdpkt) rcptree;
+
+static void del_recvdpkt __P((struct recvdpkt *));
+static void rem_recvdpkt __P((struct recvdpkt *));
+static void sweep_recvdpkt __P((void *));
+
+/*
+ * functions about management of the isakmp status table
+ */
+/* %%% management phase 1 handler */
+/*
+ * search for isakmpsa handler with isakmp index.
+ */
+
+extern caddr_t val2str(const char *, size_t);
+
+struct ph1handle *
+getph1byindex(index)
+       isakmp_index *index;
+{
+       struct ph1handle *p;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if (p->status == PHASE1ST_EXPIRED)
+                       continue;
+               if (memcmp(&p->index, index, sizeof(*index)) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * search for isakmp handler by i_ck in index.
+ */
+struct ph1handle *
+getph1byindex0(index)
+       isakmp_index *index;
+{
+       struct ph1handle *p;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if (p->status == PHASE1ST_EXPIRED)
+                       continue;
+               if (memcmp(&p->index, index, sizeof(cookie_t)) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * search for isakmpsa handler by source and remote address.
+ * don't use port number to search because this function search
+ * with phase 2's destinaion.
+ */
+struct ph1handle *
+getph1byaddr(local, remote)
+       struct sockaddr *local, *remote;
+{
+       struct ph1handle *p;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if (p->status == PHASE1ST_EXPIRED)
+                       continue;
+               if (CMPSADDR(local, p->local) == 0
+                && CMPSADDR(remote, p->remote) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+struct ph1handle *
+getph1byaddrwop(local, remote)
+       struct sockaddr *local, *remote;
+{
+       struct ph1handle *p;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if (p->status == PHASE1ST_EXPIRED)
+                       continue;
+               if (cmpsaddrwop(local, p->local) == 0
+                && cmpsaddrwop(remote, p->remote) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * search for isakmpsa handler by remote address.
+ * don't use port number to search because this function search
+ * with phase 2's destinaion.
+ */
+struct ph1handle *
+getph1bydstaddrwop(remote)
+       struct sockaddr *remote;
+{
+       struct ph1handle *p;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if (p->status == PHASE1ST_EXPIRED)
+                       continue;
+               if (cmpsaddrwop(remote, p->remote) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * dump isakmp-sa
+ */
+vchar_t *
+dumpph1()
+{
+       struct ph1handle *iph1;
+       struct ph1dump *pd;
+       int cnt = 0;
+       vchar_t *buf;
+
+       /* get length of buffer */
+       LIST_FOREACH(iph1, &ph1tree, chain)
+               cnt++;
+
+       buf = vmalloc(cnt * sizeof(struct ph1dump));
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer\n");
+               return NULL;
+       }
+       pd = (struct ph1dump *)buf->v;
+
+       LIST_FOREACH(iph1, &ph1tree, chain) {
+               memcpy(&pd->index, &iph1->index, sizeof(iph1->index));
+               pd->status = iph1->status;
+               pd->side = iph1->side;
+               memcpy(&pd->remote, iph1->remote, sysdep_sa_len(iph1->remote));
+               memcpy(&pd->local, iph1->local, sysdep_sa_len(iph1->local));
+               pd->version = iph1->version;
+               pd->etype = iph1->etype;
+               pd->created = iph1->created;
+               pd->ph2cnt = iph1->ph2cnt;
+               pd++;
+       }
+
+       return buf;
+}
+
+/*
+ * create new isakmp Phase 1 status record to handle isakmp in Phase1
+ */
+struct ph1handle *
+newph1()
+{
+       struct ph1handle *iph1;
+
+       /* create new iph1 */
+       iph1 = racoon_calloc(1, sizeof(*iph1));
+       if (iph1 == NULL)
+               return NULL;
+
+       iph1->status = PHASE1ST_SPAWN;
+
+#ifdef ENABLE_DPD
+       iph1->dpd_support = 0;
+       iph1->dpd_lastack = 0;
+       iph1->dpd_seq = 0;
+       iph1->dpd_fails = 0;
+       iph1->dpd_r_u = NULL;
+#endif
+
+       return iph1;
+}
+
+/*
+ * delete new isakmp Phase 1 status record to handle isakmp in Phase1
+ */
+void
+delph1(iph1)
+       struct ph1handle *iph1;
+{
+       /* SA down shell script hook */
+       if (iph1 != NULL)
+               script_hook(iph1, SCRIPT_PHASE1_DOWN);
+
+       EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
+
+#ifdef ENABLE_NATT
+#ifndef __APPLE__
+       if (iph1->natt_flags & NAT_KA_QUEUED)
+               natt_keepalive_remove (iph1->local, iph1->remote);
+#endif /* __APPLE__ */
+       if (iph1->natt_options) {
+               racoon_free(iph1->natt_options);
+               iph1->natt_options = NULL;
+       }
+#endif
+
+#ifdef ENABLE_DPD
+       if (iph1->dpd_r_u != NULL)
+               SCHED_KILL(iph1->dpd_r_u);
+#endif
+
+       if (iph1->remote) {
+               racoon_free(iph1->remote);
+               iph1->remote = NULL;
+       }
+       if (iph1->local) {
+               racoon_free(iph1->local);
+               iph1->local = NULL;
+       }
+
+       if (iph1->approval) {
+               delisakmpsa(iph1->approval);
+               iph1->approval = NULL;
+       }
+
+#ifdef ENABLE_HYBRID
+       if (iph1->mode_cfg)
+               isakmp_cfg_rmstate(iph1);
+#endif
+
+       VPTRINIT(iph1->authstr);
+
+       sched_scrub_param(iph1);
+       iph1->sce = NULL;
+       iph1->scr = NULL;
+
+       VPTRINIT(iph1->sendbuf);
+
+       VPTRINIT(iph1->dhpriv);
+       VPTRINIT(iph1->dhpub);
+       VPTRINIT(iph1->dhpub_p);
+       VPTRINIT(iph1->dhgxy);
+       VPTRINIT(iph1->nonce);
+       VPTRINIT(iph1->nonce_p);
+       VPTRINIT(iph1->skeyid);
+       VPTRINIT(iph1->skeyid_d);
+       VPTRINIT(iph1->skeyid_a);
+       VPTRINIT(iph1->skeyid_e);
+       VPTRINIT(iph1->key);
+       VPTRINIT(iph1->hash);
+       VPTRINIT(iph1->sig);
+       VPTRINIT(iph1->sig_p);
+       oakley_delcert(iph1->cert);
+       iph1->cert = NULL;
+       oakley_delcert(iph1->cert_p);
+       iph1->cert_p = NULL;
+       oakley_delcert(iph1->crl_p);
+       iph1->crl_p = NULL;
+       oakley_delcert(iph1->cr_p);
+       iph1->cr_p = NULL;
+       VPTRINIT(iph1->id);
+       VPTRINIT(iph1->id_p);
+
+       if (iph1->ivm) {
+               oakley_delivm(iph1->ivm);
+               iph1->ivm = NULL;
+       }
+
+       VPTRINIT(iph1->sa);
+       VPTRINIT(iph1->sa_ret);
+
+#ifdef HAVE_GSSAPI
+       VPTRINIT(iph1->gi_i);
+       VPTRINIT(iph1->gi_r);
+
+       gssapi_free_state(iph1);
+#endif
+
+       racoon_free(iph1);
+}
+
+/*
+ * create new isakmp Phase 1 status record to handle isakmp in Phase1
+ */
+int
+insph1(iph1)
+       struct ph1handle *iph1;
+{
+       /* validity check */
+       if (iph1->remote == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid isakmp SA handler. no remote address.\n");
+               return -1;
+       }
+       LIST_INSERT_HEAD(&ph1tree, iph1, chain);
+
+       return 0;
+}
+
+void
+remph1(iph1)
+       struct ph1handle *iph1;
+{
+       LIST_REMOVE(iph1, chain);
+}
+
+/*
+ * flush isakmp-sa
+ */
+void
+flushph1()
+{
+       struct ph1handle *p, *next;
+
+       for (p = LIST_FIRST(&ph1tree); p; p = next) {
+               next = LIST_NEXT(p, chain);
+
+               /* send delete information */
+               if (p->status == PHASE1ST_ESTABLISHED) 
+                       isakmp_info_send_d1(p);
+
+               remph1(p);
+               delph1(p);
+       }
+}
+
+void
+initph1tree()
+{
+       LIST_INIT(&ph1tree);
+}
+
+/* %%% management phase 2 handler */
+/*
+ * search ph2handle with policy id.
+ */
+struct ph2handle *
+getph2byspid(spid)
+      u_int32_t spid;
+{
+       struct ph2handle *p;
+
+       LIST_FOREACH(p, &ph2tree, chain) {
+               /*
+                * there are ph2handle independent on policy
+                * such like informational exchange.
+                */
+               if (p->spid == spid)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * search ph2handle with sequence number.
+ */
+struct ph2handle *
+getph2byseq(seq)
+       u_int32_t seq;
+{
+       struct ph2handle *p;
+
+       LIST_FOREACH(p, &ph2tree, chain) {
+               if (p->seq == seq)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * search ph2handle with message id.
+ */
+struct ph2handle *
+getph2bymsgid(iph1, msgid)
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+{
+       struct ph2handle *p;
+
+       LIST_FOREACH(p, &ph2tree, chain) {
+               if (p->msgid == msgid)
+                       return p;
+       }
+
+       return NULL;
+}
+
+struct ph2handle *
+getph2byid(src, dst, spid)
+       struct sockaddr *src, *dst;
+       u_int32_t spid;
+{
+       struct ph2handle *p;
+
+       LIST_FOREACH(p, &ph2tree, chain) {
+               if (spid == p->spid &&
+                   CMPSADDR(src, p->src) == 0 &&
+                   CMPSADDR(dst, p->dst) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+struct ph2handle *
+getph2bysaddr(src, dst)
+       struct sockaddr *src, *dst;
+{
+       struct ph2handle *p;
+
+       LIST_FOREACH(p, &ph2tree, chain) {
+               if (cmpsaddrstrict(src, p->src) == 0 &&
+                   cmpsaddrstrict(dst, p->dst) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * call by pk_recvexpire().
+ */
+struct ph2handle *
+getph2bysaidx(src, dst, proto_id, spi)
+       struct sockaddr *src, *dst;
+       u_int proto_id;
+       u_int32_t spi;
+{
+       struct ph2handle *iph2;
+       struct saproto *pr;
+
+       LIST_FOREACH(iph2, &ph2tree, chain) {
+               if (iph2->proposal == NULL && iph2->approval == NULL)
+                       continue;
+               if (iph2->approval != NULL) {
+                       for (pr = iph2->approval->head; pr != NULL;
+                            pr = pr->next) {
+                               if (proto_id != pr->proto_id)
+                                       break;
+                               if (spi == pr->spi || spi == pr->spi_p)
+                                       return iph2;
+                       }
+               } else if (iph2->proposal != NULL) {
+                       for (pr = iph2->proposal->head; pr != NULL;
+                            pr = pr->next) {
+                               if (proto_id != pr->proto_id)
+                                       break;
+                               if (spi == pr->spi)
+                                       return iph2;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * create new isakmp Phase 2 status record to handle isakmp in Phase2
+ */
+struct ph2handle *
+newph2()
+{
+       struct ph2handle *iph2 = NULL;
+
+       /* create new iph2 */
+       iph2 = racoon_calloc(1, sizeof(*iph2));
+       if (iph2 == NULL)
+               return NULL;
+
+       iph2->status = PHASE1ST_SPAWN;
+
+       return iph2;
+}
+
+/*
+ * initialize ph2handle
+ * NOTE: don't initialize src/dst.
+ *       SPI in the proposal is cleared.
+ */
+void
+initph2(iph2)
+       struct ph2handle *iph2;
+{
+       sched_scrub_param(iph2);
+       iph2->sce = NULL;
+       iph2->scr = NULL;
+
+       VPTRINIT(iph2->sendbuf);
+       VPTRINIT(iph2->msg1);
+
+       /* clear spi, keep variables in the proposal */
+       if (iph2->proposal) {
+               struct saproto *pr;
+               for (pr = iph2->proposal->head; pr != NULL; pr = pr->next)
+                       pr->spi = 0;
+       }
+
+       /* clear approval */
+       if (iph2->approval) {
+               flushsaprop(iph2->approval);
+               iph2->approval = NULL;
+       }
+
+       /* clear the generated policy */
+       if (iph2->spidx_gen) {
+               delsp_bothdir((struct policyindex *)iph2->spidx_gen);
+               racoon_free(iph2->spidx_gen);
+               iph2->spidx_gen = NULL;
+       }
+
+       if (iph2->pfsgrp) {
+               oakley_dhgrp_free(iph2->pfsgrp);
+               iph2->pfsgrp = NULL;
+       }
+
+       VPTRINIT(iph2->dhpriv);
+       VPTRINIT(iph2->dhpub);
+       VPTRINIT(iph2->dhpub_p);
+       VPTRINIT(iph2->dhgxy);
+       VPTRINIT(iph2->id);
+       VPTRINIT(iph2->id_p);
+       VPTRINIT(iph2->nonce);
+       VPTRINIT(iph2->nonce_p);
+       VPTRINIT(iph2->sa);
+       VPTRINIT(iph2->sa_ret);
+
+       if (iph2->ivm) {
+               oakley_delivm(iph2->ivm);
+               iph2->ivm = NULL;
+       }
+}
+
+/*
+ * delete new isakmp Phase 2 status record to handle isakmp in Phase2
+ */
+void
+delph2(iph2)
+       struct ph2handle *iph2;
+{
+       initph2(iph2);
+
+       if (iph2->src) {
+               racoon_free(iph2->src);
+               iph2->src = NULL;
+       }
+       if (iph2->dst) {
+               racoon_free(iph2->dst);
+               iph2->dst = NULL;
+       }
+       if (iph2->src_id) {
+             racoon_free(iph2->src_id);
+             iph2->src_id = NULL;
+       }
+       if (iph2->dst_id) {
+             racoon_free(iph2->dst_id);
+             iph2->dst_id = NULL;
+       }
+
+       if (iph2->proposal) {
+               flushsaprop(iph2->proposal);
+               iph2->proposal = NULL;
+       }
+
+       racoon_free(iph2);
+}
+
+/*
+ * create new isakmp Phase 2 status record to handle isakmp in Phase2
+ */
+int
+insph2(iph2)
+       struct ph2handle *iph2;
+{
+       LIST_INSERT_HEAD(&ph2tree, iph2, chain);
+
+       return 0;
+}
+
+void
+remph2(iph2)
+       struct ph2handle *iph2;
+{
+       LIST_REMOVE(iph2, chain);
+}
+
+void
+initph2tree()
+{
+       LIST_INIT(&ph2tree);
+}
+
+void
+flushph2()
+{
+       struct ph2handle *p, *next;
+
+       for (p = LIST_FIRST(&ph2tree); p; p = next) {
+               next = LIST_NEXT(p, chain);
+
+               /* send delete information */
+               if (p->status == PHASE2ST_ESTABLISHED) 
+                       isakmp_info_send_d2(p);
+
+               delete_spd(p);
+               unbindph12(p);
+               remph2(p);
+               delph2(p);
+       }
+}
+
+/*
+ * Delete all Phase 2 handlers for this src/dst/proto.  This
+ * is used during INITIAL-CONTACT processing (so no need to
+ * send a message to the peer).
+ */
+void
+deleteallph2(src, dst, proto_id)
+       struct sockaddr *src, *dst;
+       u_int proto_id;
+{
+       struct ph2handle *iph2, *next;
+       struct saproto *pr;
+
+       for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) {
+               next = LIST_NEXT(iph2, chain);
+               if (iph2->proposal == NULL && iph2->approval == NULL)
+                       continue;
+               if (iph2->approval != NULL) {
+                       for (pr = iph2->approval->head; pr != NULL;
+                            pr = pr->next) {
+                               if (proto_id == pr->proto_id)
+                                       goto zap_it;
+                       }
+               } else if (iph2->proposal != NULL) {
+                       for (pr = iph2->proposal->head; pr != NULL;
+                            pr = pr->next) {
+                               if (proto_id == pr->proto_id)
+                                       goto zap_it;
+                       }
+               }
+               continue;
+ zap_it:
+               unbindph12(iph2);
+               remph2(iph2);
+               delph2(iph2);
+       }
+}
+
+/* %%% */
+void
+bindph12(iph1, iph2)
+       struct ph1handle *iph1;
+       struct ph2handle *iph2;
+{
+       iph2->ph1 = iph1;
+       LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
+}
+
+void
+unbindph12(iph2)
+       struct ph2handle *iph2;
+{
+       if (iph2->ph1 != NULL) {
+               iph2->ph1 = NULL;
+               LIST_REMOVE(iph2, ph1bind);
+       }
+}
+
+/* %%% management contacted list */
+/*
+ * search contacted list.
+ */
+struct contacted *
+getcontacted(remote)
+       struct sockaddr *remote;
+{
+       struct contacted *p;
+
+       LIST_FOREACH(p, &ctdtree, chain) {
+               if (cmpsaddrstrict(remote, p->remote) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * create new isakmp Phase 2 status record to handle isakmp in Phase2
+ */
+int
+inscontacted(remote)
+       struct sockaddr *remote;
+{
+       struct contacted *new;
+
+       /* create new iph2 */
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return -1;
+
+       new->remote = dupsaddr(remote);
+
+       LIST_INSERT_HEAD(&ctdtree, new, chain);
+
+       return 0;
+}
+
+
+void
+clear_contacted()
+{
+       struct contacted *c, *next;
+       
+       for (c = LIST_FIRST(&ctdtree); c; c = next) {
+               next = LIST_NEXT(c, chain);
+               LIST_REMOVE(c, chain);
+               racoon_free(c->remote);
+               racoon_free(c);
+       }
+}
+
+void
+initctdtree()
+{
+       LIST_INIT(&ctdtree);
+}
+
+/*
+ * check the response has been sent to the peer.  when not, simply reply
+ * the buffered packet to the peer.
+ * OUT:
+ *      0:     the packet is received at the first time.
+ *      1:     the packet was processed before.
+ *      2:     the packet was processed before, but the address mismatches.
+ *     -1:     error happened.
+ */
+int
+check_recvdpkt(remote, local, rbuf)
+       struct sockaddr *remote, *local;
+       vchar_t *rbuf;
+{
+       vchar_t *hash;
+       struct recvdpkt *r;
+       time_t t;
+       int len, s;
+
+       /* set current time */
+       t = time(NULL);
+
+       hash = eay_md5_one(rbuf);
+       if (!hash) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               return -1;
+       }
+
+       LIST_FOREACH(r, &rcptree, chain) {
+               if (memcmp(hash->v, r->hash->v, r->hash->l) == 0)
+                       break;
+       }
+       vfree(hash);
+
+       /* this is the first time to receive the packet */
+       if (r == NULL)
+               return 0;
+
+       /*
+        * the packet was processed before, but the remote address mismatches.
+        */
+       if (cmpsaddrstrict(remote, r->remote) != 0)
+               return 2;
+
+       /*
+        * it should not check the local address because the packet
+        * may arrive at other interface.
+        */
+
+       /* check the previous time to send */
+       if (t - r->time_send < 1) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "the packet retransmitted in a short time from %s\n",
+                       saddr2str(remote));
+               /*XXX should it be error ? */
+       }
+
+       /* select the socket to be sent */
+       s = getsockmyaddr(r->local);
+       if (s == -1)
+               return -1;
+
+       /* resend the packet if needed */
+       len = sendfromto(s, r->sendbuf->v, r->sendbuf->l,
+                       r->local, r->remote, lcconf->count_persend);
+       if (len == -1) {
+               plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n");
+               return -1;
+       }
+
+       /* check the retry counter */
+       r->retry_counter--;
+       if (r->retry_counter <= 0) {
+               rem_recvdpkt(r);
+               del_recvdpkt(r);
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "deleted the retransmission packet to %s.\n",
+                       saddr2str(remote));
+       } else
+               r->time_send = t;
+
+       return 1;
+}
+
+/*
+ * adding a hash of received packet into the received list.
+ */
+int
+add_recvdpkt(remote, local, sbuf, rbuf)
+       struct sockaddr *remote, *local;
+       vchar_t *sbuf, *rbuf;
+{
+       struct recvdpkt *new = NULL;
+
+       if (lcconf->retry_counter == 0) {
+               /* no need to add it */
+               return 0;
+       }
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (!new) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               return -1;
+       }
+
+       new->hash = eay_md5_one(rbuf);
+       if (!new->hash) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               del_recvdpkt(new);
+               return -1;
+       }
+       new->remote = dupsaddr(remote);
+       if (new->remote == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               del_recvdpkt(new);
+               return -1;
+       }
+       new->local = dupsaddr(local);
+       if (new->local == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               del_recvdpkt(new);
+               return -1;
+       }
+       new->sendbuf = vdup(sbuf);
+       if (new->sendbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               del_recvdpkt(new);
+               return -1;
+       }
+
+       new->retry_counter = lcconf->retry_counter;
+       new->time_send = 0;
+       new->created = time(NULL);
+
+       LIST_INSERT_HEAD(&rcptree, new, chain);
+
+       return 0;
+}
+
+void
+del_recvdpkt(r)
+       struct recvdpkt *r;
+{
+       if (r->remote)
+               racoon_free(r->remote);
+       if (r->local)
+               racoon_free(r->local);
+       if (r->hash)
+               vfree(r->hash);
+       if (r->sendbuf)
+               vfree(r->sendbuf);
+       racoon_free(r);
+}
+
+void
+rem_recvdpkt(r)
+       struct recvdpkt *r;
+{
+       LIST_REMOVE(r, chain);
+}
+
+void
+sweep_recvdpkt(dummy)
+       void *dummy;
+{
+       struct recvdpkt *r, *next;
+       time_t t, lt;
+
+       /* set current time */
+       t = time(NULL);
+
+       /* set the lifetime of the retransmission */
+       lt = lcconf->retry_counter * lcconf->retry_interval;
+
+       for (r = LIST_FIRST(&rcptree); r; r = next) {
+               next = LIST_NEXT(r, chain);
+
+               if (t - r->created > lt) {
+                       rem_recvdpkt(r);
+                       del_recvdpkt(r);
+               }
+       }
+
+       sched_new(lt, sweep_recvdpkt, NULL);
+}
+
+void
+clear_recvdpkt()
+{
+       struct recvdpkt *r, *next;
+       
+       for (r = LIST_FIRST(&rcptree); r; r = next) {
+               next = LIST_NEXT(r, chain);
+               rem_recvdpkt(r);
+               del_recvdpkt(r);
+       }
+}
+
+void
+init_recvdpkt()
+{
+       time_t lt = lcconf->retry_counter * lcconf->retry_interval;
+
+       LIST_INIT(&rcptree);
+
+       sched_new(lt, sweep_recvdpkt, NULL);
+}
+
+#ifdef ENABLE_HYBRID
+/* 
+ * Returns 0 if the address was obtained by ISAKMP mode config, 1 otherwise
+ * This should be in isakmp_cfg.c but ph1tree being private, it must be there
+ */
+int
+exclude_cfg_addr(addr)
+       const struct sockaddr *addr;
+{
+       struct ph1handle *p;
+       struct sockaddr_in *sin;
+
+       LIST_FOREACH(p, &ph1tree, chain) {
+               if ((p->mode_cfg != NULL) &&
+                   (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) &&
+                   (addr->sa_family == AF_INET)) {
+                       sin = (struct sockaddr_in *)addr;
+                       if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr)
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+#endif
diff --git a/ipsec-tools/racoon/handler.h b/ipsec-tools/racoon/handler.h
new file mode 100644 (file)
index 0000000..2d5bfb4
--- /dev/null
@@ -0,0 +1,473 @@
+/* $Id: handler.h,v 1.11.4.3 2005/05/07 17:26:05 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _HANDLER_H
+#define _HANDLER_H
+
+#include <sys/queue.h>
+#include <openssl/rsa.h>
+
+#include <sys/time.h>
+
+#include "isakmp_var.h"
+#include "oakley.h"
+
+/* Phase 1 handler */
+/*
+ * main mode:
+ *      initiator               responder
+ *  0   (---)                   (---)
+ *  1   start                   start (1st msg received)
+ *  2   (---)                   1st valid msg received
+ *  3   1st msg sent           1st msg sent
+ *  4   1st valid msg received  2st valid msg received
+ *  5   2nd msg sent            2nd msg sent
+ *  6   2nd valid msg received  3rd valid msg received
+ *  7   3rd msg sent            3rd msg sent
+ *  8   3rd valid msg received  (---)
+ *  9   SA established          SA established
+ *
+ * aggressive mode:
+ *      initiator               responder
+ *  0   (---)                   (---)
+ *  1   start                   start (1st msg received)
+ *  2   (---)                   1st valid msg received
+ *  3   1st msg sent           1st msg sent
+ *  4   1st valid msg received  2st valid msg received
+ *  5   (---)                   (---)
+ *  6   (---)                   (---)
+ *  7   (---)                   (---)
+ *  8   (---)                   (---)
+ *  9   SA established          SA established
+ *
+ * base mode:
+ *      initiator               responder
+ *  0   (---)                   (---)
+ *  1   start                   start (1st msg received)
+ *  2   (---)                   1st valid msg received
+ *  3   1st msg sent           1st msg sent
+ *  4   1st valid msg received  2st valid msg received
+ *  5   2nd msg sent            (---)
+ *  6   (---)                   (---)
+ *  7   (---)                   (---)
+ *  8   (---)                   (---)
+ *  9   SA established          SA established
+ */
+#define PHASE1ST_SPAWN                 0
+#define PHASE1ST_START                 1
+#define PHASE1ST_MSG1RECEIVED          2
+#define PHASE1ST_MSG1SENT              3
+#define PHASE1ST_MSG2RECEIVED          4
+#define PHASE1ST_MSG2SENT              5
+#define PHASE1ST_MSG3RECEIVED          6
+#define PHASE1ST_MSG3SENT              7
+#define PHASE1ST_MSG4RECEIVED          8
+#define PHASE1ST_ESTABLISHED           9
+#define PHASE1ST_EXPIRED               10
+#define PHASE1ST_MAX                   11
+
+/* About address semantics in each case.
+ *                     initiator(addr=I)       responder(addr=R)
+ *                     src     dst             src     dst
+ *                     (local) (remote)        (local) (remote)
+ * phase 1 handler     I       R               R       I
+ * phase 2 handler     I       R               R       I
+ * getspi msg          R       I               I       R
+ * acquire msg         I       R
+ * ID payload          I       R               I       R
+ */
+#ifdef ENABLE_HYBRID
+struct isakmp_cfg_state;
+#endif
+struct ph1handle {
+       isakmp_index index;
+
+       int status;                     /* status of this SA */
+       int side;                       /* INITIATOR or RESPONDER */
+
+       struct sockaddr *remote;        /* remote address to negosiate ph1 */
+       struct sockaddr *local;         /* local address to negosiate ph1 */
+                       /* XXX copy from rmconf due to anonymous configuration.
+                        * If anonymous will be forbidden, we do delete them. */
+
+       struct remoteconf *rmconf;      /* pointer to remote configuration */
+
+       struct isakmpsa *approval;      /* pointer to SA(s) approved. */
+       vchar_t *authstr;               /* place holder of string for auth. */
+                                       /* for example pre-shared key */
+
+       u_int8_t version;               /* ISAKMP version */
+       u_int8_t etype;                 /* Exchange type actually for use */
+       u_int8_t flags;                 /* Flags */
+       u_int32_t msgid;                /* message id */
+
+       struct ph1natt_options *natt_options;   /* Selected NAT-T IKE version */
+       u_int32_t natt_flags;           /* NAT-T related flags */
+#ifdef ENABLE_FRAG
+       int frag;                       /* IKE phase 1 fragmentation */
+       struct isakmp_frag_item *frag_chain;    /* Received fragments */
+#endif
+
+       struct sched *sce;              /* schedule for expire */
+
+       struct sched *scr;              /* schedule for resend */
+       int retry_counter;              /* for resend. */
+       vchar_t *sendbuf;               /* buffer for re-sending */
+
+       vchar_t *dhpriv;                /* DH; private value */
+       vchar_t *dhpub;                 /* DH; public value */
+       vchar_t *dhpub_p;               /* DH; partner's public value */
+       vchar_t *dhgxy;                 /* DH; shared secret */
+       vchar_t *nonce;                 /* nonce value */
+       vchar_t *nonce_p;               /* partner's nonce value */
+       vchar_t *skeyid;                /* SKEYID */
+       vchar_t *skeyid_d;              /* SKEYID_d */
+       vchar_t *skeyid_a;              /* SKEYID_a, i.e. hash */
+       vchar_t *skeyid_e;              /* SKEYID_e, i.e. encryption */
+       vchar_t *key;                   /* cipher key */
+       vchar_t *hash;                  /* HASH minus general header */
+       vchar_t *sig;                   /* SIG minus general header */
+       vchar_t *sig_p;                 /* peer's SIG minus general header */
+       cert_t *cert;                   /* CERT minus general header */
+       cert_t *cert_p;                 /* peer's CERT minus general header */
+       cert_t *crl_p;                  /* peer's CRL minus general header */
+       cert_t *cr_p;                   /* peer's CR not including general */
+       RSA *rsa;                       /* my RSA key */
+       RSA *rsa_p;                     /* peer's RSA key */
+       struct genlist *rsa_candidates; /* possible candidates for peer's RSA key */
+       vchar_t *id;                    /* ID minus gen header */
+       vchar_t *id_p;                  /* partner's ID minus general header */
+                                       /* i.e. strut ipsecdoi_id_b*. */
+       struct isakmp_ivm *ivm;         /* IVs */
+
+       vchar_t *sa;                    /* whole SA payload to send/to be sent*/
+                                       /* to calculate HASH */
+                                       /* NOT INCLUDING general header. */
+
+       vchar_t *sa_ret;                /* SA payload to reply/to be replyed */
+                                       /* NOT INCLUDING general header. */
+                                       /* NOTE: Should be release after use. */
+
+#ifdef HAVE_GSSAPI
+       void *gssapi_state;             /* GSS-API specific state. */
+                                       /* Allocated when needed */
+       vchar_t *gi_i;                  /* optional initiator GSS id */
+       vchar_t *gi_r;                  /* optional responder GSS id */
+#endif
+
+       struct isakmp_pl_hash *pl_hash; /* pointer to hash payload */
+
+       time_t created;                 /* timestamp for establish */
+#ifdef ENABLE_STATS
+       struct timeval start;
+       struct timeval end;
+#endif
+
+       int             dpd_support;    /* Does remote supports DPD ? */
+       time_t          dpd_lastack;    /* Last ack received */
+       u_int16_t       dpd_seq;                /* DPD seq number to receive */
+       u_int8_t        dpd_fails;              /* number of failures */
+       struct sched    *dpd_r_u;
+
+       u_int32_t msgid2;               /* msgid counter for Phase 2 */
+       int ph2cnt;     /* the number which is negotiated by this phase 1 */
+       LIST_HEAD(_ph2ofph1_, ph2handle) ph2tree;
+
+       LIST_ENTRY(ph1handle) chain;
+#ifdef ENABLE_HYBRID
+       struct isakmp_cfg_state *mode_cfg;      /* ISAKMP mode config state */
+#endif       
+
+};
+
+/* Phase 2 handler */
+/* allocated per a SA or SA bundles of a pair of peer's IP addresses. */
+/*
+ *      initiator               responder
+ *  0   (---)                   (---)
+ *  1   start                   start (1st msg received)
+ *  2   acquire msg get         1st valid msg received
+ *  3   getspi request sent     getspi request sent
+ *  4   getspi done             getspi done
+ *  5   1st msg sent            1st msg sent
+ *  6   1st valid msg received  2nd valid msg received
+ *  7   (commit bit)            (commit bit)
+ *  8   SAs added               SAs added
+ *  9   SAs established         SAs established
+ * 10   SAs expired             SAs expired
+ */
+#define PHASE2ST_SPAWN         0
+#define PHASE2ST_START         1
+#define PHASE2ST_STATUS2       2
+#define PHASE2ST_GETSPISENT    3
+#define PHASE2ST_GETSPIDONE    4
+#define PHASE2ST_MSG1SENT      5
+#define PHASE2ST_STATUS6       6
+#define PHASE2ST_COMMIT                7
+#define PHASE2ST_ADDSA         8
+#define PHASE2ST_ESTABLISHED   9
+#define PHASE2ST_EXPIRED       10
+#define PHASE2ST_MAX           11
+
+struct ph2handle {
+       struct sockaddr *src;           /* my address of SA. */
+       struct sockaddr *dst;           /* peer's address of SA. */
+
+               /*
+                * copy ip address from ID payloads when ID type is ip address.
+                * In other case, they must be null.
+                */
+       struct sockaddr *src_id;
+       struct sockaddr *dst_id;
+
+       u_int32_t spid;                 /* policy id by kernel */
+
+       int status;                     /* ipsec sa status */
+       u_int8_t side;                  /* INITIATOR or RESPONDER */
+
+       struct sched *sce;              /* schedule for expire */
+       struct sched *scr;              /* schedule for resend */
+       int retry_counter;              /* for resend. */
+       vchar_t *sendbuf;               /* buffer for re-sending */
+       vchar_t *msg1;                  /* buffer for re-sending */
+                               /* used for responder's first message */
+
+       int retry_checkph1;             /* counter to wait phase 1 finished. */
+                                       /* NOTE: actually it's timer. */
+
+       u_int32_t seq;                  /* sequence number used by PF_KEY */
+                       /*
+                        * NOTE: In responder side, we can't identify each SAs
+                        * with same destination address for example, when
+                        * socket based SA is required.  So we set a identifier
+                        * number to "seq", and sent kernel by pfkey.
+                        */
+       u_int8_t satype;                /* satype in PF_KEY */
+                       /*
+                        * saved satype in the original PF_KEY request from
+                        * the kernel in order to reply a error.
+                        */
+
+       u_int8_t flags;                 /* Flags for phase 2 */
+       u_int32_t msgid;                /* msgid for phase 2 */
+
+       struct sainfo *sainfo;          /* place holder of sainfo */
+       struct saprop *proposal;        /* SA(s) proposal. */
+       struct saprop *approval;        /* SA(s) approved. */
+       caddr_t spidx_gen;              /* policy from peer's proposal */
+
+       struct dhgroup *pfsgrp;         /* DH; prime number */
+       vchar_t *dhpriv;                /* DH; private value */
+       vchar_t *dhpub;                 /* DH; public value */
+       vchar_t *dhpub_p;               /* DH; partner's public value */
+       vchar_t *dhgxy;                 /* DH; shared secret */
+       vchar_t *id;                    /* ID minus gen header */
+       vchar_t *id_p;                  /* peer's ID minus general header */
+       vchar_t *nonce;                 /* nonce value in phase 2 */
+       vchar_t *nonce_p;               /* partner's nonce value in phase 2 */
+
+       vchar_t *sa;                    /* whole SA payload to send/to be sent*/
+                                       /* to calculate HASH */
+                                       /* NOT INCLUDING general header. */
+
+       vchar_t *sa_ret;                /* SA payload to reply/to be replyed */
+                                       /* NOT INCLUDING general header. */
+                                       /* NOTE: Should be release after use. */
+
+       struct isakmp_ivm *ivm;         /* IVs */
+
+       int generated_spidx;    /* mark handlers whith generated policy */
+
+#ifdef ENABLE_STATS
+       struct timeval start;
+       struct timeval end;
+#endif
+       struct ph1handle *ph1;  /* back pointer to isakmp status */
+
+       LIST_ENTRY(ph2handle) chain;
+       LIST_ENTRY(ph2handle) ph1bind;  /* chain to ph1handle */
+};
+
+/*
+ * for handling initial contact.
+ */
+struct contacted {
+       struct sockaddr *remote;        /* remote address to negotiate ph1 */
+       LIST_ENTRY(contacted) chain;
+};
+
+/*
+ * for checking if a packet is retransmited.
+ */
+struct recvdpkt {
+       struct sockaddr *remote;        /* the remote address */
+       struct sockaddr *local;         /* the local address */
+       vchar_t *hash;                  /* hash of the received packet */
+       vchar_t *sendbuf;               /* buffer for the response */
+       int retry_counter;              /* how many times to send */
+       time_t time_send;               /* timestamp to send a packet */
+       time_t created;                 /* timestamp to create a queue */
+
+       struct sched *scr;              /* schedule for resend, may not used */
+
+       LIST_ENTRY(recvdpkt) chain;
+};
+
+/* for parsing ISAKMP header. */
+struct isakmp_parse_t {
+       u_char type;            /* payload type of mine */
+       int len;                /* ntohs(ptr->len) */
+       struct isakmp_gen *ptr;
+};
+
+/*
+ * for IV management.
+ *
+ * - normal case
+ * initiator                                     responder
+ * -------------------------                     --------------------------
+ * initialize iv(A), ive(A).                     initialize iv(A), ive(A).
+ * encode by ive(A).
+ * save to iv(B).            ---[packet(B)]-->   save to ive(B).
+ *                                               decode by iv(A).
+ *                                               packet consistency.
+ *                                               sync iv(B) with ive(B).
+ *                                               check auth, integrity.
+ *                                               encode by ive(B).
+ * save to ive(C).          <--[packet(C)]---    save to iv(C).
+ * decoded by iv(B).
+ *      :
+ *
+ * - In the case that a error is found while cipher processing,
+ * initiator                                     responder
+ * -------------------------                     --------------------------
+ * initialize iv(A), ive(A).                     initialize iv(A), ive(A).
+ * encode by ive(A).
+ * save to iv(B).            ---[packet(B)]-->   save to ive(B).
+ *                                               decode by iv(A).
+ *                                               packet consistency.
+ *                                               sync iv(B) with ive(B).
+ *                                               check auth, integrity.
+ *                                               error found.
+ *                                               create notify.
+ *                                               get ive2(X) from iv(B).
+ *                                               encode by ive2(X).
+ * get iv2(X) from iv(B).   <--[packet(Y)]---    save to iv2(Y).
+ * save to ive2(Y).
+ * decoded by iv2(X).
+ *      :
+ *
+ * The reason why the responder synchronizes iv with ive after checking the
+ * packet consistency is that it is required to leave the IV for decoding
+ * packet.  Because there is a potential of error while checking the packet
+ * consistency.  Also the reason why that is before authentication and
+ * integirty check is that the IV for informational exchange has to be made
+ * by the IV which is after packet decoded and checking the packet consistency.
+ * Otherwise IV mismatched happens between the intitiator and the responder.
+ */
+struct isakmp_ivm {
+       vchar_t *iv;    /* for decoding packet */
+                       /* if phase 1, it's for computing phase2 iv */
+       vchar_t *ive;   /* for encoding packet */
+};
+
+/* for dumping */
+struct ph1dump {
+       isakmp_index index;
+       int status;
+       int side;
+       struct sockaddr_storage remote;
+       struct sockaddr_storage local;
+       u_int8_t version;
+       u_int8_t etype; 
+       time_t created;
+       int ph2cnt;
+};
+
+struct sockaddr;
+struct ph1handle;
+struct ph2handle;
+struct policyindex;
+
+extern struct ph1handle *getph1byindex __P((isakmp_index *));
+extern struct ph1handle *getph1byindex0 __P((isakmp_index *));
+extern struct ph1handle *getph1byaddr __P((struct sockaddr *,
+       struct sockaddr *));
+extern struct ph1handle *getph1byaddrwop __P((struct sockaddr *,
+       struct sockaddr *));
+extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *));
+extern vchar_t *dumpph1 __P((void));
+extern struct ph1handle *newph1 __P((void));
+extern void delph1 __P((struct ph1handle *));
+extern int insph1 __P((struct ph1handle *));
+extern void remph1 __P((struct ph1handle *));
+extern void flushph1 __P((void));
+extern void initph1tree __P((void));
+
+extern struct ph2handle *getph2byspidx __P((struct policyindex *));
+extern struct ph2handle *getph2byspid __P((u_int32_t));
+extern struct ph2handle *getph2byseq __P((u_int32_t));
+extern struct ph2handle *getph2bysaddr __P((struct sockaddr *,
+       struct sockaddr *));
+extern struct ph2handle *getph2bymsgid __P((struct ph1handle *, u_int32_t));
+extern struct ph2handle *getph2byid __P((struct sockaddr *,
+       struct sockaddr *, u_int32_t));
+extern struct ph2handle *getph2bysaidx __P((struct sockaddr *,
+       struct sockaddr *, u_int, u_int32_t));
+extern struct ph2handle *newph2 __P((void));
+extern void initph2 __P((struct ph2handle *));
+extern void delph2 __P((struct ph2handle *));
+extern int insph2 __P((struct ph2handle *));
+extern void remph2 __P((struct ph2handle *));
+extern void flushph2 __P((void));
+extern void deleteallph2 __P((struct sockaddr *, struct sockaddr *, u_int));
+extern void initph2tree __P((void));
+
+extern void bindph12 __P((struct ph1handle *, struct ph2handle *));
+extern void unbindph12 __P((struct ph2handle *));
+
+extern struct contacted *getcontacted __P((struct sockaddr *));
+extern int inscontacted __P((struct sockaddr *));
+extern void clear_contacted __P((void));
+extern void initctdtree __P((void));
+
+extern int check_recvdpkt __P((struct sockaddr *,
+       struct sockaddr *, vchar_t *));
+extern int add_recvdpkt __P((struct sockaddr *, struct sockaddr *,
+       vchar_t *, vchar_t *));
+extern void clear_recvdpkt __P((void));
+extern void init_recvdpkt __P((void));
+
+#ifdef ENABLE_HYBRID
+extern int exclude_cfg_addr __P((const struct sockaddr *));
+#endif
+
+#endif /* _HANDLER_H */
diff --git a/ipsec-tools/racoon/ipsec_doi.c b/ipsec-tools/racoon/ipsec_doi.c
new file mode 100644 (file)
index 0000000..1854964
--- /dev/null
@@ -0,0 +1,4348 @@
+/* $Id: ipsec_doi.c,v 1.26.2.16 2006/02/02 14:37:17 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "cfparse_proto.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "remoteconf.h"
+#include "localconf.h"
+#include "sockmisc.h"
+#include "handler.h"
+#include "policy.h"
+#include "algorithm.h"
+#include "sainfo.h"
+#include "proposal.h"
+#include "crypto_openssl.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#ifdef ENABLE_HYBRID
+static int switch_authmethod(int);
+#endif
+
+#ifdef HAVE_GSSAPI
+#include <iconv.h>
+#include "gssapi.h"
+#ifdef HAVE_ICONV_2ND_CONST
+#define __iconv_const const
+#else
+#define __iconv_const
+#endif
+#endif
+
+int verbose_proposal_check = 1;
+
+static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **));
+static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *,
+       struct isakmpsa *, struct isakmpsa *, int));
+static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *));
+static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *));
+static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *));
+static struct prop_pair *get_ph2approval __P((struct ph2handle *,
+       struct prop_pair **));
+static struct prop_pair *get_ph2approvalx __P((struct ph2handle *,
+       struct prop_pair *));
+static void free_proppair0 __P((struct prop_pair *));
+
+static int get_transform
+       __P((struct isakmp_pl_p *, struct prop_pair **, int *));
+static u_int32_t ipsecdoi_set_ld __P((vchar_t *));
+
+static int check_doi __P((u_int32_t));
+static int check_situation __P((u_int32_t));
+
+static int check_prot_main __P((int));
+static int check_prot_quick __P((int));
+static int (*check_protocol[]) __P((int)) = {
+       check_prot_main,        /* IPSECDOI_TYPE_PH1 */
+       check_prot_quick,       /* IPSECDOI_TYPE_PH2 */
+};
+
+static int check_spi_size __P((int, int));
+
+static int check_trns_isakmp __P((int));
+static int check_trns_ah __P((int));
+static int check_trns_esp __P((int));
+static int check_trns_ipcomp __P((int));
+static int (*check_transform[]) __P((int)) = {
+       0,
+       check_trns_isakmp,      /* IPSECDOI_PROTO_ISAKMP */
+       check_trns_ah,          /* IPSECDOI_PROTO_IPSEC_AH */
+       check_trns_esp,         /* IPSECDOI_PROTO_IPSEC_ESP */
+       check_trns_ipcomp,      /* IPSECDOI_PROTO_IPCOMP */
+};
+
+static int check_attr_isakmp __P((struct isakmp_pl_t *));
+static int check_attr_ah __P((struct isakmp_pl_t *));
+static int check_attr_esp __P((struct isakmp_pl_t *));
+static int check_attr_ipsec __P((int, struct isakmp_pl_t *));
+static int check_attr_ipcomp __P((struct isakmp_pl_t *));
+static int (*check_attributes[]) __P((struct isakmp_pl_t *)) = {
+       0,
+       check_attr_isakmp,      /* IPSECDOI_PROTO_ISAKMP */
+       check_attr_ah,          /* IPSECDOI_PROTO_IPSEC_AH */
+       check_attr_esp,         /* IPSECDOI_PROTO_IPSEC_ESP */
+       check_attr_ipcomp,      /* IPSECDOI_PROTO_IPCOMP */
+};
+
+static int setph1prop __P((struct isakmpsa *, caddr_t));
+static int setph1trns __P((struct isakmpsa *, caddr_t));
+static int setph1attr __P((struct isakmpsa *, caddr_t));
+static vchar_t *setph2proposal0 __P((const struct ph2handle *,
+       const struct saprop *, const struct saproto *));
+
+static vchar_t *getidval __P((int, vchar_t *));
+
+#ifdef HAVE_GSSAPI
+static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *,
+       struct isakmpsa *));
+#endif
+
+/*%%%*/
+/*
+ * check phase 1 SA payload.
+ * make new SA payload to be replyed not including general header.
+ * the pointer to one of isakmpsa in proposal is set into iph1->approval.
+ * OUT:
+ *     positive: the pointer to new buffer of SA payload.
+ *               network byte order.
+ *     NULL    : error occurd.
+ */
+int
+ipsecdoi_checkph1proposal(sa, iph1)
+       vchar_t *sa;
+       struct ph1handle *iph1;
+{
+       vchar_t *newsa;         /* new SA payload approved. */
+       struct prop_pair **pair;
+
+       /* get proposal pair */
+       pair = get_proppair(sa, IPSECDOI_TYPE_PH1);
+       if (pair == NULL)
+               return -1;
+
+       /* check and get one SA for use */
+       newsa = get_ph1approval(iph1, pair);
+       
+       free_proppair(pair);
+
+       if (newsa == NULL)
+               return -1;
+
+       iph1->sa_ret = newsa;
+
+       return 0;
+}
+
+/*
+ * acceptable check for remote configuration.
+ * return a new SA payload to be reply to peer.
+ */
+static vchar_t *
+get_ph1approval(iph1, pair)
+       struct ph1handle *iph1;
+       struct prop_pair **pair;
+{
+       vchar_t *newsa;
+       struct isakmpsa *sa, tsa;
+       struct prop_pair *s, *p;
+       int prophlen;
+       int i;
+
+       if (iph1->approval) {
+               delisakmpsa(iph1->approval);
+               iph1->approval = NULL;
+       }
+
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               if (pair[i] == NULL)
+                       continue;
+               for (s = pair[i]; s; s = s->next) {
+                       prophlen = 
+                           sizeof(struct isakmp_pl_p) + s->prop->spi_size;
+
+                       /* compare proposal and select one */
+                       for (p = s; p; p = p->tnext) {
+                               if ((sa = get_ph1approvalx(p, 
+                                   iph1->rmconf->proposal, &tsa, 
+                                   iph1->rmconf->pcheck_level)) != NULL)
+                                       goto found;
+                       }
+               }
+       }
+
+       /*
+        * if there is no suitable proposal, racoon complains about all of
+        * mismatched items in those proposal.
+        */
+       if (verbose_proposal_check) {
+               for (i = 0; i < MAXPROPPAIRLEN; i++) {
+                       if (pair[i] == NULL)
+                               continue;
+                       for (s = pair[i]; s; s = s->next) {
+                               prophlen = sizeof(struct isakmp_pl_p)
+                                               + s->prop->spi_size;
+                               for (p = s; p; p = p->tnext) {
+                                       print_ph1mismatched(p,
+                                               iph1->rmconf->proposal);
+                               }
+                       }
+               }
+       }
+       plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n");
+
+       return NULL;
+
+found:
+       plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n");
+
+       /* check DH group settings */
+       if (sa->dhgrp) {
+               if (sa->dhgrp->prime && sa->dhgrp->gen1) {
+                       /* it's ok */
+                       goto saok;
+               }
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "invalid DH parameter found, use default.\n");
+               oakley_dhgrp_free(sa->dhgrp);
+       }
+
+       if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) {
+               sa->dhgrp = NULL;
+               return NULL;
+       }
+
+saok:
+#ifdef HAVE_GSSAPI
+       if (sa->gssid != NULL)
+               plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n",
+                   sa->gssid->l, sa->gssid->v);
+       if (iph1-> side == INITIATOR) {
+               if (iph1->rmconf->proposal->gssid != NULL)
+                       iph1->gi_i = vdup(iph1->rmconf->proposal->gssid);
+               if (tsa.gssid != NULL)
+                       iph1->gi_r = vdup(tsa.gssid);
+               iph1->approval = fixup_initiator_sa(sa, &tsa);
+       } else {
+               if (tsa.gssid != NULL) {
+                       iph1->gi_r = vdup(tsa.gssid);
+                       iph1->gi_i = gssapi_get_id(iph1);
+                       if (sa->gssid == NULL && iph1->gi_i != NULL)
+                               sa->gssid = vdup(iph1->gi_i);
+               }
+               iph1->approval = sa;
+       }
+       if (iph1->gi_i != NULL)
+               plog(LLV_DEBUG, LOCATION, NULL, "GIi is %.*s\n",
+                   iph1->gi_i->l, iph1->gi_i->v);
+       if (iph1->gi_r != NULL)
+               plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n",
+                   iph1->gi_r->l, iph1->gi_r->v);
+#else
+       iph1->approval = sa;
+#endif
+
+       newsa = get_sabyproppair(p, iph1);
+       if (newsa == NULL) {
+               delisakmpsa(iph1->approval);
+               iph1->approval = NULL;
+       }
+
+       return newsa;
+}
+
+/*
+ * compare peer's single proposal and all of my proposal.
+ * and select one if suiatable.
+ * p       : one of peer's proposal.
+ * proposal: my proposals.
+ */
+static struct isakmpsa *
+get_ph1approvalx(p, proposal, sap, check_level)
+       struct prop_pair *p;
+       struct isakmpsa *proposal, *sap;
+       int check_level;
+{
+       struct isakmp_pl_p *prop = p->prop;
+       struct isakmp_pl_t *trns = p->trns;
+       struct isakmpsa sa, *s, *tsap;
+       int authmethod;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+                       "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n",
+               prop->p_no, s_ipsecdoi_proto(prop->proto_id),
+               prop->spi_size, prop->num_t);
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "trns#=%d, trns-id=%s\n",
+               trns->t_no,
+               s_ipsecdoi_trns(prop->proto_id, trns->t_id));
+
+       tsap = sap != NULL ? sap : &sa;
+
+       memset(tsap, 0, sizeof(*tsap));
+       if (t2isakmpsa(trns, tsap) < 0)
+               return NULL;
+       for (s = proposal; s != NULL; s = s->next) {
+#ifdef ENABLE_HYBRID
+               authmethod = switch_authmethod(s->authmethod);
+#else
+               authmethod = s->authmethod;
+#endif
+               plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n");
+               plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n",
+                       (long)s->lifetime, (long)tsap->lifetime);
+               plog(LLV_DEBUG, LOCATION, NULL, "(lifebyte = %zu:%zu)\n",
+                       s->lifebyte, tsap->lifebyte);
+               plog(LLV_DEBUG, LOCATION, NULL, "enctype = %s:%s\n",
+                       s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+                                       s->enctype),
+                       s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+                                       tsap->enctype));
+               plog(LLV_DEBUG, LOCATION, NULL, "(encklen = %d:%d)\n",
+                       s->encklen, tsap->encklen);
+               plog(LLV_DEBUG, LOCATION, NULL, "hashtype = %s:%s\n",
+                       s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+                                       s->hashtype),
+                       s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+                                       tsap->hashtype));
+               plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n",
+                       s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+                                       authmethod),
+                       s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+                                       tsap->authmethod));
+               plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n",
+                       s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+                                       s->dh_group),
+                       s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+                                       tsap->dh_group));
+#if 0
+               /* XXX to be considered ? */
+               if (tsap->lifebyte > s->lifebyte) ;
+#endif
+               /*
+                * if responder side and peer's key length in proposal
+                * is bigger than mine, it might be accepted.
+                */
+               if(tsap->enctype == s->enctype &&
+                   tsap->authmethod == authmethod &&
+                   tsap->hashtype == s->hashtype &&
+                   tsap->dh_group == s->dh_group &&
+                   tsap->encklen == s->encklen) {
+                       switch(check_level) {
+                       case PROP_CHECK_OBEY:
+                               goto found;
+                               break;
+
+                       case PROP_CHECK_STRICT:
+                               if ((tsap->lifetime > s->lifetime) ||
+                                   (tsap->lifebyte > s->lifebyte))
+                                       continue;
+                               goto found;
+                               break;
+
+                       case PROP_CHECK_CLAIM:
+                               if (tsap->lifetime < s->lifetime)
+                                       s->lifetime = tsap->lifetime;
+                               if (tsap->lifebyte < s->lifebyte)
+                                       s->lifebyte = tsap->lifebyte;
+                               goto found;
+                               break;
+
+                       case PROP_CHECK_EXACT:
+                               if ((tsap->lifetime != s->lifetime) ||
+                                   (tsap->lifebyte != s->lifebyte))
+                                       continue;
+                               goto found;
+                               break;
+
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Unexpected proposal_check value\n");
+                               continue;
+                               break;
+                       }
+               }
+       }
+
+found:
+       if (tsap->dhgrp != NULL)
+               oakley_dhgrp_free(tsap->dhgrp);
+
+       if ((s = dupisakmpsa(s)) != NULL) {
+               switch(check_level) {
+               case PROP_CHECK_OBEY:
+                       s->lifetime = tsap->lifetime;
+                       s->lifebyte = tsap->lifebyte;
+                       break;
+
+               case PROP_CHECK_STRICT:
+                       s->lifetime = tsap->lifetime;
+                       s->lifebyte = tsap->lifebyte;
+                       break;
+
+               case PROP_CHECK_CLAIM:
+                       if (tsap->lifetime < s->lifetime)
+                               s->lifetime = tsap->lifetime;
+                       if (tsap->lifebyte < s->lifebyte)
+                               s->lifebyte = tsap->lifebyte;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return s;
+}
+
+/*
+ * print all of items in peer's proposal which are mismatched to my proposal.
+ * p       : one of peer's proposal.
+ * proposal: my proposals.
+ */
+static void
+print_ph1mismatched(p, proposal)
+       struct prop_pair *p;
+       struct isakmpsa *proposal;
+{
+       struct isakmpsa sa, *s;
+
+       memset(&sa, 0, sizeof(sa));
+       if (t2isakmpsa(p->trns, &sa) < 0)
+               return;
+       for (s = proposal; s ; s = s->next) {
+               if (sa.enctype != s->enctype) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "rejected enctype: "
+                               "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+                               "%s:%s\n",
+                               s->prop_no, s->trns_no,
+                               p->prop->p_no, p->trns->t_no,
+                               s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+                                       s->enctype),
+                               s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+                                       sa.enctype));
+               }
+               if (sa.authmethod != s->authmethod) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "rejected authmethod: "
+                               "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+                               "%s:%s\n",
+                               s->prop_no, s->trns_no,
+                               p->prop->p_no, p->trns->t_no,
+                               s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+                                       s->authmethod),
+                               s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+                                       sa.authmethod));
+               }
+               if (sa.hashtype != s->hashtype) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "rejected hashtype: "
+                               "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+                               "%s:%s\n",
+                               s->prop_no, s->trns_no,
+                               p->prop->p_no, p->trns->t_no,
+                               s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+                                       s->hashtype),
+                               s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+                                       sa.hashtype));
+               }
+               if (sa.dh_group != s->dh_group) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "rejected dh_group: "
+                               "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+                               "%s:%s\n",
+                               s->prop_no, s->trns_no,
+                               p->prop->p_no, p->trns->t_no,
+                               s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+                                       s->dh_group),
+                               s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+                                       sa.dh_group));
+               }
+       }
+
+       if (sa.dhgrp != NULL)
+               oakley_dhgrp_free(sa.dhgrp);
+}
+
+/*
+ * get ISAKMP data attributes
+ */
+static int
+t2isakmpsa(trns, sa)
+       struct isakmp_pl_t *trns;
+       struct isakmpsa *sa;
+{
+       struct isakmp_data *d, *prev;
+       int flag, type;
+       int error = -1;
+       int life_t;
+       int keylen = 0;
+       vchar_t *val = NULL;
+       int len, tlen;
+       u_char *p;
+
+       tlen = ntohs(trns->h.len) - sizeof(*trns);
+       prev = (struct isakmp_data *)NULL;
+       d = (struct isakmp_data *)(trns + 1);
+
+       /* default */
+       life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
+       sa->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
+       sa->lifebyte = 0;
+       sa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup));
+       if (!sa->dhgrp)
+               goto err;
+
+       while (tlen > 0) {
+
+               type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+               flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "type=%s, flag=0x%04x, lorv=%s\n",
+                       s_oakley_attr(type), flag,
+                       s_oakley_attr_v(type, ntohs(d->lorv)));
+
+               /* get variable-sized item */
+               switch (type) {
+               case OAKLEY_ATTR_GRP_PI:
+               case OAKLEY_ATTR_GRP_GEN_ONE:
+               case OAKLEY_ATTR_GRP_GEN_TWO:
+               case OAKLEY_ATTR_GRP_CURVE_A:
+               case OAKLEY_ATTR_GRP_CURVE_B:
+               case OAKLEY_ATTR_SA_LD:
+               case OAKLEY_ATTR_GRP_ORDER:
+                       if (flag) {     /*TV*/
+                               len = 2;
+                               p = (u_char *)&d->lorv;
+                       } else {        /*TLV*/
+                               len = ntohs(d->lorv);
+                               p = (u_char *)(d + 1);
+                       }
+                       val = vmalloc(len);
+                       if (!val)
+                               return -1;
+                       memcpy(val->v, p, len);
+                       break;
+
+               default:
+                       break;
+               }
+
+               switch (type) {
+               case OAKLEY_ATTR_ENC_ALG:
+                       sa->enctype = (u_int16_t)ntohs(d->lorv);
+                       break;
+
+               case OAKLEY_ATTR_HASH_ALG:
+                       sa->hashtype = (u_int16_t)ntohs(d->lorv);
+                       break;
+
+               case OAKLEY_ATTR_AUTH_METHOD:
+                       sa->authmethod = ntohs(d->lorv);
+                       break;
+
+               case OAKLEY_ATTR_GRP_DESC:
+                       sa->dh_group = (u_int16_t)ntohs(d->lorv);
+                       break;
+
+               case OAKLEY_ATTR_GRP_TYPE:
+               {
+                       int type = (int)ntohs(d->lorv);
+                       if (type == OAKLEY_ATTR_GRP_TYPE_MODP)
+                               sa->dhgrp->type = type;
+                       else
+                               return -1;
+                       break;
+               }
+               case OAKLEY_ATTR_GRP_PI:
+                       sa->dhgrp->prime = val;
+                       break;
+
+               case OAKLEY_ATTR_GRP_GEN_ONE:
+                       vfree(val);
+                       if (!flag)
+                               sa->dhgrp->gen1 = ntohs(d->lorv);
+                       else {
+                               int len = ntohs(d->lorv);
+                               sa->dhgrp->gen1 = 0;
+                               if (len > 4)
+                                       return -1;
+                               memcpy(&sa->dhgrp->gen1, d + 1, len);
+                               sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1);
+                       }
+                       break;
+
+               case OAKLEY_ATTR_GRP_GEN_TWO:
+                       vfree(val);
+                       if (!flag)
+                               sa->dhgrp->gen2 = ntohs(d->lorv);
+                       else {
+                               int len = ntohs(d->lorv);
+                               sa->dhgrp->gen2 = 0;
+                               if (len > 4)
+                                       return -1;
+                               memcpy(&sa->dhgrp->gen2, d + 1, len);
+                               sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2);
+                       }
+                       break;
+
+               case OAKLEY_ATTR_GRP_CURVE_A:
+                       sa->dhgrp->curve_a = val;
+                       break;
+
+               case OAKLEY_ATTR_GRP_CURVE_B:
+                       sa->dhgrp->curve_b = val;
+                       break;
+
+               case OAKLEY_ATTR_SA_LD_TYPE:
+               {
+                       int type = (int)ntohs(d->lorv);
+                       switch (type) {
+                       case OAKLEY_ATTR_SA_LD_TYPE_SEC:
+                       case OAKLEY_ATTR_SA_LD_TYPE_KB:
+                               life_t = type;
+                               break;
+                       default:
+                               life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
+                               break;
+                       }
+                       break;
+               }
+               case OAKLEY_ATTR_SA_LD:
+                       if (!prev
+                        || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
+                                       OAKLEY_ATTR_SA_LD_TYPE) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "life duration must follow ltype\n");
+                               break;
+                       }
+
+                       switch (life_t) {
+                       case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+                               sa->lifetime = ipsecdoi_set_ld(val);
+                               vfree(val);
+                               if (sa->lifetime == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid life duration.\n");
+                                       goto err;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+                               sa->lifebyte = ipsecdoi_set_ld(val);
+                               vfree(val);
+                               if (sa->lifebyte == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid life duration.\n");
+                                       goto err;
+                               }
+                               break;
+                       default:
+                               vfree(val);
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid life type: %d\n", life_t);
+                               goto err;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_KEY_LEN:
+               {
+                       int len = ntohs(d->lorv);
+                       if (len % 8 != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "keylen %d: not multiple of 8\n",
+                                       len);
+                               goto err;
+                       }
+                       sa->encklen = (u_int16_t)len;
+                       keylen++;
+                       break;
+               }
+               case OAKLEY_ATTR_PRF:
+               case OAKLEY_ATTR_FIELD_SIZE:
+                       /* unsupported */
+                       break;
+
+               case OAKLEY_ATTR_GRP_ORDER:
+                       sa->dhgrp->order = val;
+                       break;
+#ifdef HAVE_GSSAPI
+               case OAKLEY_ATTR_GSS_ID:
+               {
+                       iconv_t cd;
+                       size_t srcleft, dstleft, rv;
+                       __iconv_const char *src;
+                       char *dst;
+                       int len = ntohs(d->lorv);
+
+                       /*
+                        * Older verions of racoon just placed the
+                        * ISO-Latin-1 string on the wire directly.
+                        * Check to see if we are configured to be
+                        * compatible with this behavior.
+                        */
+                       if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) {
+                               sa->gssid = vmalloc(len);
+                               memcpy(sa->gssid->v, d + 1, len);
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                 "received old-style gss id '%.*s' (len %d)\n",
+                                 sa->gssid->l, sa->gssid->v, sa->gssid->l);
+                               break;
+                       }
+
+                       /*
+                        * For Windows 2000 compatibility, we expect
+                        * the GSS ID attribute on the wire to be
+                        * encoded in UTF-16LE.  Internally, we work
+                        * in ISO-Latin-1.  Therefore, we should need
+                        * 1/2 the specified length, which should always
+                        * be a multiple of 2 octets.
+                        */
+                       cd = iconv_open("latin1", "utf-16le");
+                       if (cd == (iconv_t) -1) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "unable to initialize utf-16le -> latin1 "
+                                   "conversion descriptor: %s\n",
+                                   strerror(errno));
+                               break;
+                       }
+
+                       sa->gssid = vmalloc(len / 2);
+
+                       src = (__iconv_const char *)(d + 1);
+                       srcleft = len;
+
+                       dst = sa->gssid->v;
+                       dstleft = len / 2;
+
+                       rv = iconv(cd, (__iconv_const char **)&src, &srcleft, 
+                                  &dst, &dstleft);
+                       if (rv != 0) {
+                               if (rv == -1) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                           "unable to convert GSS ID from "
+                                           "utf-16le -> latin1: %s\n",
+                                           strerror(errno));
+                               } else {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                           "%zd character%s in GSS ID cannot "
+                                           "be represented in latin1\n",
+                                           rv, rv == 1 ? "" : "s");
+                               }
+                               (void) iconv_close(cd);
+                               vfree(sa->gssid);
+                               sa->gssid = NULL;
+                               break;
+                       }
+                       (void) iconv_close(cd);
+
+                       /* XXX dstleft should always be 0; assert it? */
+                       sa->gssid->l = (len / 2) - dstleft;
+
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                           "received gss id '%.*s' (len %d)\n",
+                           sa->gssid->l, sa->gssid->v, sa->gssid->l);
+                       break;
+               }
+#endif /* HAVE_GSSAPI */
+
+               default:
+                       break;
+               }
+
+               prev = d;
+               if (flag) {
+                       tlen -= sizeof(*d);
+                       d = (struct isakmp_data *)((char *)d + sizeof(*d));
+               } else {
+                       tlen -= (sizeof(*d) + ntohs(d->lorv));
+                       d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv));
+               }
+       }
+
+       /* key length must not be specified on some algorithms */
+       if (keylen) {
+               if (sa->enctype == OAKLEY_ATTR_ENC_ALG_DES
+#ifdef HAVE_OPENSSL_IDEA_H
+                || sa->enctype == OAKLEY_ATTR_ENC_ALG_IDEA
+#endif
+                || sa->enctype == OAKLEY_ATTR_ENC_ALG_3DES) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "keylen must not be specified "
+                               "for encryption algorithm %d\n",
+                               sa->enctype);
+                       return -1;
+               }
+       }
+
+       return 0;
+err:
+       return error;
+}
+
+/*%%%*/
+/*
+ * check phase 2 SA payload and select single proposal.
+ * make new SA payload to be replyed not including general header.
+ * This function is called by responder only.
+ * OUT:
+ *     0: succeed.
+ *     -1: error occured.
+ */
+int
+ipsecdoi_selectph2proposal(iph2)
+       struct ph2handle *iph2;
+{
+       struct prop_pair **pair;
+       struct prop_pair *ret;
+
+       /* get proposal pair */
+       pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+       if (pair == NULL)
+               return -1;
+
+       /* check and select a proposal. */
+       ret = get_ph2approval(iph2, pair);
+       free_proppair(pair);
+       if (ret == NULL)
+               return -1;
+
+       /* make a SA to be replayed. */
+       /* SPI must be updated later. */
+       iph2->sa_ret = get_sabyproppair(ret, iph2->ph1);
+       free_proppair0(ret);
+       if (iph2->sa_ret == NULL)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * check phase 2 SA payload returned from responder.
+ * This function is called by initiator only.
+ * OUT:
+ *     0: valid.
+ *     -1: invalid.
+ */
+int
+ipsecdoi_checkph2proposal(iph2)
+       struct ph2handle *iph2;
+{
+       struct prop_pair **rpair = NULL, **spair = NULL;
+       struct prop_pair *p;
+       int i, n, num;
+       int error = -1;
+       vchar_t *sa_ret = NULL;
+
+       /* get proposal pair of SA sent. */
+       spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+       if (spair == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get prop pair.\n");
+               goto end;
+       }
+
+       /* XXX should check the number of transform */
+
+       /* get proposal pair of SA replayed */
+       rpair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
+       if (rpair == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get prop pair.\n");
+               goto end;
+       }
+
+       /* check proposal is only one ? */
+       n = 0;
+       num = 0;
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               if (rpair[i]) {
+                       n = i;
+                       num++;
+               }
+       }
+       if (num == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no proposal received.\n");
+               goto end;
+       }
+       if (num != 1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "some proposals received.\n");
+               goto end;
+       }
+
+       if (spair[n] == NULL) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "invalid proposal number:%d received.\n", i);
+       }
+       
+
+       if (rpair[n]->tnext != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "multi transforms replyed.\n");
+               goto end;
+       }
+
+       if (cmp_aproppair_i(rpair[n], spair[n])) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "proposal mismathed.\n");
+               goto end;
+       }
+
+       /*
+        * check and select a proposal.
+        * ensure that there is no modification of the proposal by
+        * cmp_aproppair_i()
+        */
+       p = get_ph2approval(iph2, rpair);
+       if (p == NULL)
+               goto end;
+
+       /* make a SA to be replayed. */
+       sa_ret = iph2->sa_ret;
+       iph2->sa_ret = get_sabyproppair(p, iph2->ph1);
+       free_proppair0(p);
+       if (iph2->sa_ret == NULL)
+               goto end;
+
+       error = 0;
+
+end:
+       if (rpair)
+               free_proppair(rpair);
+       if (spair)
+               free_proppair(spair);
+       if (sa_ret)
+               vfree(sa_ret);
+
+       return error;
+}
+
+/*
+ * compare two prop_pair which is assumed to have same proposal number.
+ * the case of bundle or single SA, NOT multi transforms.
+ * a: a proposal that is multi protocols and single transform, usually replyed.
+ * b: a proposal that is multi protocols and multi transform, usually sent.
+ * NOTE: this function is for initiator.
+ * OUT
+ *     0: equal
+ *     1: not equal
+ * XXX cannot understand the comment!
+ */
+static int
+cmp_aproppair_i(a, b)
+       struct prop_pair *a, *b;
+{
+       struct prop_pair *p, *q, *r;
+       int len;
+
+       for (p = a, q = b; p && q; p = p->next, q = q->next) {
+               for (r = q; r; r = r->tnext) {
+                       /* compare trns */
+                       if (p->trns->t_no == r->trns->t_no)
+                               break;
+               }
+               if (!r) {
+                       /* no suitable transform found */
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no suitable transform found.\n");
+                       return -1;
+               }
+
+               /* compare prop */
+               if (p->prop->p_no != r->prop->p_no) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "proposal #%d mismatched, "
+                               "expected #%d.\n",
+                               r->prop->p_no, p->prop->p_no);
+                       /*FALLTHROUGH*/
+               }
+
+               if (p->prop->proto_id != r->prop->proto_id) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "proto_id mismathed: my:%d peer:%d\n",
+                               r->prop->proto_id, p->prop->proto_id);
+                       return -1;
+               }
+
+               if (p->prop->proto_id != r->prop->proto_id) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid spi size: %d.\n",
+                               p->prop->proto_id);
+                       return -1;
+               }
+
+               /* check #of transforms */
+               if (p->prop->num_t != 1) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "#of transform is %d, "
+                               "but expected 1.\n", p->prop->num_t);
+                       /*FALLTHROUGH*/
+               }
+
+               if (p->trns->t_id != r->trns->t_id) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "transform number has been modified.\n");
+                       /*FALLTHROUGH*/
+               }
+               if (p->trns->reserved != r->trns->reserved) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "reserved field should be zero.\n");
+                       /*FALLTHROUGH*/
+               }
+
+               /* compare attribute */
+               len = ntohs(r->trns->h.len) - sizeof(*p->trns);
+               if (memcmp(p->trns + 1, r->trns + 1, len) != 0) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "attribute has been modified.\n");
+                       /*FALLTHROUGH*/
+               }
+       }
+       if ((p && !q) || (!p && q)) {
+               /* # of protocols mismatched */
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "#of protocols mismatched.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * acceptable check for policy configuration.
+ * return a new SA payload to be reply to peer.
+ */
+static struct prop_pair *
+get_ph2approval(iph2, pair)
+       struct ph2handle *iph2;
+       struct prop_pair **pair;
+{
+       struct prop_pair *ret;
+       int i;
+
+       iph2->approval = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "begin compare proposals.\n");
+
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               if (pair[i] == NULL)
+                       continue;
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pair[%d]: %p\n", i, pair[i]);
+               print_proppair(LLV_DEBUG, pair[i]);;
+
+               /* compare proposal and select one */
+               ret = get_ph2approvalx(iph2, pair[i]);
+               if (ret != NULL) {
+                       /* found */
+                       return ret;
+               }
+       }
+
+       plog(LLV_ERROR, LOCATION, NULL, "no suitable policy found.\n");
+
+       return NULL;
+}
+
+/*
+ * compare my proposal and peers just one proposal.
+ * set a approval.
+ */
+static struct prop_pair *
+get_ph2approvalx(iph2, pp)
+       struct ph2handle *iph2;
+       struct prop_pair *pp;
+{
+       struct prop_pair *ret = NULL;
+       struct saprop *pr0, *pr = NULL;
+       struct saprop *q1, *q2;
+
+       pr0 = aproppair2saprop(pp);
+       if (pr0 == NULL)
+               return NULL;
+
+       for (q1 = pr0; q1; q1 = q1->next) {
+               for (q2 = iph2->proposal; q2; q2 = q2->next) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "peer's single bundle:\n");
+                       printsaprop0(LLV_DEBUG, q1);
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "my single bundle:\n");
+                       printsaprop0(LLV_DEBUG, q2);
+
+                       pr = cmpsaprop_alloc(iph2->ph1, q1, q2, iph2->side);
+                       if (pr != NULL)
+                               goto found;
+
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "not matched\n");
+               }
+       }
+       /* no proposal matching */
+err:
+       flushsaprop(pr0);
+       return NULL;
+
+found:
+       flushsaprop(pr0);
+       plog(LLV_DEBUG, LOCATION, NULL, "matched\n");
+       iph2->approval = pr;
+
+    {
+       struct saproto *sp;
+       struct prop_pair *p, *n, *x;
+
+       ret = NULL;
+
+       for (p = pp; p; p = p->next) {
+               /*
+                * find a proposal with matching proto_id.
+                * we have analyzed validity already, in cmpsaprop_alloc().
+                */
+               for (sp = pr->head; sp; sp = sp->next) {
+                       if (sp->proto_id == p->prop->proto_id)
+                               break;
+               }
+               if (!sp)
+                       goto err;
+               if (sp->head->next)
+                       goto err;       /* XXX */
+
+               for (x = p; x; x = x->tnext)
+                       if (sp->head->trns_no == x->trns->t_no)
+                               break;
+               if (!x)
+                       goto err;       /* XXX */
+
+               n = racoon_calloc(1, sizeof(struct prop_pair));
+               if (!n) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get buffer.\n");
+                       goto err;
+               }
+
+               n->prop = x->prop;
+               n->trns = x->trns;
+
+               /* need to preserve the order */
+               for (x = ret; x && x->next; x = x->next)
+                       ;
+               if (x && x->prop == n->prop) {
+                       for (/*nothing*/; x && x->tnext; x = x->tnext)
+                               ;
+                       x->tnext = n;
+               } else {
+                       if (x)
+                               x->next = n;
+                       else {
+                               ret = n;
+                       }
+               }
+
+               /* #of transforms should be updated ? */
+       }
+    }
+
+       return ret;
+}
+
+void
+free_proppair(pair)
+       struct prop_pair **pair;
+{
+       int i;
+
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               free_proppair0(pair[i]);
+               pair[i] = NULL;
+       }
+       racoon_free(pair);
+}
+
+static void
+free_proppair0(pair)
+       struct prop_pair *pair;
+{
+       struct prop_pair *p, *q, *r, *s;
+
+       p = pair;
+       while (p) {
+               q = p->next;
+               r = p;
+               while (r) {
+                       s = r->tnext;
+                       racoon_free(r);
+                       r = s;
+               }
+               p = q;
+       }
+}
+
+/*
+ * get proposal pairs from SA payload.
+ * tiny check for proposal payload.
+ */
+struct prop_pair **
+get_proppair(sa, mode)
+       vchar_t *sa;
+       int mode;
+{
+       struct prop_pair **pair;
+       int num_p = 0;                  /* number of proposal for use */
+       int tlen;
+       caddr_t bp;
+       int i;
+       struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "total SA len=%zu\n", sa->l);
+       plogdump(LLV_DEBUG, sa->v, sa->l);
+
+       /* check SA payload size */
+       if (sa->l < sizeof(*sab)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid SA length = %zu.\n", sa->l);
+               return NULL;
+       }
+
+       /* check DOI */
+       if (check_doi(ntohl(sab->doi)) < 0)
+               return NULL;
+
+       /* check SITUATION */
+       if (check_situation(ntohl(sab->sit)) < 0)
+               return NULL;
+
+       pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair));
+       if (pair == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer.\n");
+               return NULL;
+       }
+       memset(pair, 0, sizeof(pair));
+
+       bp = (caddr_t)(sab + 1);
+       tlen = sa->l - sizeof(*sab);
+
+    {
+       struct isakmp_pl_p *prop;
+       int proplen;
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+
+       pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen);
+       if (pbuf == NULL)
+               return NULL;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+               /* check the value of next payload */
+               if (pa->type != ISAKMP_NPTYPE_P) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid payload type=%u\n", pa->type);
+                       vfree(pbuf);
+                       return NULL;
+               }
+
+               prop = (struct isakmp_pl_p *)pa->ptr;
+               proplen = pa->len;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "proposal #%u len=%d\n", prop->p_no, proplen);
+
+               if (proplen == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proposal with length %d\n", proplen);
+                       vfree(pbuf);
+                       return NULL;
+               }
+
+               /* check Protocol ID */
+               if (!check_protocol[mode]) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "unsupported mode %d\n", mode);
+                       continue;
+               }
+
+               if (check_protocol[mode](prop->proto_id) < 0)
+                       continue;
+
+               /* check SPI length when IKE. */
+               if (check_spi_size(prop->proto_id, prop->spi_size) < 0)
+                       continue;
+
+               /* get transform */
+               if (get_transform(prop, pair, &num_p) < 0) {
+                       vfree(pbuf);
+                       return NULL;
+               }
+       }
+       vfree(pbuf);
+       pbuf = NULL;
+    }
+
+    {
+       int notrans, nprop;
+       struct prop_pair *p, *q;
+
+       /* check for proposals with no transforms */
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               if (!pair[i])
+                       continue;
+
+               plog(LLV_DEBUG, LOCATION, NULL, "pair %d:\n", i);
+               print_proppair(LLV_DEBUG, pair[i]);
+
+               notrans = nprop = 0;
+               for (p = pair[i]; p; p = p->next) {
+                       if (p->trns == NULL) {
+                               notrans++;
+                               break;
+                       }
+                       for (q = p; q; q = q->tnext)
+                               nprop++;
+               }
+
+#if 0
+               /*
+                * XXX at this moment, we cannot accept proposal group
+                * with multiple proposals.  this should be fixed.
+                */
+               if (pair[i]->next) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "proposal #%u ignored "
+                               "(multiple proposal not supported)\n",
+                               pair[i]->prop->p_no);
+                       notrans++;
+               }
+#endif
+
+               if (notrans) {
+                       for (p = pair[i]; p; p = q) {
+                               q = p->next;
+                               racoon_free(p);
+                       }
+                       pair[i] = NULL;
+                       num_p--;
+               } else {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "proposal #%u: %d transform\n",
+                               pair[i]->prop->p_no, nprop);
+               }
+       }
+    }
+
+       /* bark if no proposal is found. */
+       if (num_p <= 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no Proposal found.\n");
+               return NULL;
+       }
+
+       return pair;
+}
+
+/*
+ * check transform payload.
+ * OUT:
+ *     positive: return the pointer to the payload of valid transform.
+ *     0       : No valid transform found.
+ */
+static int
+get_transform(prop, pair, num_p)
+       struct isakmp_pl_p *prop;
+       struct prop_pair **pair;
+       int *num_p;
+{
+       int tlen; /* total length of all transform in a proposal */
+       caddr_t bp;
+       struct isakmp_pl_t *trns;
+       int trnslen;
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       struct prop_pair *p = NULL, *q;
+       int num_t;
+
+       bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size;
+       tlen = ntohs(prop->h.len)
+               - (sizeof(struct isakmp_pl_p) + prop->spi_size);
+       pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, tlen);
+       if (pbuf == NULL)
+               return -1;
+
+       /* check and get transform for use */
+       num_t = 0;
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               num_t++;
+
+               /* check the value of next payload */
+               if (pa->type != ISAKMP_NPTYPE_T) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid payload type=%u\n", pa->type);
+                       break;
+               }
+
+               trns = (struct isakmp_pl_t *)pa->ptr;
+               trnslen = pa->len;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "transform #%u len=%u\n", trns->t_no, trnslen);
+
+               /* check transform ID */
+               if (prop->proto_id >= ARRAYLEN(check_transform)) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "unsupported proto_id %u\n",
+                               prop->proto_id);
+                       continue;
+               }
+               if (prop->proto_id >= ARRAYLEN(check_attributes)) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "unsupported proto_id %u\n",
+                               prop->proto_id);
+                       continue;
+               }
+
+               if (!check_transform[prop->proto_id]
+                || !check_attributes[prop->proto_id]) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "unsupported proto_id %u\n",
+                               prop->proto_id);
+                       continue;
+               }
+               if (check_transform[prop->proto_id](trns->t_id) < 0)
+                       continue;
+
+               /* check data attributes */
+               if (check_attributes[prop->proto_id](trns) != 0)
+                       continue;
+
+               p = racoon_calloc(1, sizeof(*p));
+               if (p == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get buffer.\n");
+                       vfree(pbuf);
+                       return -1;
+               }
+               p->prop = prop;
+               p->trns = trns;
+
+               /* need to preserve the order */
+               for (q = pair[prop->p_no]; q && q->next; q = q->next)
+                       ;
+               if (q && q->prop == p->prop) {
+                       for (/*nothing*/; q && q->tnext; q = q->tnext)
+                               ;
+                       q->tnext = p;
+               } else {
+                       if (q)
+                               q->next = p;
+                       else {
+                               pair[prop->p_no] = p;
+                               (*num_p)++;
+                       }
+               }
+       }
+
+       vfree(pbuf);
+
+       return 0;
+}
+
+/*
+ * make a new SA payload from prop_pair.
+ * NOTE: this function make spi value clear.
+ */
+vchar_t *
+get_sabyproppair(pair, iph1)
+       struct prop_pair *pair;
+       struct ph1handle *iph1;
+{
+       vchar_t *newsa;
+       int newtlen;
+       u_int8_t *np_p = NULL;
+       struct prop_pair *p;
+       int prophlen, trnslen;
+       caddr_t bp;
+
+       newtlen = sizeof(struct ipsecdoi_sa_b);
+       for (p = pair; p; p = p->next) {
+               newtlen += sizeof(struct isakmp_pl_p);
+               newtlen += p->prop->spi_size;
+               newtlen += ntohs(p->trns->h.len);
+       }
+
+       newsa = vmalloc(newtlen);
+       if (newsa == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n");
+               return NULL;
+       }
+       bp = newsa->v;
+
+       ((struct isakmp_gen *)bp)->len = htons(newtlen);
+
+       /* update some of values in SA header */
+       ((struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype);
+       ((struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype);
+       bp += sizeof(struct ipsecdoi_sa_b);
+
+       /* create proposal payloads */
+       for (p = pair; p; p = p->next) {
+               prophlen = sizeof(struct isakmp_pl_p)
+                               + p->prop->spi_size;
+               trnslen = ntohs(p->trns->h.len);
+
+               if (np_p)
+                       *np_p = ISAKMP_NPTYPE_P;
+
+               /* create proposal */
+
+               memcpy(bp, p->prop, prophlen);
+               ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+               ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
+               ((struct isakmp_pl_p *)bp)->num_t = 1;
+               np_p = &((struct isakmp_pl_p *)bp)->h.np;
+               memset(bp + sizeof(struct isakmp_pl_p), 0, p->prop->spi_size);
+               bp += prophlen;
+
+               /* create transform */
+               memcpy(bp, p->trns, trnslen);
+               ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+               ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
+               bp += trnslen;
+       }
+
+       return newsa;
+}
+
+/*
+ * update responder's spi
+ */
+int
+ipsecdoi_updatespi(iph2)
+       struct ph2handle *iph2;
+{
+       struct prop_pair **pair, *p;
+       struct saprop *pp;
+       struct saproto *pr;
+       int i;
+       int error = -1;
+       u_int8_t *spi;
+
+       pair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
+       if (pair == NULL)
+               return -1;
+       for (i = 0; i < MAXPROPPAIRLEN; i++) {
+               if (pair[i])
+                       break;
+       }
+       if (i == MAXPROPPAIRLEN || pair[i]->tnext) {
+               /* multiple transform must be filtered by selectph2proposal.*/
+               goto end;
+       }
+
+       pp = iph2->approval;
+
+       /* create proposal payloads */
+       for (p = pair[i]; p; p = p->next) {
+               /*
+                * find a proposal/transform with matching proto_id/t_id.
+                * we have analyzed validity already, in cmpsaprop_alloc().
+                */
+               for (pr = pp->head; pr; pr = pr->next) {
+                       if (p->prop->proto_id == pr->proto_id &&
+                           p->trns->t_id == pr->head->trns_id) {
+                               break;
+                       }
+               }
+               if (!pr)
+                       goto end;
+
+               /*
+                * XXX SPI bits are left-filled, for use with IPComp.
+                * we should be switching to variable-length spi field...
+                */
+               spi = (u_int8_t *)&pr->spi;
+               spi += sizeof(pr->spi);
+               spi -= pr->spisize;
+               memcpy((caddr_t)p->prop + sizeof(*p->prop), spi, pr->spisize);
+       }
+
+       error = 0;
+end:
+       free_proppair(pair);
+       return error;
+}
+
+/*
+ * make a new SA payload from prop_pair.
+ */
+vchar_t *
+get_sabysaprop(pp0, sa0)
+       struct saprop *pp0;
+       vchar_t *sa0;
+{
+       struct prop_pair **pair;
+       vchar_t *newsa;
+       int newtlen;
+       u_int8_t *np_p = NULL;
+       struct prop_pair *p = NULL;
+       struct saprop *pp;
+       struct saproto *pr;
+       struct satrns *tr;
+       int prophlen, trnslen;
+       caddr_t bp;
+
+       /* get proposal pair */
+       pair = get_proppair(sa0, IPSECDOI_TYPE_PH2);
+       if (pair == NULL)
+               return NULL;
+
+       newtlen = sizeof(struct ipsecdoi_sa_b);
+       for (pp = pp0; pp; pp = pp->next) {
+
+               if (pair[pp->prop_no] == NULL)
+                       return NULL;
+
+               for (pr = pp->head; pr; pr = pr->next) {
+                       newtlen += (sizeof(struct isakmp_pl_p)
+                               + pr->spisize);
+
+                       for (tr = pr->head; tr; tr = tr->next) {
+                               for (p = pair[pp->prop_no]; p; p = p->tnext) {
+                                       if (tr->trns_no == p->trns->t_no)
+                                               break;
+                               }
+                               if (p == NULL)
+                                       return NULL;
+
+                               newtlen += ntohs(p->trns->h.len);
+                       }
+               }
+       }
+
+       newsa = vmalloc(newtlen);
+       if (newsa == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n");
+               return NULL;
+       }
+       bp = newsa->v;
+
+       /* some of values of SA must be updated in the out of this function */
+       ((struct isakmp_gen *)bp)->len = htons(newtlen);
+       bp += sizeof(struct ipsecdoi_sa_b);
+
+       /* create proposal payloads */
+       for (pp = pp0; pp; pp = pp->next) {
+
+               for (pr = pp->head; pr; pr = pr->next) {
+                       prophlen = sizeof(struct isakmp_pl_p)
+                                       + p->prop->spi_size;
+
+                       for (tr = pr->head; tr; tr = tr->next) {
+                               for (p = pair[pp->prop_no]; p; p = p->tnext) {
+                                       if (tr->trns_no == p->trns->t_no)
+                                               break;
+                               }
+                               if (p == NULL)
+                                       return NULL;
+
+                               trnslen = ntohs(p->trns->h.len);
+
+                               if (np_p)
+                                       *np_p = ISAKMP_NPTYPE_P;
+
+                               /* create proposal */
+
+                               memcpy(bp, p->prop, prophlen);
+                               ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+                               ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
+                               ((struct isakmp_pl_p *)bp)->num_t = 1;
+                               np_p = &((struct isakmp_pl_p *)bp)->h.np;
+                               bp += prophlen;
+
+                               /* create transform */
+                               memcpy(bp, p->trns, trnslen);
+                               ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+                               ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
+                               bp += trnslen;
+                       }
+               }
+       }
+
+       return newsa;
+}
+
+/*
+ * If some error happens then return 0.  Although 0 means that lifetime is zero,
+ * such a value should not be accepted.
+ * Also 0 of lifebyte should not be included in a packet although 0 means not
+ * to care of it.
+ */
+static u_int32_t
+ipsecdoi_set_ld(buf)
+       vchar_t *buf;
+{
+       u_int32_t ld;
+
+       if (buf == 0)
+               return 0;
+
+       switch (buf->l) {
+       case 2:
+               ld = ntohs(*(u_int16_t *)buf->v);
+               break;
+       case 4:
+               ld = ntohl(*(u_int32_t *)buf->v);
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "length %zu of life duration "
+                       "isn't supported.\n", buf->l);
+               return 0;
+       }
+
+       return ld;
+}
+
+/*%%%*/
+/*
+ * check DOI
+ */
+static int
+check_doi(doi)
+       u_int32_t doi;
+{
+       switch (doi) {
+       case IPSEC_DOI:
+               return 0;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid value of DOI 0x%08x.\n", doi);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check situation
+ */
+static int
+check_situation(sit)
+       u_int32_t sit;
+{
+       switch (sit) {
+       case IPSECDOI_SIT_IDENTITY_ONLY:
+               return 0;
+
+       case IPSECDOI_SIT_SECRECY:
+       case IPSECDOI_SIT_INTEGRITY:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "situation 0x%08x unsupported yet.\n", sit);
+               return -1;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid situation 0x%08x.\n", sit);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check protocol id in main mode
+ */
+static int
+check_prot_main(proto_id)
+       int proto_id;
+{
+       switch (proto_id) {
+       case IPSECDOI_PROTO_ISAKMP:
+               return 0;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Illegal protocol id=%u.\n", proto_id);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check protocol id in quick mode
+ */
+static int
+check_prot_quick(proto_id)
+       int proto_id;
+{
+       switch (proto_id) {
+       case IPSECDOI_PROTO_IPSEC_AH:
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               return 0;
+
+       case IPSECDOI_PROTO_IPCOMP:
+               return 0;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid protocol id %d.\n", proto_id);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+static int
+check_spi_size(proto_id, size)
+       int proto_id, size;
+{
+       switch (proto_id) {
+       case IPSECDOI_PROTO_ISAKMP:
+               if (size != 0) {
+                       /* WARNING */
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "SPI size isn't zero, but IKE proposal.\n");
+               }
+               return 0;
+
+       case IPSECDOI_PROTO_IPSEC_AH:
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               if (size != 4) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid SPI size=%d for IPSEC proposal.\n",
+                               size);
+                       return -1;
+               }
+               return 0;
+
+       case IPSECDOI_PROTO_IPCOMP:
+               if (size != 2 && size != 4) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid SPI size=%d for IPCOMP proposal.\n",
+                               size);
+                       return -1;
+               }
+               return 0;
+
+       default:
+               /* ??? */
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check transform ID in ISAKMP.
+ */
+static int
+check_trns_isakmp(t_id)
+       int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_KEY_IKE:
+               return 0;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid transform-id=%u in proto_id=%u.\n",
+                       t_id, IPSECDOI_KEY_IKE);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check transform ID in AH.
+ */
+static int
+check_trns_ah(t_id)
+       int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_AH_MD5:
+       case IPSECDOI_AH_SHA:
+       case IPSECDOI_AH_SHA256:
+       case IPSECDOI_AH_SHA384:
+       case IPSECDOI_AH_SHA512:
+               return 0;
+       case IPSECDOI_AH_DES:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not support transform-id=%u in AH.\n", t_id);
+               return -1;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid transform-id=%u in AH.\n", t_id);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check transform ID in ESP.
+ */
+static int
+check_trns_esp(t_id)
+       int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_ESP_DES:
+       case IPSECDOI_ESP_3DES:
+       case IPSECDOI_ESP_NULL:
+       case IPSECDOI_ESP_RC5:
+       case IPSECDOI_ESP_CAST:
+       case IPSECDOI_ESP_BLOWFISH:
+       case IPSECDOI_ESP_AES:
+       case IPSECDOI_ESP_TWOFISH:
+               return 0;
+       case IPSECDOI_ESP_DES_IV32:
+       case IPSECDOI_ESP_DES_IV64:
+       case IPSECDOI_ESP_IDEA:
+       case IPSECDOI_ESP_3IDEA:
+       case IPSECDOI_ESP_RC4:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not support transform-id=%u in ESP.\n", t_id);
+               return -1;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid transform-id=%u in ESP.\n", t_id);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check transform ID in IPCOMP.
+ */
+static int
+check_trns_ipcomp(t_id)
+       int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_IPCOMP_OUI:
+       case IPSECDOI_IPCOMP_DEFLATE:
+       case IPSECDOI_IPCOMP_LZS:
+               return 0;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid transform-id=%u in IPCOMP.\n", t_id);
+               return -1;
+       }
+       /* NOT REACHED */
+}
+
+/*
+ * check data attributes in IKE.
+ */
+static int
+check_attr_isakmp(trns)
+       struct isakmp_pl_t *trns;
+{
+       struct isakmp_data *d;
+       int tlen;
+       int flag, type;
+       u_int16_t lorv;
+
+       tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+       d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+
+       while (tlen > 0) {
+               type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+               flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+               lorv = ntohs(d->lorv);
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "type=%s, flag=0x%04x, lorv=%s\n",
+                       s_oakley_attr(type), flag,
+                       s_oakley_attr_v(type, lorv));
+
+               /*
+                * some of the attributes must be encoded in TV.
+                * see RFC2409 Appendix A "Attribute Classes".
+                */
+               switch (type) {
+               case OAKLEY_ATTR_ENC_ALG:
+               case OAKLEY_ATTR_HASH_ALG:
+               case OAKLEY_ATTR_AUTH_METHOD:
+               case OAKLEY_ATTR_GRP_DESC:
+               case OAKLEY_ATTR_GRP_TYPE:
+               case OAKLEY_ATTR_SA_LD_TYPE:
+               case OAKLEY_ATTR_PRF:
+               case OAKLEY_ATTR_KEY_LEN:
+               case OAKLEY_ATTR_FIELD_SIZE:
+                       if (!flag) {    /* TLV*/
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "oakley attribute %d must be TV.\n",
+                                       type);
+                               return -1;
+                       }
+                       break;
+               }
+
+               /* sanity check for TLV.  length must be specified. */
+               if (!flag && lorv == 0) {       /*TLV*/
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid length %d for TLV attribute %d.\n",
+                               lorv, type);
+                       return -1;
+               }
+
+               switch (type) {
+               case OAKLEY_ATTR_ENC_ALG:
+                       if (!alg_oakley_encdef_ok(lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalied encryption algorithm=%d.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_HASH_ALG:
+                       if (!alg_oakley_hashdef_ok(lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalied hash algorithm=%d.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_AUTH_METHOD:
+                       switch (lorv) {
+                       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+                       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+#endif  
+                       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+                               break;
+                       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+#ifdef ENABLE_HYBRID
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+#endif
+                       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+                       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "auth method %d isn't supported.\n",
+                                       lorv);
+                               return -1;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid auth method %d.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_GRP_DESC:
+                       if (!alg_oakley_dhdef_ok(lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid DH group %d.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_GRP_TYPE:
+                       switch (lorv) {
+                       case OAKLEY_ATTR_GRP_TYPE_MODP:
+                               break;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "unsupported DH group type %d.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_GRP_PI:
+               case OAKLEY_ATTR_GRP_GEN_ONE:
+                       /* sanity checks? */
+                       break;
+
+               case OAKLEY_ATTR_GRP_GEN_TWO:
+               case OAKLEY_ATTR_GRP_CURVE_A:
+               case OAKLEY_ATTR_GRP_CURVE_B:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "attr type=%u isn't supported.\n", type);
+                       return -1;
+
+               case OAKLEY_ATTR_SA_LD_TYPE:
+                       switch (lorv) {
+                       case OAKLEY_ATTR_SA_LD_TYPE_SEC:
+                       case OAKLEY_ATTR_SA_LD_TYPE_KB:
+                               break;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid life type %d.\n", lorv);
+                               return -1;
+                       }
+                       break;
+
+               case OAKLEY_ATTR_SA_LD:
+                       /* should check the value */
+                       break;
+
+               case OAKLEY_ATTR_PRF:
+               case OAKLEY_ATTR_KEY_LEN:
+                       break;
+
+               case OAKLEY_ATTR_FIELD_SIZE:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "attr type=%u isn't supported.\n", type);
+                       return -1;
+
+               case OAKLEY_ATTR_GRP_ORDER:
+                       break;
+
+               case OAKLEY_ATTR_GSS_ID:
+                       break;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid attribute type %d.\n", type);
+                       return -1;
+               }
+
+               if (flag) {
+                       tlen -= sizeof(*d);
+                       d = (struct isakmp_data *)((char *)d
+                               + sizeof(*d));
+               } else {
+                       tlen -= (sizeof(*d) + lorv);
+                       d = (struct isakmp_data *)((char *)d
+                               + sizeof(*d) + lorv);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * check data attributes in IPSEC AH/ESP.
+ */
+static int
+check_attr_ah(trns)
+       struct isakmp_pl_t *trns;
+{
+       return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_AH, trns);
+}
+
+static int
+check_attr_esp(trns)
+       struct isakmp_pl_t *trns;
+{
+       return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns);
+}
+
+static int
+check_attr_ipsec(proto_id, trns)
+       int proto_id;
+       struct isakmp_pl_t *trns;
+{
+       struct isakmp_data *d;
+       int tlen;
+       int flag, type = 0;
+       u_int16_t lorv;
+       int attrseen[16];       /* XXX magic number */
+
+       tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+       d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+       memset(attrseen, 0, sizeof(attrseen));
+
+       while (tlen > 0) {
+               type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+               flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+               lorv = ntohs(d->lorv);
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "type=%s, flag=0x%04x, lorv=%s\n",
+                       s_ipsecdoi_attr(type), flag,
+                       s_ipsecdoi_attr_v(type, lorv));
+
+               if (type < sizeof(attrseen)/sizeof(attrseen[0]))
+                       attrseen[type]++;
+
+               switch (type) {
+               case IPSECDOI_ATTR_ENC_MODE:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when ENC_MODE.\n");
+                               return -1;
+                       }
+
+                       switch (lorv) {
+                       case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
+                       case IPSECDOI_ATTR_ENC_MODE_TRNS:
+                               break;
+#ifdef ENABLE_NATT
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                    "UDP encapsulation requested\n");
+                               break;
+#endif
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid encryption mode=%u.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_AUTH:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when AUTH.\n");
+                               return -1;
+                       }
+
+                       switch (lorv) {
+                       case IPSECDOI_ATTR_AUTH_HMAC_MD5:
+                               if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
+                                   trns->t_id != IPSECDOI_AH_MD5) {
+ahmismatch:
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "auth algorithm %u conflicts "
+                                               "with transform %u.\n",
+                                               lorv, trns->t_id);
+                                       return -1;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
+                               if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+                                       if (trns->t_id != IPSECDOI_AH_SHA)
+                                               goto ahmismatch;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
+                               if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+                                       if (trns->t_id != IPSECDOI_AH_SHA256)
+                                               goto ahmismatch;
+                               }       
+                               break;
+                       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
+                               if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+                                       if (trns->t_id != IPSECDOI_AH_SHA384)
+                                               goto ahmismatch;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
+                               if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+                                       if (trns->t_id != IPSECDOI_AH_SHA512)
+                                       goto ahmismatch;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_AUTH_DES_MAC:
+                       case IPSECDOI_ATTR_AUTH_KPDK:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "auth algorithm %u isn't supported.\n",
+                                       lorv);
+                               return -1;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid auth algorithm=%u.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_SA_LD_TYPE:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when LD_TYPE.\n");
+                               return -1;
+                       }
+
+                       switch (lorv) {
+                       case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+                       case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+                               break;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid life type %d.\n", lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_SA_LD:
+                       if (flag) {
+                               /* i.e. ISAKMP_GEN_TV */
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "life duration was in TLV.\n");
+                       } else {
+                               /* i.e. ISAKMP_GEN_TLV */
+                               if (lorv == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid length of LD\n");
+                                       return -1;
+                               }
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_GRP_DESC:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when GRP_DESC.\n");
+                               return -1;
+                       }
+
+                       if (!alg_oakley_dhdef_ok(lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid group description=%u.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_KEY_LENGTH:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when KEY_LENGTH.\n");
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_KEY_ROUNDS:
+               case IPSECDOI_ATTR_COMP_DICT_SIZE:
+               case IPSECDOI_ATTR_COMP_PRIVALG:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "attr type=%u isn't supported.\n", type);
+                       return -1;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid attribute type %d.\n", type);
+                       return -1;
+               }
+
+               if (flag) {
+                       tlen -= sizeof(*d);
+                       d = (struct isakmp_data *)((char *)d
+                               + sizeof(*d));
+               } else {
+                       tlen -= (sizeof(*d) + lorv);
+                       d = (struct isakmp_data *)((caddr_t)d
+                               + sizeof(*d) + lorv);
+               }
+       }
+
+       if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
+           !attrseen[IPSECDOI_ATTR_AUTH]) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "attr AUTH must be present for AH.\n");
+               return -1;
+       }
+
+       if (proto_id == IPSECDOI_PROTO_IPSEC_ESP &&
+           trns->t_id == IPSECDOI_ESP_NULL &&
+           !attrseen[IPSECDOI_ATTR_AUTH]) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "attr AUTH must be present for ESP NULL encryption.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+check_attr_ipcomp(trns)
+       struct isakmp_pl_t *trns;
+{
+       struct isakmp_data *d;
+       int tlen;
+       int flag, type = 0;
+       u_int16_t lorv;
+       int attrseen[16];       /* XXX magic number */
+
+       tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+       d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+       memset(attrseen, 0, sizeof(attrseen));
+
+       while (tlen > 0) {
+               type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+               flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+               lorv = ntohs(d->lorv);
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "type=%d, flag=0x%04x, lorv=0x%04x\n",
+                       type, flag, lorv);
+
+               if (type < sizeof(attrseen)/sizeof(attrseen[0]))
+                       attrseen[type]++;
+
+               switch (type) {
+               case IPSECDOI_ATTR_ENC_MODE:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when ENC_MODE.\n");
+                               return -1;
+                       }
+
+                       switch (lorv) {
+                       case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
+                       case IPSECDOI_ATTR_ENC_MODE_TRNS:
+                               break;
+#ifdef ENABLE_NATT
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
+                       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                    "UDP encapsulation requested\n");
+                               break;
+#endif
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid encryption mode=%u.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_SA_LD_TYPE:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when LD_TYPE.\n");
+                               return -1;
+                       }
+
+                       switch (lorv) {
+                       case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+                       case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+                               break;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid life type %d.\n", lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_SA_LD:
+                       if (flag) {
+                               /* i.e. ISAKMP_GEN_TV */
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "life duration was in TLV.\n");
+                       } else {
+                               /* i.e. ISAKMP_GEN_TLV */
+                               if (lorv == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid length of LD\n");
+                                       return -1;
+                               }
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_GRP_DESC:
+                       if (! flag) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "must be TV when GRP_DESC.\n");
+                               return -1;
+                       }
+
+                       if (!alg_oakley_dhdef_ok(lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid group description=%u.\n",
+                                       lorv);
+                               return -1;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_AUTH:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid attr type=%u.\n", type);
+                       return -1;
+
+               case IPSECDOI_ATTR_KEY_LENGTH:
+               case IPSECDOI_ATTR_KEY_ROUNDS:
+               case IPSECDOI_ATTR_COMP_DICT_SIZE:
+               case IPSECDOI_ATTR_COMP_PRIVALG:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "attr type=%u isn't supported.\n", type);
+                       return -1;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid attribute type %d.\n", type);
+                       return -1;
+               }
+
+               if (flag) {
+                       tlen -= sizeof(*d);
+                       d = (struct isakmp_data *)((char *)d
+                               + sizeof(*d));
+               } else {
+                       tlen -= (sizeof(*d) + lorv);
+                       d = (struct isakmp_data *)((caddr_t)d
+                               + sizeof(*d) + lorv);
+               }
+       }
+
+#if 0
+       if (proto_id == IPSECDOI_PROTO_IPCOMP &&
+           !attrseen[IPSECDOI_ATTR_AUTH]) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "attr AUTH must be present for AH.\n", type);
+               return -1;
+       }
+#endif
+
+       return 0;
+}
+
+/* %%% */
+/*
+ * create phase1 proposal from remote configuration.
+ * NOT INCLUDING isakmp general header of SA payload
+ */
+vchar_t *
+ipsecdoi_setph1proposal(props)
+       struct isakmpsa *props;
+{
+       vchar_t *mysa;
+       int sablen;
+
+       /* count total size of SA minus isakmp general header */
+       /* not including isakmp general header of SA payload */
+       sablen = sizeof(struct ipsecdoi_sa_b);
+       sablen += setph1prop(props, NULL);
+
+       mysa = vmalloc(sablen);
+       if (mysa == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate my sa buffer\n");
+               return NULL;
+       }
+
+       /* create SA payload */
+       /* not including isakmp general header */
+       ((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(props->rmconf->doitype);
+       ((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype);
+
+       (void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b));
+
+       return mysa;
+}
+
+static int
+setph1prop(props, buf)
+       struct isakmpsa *props;
+       caddr_t buf;
+{
+       struct isakmp_pl_p *prop = NULL;
+       struct isakmpsa *s = NULL;
+       int proplen, trnslen;
+       u_int8_t *np_t; /* pointer next trns type in previous header */
+       int trns_num;
+       caddr_t p = buf;
+
+       proplen = sizeof(*prop);
+       if (buf) {
+               /* create proposal */
+               prop = (struct isakmp_pl_p *)p;
+               prop->h.np = ISAKMP_NPTYPE_NONE;
+               prop->p_no = props->prop_no;
+               prop->proto_id = IPSECDOI_PROTO_ISAKMP;
+               prop->spi_size = 0;
+               p += sizeof(*prop);
+       }
+
+       np_t = NULL;
+       trns_num = 0;
+
+       for (s = props; s != NULL; s = s->next) {
+               if (np_t)
+                       *np_t = ISAKMP_NPTYPE_T;
+
+               trnslen = setph1trns(s, p);
+               proplen += trnslen;
+               if (buf) {
+                       /* save buffer to pre-next payload */
+                       np_t = &((struct isakmp_pl_t *)p)->h.np;
+                       p += trnslen;
+
+                       /* count up transform length */
+                       trns_num++;
+               }
+       }
+
+       /* update proposal length */
+       if (buf) {
+               prop->h.len = htons(proplen);
+               prop->num_t = trns_num;
+       }
+
+       return proplen;
+}
+
+static int
+setph1trns(sa, buf)
+       struct isakmpsa *sa;
+       caddr_t buf;
+{
+       struct isakmp_pl_t *trns = NULL;
+       int trnslen, attrlen;
+       caddr_t p = buf;
+
+       trnslen = sizeof(*trns);
+       if (buf) {
+               /* create transform */
+               trns = (struct isakmp_pl_t *)p;
+               trns->h.np  = ISAKMP_NPTYPE_NONE;
+               trns->t_no  = sa->trns_no;
+               trns->t_id  = IPSECDOI_KEY_IKE;
+               p += sizeof(*trns);
+       }
+
+       attrlen = setph1attr(sa, p);
+       trnslen += attrlen;
+       if (buf)
+               p += attrlen;
+
+       if (buf)
+               trns->h.len = htons(trnslen);
+
+       return trnslen;
+}
+
+static int
+setph1attr(sa, buf)
+       struct isakmpsa *sa;
+       caddr_t buf;
+{
+       caddr_t p = buf;
+       int attrlen = 0;
+
+       if (sa->lifetime) {
+               u_int32_t lifetime = htonl((u_int32_t)sa->lifetime);
+
+               attrlen += sizeof(struct isakmp_data)
+                       + sizeof(struct isakmp_data);
+               if (sa->lifetime > 0xffff)
+                       attrlen += sizeof(lifetime);
+               if (buf) {
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
+                                               OAKLEY_ATTR_SA_LD_TYPE_SEC);
+                       if (sa->lifetime > 0xffff) {
+                               p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
+                                               (caddr_t)&lifetime, 
+                                               sizeof(lifetime));
+                       } else {
+                               p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
+                                                       sa->lifetime);
+                       }
+               }
+       }
+
+       if (sa->lifebyte) {
+               u_int32_t lifebyte = htonl((u_int32_t)sa->lifebyte);
+               
+               attrlen += sizeof(struct isakmp_data)
+                       + sizeof(struct isakmp_data);
+               if (sa->lifebyte > 0xffff)
+                       attrlen += sizeof(lifebyte);
+               if (buf) {
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
+                                               OAKLEY_ATTR_SA_LD_TYPE_KB);
+                       if (sa->lifebyte > 0xffff) {
+                               p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
+                                                       (caddr_t)&lifebyte,
+                                                       sizeof(lifebyte));
+                       } else {
+                               p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
+                                                       sa->lifebyte);
+                       }
+               }
+       }
+
+       if (sa->enctype) {
+               attrlen += sizeof(struct isakmp_data);
+               if (buf)
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_ENC_ALG, sa->enctype);
+       }
+       if (sa->encklen) {
+               attrlen += sizeof(struct isakmp_data);
+               if (buf)
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_KEY_LEN, sa->encklen);
+       }
+       if (sa->authmethod) {
+               int authmethod;
+
+#ifdef ENABLE_HYBRID
+               authmethod = switch_authmethod(sa->authmethod);
+#else
+               authmethod = sa->authmethod;
+#endif
+               attrlen += sizeof(struct isakmp_data);
+               if (buf)
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod);
+       }
+       if (sa->hashtype) {
+               attrlen += sizeof(struct isakmp_data);
+               if (buf)
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_HASH_ALG, sa->hashtype);
+       }
+       switch (sa->dh_group) {
+       case OAKLEY_ATTR_GRP_DESC_MODP768:
+       case OAKLEY_ATTR_GRP_DESC_MODP1024:
+       case OAKLEY_ATTR_GRP_DESC_MODP1536:
+       case OAKLEY_ATTR_GRP_DESC_MODP2048:
+       case OAKLEY_ATTR_GRP_DESC_MODP3072:
+       case OAKLEY_ATTR_GRP_DESC_MODP4096:
+       case OAKLEY_ATTR_GRP_DESC_MODP6144:
+       case OAKLEY_ATTR_GRP_DESC_MODP8192:
+               /* don't attach group type for known groups */
+               attrlen += sizeof(struct isakmp_data);
+               if (buf) {
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_DESC,
+                               sa->dh_group);
+               }
+               break;
+       case OAKLEY_ATTR_GRP_DESC_EC2N155:
+       case OAKLEY_ATTR_GRP_DESC_EC2N185:
+               /* don't attach group type for known groups */
+               attrlen += sizeof(struct isakmp_data);
+               if (buf) {
+                       p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_TYPE,
+                               OAKLEY_ATTR_GRP_TYPE_EC2N);
+               }
+               break;
+       case 0:
+       default:
+               break;
+       }
+
+#ifdef HAVE_GSSAPI
+       if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+           sa->gssid != NULL) {
+               attrlen += sizeof(struct isakmp_data);
+               /*
+                * Older versions of racoon just placed the ISO-Latin-1
+                * string on the wire directly.  Check to see if we are
+                * configured to be compatible with this behavior.  Otherwise,
+                * we encode the GSS ID as UTF-16LE for Windows 2000
+                * compatibility, which requires twice the number of octets.
+                */
+               if (lcconf->gss_id_enc == LC_GSSENC_LATIN1)
+                       attrlen += sa->gssid->l;
+               else
+                       attrlen += sa->gssid->l * 2;
+               if (buf) {
+                       plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %d, "
+                           "val '%.*s'\n", sa->gssid->l, sa->gssid->l,
+                           sa->gssid->v);
+                       if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) {
+                               p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID,
+                                       (caddr_t)sa->gssid->v,
+                                       sa->gssid->l);
+                       } else {
+                               size_t dstleft = sa->gssid->l * 2;
+                               size_t srcleft = sa->gssid->l;
+                               const char *src = (const char *)sa->gssid->v;
+                               char *odst, *dst = racoon_malloc(dstleft);
+                               iconv_t cd;
+                               size_t rv;
+
+                               cd = iconv_open("utf-16le", "latin1");
+                               if (cd == (iconv_t) -1) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                           "unable to initialize "
+                                           "latin1 -> utf-16le "
+                                           "converstion descriptor: %s\n",
+                                           strerror(errno));
+                                       attrlen -= sa->gssid->l * 2;
+                                       goto gssid_done;
+                               }
+                               odst = dst;
+                               rv = iconv(cd, (__iconv_const char **)&src, 
+                                   &srcleft, &dst, &dstleft);
+                               if (rv != 0) {
+                                       if (rv == -1) {
+                                               plog(LLV_ERROR, LOCATION, NULL,
+                                                   "unable to convert GSS ID "
+                                                   "from latin1 -> utf-16le: "
+                                                   "%s\n", strerror(errno));
+                                       } else {
+                                               /* should never happen */
+                                               plog(LLV_ERROR, LOCATION, NULL,
+                                                   "%zd character%s in GSS ID "
+                                                   "cannot be represented "
+                                                   "in utf-16le\n",
+                                                   rv, rv == 1 ? "" : "s");
+                                       }
+                                       (void) iconv_close(cd);
+                                       attrlen -= sa->gssid->l * 2;
+                                       goto gssid_done;
+                               }
+                               (void) iconv_close(cd);
+
+                               /* XXX Check srcleft and dstleft? */
+
+                               p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID,
+                                       odst, sa->gssid->l * 2);
+
+                               racoon_free(odst);
+                       }
+               }
+       }
+ gssid_done:
+#endif /* HAVE_GSSAPI */
+
+       return attrlen;
+}
+
+static vchar_t *
+setph2proposal0(iph2, pp, pr)
+       const struct ph2handle *iph2;
+       const struct saprop *pp;
+       const struct saproto *pr;
+{
+       vchar_t *p;
+       struct isakmp_pl_p *prop;
+       struct isakmp_pl_t *trns;
+       struct satrns *tr;
+       int attrlen;
+       size_t trnsoff;
+       caddr_t x0, x;
+       u_int8_t *np_t; /* pointer next trns type in previous header */
+       const u_int8_t *spi;
+
+       p = vmalloc(sizeof(*prop) + sizeof(pr->spi));
+       if (p == NULL)
+               return NULL;
+
+       /* create proposal */
+       prop = (struct isakmp_pl_p *)p->v;
+       prop->h.np = ISAKMP_NPTYPE_NONE;
+       prop->p_no = pp->prop_no;
+       prop->proto_id = pr->proto_id;
+       prop->num_t = 1;
+
+       spi = (const u_int8_t *)&pr->spi;
+       switch (pr->proto_id) {
+       case IPSECDOI_PROTO_IPCOMP:
+               /*
+                * draft-shacham-ippcp-rfc2393bis-05.txt:
+                * construct 16bit SPI (CPI).
+                * XXX we may need to provide a configuration option to
+                * generate 32bit SPI.  otherwise we cannot interoeprate
+                * with nodes that uses 32bit SPI, in case we are initiator.
+                */
+               prop->spi_size = sizeof(u_int16_t);
+               spi += sizeof(pr->spi) - sizeof(u_int16_t);
+               p->l -= sizeof(pr->spi);
+               p->l += sizeof(u_int16_t);
+               break;
+       default:
+               prop->spi_size = sizeof(pr->spi);
+               break;
+       }
+       memcpy(prop + 1, spi, prop->spi_size);
+
+       /* create transform */
+       trnsoff = sizeof(*prop) + prop->spi_size;
+       np_t = NULL;
+
+       for (tr = pr->head; tr; tr = tr->next) {
+       
+               switch (pr->proto_id) {
+               case IPSECDOI_PROTO_IPSEC_ESP:
+                       /*
+                        * don't build a null encryption
+                        * with no authentication transform.
+                        */
+                       if (tr->trns_id == IPSECDOI_ESP_NULL &&
+                           tr->authtype == IPSECDOI_ATTR_AUTH_NONE)
+                               continue;
+                       break;
+               }
+
+               if (np_t) {
+                       *np_t = ISAKMP_NPTYPE_T;
+                       prop->num_t++;
+               }
+
+               /* get attribute length */
+               attrlen = 0;
+               if (pp->lifetime) {
+                       attrlen += sizeof(struct isakmp_data)
+                               + sizeof(struct isakmp_data);
+                       if (pp->lifetime > 0xffff)
+                               attrlen += sizeof(u_int32_t);
+               }
+               if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
+                       attrlen += sizeof(struct isakmp_data)
+                               + sizeof(struct isakmp_data);
+                       if (pp->lifebyte > 0xffff)
+                               attrlen += sizeof(u_int32_t);
+               }
+               attrlen += sizeof(struct isakmp_data);  /* enc mode */
+               if (tr->encklen)
+                       attrlen += sizeof(struct isakmp_data);
+
+               switch (pr->proto_id) {
+               case IPSECDOI_PROTO_IPSEC_ESP:
+                       /* non authentication mode ? */
+                       if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
+                               attrlen += sizeof(struct isakmp_data);
+                       break;
+               case IPSECDOI_PROTO_IPSEC_AH:
+                       if (tr->authtype == IPSECDOI_ATTR_AUTH_NONE) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no authentication algorithm found "
+                                       "but protocol is AH.\n");
+                               vfree(p);
+                               return NULL;
+                       }
+                       attrlen += sizeof(struct isakmp_data);
+                       break;
+               case IPSECDOI_PROTO_IPCOMP:
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid protocol: %d\n", pr->proto_id);
+                       vfree(p);
+                       return NULL;
+               }
+
+               if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
+                       attrlen += sizeof(struct isakmp_data);
+
+               p = vrealloc(p, p->l + sizeof(*trns) + attrlen);
+               if (p == NULL)
+                       return NULL;
+               prop = (struct isakmp_pl_p *)p->v;
+
+               /* set transform's values */
+               trns = (struct isakmp_pl_t *)(p->v + trnsoff);
+               trns->h.np  = ISAKMP_NPTYPE_NONE;
+               trns->t_no  = tr->trns_no;
+               trns->t_id  = tr->trns_id;
+
+               /* set attributes */
+               x = x0 = p->v + trnsoff + sizeof(*trns);
+
+               if (pp->lifetime) {
+                       x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
+                                               IPSECDOI_ATTR_SA_LD_TYPE_SEC);
+                       if (pp->lifetime > 0xffff) {
+                               u_int32_t v = htonl((u_int32_t)pp->lifetime);
+                               x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
+                                                       (caddr_t)&v, sizeof(v));
+                       } else {
+                               x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
+                                                       pp->lifetime);
+                       }
+               }
+
+               if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
+                       x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
+                                               IPSECDOI_ATTR_SA_LD_TYPE_KB);
+                       if (pp->lifebyte > 0xffff) {
+                               u_int32_t v = htonl((u_int32_t)pp->lifebyte);
+                               x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
+                                                       (caddr_t)&v, sizeof(v));
+                       } else {
+                               x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
+                                                       pp->lifebyte);
+                       }
+               }
+
+               x = isakmp_set_attr_l(x, IPSECDOI_ATTR_ENC_MODE, pr->encmode);
+
+               if (tr->encklen)
+                       x = isakmp_set_attr_l(x, IPSECDOI_ATTR_KEY_LENGTH, tr->encklen);
+
+               /* mandatory check has done above. */
+               if ((pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP && tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
+                || pr->proto_id == IPSECDOI_PROTO_IPSEC_AH)
+                       x = isakmp_set_attr_l(x, IPSECDOI_ATTR_AUTH, tr->authtype);
+
+               if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
+                       x = isakmp_set_attr_l(x, IPSECDOI_ATTR_GRP_DESC,
+                               iph2->sainfo->pfs_group);
+
+               /* update length of this transform. */
+               trns = (struct isakmp_pl_t *)(p->v + trnsoff);
+               trns->h.len = htons(sizeof(*trns) + attrlen);
+
+               /* save buffer to pre-next payload */
+               np_t = &trns->h.np;
+
+               trnsoff += (sizeof(*trns) + attrlen);
+       }
+
+       if (np_t == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no suitable proposal was created.\n");
+               return NULL;
+       }
+
+       /* update length of this protocol. */
+       prop->h.len = htons(p->l);
+
+       return p;
+}
+
+/*
+ * create phase2 proposal from policy configuration.
+ * NOT INCLUDING isakmp general header of SA payload.
+ * This function is called by initiator only.
+ */
+int
+ipsecdoi_setph2proposal(iph2)
+       struct ph2handle *iph2;
+{
+       struct saprop *proposal, *a;
+       struct saproto *b = NULL;
+       vchar_t *q;
+       struct ipsecdoi_sa_b *sab;
+       struct isakmp_pl_p *prop;
+       size_t propoff; /* for previous field of type of next payload. */
+
+       proposal = iph2->proposal;
+
+       iph2->sa = vmalloc(sizeof(*sab));
+       if (iph2->sa == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate my sa buffer\n");
+               return -1;
+       }
+
+       /* create SA payload */
+       sab = (struct ipsecdoi_sa_b *)iph2->sa->v;
+       sab->doi = htonl(IPSEC_DOI);
+       sab->sit = htonl(IPSECDOI_SIT_IDENTITY_ONLY);   /* XXX configurable ? */
+
+       prop = NULL;
+       propoff = 0;
+       for (a = proposal; a; a = a->next) {
+               for (b = a->head; b; b = b->next) {
+#ifdef ENABLE_NATT
+                       if (iph2->ph1->natt_flags & NAT_DETECTED) {
+                         int udp_diff = iph2->ph1->natt_options->mode_udp_diff;
+                         plog (LLV_INFO, LOCATION, NULL,
+                               "NAT detected -> UDP encapsulation "
+                               "(ENC_MODE %d->%d).\n",
+                               b->encmode,
+                               b->encmode+udp_diff);
+                         /* Tunnel -> UDP-Tunnel, Transport -> UDP_Transport */
+                         b->encmode += udp_diff;
+                         b->udp_encap = 1;
+                       }
+#endif
+
+                       q = setph2proposal0(iph2, a, b);
+                       if (q == NULL) {
+                               VPTRINIT(iph2->sa);
+                               return -1;
+                       }
+
+                       iph2->sa = vrealloc(iph2->sa, iph2->sa->l + q->l);
+                       if (iph2->sa == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to allocate my sa buffer\n");
+                               if (q)
+                                       vfree(q);
+                               return -1;
+                       }
+                       memcpy(iph2->sa->v + iph2->sa->l - q->l, q->v, q->l);
+                       if (propoff != 0) {
+                               prop = (struct isakmp_pl_p *)(iph2->sa->v +
+                                       propoff);
+                               prop->h.np = ISAKMP_NPTYPE_P;
+                       }
+                       propoff = iph2->sa->l - q->l;
+
+                       vfree(q);
+               }
+       }
+
+       return 0;
+}
+
+#ifdef __APPLE__
+/*
+ * return 1 if all of the given protocols are transport mode.
+ */
+int
+ipsecdoi_tunnelmode(iph2)
+       struct ph2handle *iph2;
+{
+       struct saprop *pp;
+       struct saproto *pr = NULL;
+
+       for (pp = iph2->proposal; pp; pp = pp->next) {
+               for (pr = pp->head; pr; pr = pr->next) {
+                       if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TUNNEL &&
+                               pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC &&
+                               pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT)
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+#endif
+
+/*
+ * return 1 if all of the given protocols are transport mode.
+ */
+int
+ipsecdoi_transportmode(pp)
+       struct saprop *pp;
+{
+       struct saproto *pr = NULL;
+
+       for (; pp; pp = pp->next) {
+               for (pr = pp->head; pr; pr = pr->next) {
+                       if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS)
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+
+int
+ipsecdoi_get_defaultlifetime()
+{
+       return IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+}
+
+int
+ipsecdoi_checkalgtypes(proto_id, enc, auth, comp)
+       int proto_id, enc, auth, comp;
+{
+#define TMPALGTYPE2STR(n) s_algtype(algclass_ipsec_##n, n)
+       switch (proto_id) {
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               if (enc == 0 || comp != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "illegal algorithm defined "
+                               "ESP enc=%s auth=%s comp=%s.\n",
+                               TMPALGTYPE2STR(enc),
+                               TMPALGTYPE2STR(auth),
+                               TMPALGTYPE2STR(comp));
+                       return -1;
+               }
+               break;
+       case IPSECDOI_PROTO_IPSEC_AH:
+               if (enc != 0 || auth == 0 || comp != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "illegal algorithm defined "
+                               "AH enc=%s auth=%s comp=%s.\n",
+                               TMPALGTYPE2STR(enc),
+                               TMPALGTYPE2STR(auth),
+                               TMPALGTYPE2STR(comp));
+                       return -1;
+               }
+               break;
+       case IPSECDOI_PROTO_IPCOMP:
+               if (enc != 0 || auth != 0 || comp == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "illegal algorithm defined "
+                               "IPcomp enc=%s auth=%s comp=%s.\n",
+                               TMPALGTYPE2STR(enc),
+                               TMPALGTYPE2STR(auth),
+                               TMPALGTYPE2STR(comp));
+                       return -1;
+               }
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid ipsec protocol %d\n", proto_id);
+               return -1;
+       }
+#undef TMPALGTYPE2STR
+       return 0;
+}
+
+int
+ipproto2doi(proto)
+       int proto;
+{
+       switch (proto) {
+       case IPPROTO_AH:
+               return IPSECDOI_PROTO_IPSEC_AH;
+       case IPPROTO_ESP:
+               return IPSECDOI_PROTO_IPSEC_ESP;
+       case IPPROTO_IPCOMP:
+               return IPSECDOI_PROTO_IPCOMP;
+       }
+       return -1;      /* XXX */
+}
+
+int
+doi2ipproto(proto)
+       int proto;
+{
+       switch (proto) {
+       case IPSECDOI_PROTO_IPSEC_AH:
+               return IPPROTO_AH;
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               return IPPROTO_ESP;
+       case IPSECDOI_PROTO_IPCOMP:
+               return IPPROTO_IPCOMP;
+       }
+       return -1;      /* XXX */
+}
+
+/*
+ * check the following:
+ * - In main mode with pre-shared key, only address type can be used.
+ * - if proper type for phase 1 ?
+ * - if phase 1 ID payload conformed RFC2407 4.6.2.
+ *   (proto, port) must be (0, 0), (udp, 500) or (udp, [specified]).
+ * - if ID payload sent from peer is equal to the ID expected by me.
+ *
+ * both of "id" and "id_p" should be ID payload without general header,
+ */
+int
+ipsecdoi_checkid1(iph1)
+       struct ph1handle *iph1;
+{
+       struct ipsecdoi_id_b *id_b;
+       struct sockaddr *sa;
+       caddr_t sa1, sa2;
+
+       if (iph1->id_p == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid iph1 passed id_p == NULL\n");
+               return ISAKMP_INTERNAL_ERROR;
+       }
+       if (iph1->id_p->l < sizeof(*id_b)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid value passed as \"ident\" (len=%lu)\n",
+                       (u_long)iph1->id_p->l);
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+
+       id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
+
+       /*      In main mode with pre-shared key, only address type can be used. 
+        *      If NAT Traversal being used and peer is behind nat and 
+        *      natt version = 02 - allow non-address ID type.          
+        */
+       if (iph1->etype == ISAKMP_ETYPE_IDENT
+        && iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY
+#ifdef ENABLE_NATT     
+        && (iph1->natt_flags & NAT_DETECTED_PEER) == 0
+#endif
+               ) {
+                if (id_b->type != IPSECDOI_ID_IPV4_ADDR
+                 && id_b->type != IPSECDOI_ID_IPV6_ADDR) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Expecting IP address type in main mode, "
+                               "but %s.\n", s_ipsecdoi_ident(id_b->type));
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+       }
+
+       /* if proper type for phase 1 ? */
+       switch (id_b->type) {
+       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+       case IPSECDOI_ID_IPV4_ADDR_RANGE:
+       case IPSECDOI_ID_IPV6_ADDR_RANGE:
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "such ID type %s is not proper.\n",
+                       s_ipsecdoi_ident(id_b->type));
+               /*FALLTHROUGH*/
+       }
+
+       /* if phase 1 ID payload conformed RFC2407 4.6.2. */
+       if (id_b->type == IPSECDOI_ID_IPV4_ADDR ||              // %%%% BUG_FIX - should be || not &&
+           id_b->type == IPSECDOI_ID_IPV6_ADDR) {
+
+               if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "protocol ID and Port mismatched. "
+                               "proto_id:%d port:%d\n",
+                               id_b->proto_id, ntohs(id_b->port));
+                       /*FALLTHROUGH*/
+
+               } else if (id_b->proto_id == IPPROTO_UDP) {
+                       /*
+                        * copmaring with expected port.
+                        * always permit if port is equal to PORT_ISAKMP
+                        */
+                       if (ntohs(id_b->port) != PORT_ISAKMP) {
+
+                               u_int16_t port;
+
+                               switch (iph1->remote->sa_family) {
+                               case AF_INET:
+                                       port = ((struct sockaddr_in *)iph1->remote)->sin_port;
+                                       break;
+#ifdef INET6
+                               case AF_INET6:
+                                       port = ((struct sockaddr_in6 *)iph1->remote)->sin6_port;
+                                       break;
+#endif
+                               default:
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid family: %d\n",
+                                               iph1->remote->sa_family);
+                                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                               }
+                               if (ntohs(id_b->port) != port) {
+                                       plog(LLV_WARNING, LOCATION, NULL,
+                                               "port %d expected, but %d\n",
+                                               port, ntohs(id_b->port));
+                                       /*FALLTHROUGH*/
+                               }
+                       }
+               }
+       }
+
+       /* compare with the ID if specified. */
+       if (genlist_next(iph1->rmconf->idvl_p, 0)) {
+               vchar_t *ident0 = NULL;
+               vchar_t ident;
+               struct idspec *id;
+               struct genlist_entry *gpb;
+
+               for (id = genlist_next (iph1->rmconf->idvl_p, &gpb); id; id = genlist_next (0, &gpb)) {
+                       /* check the type of both IDs */
+                       if (id->idtype != doi2idtype(id_b->type))
+                               continue;  /* ID type mismatch */
+                       if (id->id == 0)
+                               goto matched;
+
+                       /* compare defined ID with the ID sent by peer. */
+                       if (ident0 != NULL)
+                               vfree(ident0);
+                       ident0 = getidval(id->idtype, id->id);
+
+                       switch (id->idtype) {
+                       case IDTYPE_ASN1DN:
+                               ident.v = (caddr_t)(id_b + 1);
+                               ident.l = iph1->id_p->l - 1; /* had ident.l = ident0->l; but why?? */
+                                     /* is the actual packet contents length sometimes wrong? */
+                               if (eay_cmp_asn1dn(ident0, &ident) == 0)
+                                       goto matched;
+                               break;
+                       case IDTYPE_ADDRESS:
+                               sa = (struct sockaddr *)ident0->v;
+                               sa2 = (caddr_t)(id_b + 1);
+                               switch (sa->sa_family) {
+                               case AF_INET:
+                                       if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in_addr))
+                                               continue;  /* ID value mismatch */
+                                       sa1 = (caddr_t)&((struct sockaddr_in *)sa)->sin_addr;
+                                       if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0)
+                                               goto matched;
+                                       break;
+#ifdef INET6
+                               case AF_INET6:
+                                       if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in6_addr))
+                                               continue;  /* ID value mismatch */
+                                       sa1 = (caddr_t)&((struct sockaddr_in6 *)sa)->sin6_addr;
+                                       if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0)
+                                               goto matched;
+                                       break;
+#endif
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               if (memcmp(ident0->v, id_b + 1, ident0->l) == 0)
+                                       goto matched;
+                               break;
+                       }
+               }
+               if (ident0 != NULL) {
+                       vfree(ident0);
+                       ident0 = NULL;
+               }
+               plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n");
+               if (iph1->rmconf->verify_identifier)
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+matched: /* ID value match */
+               if (ident0 != NULL)
+                       vfree(ident0);
+       }
+
+       return 0;
+}
+
+/*
+ * create ID payload for phase 1 and set into iph1->id.
+ * NOT INCLUDING isakmp general header.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_setid1(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *ret = NULL;
+       struct ipsecdoi_id_b id_b;
+       vchar_t *ident = NULL;
+       struct sockaddr *ipid = NULL;
+
+       /* init */
+       id_b.proto_id = 0;
+       id_b.port = 0;
+       ident = NULL;
+
+       switch (iph1->rmconf->idvtype) {
+       case IDTYPE_FQDN:
+               id_b.type = IPSECDOI_ID_FQDN;
+               ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+               break;
+       case IDTYPE_USERFQDN:
+               id_b.type = IPSECDOI_ID_USER_FQDN;
+               ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+               break;
+       case IDTYPE_KEYID:
+#ifdef __APPLE__
+       case IDTYPE_KEYIDUSE:
+#endif
+               id_b.type = IPSECDOI_ID_KEY_ID;
+               ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+               break;
+       case IDTYPE_ASN1DN:
+               id_b.type = IPSECDOI_ID_DER_ASN1_DN;
+               if (iph1->rmconf->idv) {
+                       /* XXX it must be encoded to asn1dn. */
+                       ident = vdup(iph1->rmconf->idv);
+               } else {
+                       if (oakley_getmycert(iph1) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get own CERT.\n");
+                               goto err;
+                       }
+                       ident = eay_get_x509asn1subjectname(&iph1->cert->cert);
+               }
+               break;
+       case IDTYPE_ADDRESS:
+               /*
+                * if the value of the id type was set by the configuration
+                * file, then use it.  otherwise the value is get from local
+                * ip address by using ike negotiation.
+                */
+               if (iph1->rmconf->idv)
+                       ipid = (struct sockaddr *)iph1->rmconf->idv->v;
+               /*FALLTHROUGH*/
+       default:
+           {
+               int l;
+               caddr_t p;
+
+               if (ipid == NULL)
+                       ipid = iph1->local;
+
+               /* use IP address */
+               switch (ipid->sa_family) {
+               case AF_INET:
+                       id_b.type = IPSECDOI_ID_IPV4_ADDR;
+                       l = sizeof(struct in_addr);
+                       p = (caddr_t)&((struct sockaddr_in *)ipid)->sin_addr;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       id_b.type = IPSECDOI_ID_IPV6_ADDR;
+                       l = sizeof(struct in6_addr);
+                       p = (caddr_t)&((struct sockaddr_in6 *)ipid)->sin6_addr;
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid address family.\n");
+                       goto err;
+               }
+               id_b.proto_id = IPPROTO_UDP;
+               id_b.port = htons(PORT_ISAKMP);
+               ident = vmalloc(l);
+               if (!ident) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get ID buffer.\n");
+                       return 0;
+               }
+               memcpy(ident->v, p, ident->l);
+           }
+       }
+       if (!ident) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID buffer.\n");
+               return 0;
+       }
+
+       ret = vmalloc(sizeof(id_b) + ident->l);
+       if (ret == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID buffer.\n");
+               goto err;
+       }
+
+       memcpy(ret->v, &id_b, sizeof(id_b));
+       memcpy(ret->v + sizeof(id_b), ident->v, ident->l);
+
+       iph1->id = ret;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "use ID type of %s\n", s_ipsecdoi_ident(id_b.type));
+       if (ident)
+               vfree(ident);
+       return 0;
+
+err:
+       if (ident)
+               vfree(ident);
+       plog(LLV_ERROR, LOCATION, NULL, "failed get my ID\n");
+       return -1;
+}
+
+static vchar_t *
+getidval(type, val)
+       int type;
+       vchar_t *val;
+{
+       vchar_t *new = NULL;
+
+       if (val)
+               new = vdup(val);
+       else if (lcconf->ident[type])
+               new = vdup(lcconf->ident[type]);
+
+       return new;
+}
+
+/* it's only called by cfparse.y. */
+int
+set_identifier(vpp, type, value)
+       vchar_t **vpp, *value;
+       int type;
+{
+       vchar_t *new = NULL;
+
+       /* simply return if value is null. */
+       if (!value){
+               if( type == IDTYPE_FQDN || type == IDTYPE_USERFQDN){
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "No %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
+                       return -1;
+               }
+               return 0;
+       }
+
+       switch (type) {
+       case IDTYPE_FQDN:
+       case IDTYPE_USERFQDN:
+               if(value->l <= 1){
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "Empty %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
+                       return -1;
+               }
+#ifdef __APPLE__
+       case IDTYPE_KEYIDUSE:
+#endif
+#ifdef ENABLE_HYBRID
+       case IDTYPE_LOGIN:
+#endif
+               /* length is adjusted since QUOTEDSTRING teminates NULL. */
+               new = vmalloc(value->l - 1);
+               if (new == NULL)
+                       return -1;
+               memcpy(new->v, value->v, new->l);
+               break;
+       case IDTYPE_KEYID:
+       {
+               FILE *fp;
+               char b[512];
+               int tlen, len;
+
+               fp = fopen(value->v, "r");
+               if (fp == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "can not open %s\n", value->v);
+                       return -1;
+               }
+               tlen = 0;
+               while ((len = fread(b, 1, sizeof(b), fp)) != 0) {
+                       new = vrealloc(new, tlen + len);
+                       if (!new) {
+                               fclose(fp);
+                               return -1;
+                       }
+                       memcpy(new->v + tlen, b, len);
+                       tlen += len;
+               }
+               break;
+       }
+       case IDTYPE_ADDRESS:
+       {
+               struct sockaddr *sa;
+
+               /* length is adjusted since QUOTEDSTRING teminates NULL. */
+               if (value->l == 0)
+                       break;
+
+               sa = str2saddr(value->v, NULL);
+               if (sa == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid ip address %s\n", value->v);
+                       return -1;
+               }
+
+               new = vmalloc(sysdep_sa_len(sa));
+               if (new == NULL)
+                       return -1;
+               memcpy(new->v, sa, new->l);
+               break;
+       }
+       case IDTYPE_ASN1DN:
+               if (value->v[0] == '~')
+                       /* Hex-encoded ASN1 strings */
+                       new = eay_hex2asn1dn(value->v + 1, - 1);
+               else
+                       /* DN encoded strings */
+                       new = eay_str2asn1dn(value->v, value->l - 1);
+
+               if (new == NULL)
+                       return -1;
+
+               if (loglevel >= LLV_DEBUG) {
+                       X509_NAME *xn;
+                       BIO *bio;
+                       unsigned char *ptr = (unsigned char *) new->v, *buf;
+                       size_t len;
+                       char save;
+
+                       xn = d2i_X509_NAME(NULL, (void *)&ptr, new->l);
+                       bio = BIO_new(BIO_s_mem());
+                       
+                       X509_NAME_print_ex(bio, xn, 0, 0);
+                       len = BIO_get_mem_data(bio, &ptr);
+                       save = ptr[len];
+                       ptr[len] = 0;
+                       plog(LLV_DEBUG, LOCATION, NULL, "Parsed DN: %s\n", ptr);
+                       ptr[len] = save;
+                       X509_NAME_free(xn);
+                       BIO_free(bio);
+               }
+
+               break;
+       }
+
+       *vpp = new;
+
+       return 0;
+}
+
+/*
+ * create ID payload for phase 2, and set into iph2->id and id_p.  There are
+ * NOT INCLUDING isakmp general header.
+ * this function is for initiator.  responder will get to copy from payload.
+ * responder ID type is always address type.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_setid2(iph2)
+       struct ph2handle *iph2;
+{
+       struct secpolicy *sp;
+
+       /* check there is phase 2 handler ? */
+       sp = getspbyspid(iph2->spid);
+       if (sp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no policy found for spid:%u.\n", iph2->spid);
+               return -1;
+       }
+
+       iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src,
+                                       sp->spidx.prefs, sp->spidx.ul_proto);
+       if (iph2->id == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID for %s\n",
+                       spidx2str(&sp->spidx));
+               return -1;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "use local ID type %s\n",
+               s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type));
+
+       /* remote side */
+       iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst,
+                               sp->spidx.prefd, sp->spidx.ul_proto);
+       if (iph2->id_p == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID for %s\n",
+                       spidx2str(&sp->spidx));
+               VPTRINIT(iph2->id);
+               return -1;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "use remote ID type %s\n",
+               s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id_p->v)->type));
+
+       return 0;
+}
+
+/*
+ * set address type of ID.
+ * NOT INCLUDING general header.
+ */
+vchar_t *
+ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto)
+       struct sockaddr *saddr;
+       u_int prefixlen;
+       u_int ul_proto;
+{
+       vchar_t *new;
+       int type, len1, len2;
+       caddr_t sa;
+       u_short port;
+
+       /*
+        * Q. When type is SUBNET, is it allowed to be ::1/128.
+        * A. Yes. (consensus at bake-off)
+        */
+       switch (saddr->sa_family) {
+       case AF_INET:
+               len1 = sizeof(struct in_addr);
+               if (
+#if 0
+                       prefixlen == ~0
+#else
+                       prefixlen == (sizeof(struct in_addr) << 3)
+#endif
+                       ) {
+                       type = IPSECDOI_ID_IPV4_ADDR;
+                       len2 = 0;
+               } else {
+                       type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
+                       len2 = sizeof(struct in_addr);
+               }
+               sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr;
+               port = ((struct sockaddr_in *)(saddr))->sin_port;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               len1 = sizeof(struct in6_addr);
+               if (
+#if 0
+               prefixlen == ~0
+#else
+               prefixlen == (sizeof(struct in6_addr) << 3)
+#endif
+                       ) {
+                       type = IPSECDOI_ID_IPV6_ADDR;
+                       len2 = 0;
+               } else {
+                       type = IPSECDOI_ID_IPV6_ADDR_SUBNET;
+                       len2 = sizeof(struct in6_addr);
+               }
+               sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr;
+               port = ((struct sockaddr_in6 *)(saddr))->sin6_port;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d.\n", saddr->sa_family);
+               return NULL;
+       }
+
+       /* get ID buffer */
+       new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2);
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID buffer.\n");
+               return NULL;
+       }
+
+       memset(new->v, 0, new->l);
+
+       /* set the part of header. */
+       ((struct ipsecdoi_id_b *)new->v)->type = type;
+
+       /* set ul_proto and port */
+       /*
+        * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card
+        * because 0 means port number of 0.  Instead of 0, we use IPSEC_*_ANY.
+        */
+       ((struct ipsecdoi_id_b *)new->v)->proto_id =
+               ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto;
+       ((struct ipsecdoi_id_b *)new->v)->port =
+               port == IPSEC_PORT_ANY ? 0 : port;
+       memcpy(new->v + sizeof(struct ipsecdoi_id_b), sa, len1);
+
+       /* set address */
+
+       /* set prefix */
+       if (len2) {
+               u_char *p = (unsigned char *) new->v + 
+                       sizeof(struct ipsecdoi_id_b) + len1;
+               u_int bits = prefixlen;
+
+               while (bits >= 8) {
+                       *p++ = 0xff;
+                       bits -= 8;
+               }
+
+               if (bits > 0)
+                       *p = ~((1 << (8 - bits)) - 1);
+       }
+
+       return new;
+}
+
+/*
+ * create sockaddr structure from ID payload (buf).
+ * buffers (saddr, prefixlen, ul_proto) must be allocated.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto)
+       vchar_t *buf;
+       struct sockaddr *saddr;
+       u_int8_t *prefixlen;
+       u_int16_t *ul_proto;
+{
+       struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v;
+       u_int plen = 0;
+
+       /*
+        * When a ID payload of subnet type with a IP address of full bit
+        * masked, it has to be processed as host address.
+        * e.g. below 2 type are same.
+        *      type = ipv6 subnet, data = 2001::1/128
+        *      type = ipv6 address, data = 2001::1
+        */
+       switch (id_b->type) {
+       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+#ifndef __linux__
+               saddr->sa_len = sizeof(struct sockaddr_in);
+#endif
+               saddr->sa_family = AF_INET;
+               ((struct sockaddr_in *)saddr)->sin_port =
+                       (id_b->port == 0
+                               ? IPSEC_PORT_ANY
+                               : id_b->port);          /* see sockaddr2id() */
+               memcpy(&((struct sockaddr_in *)saddr)->sin_addr,
+                       buf->v + sizeof(*id_b), sizeof(struct in_addr));
+               break;
+#ifdef INET6
+       case IPSECDOI_ID_IPV6_ADDR:
+       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+#ifndef __linux__
+               saddr->sa_len = sizeof(struct sockaddr_in6);
+#endif
+               saddr->sa_family = AF_INET6;
+               ((struct sockaddr_in6 *)saddr)->sin6_port =
+                       (id_b->port == 0
+                               ? IPSEC_PORT_ANY
+                               : id_b->port);          /* see sockaddr2id() */
+               memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr,
+                       buf->v + sizeof(*id_b), sizeof(struct in6_addr));
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unsupported ID type %d\n", id_b->type);
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+
+       /* get prefix length */
+       switch (id_b->type) {
+       case IPSECDOI_ID_IPV4_ADDR:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+#ifdef INET6
+       case IPSECDOI_ID_IPV6_ADDR:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+#endif
+       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+#ifdef INET6
+       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+#endif
+           {
+               u_char *p;
+               u_int max;
+               int alen = sizeof(struct in_addr);
+
+               switch (id_b->type) {
+               case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+                       alen = sizeof(struct in_addr);
+                       break;
+#ifdef INET6
+               case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+                       alen = sizeof(struct in6_addr);
+                       break;
+#endif
+               }
+
+               /* sanity check */
+               if (buf->l < alen)
+                       return ISAKMP_INTERNAL_ERROR;
+
+               /* get subnet mask length */
+               plen = 0;
+               max = alen <<3;
+
+               p = (unsigned char *) buf->v
+                       + sizeof(struct ipsecdoi_id_b)
+                       + alen;
+
+               for (; *p == 0xff; p++) {
+                       if (plen >= max)
+                               break;
+                       plen += 8;
+               }
+
+               if (plen < max) {
+                       u_int l = 0;
+                       u_char b = ~(*p);
+
+                       while (b) {
+                               b >>= 1;
+                               l++;
+                       }
+
+                       l = 8 - l;
+                       plen += l;
+               }
+           }
+               break;
+       }
+
+       *prefixlen = plen;
+       *ul_proto = id_b->proto_id == 0
+                               ? IPSEC_ULPROTO_ANY
+                               : id_b->proto_id;       /* see sockaddr2id() */
+
+       return 0;
+}
+
+/*
+ * make printable string from ID payload except of general header.
+ */
+const char *
+ipsecdoi_id2str(id)
+       const vchar_t *id;
+{
+       static char buf[256];
+
+       /* XXX */
+       buf[0] = '\0';
+
+       return buf;
+}
+
+/*
+ * set IPsec data attributes into a proposal.
+ * NOTE: MUST called per a transform.
+ */
+int
+ipsecdoi_t2satrns(t, pp, pr, tr)
+       struct isakmp_pl_t *t;
+       struct saprop *pp;
+       struct saproto *pr;
+       struct satrns *tr;
+{
+       struct isakmp_data *d, *prev;
+       int flag, type;
+       int error = -1;
+       int life_t;
+       int tlen;
+
+       tr->trns_no = t->t_no;
+       tr->trns_id = t->t_id;
+
+       tlen = ntohs(t->h.len) - sizeof(*t);
+       prev = (struct isakmp_data *)NULL;
+       d = (struct isakmp_data *)(t + 1);
+
+       /* default */
+       life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
+       pp->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+       pp->lifebyte = 0;
+       tr->authtype = IPSECDOI_ATTR_AUTH_NONE;
+
+       while (tlen > 0) {
+
+               type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+               flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "type=%s, flag=0x%04x, lorv=%s\n",
+                       s_ipsecdoi_attr(type), flag,
+                       s_ipsecdoi_attr_v(type, ntohs(d->lorv)));
+
+               switch (type) {
+               case IPSECDOI_ATTR_SA_LD_TYPE:
+               {
+                       int type = ntohs(d->lorv);
+                       switch (type) {
+                       case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+                       case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+                               life_t = type;
+                               break;
+                       default:
+                               plog(LLV_WARNING, LOCATION, NULL,
+                                       "invalid life duration type. "
+                                       "use default\n");
+                               life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
+                               break;
+                       }
+                       break;
+               }
+               case IPSECDOI_ATTR_SA_LD:
+                       if (prev == NULL
+                        || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
+                                       IPSECDOI_ATTR_SA_LD_TYPE) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "life duration must follow ltype\n");
+                               break;
+                       }
+
+                   {
+                       u_int32_t t;
+                       vchar_t *ld_buf = NULL;
+
+                       if (flag) {
+                               /* i.e. ISAKMP_GEN_TV */
+                               ld_buf = vmalloc(sizeof(d->lorv));
+                               if (ld_buf == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                           "failed to get LD buffer.\n");
+                                       goto end;
+                               }
+                               memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv));
+                       } else {
+                               int len = ntohs(d->lorv);
+                               /* i.e. ISAKMP_GEN_TLV */
+                               ld_buf = vmalloc(len);
+                               if (ld_buf == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                           "failed to get LD buffer.\n");
+                                       goto end;
+                               }
+                               memcpy(ld_buf->v, d + 1, len);
+                       }
+                       switch (life_t) {
+                       case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+                               t = ipsecdoi_set_ld(ld_buf);
+                               vfree(ld_buf);
+                               if (t == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid life duration.\n");
+                                       goto end;
+                               }
+                               /* lifetime must be equal in a proposal. */
+                               if (pp->lifetime == IPSECDOI_ATTR_SA_LD_SEC_DEFAULT)
+                                       pp->lifetime = t;
+                               else if (pp->lifetime != t) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "lifetime mismatched "
+                                               "in a proposal, "
+                                               "prev:%ld curr:%u.\n",
+                                               (long)pp->lifetime, t);
+                                       goto end;
+                               }
+                               break;
+                       case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+                               t = ipsecdoi_set_ld(ld_buf);
+                               vfree(ld_buf);
+                               if (t == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "invalid life duration.\n");
+                                       goto end;
+                               }
+                               /* lifebyte must be equal in a proposal. */
+                               if (pp->lifebyte == 0)
+                                       pp->lifebyte = t;
+                               else if (pp->lifebyte != t) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "lifebyte mismatched "
+                                               "in a proposal, "
+                                               "prev:%d curr:%u.\n",
+                                               pp->lifebyte, t);
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               vfree(ld_buf);
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid life type: %d\n", life_t);
+                               goto end;
+                       }
+                   }
+                       break;
+
+               case IPSECDOI_ATTR_GRP_DESC:
+                       /*
+                        * RFC2407: 4.5 IPSEC Security Association Attributes
+                        *   Specifies the Oakley Group to be used in a PFS QM
+                        *   negotiation.  For a list of supported values, see
+                        *   Appendix A of [IKE].
+                        */
+                       if (pp->pfs_group == 0)
+                               pp->pfs_group = (u_int16_t)ntohs(d->lorv);
+                       else if (pp->pfs_group != (u_int16_t)ntohs(d->lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "pfs_group mismatched "
+                                       "in a proposal.\n");
+                               goto end;
+                       }
+                       break;
+
+               case IPSECDOI_ATTR_ENC_MODE:
+                       if (pr->encmode &&
+                           pr->encmode != (u_int16_t)ntohs(d->lorv)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "multiple encmode exist "
+                                       "in a transform.\n");
+                               goto end;
+                       }
+                       pr->encmode = (u_int16_t)ntohs(d->lorv);
+                       break;
+
+               case IPSECDOI_ATTR_AUTH:
+                       if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "multiple authtype exist "
+                                       "in a transform.\n");
+                               goto end;
+                       }
+                       tr->authtype = (u_int16_t)ntohs(d->lorv);
+                       break;
+
+               case IPSECDOI_ATTR_KEY_LENGTH:
+                       if (pr->proto_id != IPSECDOI_PROTO_IPSEC_ESP) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "key length defined but not ESP");
+                               goto end;
+                       }
+                       tr->encklen = ntohs(d->lorv);
+                       break;
+
+               case IPSECDOI_ATTR_KEY_ROUNDS:
+               case IPSECDOI_ATTR_COMP_DICT_SIZE:
+               case IPSECDOI_ATTR_COMP_PRIVALG:
+               default:
+                       break;
+               }
+
+               prev = d;
+               if (flag) {
+                       tlen -= sizeof(*d);
+                       d = (struct isakmp_data *)((char *)d + sizeof(*d));
+               } else {
+                       tlen -= (sizeof(*d) + ntohs(d->lorv));
+                       d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv));
+               }
+       }
+
+       error = 0;
+end:
+       return error;
+}
+
+int
+ipsecdoi_authalg2trnsid(alg)
+       int alg;
+{
+       switch (alg) {
+        case IPSECDOI_ATTR_AUTH_HMAC_MD5:
+               return IPSECDOI_AH_MD5;
+        case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
+               return IPSECDOI_AH_SHA;
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
+               return IPSECDOI_AH_SHA256;
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
+               return IPSECDOI_AH_SHA384;
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
+               return IPSECDOI_AH_SHA512;
+        case IPSECDOI_ATTR_AUTH_DES_MAC:
+               return IPSECDOI_AH_DES;
+       case IPSECDOI_ATTR_AUTH_KPDK:
+               return IPSECDOI_AH_MD5; /* XXX */
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid authentication algorithm:%d\n", alg);
+       }
+       return -1;
+}
+
+#ifdef HAVE_GSSAPI
+struct isakmpsa *
+fixup_initiator_sa(match, received)
+       struct isakmpsa *match, *received;
+{
+       if (received->gssid != NULL)
+               match->gssid = vdup(received->gssid);
+
+       return match;
+}
+#endif
+
+static int rm_idtype2doi[] = {
+       255,                            /* IDTYPE_UNDEFINED, 0 */
+       IPSECDOI_ID_FQDN,               /* IDTYPE_FQDN, 1 */
+       IPSECDOI_ID_USER_FQDN,          /* IDTYPE_USERFQDN, 2 */
+       IPSECDOI_ID_KEY_ID,             /* IDTYPE_KEYID, 3 */
+       255,    /*                         IDTYPE_ADDRESS, 4 
+                * it expands into 4 types by another function. */
+       IPSECDOI_ID_DER_ASN1_DN,        /* IDTYPE_ASN1DN, 5 */
+#ifdef ENABLE_HYBRID
+       255,                            /* IDTYPE_LOGIN, 6 */
+#endif
+};
+
+/*
+ * convert idtype to DOI value.
+ * OUT 255  : NG
+ *     other: converted.
+ */
+int
+idtype2doi(idtype)
+       int idtype;
+{
+       if (ARRAYLEN(rm_idtype2doi) > idtype)
+               return rm_idtype2doi[idtype];
+       return 255;
+}
+
+int
+doi2idtype(doi)
+       int doi;
+{
+       switch(doi) {
+       case IPSECDOI_ID_FQDN:
+               return(IDTYPE_FQDN);
+       case IPSECDOI_ID_USER_FQDN:
+               return(IDTYPE_USERFQDN);
+       case IPSECDOI_ID_KEY_ID:
+               return(IDTYPE_KEYID);
+       case IPSECDOI_ID_DER_ASN1_DN:
+               return(IDTYPE_ASN1DN);
+       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+       case IPSECDOI_ID_IPV6_ADDR:
+       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+               return(IDTYPE_ADDRESS);
+       default:
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "Inproper idtype:%s in this function.\n",
+                       s_ipsecdoi_ident(doi));
+               return(IDTYPE_ADDRESS); /* XXX */
+       }
+       /*NOTREACHED*/
+}
+
+#ifdef ENABLE_HYBRID
+static int
+switch_authmethod(authmethod)
+       int authmethod;
+{
+       switch(authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I;
+               break;
+       /* Those are not implemented */
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
+               authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I;
+               break;
+       default:
+               break;
+       }
+
+       return authmethod;
+}
+#endif
diff --git a/ipsec-tools/racoon/ipsec_doi.h b/ipsec-tools/racoon/ipsec_doi.h
new file mode 100644 (file)
index 0000000..9d5e7a9
--- /dev/null
@@ -0,0 +1,249 @@
+/* $Id: ipsec_doi.h,v 1.9.2.2 2005/10/17 16:23:50 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IPSEC_DOI_H
+#define _IPSEC_DOI_H
+
+/* refered to RFC2407 */
+
+#define IPSEC_DOI 1
+
+/* 4.2 IPSEC Situation Definition */
+#define IPSECDOI_SIT_IDENTITY_ONLY           0x00000001
+#define IPSECDOI_SIT_SECRECY                 0x00000002
+#define IPSECDOI_SIT_INTEGRITY               0x00000004
+
+/* 4.4.1 IPSEC Security Protocol Identifiers */
+  /* 4.4.2 IPSEC ISAKMP Transform Values */
+#define IPSECDOI_PROTO_ISAKMP                        1
+#define   IPSECDOI_KEY_IKE                             1
+
+/* 4.4.1 IPSEC Security Protocol Identifiers */
+#define IPSECDOI_PROTO_IPSEC_AH                      2
+  /* 4.4.3 IPSEC AH Transform Values */
+#define   IPSECDOI_AH_MD5                              2
+#define   IPSECDOI_AH_SHA                              3
+#define   IPSECDOI_AH_DES                              4
+#define   IPSECDOI_AH_SHA256                           5
+#define   IPSECDOI_AH_SHA384                           6
+#define   IPSECDOI_AH_SHA512                           7
+
+/* 4.4.1 IPSEC Security Protocol Identifiers */
+#define IPSECDOI_PROTO_IPSEC_ESP                     3
+  /* 4.4.4 IPSEC ESP Transform Identifiers */
+#define   IPSECDOI_ESP_DES_IV64                                1
+#define   IPSECDOI_ESP_DES                             2
+#define   IPSECDOI_ESP_3DES                            3
+#define   IPSECDOI_ESP_RC5                             4
+#define   IPSECDOI_ESP_IDEA                            5
+#define   IPSECDOI_ESP_CAST                            6
+#define   IPSECDOI_ESP_BLOWFISH                                7
+#define   IPSECDOI_ESP_3IDEA                           8
+#define   IPSECDOI_ESP_DES_IV32                                9
+#define   IPSECDOI_ESP_RC4                             10
+#define   IPSECDOI_ESP_NULL                            11
+#define   IPSECDOI_ESP_AES                             12
+#if 1
+  /* draft-ietf-ipsec-ciph-aes-cbc-00.txt */
+#define   IPSECDOI_ESP_TWOFISH                         253
+#else
+  /* SSH uses these value for now */
+#define   IPSECDOI_ESP_TWOFISH                         250
+#endif
+
+/* 4.4.1 IPSEC Security Protocol Identifiers */
+#define IPSECDOI_PROTO_IPCOMP                        4
+  /* 4.4.5 IPSEC IPCOMP Transform Identifiers */
+#define   IPSECDOI_IPCOMP_OUI                          1
+#define   IPSECDOI_IPCOMP_DEFLATE                      2
+#define   IPSECDOI_IPCOMP_LZS                          3
+
+/* 4.5 IPSEC Security Association Attributes */
+/* NOTE: default value is not included in a packet. */
+#define IPSECDOI_ATTR_SA_LD_TYPE              1 /* B */
+#define   IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT      1
+#define   IPSECDOI_ATTR_SA_LD_TYPE_SEC          1
+#define   IPSECDOI_ATTR_SA_LD_TYPE_KB           2
+#define   IPSECDOI_ATTR_SA_LD_TYPE_MAX          3
+#define IPSECDOI_ATTR_SA_LD                   2 /* V */
+#define   IPSECDOI_ATTR_SA_LD_SEC_DEFAULT      28800 /* 8 hours */
+#define   IPSECDOI_ATTR_SA_LD_KB_MAX  (~(1 << ((sizeof(int) << 3) - 1)))
+#define IPSECDOI_ATTR_GRP_DESC                3 /* B */
+#define IPSECDOI_ATTR_ENC_MODE                4 /* B */
+       /* default value: host dependent */
+#define   IPSECDOI_ATTR_ENC_MODE_ANY            0      /* NOTE:internal use */
+#define   IPSECDOI_ATTR_ENC_MODE_TUNNEL         1
+#define   IPSECDOI_ATTR_ENC_MODE_TRNS           2
+
+/* NAT-T draft-ietf-ipsec-nat-t-ike-05 and later */
+#define   IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC 3
+#define   IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC   4
+
+/* NAT-T up to draft-ietf-ipsec-nat-t-ike-04 */
+#define   IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT       61443
+#define   IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT         61444
+
+#define IPSECDOI_ATTR_AUTH                    5 /* B */
+       /* 0 means not to use authentication. */
+#define   IPSECDOI_ATTR_AUTH_HMAC_MD5           1
+#define   IPSECDOI_ATTR_AUTH_HMAC_SHA1          2
+#define   IPSECDOI_ATTR_AUTH_DES_MAC            3
+#define   IPSECDOI_ATTR_AUTH_KPDK               4 /*RFC-1826(Key/Pad/Data/Key)*/
+#define   IPSECDOI_ATTR_AUTH_HMAC_SHA2_256      5
+#define   IPSECDOI_ATTR_AUTH_HMAC_SHA2_384      6
+#define   IPSECDOI_ATTR_AUTH_HMAC_SHA2_512      7
+#define   IPSECDOI_ATTR_AUTH_NONE               254    /* NOTE:internal use */
+       /*
+        * When negotiating ESP without authentication, the Auth
+        * Algorithm attribute MUST NOT be included in the proposal.
+        * When negotiating ESP without confidentiality, the Auth
+        * Algorithm attribute MUST be included in the proposal and
+        * the ESP transform ID must be ESP_NULL.
+       */
+#define IPSECDOI_ATTR_KEY_LENGTH              6 /* B */
+#define IPSECDOI_ATTR_KEY_ROUNDS              7 /* B */
+#define IPSECDOI_ATTR_COMP_DICT_SIZE          8 /* B */
+#define IPSECDOI_ATTR_COMP_PRIVALG            9 /* V */
+
+/* 4.6.1 Security Association Payload */
+struct ipsecdoi_pl_sa {
+       struct isakmp_gen h;
+       struct ipsecdoi_sa_b {
+               u_int32_t doi; /* Domain of Interpretation */
+               u_int32_t sit; /* Situation */
+       } b;
+       /* followed by Leveled Domain Identifier and so on. */
+} __attribute__((__packed__));
+
+struct ipsecdoi_secrecy_h {
+       u_int16_t len;
+       u_int16_t reserved;
+       /* followed by the value */
+} __attribute__((__packed__));
+
+/* 4.6.2 Identification Payload Content */
+struct ipsecdoi_pl_id {
+       struct isakmp_gen h;
+       struct ipsecdoi_id_b {
+               u_int8_t type;          /* ID Type */
+               u_int8_t proto_id;      /* Protocol ID */
+               u_int16_t port;         /* Port */
+       } b;
+       /* followed by Identification Data */
+} __attribute__((__packed__));
+
+#define IPSECDOI_ID_IPV4_ADDR                        1
+#define IPSECDOI_ID_FQDN                             2
+#define IPSECDOI_ID_USER_FQDN                        3
+#define IPSECDOI_ID_IPV4_ADDR_SUBNET                 4
+#define IPSECDOI_ID_IPV6_ADDR                        5
+#define IPSECDOI_ID_IPV6_ADDR_SUBNET                 6
+#define IPSECDOI_ID_IPV4_ADDR_RANGE                  7
+#define IPSECDOI_ID_IPV6_ADDR_RANGE                  8
+#define IPSECDOI_ID_DER_ASN1_DN                      9
+#define IPSECDOI_ID_DER_ASN1_GN                      10
+#define IPSECDOI_ID_KEY_ID                           11
+
+/* compressing doi type, it's internal use. */
+#define IDTYPE_UNDEFINED       0
+#define IDTYPE_FQDN            1
+#define IDTYPE_USERFQDN                2
+#define IDTYPE_KEYID           3
+#define IDTYPE_ADDRESS         4
+#define IDTYPE_ASN1DN          5
+#define IDTYPE_LOGIN           6
+#define IDTYPE_SUBNET          7
+#ifdef __APPLE__
+#define IDTYPE_KEYIDUSE     8
+
+/* shared secret type, it's internal use. */
+#define SECRETTYPE_USE                         0
+#define SECRETTYPE_KEY                         1
+#define SECRETTYPE_KEYCHAIN                    2
+#define SECRETTYPE_KEYCHAIN_BY_ID      3
+
+/* verification modules */
+#define VERIFICATION_MODULE_OPENSSL                    0
+#define VERIFICATION_MODULE_SEC_FRAMEWORK      1
+
+/* verification options */
+#define VERIFICATION_OPTION_NONE                               0
+#define VERIFICATION_OPTION_PEERS_IDENTIFIER   1
+#define VERIFICATION_OPTION_OPEN_DIR                   2
+#endif
+
+/* The use for checking proposal payload. This is not exchange type. */
+#define IPSECDOI_TYPE_PH1      0
+#define IPSECDOI_TYPE_PH2      1
+
+struct isakmpsa;
+struct ipsecdoi_pl_sa;
+struct saprop;
+struct saproto;
+struct satrns;
+struct prop_pair;
+
+extern int ipsecdoi_checkph1proposal __P((vchar_t *, struct ph1handle *));
+extern int ipsecdoi_selectph2proposal __P((struct ph2handle *));
+extern int ipsecdoi_checkph2proposal __P((struct ph2handle *));
+
+extern struct prop_pair **get_proppair __P((vchar_t *, int));
+extern vchar_t *get_sabyproppair __P((struct prop_pair *, struct ph1handle *));
+extern int ipsecdoi_updatespi __P((struct ph2handle *iph2));
+extern vchar_t *get_sabysaprop __P((struct saprop *, vchar_t *));
+extern int ipsecdoi_checkid1 __P((struct ph1handle *));
+extern int ipsecdoi_setid1 __P((struct ph1handle *));
+extern int set_identifier __P((vchar_t **, int, vchar_t *));
+extern int ipsecdoi_setid2 __P((struct ph2handle *));
+extern vchar_t *ipsecdoi_sockaddr2id __P((struct sockaddr *, u_int, u_int));
+extern int ipsecdoi_id2sockaddr __P((vchar_t *, struct sockaddr *,
+       u_int8_t *, u_int16_t *));
+extern const char *ipsecdoi_id2str __P((const vchar_t *));
+
+extern vchar_t *ipsecdoi_setph1proposal __P((struct isakmpsa *));
+extern int ipsecdoi_setph2proposal __P((struct ph2handle *));
+extern int ipsecdoi_transportmode __P((struct saprop *));
+#ifdef __APPLE__
+extern int ipsecdoi_tunnelmode __P((struct ph2handle *));
+#endif
+extern int ipsecdoi_get_defaultlifetime __P((void));
+extern int ipsecdoi_checkalgtypes __P((int, int, int, int));
+extern int ipproto2doi __P((int));
+extern int doi2ipproto __P((int));
+
+extern int ipsecdoi_t2satrns __P((struct isakmp_pl_t *,
+       struct saprop *, struct saproto *, struct satrns *));
+extern int ipsecdoi_authalg2trnsid __P((int));
+extern int idtype2doi __P((int));
+extern int doi2idtype __P((int));
+
+
+#endif /* _IPSEC_DOI_H */
diff --git a/ipsec-tools/racoon/isakmp.c b/ipsec-tools/racoon/isakmp.c
new file mode 100644 (file)
index 0000000..5fa5e07
--- /dev/null
@@ -0,0 +1,3633 @@
+/* $Id: isakmp.c,v 1.34.2.21 2006/02/02 10:31:01 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifdef __APPLE__
+#define __APPLE_API_PRIVATE
+#endif
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else 
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "remoteconf.h"
+#include "localconf.h"
+#include "grabmyaddr.h"
+#include "admin.h"
+#include "privsep.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "evt.h"
+#include "handler.h"
+#include "proposal.h"
+#include "ipsec_doi.h"
+#include "pfkey.h"
+#include "crypto_openssl.h"
+#include "policy.h"
+#include "isakmp_ident.h"
+#include "isakmp_agg.h"
+#include "isakmp_base.h"
+#include "isakmp_quick.h"
+#include "isakmp_inf.h"
+#include "isakmp_newg.h"
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
+#ifdef ENABLE_FRAG
+#include "isakmp_frag.h"
+#endif
+#include "strnames.h"
+
+#ifdef ENABLE_NATT
+# include "nattraversal.h"
+# ifdef __linux__
+#  include <linux/udp.h>
+#include <fcntl.h>
+
+#  ifndef SOL_UDP
+#   define SOL_UDP 17
+#  endif
+# endif /* __linux__ */
+# if defined(__NetBSD__) || defined(__FreeBSD__)
+#  include <netinet/in.h>
+#  include <netinet/udp.h>
+#  define SOL_UDP IPPROTO_UDP
+# endif /* __NetBSD__ / __FreeBSD__ */
+#endif
+
+static int nostate1 __P((struct ph1handle *, vchar_t *));
+static int nostate2 __P((struct ph2handle *, vchar_t *));
+
+extern caddr_t val2str(const char *, size_t);
+
+static int (*ph1exchange[][2][PHASE1ST_MAX])
+       __P((struct ph1handle *, vchar_t *)) = {
+ /* error */
+ { {}, {}, },
+ /* Identity Protection exchange */
+ {
+  { nostate1, ident_i1send, nostate1, ident_i2recv, ident_i2send,
+    ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, },
+  { nostate1, ident_r1recv, ident_r1send, ident_r2recv, ident_r2send,
+    ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, },
+ },
+ /* Aggressive exchange */
+ {
+  { nostate1, agg_i1send, nostate1, agg_i2recv, agg_i2send,
+    nostate1, nostate1, nostate1, nostate1, nostate1, },
+  { nostate1, agg_r1recv, agg_r1send, agg_r2recv, agg_r2send,
+    nostate1, nostate1, nostate1, nostate1, nostate1, },
+ },
+ /* Base exchange */
+ {
+  { nostate1, base_i1send, nostate1, base_i2recv, base_i2send,
+    base_i3recv, base_i3send, nostate1, nostate1, nostate1, },
+  { nostate1, base_r1recv, base_r1send, base_r2recv, base_r2send,
+    nostate1, nostate1, nostate1, nostate1, nostate1, },
+ },
+};
+
+static int (*ph2exchange[][2][PHASE2ST_MAX])
+       __P((struct ph2handle *, vchar_t *)) = {
+ /* error */
+ { {}, {}, },
+ /* Quick mode for IKE*/
+ {
+  { nostate2, nostate2, quick_i1prep, nostate2, quick_i1send,
+    quick_i2recv, quick_i2send, quick_i3recv, nostate2, nostate2, },
+  { nostate2, quick_r1recv, quick_r1prep, nostate2, quick_r2send,
+    quick_r3recv, quick_r3prep, quick_r3send, nostate2, nostate2, }
+ },
+};
+
+static u_char r_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the r_ck. */
+static int isakmp_main __P((vchar_t *, struct sockaddr *, struct sockaddr *));
+static int ph1_main __P((struct ph1handle *, vchar_t *));
+static int quick_main __P((struct ph2handle *, vchar_t *));
+static int isakmp_ph1begin_r __P((vchar_t *,
+       struct sockaddr *, struct sockaddr *, u_int8_t));
+static int isakmp_ph2begin_i __P((struct ph1handle *, struct ph2handle *));
+static int isakmp_ph2begin_r __P((struct ph1handle *, vchar_t *));
+static int etypesw1 __P((int));
+static int etypesw2 __P((int));
+#ifdef ENABLE_FRAG
+static int frag_handler(struct ph1handle *, 
+    vchar_t *, struct sockaddr *, struct sockaddr *);
+#endif
+
+/*
+ * isakmp packet handler
+ */
+int
+isakmp_handler(so_isakmp)
+       int so_isakmp;
+{
+       struct isakmp isakmp;
+       union {
+               char            buf[sizeof (isakmp) + 4];
+               u_int32_t       non_esp[2];
+       } x;
+       struct sockaddr_storage remote;
+       struct sockaddr_storage local;
+       unsigned int remote_len = sizeof(remote);
+       unsigned int local_len = sizeof(local);
+       int len = 0, extralen = 0;
+       u_short port;
+       vchar_t *buf = NULL, *tmpbuf = NULL;
+       int error = -1;
+
+       /* read message by MSG_PEEK */
+       while ((len = recvfromto(so_isakmp, x.buf, sizeof(x),
+                   MSG_PEEK, (struct sockaddr *)&remote, &remote_len,
+                   (struct sockaddr *)&local, &local_len)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to receive isakmp packet: %s\n",
+                       strerror (errno));
+               goto end;
+       }
+
+       /* keep-alive packet - ignore */
+       if (len == 1 && (x.buf[0]&0xff) == 0xff) {
+               /* Pull the keep-alive packet */
+               if ((len = recvfrom(so_isakmp, (char *)x.buf, 1,
+                   0, (struct sockaddr *)&remote, &remote_len)) != 1) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "failed to receive keep alive packet: %s\n",
+                           strerror (errno));
+               }
+               goto end;
+       }
+
+#ifdef ENABLE_NATT
+       /* we don't know about portchange yet, 
+          look for non-esp marker instead */
+       if (x.non_esp[0] == 0 && x.non_esp[1] != 0)
+               extralen = NON_ESP_MARKER_LEN;
+#endif
+
+       /* now we know if there is an extra non-esp 
+          marker at the beginning or not */
+       memcpy ((char *)&isakmp, x.buf + extralen, sizeof (isakmp));
+
+       /* check isakmp header length, as well as sanity of header length */
+       if (len < sizeof(isakmp) || ntohl(isakmp.len) < sizeof(isakmp)) {
+               plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
+                       "packet shorter than isakmp header size (%u, %u, %zu)\n",
+                       len, ntohl(isakmp.len), sizeof(isakmp));
+               /* dummy receive */
+               if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
+                           0, (struct sockaddr *)&remote, &remote_len)) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to receive isakmp packet: %s\n",
+                               strerror (errno));
+               }
+               goto end;
+       }
+
+       /* reject it if the size is tooooo big. */
+       if (ntohl(isakmp.len) > 0xffff) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "the length in the isakmp header is too big.\n");
+               if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
+                           0, (struct sockaddr *)&remote, &remote_len)) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to receive isakmp packet: %s\n",
+                               strerror (errno));
+               }
+               goto end;
+       }
+
+       /* read real message */
+       if ((tmpbuf = vmalloc(ntohl(isakmp.len) + extralen)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate reading buffer (%u Bytes)\n",
+                       ntohl(isakmp.len) + extralen);
+               /* dummy receive */
+               if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
+                           0, (struct sockaddr *)&remote, &remote_len)) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to receive isakmp packet: %s\n", 
+                               strerror (errno));
+#ifdef __APPLE__
+                               error = -2;    /* serious problem with socket */
+#endif
+               }
+               goto end;
+       }
+
+       while ((len = recvfromto(so_isakmp, (char *)tmpbuf->v, tmpbuf->l,
+                           0, (struct sockaddr *)&remote, &remote_len,
+                           (struct sockaddr *)&local, &local_len)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to receive isakmp packet: %s\n",
+                       strerror (errno));
+               goto end;
+       }
+
+       if ((buf = vmalloc(len - extralen)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate reading buffer (%u Bytes)\n",
+                       (len - extralen));
+               goto end;
+       }
+       
+       memcpy (buf->v, tmpbuf->v + extralen, buf->l);
+
+       vfree (tmpbuf);
+
+       len -= extralen;
+       
+       if (len != buf->l) {
+               plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
+                       "received invalid length (%d != %zu), why ?\n",
+                       len, buf->l);
+               goto end;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "%d bytes message received %s\n",
+               len, saddr2str_fromto("from %s to %s", 
+                       (struct sockaddr *)&remote,
+                       (struct sockaddr *)&local));
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* avoid packets with malicious port/address */
+       switch (remote.ss_family) {
+       case AF_INET:
+               port = ((struct sockaddr_in *)&remote)->sin_port;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               port = ((struct sockaddr_in6 *)&remote)->sin6_port;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", remote.ss_family);
+               goto end;
+       }
+       if (port == 0) {
+               plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
+                       "src port == 0 (valid as UDP but not with IKE)\n");
+               goto end;
+       }
+
+       /* XXX: check sender whether to be allowed or not to accept */
+
+       /* XXX: I don't know how to check isakmp half connection attack. */
+
+       /* simply reply if the packet was processed. */
+       if (check_recvdpkt((struct sockaddr *)&remote,
+                       (struct sockaddr *)&local, buf)) {
+               plog(LLV_NOTIFY, LOCATION, NULL,
+                       "the packet is retransmitted by %s.\n",
+                       saddr2str((struct sockaddr *)&remote));
+               error = 0;
+               goto end;
+       }
+
+       /* isakmp main routine */
+       if (isakmp_main(buf, (struct sockaddr *)&remote,
+                       (struct sockaddr *)&local) != 0) goto end;
+
+       error = 0;
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+
+       return(error);
+}
+
+/*
+ * main processing to handle isakmp payload
+ */
+static int
+isakmp_main(msg, remote, local)
+       vchar_t *msg;
+       struct sockaddr *remote, *local;
+{
+       struct isakmp *isakmp = (struct isakmp *)msg->v;
+       isakmp_index *index = (isakmp_index *)isakmp;
+       u_int32_t msgid = isakmp->msgid;
+       struct ph1handle *iph1;
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(msg, remote, local, 0);
+#endif
+
+       /* the initiator's cookie must not be zero */
+       if (memcmp(&isakmp->i_ck, r_ck0, sizeof(cookie_t)) == 0) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "malformed cookie received.\n");
+               return -1;
+       }
+
+       /* Check the Major and Minor Version fields. */
+       /*
+        * XXX Is is right to check version here ?
+        * I think it may no be here because the version depends
+        * on exchange status.
+        */
+       if (isakmp->v < ISAKMP_VERSION_NUMBER) {
+               if (ISAKMP_GETMAJORV(isakmp->v) < ISAKMP_MAJOR_VERSION) {
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "invalid major version %d.\n",
+                               ISAKMP_GETMAJORV(isakmp->v));
+                       return -1;
+               }
+#if ISAKMP_MINOR_VERSION > 0
+               if (ISAKMP_GETMINORV(isakmp->v) < ISAKMP_MINOR_VERSION) {
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "invalid minor version %d.\n",
+                               ISAKMP_GETMINORV(isakmp->v));
+                       return -1;
+               }
+#endif
+       }
+
+       /* check the Flags field. */
+       /* XXX How is the exclusive check, E and A ? */
+       if (isakmp->flags & ~(ISAKMP_FLAG_E | ISAKMP_FLAG_C | ISAKMP_FLAG_A)) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "invalid flag 0x%02x.\n", isakmp->flags);
+               return -1;
+       }
+
+       /* ignore commit bit. */
+       if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) {
+               if (isakmp->msgid == 0) {
+                       isakmp_info_send_nx(isakmp, remote, local,
+                               ISAKMP_NTYPE_INVALID_FLAGS, NULL);
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "Commit bit on phase1 forbidden.\n");
+                       return -1;
+               }
+       }
+
+       iph1 = getph1byindex(index);
+       if (iph1 != NULL) {
+               /* validity check */
+               if (memcmp(&isakmp->r_ck, r_ck0, sizeof(cookie_t)) == 0 &&
+                   iph1->side == INITIATOR) {
+                       plog(LLV_DEBUG, LOCATION, remote,
+                               "malformed cookie received or "
+                               "the initiator's cookies collide.\n");
+                       return -1;
+               }
+
+#ifdef ENABLE_NATT
+               /* Floating ports for NAT-T */
+               if (NATT_AVAILABLE(iph1) &&
+                   ! (iph1->natt_flags & NAT_PORTS_CHANGED) &&
+                   ((cmpsaddrstrict(iph1->remote, remote) != 0) ||
+                   (cmpsaddrstrict(iph1->local, local) != 0)))
+               {
+                       /* prevent memory leak */
+                       racoon_free(iph1->remote);
+                       racoon_free(iph1->local);
+
+                       /* copy-in new addresses */
+                       iph1->remote = dupsaddr(remote);
+                       iph1->local = dupsaddr(local);
+
+                       /* set the flag to prevent further port floating
+                          (FIXME: should we allow it? E.g. when the NAT gw 
+                           is rebooted?) */
+                       iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER;
+                       
+                       /* print some neat info */
+                       plog (LLV_INFO, LOCATION, NULL, 
+                             "NAT-T: ports changed to: %s\n",
+                             saddr2str_fromto ("%s<->%s", iph1->remote, iph1->local));
+#ifndef __APPLE__
+                       natt_keepalive_add_ph1 (iph1);
+#endif
+               }
+#endif
+
+               /* must be same addresses in one stream of a phase at least. */
+               if (cmpsaddrstrict(iph1->remote, remote) != 0) {
+                       char *saddr_db, *saddr_act;
+
+                       saddr_db = strdup(saddr2str(iph1->remote));
+                       saddr_act = strdup(saddr2str(remote));
+
+                       plog(LLV_WARNING, LOCATION, remote,
+                               "remote address mismatched. db=%s, act=%s\n",
+                               saddr_db, saddr_act);
+
+                       racoon_free(saddr_db);
+                       racoon_free(saddr_act);
+               }
+
+               /*
+                * don't check of exchange type here because other type will be
+                * with same index, for example, informational exchange.
+                */
+
+               /* XXX more acceptable check */
+       }
+
+       switch (isakmp->etype) {
+       case ISAKMP_ETYPE_IDENT:
+       case ISAKMP_ETYPE_AGG:
+       case ISAKMP_ETYPE_BASE:
+               /* phase 1 validity check */
+               if (isakmp->msgid != 0) {
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "message id should be zero in phase1.\n");
+                       return -1;
+               }
+
+               /* search for isakmp status record of phase 1 */
+               if (iph1 == NULL) {
+                       /*
+                        * the packet must be the 1st message from a initiator
+                        * or the 2nd message from the responder.
+                        */
+
+                       /* search for phase1 handle by index without r_ck */
+                       iph1 = getph1byindex0(index);
+                       if (iph1 == NULL) {
+                               /*it must be the 1st message from a initiator.*/
+                               if (memcmp(&isakmp->r_ck, r_ck0,
+                                       sizeof(cookie_t)) != 0) {
+
+                                       plog(LLV_DEBUG, LOCATION, remote,
+                                               "malformed cookie received "
+                                               "or the spi expired.\n");
+                                       return -1;
+                               }
+
+                               /* it must be responder's 1st exchange. */
+                               if (isakmp_ph1begin_r(msg, remote, local,
+                                       isakmp->etype) < 0)
+                                       return -1;
+                               break;
+
+                               /*NOTREACHED*/
+                       }
+
+                       /* it must be the 2nd message from the responder. */
+                       if (iph1->side != INITIATOR) {
+                               plog(LLV_DEBUG, LOCATION, remote,
+                                       "malformed cookie received. "
+                                       "it has to be as the initiator.  %s\n",
+                                       isakmp_pindex(&iph1->index, 0));
+                               return -1;
+                       }
+               }
+
+               /*
+                * Don't delete phase 1 handler when the exchange type
+                * in handler is not equal to packet's one because of no
+                * authencication completed.
+                */
+               if (iph1->etype != isakmp->etype) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "exchange type is mismatched: "
+                               "db=%s packet=%s, ignore it.\n",
+                               s_isakmp_etype(iph1->etype),
+                               s_isakmp_etype(isakmp->etype));
+                       return -1;
+               }
+
+#ifdef ENABLE_FRAG
+               if (isakmp->np == ISAKMP_NPTYPE_FRAG)
+                       return frag_handler(iph1, msg, remote, local);
+#endif
+
+               /* call main process of phase 1 */
+               if (ph1_main(iph1, msg) < 0) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "phase1 negotiation failed.\n");
+                       remph1(iph1);
+                       delph1(iph1);
+                       return -1;
+               }
+               break;
+
+       case ISAKMP_ETYPE_AUTH:
+               plog(LLV_INFO, LOCATION, remote,
+                       "unsupported exchange %d received.\n",
+                       isakmp->etype);
+               break;
+
+       case ISAKMP_ETYPE_INFO:
+       case ISAKMP_ETYPE_ACKINFO:
+               /*
+                * iph1 must be present for Information message.
+                * if iph1 is null then trying to get the phase1 status
+                * as the packet from responder againt initiator's 1st
+                * exchange in phase 1.
+                * NOTE: We think such informational exchange should be ignored.
+                */
+               if (iph1 == NULL) {
+                       iph1 = getph1byindex0(index);
+                       if (iph1 == NULL) {
+                               plog(LLV_ERROR, LOCATION, remote,
+                                       "unknown Informational "
+                                       "exchange received.\n");
+                               return -1;
+                       }
+                       if (cmpsaddrstrict(iph1->remote, remote) != 0) {
+                               plog(LLV_WARNING, LOCATION, remote,
+                                       "remote address mismatched. "
+                                       "db=%s\n",
+                                       saddr2str(iph1->remote));
+                       }
+               }
+
+#ifdef ENABLE_FRAG
+               if (isakmp->np == ISAKMP_NPTYPE_FRAG)
+                       return frag_handler(iph1, msg, remote, local);
+#endif
+
+               if (isakmp_info_recv(iph1, msg) < 0)
+                       return -1;
+               break;
+
+       case ISAKMP_ETYPE_QUICK:
+       {
+               struct ph2handle *iph2;
+
+               if (iph1 == NULL) {
+                       isakmp_info_send_nx(isakmp, remote, local,
+                               ISAKMP_NTYPE_INVALID_COOKIE, NULL);
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "can't start the quick mode, "
+                               "there is no ISAKMP-SA, %s\n",
+                               isakmp_pindex((isakmp_index *)&isakmp->i_ck,
+                                       isakmp->msgid));
+                       return -1;
+               }
+
+#ifdef ENABLE_FRAG
+               if (isakmp->np == ISAKMP_NPTYPE_FRAG)
+                       return frag_handler(iph1, msg, remote, local);
+#endif
+
+               /* check status of phase 1 whether negotiated or not. */
+               if (iph1->status != PHASE1ST_ESTABLISHED) {
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "can't start the quick mode, "
+                               "there is no valid ISAKMP-SA, %s\n",
+                               isakmp_pindex(&iph1->index, iph1->msgid));
+                       return -1;
+               }
+
+               /* search isakmp phase 2 stauts record. */
+               iph2 = getph2bymsgid(iph1, msgid);
+               if (iph2 == NULL) {
+                       /* it must be new negotiation as responder */
+                       if (isakmp_ph2begin_r(iph1, msg) < 0)
+                               return -1;
+                       return 0;
+                       /*NOTREACHED*/
+               }
+
+               /* commit bit. */
+               /* XXX
+                * we keep to set commit bit during negotiation.
+                * When SA is configured, bit will be reset.
+                * XXX
+                * don't initiate commit bit.  should be fixed in the future.
+                */
+               if (ISSET(isakmp->flags, ISAKMP_FLAG_C))
+                       iph2->flags |= ISAKMP_FLAG_C;
+
+               /* call main process of quick mode */
+               if (quick_main(iph2, msg) < 0) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "phase2 negotiation failed.\n");
+                       unbindph12(iph2);
+                       remph2(iph2);
+                       delph2(iph2);
+                       return -1;
+               }
+       }
+               break;
+
+       case ISAKMP_ETYPE_NEWGRP:
+               if (iph1 == NULL) {
+                       plog(LLV_ERROR, LOCATION, remote,
+                               "Unknown new group mode exchange, "
+                               "there is no ISAKMP-SA.\n");
+                       return -1;
+               }
+
+#ifdef ENABLE_FRAG
+               if (isakmp->np == ISAKMP_NPTYPE_FRAG)
+                       return frag_handler(iph1, msg, remote, local);
+#endif
+
+               isakmp_newgroup_r(iph1, msg);
+               break;
+
+#ifdef ENABLE_HYBRID
+       case ISAKMP_ETYPE_CFG:
+               if (iph1 == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "mode config %d from %s, "
+                            "but we have no ISAKMP-SA.\n",
+                            isakmp->etype, saddr2str(remote));
+                       return -1;
+               }
+
+#ifdef ENABLE_FRAG
+               if (isakmp->np == ISAKMP_NPTYPE_FRAG)
+                       return frag_handler(iph1, msg, remote, local);
+#endif
+
+               isakmp_cfg_r(iph1, msg);
+               break;
+#endif  
+
+       case ISAKMP_ETYPE_NONE:
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid exchange type %d from %s.\n",
+                       isakmp->etype, saddr2str(remote));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * main function of phase 1.
+ */
+static int
+ph1_main(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       /* ignore a packet */
+       if (iph1->status == PHASE1ST_ESTABLISHED)
+               return 0;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+       /* receive */
+       if (ph1exchange[etypesw1(iph1->etype)]
+                      [iph1->side]
+                      [iph1->status] == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "why isn't the function defined.\n");
+               return -1;
+       }
+       error = (ph1exchange[etypesw1(iph1->etype)]
+                           [iph1->side]
+                           [iph1->status])(iph1, msg);
+       if (error != 0) {
+#if 0
+               /* XXX
+                * When an invalid packet is received on phase1, it should
+                * be selected to process this packet.  That is to respond
+                * with a notify and delete phase 1 handler, OR not to respond
+                * and keep phase 1 handler.
+                */
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to pre-process packet.\n");
+               return -1;
+#else
+               /* ignore the error and keep phase 1 handler */
+               return 0;
+#endif
+       }
+
+       /* free resend buffer */
+       if (iph1->sendbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no buffer found as sendbuf\n"); 
+               return -1;
+       }
+       VPTRINIT(iph1->sendbuf);
+
+       /* turn off schedule */
+       if (iph1->scr)
+               SCHED_KILL(iph1->scr);
+
+       /* send */
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       if ((ph1exchange[etypesw1(iph1->etype)]
+                       [iph1->side]
+                       [iph1->status])(iph1, msg) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to process packet.\n");
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase1", s_isakmp_state(iph1->etype, iph1->side, iph1->status),
+               timedelta(&start, &end));
+#endif
+       if (iph1->status == PHASE1ST_ESTABLISHED) {
+
+#ifdef ENABLE_STATS
+               gettimeofday(&iph1->end, NULL);
+               syslog(LOG_NOTICE, "%s(%s): %8.6f",
+                       "phase1", s_isakmp_etype(iph1->etype),
+                       timedelta(&iph1->start, &iph1->end));
+#endif
+
+#ifdef ENABLE_VPNCONTROL_PORT  
+
+       if (iph1->side == RESPONDER &&
+               iph1->local->sa_family == AF_INET) {
+               
+               struct redirect *addr;
+               
+               LIST_FOREACH(addr, &lcconf->redirect_addresses, chain) {
+                       if (((struct sockaddr_in *)iph1->local)->sin_addr.s_addr == addr->cluster_address) {
+                               vchar_t *raddr = vmalloc(sizeof(u_int32_t));
+                       
+                               if (raddr == NULL) {
+                                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                                               "failed to send redirect message - memory error.\n");
+                               } else {
+                                       memcpy(raddr->v, &addr->redirect_address, sizeof(u_int32_t));
+                                       (void)isakmp_info_send_n1(iph1, ISAKMP_NTYPE_LOAD_BALANCE, raddr);
+                                       plog(LLV_DEBUG, LOCATION, iph1->remote, "sent redirect notification - address = %x.\n", ntohl(addr->redirect_address));
+                                       vfree(raddr);
+                                       if (addr->force)
+                                               isakmp_ph1delete(iph1);
+                               }
+                       }
+                       return 0;
+               }
+       }
+#endif 
+               /* save created date. */
+               (void)time(&iph1->created);
+
+               /* add to the schedule to expire, and save back pointer. */
+               iph1->sce = sched_new(iph1->approval->lifetime,
+                   isakmp_ph1expire_stub, iph1);
+#ifdef ENABLE_HYBRID
+               if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) {
+                       switch(iph1->approval->authmethod) {
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+                               xauth_sendreq(iph1);
+                               /* XXX Don't process INITIAL_CONTACT */
+                               iph1->rmconf->ini_contact = 0;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+#endif
+#ifdef ENABLE_DPD
+               /* Schedule the r_u_there.... */
+               if(iph1->dpd_support && iph1->rmconf->dpd_interval)
+                       isakmp_sched_r_u(iph1, 0);
+#endif
+
+               /* INITIAL-CONTACT processing */
+               /* don't send anything if local test mode. */
+               if (!f_local
+                && iph1->rmconf->ini_contact && !getcontacted(iph1->remote)) {
+                       /* send INITIAL-CONTACT */
+                       isakmp_info_send_n1(iph1,
+                                       ISAKMP_NTYPE_INITIAL_CONTACT, NULL);
+                       /* insert a node into contacted list. */
+                       if (inscontacted(iph1->remote) == -1) {
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "failed to add contacted list.\n");
+                               /* ignore */
+                       }
+               }
+
+               log_ph1established(iph1);
+               plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+               
+#ifdef ENABLE_VPNCONTROL_PORT
+               vpncontrol_notify_phase_change(0, FROM_LOCAL, iph1, NULL);
+#endif
+
+
+               /* 
+                * SA up shell script hook: do it now,except if
+                * ISAKMP mode config was requested. In the later
+                * case it is done when we receive the configuration.
+                */
+               if ((iph1->status == PHASE1ST_ESTABLISHED) &&
+                   !iph1->rmconf->mode_cfg)
+                       script_hook(iph1, SCRIPT_PHASE1_UP);    
+       }
+
+       return 0;
+}
+
+/*
+ * main function of quick mode.
+ */
+static int
+quick_main(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg;
+{
+       struct isakmp *isakmp = (struct isakmp *)msg->v;
+       int error;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       /* ignore a packet */
+       if (iph2->status == PHASE2ST_ESTABLISHED
+        || iph2->status == PHASE2ST_GETSPISENT)
+               return 0;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+
+       /* receive */
+       if (ph2exchange[etypesw2(isakmp->etype)]
+                      [iph2->side]
+                      [iph2->status] == NULL) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "why isn't the function defined.\n");
+               return -1;
+       }
+       error = (ph2exchange[etypesw2(isakmp->etype)]
+                           [iph2->side]
+                           [iph2->status])(iph2, msg);
+       if (error != 0) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "failed to pre-process packet.\n");
+               if (error == ISAKMP_INTERNAL_ERROR)
+                       return 0;
+               isakmp_info_send_n1(iph2->ph1, error, NULL);
+               return -1;
+       }
+
+       /* when using commit bit, status will be reached here. */
+       //if (iph2->status == PHASE2ST_ADDSA)   //%%% BUG FIX - wrong place
+       //      return 0;
+
+       /* free resend buffer */
+       if (iph2->sendbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no buffer found as sendbuf\n"); 
+               return -1;
+       }
+       VPTRINIT(iph2->sendbuf);
+
+       /* turn off schedule */
+       if (iph2->scr)
+               SCHED_KILL(iph2->scr);
+               
+       /* when using commit bit, status will be reached here. */
+       if (iph2->status == PHASE2ST_ADDSA)             //%%% BUG FIX - moved to here
+               return 0;
+
+       /* send */
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       if ((ph2exchange[etypesw2(isakmp->etype)]
+                       [iph2->side]
+                       [iph2->status])(iph2, msg) != 0) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "failed to process packet.\n");
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase2",
+               s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
+               timedelta(&start, &end));
+#endif
+
+       return 0;
+}
+
+/* new negotiation of phase 1 for initiator */
+int
+isakmp_ph1begin_i(rmconf, remote, local)
+       struct remoteconf *rmconf;
+       struct sockaddr *remote, *local;
+{
+       struct ph1handle *iph1;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       /* get new entry to isakmp status table. */
+       iph1 = newph1();
+       if (iph1 == NULL)
+               return -1;
+
+       iph1->status = PHASE1ST_START;
+       iph1->rmconf = rmconf;
+       iph1->side = INITIATOR;
+       iph1->version = ISAKMP_VERSION_NUMBER;
+       iph1->msgid = 0;
+       iph1->flags = 0;
+       iph1->ph2cnt = 0;
+#ifdef HAVE_GSSAPI
+       iph1->gssapi_state = NULL;
+#endif
+#ifdef ENABLE_HYBRID
+       if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL)
+               return -1;
+#endif
+#ifdef ENABLE_FRAG
+       iph1->frag = 0;
+       iph1->frag_chain = NULL;
+#endif
+       iph1->approval = NULL;
+
+       /* XXX copy remote address */
+       if (copy_ph1addresses(iph1, rmconf, remote, local) < 0)
+               return -1;
+
+       (void)insph1(iph1);
+
+       /* start phase 1 exchange */
+       iph1->etype = rmconf->etypes->type;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+    {
+       char *a;
+
+       a = strdup(saddr2str(iph1->local));
+       plog(LLV_INFO, LOCATION, NULL,
+               "initiate new phase 1 negotiation: %s<=>%s\n",
+               a, saddr2str(iph1->remote));
+       racoon_free(a);
+    }
+       plog(LLV_INFO, LOCATION, NULL,
+               "begin %s mode.\n",
+               s_isakmp_etype(iph1->etype));
+
+#ifdef ENABLE_STATS
+       gettimeofday(&iph1->start, NULL);
+       gettimeofday(&start, NULL);
+#endif
+       /* start exchange */
+       if ((ph1exchange[etypesw1(iph1->etype)]
+                       [iph1->side]
+                       [iph1->status])(iph1, NULL) != 0) {
+               /* failed to start phase 1 negotiation */
+               remph1(iph1);
+               delph1(iph1);
+
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase1",
+               s_isakmp_state(iph1->etype, iph1->side, iph1->status),
+               timedelta(&start, &end));
+#endif
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL);
+#endif
+
+       
+       return 0;
+}
+
+/* new negotiation of phase 1 for responder */
+static int
+isakmp_ph1begin_r(msg, remote, local, etype)
+       vchar_t *msg;
+       struct sockaddr *remote, *local;
+       u_int8_t etype;
+{
+       struct isakmp *isakmp = (struct isakmp *)msg->v;
+       struct remoteconf *rmconf;
+       struct ph1handle *iph1;
+       struct etypes *etypeok;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       /* look for my configuration */
+       rmconf = getrmconf(remote);
+       if (rmconf == NULL) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "couldn't find "
+                       "configuration.\n");
+               return -1;
+       }
+
+       /* check to be acceptable exchange type */
+       etypeok = check_etypeok(rmconf, etype);
+       if (etypeok == NULL) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "not acceptable %s mode\n", s_isakmp_etype(etype));
+               return -1;
+       }
+
+       /* get new entry to isakmp status table. */
+       iph1 = newph1();
+       if (iph1 == NULL)
+               return -1;
+
+       memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(iph1->index.i_ck));
+       iph1->status = PHASE1ST_START;
+       iph1->rmconf = rmconf;
+       iph1->flags = 0;
+       iph1->side = RESPONDER;
+       iph1->etype = etypeok->type;
+       iph1->version = isakmp->v;
+       iph1->msgid = 0;
+#ifdef HAVE_GSSAPI
+       iph1->gssapi_state = NULL;
+#endif
+#ifdef ENABLE_HYBRID
+       if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL)
+               return -1;
+#endif
+#ifdef ENABLE_FRAG
+       iph1->frag = 0;
+       iph1->frag_chain = NULL;
+#endif
+       iph1->approval = NULL;
+
+#ifdef ENABLE_NATT
+       /* RFC3947 says that we MUST accept new phases1 on NAT-T floated port.
+        * We have to setup this flag now to correctly generate the first reply.
+        * Don't know if a better check could be done for that ?
+        */
+       if(extract_port(local) == lcconf->port_isakmp_natt)
+               iph1->natt_flags |= (NAT_PORTS_CHANGED);
+#endif
+
+       /* copy remote address */
+       if (copy_ph1addresses(iph1, rmconf, remote, local) < 0)
+               return -1;
+
+       (void)insph1(iph1);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+    {
+       char *a;
+
+       a = strdup(saddr2str(iph1->local));
+       plog(LLV_INFO, LOCATION, NULL,
+               "respond new phase 1 negotiation: %s<=>%s\n",
+               a, saddr2str(iph1->remote));
+       racoon_free(a);
+    }
+       plog(LLV_INFO, LOCATION, NULL,
+               "begin %s mode.\n", s_isakmp_etype(etype));
+
+#ifdef ENABLE_STATS
+       gettimeofday(&iph1->start, NULL);
+       gettimeofday(&start, NULL);
+#endif
+       /* start exchange */
+       if ((ph1exchange[etypesw1(iph1->etype)]
+                       [iph1->side]
+                       [iph1->status])(iph1, msg) < 0
+        || (ph1exchange[etypesw1(iph1->etype)]
+                       [iph1->side]
+                       [iph1->status])(iph1, msg) < 0) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "failed to process packet.\n");
+               remph1(iph1);
+               delph1(iph1);
+               return -1;
+       }
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase1",
+               s_isakmp_state(iph1->etype, iph1->side, iph1->status),
+               timedelta(&start, &end));
+#endif
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_REMOTE, iph1, NULL);
+#endif
+
+       return 0;
+}
+
+/* new negotiation of phase 2 for initiator */
+static int
+isakmp_ph2begin_i(iph1, iph2)
+       struct ph1handle *iph1;
+       struct ph2handle *iph2;
+{
+#ifdef ENABLE_HYBRID
+       if (xauth_check(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Attempt to start phase 2 whereas Xauth failed\n");
+               return -1;
+       }
+#endif
+
+       /* found ISAKMP-SA. */
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n");
+    {
+       char *a;
+       a = strdup(saddr2str(iph2->src));
+       plog(LLV_INFO, LOCATION, NULL,
+               "initiate new phase 2 negotiation: %s<=>%s\n",
+               a, saddr2str(iph2->dst));
+       racoon_free(a);
+    }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&iph2->start, NULL);
+#endif
+       /* found isakmp-sa */
+       bindph12(iph1, iph2);
+       iph2->status = PHASE2ST_STATUS2;
+
+       if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
+                        [iph2->side]
+                        [iph2->status])(iph2, NULL) < 0) {
+               unbindph12(iph2);
+               /* release ipsecsa handler due to internal error. */
+               remph2(iph2);
+               return -1;
+       }
+       
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_LOCAL, NULL, iph2);
+#endif
+
+       return 0;
+}
+
+/* new negotiation of phase 2 for responder */
+static int
+isakmp_ph2begin_r(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct isakmp *isakmp = (struct isakmp *)msg->v;
+       struct ph2handle *iph2 = 0;
+       int error;
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+#ifdef ENABLE_HYBRID
+       if (xauth_check(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Attempt to start phase 2 whereas Xauth failed\n");
+               return -1;
+       }
+#endif
+
+       iph2 = newph2();
+       if (iph2 == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate phase2 entry.\n");
+               return -1;
+       }
+
+       iph2->ph1 = iph1;
+       iph2->side = RESPONDER;
+       iph2->status = PHASE2ST_START;
+       iph2->flags = isakmp->flags;
+       iph2->msgid = isakmp->msgid;
+       iph2->seq = pk_getseq();
+       iph2->ivm = oakley_newiv2(iph1, iph2->msgid);
+       if (iph2->ivm == NULL) {
+               delph2(iph2);
+               return -1;
+       }
+       iph2->dst = dupsaddr(iph1->remote);     /* XXX should be considered */
+       if (iph2->dst == NULL) {
+               delph2(iph2);
+               return -1;
+       }
+       switch (iph2->dst->sa_family) {
+       case AF_INET:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in *)iph2->dst)->sin_port = 0;
+#endif
+               break;
+#ifdef INET6
+       case AF_INET6:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0;
+#endif
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph2->dst->sa_family);
+               delph2(iph2);
+               return -1;
+       }
+
+       iph2->src = dupsaddr(iph1->local);      /* XXX should be considered */
+       if (iph2->src == NULL) {
+               delph2(iph2);
+               return -1;
+       }
+       switch (iph2->src->sa_family) {
+       case AF_INET:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in *)iph2->src)->sin_port = 0;
+#endif
+               break;
+#ifdef INET6
+       case AF_INET6:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0;
+#endif
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph2->src->sa_family);
+               delph2(iph2);
+               return -1;
+       }
+
+       /* add new entry to isakmp status table */
+       insph2(iph2);
+       bindph12(iph1, iph2);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+    {
+       char *a;
+
+       a = strdup(saddr2str(iph2->src));
+       plog(LLV_INFO, LOCATION, NULL,
+               "respond new phase 2 negotiation: %s<=>%s\n",
+               a, saddr2str(iph2->dst));
+       racoon_free(a);
+    }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+
+       error = (ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
+                          [iph2->side]
+                          [iph2->status])(iph2, msg);
+       if (error != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to pre-process packet.\n");
+               if (error != ISAKMP_INTERNAL_ERROR)
+                       isakmp_info_send_n1(iph2->ph1, error, NULL);
+               /*
+                * release handler because it's wrong that ph2handle is kept
+                * after failed to check message for responder's.
+                */
+               unbindph12(iph2);
+               remph2(iph2);
+               delph2(iph2);
+               return -1;
+       }
+
+       /* send */
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       if ((ph2exchange[etypesw2(isakmp->etype)]
+                       [iph2->side]
+                       [iph2->status])(iph2, msg) < 0) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "failed to process packet.\n");
+               /* don't release handler */
+               return -1;
+       }
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase2",
+               s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
+               timedelta(&start, &end));
+#endif
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_REMOTE, NULL, iph2);
+#endif
+
+
+       return 0;
+}
+
+/*
+ * parse ISAKMP payloads, without ISAKMP base header.
+ */
+vchar_t *
+isakmp_parsewoh(np0, gen, len)
+       int np0;
+       struct isakmp_gen *gen;
+       int len;
+{
+       u_char np = np0 & 0xff;
+       int tlen, plen;
+       vchar_t *result;
+       struct isakmp_parse_t *p, *ep;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "begin.\n");
+
+       /*
+        * 5 is a magic number, but any value larger than 2 should be fine
+        * as we do vrealloc() in the following loop.
+        */
+       result = vmalloc(sizeof(struct isakmp_parse_t) * 5);
+       if (result == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer.\n");
+               return NULL;
+       }
+       p = (struct isakmp_parse_t *)result->v;
+       ep = (struct isakmp_parse_t *)(result->v + result->l - sizeof(*ep));
+
+       tlen = len;
+
+       /* parse through general headers */
+       while (0 < tlen && np != ISAKMP_NPTYPE_NONE) {
+               if (tlen <= sizeof(struct isakmp_gen)) {
+                       /* don't send information, see isakmp_ident_r1() */
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid length of payload\n");
+                       vfree(result);
+                       return NULL;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "seen nptype=%u(%s)\n", np, s_isakmp_nptype(np));
+
+               p->type = np;
+               p->len = ntohs(gen->len);
+               if (p->len < sizeof(struct isakmp_gen) || p->len > tlen) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "invalid length of payload\n");
+                       vfree(result);
+                       return NULL;
+               }
+               p->ptr = gen;
+               p++;
+               if (ep <= p) {
+                       int off;
+
+                       off = p - (struct isakmp_parse_t *)result->v;
+                       result = vrealloc(result, result->l * 2);
+                       if (result == NULL) {
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "failed to realloc buffer.\n");
+                               vfree(result);
+                               return NULL;
+                       }
+                       ep = (struct isakmp_parse_t *)
+                               (result->v + result->l - sizeof(*ep));
+                       p = (struct isakmp_parse_t *)result->v;
+                       p += off;
+               }
+
+               np = gen->np;
+               plen = ntohs(gen->len);
+               gen = (struct isakmp_gen *)((caddr_t)gen + plen);
+               tlen -= plen;
+       }
+       p->type = ISAKMP_NPTYPE_NONE;
+       p->len = 0;
+       p->ptr = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "succeed.\n");
+
+       return result;
+}
+
+/*
+ * parse ISAKMP payloads, including ISAKMP base header.
+ */
+vchar_t *
+isakmp_parse(buf)
+       vchar_t *buf;
+{
+       struct isakmp *isakmp = (struct isakmp *)buf->v;
+       struct isakmp_gen *gen;
+       int tlen;
+       vchar_t *result;
+       u_char np;
+
+       np = isakmp->np;
+       gen = (struct isakmp_gen *)(buf->v + sizeof(*isakmp));
+       tlen = buf->l - sizeof(struct isakmp);
+       result = isakmp_parsewoh(np, gen, tlen);
+
+       return result;
+}
+
+/* %%% */
+int
+isakmp_init()
+{
+       /* initialize a isakmp status table */
+       initph1tree();
+       initph2tree();
+       initctdtree();
+       init_recvdpkt();
+
+       if (isakmp_open() < 0)
+               goto err;
+
+       return(0);
+
+err:
+       isakmp_close();
+       return(-1);
+}
+
+void
+isakmp_cleanup()
+{
+       clear_recvdpkt();
+       clear_contacted();
+}
+
+/*
+ * make strings containing i_cookie + r_cookie + msgid
+ */
+const char *
+isakmp_pindex(index, msgid)
+       const isakmp_index *index;
+       const u_int32_t msgid;
+{
+       static char buf[64];
+       const u_char *p;
+       int i, j;
+
+       memset(buf, 0, sizeof(buf));
+
+       /* copy index */
+       p = (const u_char *)index;
+       for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
+               snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
+               j += 2;
+               switch (i) {
+               case 7:
+                       buf[j++] = ':';
+               }
+       }
+
+       if (msgid == 0)
+               return buf;
+
+       /* copy msgid */
+       snprintf((char *)&buf[j], sizeof(buf) - j, ":%08x", ntohs(msgid));
+
+       return buf;
+}
+
+/* open ISAKMP sockets. */
+int
+isakmp_open()
+{
+       const int yes = 1;
+       int ifnum = 0, encap_ifnum = 0;
+#ifdef INET6
+       int pktinfo;
+#endif
+       struct myaddrs *p;
+
+       for (p = lcconf->myaddrs; p; p = p->next) {
+               if (!p->addr)
+                       continue;
+
+#ifdef __APPLE__
+               if (p->sock != -1) {
+                       ifnum++;
+                       if (p->udp_encap)
+                               encap_ifnum++;
+                       continue;               // socket already open  
+               }
+#endif
+
+               /* warn if wildcard address - should we forbid this? */
+               switch (p->addr->sa_family) {
+               case AF_INET:
+                       if (((struct sockaddr_in *)p->addr)->sin_addr.s_addr == 0)
+                               plog(LLV_WARNING, LOCATION, NULL,
+                                       "listening to wildcard address,"
+                                       "broadcast IKE packet may kill you\n");
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)p->addr)->sin6_addr))
+                               plog(LLV_WARNING, LOCATION, NULL,
+                                       "listening to wildcard address, "
+                                       "broadcast IKE packet may kill you\n");
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "unsupported address family %d\n",
+                               lcconf->default_af);
+                       goto err_and_next;
+               }
+
+#ifdef INET6
+               if (p->addr->sa_family == AF_INET6 &&
+                   IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)
+                                           p->addr)->sin6_addr))
+               {
+                       plog(LLV_DEBUG, LOCATION, NULL, 
+                               "Ignoring multicast address %s\n",
+                               saddr2str(p->addr));
+                               racoon_free(p->addr);
+                               p->addr = NULL;
+                       continue;
+               }
+#endif
+
+               if ((p->sock = socket(p->addr->sa_family, SOCK_DGRAM, 0)) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "socket (%s)\n", strerror(errno));
+                       goto err_and_next;
+               }
+
+               /* receive my interface address on inbound packets. */
+               switch (p->addr->sa_family) {
+               case AF_INET:
+                       if (setsockopt(p->sock, IPPROTO_IP,
+#ifdef __linux__
+                                      IP_PKTINFO,
+#else
+                                      IP_RECVDSTADDR,
+#endif
+                                       (const void *)&yes, sizeof(yes)) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "setsockopt (%s)\n", strerror(errno));
+                               goto err_and_next;
+                       }
+                       break;
+#ifdef INET6
+               case AF_INET6:
+#ifdef INET6_ADVAPI
+#ifdef IPV6_RECVPKTINFO
+                       pktinfo = IPV6_RECVPKTINFO;
+#else  /* old adv. API */
+                       pktinfo = IPV6_PKTINFO;
+#endif /* IPV6_RECVPKTINFO */
+#else
+                       pktinfo = IPV6_RECVDSTADDR;
+#endif
+                       if (setsockopt(p->sock, IPPROTO_IPV6, pktinfo,
+                                       (const void *)&yes, sizeof(yes)) < 0)
+                       {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "setsockopt(%d): %s\n",
+                                       pktinfo, strerror(errno));
+               if (fcntl(p->sock, F_SETFL, O_NONBLOCK) == -1)
+                       plog(LLV_WARNING, LOCATION, NULL,
+                               "failed to put socket in non-blocking mode\n");
+
+                               goto err_and_next;
+                       }
+                       break;
+#endif
+               }
+
+#ifdef IPV6_USE_MIN_MTU
+               if (p->addr->sa_family == AF_INET6 &&
+                   setsockopt(p->sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+                   (void *)&yes, sizeof(yes)) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "setsockopt (%s)\n", strerror(errno));
+                       return -1;
+               }
+#endif
+
+               if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0)
+                       goto err_and_next;
+
+#ifdef __APPLE__
+               if (extract_port(p->addr) == PORT_ISAKMP) {
+                       if (setsockopt(p->sock, SOL_SOCKET, SO_NOTIFYCONFLICT, 
+                               (void *)&yes, sizeof(yes)) < 0) {
+                               plog(LLV_ERROR, LOCATION, p->addr,
+                                       "setsockopt (%s)\n", strerror(errno));
+                               goto err_and_next;
+                       }
+               }
+#endif
+
+               if (bind(p->sock, p->addr, sysdep_sa_len(p->addr)) < 0) {
+                       plog(LLV_ERROR, LOCATION, p->addr,
+                               "failed to bind to address %s (%s).\n",
+                               saddr2str(p->addr), strerror(errno));
+                       close(p->sock);
+                       p->sock = -1;
+                       goto err_and_next;
+               }
+               
+               ifnum++;
+#ifdef __APPLE__
+               if (p->udp_encap)
+                       encap_ifnum++;
+#endif
+
+               plog(LLV_INFO, LOCATION, NULL,
+                       "%s used as isakmp port (fd=%d)\n",
+                       saddr2str(p->addr), p->sock);
+
+#ifndef __APPLE__
+#ifdef ENABLE_NATT
+               if (p->addr->sa_family == AF_INET) {
+                       int option = -1;
+
+                       if(p->udp_encap)
+                               option = UDP_ENCAP_ESPINUDP;
+#if defined(ENABLE_NATT_00) || defined(ENABLE_NATT_01)
+                       else
+                               option = UDP_ENCAP_ESPINUDP_NON_IKE;
+#endif
+                       if(option != -1){
+                               if (setsockopt (p->sock, SOL_UDP, UDP_ENCAP,
+                                                               &option, sizeof (option)) < 0) {
+                                       plog(LLV_WARNING, LOCATION, NULL,
+                                                "setsockopt(%s): %s\n",
+                                                option == UDP_ENCAP_ESPINUDP ? "UDP_ENCAP_ESPINUDP" : "UDP_ENCAP_ESPINUDP_NON_IKE",
+                                                strerror(errno));
+                                       goto skip_encap;
+                               }
+                               else {
+                                       plog(LLV_INFO, LOCATION, NULL,
+                                                "%s used for NAT-T\n",
+                                                saddr2str(p->addr));
+                                       encap_ifnum++;
+                               }
+                       }
+               }
+skip_encap:
+#endif
+#endif /* __APPLE__ */
+
+               continue;
+
+       err_and_next:
+               racoon_free(p->addr);
+               p->addr = NULL;
+               if (! lcconf->autograbaddr && lcconf->strict_address)
+                       return -1;
+               continue;
+       }
+
+       if (!ifnum) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no address could be bound.\n");
+               return -1;
+       }
+
+#ifdef ENABLE_NATT
+       if (natt_enabled_in_rmconf() && !encap_ifnum) {
+               plog(LLV_WARNING, LOCATION, NULL, 
+                       "NAT-T is enabled in at least one remote{} section,\n");
+               plog(LLV_WARNING, LOCATION, NULL, 
+                       "but no 'isakmp_natt' address was specified!\n");
+       }
+#endif
+
+       return 0;
+}
+
+void
+isakmp_close()
+{
+       isakmp_close_sockets();
+       clear_myaddr();
+}
+
+void
+isakmp_close_sockets()
+{
+       struct myaddrs *p;
+
+       for (p = lcconf->myaddrs; p; p = p->next) {
+
+               if (!p->addr)
+                       continue;
+
+               if (p->sock >= 0) {
+                       close(p->sock);
+                       p->sock = -1;
+               }               
+       }
+
+}
+
+
+// close sockets for addresses that have gone away
+void
+isakmp_close_unused()
+{
+       struct myaddrs *p, *next, **prev;
+       
+       prev = &(lcconf->myaddrs);
+       for (p = lcconf->myaddrs; p; p = next) {
+               next = p->next;
+               if (p->in_use == 0) {   // not in use ?
+       
+                       if (p->sock >= 0)
+                               close(p->sock);                 
+                       if (p->addr)
+                               racoon_free(p->addr);
+                       *prev = p->next;
+                       racoon_free(p);
+               } else
+                       prev = &(p->next);
+       }
+}
+
+int
+isakmp_send(iph1, sbuf)
+       struct ph1handle *iph1;
+       vchar_t *sbuf;
+{
+       int len = 0;
+       int s;
+       vchar_t *vbuf = NULL;
+
+#ifdef ENABLE_NATT
+       size_t extralen = NON_ESP_MARKER_USE(iph1) ? NON_ESP_MARKER_LEN : 0;
+
+#ifdef ENABLE_FRAG
+       /* 
+        * Do not add the non ESP marker for a packet that will
+        * be fragmented. The non ESP marker should appear in 
+        * all fragment's packets, but not in the fragmented packet
+        */
+       if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) 
+               extralen = 0;
+#endif
+       if (extralen)
+               plog (LLV_DEBUG, LOCATION, NULL, "Adding NON-ESP marker\n");
+
+       /* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker) 
+          must added just before the packet itself. For this we must 
+          allocate a new buffer and release it at the end. */
+       if (extralen) {
+               vbuf = vmalloc (sbuf->l + extralen);
+               *(u_int32_t *)vbuf->v = 0;
+               memcpy (vbuf->v + extralen, sbuf->v, sbuf->l);
+               sbuf = vbuf;
+       }
+#endif
+
+       /* select the socket to be sent */
+       s = getsockmyaddr(iph1->local);
+       if (s == -1){
+               if ( vbuf != NULL )
+                       vfree(vbuf);
+               return -1;
+       }
+
+       plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l, 
+             saddr2str_fromto("from %s to %s", iph1->local, iph1->remote));
+
+#ifdef ENABLE_FRAG
+       if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) {
+               if (isakmp_sendfrags(iph1, sbuf) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "isakmp_sendfrags failed\n");
+                       if ( vbuf != NULL )
+                               vfree(vbuf);
+                       return -1;
+               }
+       } else 
+#endif
+       {
+               len = sendfromto(s, sbuf->v, sbuf->l,
+                   iph1->local, iph1->remote, lcconf->count_persend);
+               if (len == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n");
+                       if ( vbuf != NULL )
+                               vfree(vbuf);
+                       return -1;
+               }
+       }
+       
+       if ( vbuf != NULL )
+               vfree(vbuf);
+       
+       return 0;
+}
+
+/* called from scheduler */
+void
+isakmp_ph1resend_stub(p)
+       void *p;
+{
+       (void)isakmp_ph1resend((struct ph1handle *)p);
+}
+
+int
+isakmp_ph1resend(iph1)
+       struct ph1handle *iph1;
+{
+       if (iph1->retry_counter < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "phase1 negotiation failed due to time up. %s\n",
+                       isakmp_pindex(&iph1->index, iph1->msgid));
+               EVT_PUSH(iph1->local, iph1->remote, 
+                   EVTT_PEER_NO_RESPONSE, NULL);
+
+               remph1(iph1);
+               delph1(iph1);
+               return -1;
+       }
+
+       if (isakmp_send(iph1, iph1->sendbuf) < 0){
+               iph1->retry_counter--;
+
+               iph1->scr = sched_new(iph1->rmconf->retry_interval,
+                                                         isakmp_ph1resend_stub, iph1);
+               return -1;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "resend phase1 packet %s\n",
+               isakmp_pindex(&iph1->index, iph1->msgid));
+
+       iph1->retry_counter--;
+
+       iph1->scr = sched_new(iph1->rmconf->retry_interval,
+               isakmp_ph1resend_stub, iph1);
+
+       return 0;
+}
+
+/* called from scheduler */
+void
+isakmp_ph2resend_stub(p)
+       void *p;
+{
+
+       (void)isakmp_ph2resend((struct ph2handle *)p);
+}
+
+int
+isakmp_ph2resend(iph2)
+       struct ph2handle *iph2;
+{
+       if (iph2->retry_counter < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "phase2 negotiation failed due to time up. %s\n",
+                               isakmp_pindex(&iph2->ph1->index, iph2->msgid));
+               EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL);
+               unbindph12(iph2);
+               remph2(iph2);
+               delph2(iph2);
+               return -1;
+       }
+
+       //%%% BUG FIX - related to commit bit usage - crash happened here
+       if (iph2->ph1 == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "internal error - attempt to re-send phase2 with no phase1 bound.\n");
+               iph2->retry_counter = -1;
+               remph2(iph2);
+               delph2(iph2);
+               return -1;
+       }
+
+       if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0)
+               return -1;
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "resend phase2 packet %s\n",
+               isakmp_pindex(&iph2->ph1->index, iph2->msgid));
+
+       iph2->retry_counter--;
+
+       iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval,
+               isakmp_ph2resend_stub, iph2);
+
+       return 0;
+}
+
+/* called from scheduler */
+void
+isakmp_ph1expire_stub(p)
+       void *p;
+{
+
+       isakmp_ph1expire((struct ph1handle *)p);
+}
+
+void
+isakmp_ph1expire(iph1)
+       struct ph1handle *iph1;
+{
+       char *src, *dst;
+
+       SCHED_KILL(iph1->sce);
+
+       if(iph1->status != PHASE1ST_EXPIRED){
+               src = strdup(saddr2str(iph1->local));
+               dst = strdup(saddr2str(iph1->remote));
+               plog(LLV_INFO, LOCATION, NULL,
+                        "ISAKMP-SA expired %s-%s spi:%s\n",
+                        src, dst,
+                        isakmp_pindex(&iph1->index, 0));
+               racoon_free(src);
+               racoon_free(dst);
+               iph1->status = PHASE1ST_EXPIRED;
+       }
+
+       /*
+        * the phase1 deletion is postponed until there is no phase2.
+        */
+       if (LIST_FIRST(&iph1->ph2tree) != NULL) {
+               iph1->sce = sched_new(1, isakmp_ph1expire_stub, iph1);
+               return;
+       }
+
+       iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+}
+
+/* called from scheduler */
+void
+isakmp_ph1delete_stub(p)
+       void *p;
+{
+
+       isakmp_ph1delete((struct ph1handle *)p);
+}
+
+void
+isakmp_ph1delete(iph1)
+       struct ph1handle *iph1;
+{
+       char *src, *dst;
+
+       if (iph1->sce)
+               SCHED_KILL(iph1->sce);
+
+       if (LIST_FIRST(&iph1->ph2tree) != NULL) {
+               iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+               return;
+       }
+
+       /* don't re-negosiation when the phase 1 SA expires. */
+
+       src = strdup(saddr2str(iph1->local));
+       dst = strdup(saddr2str(iph1->remote));
+       plog(LLV_INFO, LOCATION, NULL,
+               "ISAKMP-SA deleted %s-%s spi:%s\n",
+               src, dst, isakmp_pindex(&iph1->index, 0));
+       EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
+       racoon_free(src);
+       racoon_free(dst);
+
+       remph1(iph1);
+       delph1(iph1);
+
+       return;
+}
+
+/* called from scheduler.
+ * this function will call only isakmp_ph2delete().
+ * phase 2 handler remain forever if kernel doesn't cry a expire of phase 2 SA
+ * by something cause.  That's why this function is called after phase 2 SA
+ * expires in the userland.
+ */
+void
+isakmp_ph2expire_stub(p)
+       void *p;
+{
+
+       isakmp_ph2expire((struct ph2handle *)p);
+}
+
+void
+isakmp_ph2expire(iph2)
+       struct ph2handle *iph2;
+{
+       char *src, *dst;
+
+       SCHED_KILL(iph2->sce);
+
+       src = strdup(saddrwop2str(iph2->src));
+       dst = strdup(saddrwop2str(iph2->dst));
+       plog(LLV_INFO, LOCATION, NULL,
+               "phase2 sa expired %s-%s\n", src, dst);
+       racoon_free(src);
+       racoon_free(dst);
+
+       iph2->status = PHASE2ST_EXPIRED;
+
+       iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2);
+
+       return;
+}
+
+/* called from scheduler */
+void
+isakmp_ph2delete_stub(p)
+       void *p;
+{
+
+       isakmp_ph2delete((struct ph2handle *)p);
+}
+
+void
+isakmp_ph2delete(iph2)
+       struct ph2handle *iph2;
+{
+       char *src, *dst;
+
+       SCHED_KILL(iph2->sce);
+
+       src = strdup(saddrwop2str(iph2->src));
+       dst = strdup(saddrwop2str(iph2->dst));
+       plog(LLV_INFO, LOCATION, NULL,
+               "phase2 sa deleted %s-%s\n", src, dst);
+       racoon_free(src);
+       racoon_free(dst);
+
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+
+       return;
+}
+
+/* \f%%%
+ * Interface between PF_KEYv2 and ISAKMP
+ */
+/*
+ * receive ACQUIRE from kernel, and begin either phase1 or phase2.
+ * if phase1 has been finished, begin phase2.
+ */
+int
+isakmp_post_acquire(iph2)
+       struct ph2handle *iph2;
+{
+       struct remoteconf *rmconf;
+       struct ph1handle *iph1 = NULL;
+
+       /* search appropreate configuration with masking port. */
+       rmconf = getrmconf(iph2->dst);
+       if (rmconf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no configuration found for %s.\n",
+                       saddrwop2str(iph2->dst));
+               return -1;
+       }
+
+       /* if passive mode, ignore the acquire message */
+       if (rmconf->passive) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "because of passive mode, "
+                       "ignore the acquire message for %s.\n",
+                       saddrwop2str(iph2->dst));
+               return 0;
+       }
+
+       /* 
+        * Search isakmp status table by address and port 
+        * If NAT-T is in use, consider null ports as a 
+        * wildcard and use IKE ports instead.
+        */
+#ifdef ENABLE_NATT
+       if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
+               if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
+                       set_port(iph2->src, extract_port(iph1->local));
+                       set_port(iph2->dst, extract_port(iph1->remote));
+               }
+       } else {
+               iph1 = getph1byaddr(iph2->src, iph2->dst);
+       }
+#else
+       iph1 = getph1byaddr(iph2->src, iph2->dst);
+#endif
+
+       /* no ISAKMP-SA found. */
+       if (iph1 == NULL) {
+               struct sched *sc;
+
+               iph2->retry_checkph1 = lcconf->retry_checkph1;
+               sc = sched_new(1, isakmp_chkph1there_stub, iph2);
+               plog(LLV_INFO, LOCATION, NULL,
+                       "IPsec-SA request for %s queued "
+                       "due to no phase1 found.\n",
+                       saddrwop2str(iph2->dst));
+
+               /* start phase 1 negotiation as a initiator. */
+               if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src) < 0) {
+                       SCHED_KILL(sc);
+                       return -1;
+               }
+
+               return 0;
+               /*NOTREACHED*/
+       }
+
+       /* found ISAKMP-SA, but on negotiation. */
+       if (iph1->status != PHASE1ST_ESTABLISHED) {
+               iph2->retry_checkph1 = lcconf->retry_checkph1;
+               sched_new(1, isakmp_chkph1there_stub, iph2);
+               plog(LLV_INFO, LOCATION, iph2->dst,
+                       "request for establishing IPsec-SA was queued "
+                       "due to no phase1 found.\n");
+               return 0;
+               /*NOTREACHED*/
+       }
+
+       /* found established ISAKMP-SA */
+       /* i.e. iph1->status == PHASE1ST_ESTABLISHED */
+
+       /* found ISAKMP-SA. */
+       plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n");
+
+       /* begin quick mode */
+       if (isakmp_ph2begin_i(iph1, iph2))
+               return -1;
+
+       return 0;
+}
+
+/*
+ * receive GETSPI from kernel.
+ */
+int
+isakmp_post_getspi(iph2)
+       struct ph2handle *iph2;
+{
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+       /* don't process it because there is no suitable phase1-sa. */
+       if (iph2->ph1->status == PHASE1ST_EXPIRED) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "the negotiation is stopped, "
+                       "because there is no suitable ISAKMP-SA.\n");
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+       if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
+                       [iph2->side]
+                       [iph2->status])(iph2, NULL) != 0)
+               return -1;
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase2",
+               s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
+               timedelta(&start, &end));
+#endif
+
+       return 0;
+}
+
+/* called by scheduler */
+void
+isakmp_chkph1there_stub(p)
+       void *p;
+{
+       isakmp_chkph1there((struct ph2handle *)p);
+}
+
+void
+isakmp_chkph1there(iph2)
+       struct ph2handle *iph2;
+{
+       struct ph1handle *iph1;
+
+       iph2->retry_checkph1--;
+       if (iph2->retry_checkph1 < 0) {
+               plog(LLV_ERROR, LOCATION, iph2->dst,
+                       "phase2 negotiation failed "
+                       "due to time up waiting for phase1. %s\n",
+                       sadbsecas2str(iph2->dst, iph2->src,
+                               iph2->satype, 0, 0));
+               plog(LLV_INFO, LOCATION, NULL,
+                       "delete phase 2 handler.\n");
+
+               /* send acquire to kernel as error */
+               pk_sendeacquire(iph2);
+
+               unbindph12(iph2);
+               remph2(iph2);
+               delph2(iph2);
+
+               return;
+       }
+
+       /* 
+        * Search isakmp status table by address and port 
+        * If NAT-T is in use, consider null ports as a 
+        * wildcard and use IKE ports instead.
+        */
+#ifdef ENABLE_NATT
+       if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
+               if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
+                       /*
+                        *      cannot set ph2 ports until after switch to natt port
+                        *      otherwise this function will never again find phase 1
+                        */
+                       if (iph1->status == PHASE1ST_ESTABLISHED) {
+                               set_port(iph2->src, extract_port(iph1->local));
+                               set_port(iph2->dst, extract_port(iph1->remote));
+                       }
+               }
+       } else {
+               iph1 = getph1byaddr(iph2->src, iph2->dst);
+       }
+#else
+       iph1 = getph1byaddr(iph2->src, iph2->dst);
+#endif
+
+       /* XXX Even if ph1 as responder is there, should we not start
+        * phase 2 negotiation ? */
+       if (iph1 != NULL
+        && iph1->status == PHASE1ST_ESTABLISHED) {
+               /* found isakmp-sa */
+               /* begin quick mode */
+               (void)isakmp_ph2begin_i(iph1, iph2);
+               return;
+       }
+
+       /* no isakmp-sa found */
+       sched_new(1, isakmp_chkph1there_stub, iph2);
+
+       return;
+}
+
+/* copy variable data into ALLOCATED buffer. */
+caddr_t
+isakmp_set_attr_v(buf, type, val, len)
+       caddr_t buf;
+       int type;
+       caddr_t val;
+       int len;
+{
+       struct isakmp_data *data;
+
+       data = (struct isakmp_data *)buf;
+       data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV);
+       data->lorv = htons((u_int16_t)len);
+       memcpy(data + 1, val, len);
+
+       return buf + sizeof(*data) + len;
+}
+
+/* copy fixed length data into ALLOCATED buffer. */
+caddr_t
+isakmp_set_attr_l(buf, type, val)
+       caddr_t buf;
+       int type;
+       u_int32_t val;
+{
+       struct isakmp_data *data;
+
+       data = (struct isakmp_data *)buf;
+       data->type = htons((u_int16_t)type | ISAKMP_GEN_TV);
+       data->lorv = htons((u_int16_t)val);
+
+       return buf + sizeof(*data);
+}
+
+/* add a variable data attribute to the buffer by reallocating it. */
+vchar_t *
+isakmp_add_attr_v(buf0, type, val, len)
+       vchar_t *buf0;
+       int type;
+       caddr_t val;
+       int len;
+{
+       vchar_t *buf = NULL;
+       struct isakmp_data *data;
+       int tlen;
+       int oldlen = 0;
+
+       tlen = sizeof(*data) + len;
+
+       if (buf0) {
+               oldlen = buf0->l;
+               buf = vrealloc(buf0, oldlen + tlen);
+       } else
+               buf = vmalloc(tlen);
+       if (!buf) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get a attribute buffer.\n");
+               return NULL;
+       }
+
+       data = (struct isakmp_data *)(buf->v + oldlen);
+       data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV);
+       data->lorv = htons((u_int16_t)len);
+       memcpy(data + 1, val, len);
+
+       return buf;
+}
+
+/* add a fixed data attribute to the buffer by reallocating it. */
+vchar_t *
+isakmp_add_attr_l(buf0, type, val)
+       vchar_t *buf0;
+       int type;
+       u_int32_t val;
+{
+       vchar_t *buf = NULL;
+       struct isakmp_data *data;
+       int tlen;
+       int oldlen = 0;
+
+       tlen = sizeof(*data);
+
+       if (buf0) {
+               oldlen = buf0->l;
+               buf = vrealloc(buf0, oldlen + tlen);
+       } else
+               buf = vmalloc(tlen);
+       if (!buf) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get a attribute buffer.\n");
+               return NULL;
+       }
+
+       data = (struct isakmp_data *)(buf->v + oldlen);
+       data->type = htons((u_int16_t)type | ISAKMP_GEN_TV);
+       data->lorv = htons((u_int16_t)val);
+
+       return buf;
+}
+
+/*
+ * calculate cookie and set.
+ */
+int
+isakmp_newcookie(place, remote, local)
+       caddr_t place;
+       struct sockaddr *remote;
+       struct sockaddr *local;
+{
+       vchar_t *buf = NULL, *buf2 = NULL;
+       char *p;
+       int blen;
+       int alen;
+       caddr_t sa1, sa2;
+       time_t t;
+       int error = -1;
+       u_short port;
+
+
+       if (remote->sa_family != local->sa_family) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "address family mismatch, remote:%d local:%d\n",
+                       remote->sa_family, local->sa_family);
+               goto end;
+       }
+       switch (remote->sa_family) {
+       case AF_INET:
+               alen = sizeof(struct in_addr);
+               sa1 = (caddr_t)&((struct sockaddr_in *)remote)->sin_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in *)local)->sin_addr;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               alen = sizeof(struct in_addr);
+               sa1 = (caddr_t)&((struct sockaddr_in6 *)remote)->sin6_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in6 *)local)->sin6_addr;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", remote->sa_family);
+               goto end;
+       }
+       blen = (alen + sizeof(u_short)) * 2
+               + sizeof(time_t) + lcconf->secret_size;
+       buf = vmalloc(blen);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get a cookie.\n");
+               goto end;
+       }
+       p = buf->v;
+
+       /* copy my address */
+       memcpy(p, sa1, alen);
+       p += alen;
+       port = ((struct sockaddr_in *)remote)->sin_port;
+       memcpy(p, &port, sizeof(u_short));
+       p += sizeof(u_short);
+
+       /* copy target address */
+       memcpy(p, sa2, alen);
+       p += alen;
+       port = ((struct sockaddr_in *)local)->sin_port;
+       memcpy(p, &port, sizeof(u_short));
+       p += sizeof(u_short);
+
+       /* copy time */
+       t = time(0);
+       memcpy(p, (caddr_t)&t, sizeof(t));
+       p += sizeof(t);
+
+       /* copy random value */
+       buf2 = eay_set_random(lcconf->secret_size);
+       if (buf2 == NULL)
+               goto end;
+       memcpy(p, buf2->v, lcconf->secret_size);
+       p += lcconf->secret_size;
+       vfree(buf2);
+
+       buf2 = eay_sha1_one(buf);
+       memcpy(place, buf2->v, sizeof(cookie_t));
+
+       sa1 = val2str(place, sizeof (cookie_t));
+       plog(LLV_DEBUG, LOCATION, NULL, "new cookie:\n%s\n", sa1);
+       racoon_free(sa1);
+
+       error = 0;
+end:
+       if (buf != NULL)
+               vfree(buf);
+       if (buf2 != NULL)
+               vfree(buf2);
+       return error;
+}
+
+/*
+ * save partner's(payload) data into phhandle.
+ */
+int
+isakmp_p2ph(buf, gen)
+       vchar_t **buf;
+       struct isakmp_gen *gen;
+{
+       /* XXX to be checked in each functions for logging. */
+       if (*buf) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "ignore this payload, same payload type exist.\n");
+               return -1;
+       }
+
+       *buf = vmalloc(ntohs(gen->len) - sizeof(*gen));
+       if (*buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer.\n");
+               return -1;
+       }
+       memcpy((*buf)->v, gen + 1, (*buf)->l);
+
+       return 0;
+}
+
+u_int32_t
+isakmp_newmsgid2(iph1)
+       struct ph1handle *iph1;
+{
+       u_int32_t msgid2;
+
+       do {
+               msgid2 = eay_random();
+       } while (getph2bymsgid(iph1, msgid2));
+
+       return msgid2;
+}
+
+/*
+ * set values into allocated buffer of isakmp header for phase 1
+ */
+static caddr_t
+set_isakmp_header(vbuf, iph1, nptype, etype, flags, msgid)
+       vchar_t *vbuf;
+       struct ph1handle *iph1;
+       int nptype;
+       u_int8_t etype;
+       u_int8_t flags;
+       u_int32_t msgid;
+{
+       struct isakmp *isakmp;
+
+       if (vbuf->l < sizeof(*isakmp))
+               return NULL;
+
+       isakmp = (struct isakmp *)vbuf->v;
+
+       memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t));
+       memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t));
+       isakmp->np = nptype;
+       isakmp->v = iph1->version;
+       isakmp->etype = etype;
+       isakmp->flags = flags;
+       isakmp->msgid = msgid;
+       isakmp->len = htonl(vbuf->l);
+
+       return vbuf->v + sizeof(*isakmp);
+}
+
+/*
+ * set values into allocated buffer of isakmp header for phase 1
+ */
+caddr_t
+set_isakmp_header1(vbuf, iph1, nptype)
+       vchar_t *vbuf;
+       struct ph1handle *iph1;
+       int nptype;
+{
+       return set_isakmp_header (vbuf, iph1, nptype, iph1->etype, iph1->flags, iph1->msgid);
+}
+
+/*
+ * set values into allocated buffer of isakmp header for phase 2
+ */
+caddr_t
+set_isakmp_header2(vbuf, iph2, nptype)
+       vchar_t *vbuf;
+       struct ph2handle *iph2;
+       int nptype;
+{
+       return set_isakmp_header (vbuf, iph2->ph1, nptype, ISAKMP_ETYPE_QUICK, iph2->flags, iph2->msgid);
+}
+
+/*
+ * set values into allocated buffer of isakmp payload.
+ */
+caddr_t
+set_isakmp_payload(buf, src, nptype)
+       caddr_t buf;
+       vchar_t *src;
+       int nptype;
+{
+       struct isakmp_gen *gen;
+       caddr_t p = buf;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "add payload of len %zu, next type %d\n",
+           src->l, nptype);
+
+       gen = (struct isakmp_gen *)p;
+       gen->np = nptype;
+       gen->len = htons(sizeof(*gen) + src->l);
+       p += sizeof(*gen);
+       memcpy(p, src->v, src->l);
+       p += src->l;
+
+       return p;
+}
+
+static int
+etypesw1(etype)
+       int etype;
+{
+       switch (etype) {
+       case ISAKMP_ETYPE_IDENT:
+               return 1;
+       case ISAKMP_ETYPE_AGG:
+               return 2;
+       case ISAKMP_ETYPE_BASE:
+               return 3;
+       default:
+               return 0;
+       }
+       /*NOTREACHED*/
+}
+
+static int
+etypesw2(etype)
+       int etype;
+{
+       switch (etype) {
+       case ISAKMP_ETYPE_QUICK:
+               return 1;
+       default:
+               return 0;
+       }
+       /*NOTREACHED*/
+}
+
+#ifdef HAVE_PRINT_ISAKMP_C
+/* for print-isakmp.c */
+char *snapend;
+extern void isakmp_print __P((const u_char *, u_int, const u_char *));
+
+char *getname __P((const u_char *));
+#ifdef INET6
+char *getname6 __P((const u_char *));
+#endif
+int safeputchar __P((int));
+
+/*
+ * Return a name for the IP address pointed to by ap.  This address
+ * is assumed to be in network byte order.
+ */
+char *
+getname(ap)
+       const u_char *ap;
+{
+       struct sockaddr_in addr;
+       static char ntop_buf[NI_MAXHOST];
+
+       memset(&addr, 0, sizeof(addr));
+#ifndef __linux__
+       addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+       addr.sin_family = AF_INET;
+       memcpy(&addr.sin_addr, ap, sizeof(addr.sin_addr));
+       if (getnameinfo((struct sockaddr *)&addr, sizeof(addr),
+                       ntop_buf, sizeof(ntop_buf), NULL, 0,
+                       NI_NUMERICHOST | niflags))
+               strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+
+       return ntop_buf;
+}
+
+#ifdef INET6
+/*
+ * Return a name for the IP6 address pointed to by ap.  This address
+ * is assumed to be in network byte order.
+ */
+char *
+getname6(ap)
+       const u_char *ap;
+{
+       struct sockaddr_in6 addr;
+       static char ntop_buf[NI_MAXHOST];
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin6_len = sizeof(struct sockaddr_in6);
+       addr.sin6_family = AF_INET6;
+       memcpy(&addr.sin6_addr, ap, sizeof(addr.sin6_addr));
+       if (getnameinfo((struct sockaddr *)&addr, addr.sin6_len,
+                       ntop_buf, sizeof(ntop_buf), NULL, 0,
+                       NI_NUMERICHOST | niflags))
+               strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+
+       return ntop_buf;
+}
+#endif /* INET6 */
+
+int
+safeputchar(c)
+       int c;
+{
+       unsigned char ch;
+
+       ch = (unsigned char)(c & 0xff);
+       if (c < 0x80 && isprint(c))
+               return printf("%c", c & 0xff);
+       else
+               return printf("\\%03o", c & 0xff);
+}
+
+void
+isakmp_printpacket(msg, from, my, decoded)
+       vchar_t *msg;
+       struct sockaddr *from;
+       struct sockaddr *my;
+       int decoded;
+{
+#ifdef YIPS_DEBUG
+       struct timeval tv;
+       int s;
+       char hostbuf[NI_MAXHOST];
+       char portbuf[NI_MAXSERV];
+       struct isakmp *isakmp;
+       vchar_t *buf;
+#endif
+
+       if (loglevel < LLV_DEBUG)
+               return;
+
+#ifdef YIPS_DEBUG
+       plog(LLV_DEBUG, LOCATION, NULL, "begin.\n");
+
+       gettimeofday(&tv, NULL);
+       s = tv.tv_sec % 3600;
+       printf("%02d:%02d.%06u ", s / 60, s % 60, (u_int32_t)tv.tv_usec);
+
+       if (from) {
+               if (getnameinfo(from, sysdep_sa_len(from), hostbuf, sizeof(hostbuf),
+                               portbuf, sizeof(portbuf),
+                               NI_NUMERICHOST | NI_NUMERICSERV | niflags)) {
+                       strlcpy(hostbuf, "?", sizeof(hostbuf));
+                       strlcpy(portbuf, "?", sizeof(portbuf));
+               }
+               printf("%s:%s", hostbuf, portbuf);
+       } else
+               printf("?");
+       printf(" -> ");
+       if (my) {
+               if (getnameinfo(my, sysdep_sa_len(my), hostbuf, sizeof(hostbuf),
+                               portbuf, sizeof(portbuf),
+                               NI_NUMERICHOST | NI_NUMERICSERV | niflags)) {
+                       strlcpy(hostbuf, "?", sizeof(hostbuf));
+                       strlcpy(portbuf, "?", sizeof(portbuf));
+               }
+               printf("%s:%s", hostbuf, portbuf);
+       } else
+               printf("?");
+       printf(": ");
+
+       buf = vdup(msg);
+       if (!buf) {
+               printf("(malloc fail)\n");
+               return;
+       }
+       if (decoded) {
+               isakmp = (struct isakmp *)buf->v;
+               if (isakmp->flags & ISAKMP_FLAG_E) {
+#if 0
+                       int pad;
+                       pad = *(u_char *)(buf->v + buf->l - 1);
+                       if (buf->l < pad && 2 < vflag)
+                               printf("(wrong padding)");
+#endif
+                       isakmp->flags &= ~ISAKMP_FLAG_E;
+               }
+       }
+
+       snapend = buf->v + buf->l;
+       isakmp_print(buf->v, buf->l, NULL);
+       vfree(buf);
+       printf("\n");
+       fflush(stdout);
+
+       return;
+#endif
+}
+#endif /*HAVE_PRINT_ISAKMP_C*/
+
+int
+copy_ph1addresses(iph1, rmconf, remote, local)
+       struct ph1handle *iph1;
+       struct remoteconf *rmconf;
+       struct sockaddr *remote, *local;
+{
+       u_short *port = NULL;
+
+       /* address portion must be grabbed from real remote address "remote" */
+       iph1->remote = dupsaddr(remote);
+       if (iph1->remote == NULL) {
+               delph1(iph1);
+               return -1;
+       }
+
+       /*
+        * if remote has no port # (in case of initiator - from ACQUIRE msg)
+        * - if remote.conf specifies port #, use that
+        * - if remote.conf does not, use 500
+        * if remote has port # (in case of responder - from recvfrom(2))
+        * respect content of "remote".
+        */
+       switch (iph1->remote->sa_family) {
+       case AF_INET:
+               port = &((struct sockaddr_in *)iph1->remote)->sin_port;
+               if (*port)
+                       break;
+               *port = ((struct sockaddr_in *)rmconf->remote)->sin_port;
+               if (*port)
+                       break;
+               *port = htons(PORT_ISAKMP);
+               break;
+#ifdef INET6
+       case AF_INET6:
+               port = &((struct sockaddr_in6 *)iph1->remote)->sin6_port;
+               if (*port)
+                       break;
+               *port = ((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
+               if (*port)
+                       break;
+               *port = htons(PORT_ISAKMP);
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph1->remote->sa_family);
+               return -1;
+       }
+
+       if (local == NULL)
+               iph1->local = getlocaladdr(iph1->remote);
+       else
+               iph1->local = dupsaddr(local);
+       if (iph1->local == NULL) {
+               delph1(iph1);
+               return -1;
+       }
+       port = NULL;
+       switch (iph1->local->sa_family) {
+       case AF_INET:
+               port = &((struct sockaddr_in *)iph1->local)->sin_port;
+               if (*port)
+                       break;
+               *port = ((struct sockaddr_in *)local)->sin_port;
+               if (*port)
+                       break;
+               *port = getmyaddrsport(iph1->local);
+               break;
+#ifdef INET6
+       case AF_INET6:
+               port = &((struct sockaddr_in6 *)iph1->local)->sin6_port;
+               if (*port)
+                       break;
+               *port = ((struct sockaddr_in6 *)local)->sin6_port;
+               if (*port)
+                       break;
+               *port = getmyaddrsport(iph1->local);
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph1->local->sa_family);
+               delph1(iph1);
+               return -1;
+       }
+#ifdef ENABLE_NATT
+       if ( port != NULL && *port == htons(lcconf->port_isakmp_natt) ) {
+           plog (LLV_DEBUG, LOCATION, NULL, "Marking ports as changed\n");
+           iph1->natt_flags |= NAT_ADD_NON_ESP_MARKER;
+       }
+#endif
+
+       return 0;
+}
+
+static int
+nostate1(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       plog(LLV_ERROR, LOCATION, iph1->remote, "wrong state %u.\n",
+                       iph1->status);
+       return -1;
+}
+
+static int
+nostate2(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg;
+{
+       plog(LLV_ERROR, LOCATION, iph2->ph1->remote, "wrong state %u.\n",
+               iph2->status);
+       return -1;
+}
+
+void
+log_ph1established(iph1)
+       const struct ph1handle *iph1;
+{
+       char *src, *dst;
+
+       src = strdup(saddr2str(iph1->local));
+       dst = strdup(saddr2str(iph1->remote));
+       plog(LLV_INFO, LOCATION, NULL,
+               "ISAKMP-SA established %s-%s spi:%s\n",
+               src, dst,
+               isakmp_pindex(&iph1->index, 0));
+       EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_UP, NULL);
+       racoon_free(src);
+       racoon_free(dst);
+
+       return;
+}
+
+struct payload_list *
+isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_type)
+{
+       if (! plist) {
+               plist = racoon_malloc (sizeof (struct payload_list));
+               plist->prev = NULL;
+       }
+       else {
+               plist->next = racoon_malloc (sizeof (struct payload_list));
+               plist->next->prev = plist;
+               plist = plist->next;
+       }
+
+       plist->next = NULL;
+       plist->payload = payload;
+       plist->payload_type = payload_type;
+
+       return plist;
+}
+
+vchar_t * 
+isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1)
+{
+       struct payload_list *ptr, *first;
+       size_t tlen = sizeof (struct isakmp), n = 0;
+       vchar_t *buf;
+       char *p;
+
+       if (plist == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "in isakmp_plist_set_all: plist == NULL\n");
+               return NULL;
+       }
+
+       /* Seek to the first item.  */
+       ptr = *plist;
+       while (ptr->prev)
+               ptr = ptr->prev;
+       first = ptr;
+       
+       /* Compute the whole length.  */
+       while (ptr) {
+               tlen += ptr->payload->l + sizeof (struct isakmp_gen);
+               ptr = ptr->next;
+       }
+
+       buf = vmalloc(tlen);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       ptr = first;
+
+       p = set_isakmp_header1(buf, iph1, ptr->payload_type);
+       if (p == NULL)
+               goto end;
+
+       while (ptr)
+       {
+               p = set_isakmp_payload (p, ptr->payload, ptr->next ? ptr->next->payload_type : ISAKMP_NPTYPE_NONE);
+               first = ptr;
+               ptr = ptr->next;
+               racoon_free (first);
+               /* ptr->prev = NULL; first = NULL; ... omitted.  */
+               n++;
+       }
+
+       *plist = NULL;
+
+       return buf;
+end:
+       return NULL;
+}
+
+#ifdef ENABLE_FRAG
+int 
+frag_handler(iph1, msg, remote, local)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+       struct sockaddr *remote;
+       struct sockaddr *local;
+{
+       vchar_t *newmsg;
+
+       if (isakmp_frag_extract(iph1, msg) == 1) {
+               if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, remote, 
+                           "Packet reassembly failed\n");
+                       return -1;
+               }
+               return isakmp_main(newmsg, remote, local);
+       }
+
+       return 0;
+}
+#endif
+
+void
+script_hook(iph1, script)
+       struct ph1handle *iph1;
+       int script;
+{
+#define IP_MAX 40
+#define PORT_MAX 6
+       char addrstr[IP_MAX];
+       char portstr[PORT_MAX];
+       char **envp = NULL;
+       int envc = 1;
+       struct sockaddr_in *sin;
+       char **c;
+
+       if (iph1->rmconf->script[script] == -1)
+               return;
+
+#ifdef ENABLE_HYBRID
+       (void)isakmp_cfg_setenv(iph1, &envp, &envc);
+#endif
+
+       /* local address */
+       sin = (struct sockaddr_in *)iph1->local;
+       inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
+       snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
+
+       if (script_env_append(&envp, &envc, "LOCAL_ADDR", addrstr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_ADDR\n");
+               goto out;
+       }
+
+       if (script_env_append(&envp, &envc, "LOCAL_PORT", portstr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_PORT\n");
+               goto out;
+       }
+
+       /* Peer address */
+       sin = (struct sockaddr_in *)iph1->remote;
+       inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
+       snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
+
+       if (script_env_append(&envp, &envc, "REMOTE_ADDR", addrstr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set REMOTE_ADDR\n");
+               goto out;
+       }
+
+       if (script_env_append(&envp, &envc, "REMOTE_PORT", portstr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set REMOTEL_PORT\n");
+               goto out;
+       }
+
+       if (privsep_script_exec(iph1->rmconf->script[script], 
+           script, envp) != 0) 
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Script %s execution failed\n", script_names[script]);
+
+out:
+       for (c = envp; *c; c++)
+               racoon_free(*c);
+
+       racoon_free(envp);
+
+       return;
+}
+
+int
+script_env_append(envp, envc, name, value)
+       char ***envp;
+       int *envc;
+       char *name;
+       char *value;
+{
+       char *envitem;
+       char **newenvp;
+       int newenvc;
+       int envitemlen = strlen(name) + 1 + strlen(value) + 1;
+
+       envitem = racoon_malloc(envitemlen);
+       if (envitem == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       snprintf(envitem, envitemlen, "%s=%s", name, value);
+
+       newenvc = (*envc) + 1;
+       newenvp = racoon_realloc(*envp, newenvc * sizeof(char *));
+       if (newenvp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+
+       newenvp[newenvc - 2] = envitem;
+       newenvp[newenvc - 1] = NULL;
+
+       *envp = newenvp;
+       *envc = newenvc;
+       return 0;
+}
+
+int
+script_exec(script, name, envp)
+       int script;
+       int name;
+       char *const envp[];
+{
+       char *argv[] = { NULL, NULL, NULL };
+       vchar_t **sp;
+
+       if (script_paths == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "privsep_script_exec: script_paths was not initialized\n");
+               return -1;
+       }
+
+       sp = (vchar_t **)(script_paths->v);
+
+       argv[0] = sp[script]->v;
+       argv[1] = script_names[name];
+       argv[2] = NULL;
+
+       switch (fork()) { 
+       case 0:
+               execve(argv[0], argv, envp);
+               plog(LLV_ERROR2, LOCATION, NULL,
+                   "execve(\"%s\") failed: %s\n",
+                   argv[0], strerror(errno));
+               _exit(1);
+               break;
+       case -1:
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot fork: %s\n", strerror(errno));
+               return -1;
+               break;
+       default:
+               break;
+       }       
+
+       return 0;
+}
+
+void
+purge_remote(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf = NULL;
+       struct sadb_msg *msg, *next, *end;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       u_int proto_id;
+       struct ph2handle *iph2;
+       struct ph1handle *new_iph1;
+
+       plog(LLV_INFO, LOCATION, NULL,
+                "purging ISAKMP-SA spi=%s.\n",
+                isakmp_pindex(&(iph1->index), iph1->msgid));
+
+       /* Mark as expired. */
+       iph1->status = PHASE1ST_EXPIRED;
+
+       /* Check if we have another, still valid, phase1 SA. */
+       new_iph1 = getph1byaddr(iph1->local, iph1->remote);
+
+       /*
+        * Delete all orphaned or binded to the deleting ph1handle phase2 SAs.
+        * Keep all others phase2 SAs.
+        */
+       buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey_dump_sadb returned nothing.\n");
+               return;
+       }
+
+       msg = (struct sadb_msg *)buf->v;
+       end = (struct sadb_msg *)(buf->v + buf->l);
+
+       while (msg < end) {
+               if ((msg->sadb_msg_len << 3) < sizeof(*msg))
+                       break;
+               next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3));
+               if (msg->sadb_msg_type != SADB_DUMP) {
+                       msg = next;
+                       continue;
+               }
+
+               if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey_check (%s)\n", ipsec_strerror());
+                       msg = next;
+                       continue;
+               }
+
+               sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
+               if (!sa ||
+                   !mhp[SADB_EXT_ADDRESS_SRC] ||
+                   !mhp[SADB_EXT_ADDRESS_DST]) {
+                       msg = next;
+                       continue;
+               }
+               src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+               dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+               if (sa->sadb_sa_state != SADB_SASTATE_LARVAL &&
+                   sa->sadb_sa_state != SADB_SASTATE_MATURE &&
+                   sa->sadb_sa_state != SADB_SASTATE_DYING) {
+                       msg = next;
+                       continue;
+               }
+
+               /* check in/outbound SAs */
+               if ((CMPSADDR(iph1->local, src) || CMPSADDR(iph1->remote, dst)) &&
+                       (CMPSADDR(iph1->local, dst) || CMPSADDR(iph1->remote, src))) {
+                       msg = next;
+                       continue;
+               }
+
+               proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+               iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
+
+               /* Check if there is another valid ISAKMP-SA */
+               if (new_iph1 != NULL) {
+
+                       if (iph2 == NULL) {
+                               /* No handler... still send a pfkey_delete message, but log this !*/
+                               plog(LLV_INFO, LOCATION, NULL,
+                                       "Unknown IPsec-SA spi=%u, hmmmm?\n",
+                                       ntohl(sa->sadb_sa_spi));
+                       }else{
+
+                               /* 
+                                * If we have a new ph1, do not purge IPsec-SAs binded
+                                *  to a different ISAKMP-SA
+                                */
+                               if (iph2->ph1 != NULL && iph2->ph1 != iph1){
+                                       msg = next;
+                                       continue;
+                               }
+
+                               /* If the ph2handle is established, do not purge IPsec-SA */
+                               if (iph2->status == PHASE2ST_ESTABLISHED ||
+                                       iph2->status == PHASE2ST_EXPIRED) {
+                                       
+                                       plog(LLV_INFO, LOCATION, NULL,
+                                                "keeping IPsec-SA spi=%u - found valid ISAKMP-SA spi=%s.\n",
+                                                ntohl(sa->sadb_sa_spi),
+                                                isakmp_pindex(&(new_iph1->index), new_iph1->msgid));
+                                       msg = next;
+                                       continue;
+                               }
+                       }
+               }
+
+               
+               pfkey_send_delete(lcconf->sock_pfkey,
+                                 msg->sadb_msg_satype,
+                                 IPSEC_MODE_ANY,
+                                 src, dst, sa->sadb_sa_spi);
+
+               /* delete a relative phase 2 handle. */
+               if (iph2 != NULL) {
+                       delete_spd(iph2);
+                       unbindph12(iph2);
+                       remph2(iph2);
+                       delph2(iph2);
+               }
+
+               plog(LLV_INFO, LOCATION, NULL,
+                        "purged IPsec-SA spi=%u.\n",
+                        ntohl(sa->sadb_sa_spi));
+
+               msg = next;
+       }
+
+       if (buf)
+               vfree(buf);
+
+       /* Mark the phase1 handler as EXPIRED */
+       plog(LLV_INFO, LOCATION, NULL,
+                "purged ISAKMP-SA spi=%s.\n",
+                isakmp_pindex(&(iph1->index), iph1->msgid));
+
+       if (iph1->sce)
+               SCHED_KILL(iph1->sce);
+
+       iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+}
+
+void 
+delete_spd(iph2)
+       struct ph2handle *iph2;
+{
+       if (iph2 == NULL)
+               return;
+
+       /* Delete the SPD entry if we generated it
+        */
+       if (iph2->generated_spidx) {
+               struct policyindex spidx;
+               struct sockaddr_storage addr;
+               u_int8_t pref;
+               struct sockaddr *src = iph2->src;
+               struct sockaddr *dst = iph2->dst;
+               int error;
+               int idi2type = 0;/* switch whether copy IDs into id[src,dst]. */
+
+               plog(LLV_INFO, LOCATION, NULL,
+                        "generated policy, deleting it.\n");
+               
+               memset(&spidx, 0, sizeof(spidx));
+               iph2->spidx_gen = (caddr_t )&spidx;
+               
+               /* make inbound policy */
+               iph2->src = dst;
+               iph2->dst = src;
+               spidx.dir = IPSEC_DIR_INBOUND;
+               spidx.ul_proto = 0;
+               
+               /* 
+                * Note: code from get_proposal_r
+                */
+               
+#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
+               
+               /*
+                * make destination address in spidx from either ID payload
+                * or phase 1 address into a address in spidx.
+                */
+               if (iph2->id != NULL
+                       && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
+                       || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR
+                       || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET
+                       || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+                       /* get a destination address of a policy */
+                       error = ipsecdoi_id2sockaddr(iph2->id,
+                           (struct sockaddr *)&spidx.dst,
+                           &spidx.prefd, &spidx.ul_proto);
+                       if (error)
+                               goto purge;
+                       
+#ifdef INET6
+                       /*
+                        * get scopeid from the SA address.
+                        * note that the phase 1 source address is used as
+                        * a destination address to search for a inbound 
+                        * policy entry because rcoon is responder.
+                        */
+                       if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) {
+                               if ((error = 
+                                   setscopeid((struct sockaddr *)&spidx.dst,
+                                  iph2->src)) != 0)
+                                       goto purge;
+                       }
+#endif
+                       
+                       if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
+                               || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR)
+                               idi2type = _XIDT(iph2->id);
+                       
+               } else {
+                       
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                                "get a destination address of SP index "
+                                "from phase1 address "
+                                "due to no ID payloads found "
+                                "OR because ID type is not address.\n");
+                       
+                       /*
+                        * copy the SOURCE address of IKE into the 
+                        * DESTINATION address of the key to search the 
+                        * SPD because the direction of policy is inbound.
+                        */
+                       memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src));
+                       switch (spidx.dst.ss_family) {
+                               case AF_INET:
+                                       spidx.prefd = 
+                                           sizeof(struct in_addr) << 3;
+                                       break;
+#ifdef INET6
+                               case AF_INET6:
+                                       spidx.prefd = 
+                                           sizeof(struct in6_addr) << 3;
+                                       break;
+#endif
+                               default:
+                                       spidx.prefd = 0;
+                                       break;
+                       }
+               }
+                                       
+               /* make source address in spidx */
+               if (iph2->id_p != NULL
+                       && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR
+                       || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR
+                       || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET
+                       || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+                       /* get a source address of inbound SA */
+                       error = ipsecdoi_id2sockaddr(iph2->id_p,
+                           (struct sockaddr *)&spidx.src,
+                           &spidx.prefs, &spidx.ul_proto);
+                       if (error)
+                               goto purge;
+
+#ifdef INET6
+                       /*
+                        * get scopeid from the SA address.
+                        * for more detail, see above of this function.
+                        */
+                       if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) {
+                               error = 
+                                   setscopeid((struct sockaddr *)&spidx.src,
+                                   iph2->dst);
+                               if (error)
+                                       goto purge;
+                       }
+#endif
+
+                       /* make id[src,dst] if both ID types are IP address and same */
+                       if (_XIDT(iph2->id_p) == idi2type
+                               && spidx.dst.ss_family == spidx.src.ss_family) {
+                               iph2->src_id = 
+                                   dupsaddr((struct sockaddr *)&spidx.dst);
+                               iph2->dst_id = 
+                                   dupsaddr((struct sockaddr *)&spidx.src);
+                       }
+
+               } else {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                                "get a source address of SP index "
+                                "from phase1 address "
+                                "due to no ID payloads found "
+                                "OR because ID type is not address.\n");
+
+                       /* see above comment. */
+                       memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
+                       switch (spidx.src.ss_family) {
+                               case AF_INET:
+                                       spidx.prefs = 
+                                           sizeof(struct in_addr) << 3;
+                                       break;
+#ifdef INET6
+                               case AF_INET6:
+                                       spidx.prefs = 
+                                           sizeof(struct in6_addr) << 3;
+                                       break;
+#endif
+                               default:
+                                       spidx.prefs = 0;
+                                       break;
+                       }
+               }
+
+#undef _XIDT
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                        "get a src address from ID payload "
+                        "%s prefixlen=%u ul_proto=%u\n",
+                        saddr2str((struct sockaddr *)&spidx.src),
+                        spidx.prefs, spidx.ul_proto);
+               plog(LLV_DEBUG, LOCATION, NULL,
+                        "get dst address from ID payload "
+                        "%s prefixlen=%u ul_proto=%u\n",
+                        saddr2str((struct sockaddr *)&spidx.dst),
+                        spidx.prefd, spidx.ul_proto);
+
+               /*
+                * convert the ul_proto if it is 0
+                * because 0 in ID payload means a wild card.
+                */
+               if (spidx.ul_proto == 0)
+                       spidx.ul_proto = IPSEC_ULPROTO_ANY;
+
+#undef _XIDT
+
+               /* End of code from get_proposal_r
+                */
+
+               if (pk_sendspddelete(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "pfkey spddelete(inbound) failed.\n");
+               }else{
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                                "pfkey spddelete(inbound) sent.\n");
+               }
+
+#ifdef HAVE_POLICY_FWD
+               /* make forward policy if required */
+               if (tunnel_mode_prop(iph2->approval)) {
+                       spidx.dir = IPSEC_DIR_FWD;
+                       if (pk_sendspddelete(iph2) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                        "pfkey spddelete(forward) failed.\n");
+                       }else{
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                        "pfkey spddelete(forward) sent.\n");
+                       }
+               }
+#endif
+
+               /* make outbound policy */
+               iph2->src = src;
+               iph2->dst = dst;
+               spidx.dir = IPSEC_DIR_OUTBOUND;
+               addr = spidx.src;
+               spidx.src = spidx.dst;
+               spidx.dst = addr;
+               pref = spidx.prefs;
+               spidx.prefs = spidx.prefd;
+               spidx.prefd = pref;
+
+               if (pk_sendspddelete(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "pfkey spddelete(outbound) failed.\n");
+               }else{
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                                "pfkey spddelete(outbound) sent.\n");
+               }
+purge:
+               iph2->spidx_gen=NULL;
+       }
+}
+
+#ifdef INET6
+u_int32_t
+setscopeid(sp_addr0, sa_addr0)
+       struct sockaddr *sp_addr0, *sa_addr0;
+{
+       struct sockaddr_in6 *sp_addr, *sa_addr;
+    
+       sp_addr = (struct sockaddr_in6 *)sp_addr0;
+       sa_addr = (struct sockaddr_in6 *)sa_addr0;
+
+       if (!IN6_IS_ADDR_LINKLOCAL(&sp_addr->sin6_addr)
+        && !IN6_IS_ADDR_SITELOCAL(&sp_addr->sin6_addr)
+        && !IN6_IS_ADDR_MULTICAST(&sp_addr->sin6_addr))
+               return 0;
+
+       /* this check should not be here ? */
+       if (sa_addr->sin6_family != AF_INET6) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "can't get scope ID: family mismatch\n");
+               return -1;
+       }
+
+       if (!IN6_IS_ADDR_LINKLOCAL(&sa_addr->sin6_addr)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "scope ID is not supported except of lladdr.\n");
+               return -1;
+       }
+
+       sp_addr->sin6_scope_id = sa_addr->sin6_scope_id;
+
+       return 0;
+}
+#endif
diff --git a/ipsec-tools/racoon/isakmp.h b/ipsec-tools/racoon/isakmp.h
new file mode 100644 (file)
index 0000000..06ee511
--- /dev/null
@@ -0,0 +1,447 @@
+/* $Id: isakmp.h,v 1.10 2005/01/29 16:34:25 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_H
+#define _ISAKMP_H
+
+/* refer to RFC 2408 */
+
+/* must include <netinet/in.h> first. */
+/* must include "isakmp_var.h" first. */
+
+#define INITIATOR      0       /* synonym sender */
+#define RESPONDER      1       /* synonym receiver */
+
+#define GENERATE       1
+#define VALIDATE       0
+
+/* 3.1 ISAKMP Header Format
+         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !                          Initiator                            !
+        !                            Cookie                             !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !                          Responder                            !
+        !                            Cookie                             !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !  Next Payload ! MjVer ! MnVer ! Exchange Type !     Flags     !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !                          Message ID                           !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !                            Length                             !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct isakmp {
+       cookie_t i_ck;          /* Initiator Cookie */
+       cookie_t r_ck;          /* Responder Cookie */
+       u_int8_t np;            /* Next Payload Type */
+       u_int8_t v;
+       u_int8_t etype;         /* Exchange Type */
+       u_int8_t flags;         /* Flags */
+       u_int32_t msgid;
+       u_int32_t len;          /* Length */
+} __attribute__((__packed__));
+
+/* Next Payload Type */
+#define ISAKMP_NPTYPE_NONE     0       /* NONE*/
+#define ISAKMP_NPTYPE_SA       1       /* Security Association */
+#define ISAKMP_NPTYPE_P                2       /* Proposal */
+#define ISAKMP_NPTYPE_T                3       /* Transform */
+#define ISAKMP_NPTYPE_KE       4       /* Key Exchange */
+#define ISAKMP_NPTYPE_ID       5       /* Identification */
+#define ISAKMP_NPTYPE_CERT     6       /* Certificate */
+#define ISAKMP_NPTYPE_CR       7       /* Certificate Request */
+#define ISAKMP_NPTYPE_HASH     8       /* Hash */
+#define ISAKMP_NPTYPE_SIG      9       /* Signature */
+#define ISAKMP_NPTYPE_NONCE    10      /* Nonce */
+#define ISAKMP_NPTYPE_N                11      /* Notification */
+#define ISAKMP_NPTYPE_D                12      /* Delete */
+#define ISAKMP_NPTYPE_VID      13      /* Vendor ID */
+#define ISAKMP_NPTYPE_ATTR     14      /* Attribute */
+
+
+/* NAT-T draft-ietf-ipsec-nat-t-ike-05 and later */
+/* XXX conflicts with values assigned to RFC 3547 */
+#define ISAKMP_NPTYPE_NATD_BADDRAFT            15      /* NAT Discovery */
+#define ISAKMP_NPTYPE_NATOA_BADDRAFT   16      /* NAT Original Address */
+
+
+/* NAT-T RFC */
+#define ISAKMP_NPTYPE_NATD_RFC 20      /* NAT Discovery */
+#define ISAKMP_NPTYPE_NATOA_RFC        21      /* NAT Original Address */
+
+/* NAT-T up to draft-ietf-ipsec-nat-t-ike-04 */
+#define ISAKMP_NPTYPE_NATD_DRAFT       130     /* NAT Discovery */
+#define ISAKMP_NPTYPE_NATOA_DRAFT      131     /* NAT Original Address */
+
+/* Frag does not seems to be documented */
+#define ISAKMP_NPTYPE_FRAG     132     /* IKE fragmentation payload */
+
+#define ISAKMP_NPTYPE_MAX      17
+                       /*      128 - 255 Private Use */
+
+/*
+ * The following are valid when the Vendor ID is one of the
+ * following:
+ *
+ *     MD5("A GSS-API Authentication Method for IKE")
+ *     MD5("GSSAPI") (recognized by Windows 2000)
+ *     MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000)
+ *
+ * See draft-ietf-ipsec-isakmp-gss-auth-06.txt.
+ */
+#define ISAKMP_NPTYPE_GSS      129     /* GSS token */
+
+#define ISAKMP_MAJOR_VERSION   1
+#define ISAKMP_MINOR_VERSION   0
+#define ISAKMP_VERSION_NUMBER  0x10
+#define ISAKMP_GETMAJORV(v)    (((v) & 0xf0) >> 4)
+#define ISAKMP_SETMAJORV(v, m) ((v) = ((v) & 0x0f) | (((m) << 4) & 0xf0))
+#define ISAKMP_GETMINORV(v)    ((v) & 0x0f)
+#define ISAKMP_SETMINORV(v, m) ((v) = ((v) & 0xf0) | ((m) & 0x0f))
+
+/* Exchange Type */
+#define ISAKMP_ETYPE_NONE      0       /* NONE */
+#define ISAKMP_ETYPE_BASE      1       /* Base */
+#define ISAKMP_ETYPE_IDENT     2       /* Identity Proteciton */
+#define ISAKMP_ETYPE_AUTH      3       /* Authentication Only */
+#define ISAKMP_ETYPE_AGG       4       /* Aggressive */
+#define ISAKMP_ETYPE_INFO      5       /* Informational */
+#define ISAKMP_ETYPE_CFG       6       /* Mode config */
+/* Additional Exchange Type */
+#define ISAKMP_ETYPE_QUICK     32      /* Quick Mode */
+#define ISAKMP_ETYPE_NEWGRP    33      /* New group Mode */
+#define ISAKMP_ETYPE_ACKINFO   34      /* Acknowledged Informational */
+
+/* Flags */
+#define ISAKMP_FLAG_E 0x01 /* Encryption Bit */
+#define ISAKMP_FLAG_C 0x02 /* Commit Bit */
+#define ISAKMP_FLAG_A 0x04 /* Authentication Only Bit */
+
+/* 3.2 Payload Generic Header
+         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        ! Next Payload  !   RESERVED    !         Payload Length        !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct isakmp_gen {
+       u_int8_t np;            /* Next Payload */
+       u_int8_t reserved;      /* RESERVED, unused, must set to 0 */
+       u_int16_t len;          /* Payload Length */
+} __attribute__((__packed__));
+
+/* 3.3 Data Attributes
+         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        !A!       Attribute Type        !    AF=0  Attribute Length     !
+        !F!                             !    AF=1  Attribute Value      !
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        .                   AF=0  Attribute Value                       .
+        .                   AF=1  Not Transmitted                       .
+        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct isakmp_data {
+       u_int16_t type;         /* defined by DOI-spec, and Attribute Format */
+       u_int16_t lorv;         /* if f equal 1, Attribute Length */
+                               /* if f equal 0, Attribute Value */
+       /* if f equal 1, Attribute Value */
+} __attribute__((__packed__));
+#define ISAKMP_GEN_TLV 0x0000
+#define ISAKMP_GEN_TV  0x8000
+       /* mask for type of attribute format */
+#define ISAKMP_GEN_MASK 0x8000
+
+#if 0
+/* MAY NOT be used, because of being defined in ipsec-doi. */
+/* 3.4 Security Association Payload */
+struct isakmp_pl_sa {
+       struct isakmp_gen h;
+       u_int32_t doi;          /* Domain of Interpretation */
+       u_int32_t sit;          /* Situation */
+} __attribute__((__packed__));
+#endif
+
+/* 3.5 Proposal Payload */
+       /*
+       The value of the next payload field MUST only contain the value "2"
+       or "0".  If there are additional Proposal payloads in the message,
+       then this field will be 2.  If the current Proposal payload is the
+       last within the security association proposal, then this field will
+       be 0.
+       */
+struct isakmp_pl_p {
+       struct isakmp_gen h;
+       u_int8_t p_no;          /* Proposal # */
+       u_int8_t proto_id;      /* Protocol */
+       u_int8_t spi_size;      /* SPI Size */
+       u_int8_t num_t;         /* Number of Transforms */
+       /* SPI */
+} __attribute__((__packed__));
+
+/* 3.6 Transform Payload */
+       /*
+       The value of the next payload field MUST only contain the value "3"
+       or "0".  If there are additional Transform payloads in the proposal,
+       then this field will be 3.  If the current Transform payload is the
+       last within the proposal, then this field will be 0.
+       */
+struct isakmp_pl_t {
+       struct isakmp_gen h;
+       u_int8_t t_no;          /* Transform # */
+       u_int8_t t_id;          /* Transform-Id */
+       u_int16_t reserved;     /* RESERVED2 */
+       /* SA Attributes */
+} __attribute__((__packed__));
+
+/* 3.7 Key Exchange Payload */
+struct isakmp_pl_ke {
+       struct isakmp_gen h;
+       /* Key Exchange Data */
+} __attribute__((__packed__));
+
+#if 0
+/* NOTE: MUST NOT use because of being defined in ipsec-doi instead them. */
+/* 3.8 Identification Payload */
+struct isakmp_pl_id {
+       struct isakmp_gen h;
+       union {
+               u_int8_t id_type;       /* ID Type */
+               u_int32_t doi_data;     /* DOI Specific ID Data */
+       } d;
+       /* Identification Data */
+} __attribute__((__packed__));
+/* A.4 ISAKMP Identification Type Values */
+#define ISAKMP_ID_IPV4_ADDR            0
+#define ISAKMP_ID_IPV4_ADDR_SUBNET     1
+#define ISAKMP_ID_IPV6_ADDR            2
+#define ISAKMP_ID_IPV6_ADDR_SUBNET     3
+#endif
+
+/* 3.9 Certificate Payload */
+struct isakmp_pl_cert {
+       struct isakmp_gen h;
+       /*
+        * Encoding type of 1 octet follows immediately,
+        * variable length CERT data follows encoding type.
+        */
+} __attribute__((__packed__));
+
+/* Certificate Type */
+#define ISAKMP_CERT_NONE       0
+#define ISAKMP_CERT_PKCS7      1
+#define ISAKMP_CERT_PGP                2
+#define ISAKMP_CERT_DNS                3
+#define ISAKMP_CERT_X509SIGN   4
+#define ISAKMP_CERT_X509KE     5
+#define ISAKMP_CERT_KERBEROS   6
+#define ISAKMP_CERT_CRL                7
+#define ISAKMP_CERT_ARL                8
+#define ISAKMP_CERT_SPKI       9
+#define ISAKMP_CERT_X509ATTR   10
+#define ISAKMP_CERT_PLAINRSA   11
+
+/* the method to get peers certificate */
+#define ISAKMP_GETCERT_PAYLOAD         1
+#define ISAKMP_GETCERT_LOCALFILE       2
+#define ISAKMP_GETCERT_DNS             3
+
+/* 3.10 Certificate Request Payload */
+struct isakmp_pl_cr {
+       struct isakmp_gen h;
+       u_int8_t num_cert; /* # Cert. Types */
+       /*
+       Certificate Types (variable length)
+         -- Contains a list of the types of certificates requested,
+         sorted in order of preference.  Each individual certificate
+         type is 1 octet.  This field is NOT required.
+       */
+       /* # Certificate Authorities (1 octet) */
+       /* Certificate Authorities (variable length) */
+} __attribute__((__packed__));
+
+/* 3.11 Hash Payload */
+struct isakmp_pl_hash {
+       struct isakmp_gen h;
+       /* Hash Data */
+} __attribute__((__packed__));
+
+/* 3.12 Signature Payload */
+struct isakmp_pl_sig {
+       struct isakmp_gen h;
+       /* Signature Data */
+} __attribute__((__packed__));
+
+/* 3.13 Nonce Payload */
+struct isakmp_pl_nonce {
+       struct isakmp_gen h;
+       /* Nonce Data */
+} __attribute__((__packed__));
+
+/* 3.14 Notification Payload */
+struct isakmp_pl_n {
+       struct isakmp_gen h;
+       u_int32_t doi;          /* Domain of Interpretation */
+       u_int8_t proto_id;      /* Protocol-ID */
+       u_int8_t spi_size;      /* SPI Size */
+       u_int16_t type;         /* Notify Message Type */
+       /* SPI */
+       /* Notification Data */
+} __attribute__((__packed__));
+
+/* 3.14.1 Notify Message Types */
+/* NOTIFY MESSAGES - ERROR TYPES */
+#define ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE      1
+#define ISAKMP_NTYPE_DOI_NOT_SUPPORTED         2
+#define ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED   3
+#define ISAKMP_NTYPE_INVALID_COOKIE            4
+#define ISAKMP_NTYPE_INVALID_MAJOR_VERSION     5
+#define ISAKMP_NTYPE_INVALID_MINOR_VERSION     6
+#define ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE     7
+#define ISAKMP_NTYPE_INVALID_FLAGS             8
+#define ISAKMP_NTYPE_INVALID_MESSAGE_ID                9
+#define ISAKMP_NTYPE_INVALID_PROTOCOL_ID       10
+#define ISAKMP_NTYPE_INVALID_SPI               11
+#define ISAKMP_NTYPE_INVALID_TRANSFORM_ID      12
+#define ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED  13
+#define ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN                14
+#define ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX       15
+#define ISAKMP_NTYPE_PAYLOAD_MALFORMED         16
+#define ISAKMP_NTYPE_INVALID_KEY_INFORMATION   17
+#define ISAKMP_NTYPE_INVALID_ID_INFORMATION    18
+#define ISAKMP_NTYPE_INVALID_CERT_ENCODING     19
+#define ISAKMP_NTYPE_INVALID_CERTIFICATE       20
+#define ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX   21
+#define ISAKMP_NTYPE_INVALID_CERT_AUTHORITY    22
+#define ISAKMP_NTYPE_INVALID_HASH_INFORMATION  23
+#define ISAKMP_NTYPE_AUTHENTICATION_FAILED     24
+#define ISAKMP_NTYPE_INVALID_SIGNATURE         25
+#define ISAKMP_NTYPE_ADDRESS_NOTIFICATION      26
+#define ISAKMP_NTYPE_NOTIFY_SA_LIFETIME                27
+#define ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE   28
+#define ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE 29
+#define ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS   30
+/* NOTIFY MESSAGES - STATUS TYPES */
+#define ISAKMP_NTYPE_CONNECTED                 16384
+/* 4.6.3 IPSEC DOI Notify Message Types */
+#define ISAKMP_NTYPE_RESPONDER_LIFETIME                24576
+#define ISAKMP_NTYPE_REPLAY_STATUS             24577
+#define ISAKMP_NTYPE_INITIAL_CONTACT           24578
+
+/* DPD */
+#define ISAKMP_NTYPE_R_U_THERE                 36136
+#define ISAKMP_NTYPE_R_U_THERE_ACK             36137
+
+#define ISAKMP_NTYPE_LOAD_BALANCE              40501
+#define ISAKMP_NTYPE_HEARTBEAT                 40503
+
+/* using only to log */
+#define ISAKMP_LOG_RETRY_LIMIT_REACHED         65530
+
+/* XXX means internal error but it's not reserved by any drafts... */
+#define ISAKMP_INTERNAL_ERROR                  -1
+
+/* 3.15 Delete Payload */
+struct isakmp_pl_d {
+       struct isakmp_gen h;
+       u_int32_t doi;          /* Domain of Interpretation */
+       u_int8_t proto_id;      /* Protocol-Id */
+       u_int8_t spi_size;      /* SPI Size */
+       u_int16_t num_spi;      /* # of SPIs */
+       /* SPI(es) */
+} __attribute__((__packed__));
+
+/* natoa payload */
+struct isakmp_pl_natoa {
+       struct isakmp_gen h;
+       u_int8_t id_type;               /* address type */
+       u_int8_t reserved1;             /* reserved */
+       u_int16_t reserved2;    /* reserved */
+       /* IP address */
+} __attribute__((__packed__));
+
+struct payload_list {
+       struct payload_list     *next, *prev;
+       vchar_t                 *payload;
+       int                     payload_type;
+};
+
+
+/* See draft-ietf-ipsec-isakmp-mode-cfg-04.txt, 3.2 */
+struct isakmp_pl_attr {
+       struct isakmp_gen h;
+       u_int8_t type;          /* Exchange type */
+       u_int8_t res2;
+       u_int16_t id;           /* Per transaction id */
+} __attribute__((__packed__));
+            
+/* Exchange type */
+#define ISAKMP_CFG_REQUEST     1
+#define ISAKMP_CFG_REPLY       2
+#define ISAKMP_CFG_SET         3
+#define ISAKMP_CFG_ACK         4
+
+/* IKE fragmentation payload */
+struct isakmp_frag {
+       u_int16_t unknown0;     /* always set to zero? */
+       u_int16_t len;
+       u_int16_t unknown1;     /* always set to 1? */
+       u_int8_t index;
+       u_int8_t flags;
+} __attribute__((__packed__)); 
+
+/* flags */
+#define ISAKMP_FRAG_LAST       1
+
+/* DPD R-U-THERE / R-U-THERE-ACK Payload */
+struct isakmp_pl_ru {
+       struct isakmp_gen h;
+       u_int32_t doi;          /* Domain of Interpretation */
+       u_int8_t proto_id;      /* Protocol-Id */
+       u_int8_t spi_size;      /* SPI Size */
+       u_int16_t type;         /* Notify type */
+       cookie_t  i_ck; /* Initiator Cookie */
+       cookie_t r_ck;  /* Responder cookie*/
+       u_int32_t data;         /* Notification data */
+} __attribute__((__packed__));
+
+/* Load Balance Notification */
+struct isakmp_pl_lb {
+       struct isakmp_gen h;
+       u_int32_t doi;          /* Domain of Interpretation */
+       u_int8_t proto_id;      /* Protocol-Id */
+       u_int8_t spi_size;      /* SPI Size */
+       u_int16_t type;         /* Notify type */
+       cookie_t  i_ck;         /* Initiator Cookie */
+       cookie_t r_ck;          /* Responder cookie*/
+       u_int32_t address;      /* redirect address */
+} __attribute__((__packed__));
+
+#endif /* _ISAKMP_H */
diff --git a/ipsec-tools/racoon/isakmp_agg.c b/ipsec-tools/racoon/isakmp_agg.c
new file mode 100644 (file)
index 0000000..eea7726
--- /dev/null
@@ -0,0 +1,1514 @@
+/* $Id: isakmp_agg.c,v 1.20.2.5 2005/11/21 09:46:23 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Aggressive Exchange (Aggressive Mode) */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "evt.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "isakmp_agg.h"
+#include "isakmp_inf.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
+#ifdef ENABLE_FRAG
+#include "isakmp_frag.h"
+#endif
+#include "vendorid.h"
+#include "strnames.h"
+
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+
+#ifdef HAVE_GSSAPI
+#include "gssapi.h"
+#endif
+
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+
+/*
+ * begin Aggressive Mode as initiator.
+ */
+/*
+ * send to responder
+ *     psk: HDR, SA, KE, Ni, IDi1
+ *     sig: HDR, SA, KE, Ni, IDi1 [, CR ]
+ *   gssapi: HDR, SA, KE, Ni, IDi1, GSSi
+ *     rsa: HDR, SA, [ HASH(1),] KE, <IDi1_b>Pubkey_r, <Ni_b>Pubkey_r
+ *     rev: HDR, SA, [ HASH(1),] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ *          <IDii_b>Ke_i [, <Cert-I_b>Ke_i ]
+ */
+int
+agg_i1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg; /* must be null */
+{
+       struct payload_list *plist = NULL;
+       int need_cr = 0;
+       vchar_t *cr = NULL, *gsstoken = NULL;
+       int error = -1;
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL };
+       int i;
+#endif
+#ifdef ENABLE_HYBRID
+       vchar_t *vid_xauth = NULL;
+       vchar_t *vid_unity = NULL;
+#endif
+#ifdef ENABLE_FRAG
+       vchar_t *vid_frag = NULL;
+#endif
+#ifdef HAVE_GSSAPI
+       int len;
+#endif
+#ifdef ENABLE_DPD
+       vchar_t *vid_dpd = NULL;
+#endif
+
+
+       /* validity check */
+       if (msg != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "msg has to be NULL in this function.\n");
+               goto end;
+       }
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* create isakmp index */
+       memset(&iph1->index, 0, sizeof(iph1->index));
+       isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local);
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+       /* create SA payload for my proposal */
+       iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+       if (iph1->sa == NULL)
+               goto end;
+
+       /* consistency check of proposals */
+       if (iph1->rmconf->dhgrp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "configuration failure about DH group.\n");
+               goto end;
+       }
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->rmconf->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+#ifdef ENABLE_HYBRID
+       /* Do we need Xauth VID? */
+       switch (iph1->rmconf->proposal->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+               if ((vid_xauth = set_vendorid(VENDORID_XAUTH)) == NULL)
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                            "Xauth vendor ID generation failed\n");
+               if ((vid_unity = set_vendorid(VENDORID_UNITY)) == NULL)
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                            "Unity vendor ID generation failed\n");
+               break;
+       default:
+               break;
+       }
+#endif
+
+#ifdef ENABLE_FRAG
+       if (iph1->rmconf->ike_frag) {
+               vid_frag = set_vendorid(VENDORID_FRAG);
+               if (vid_frag != NULL)
+                       vid_frag = isakmp_frag_addcap(vid_frag,
+                           VENDORID_FRAG_AGG);
+               if (vid_frag == NULL)
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Frag vendorID construction failed\n");
+       }               
+#endif
+
+       /* create CR if need */
+       if (iph1->rmconf->send_cr
+        && oakley_needcr(iph1->rmconf->proposal->authmethod)
+        && iph1->rmconf->peerscertfile == NULL) {
+               need_cr = 1;
+               cr = oakley_getcr(iph1);
+               if (cr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get cr buffer.\n");
+                       goto end;
+               }
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "authmethod is %s\n",
+               s_oakley_attr_method(iph1->rmconf->proposal->authmethod));
+#ifdef HAVE_GSSAPI
+       if (iph1->rmconf->proposal->authmethod ==
+           OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+               gssapi_get_itoken(iph1, &len);
+       }
+#endif
+
+       /* set SA payload to propose */
+       plist = isakmp_plist_append(plist, iph1->sa, ISAKMP_NPTYPE_SA);
+
+       /* create isakmp KE payload */
+       plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+       /* create isakmp NONCE payload */
+       plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+       /* create isakmp ID payload */
+       plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+#ifdef HAVE_GSSAPI
+       if (iph1->rmconf->proposal->authmethod ==
+           OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+               gssapi_get_token_to_send(iph1, &gsstoken);
+               plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
+       } else
+#endif
+       /* create isakmp CR payload */
+       if (need_cr)
+               plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+
+#ifdef ENABLE_FRAG
+       if (vid_frag)
+               plist = isakmp_plist_append(plist, vid_frag, ISAKMP_NPTYPE_VID);
+#endif
+#ifdef ENABLE_NATT
+       /* 
+        * set VID payload for NAT-T if NAT-T 
+        * support allowed in the config file 
+        */
+       if (iph1->rmconf->nat_traversal) 
+               plist = isakmp_plist_append_natt_vids(plist, vid_natt);
+#endif
+#ifdef ENABLE_HYBRID
+       if (vid_xauth)
+               plist = isakmp_plist_append(plist, 
+                   vid_xauth, ISAKMP_NPTYPE_VID);
+       if (vid_unity)
+               plist = isakmp_plist_append(plist, 
+                   vid_unity, ISAKMP_NPTYPE_VID);
+#endif
+#ifdef ENABLE_DPD
+       if(iph1->rmconf->dpd){
+               vid_dpd = set_vendorid(VENDORID_DPD);
+               if (vid_dpd != NULL)
+                       plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID);
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+       error = 0;
+
+end:
+       if (cr)
+               vfree(cr);
+       if (gsstoken)
+               vfree(gsstoken);
+#ifdef ENABLE_FRAG
+       if (vid_frag)
+               vfree(vid_frag);
+#endif
+#ifdef ENABLE_NATT
+       for (i = 0; i < MAX_NATT_VID_COUNT && vid_natt[i] != NULL; i++)
+               vfree(vid_natt[i]);
+#endif
+#ifdef ENABLE_DPD
+       if (vid_dpd != NULL)
+               vfree(vid_dpd);
+#endif
+#ifdef ENABLE_HYBRID
+       if (vid_xauth != NULL)
+               vfree(vid_xauth);
+       if (vid_unity != NULL)
+               vfree(vid_unity);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR, SA, KE, Nr, IDr1, HASH_R
+ *     sig: HDR, SA, KE, Nr, IDr1, [ CR, ] [ CERT, ] SIG_R
+ *   gssapi: HDR, SA, KE, Nr, IDr1, GSSr, HASH_R
+ *     rsa: HDR, SA, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i, HASH_R
+ *     rev: HDR, SA, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDir_b>Ke_r, HASH_R
+ */
+int
+agg_i2recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       vchar_t *satmp = NULL;
+       int error = -1;
+       int vid_numeric;
+       int ptype;
+#ifdef ENABLE_HYBRID
+       vchar_t *unity_vid;
+       vchar_t *xauth_vid;
+#endif
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+
+#ifdef ENABLE_NATT
+       int natd_seq = 0;
+       struct natd_payload {
+               int seq;
+               vchar_t *payload;
+               TAILQ_ENTRY(natd_payload) chain;
+       };
+       TAILQ_HEAD(_natd_payload, natd_payload) natd_tree;
+       TAILQ_INIT(&natd_tree);
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       iph1->pl_hash = NULL;
+
+       /* SA payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+
+       if (isakmp_p2ph(&satmp, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_CR:
+                       if (oakley_savecr(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal && 
+                           natt_vendorid(vid_numeric))
+                               natt_handle_vendorid(iph1, vid_numeric);
+#endif
+#ifdef ENABLE_HYBRID
+                       switch (vid_numeric) {
+                       case VENDORID_XAUTH:
+                               iph1->mode_cfg->flags |= 
+                                   ISAKMP_CFG_VENDORID_XAUTH;
+                               break;
+
+                       case VENDORID_UNITY:
+                               iph1->mode_cfg->flags |= 
+                                   ISAKMP_CFG_VENDORID_UNITY;
+                               break;
+                       default:
+                               break;
+                       }
+#endif
+#ifdef ENABLE_DPD
+                       if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
+                               iph1->dpd_support=1;
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                        "remote supports DPD\n");
+                       }
+#endif
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph1);
+                       break;
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (NATT_AVAILABLE(iph1) && iph1->natt_options != NULL &&
+                           pa->type == iph1->natt_options->payload_nat_d) {
+                               struct natd_payload *natd;
+                               natd = (struct natd_payload *)racoon_malloc(sizeof(*natd));
+                               if (!natd)
+                                       goto end;
+
+                               natd->payload = NULL;
+
+                               if (isakmp_p2ph (&natd->payload, pa->ptr) < 0)
+                                       goto end;
+
+                               natd->seq = natd_seq++;
+
+                               TAILQ_INSERT_TAIL(&natd_tree, natd, chain);
+                               break;
+                       }
+                       /* %%% Be lenient here - some servers send natd payloads */
+                       /* when nat not detected                                                                 */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see isakmp_ident_r1() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+       VPTRINIT(iph1->sa_ret);
+
+       /* fix isakmp index */
+       memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck,
+               sizeof(cookie_t));
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1)) {
+               struct natd_payload *natd = NULL;
+               int natd_verified;
+               
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+
+               /* set both bits first so that we can clear them
+                  upon verifying hashes */
+               iph1->natt_flags |= NAT_DETECTED;
+                        
+               while ((natd = TAILQ_FIRST(&natd_tree)) != NULL) {
+                       /* this function will clear appropriate bits bits 
+                          from iph1->natt_flags */
+                       natd_verified = natt_compare_addr_hash (iph1,
+                               natd->payload, natd->seq);
+
+                       plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                               natd->seq - 1,
+                               natd_verified ? "verified" : "doesn't match");
+                       
+                       vfree (natd->payload);
+
+                       TAILQ_REMOVE(&natd_tree, natd, chain);
+                       racoon_free (natd);
+               }
+
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+
+               if (iph1->natt_flags & NAT_DETECTED)
+                       natt_float_ports (iph1);
+       }
+#endif
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->rmconf->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid(iph1) < 0)
+               goto end;
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+       /* validate authentication value */
+       ptype = oakley_validate_auth(iph1);
+       if (ptype != 0) {
+               if (ptype == -1) {
+                       /* message printed inner oakley_validate_auth() */
+                       goto end;
+               }
+               EVT_PUSH(iph1->local, iph1->remote, 
+                   EVTT_PEERPH1AUTH_FAILED, NULL);
+               isakmp_info_send_n1(iph1, ptype, NULL);
+               goto end;
+       }
+
+       if (oakley_checkcr(iph1) < 0) {
+               /* Ignore this error in order to be interoperability. */
+               ;
+       }
+
+       /* change status of isakmp status entry */
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_REMOTE, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (satmp)
+               vfree(satmp);
+       if (error) {
+               VPTRINIT(iph1->dhpub_p);
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+               oakley_delcert(iph1->cr_p);
+               iph1->cr_p = NULL;
+       }
+
+       return error;
+}
+
+/*
+ * send to responder
+ *     psk: HDR, HASH_I
+ *   gssapi: HDR, HASH_I
+ *     sig: HDR, [ CERT, ] SIG_I
+ *     rsa: HDR, HASH_I
+ *     rev: HDR, HASH_I
+ */
+int
+agg_i2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       int need_cert = 0;
+       int error = -1;
+       vchar_t *gsshash = NULL;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* generate HASH to send */
+       plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n");
+       iph1->hash = oakley_ph1hash_common(iph1, GENERATE);
+       if (iph1->hash == NULL) {
+#ifdef HAVE_GSSAPI
+               if (gssapi_more_tokens(iph1))
+                       isakmp_info_send_n1(iph1,
+                           ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL);
+#endif
+               goto end;
+       }
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+#endif  
+               /* set HASH payload */
+               plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+#endif  
+               /* XXX if there is CR or not ? */
+
+               if (oakley_getmycert(iph1) < 0)
+                       goto end;
+
+               if (oakley_getsign(iph1) < 0)
+                       goto end;
+
+               if (iph1->cert != NULL && iph1->rmconf->send_cert)
+                       need_cert = 1;
+
+               /* add CERT payload if there */
+               if (need_cert)
+                       plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+
+               /* add SIG payload */
+               plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
+               break;
+
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               break;
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               gsshash = gssapi_wraphash(iph1);
+               if (gsshash == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to wrap hash\n");
+                       isakmp_info_send_n1(iph1,
+                               ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL);
+                       goto end;
+               }
+
+               plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH);
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "invalid authmethod %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+               break;
+       }
+
+#ifdef ENABLE_NATT
+       /* generate NAT-D payloads */
+       if (NATT_AVAILABLE(iph1))
+       {
+               vchar_t *natd[2] = { NULL, NULL };
+
+               plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n");
+               if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->remote));
+                       goto end;
+               }
+
+               if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->local));
+                       goto end;
+               }
+
+#ifdef __APPLE__
+               /* old Apple version sends natd payloads in the wrong order */
+               if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+               } else
+#endif
+               {
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+               }
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send to responder */
+       if (isakmp_send(iph1, iph1->sendbuf) < 0)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+       if (gsshash)
+               vfree(gsshash);
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, SA, KE, Ni, IDi1
+ *     sig: HDR, SA, KE, Ni, IDi1 [, CR ]
+ *   gssapi: HDR, SA, KE, Ni, IDi1 , GSSi
+ *     rsa: HDR, SA, [ HASH(1),] KE, <IDi1_b>Pubkey_r, <Ni_b>Pubkey_r
+ *     rev: HDR, SA, [ HASH(1),] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ *          <IDii_b>Ke_i [, <Cert-I_b>Ke_i ]
+ */
+int
+agg_r1recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int vid_numeric;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* SA payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+       if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "received payload of type %s\n",
+                       s_isakmp_nptype(pa->type));
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal &&
+                           natt_vendorid(vid_numeric)) {
+                               natt_handle_vendorid(iph1, vid_numeric);
+                               break;
+                       }
+#endif
+#ifdef ENABLE_HYBRID
+                       switch (vid_numeric) {
+                       case VENDORID_XAUTH:
+                               iph1->mode_cfg->flags |= 
+                                   ISAKMP_CFG_VENDORID_XAUTH;
+                               break;
+
+                       case VENDORID_UNITY:
+                               iph1->mode_cfg->flags |= 
+                                   ISAKMP_CFG_VENDORID_UNITY;
+                               break;
+                       default:
+                               break;
+                       }
+#endif
+#ifdef ENABLE_DPD
+                       if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
+                               iph1->dpd_support=1;
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                        "remote supports DPD\n");
+                       }
+#endif
+#ifdef ENABLE_FRAG
+                       if ((vid_numeric == VENDORID_FRAG) &&
+                           (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_AGG))
+                               iph1->frag = 1;
+#endif
+                       break;
+
+               case ISAKMP_NPTYPE_CR:
+                       if (oakley_savecr(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+               default:
+                       /* don't send information, see isakmp_ident_r1() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+#endif
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+
+       if (oakley_checkcr(iph1) < 0) {
+               /* Ignore this error in order to be interoperability. */
+               ;
+       }
+
+       iph1->status = PHASE1ST_MSG1RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (error) {
+               VPTRINIT(iph1->sa);
+               VPTRINIT(iph1->dhpub_p);
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+               oakley_delcert(iph1->cr_p);
+               iph1->cr_p = NULL;
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR, SA, KE, Nr, IDr1, HASH_R
+ *     sig: HDR, SA, KE, Nr, IDr1, [ CR, ] [ CERT, ] SIG_R
+ *   gssapi: HDR, SA, KE, Nr, IDr1, GSSr, HASH_R
+ *     rsa: HDR, SA, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i, HASH_R
+ *     rev: HDR, SA, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDir_b>Ke_r, HASH_R
+ */
+int
+agg_r1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       int need_cr = 0;
+       int need_cert = 0;
+       vchar_t *cr = NULL;
+       vchar_t *vid = NULL;
+       int error = -1;
+#ifdef ENABLE_HYBRID
+       vchar_t *xauth_vid = NULL;
+       vchar_t *unity_vid = NULL;
+#endif
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt = NULL;
+       vchar_t *natd[2] = { NULL, NULL };
+#endif
+#ifdef ENABLE_DPD
+       vchar_t *vid_dpd = NULL;
+#endif
+
+#ifdef HAVE_GSSAPI
+       int gsslen;
+       vchar_t *gsstoken = NULL, *gsshash = NULL;
+       vchar_t *gss_sa = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* set responder's cookie */
+       isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local);
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->rmconf->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid(iph1) < 0)
+               goto end;
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->rmconf->proposal->authmethod ==       
+           OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+               gssapi_get_rtoken(iph1, &gsslen);
+#endif
+
+       /* generate HASH to send */
+       plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_R\n");
+       iph1->hash = oakley_ph1hash_common(iph1, GENERATE);
+       if (iph1->hash == NULL) {
+#ifdef HAVE_GSSAPI
+               if (gssapi_more_tokens(iph1))
+                       isakmp_info_send_n1(iph1,
+                           ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL);
+#endif
+               goto end;
+       }
+
+       /* create CR if need */
+       if (iph1->rmconf->send_cr
+        && oakley_needcr(iph1->approval->authmethod)
+        && iph1->rmconf->peerscertfile == NULL) {
+               need_cr = 1;
+               cr = oakley_getcr(iph1);
+               if (cr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get cr buffer.\n");
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       /* Has the peer announced NAT-T? */
+       if (NATT_AVAILABLE(iph1)) {
+               /* set chosen VID */
+               vid_natt = set_vendorid(iph1->natt_options->version);
+
+               /* generate NAT-D payloads */
+               plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n");
+               if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->remote));
+                       goto end;
+               }
+
+               if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->local));
+                       goto end;
+               }
+       }
+#endif
+#ifdef ENABLE_DPD
+       /* Only send DPD support if remote announced DPD and if DPD support is active */
+       if (iph1->dpd_support && iph1->rmconf->dpd)
+               vid_dpd = set_vendorid(VENDORID_DPD);
+#endif
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               /* set SA payload to reply */
+               plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA);
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* create isakmp NONCE payload */
+               plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+               /* create isakmp ID payload */
+               plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+               /* create isakmp HASH payload */
+               plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH);
+
+               /* append vendor id, if needed */
+               if (vid)
+                       plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+
+               /* create isakmp CR payload if needed */
+               if (need_cr)
+                       plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+#endif
+               /* XXX if there is CR or not ? */
+
+               if (oakley_getmycert(iph1) < 0)
+                       goto end;
+
+               if (oakley_getsign(iph1) < 0)
+                       goto end;
+
+               if (iph1->cert != NULL && iph1->rmconf->send_cert)
+                       need_cert = 1;
+
+               /* set SA payload to reply */
+               plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA);
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* create isakmp NONCE payload */
+               plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+               /* add ID payload */
+               plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+               /* add CERT payload if there */
+               if (need_cert)
+                       plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+
+               /* add SIG payload */
+               plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
+
+               /* append vendor id, if needed */
+               if (vid)
+                       plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+
+#ifdef ENABLE_HYBRID
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) {
+               if ((xauth_vid = set_vendorid(VENDORID_XAUTH)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Cannot create Xauth vendor ID\n");
+                       goto end;
+               }
+               plist = isakmp_plist_append(plist, 
+                   xauth_vid, ISAKMP_NPTYPE_VID);
+       }
+
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_UNITY) {
+               if ((unity_vid = set_vendorid(VENDORID_UNITY)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Cannot create Unity vendor ID\n");
+                       goto end;
+               }
+               plist = isakmp_plist_append(plist, 
+                   unity_vid, ISAKMP_NPTYPE_VID);
+       }
+#endif
+
+               /* create isakmp CR payload if needed */
+               if (need_cr)
+                       plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+               break;
+
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               break;
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               /* create buffer to send isakmp payload */
+               gsshash = gssapi_wraphash(iph1);
+               if (gsshash == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to wrap hash\n");
+                       /*
+                        * This is probably due to the GSS roundtrips not
+                        * being finished yet. Return this error in
+                        * the hope that a fallback to main mode will
+                        * be done.
+                        */
+                       isakmp_info_send_n1(iph1,
+                           ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL);
+                       goto end;
+               }
+               if (iph1->approval->gssid != NULL)
+                       gss_sa = ipsecdoi_setph1proposal(iph1->approval);  
+               else
+                       gss_sa = iph1->sa_ret;
+
+               /* set SA payload to reply */
+               plist = isakmp_plist_append(plist, gss_sa, ISAKMP_NPTYPE_SA);
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* create isakmp NONCE payload */
+               plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+               /* create isakmp ID payload */
+               plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+               /* create GSS payload */
+               gssapi_get_token_to_send(iph1, &gsstoken);
+               plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
+
+               /* create isakmp HASH payload */
+               plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH);
+
+               /* append vendor id, if needed */
+               if (vid)
+                       plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Invalid authmethod %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+               break;
+       }
+
+#ifdef ENABLE_NATT
+       /* append NAT-T payloads */
+       if (vid_natt) {
+               /* chosen VID */
+               plist = isakmp_plist_append(plist, vid_natt, ISAKMP_NPTYPE_VID);
+               /* NAT-D */
+#ifdef __APPLE__
+               /* old Apple version sends natd payloads in the wrong order */
+               if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+               } else
+#endif
+               {
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+               }
+       }
+#endif
+#ifdef ENABLE_DPD
+       if (vid_dpd)
+               plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID);
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 1);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+       if (cr)
+               vfree(cr);
+       if (vid)
+               vfree(vid);
+#ifdef ENABLE_HYBRID
+       if (xauth_vid)
+               vfree(xauth_vid);
+       if (unity_vid)
+               vfree(unity_vid);
+#endif
+#ifdef HAVE_GSSAPI
+       if (gsstoken)
+               vfree(gsstoken);
+       if (gsshash)
+               vfree(gsshash);
+       if (gss_sa != iph1->sa_ret)
+               vfree(gss_sa);
+#endif
+#ifdef ENABLE_DPD
+       if (vid_dpd)
+               vfree(vid_dpd);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, HASH_I
+ *   gssapi: HDR, HASH_I
+ *     sig: HDR, [ CERT, ] SIG_I
+ *     rsa: HDR, HASH_I
+ *     rev: HDR, HASH_I
+ */
+int
+agg_r2recv(iph1, msg0)
+       struct ph1handle *iph1;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int ptype;
+
+#ifdef ENABLE_NATT
+       int natd_seq = 0;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* decrypting if need. */
+       /* XXX configurable ? */
+       if (ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               msg = oakley_do_decrypt(iph1, msg0,
+                                       iph1->ivm->iv, iph1->ivm->ive);
+               if (msg == NULL)
+                       goto end;
+       } else
+               msg = vdup(msg0);
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       iph1->pl_hash = NULL;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph1);
+                       break;
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (NATT_AVAILABLE(iph1) && iph1->natt_options != NULL &&
+                               pa->type == iph1->natt_options->payload_nat_d)
+                       {
+                               vchar_t *natd_received = NULL;
+                               int natd_verified;
+                               
+                               if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
+                                       goto end;
+                               
+                               if (natd_seq == 0)
+                                       iph1->natt_flags |= NAT_DETECTED;
+                               
+                               natd_verified = natt_compare_addr_hash (iph1,
+                                       natd_received, natd_seq++);
+                               
+                               plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                                       natd_seq - 1,
+                                       natd_verified ? "verified" : "doesn't match");
+                               
+                               vfree (natd_received);
+                               break;
+                       }
+                       /* %%%% Be lenient here - some servers send natd payloads */
+                       /* when no nat is detected                                                                */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see isakmp_ident_r1() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+#endif
+
+       /* validate authentication value */
+       ptype = oakley_validate_auth(iph1);
+       if (ptype != 0) {
+               if (ptype == -1) {
+                       /* message printed inner oakley_validate_auth() */
+                       goto end;
+               }
+               EVT_PUSH(iph1->local, iph1->remote, 
+                   EVTT_PEERPH1AUTH_FAILED, NULL);
+               isakmp_info_send_n1(iph1, ptype, NULL);
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (msg)
+               vfree(msg);
+       if (error) {
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+       }
+
+       return error;
+}
+
+/*
+ * status update and establish isakmp sa.
+ */
+int
+agg_r2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* IV synchronized when packet encrypted. */
+       /* see handler.h about IV synchronization. */
+       if (ISSET(((struct isakmp *)msg->v)->flags, ISAKMP_FLAG_E))
+               memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l);
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+       return error;
+}
diff --git a/ipsec-tools/racoon/isakmp_agg.h b/ipsec-tools/racoon/isakmp_agg.h
new file mode 100644 (file)
index 0000000..8bf35ed
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id: isakmp_agg.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_AGG_H
+#define _ISAKMP_AGG_H
+
+extern int agg_i1send __P((struct ph1handle *, vchar_t *));
+extern int agg_i2recv __P((struct ph1handle *, vchar_t *));
+extern int agg_i2send __P((struct ph1handle *, vchar_t *));
+
+extern int agg_r1recv __P((struct ph1handle *, vchar_t *));
+extern int agg_r1send __P((struct ph1handle *, vchar_t *));
+extern int agg_r2recv __P((struct ph1handle *, vchar_t *));
+extern int agg_r2send __P((struct ph1handle *, vchar_t *));
+
+#endif /* _ISAKMP_AGG_H */
diff --git a/ipsec-tools/racoon/isakmp_base.c b/ipsec-tools/racoon/isakmp_base.c
new file mode 100644 (file)
index 0000000..f33b733
--- /dev/null
@@ -0,0 +1,1237 @@
+/*     $KAME: isakmp_base.c,v 1.49 2003/11/13 02:30:20 sakane Exp $    */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Base Exchange (Base Mode) */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "evt.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "isakmp_base.h"
+#include "isakmp_inf.h"
+#include "vendorid.h"
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#ifdef ENABLE_FRAG
+#include "isakmp_frag.h"
+#endif
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+
+/* %%%
+ * begin Identity Protection Mode as initiator.
+ */
+/*
+ * send to responder
+ *     psk: HDR, SA, Idii, Ni_b
+ *     sig: HDR, SA, Idii, Ni_b
+ *     rsa: HDR, SA, [HASH(1),] <IDii_b>Pubkey_r, <Ni_b>Pubkey_r
+ *     rev: HDR, SA, [HASH(1),] <Ni_b>Pubkey_r, <IDii_b>Ke_i
+ */
+int
+base_i1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg; /* must be null */
+{
+       struct payload_list *plist = NULL;
+       int error = -1;
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL };
+       int i, vid_natt_i = 0;
+#endif
+#ifdef ENABLE_FRAG
+       vchar_t *vid_frag = NULL;
+#endif
+
+       /* validity check */
+       if (msg != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "msg has to be NULL in this function.\n");
+               goto end;
+       }
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* create isakmp index */
+       memset(&iph1->index, 0, sizeof(iph1->index));
+       isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local);
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+       /* create SA payload for my proposal */
+       iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+       if (iph1->sa == NULL)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+#ifdef ENABLE_FRAG
+       if (iph1->rmconf->ike_frag) {
+               vid_frag = set_vendorid(VENDORID_FRAG);
+               if (vid_frag != NULL)
+                       vid_frag = isakmp_frag_addcap(vid_frag, 
+                           VENDORID_FRAG_BASE);
+               if (vid_frag == NULL)
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Frag vendorID construction failed\n");
+       }
+#endif
+#ifdef ENABLE_NATT
+       /* Is NAT-T support allowed in the config file? */
+       if (iph1->rmconf->nat_traversal) {
+               /* Advertise NAT-T capability */
+               memset (vid_natt, 0, sizeof (vid_natt));
+#ifdef VENDORID_NATT_00
+               if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_00)) != NULL)
+                       vid_natt_i++;
+#endif
+#ifdef VENDORID_NATT_02
+               if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02)) != NULL)
+                       vid_natt_i++;
+#endif
+#ifdef VENDORID_NATT_02_N
+               if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02_N)) != NULL)
+                       vid_natt_i++;
+#endif
+#ifdef VENDORID_NATT_RFC
+               if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_RFC)) != NULL)
+                       vid_natt_i++;
+#endif
+       }
+#endif
+
+       /* set SA payload to propose */
+       plist = isakmp_plist_append(plist, iph1->sa, ISAKMP_NPTYPE_SA);
+
+       /* create isakmp ID payload */
+       plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+       /* create isakmp NONCE payload */
+       plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+#ifdef ENABLE_FRAG
+       if (vid_frag)
+               plist = isakmp_plist_append(plist, vid_frag, ISAKMP_NPTYPE_VID);
+#endif
+#ifdef ENABLE_NATT
+       /* set VID payload for NAT-T */
+       for (i = 0; i < vid_natt_i; i++)
+               plist = isakmp_plist_append(plist, vid_natt[i], ISAKMP_NPTYPE_VID);
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+#endif
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+       error = 0;
+
+end:
+#ifdef ENABLE_FRAG
+       if (vid_frag)
+               vfree(vid_frag);
+#endif 
+#ifdef ENABLE_NATT
+       for (i = 0; i < vid_natt_i; i++)
+               vfree(vid_natt[i]);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR, SA, Idir, Nr_b
+ *     sig: HDR, SA, Idir, Nr_b, [ CR ]
+ *     rsa: HDR, SA, <IDir_b>PubKey_i, <Nr_b>PubKey_i
+ *     rev: HDR, SA, <Nr_b>PubKey_i, <IDir_b>Ke_r
+ */
+int
+base_i2recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       vchar_t *satmp = NULL;
+       int error = -1;
+       int vid_numeric;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* SA payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+       if (isakmp_p2ph(&satmp, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
+                         natt_handle_vendorid(iph1, vid_numeric);
+#endif
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       if (iph1->nonce_p == NULL || iph1->id_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+#endif
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+       VPTRINIT(iph1->sa_ret);
+
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_REMOTE, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (satmp)
+               vfree(satmp);
+
+       if (error) {
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+       }
+
+       return error;
+}
+
+/*
+ * send to responder
+ *     psk: HDR, KE, HASH_I
+ *     sig: HDR, KE, [ CR, ] [CERT,] SIG_I
+ *     rsa: HDR, KE, HASH_I
+ *     rev: HDR, <KE>Ke_i, HASH_I
+ */
+int
+base_i2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       vchar_t *vid = NULL;
+       int need_cert = 0;
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* fix isakmp index */
+       memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck,
+               sizeof(cookie_t));
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->approval->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* generate SKEYID to compute hash if not signature mode */
+       if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG
+        && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG) {
+               if (oakley_skeyid(iph1) < 0)
+                       goto end;
+       }
+
+       /* generate HASH to send */
+       plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n");
+       iph1->hash = oakley_ph1hash_base_i(iph1, GENERATE);
+       if (iph1->hash == NULL)
+               goto end;
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               vid = set_vendorid(iph1->approval->vendorid);
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* create isakmp HASH payload */
+               plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH);
+
+               /* append vendor id, if needed */
+               if (vid)
+                       plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+               /* XXX if there is CR or not ? */
+
+               if (oakley_getmycert(iph1) < 0)
+                       goto end;
+
+               if (oakley_getsign(iph1) < 0)
+                       goto end;
+
+               if (iph1->cert && iph1->rmconf->send_cert)
+                       need_cert = 1;
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* add CERT payload if there */
+               if (need_cert)
+                       plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+
+               /* add SIG payload */
+               plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               /* ... */
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "invalid authmethod %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+               break;
+       }
+
+#ifdef ENABLE_NATT
+       /* generate NAT-D payloads */
+       if (NATT_AVAILABLE(iph1))
+       {
+               vchar_t *natd[2] = { NULL, NULL };
+
+               plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n");
+               if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->remote));
+                       goto end;
+               }
+
+               if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->local));
+                       goto end;
+               }
+
+#ifdef __APPLE__
+               /* old Apple version sends natd payloads in the wrong order */
+               if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+               } else
+#endif
+               {
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+               }
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG2SENT;
+
+       error = 0;
+
+end:
+       if (vid)
+               vfree(vid);
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR, KE, HASH_R
+ *     sig: HDR, KE, [CERT,] SIG_R
+ *     rsa: HDR, KE, HASH_R
+ *     rev: HDR, <KE>_Ke_r, HASH_R
+ */
+int
+base_i3recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int ptype;
+#ifdef ENABLE_NATT
+       vchar_t *natd_received;
+       int natd_seq = 0, natd_verified;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (NATT_AVAILABLE(iph1) && iph1->natt_options &&
+                           pa->type == iph1->natt_options->payload_nat_d) {
+                               natd_received = NULL;
+                               if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
+                                       goto end;
+                        
+                               /* set both bits first so that we can clear them
+                                  upon verifying hashes */
+                               if (natd_seq == 0)
+                                       iph1->natt_flags |= NAT_DETECTED;
+                        
+                               /* this function will clear appropriate bits bits 
+                                  from iph1->natt_flags */
+                               natd_verified = natt_compare_addr_hash (iph1,
+                                       natd_received, natd_seq++);
+                        
+                               plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                                       natd_seq - 1,
+                                       natd_verified ? "verified" : "doesn't match");
+                        
+                               vfree (natd_received);
+                               break;
+                       }
+                       /* %%%% Be lenient here - some servers send natd payloads */
+                       /* when no nat is detected                                                                */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1)) {
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+               if (iph1->natt_flags & NAT_DETECTED)
+                       natt_float_ports (iph1);
+       }
+#endif
+
+       /* payload existency check */
+       /* validate authentication value */
+       ptype = oakley_validate_auth(iph1);
+       if (ptype != 0) {
+               if (ptype == -1) {
+                       /* message printed inner oakley_validate_auth() */
+                       goto end;
+               }
+               EVT_PUSH(iph1->local, iph1->remote, 
+                   EVTT_PEERPH1AUTH_FAILED, NULL);
+               isakmp_info_send_n1(iph1, ptype, NULL);
+               goto end;
+       }
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYID to compute hash if signature mode */
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_RSASIG
+        || iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_DSSSIG) {
+               if (oakley_skeyid(iph1) < 0)
+                       goto end;
+       }
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l);
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       iph1->status = PHASE1ST_MSG3RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+
+       if (error) {
+               VPTRINIT(iph1->dhpub_p);
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+       }
+
+       return error;
+}
+
+/*
+ * status update and establish isakmp sa.
+ */
+int
+base_i3send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG3RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, SA, Idii, Ni_b
+ *     sig: HDR, SA, Idii, Ni_b
+ *     rsa: HDR, SA, [HASH(1),] <IDii_b>Pubkey_r, <Ni_b>Pubkey_r
+ *     rev: HDR, SA, [HASH(1),] <Ni_b>Pubkey_r, <IDii_b>Ke_i
+ */
+int
+base_r1recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int vid_numeric;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       /*
+        * NOTE: XXX even if multiple VID, we'll silently ignore those.
+        */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* check the position of SA payload */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+       if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
+                               natt_handle_vendorid(iph1, vid_numeric);
+#endif
+#ifdef ENABLE_FRAG
+                       if ((vid_numeric == VENDORID_FRAG) &&
+                           (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_BASE))
+                               iph1->frag = 1;
+#endif
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       if (iph1->nonce_p == NULL || iph1->id_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+#endif
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG1RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+
+       if (error) {
+               VPTRINIT(iph1->sa);
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR, SA, Idir, Nr_b
+ *     sig: HDR, SA, Idir, Nr_b, [ CR ]
+ *     rsa: HDR, SA, <IDir_b>PubKey_i, <Nr_b>PubKey_i
+ *     rev: HDR, SA, <Nr_b>PubKey_i, <IDir_b>Ke_r
+ */
+int
+base_r1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       int error = -1;
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* set responder's cookie */
+       isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local);
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+       /* set SA payload to reply */
+       plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA);
+
+       /* create isakmp ID payload */
+       plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+       /* create isakmp NONCE payload */
+       plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+#ifdef ENABLE_NATT
+       /* has the peer announced nat-t? */
+       if (NATT_AVAILABLE(iph1))
+               vid_natt = set_vendorid(iph1->natt_options->version);
+       if (vid_natt)
+               plist = isakmp_plist_append(plist, vid_natt, ISAKMP_NPTYPE_VID);
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+#ifdef ENABLE_NATT
+       if (vid_natt)
+               vfree(vid_natt);
+#endif
+
+       VPTRINIT(iph1->sa_ret);
+
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, KE, HASH_I
+ *     sig: HDR, KE, [ CR, ] [CERT,] SIG_I
+ *     rsa: HDR, KE, HASH_I
+ *     rev: HDR, <KE>Ke_i, HASH_I
+ */
+int
+base_r2recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int ptype;
+#ifdef ENABLE_NATT
+       int natd_seq = 0;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       iph1->pl_hash = NULL;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (pa->type == iph1->natt_options->payload_nat_d)
+                       {
+                               vchar_t *natd_received = NULL;
+                               int natd_verified;
+                               
+                               if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
+                                       goto end;
+                               
+                               if (natd_seq == 0)
+                                       iph1->natt_flags |= NAT_DETECTED;
+                               
+                               natd_verified = natt_compare_addr_hash (iph1,
+                                       natd_received, natd_seq++);
+                               
+                               plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                                       natd_seq - 1,
+                                       natd_verified ? "verified" : "doesn't match");
+                               
+                               vfree (natd_received);
+                               break;
+                       }
+                       /* %%%% Be lenient here - some servers send natd payloads */
+                       /* when no nat is detected                                                                */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->approval->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYID */
+       if (oakley_skeyid(iph1) < 0)
+               goto end;
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+#endif
+
+       /* payload existency check */
+       /* validate authentication value */
+       ptype = oakley_validate_auth(iph1);
+       if (ptype != 0) {
+               if (ptype == -1) {
+                       /* message printed inner oakley_validate_auth() */
+                       goto end;
+               }
+               EVT_PUSH(iph1->local, iph1->remote, 
+                   EVTT_PEERPH1AUTH_FAILED, NULL);
+               isakmp_info_send_n1(iph1, ptype, NULL);
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+
+       if (error) {
+               VPTRINIT(iph1->dhpub_p);
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR, KE, HASH_R
+ *     sig: HDR, KE, [CERT,] SIG_R
+ *     rsa: HDR, KE, HASH_R
+ *     rev: HDR, <KE>_Ke_r, HASH_R
+ */
+int
+base_r2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       vchar_t *vid = NULL;
+       int need_cert = 0;
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* generate HASH to send */
+       plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n");
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               iph1->hash = oakley_ph1hash_common(iph1, GENERATE);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               iph1->hash = oakley_ph1hash_base_r(iph1, GENERATE);
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid authentication method %d\n",
+                       iph1->approval->authmethod);
+               goto end; 
+       }
+       if (iph1->hash == NULL)
+               goto end;
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               vid = set_vendorid(iph1->approval->vendorid);
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* create isakmp HASH payload */
+               plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH);
+
+               /* append vendor id, if needed */
+               if (vid)
+                       plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+               /* XXX if there is CR or not ? */
+
+               if (oakley_getmycert(iph1) < 0)
+                       goto end;
+
+               if (oakley_getsign(iph1) < 0)
+                       goto end;
+
+               if (iph1->cert && iph1->rmconf->send_cert)
+                       need_cert = 1;
+
+               /* create isakmp KE payload */
+               plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+               /* add CERT payload if there */
+               if (need_cert)
+                       plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+               /* add SIG payload */
+               plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               /* ... */
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "invalid authmethod %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+               break;
+       }
+
+#ifdef ENABLE_NATT
+       /* generate NAT-D payloads */
+       if (NATT_AVAILABLE(iph1))
+       {
+               vchar_t *natd[2] = { NULL, NULL };
+
+               plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n");
+               if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->remote));
+                       goto end;
+               }
+
+               if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->local));
+                       goto end;
+               }
+
+#ifdef __APPLE__
+               /* old Apple version sends natd payloads in the wrong order */
+               if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+               } else
+#endif
+               {
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+               }
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send HDR;KE;NONCE to responder */
+       if (isakmp_send(iph1, iph1->sendbuf) < 0)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+       if (vid)
+               vfree(vid);
+       return error;
+}
diff --git a/ipsec-tools/racoon/isakmp_base.h b/ipsec-tools/racoon/isakmp_base.h
new file mode 100644 (file)
index 0000000..d6ecd63
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: isakmp_base.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_BASE_H
+#define _ISAKMP_BASE_H
+
+extern int base_i1send __P((struct ph1handle *, vchar_t *));
+extern int base_i2recv __P((struct ph1handle *, vchar_t *));
+extern int base_i2send __P((struct ph1handle *, vchar_t *));
+extern int base_i3recv __P((struct ph1handle *, vchar_t *));
+extern int base_i3send __P((struct ph1handle *, vchar_t *));
+
+extern int base_r1recv __P((struct ph1handle *, vchar_t *));
+extern int base_r1send __P((struct ph1handle *, vchar_t *));
+extern int base_r2recv __P((struct ph1handle *, vchar_t *));
+extern int base_r2send __P((struct ph1handle *, vchar_t *));
+
+#endif /* _ISAKMP_BASE_H */
diff --git a/ipsec-tools/racoon/isakmp_cfg.c b/ipsec-tools/racoon/isakmp_cfg.c
new file mode 100644 (file)
index 0000000..56e96de
--- /dev/null
@@ -0,0 +1,1600 @@
+/* $Id: isakmp_cfg.c,v 1.26.2.7 2006/01/07 23:50:42 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004-2006 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#ifdef HAVE_LIBRADIUS
+#include <sys/utsname.h>
+#include <radlib.h>
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "handler.h"
+#include "evt.h"
+#include "throttle.h"
+#include "remoteconf.h"
+#include "crypto_openssl.h"
+#include "isakmp_inf.h"
+#include "isakmp_xauth.h"
+#include "isakmp_unity.h"
+#include "isakmp_cfg.h"
+#include "strnames.h"
+#include "admin.h"
+#include "privsep.h"
+
+struct isakmp_cfg_config isakmp_cfg_config = {
+       0x00000000,     /* network4 */
+       0x00000000,     /* netmask4 */
+       0x00000000,     /* dns4 */
+       0x00000000,     /* nbns4 */
+       NULL,           /* pool */
+       ISAKMP_CFG_AUTH_SYSTEM,         /* authsource */
+       ISAKMP_CFG_CONF_LOCAL,          /* confsource */
+       ISAKMP_CFG_ACCT_NONE,           /* accounting */
+       ISAKMP_CFG_MAX_CNX,             /* pool_size */
+       THROTTLE_PENALTY,               /* auth_throttle */
+       ISAKMP_CFG_MOTD,                /* motd */
+       0,                              /* pfs_group */
+       0,                              /* save_passwd */
+};
+
+static vchar_t *buffer_cat(vchar_t *s, vchar_t *append);
+static vchar_t *isakmp_cfg_net(struct ph1handle *, struct isakmp_data *);
+#if 0
+static vchar_t *isakmp_cfg_void(struct ph1handle *, struct isakmp_data *);
+#endif
+static vchar_t *isakmp_cfg_addr4(struct ph1handle *, 
+                                struct isakmp_data *, in_addr_t *);
+static void isakmp_cfg_getaddr4(struct isakmp_data *, struct in_addr *);
+
+#define ISAKMP_CFG_LOGIN       1
+#define ISAKMP_CFG_LOGOUT      2
+static int isakmp_cfg_accounting(struct ph1handle *, int);
+#ifdef HAVE_LIBRADIUS
+static int isakmp_cfg_accounting_radius(struct ph1handle *, int);
+#endif
+
+/* 
+ * Handle an ISAKMP config mode packet
+ * We expect HDR, HASH, ATTR
+ */
+void
+isakmp_cfg_r(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct isakmp *packet;
+       struct isakmp_gen *ph;
+       int tlen;
+       char *npp;
+       int np;
+       vchar_t *dmsg;
+       struct isakmp_ivm *ivm;
+
+       /* Check that the packet is long enough to have a header */
+       if (msg->l < sizeof(*packet)) {
+            plog(LLV_ERROR, LOCATION, NULL, "Unexpected short packet\n");
+            return;
+       }
+
+       packet = (struct isakmp *)msg->v;
+
+       /* Is it encrypted? It should be encrypted */
+       if ((packet->flags & ISAKMP_FLAG_E) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "User credentials sent in cleartext!\n");
+               return;
+       }
+
+       /* 
+        * Decrypt the packet. If this is the beginning of a new
+        * exchange, reinitialize the IV
+        */
+       if (iph1->mode_cfg->ivm == NULL)
+               iph1->mode_cfg->ivm = 
+                   isakmp_cfg_newiv(iph1, packet->msgid);
+       ivm = iph1->mode_cfg->ivm;
+
+       dmsg = oakley_do_decrypt(iph1, msg, ivm->iv, ivm->ive);
+       if (dmsg == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "failed to decrypt message\n");
+               return;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "MODE_CFG packet\n");
+       plogdump(LLV_DEBUG, dmsg->v, dmsg->l);
+
+       /* Now work with the decrypted packet */
+       packet = (struct isakmp *)dmsg->v;
+       tlen = dmsg->l - sizeof(*packet);
+       ph = (struct isakmp_gen *)(packet + 1);
+
+       np = packet->np;
+       while ((tlen > 0) && (np != ISAKMP_NPTYPE_NONE)) {
+               /* Check that the payload header fits in the packet */
+               if (tlen < sizeof(*ph)) {
+                        plog(LLV_WARNING, LOCATION, NULL, 
+                             "Short payload header\n");
+                        goto out;
+               }
+
+               /* Check that the payload fits in the packet */
+               if (tlen < ntohs(ph->len)) {
+                       plog(LLV_WARNING, LOCATION, NULL, 
+                             "Short payload\n");
+                       goto out;
+               }
+               
+               plog(LLV_DEBUG, LOCATION, NULL, "Seen payload %d\n", np);
+               plogdump(LLV_DEBUG, ph, ntohs(ph->len));
+
+               switch(np) {
+               case ISAKMP_NPTYPE_HASH: {
+                       vchar_t *check;
+                       vchar_t *payload;
+                       size_t plen;
+                       struct isakmp_gen *nph;
+
+                       plen = ntohs(ph->len);
+                       nph = (struct isakmp_gen *)((char *)ph + plen);
+                       plen = ntohs(nph->len);
+
+                       if ((payload = vmalloc(plen)) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Cannot allocate memory\n");
+                               goto out;
+                       }
+                       memcpy(payload->v, nph, plen);
+
+                       if ((check = oakley_compute_hash1(iph1, 
+                           packet->msgid, payload)) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Cannot compute hash\n");
+                               vfree(payload);
+                               goto out;
+                       }
+
+                       if (memcmp(ph + 1, check->v, check->l) != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Hash verification failed\n");
+                               vfree(payload);
+                               vfree(check);
+                               goto out;
+                       }
+                       vfree(payload);
+                       vfree(check);
+                       break;
+               }
+               case ISAKMP_NPTYPE_ATTR: {
+                       struct isakmp_pl_attr *attrpl;
+
+                       attrpl = (struct isakmp_pl_attr *)ph;
+                       isakmp_cfg_attr_r(iph1, packet->msgid, attrpl);
+
+                       break;
+               }
+               default:
+                        plog(LLV_WARNING, LOCATION, NULL, 
+                             "Unexpected next payload %d\n", np);
+                        /* Skip to the next payload */
+                        break;
+               }
+
+               /* Move to the next payload */
+               np = ph->np;
+               tlen -= ntohs(ph->len);
+               npp = (char *)ph;
+               ph = (struct isakmp_gen *)(npp + ntohs(ph->len));
+       }
+
+out:
+       vfree(dmsg);
+}
+
+int
+isakmp_cfg_attr_r(iph1, msgid, attrpl) 
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+       struct isakmp_pl_attr *attrpl;
+{
+       int type = attrpl->type;
+
+       switch (type) {
+       case ISAKMP_CFG_ACK:
+               /* ignore, but this is the time to reinit the IV */
+               oakley_delivm(iph1->mode_cfg->ivm);
+               iph1->mode_cfg->ivm = NULL;
+               return 0;
+               break;
+
+       case ISAKMP_CFG_REPLY:
+               return isakmp_cfg_reply(iph1, attrpl);
+               break;
+
+       case ISAKMP_CFG_REQUEST:
+               iph1->msgid = msgid;
+               return isakmp_cfg_request(iph1, attrpl);
+               break;
+
+       case ISAKMP_CFG_SET:
+               iph1->msgid = msgid;
+               return isakmp_cfg_set(iph1, attrpl);
+               break;
+
+       default:
+               plog(LLV_WARNING, LOCATION, NULL,
+                    "Unepected configuration exchange type %d\n", type);
+               return -1;
+               break;
+       }
+
+       return 0;
+}
+
+int
+isakmp_cfg_reply(iph1, attrpl)
+       struct ph1handle *iph1;
+       struct isakmp_pl_attr *attrpl;
+{
+       struct isakmp_data *attr;
+       int tlen;
+       size_t alen;
+       char *npp;
+       int type;
+       struct sockaddr_in *sin;
+
+       tlen = ntohs(attrpl->h.len);
+       attr = (struct isakmp_data *)(attrpl + 1);
+       tlen -= sizeof(*attrpl);
+       
+       while (tlen > 0) {
+               type = ntohs(attr->type);
+
+               /* Handle short attributes */
+               if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
+                       type &= ~ISAKMP_GEN_MASK;
+
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                            "Short attribute %d = %d\n", 
+                            type, ntohs(attr->lorv));
+
+                       switch (type) {
+                       case XAUTH_TYPE:
+                               xauth_attr_reply(iph1, attr, ntohs(attrpl->id));
+                               break;
+
+                       default:
+                               plog(LLV_WARNING, LOCATION, NULL,
+                                    "Ignored short attribute %d\n", type);
+                               break;
+                       }
+
+                       tlen -= sizeof(*attr);
+                       attr++;
+                       continue;
+               }
+
+               type = ntohs(attr->type);
+               alen = ntohs(attr->lorv);
+
+               /* Check that the attribute fit in the packet */
+               if (tlen < alen) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Short attribute %d\n", type);
+                       return -1;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                    "Attribute %d, len %zu\n", type, alen);
+
+               switch(type) {
+               case XAUTH_TYPE:
+               case XAUTH_USER_NAME:
+               case XAUTH_USER_PASSWORD:
+               case XAUTH_PASSCODE:
+               case XAUTH_MESSAGE:
+               case XAUTH_CHALLENGE:
+               case XAUTH_DOMAIN:
+               case XAUTH_STATUS:
+               case XAUTH_NEXT_PIN:
+               case XAUTH_ANSWER:
+                       xauth_attr_reply(iph1, attr, ntohs(attrpl->id));
+                       break;
+               case INTERNAL_IP4_ADDRESS:
+                       isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->addr4);
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_ADDR4;
+                       break;
+               case INTERNAL_IP4_NETMASK:
+                       isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->mask4);
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_MASK4;
+                       break;
+               case INTERNAL_IP4_DNS:
+                       isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->dns4);
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_DNS4;
+                       break;
+               case INTERNAL_IP4_NBNS:
+                       isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->wins4);
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_WINS4;
+                       break;
+               case INTERNAL_IP4_SUBNET:
+               case INTERNAL_ADDRESS_EXPIRY:
+               case UNITY_BANNER:
+               case UNITY_SAVE_PASSWD:
+               case UNITY_DEF_DOMAIN:
+               case UNITY_SPLITDNS_NAME:
+               case UNITY_SPLIT_INCLUDE:
+               case UNITY_NATT_PORT:
+               case UNITY_PFS:
+               case UNITY_FW_TYPE:
+               case UNITY_BACKUP_SERVERS:
+               case UNITY_DDNS_HOSTNAME:
+               default:
+                       plog(LLV_WARNING, LOCATION, NULL,
+                            "Ignored attribute %d\n", type);
+                       break;
+               }
+
+               npp = (char *)attr;
+               attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen);
+               tlen -= (sizeof(*attr) + alen);
+       }
+
+       /* 
+        * Call the SA up script hook now that we have the configuration
+        * It is done at the end of phase 1 if ISAKMP mode config is not
+        * requested.
+        */
+       if ((iph1->status == PHASE1ST_ESTABLISHED) && 
+           iph1->rmconf->mode_cfg)
+               script_hook(iph1, SCRIPT_PHASE1_UP);
+
+#ifdef ENABLE_ADMINPORT
+       {
+               vchar_t *buf;
+
+               alen = ntohs(attrpl->h.len) - sizeof(*attrpl);
+               if ((buf = vmalloc(alen)) == NULL) {
+                       plog(LLV_WARNING, LOCATION, NULL, 
+                           "Cannot allocate memory: %s\n", strerror(errno));
+               } else {
+                       memcpy(buf->v, attrpl + 1, buf->l);
+                       EVT_PUSH(iph1->local, iph1->remote, 
+                           EVTT_ISAKMP_CFG_DONE, buf);
+                       vfree(buf);
+               }
+       }
+#endif
+
+       return 0;
+}
+
+int
+isakmp_cfg_request(iph1, attrpl)
+       struct ph1handle *iph1;
+       struct isakmp_pl_attr *attrpl;
+{
+       struct isakmp_data *attr;
+       int tlen;
+       size_t alen;
+       char *npp;
+       vchar_t *payload;
+       struct isakmp_pl_attr *reply;
+       vchar_t *reply_attr;
+       int type;
+       int error = -1;
+
+       if ((payload = vmalloc(sizeof(*reply))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return -1;
+       }
+       memset(payload->v, 0, sizeof(*reply));
+
+       tlen = ntohs(attrpl->h.len);
+       attr = (struct isakmp_data *)(attrpl + 1);
+       tlen -= sizeof(*attrpl);
+       
+       while (tlen > 0) {
+               reply_attr = NULL;
+               type = ntohs(attr->type);
+
+               /* Handle short attributes */
+               if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
+                       type &= ~ISAKMP_GEN_MASK;
+
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                            "Short attribute %d = %d\n", 
+                            type, ntohs(attr->lorv));
+
+                       switch (type) {
+                       case XAUTH_TYPE:
+                               reply_attr = isakmp_xauth_req(iph1, attr);
+                               break;
+                       default:
+                               plog(LLV_WARNING, LOCATION, NULL,
+                                    "Ignored short attribute %d\n", type);
+                               break;
+                       }
+
+                       tlen -= sizeof(*attr);
+                       attr++;
+
+                       if (reply_attr != NULL) {
+                               payload = buffer_cat(payload, reply_attr);
+                               vfree(reply_attr);
+                       }
+
+                       continue;
+               }
+
+               type = ntohs(attr->type);
+               alen = ntohs(attr->lorv);
+
+               /* Check that the attribute fit in the packet */
+               if (tlen < alen) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Short attribute %d\n", type);
+                       goto end;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                    "Attribute %d, len %zu\n", type, alen);
+
+               switch(type) {
+               case INTERNAL_IP4_ADDRESS:
+               case INTERNAL_IP4_NETMASK:
+               case INTERNAL_IP4_DNS:
+               case INTERNAL_IP4_NBNS:
+               case INTERNAL_IP4_SUBNET:
+                       reply_attr = isakmp_cfg_net(iph1, attr);
+                       break;
+
+               case XAUTH_TYPE:
+               case XAUTH_USER_NAME:
+               case XAUTH_USER_PASSWORD:
+               case XAUTH_PASSCODE:
+               case XAUTH_MESSAGE:
+               case XAUTH_CHALLENGE:
+               case XAUTH_DOMAIN:
+               case XAUTH_STATUS:
+               case XAUTH_NEXT_PIN:
+               case XAUTH_ANSWER:
+                       reply_attr = isakmp_xauth_req(iph1, attr);
+                       break;
+
+               case APPLICATION_VERSION:
+                       reply_attr = isakmp_cfg_string(iph1, 
+                           attr, ISAKMP_CFG_RACOON_VERSION);
+                       break;
+
+               case UNITY_BANNER:
+               case UNITY_PFS:
+               case UNITY_SAVE_PASSWD:
+               case UNITY_DEF_DOMAIN:
+               case UNITY_DDNS_HOSTNAME:
+               case UNITY_FW_TYPE:
+               case UNITY_SPLITDNS_NAME:
+               case UNITY_SPLIT_INCLUDE:
+               case UNITY_NATT_PORT:
+               case UNITY_BACKUP_SERVERS:
+                       reply_attr = isakmp_unity_req(iph1, attr);
+                       break;
+
+               case INTERNAL_ADDRESS_EXPIRY:
+               default:
+                       plog(LLV_WARNING, LOCATION, NULL,
+                            "Ignored attribute %d\n", type);
+                       break;
+               }
+
+               npp = (char *)attr;
+               attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen);
+               tlen -= (sizeof(*attr) + alen);
+
+               if (reply_attr != NULL) {
+                       payload = buffer_cat(payload, reply_attr);
+                       vfree(reply_attr);
+               }
+
+       }
+
+       reply = (struct isakmp_pl_attr *)payload->v;
+       reply->h.len = htons(payload->l);
+       reply->type = ISAKMP_CFG_REPLY;
+       reply->id = attrpl->id;
+
+       error = isakmp_cfg_send(iph1, payload, 
+           ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
+
+       /* Reinit the IV */
+       oakley_delivm(iph1->mode_cfg->ivm);
+       iph1->mode_cfg->ivm = NULL;
+end:
+       vfree(payload);
+
+       return error;
+}
+
+int
+isakmp_cfg_set(iph1, attrpl)
+       struct ph1handle *iph1;
+       struct isakmp_pl_attr *attrpl;
+{
+       struct isakmp_data *attr;
+       int tlen;
+       size_t alen;
+       char *npp;
+       vchar_t *payload;
+       struct isakmp_pl_attr *reply;
+       vchar_t *reply_attr;
+       int type;
+       int error = -1;
+
+       if ((payload = vmalloc(sizeof(*reply))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return -1;
+       }
+       memset(payload->v, 0, sizeof(*reply));
+
+       tlen = ntohs(attrpl->h.len);
+       attr = (struct isakmp_data *)(attrpl + 1);
+       tlen -= sizeof(*attrpl);
+       
+       /* 
+        * We should send ack for the attributes we accepted 
+        */
+       while (tlen > 0) {
+               reply_attr = NULL;
+               type = ntohs(attr->type);
+
+               switch (type & ~ISAKMP_GEN_MASK) {
+               case XAUTH_STATUS:
+                       reply_attr = isakmp_xauth_set(iph1, attr);
+                       break;
+               default:
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                            "Unexpected SET attribute %d\n", 
+                                type & ~ISAKMP_GEN_MASK);
+                       break;
+               }
+
+               if ((reply_attr = vmalloc(sizeof(*reply_attr))) != NULL) {
+                       payload = buffer_cat(payload, reply_attr);
+                       vfree(reply_attr);
+               }
+
+               /* 
+                * Move to next attribute. If we run out of the packet, 
+                * tlen becomes negative and we exit. 
+                */
+               if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
+                       tlen -= sizeof(*attr);
+                       attr++;
+               } else {
+                       alen = ntohs(attr->lorv);
+                       tlen -= (sizeof(*attr) + alen);
+                       npp = (char *)attr;
+                       attr = (struct isakmp_data *)
+                           (npp + sizeof(*attr) + alen);
+               }
+       }
+
+       reply = (struct isakmp_pl_attr *)payload->v;
+       reply->h.len = htons(payload->l);
+       reply->type = ISAKMP_CFG_ACK;
+       reply->id = attrpl->id;
+
+       error = isakmp_cfg_send(iph1, payload, 
+           ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
+
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_DELETE_PH1) {
+               if (iph1->status == PHASE1ST_ESTABLISHED)
+                       isakmp_info_send_d1(iph1);
+               remph1(iph1);
+               delph1(iph1);
+       }
+end:
+       vfree(payload);
+
+       /* 
+        * If required, request ISAKMP mode config information
+        */
+       if ((iph1->rmconf->mode_cfg) && (error == 0))
+               error = isakmp_cfg_getconfig(iph1);
+
+       return error;
+}
+
+
+static vchar_t *
+buffer_cat(s, append)
+       vchar_t *s;
+       vchar_t *append;
+{
+       vchar_t *new;
+
+       new = vmalloc(s->l + append->l);
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory\n");
+               return s;
+       }
+
+       memcpy(new->v, s->v, s->l);
+       memcpy(new->v + s->l, append->v, append->l);
+
+       vfree(s);
+       return new;
+}
+
+static vchar_t *
+isakmp_cfg_net(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       int type;
+       in_addr_t addr4;
+
+       type = ntohs(attr->type);
+
+       /* 
+        * Don't give an address to a peer that did not succeed Xauth
+        */
+       if (xauth_check(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Attempt to start phase config whereas Xauth failed\n");
+               return NULL;
+       }
+
+       switch(type) {
+       case INTERNAL_IP4_ADDRESS:
+               switch(isakmp_cfg_config.confsource) {
+#ifdef HAVE_LIBRADIUS
+               case ISAKMP_CFG_CONF_RADIUS:
+                       if ((iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_RADIUS)
+                           && (iph1->mode_cfg->addr4.s_addr != htonl(-2)))
+                           /*
+                            * -2 is 255.255.255.254, RADIUS uses that
+                            * to instruct the NAS to use a local pool
+                            */
+                           break;
+                       plog(LLV_INFO, LOCATION, NULL, 
+                           "No IP from RADIUS, using local pool\n");
+                       /* FALLTHROUGH */
+#endif
+               case ISAKMP_CFG_CONF_LOCAL:
+                       if (isakmp_cfg_getport(iph1) == -1) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Port pool depleted\n");
+                               break;
+                       }
+
+                       iph1->mode_cfg->addr4.s_addr = 
+                           htonl(ntohl(isakmp_cfg_config.network4) 
+                           + iph1->mode_cfg->port);
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_ADDR4_LOCAL;
+                       break;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Unexpected confsource\n");
+               }
+                       
+               if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGIN) != 0)
+                       plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n");
+
+               return isakmp_cfg_addr4(iph1, 
+                   attr, &iph1->mode_cfg->addr4.s_addr);
+               break;
+
+       case INTERNAL_IP4_NETMASK:
+               switch(isakmp_cfg_config.confsource) {
+#ifdef HAVE_LIBRADIUS
+               case ISAKMP_CFG_CONF_RADIUS:
+                       if (iph1->mode_cfg->flags & ISAKMP_CFG_MASK4_RADIUS)
+                               break;
+                       plog(LLV_INFO, LOCATION, NULL, 
+                           "No mask from RADIUS, using local pool\n");
+                       /* FALLTHROUGH */
+#endif
+               case ISAKMP_CFG_CONF_LOCAL:
+                       iph1->mode_cfg->mask4.s_addr 
+                           = isakmp_cfg_config.netmask4;
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_MASK4_LOCAL;
+                       break;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Unexpected confsource\n");
+               }
+               return isakmp_cfg_addr4(iph1, attr, 
+                   &iph1->mode_cfg->mask4.s_addr);
+               break;
+
+       case INTERNAL_IP4_DNS:
+               return isakmp_cfg_addr4(iph1, 
+                   attr, &isakmp_cfg_config.dns4);
+               break;
+
+       case INTERNAL_IP4_NBNS:
+               return isakmp_cfg_addr4(iph1, 
+                   attr, &isakmp_cfg_config.nbns4);
+               break;
+
+       case INTERNAL_IP4_SUBNET:
+               return isakmp_cfg_addr4(iph1, 
+                   attr, &isakmp_cfg_config.network4);
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Unexpected type %d\n", type);
+               break;
+       }
+
+       return NULL;
+}
+
+#if 0
+static vchar_t *
+isakmp_cfg_void(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       vchar_t *buffer;
+       struct isakmp_data *new;
+
+       if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       new = (struct isakmp_data *)buffer->v;
+
+       new->type = attr->type;
+       new->lorv = htons(0);
+
+       return buffer;
+}
+#endif
+
+vchar_t *
+isakmp_cfg_copy(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       vchar_t *buffer;
+       size_t len = 0;
+
+       if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TLV)
+               len = ntohs(attr->lorv);
+
+       if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       memcpy(buffer->v, attr, sizeof(*attr) + ntohs(attr->lorv));
+
+       return buffer;
+}
+
+vchar_t *
+isakmp_cfg_short(iph1, attr, value)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+       int value;
+{
+       vchar_t *buffer;
+       struct isakmp_data *new;
+       int type;
+
+       if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       new = (struct isakmp_data *)buffer->v;
+       type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
+
+       new->type = htons(type | ISAKMP_GEN_TV);
+       new->lorv = htons(value);
+
+       return buffer;
+}
+
+vchar_t *
+isakmp_cfg_string(iph1, attr, string)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+       char *string;
+{
+       vchar_t *buffer;
+       struct isakmp_data *new;
+       size_t len;
+       char *data;
+
+       len = strlen(string);
+       if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       new = (struct isakmp_data *)buffer->v;
+
+       new->type = attr->type;
+       new->lorv = htons(len);
+       data = (char *)(new + 1);
+
+       memcpy(data, string, len);
+       
+       return buffer;
+}
+
+static vchar_t *
+isakmp_cfg_addr4(iph1, attr, addr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+       in_addr_t *addr;
+{
+       vchar_t *buffer;
+       struct isakmp_data *new;
+       size_t len;
+
+       len = sizeof(*addr);
+       if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       new = (struct isakmp_data *)buffer->v;
+
+       new->type = attr->type;
+       new->lorv = htons(len);
+       memcpy(new + 1, addr, len);
+       
+       return buffer;
+}
+
+struct isakmp_ivm *
+isakmp_cfg_newiv(iph1, msgid)
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+{
+       struct isakmp_cfg_state *ics = iph1->mode_cfg;
+
+       if (ics == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "isakmp_cfg_newiv called without mode config state\n");
+               return NULL;
+       }
+
+       if (ics->ivm != NULL)
+               oakley_delivm(ics->ivm);
+
+       ics->ivm = oakley_newiv2(iph1, msgid);
+
+       return ics->ivm;
+}
+
+/* Derived from isakmp_info_send_common */
+int
+isakmp_cfg_send(iph1, payload, np, flags, new_exchange)
+       struct ph1handle *iph1;
+       vchar_t *payload;
+       u_int32_t np;
+       int flags;
+       int new_exchange;
+{
+       struct ph2handle *iph2 = NULL;
+       vchar_t *hash = NULL;
+       struct isakmp *isakmp;
+       struct isakmp_gen *gen;
+       char *p;
+       int tlen;
+       int error = -1;
+       struct isakmp_cfg_state *ics = iph1->mode_cfg;
+
+       /* Check if phase 1 is established */
+       if ((iph1->status != PHASE1ST_ESTABLISHED) || 
+           (iph1->local == NULL) ||
+           (iph1->remote == NULL)) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "ISAKMP mode config exchange with immature phase 1\n");
+               goto end;
+       }
+
+       /* add new entry to isakmp status table */
+       iph2 = newph2();
+       if (iph2 == NULL)
+               goto end;
+
+       iph2->dst = dupsaddr(iph1->remote);
+       iph2->src = dupsaddr(iph1->local);
+       switch (iph1->remote->sa_family) {
+       case AF_INET:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in *)iph2->dst)->sin_port = 0;
+               ((struct sockaddr_in *)iph2->src)->sin_port = 0;
+#endif
+               break;
+#ifdef INET6
+       case AF_INET6:
+               ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0;
+               ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph1->remote->sa_family);
+               delph2(iph2);
+               goto end;
+       }
+       iph2->ph1 = iph1;
+       iph2->side = INITIATOR;
+       iph2->status = PHASE2ST_START;
+
+       if (new_exchange)
+               iph2->msgid = isakmp_newmsgid2(iph1);
+       else
+               iph2->msgid = iph1->msgid;
+
+       /* get IV and HASH(1) if skeyid_a was generated. */
+       if (iph1->skeyid_a != NULL) {
+               if (new_exchange) {
+                       if (isakmp_cfg_newiv(iph1, iph2->msgid) == NULL) {
+                               delph2(iph2);
+                               goto end;
+                       }
+               }
+
+               /* generate HASH(1) */
+               hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload);
+               if (hash == NULL) {
+                       delph2(iph2);
+                       goto end;
+               }
+
+               /* initialized total buffer length */
+               tlen = hash->l;
+               tlen += sizeof(*gen);
+       } else {
+               /* IKE-SA is not established */
+               hash = NULL;
+
+               /* initialized total buffer length */
+               tlen = 0;
+       }
+       if ((flags & ISAKMP_FLAG_A) == 0)
+               iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E);
+       else
+               iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A);
+
+       insph2(iph2);
+       bindph12(iph1, iph2);
+
+       tlen += sizeof(*isakmp) + payload->l;
+
+       /* create buffer for isakmp payload */
+       iph2->sendbuf = vmalloc(tlen);
+       if (iph2->sendbuf == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto err;
+       }
+
+       /* create isakmp header */
+       isakmp = (struct isakmp *)iph2->sendbuf->v;
+       memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t));
+       memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t));
+       isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH;
+       isakmp->v = iph1->version;
+       isakmp->etype = ISAKMP_ETYPE_CFG;
+       isakmp->flags = iph2->flags;
+       memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid));
+       isakmp->len = htonl(tlen);
+       p = (char *)(isakmp + 1);
+
+       /* create HASH payload */
+       if (hash != NULL) {
+               gen = (struct isakmp_gen *)p;
+               gen->np = np & 0xff;
+               gen->len = htons(sizeof(*gen) + hash->l);
+               p += sizeof(*gen);
+               memcpy(p, hash->v, hash->l);
+               p += hash->l;
+       }
+
+       /* add payload */
+       memcpy(p, payload->v, payload->l);
+       p += payload->l;
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1);
+#endif
+
+       /* encoding */
+       if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) {
+               vchar_t *tmp;
+
+               tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, 
+                       ics->ivm->ive, ics->ivm->iv);
+               VPTRINIT(iph2->sendbuf);
+               if (tmp == NULL)
+                       goto err;
+               iph2->sendbuf = tmp;
+       }
+
+       /* HDR*, HASH(1), ATTR */
+       if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) {
+               VPTRINIT(iph2->sendbuf);
+               goto err;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "sendto mode config %s.\n", s_isakmp_nptype(np));
+
+       /*
+        * XXX We might need to resend the message...
+        */
+
+       error = 0;
+       VPTRINIT(iph2->sendbuf);
+
+err:
+       if (iph2->sendbuf != NULL)
+               vfree(iph2->sendbuf);
+
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+end:
+       if (hash)
+               vfree(hash);
+       return error;
+}
+
+
+void 
+isakmp_cfg_rmstate(iph1)
+       struct ph1handle *iph1;
+{
+       struct isakmp_cfg_state *state = iph1->mode_cfg;
+
+       if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGOUT) != 0)
+               plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n");
+
+       if (state->flags & ISAKMP_CFG_PORT_ALLOCATED)
+               isakmp_cfg_putport(iph1, state->port);  
+
+       xauth_rmstate(&state->xauth);
+
+       racoon_free(state);
+       iph1->mode_cfg = NULL;
+
+       return;
+}
+
+struct isakmp_cfg_state *
+isakmp_cfg_mkstate(void) 
+{
+       struct isakmp_cfg_state *state;
+
+       if ((state = racoon_malloc(sizeof(*state))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory for mode config state\n");
+               return NULL;
+       }
+       memset(state, 0, sizeof(*state));
+
+       return state;
+}
+
+int 
+isakmp_cfg_getport(iph1)
+       struct ph1handle *iph1;
+{
+       unsigned int i;
+       size_t size = isakmp_cfg_config.pool_size;
+
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_PORT_ALLOCATED)
+               return iph1->mode_cfg->port;
+
+       if (isakmp_cfg_config.port_pool == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "isakmp_cfg_config.port_pool == NULL\n");
+               return -1;
+       }
+
+       for (i = 0; i < size; i++) {
+               if (isakmp_cfg_config.port_pool[i].used == 0)
+                       break;
+       }
+
+       if (i == size) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "No more addresses available\n");
+                       return -1;
+       }
+
+       isakmp_cfg_config.port_pool[i].used = 1;
+
+       plog(LLV_INFO, LOCATION, NULL, "Using port %d\n", i);
+
+       iph1->mode_cfg->flags |= ISAKMP_CFG_PORT_ALLOCATED;
+       iph1->mode_cfg->port = i;
+
+       return i;
+}
+
+int 
+isakmp_cfg_putport(iph1, index)
+       struct ph1handle *iph1;
+       unsigned int index;
+{
+       if (isakmp_cfg_config.port_pool == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "isakmp_cfg_config.port_pool == NULL\n");
+               return -1;
+       }
+
+       if (isakmp_cfg_config.port_pool[index].used == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Attempt to release an unallocated address (port %d)\n",
+                   index);
+               return -1;
+       }
+
+#ifdef HAVE_LIBPAM
+       /* Cleanup PAM status associated with the port */
+       if (isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_PAM)
+               privsep_cleanup_pam(index);
+#endif
+       isakmp_cfg_config.port_pool[index].used = 0;
+       iph1->mode_cfg->flags &= ISAKMP_CFG_PORT_ALLOCATED;
+
+       plog(LLV_INFO, LOCATION, NULL, "Released port %d\n", index);
+
+       return 0;
+}
+
+#ifdef HAVE_LIBPAM
+void
+cleanup_pam(port)
+       int port;
+{
+       if (isakmp_cfg_config.port_pool[port].pam != NULL) {
+               pam_end(isakmp_cfg_config.port_pool[port].pam, PAM_SUCCESS);
+               isakmp_cfg_config.port_pool[port].pam = NULL;
+       }
+
+       return;
+}
+#endif
+
+/* Accounting, only for RADIUS or PAM */
+static int
+isakmp_cfg_accounting(iph1, inout)
+       struct ph1handle *iph1;
+       int inout;
+{
+#ifdef HAVE_LIBPAM
+       if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_PAM)
+               return privsep_accounting_pam(iph1->mode_cfg->port, 
+                   inout);
+#endif 
+#ifdef HAVE_LIBRADIUS
+       if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS)
+               return isakmp_cfg_accounting_radius(iph1, inout);
+#endif
+       return 0;
+}
+
+#ifdef HAVE_LIBPAM
+int 
+isakmp_cfg_accounting_pam(port, inout)
+       int port;
+       int inout;
+{
+       int error = 0;
+       pam_handle_t *pam;
+
+       if (isakmp_cfg_config.port_pool == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "isakmp_cfg_config.port_pool == NULL\n");
+               return -1;
+       }
+       
+       pam = isakmp_cfg_config.port_pool[port].pam;
+       if (pam == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "pam handle is NULL\n");
+               return -1;
+       }
+
+       switch (inout) {
+       case ISAKMP_CFG_LOGIN:
+               error = pam_open_session(pam, 0);
+               break;
+       case ISAKMP_CFG_LOGOUT:
+               error = pam_close_session(pam, 0);
+               pam_end(pam, error);
+               isakmp_cfg_config.port_pool[port].pam = NULL;
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n");
+               break;
+       }
+       
+       if (error != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "pam_open_session/pam_close_session failed: %s\n",
+                   pam_strerror(pam, error)); 
+               return -1;
+        }
+
+       return 0;
+}
+#endif /* HAVE_LIBPAM */
+
+#ifdef HAVE_LIBRADIUS
+static int
+isakmp_cfg_accounting_radius(iph1, inout)
+       struct ph1handle *iph1;
+       int inout;
+{
+       /* For first time use, initialize Radius */
+       if (radius_acct_state == NULL) {
+               if ((radius_acct_state = rad_acct_open()) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Cannot init librradius\n");
+                       return -1;
+               }
+
+               if (rad_config(radius_acct_state, NULL) != 0) {
+                        plog(LLV_ERROR, LOCATION, NULL,
+                            "Cannot open librarius config file: %s\n",
+                            rad_strerror(radius_acct_state));
+                         rad_close(radius_acct_state);
+                         radius_acct_state = NULL;
+                         return -1;
+               }
+       }
+
+       if (rad_create_request(radius_acct_state, 
+           RAD_ACCOUNTING_REQUEST) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_create_request failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       if (rad_put_string(radius_acct_state, RAD_USER_NAME, 
+           iph1->mode_cfg->login) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_string failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       switch (inout) {
+       case ISAKMP_CFG_LOGIN:
+               inout = RAD_START;
+               break;
+       case ISAKMP_CFG_LOGOUT:
+               inout = RAD_STOP;
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n");
+               break;
+       }
+
+       if (rad_put_addr(radius_acct_state, 
+           RAD_FRAMED_IP_ADDRESS, iph1->mode_cfg->addr4) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_addr failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       if (rad_put_addr(radius_acct_state, 
+           RAD_LOGIN_IP_HOST, iph1->mode_cfg->addr4) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_addr failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       if (rad_put_int(radius_acct_state, RAD_ACCT_STATUS_TYPE, inout) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_int failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       if (isakmp_cfg_radius_common(radius_acct_state, 
+           iph1->mode_cfg->port) != 0)
+               return -1;
+
+       if (rad_send_request(radius_acct_state) != RAD_ACCOUNTING_RESPONSE) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_send_request failed: %s\n",
+                   rad_strerror(radius_acct_state));
+               return -1;
+       }
+
+       return 0;
+}
+#endif /* HAVE_LIBRADIUS */
+
+/*
+ * Attributes common to all RADIUS requests
+ */
+#ifdef HAVE_LIBRADIUS
+int
+isakmp_cfg_radius_common(radius_state, port)
+       struct rad_handle *radius_state;
+       int port;
+{ 
+       struct utsname name;
+       static struct hostent *host = NULL;
+       struct in_addr nas_addr;
+
+       /* 
+        * Find our own IP by resolving our nodename
+        */
+       if (host == NULL) {
+               if (uname(&name) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "uname failed: %s\n", strerror(errno));
+                       return -1;
+               }
+
+               if ((host = gethostbyname(name.nodename)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "gethostbyname failed: %s\n", strerror(errno));
+                       return -1;
+               }
+       }
+
+       memcpy(&nas_addr, host->h_addr, sizeof(nas_addr));
+       if (rad_put_addr(radius_state, RAD_NAS_IP_ADDRESS, nas_addr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_addr failed: %s\n",
+                   rad_strerror(radius_state));
+               return -1;
+       }
+
+       if (rad_put_int(radius_state, RAD_NAS_PORT, port) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_int failed: %s\n",
+                   rad_strerror(radius_state));
+               return -1;
+       }
+
+       if (rad_put_int(radius_state, RAD_NAS_PORT_TYPE, RAD_VIRTUAL) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_int failed: %s\n",
+                   rad_strerror(radius_state));
+               return -1;
+       }
+
+       if (rad_put_int(radius_state, RAD_SERVICE_TYPE, RAD_FRAMED) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "rad_put_int failed: %s\n",
+                   rad_strerror(radius_state));
+               return -1;
+       }
+       
+       return 0;
+}
+#endif
+       
+int 
+isakmp_cfg_getconfig(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buffer;
+       struct isakmp_pl_attr *attrpl;
+       struct isakmp_data *attr;
+       size_t len;
+       int error;
+       int attrcount;
+       int i;
+       int attrlist[] = {
+               INTERNAL_IP4_ADDRESS,
+               INTERNAL_IP4_NETMASK,
+               INTERNAL_IP4_DNS,
+               INTERNAL_IP4_NBNS,
+               UNITY_BANNER,
+               APPLICATION_VERSION,
+       };
+
+       attrcount = sizeof(attrlist) / sizeof(*attrlist);
+       len = sizeof(*attrpl) + sizeof(*attr) * attrcount;
+           
+       if ((buffer = vmalloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return -1;
+       }
+
+       attrpl = (struct isakmp_pl_attr *)buffer->v;
+       attrpl->h.len = htons(len);
+       attrpl->type = ISAKMP_CFG_REQUEST;
+       attrpl->id = htons((u_int16_t)(eay_random() & 0xffff));
+
+       attr = (struct isakmp_data *)(attrpl + 1);
+
+       for (i = 0; i < attrcount; i++) {
+               attr->type = htons(attrlist[i]);
+               attr->lorv = htons(0);
+               attr++;
+       }
+
+       error = isakmp_cfg_send(iph1, buffer,
+           ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
+
+       vfree(buffer);
+
+       return error;
+}
+
+static void
+isakmp_cfg_getaddr4(attr, ip)
+       struct isakmp_data *attr;
+       struct in_addr *ip;
+{
+       size_t alen = ntohs(attr->lorv);
+       in_addr_t *addr;
+
+       if (alen != sizeof(*ip)) {
+               plog(LLV_ERROR, LOCATION, NULL, "Bad IPv4 address len\n");
+               return;
+       }
+
+       addr = (in_addr_t *)(attr + 1);
+       ip->s_addr = *addr;
+
+       return;
+}
+
+int
+isakmp_cfg_setenv(iph1, envp, envc)
+       struct ph1handle *iph1; 
+       char ***envp;
+       int *envc;
+{
+#define IP_MAX 40
+       char addrstr[IP_MAX];
+
+       /* 
+        * Internal IPv4 address, either if 
+        * we are a client or a server.
+        */
+       if ((iph1->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) ||
+#ifdef HAVE_LIBRADIUS
+           (iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_RADIUS) ||
+#endif
+           (iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_LOCAL)) {
+               inet_ntop(AF_INET, &iph1->mode_cfg->addr4, 
+                   addrstr, IP_MAX);
+       } else
+               addrstr[0] = '\0';
+
+       if (script_env_append(envp, envc, "INTERNAL_ADDR4", addrstr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_ADDR4\n");
+               return -1;
+       }
+
+       /* Internal IPv4 mask */
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_MASK4) 
+               inet_ntop(AF_INET, &iph1->mode_cfg->mask4, 
+                   addrstr, IP_MAX);
+       else
+               addrstr[0] = '\0';
+
+       /* 
+       * During several releases, documentation adverised INTERNAL_NETMASK4
+       * while code was using INTERNAL_MASK4. We now do both.
+       */
+       if (script_env_append(envp, envc, "INTERNAL_MASK4", addrstr) != 0) {
+                plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_MASK4\n");
+                return -1;
+        } 
+
+       if (script_env_append(envp, envc, "INTERNAL_NETMASK4", addrstr) != 0) {
+              plog(LLV_ERROR, LOCATION, NULL,  
+                  "Cannot set INTERNAL_NETMASK4\n");
+              return -1;
+       }
+
+
+       /* Internal IPv4 DNS */
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_DNS4) 
+               inet_ntop(AF_INET, &iph1->mode_cfg->dns4, 
+                   addrstr, IP_MAX);
+       else
+               addrstr[0] = '\0';
+
+       if (script_env_append(envp, envc, "INTERNAL_DNS4", addrstr) != 0) { 
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_DNS4\n");
+               return -1;
+       }
+
+       /* Internal IPv4 WINS */
+       if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_WINS4) 
+               inet_ntop(AF_INET, &iph1->mode_cfg->wins4, 
+                   addrstr, IP_MAX);
+       else
+               addrstr[0] = '\0';
+
+       if (script_env_append(envp, envc, "INTERNAL_WINS4", addrstr) != 0) { 
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_WINS4\n");
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/ipsec-tools/racoon/isakmp_cfg.h b/ipsec-tools/racoon/isakmp_cfg.h
new file mode 100644 (file)
index 0000000..ba45ef8
--- /dev/null
@@ -0,0 +1,176 @@
+/*     $KAME$ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * 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.
+ */
+
+#ifdef HAVE_LIBPAM
+#ifdef __APPLE__
+#include <pam/pam_appl.h>
+#else
+#include <security/pam_appl.h>
+#endif
+#endif
+
+/* 
+ * XXX don't forget to update 
+ * src/racoon/handler.c:exclude_cfg_addr()
+ * if you add IPv6 capability
+ */
+
+/* Attribute types */
+#define INTERNAL_IP4_ADDRESS        1
+#define INTERNAL_IP4_NETMASK        2
+#define INTERNAL_IP4_DNS            3
+#define INTERNAL_IP4_NBNS           4
+#define INTERNAL_ADDRESS_EXPIRY     5
+#define INTERNAL_IP4_DHCP           6
+#define APPLICATION_VERSION         7
+#define INTERNAL_IP6_ADDRESS        8
+#define INTERNAL_IP6_NETMASK        9
+#define INTERNAL_IP6_DNS           10
+#define INTERNAL_IP6_NBNS          11
+#define INTERNAL_IP6_DHCP          12
+#define INTERNAL_IP4_SUBNET        13
+#define SUPPORTED_ATTRIBUTES       14
+#define INTERNAL_IP6_SUBNET        15
+
+/* For APPLICATION_VERSION */
+#define ISAKMP_CFG_RACOON_VERSION "KAME/racoon " \
+                                 "+ Hybrid auth Patches <manu@netbsd.org>"
+
+/* 
+ * Global configuration for ISAKMP mode confiration address allocation 
+ * Readen from the mode_cfg section of racoon.conf
+ */
+struct isakmp_cfg_port {
+       char    used;
+#ifdef HAVE_LIBPAM
+       pam_handle_t *pam;
+#endif
+};
+
+struct isakmp_cfg_config {
+       in_addr_t       network4;
+       in_addr_t       netmask4;
+       in_addr_t       dns4;
+       in_addr_t       nbns4;
+       struct isakmp_cfg_port *port_pool;
+       int authsource;
+       int confsource;
+       int accounting;
+       size_t pool_size;
+       int auth_throttle;
+       char motd[MAXPATHLEN + 1];
+       int pfs_group;
+       int save_passwd;
+};
+
+/* For authsource */
+#define ISAKMP_CFG_AUTH_SYSTEM 0
+#define ISAKMP_CFG_AUTH_RADIUS 1
+#define ISAKMP_CFG_AUTH_PAM    2
+
+/* For confsource */
+#define ISAKMP_CFG_CONF_LOCAL  0
+#define ISAKMP_CFG_CONF_RADIUS 1
+
+/* For accounting */
+#define ISAKMP_CFG_ACCT_NONE   0
+#define ISAKMP_CFG_ACCT_RADIUS 1
+#define ISAKMP_CFG_ACCT_PAM    2
+
+/* For pool_size */
+#define ISAKMP_CFG_MAX_CNX     255
+
+/* For motd */
+#define ISAKMP_CFG_MOTD        "/etc/motd"
+
+extern struct isakmp_cfg_config isakmp_cfg_config;
+
+/*
+ * ISAKMP mode config state 
+ */
+#define LOGINLEN 31
+struct isakmp_cfg_state {
+       int flags;                      /* See below */
+       unsigned int port;              /* address index */
+       char login[LOGINLEN + 1];       /* login */
+       struct in_addr addr4;           /* IPv4 address */
+       struct in_addr mask4;           /* IPv4 netmask */
+       struct in_addr dns4;            /* IPv4 DNS (when client only) */
+       struct in_addr wins4;           /* IPv4 WINS (when client only) */
+       struct xauth_state xauth;       /* Xauth state, if revelant */          
+       struct isakmp_ivm *ivm;         /* XXX Use iph1's ivm? */
+};
+
+/* flags */
+#define ISAKMP_CFG_VENDORID_XAUTH      0x01    /* Supports Xauth */
+#define ISAKMP_CFG_VENDORID_UNITY      0x02    /* Cisco Unity compliant */
+#define ISAKMP_CFG_PORT_ALLOCATED      0x04    /* Port allocated */
+#define ISAKMP_CFG_ADDR4_RADIUS                0x08    /* Address from RADIUS  */
+#define ISAKMP_CFG_MASK4_RADIUS                0x10    /* Netmask from RADIUS */
+#define ISAKMP_CFG_ADDR4_LOCAL         0x20    /* Address from local pool */
+#define ISAKMP_CFG_MASK4_LOCAL         0x40    /* Netmask from local pool */
+#define ISAKMP_CFG_GOT_ADDR4           0x80    /* Client got address */
+#define ISAKMP_CFG_GOT_MASK4           0x100   /* Client got mask */
+#define ISAKMP_CFG_GOT_DNS4            0x200   /* Client got DNS */
+#define ISAKMP_CFG_GOT_WINS4           0x400   /* Client got WINS */
+#define ISAKMP_CFG_DELETE_PH1          0x800   /* phase 1 should be deleted */
+
+struct isakmp_pl_attr;
+struct ph1handle;
+struct isakmp_ivm;
+void isakmp_cfg_r(struct ph1handle *, vchar_t *);
+int isakmp_cfg_attr_r(struct ph1handle *, u_int32_t, struct isakmp_pl_attr *);
+int isakmp_cfg_reply(struct ph1handle *, struct isakmp_pl_attr *);
+int isakmp_cfg_request(struct ph1handle *, struct isakmp_pl_attr *);
+int isakmp_cfg_set(struct ph1handle *, struct isakmp_pl_attr *);
+int isakmp_cfg_send(struct ph1handle *, vchar_t *, u_int32_t, int, int);
+struct isakmp_ivm *isakmp_cfg_newiv(struct ph1handle *, u_int32_t);
+void isakmp_cfg_rmstate(struct ph1handle *);
+struct isakmp_cfg_state *isakmp_cfg_mkstate(void);
+vchar_t *isakmp_cfg_copy(struct ph1handle *, struct isakmp_data *);
+vchar_t *isakmp_cfg_short(struct ph1handle *, struct isakmp_data *, int);
+vchar_t *isakmp_cfg_string(struct ph1handle *, struct isakmp_data *, char *);
+int isakmp_cfg_getconfig(struct ph1handle *);
+int isakmp_cfg_setenv(struct ph1handle *, char ***, int *);
+
+int isakmp_cfg_getport(struct ph1handle *);       
+int isakmp_cfg_putport(struct ph1handle *, unsigned int);
+
+#ifdef HAVE_LIBRADIUS
+struct rad_handle;
+extern struct rad_handle *radius_acct_state;
+int isakmp_cfg_radius_common(struct rad_handle *, int); 
+#endif
+
+#ifdef HAVE_LIBPAM
+int isakmp_cfg_accounting_pam(int, int);
+void cleanup_pam(int);
+#endif
diff --git a/ipsec-tools/racoon/isakmp_frag.c b/ipsec-tools/racoon/isakmp_frag.c
new file mode 100644 (file)
index 0000000..e728c74
--- /dev/null
@@ -0,0 +1,353 @@
+/* $Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/md5.h> 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "handler.h"
+#include "isakmp_frag.h"
+#include "strnames.h"
+
+int
+isakmp_sendfrags(iph1, buf) 
+       struct ph1handle *iph1;
+       vchar_t *buf;
+{
+       struct isakmp *hdr;
+       struct isakmp_frag *fraghdr;
+       caddr_t data;
+       caddr_t sdata;
+       size_t datalen;
+       size_t max_datalen;
+       size_t fraglen;
+       vchar_t *frag;
+       unsigned int trailer;
+       unsigned int fragnum = 0;
+       size_t len;
+       int etype;
+
+       /*
+        * Catch the exchange type for later: the fragments and the
+        * fragmented packet must have the same exchange type.
+        */
+       hdr = (struct isakmp *)buf->v;
+       etype = hdr->etype;
+
+       /*
+        * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN
+        * First compute the maximum data length that will fit in it
+        */
+       max_datalen = ISAKMP_FRAG_MAXLEN - 
+           (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(trailer));
+
+       sdata = buf->v;
+       len = buf->l;
+
+       while (len > 0) {
+               fragnum++;
+
+               if (len > max_datalen)
+                       datalen = max_datalen;
+               else
+                       datalen = len;
+
+               fraglen = sizeof(*hdr) 
+                       + sizeof(*fraghdr) 
+                       + datalen;
+
+               if ((frag = vmalloc(fraglen)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot allocate memory\n");
+                       return -1;
+               }
+
+               set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG);
+               hdr = (struct isakmp *)frag->v;
+               hdr->etype = etype;
+
+               fraghdr = (struct isakmp_frag *)(hdr + 1);
+               fraghdr->unknown0 = htons(0);
+               fraghdr->len = htons(fraglen - sizeof(*hdr));
+               fraghdr->unknown1 = htons(1);
+               fraghdr->index = fragnum;
+               if (len == datalen)
+                       fraghdr->flags = ISAKMP_FRAG_LAST;
+               else
+                       fraghdr->flags = 0;
+
+               data = (caddr_t)(fraghdr + 1);
+               memcpy(data, sdata, datalen);
+
+               if (isakmp_send(iph1, frag) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n");
+                       return -1;
+               }
+
+               vfree(frag);
+
+               len -= datalen;
+               sdata += datalen;
+       }
+               
+       return fragnum;
+}
+
+unsigned int 
+vendorid_frag_cap(gen)
+       struct isakmp_gen *gen;
+{
+       int *hp;
+
+       hp = (int *)(gen + 1);
+
+       return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]);
+}
+
+int 
+isakmp_frag_extract(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct isakmp *isakmp;
+       struct isakmp_frag *frag;
+       struct isakmp_frag_item *item;
+       vchar_t *buf;
+       size_t len;
+       int last_frag = 0;
+       char *data;
+       int i;
+
+       if (msg->l < sizeof(*isakmp) + sizeof(*frag)) {
+               plog(LLV_ERROR, LOCATION, NULL, "Message too short\n");
+               return -1;
+       }
+
+       isakmp = (struct isakmp *)msg->v;
+       frag = (struct isakmp_frag *)(isakmp + 1);
+
+       /* 
+        * frag->len is the frag payload data plus the frag payload header,
+        * whose size is sizeof(*frag) 
+        */
+       if (msg->l < sizeof(*isakmp) + ntohs(frag->len)) {
+               plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n");
+               return -1;
+       }
+
+       if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               return -1;
+       }
+
+       if ((item = racoon_malloc(sizeof(*item))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               vfree(buf);
+               return -1;
+       }
+
+       data = (char *)(frag + 1);
+       memcpy(buf->v, data, buf->l);
+
+       item->frag_num = frag->index;
+       item->frag_last = (frag->flags & ISAKMP_FRAG_LAST);
+       item->frag_next = NULL;
+       item->frag_packet = buf;
+
+       /* Look for the last frag while inserting the new item in the chain */
+       if (item->frag_last)
+               last_frag = item->frag_num;
+
+       if (iph1->frag_chain == NULL) {
+               iph1->frag_chain = item;
+       } else {
+               struct isakmp_frag_item *current;
+
+               current = iph1->frag_chain;
+               while (current->frag_next) {
+                       if (current->frag_last)
+                               last_frag = item->frag_num;
+                       current = current->frag_next;
+               }
+               current->frag_next = item;
+       }
+
+       /* If we saw the last frag, check if the chain is complete */
+       if (last_frag != 0) {
+               for (i = 1; i <= last_frag; i++) {
+                       item = iph1->frag_chain;
+                       do {
+                               if (item->frag_num == i)
+                                       break;
+                               item = item->frag_next;
+                       } while (item != NULL);
+
+                       if (item == NULL) /* Not found */
+                               break;
+               }
+
+               if (item != NULL) /* It is complete */
+                       return 1;
+       }
+               
+       return 0;
+}
+
+vchar_t *
+isakmp_frag_reassembly(iph1)
+       struct ph1handle *iph1;
+{
+       struct isakmp_frag_item *item;
+       size_t len = 0;
+       vchar_t *buf = NULL;
+       int frag_count = 0;
+       int i;
+       char *data;
+
+       if ((item = iph1->frag_chain) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n");
+               goto out;
+       }
+
+       do {
+               frag_count++;
+               len += item->frag_packet->l;
+               item = item->frag_next;
+       } while (item != NULL);
+       
+       if ((buf = vmalloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+               goto out;
+       }
+       data = buf->v;
+
+       for (i = 1; i <= frag_count; i++) {
+               item = iph1->frag_chain;
+               do {
+                       if (item->frag_num == i)
+                               break;
+                       item = item->frag_next;
+               } while (item != NULL);
+
+               if (item == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Missing fragment #%d\n", i);
+                       vfree(buf);
+                       buf = NULL;
+                       goto out;
+               }
+               memcpy(data, item->frag_packet->v, item->frag_packet->l);
+               data += item->frag_packet->l;
+       }
+
+out:
+       item = iph1->frag_chain;                
+       do {
+               struct isakmp_frag_item *next_item;
+
+               next_item = item->frag_next;
+
+               vfree(item->frag_packet);
+               racoon_free(item);
+
+               item = next_item;
+       } while (item != NULL);
+
+       iph1->frag_chain = NULL;
+
+       return buf;
+}
+
+vchar_t *
+isakmp_frag_addcap(buf, cap)
+       vchar_t *buf;
+       int cap;
+{
+       int *capp;
+       size_t len;
+
+       /* If the capability has not been added, add room now */
+       len = buf->l;
+       if (len == MD5_DIGEST_LENGTH) {
+               if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot allocate memory\n");
+                       return NULL;
+               }
+               capp = (int *)(buf->v + len);
+               *capp = htonl(0);
+       }
+
+       capp = (int *)(buf->v + MD5_DIGEST_LENGTH);
+       *capp |= htonl(cap);
+
+       return buf;
+}
+
diff --git a/ipsec-tools/racoon/isakmp_frag.h b/ipsec-tools/racoon/isakmp_frag.h
new file mode 100644 (file)
index 0000000..52ee10a
--- /dev/null
@@ -0,0 +1,49 @@
+/*     $Id: isakmp_frag.h,v 1.2 2004/10/24 16:51:24 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus 
+ * 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.
+ */
+
+/* IKE fragmentation capabilities */
+#define VENDORID_FRAG_BASE     0x40000000
+#define VENDORID_FRAG_AGG      0x80000000
+
+#define ISAKMP_FRAG_MAXLEN 552
+
+struct isakmp_frag_item {
+       int     frag_num;
+       int     frag_last;
+       struct isakmp_frag_item *frag_next;
+       vchar_t *frag_packet;
+};
+
+int isakmp_sendfrags(struct ph1handle *, vchar_t *);
+unsigned int vendorid_frag_cap(struct isakmp_gen *);
+int isakmp_frag_extract(struct ph1handle *, vchar_t *);
+vchar_t *isakmp_frag_reassembly(struct ph1handle *);
+vchar_t *isakmp_frag_addcap(vchar_t *, int);
diff --git a/ipsec-tools/racoon/isakmp_ident.c b/ipsec-tools/racoon/isakmp_ident.c
new file mode 100644 (file)
index 0000000..d9e6cf9
--- /dev/null
@@ -0,0 +1,1792 @@
+/* $Id: isakmp_ident.c,v 1.13.2.2 2005/11/21 09:46:23 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Identity Protecion Exchange (Main Mode) */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "evt.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "isakmp_ident.h"
+#include "isakmp_inf.h"
+#include "vendorid.h"
+
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#ifdef HAVE_GSSAPI
+#include "gssapi.h"
+#endif
+
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+
+static vchar_t *ident_ir2mx __P((struct ph1handle *));
+static vchar_t *ident_ir3mx __P((struct ph1handle *));
+
+/* %%%
+ * begin Identity Protection Mode as initiator.
+ */
+/*
+ * send to responder
+ *     psk: HDR, SA
+ *     sig: HDR, SA
+ *     rsa: HDR, SA
+ *     rev: HDR, SA
+ */
+int
+ident_i1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg; /* must be null */
+{
+       struct payload_list *plist = NULL;
+       int error = -1;
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL };
+       int i;
+#endif
+#ifdef ENABLE_DPD
+       vchar_t *vid_dpd = NULL;
+#endif
+       /* validity check */
+       if (msg != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "msg has to be NULL in this function.\n");
+               goto end;
+       }
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* create isakmp index */
+       memset(&iph1->index, 0, sizeof(iph1->index));
+       isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local);
+
+       /* create SA payload for my proposal */
+       iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+       if (iph1->sa == NULL)
+               goto end;
+
+       /* set SA payload to propose */
+       plist = isakmp_plist_append(plist, iph1->sa, ISAKMP_NPTYPE_SA);
+
+#ifdef ENABLE_NATT
+       /* set VID payload for NAT-T if NAT-T support allowed in the config file */
+       if (iph1->rmconf->nat_traversal) 
+               plist = isakmp_plist_append_natt_vids(plist, vid_natt);
+#endif
+#ifdef ENABLE_DPD
+       if(iph1->rmconf->dpd){
+               vid_dpd = set_vendorid(VENDORID_DPD);
+               if (vid_dpd != NULL)
+                       plist = isakmp_plist_append(plist, vid_dpd,
+                                                                               ISAKMP_NPTYPE_VID);
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+       error = 0;
+
+end:
+#ifdef ENABLE_NATT
+       for (i = 0; i < MAX_NATT_VID_COUNT && vid_natt[i] != NULL; i++)
+               vfree(vid_natt[i]);
+#endif
+#ifdef ENABLE_DPD
+       if (vid_dpd != NULL)
+               vfree(vid_dpd);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR, SA
+ *     sig: HDR, SA
+ *     rsa: HDR, SA
+ *     rev: HDR, SA
+ */
+int
+ident_i2recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       vchar_t *satmp = NULL;
+       int error = -1;
+       int vid_numeric;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       /*
+        * NOTE: RedCreek(as responder) attaches N[responder-lifetime] here,
+        *      if proposal-lifetime > lifetime-redcreek-wants.
+        *      (see doi-08 4.5.4)
+        *      => According to the seciton 4.6.3 in RFC 2407, This is illegal.
+        * NOTE: we do not really care about ordering of VID and N.
+        *      does it matters?
+        * NOTE: even if there's multiple VID/N, we'll ignore them.
+        */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* SA payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+       if (isakmp_p2ph(&satmp, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
+                         natt_handle_vendorid(iph1, vid_numeric);
+#endif
+#ifdef ENABLE_DPD
+                       if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd)
+                               iph1->dpd_support=1;
+#endif
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+#endif
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+       VPTRINIT(iph1->sa_ret);
+
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_REMOTE, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (satmp)
+               vfree(satmp);
+       return error;
+}
+
+/*
+ * send to responder
+ *     psk: HDR, KE, Ni
+ *     sig: HDR, KE, Ni
+ *   gssapi: HDR, KE, Ni, GSSi
+ *     rsa: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ *     rev: HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ *               <IDi1_b>Ke_i, [<<Cert-I_b>Ke_i]
+ */
+int
+ident_i2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* fix isakmp index */
+       memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck,
+               sizeof(cookie_t));
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->approval->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+           gssapi_get_itoken(iph1, NULL) < 0)
+               goto end;
+#endif
+
+       /* create buffer to send isakmp payload */
+       iph1->sendbuf = ident_ir2mx(iph1);
+       if (iph1->sendbuf == NULL)
+               goto end;
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG2SENT;
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR, KE, Nr
+ *     sig: HDR, KE, Nr [, CR ]
+ *   gssapi: HDR, KE, Nr, GSSr
+ *     rsa: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ *     rev: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r,
+ */
+int
+ident_i3recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+#ifdef ENABLE_NATT
+       vchar_t *natd_received;
+       int natd_seq = 0, natd_verified;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               case ISAKMP_NPTYPE_CR:
+                       if (oakley_savecr(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (NATT_AVAILABLE(iph1) && iph1->natt_options != NULL &&
+                           pa->type == iph1->natt_options->payload_nat_d) {
+                               natd_received = NULL;
+                               if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
+                                       goto end;
+                        
+                               /* set both bits first so that we can clear them
+                                  upon verifying hashes */
+                               if (natd_seq == 0)
+                                       iph1->natt_flags |= NAT_DETECTED;
+                        
+                               /* this function will clear appropriate bits bits 
+                                  from iph1->natt_flags */
+                               natd_verified = natt_compare_addr_hash (iph1,
+                                       natd_received, natd_seq++);
+                        
+                               plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                                       natd_seq - 1,
+                                       natd_verified ? "verified" : "doesn't match");
+                        
+                               vfree (natd_received);
+                               break;
+                       }
+                       /* %%%% Be lenient here - some servers send natd payloads */
+                       /* when no nat is detected                                                                */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1)) {
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+               if (iph1->natt_flags & NAT_DETECTED)
+                       natt_float_ports (iph1);
+       }
+#endif
+
+       /* payload existency check */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       if (oakley_checkcr(iph1) < 0) {
+               /* Ignore this error in order to be interoperability. */
+               ;
+       }
+
+       iph1->status = PHASE1ST_MSG3RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (error) {
+               VPTRINIT(iph1->dhpub_p);
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+               oakley_delcert(iph1->cr_p);
+               iph1->cr_p = NULL;
+       }
+
+       return error;
+}
+
+/*
+ * send to responder
+ *     psk: HDR*, IDi1, HASH_I
+ *     sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I
+ *   gssapi: HDR*, IDi1, < Gssi(n) | HASH_I >
+ *     rsa: HDR*, HASH_I
+ *     rev: HDR*, HASH_I
+ */
+int
+ident_i3send(iph1, msg0)
+       struct ph1handle *iph1;
+       vchar_t *msg0;
+{
+       int error = -1;
+       int dohash = 1;
+#ifdef HAVE_GSSAPI
+       int len;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG3RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid(iph1) < 0)
+               goto end;
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+           gssapi_more_tokens(iph1)) {
+               plog(LLV_DEBUG, LOCATION, NULL, "calling get_itoken\n");
+               if (gssapi_get_itoken(iph1, &len) < 0)
+                       goto end;
+               if (len != 0)
+                       dohash = 0;
+       }
+#endif
+
+       /* generate HASH to send */
+       if (dohash) {
+               iph1->hash = oakley_ph1hash_common(iph1, GENERATE);
+               if (iph1->hash == NULL)
+                       goto end;
+       } else
+               iph1->hash = NULL;
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       /* create HDR;ID;HASH payload */
+       iph1->sendbuf = ident_ir3mx(iph1);
+       if (iph1->sendbuf == NULL)
+               goto end;
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg0) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->ive->v, iph1->ivm->iv->v, iph1->ivm->iv->l);
+
+       iph1->status = PHASE1ST_MSG3SENT;
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * receive from responder
+ *     psk: HDR*, IDr1, HASH_R
+ *     sig: HDR*, IDr1, [ CERT, ] SIG_R
+ *   gssapi: HDR*, IDr1, < GSSr(n) | HASH_R >
+ *     rsa: HDR*, HASH_R
+ *     rev: HDR*, HASH_R
+ */
+int
+ident_i4recv(iph1, msg0)
+       struct ph1handle *iph1;
+       vchar_t *msg0;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       vchar_t *msg = NULL;
+       int error = -1;
+       int type;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG3SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* decrypting */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "ignore the packet, "
+                       "expecting the packet encrypted.\n");
+               goto end;
+       }
+       msg = oakley_do_decrypt(iph1, msg0, iph1->ivm->iv, iph1->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       iph1->pl_hash = NULL;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph1);
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+       /* validate authentication value */
+#ifdef HAVE_GSSAPI
+       if (gsstoken == NULL) {
+#endif
+               type = oakley_validate_auth(iph1);
+               if (type != 0) {
+                       if (type == -1) {
+                               /* msg printed inner oakley_validate_auth() */
+                               goto end;
+                       }
+                       EVT_PUSH(iph1->local, iph1->remote, 
+                           EVTT_PEERPH1AUTH_FAILED, NULL);
+                       isakmp_info_send_n1(iph1, type, NULL);
+                       goto end;
+               }
+#ifdef HAVE_GSSAPI
+       }
+#endif
+
+       /*
+        * XXX: Should we do compare two addresses, ph1handle's and ID
+        * payload's.
+        */
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote, "peer's ID:");
+       plogdump(LLV_DEBUG, iph1->id_p->v, iph1->id_p->l);
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->ive->l);
+
+       /*
+        * If we got a GSS token, we need to this roundtrip again.
+        */
+#ifdef HAVE_GSSAPI
+       iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED : 
+           PHASE1ST_MSG4RECEIVED;
+#else
+       iph1->status = PHASE1ST_MSG4RECEIVED;
+#endif
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (msg)
+               vfree(msg);
+#ifdef HAVE_GSSAPI
+       if (gsstoken)
+               vfree(gsstoken);
+#endif
+
+       if (error) {
+               VPTRINIT(iph1->id_p);
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+       }
+
+       return error;
+}
+
+/*
+ * status update and establish isakmp sa.
+ */
+int
+ident_i4send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG4RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l);
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, SA
+ *     sig: HDR, SA
+ *     rsa: HDR, SA
+ *     rev: HDR, SA
+ */
+int
+ident_r1recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int vid_numeric;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       /*
+        * NOTE: XXX even if multiple VID, we'll silently ignore those.
+        */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* check the position of SA payload */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               goto end;
+       }
+       if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0)
+               goto end;
+       pa++;
+
+       for (/*nothing*/;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_VID:
+                       vid_numeric = check_vendorid(pa->ptr);
+#ifdef ENABLE_NATT
+                       if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
+                               natt_handle_vendorid(iph1, vid_numeric);
+#endif
+#ifdef ENABLE_DPD
+                       if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd)
+                               iph1->dpd_support=1;
+#endif
+                       break;
+               default:
+                       /*
+                        * We don't send information to the peer even
+                        * if we received malformed packet.  Because we
+                        * can't distinguish the malformed packet and
+                        * the re-sent packet.  And we do same behavior
+                        * when we expect encrypted packet.
+                        */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog(LLV_INFO, LOCATION, iph1->remote,
+                    "Selected NAT-T version: %s\n",
+                    vid_string_by_id(iph1->natt_options->version));
+#endif
+
+       /* check SA payload and set approval SA for use */
+       if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "failed to get valid proposal.\n");
+               /* XXX send information */
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG1RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (error) {
+               VPTRINIT(iph1->sa);
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR, SA
+ *     sig: HDR, SA
+ *     rsa: HDR, SA
+ *     rev: HDR, SA
+ */
+int
+ident_r1send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct payload_list *plist = NULL;
+       int error = -1;
+       vchar_t *gss_sa = NULL;
+       vchar_t *vid = NULL;
+#ifdef ENABLE_NATT
+       vchar_t *vid_natt = NULL;
+#endif
+#ifdef ENABLE_DPD
+       vchar_t *vid_dpd = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* set responder's cookie */
+       isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local);
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->gssid != NULL)
+               gss_sa = ipsecdoi_setph1proposal(iph1->approval);
+       else
+#endif
+               gss_sa = iph1->sa_ret;
+
+       /* set SA payload to reply */
+       plist = isakmp_plist_append(plist, gss_sa, ISAKMP_NPTYPE_SA);
+
+       /* Set Vendor ID, if necessary. */
+       if (vid)
+               plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+
+#ifdef ENABLE_NATT
+       /* Has the peer announced NAT-T? */
+       if (NATT_AVAILABLE(iph1))
+               vid_natt = set_vendorid(iph1->natt_options->version);
+
+       if (vid_natt)
+               plist = isakmp_plist_append(plist, vid_natt, ISAKMP_NPTYPE_VID);
+#endif
+#ifdef ENABLE_DPD
+       /* XXX only send DPD VID if remote sent it ? */
+       if(iph1->rmconf->dpd){
+               vid_dpd = set_vendorid(VENDORID_DPD);
+               if (vid_dpd != NULL)
+                       plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID);
+       }
+#endif
+
+       iph1->sendbuf = isakmp_plist_set_all (&plist, iph1);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG1SENT;
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL);
+#endif
+
+       error = 0;
+
+end:
+#ifdef HAVE_GSSAPI
+       if (gss_sa != iph1->sa_ret)
+               vfree(gss_sa);
+#endif
+       if (vid)
+               vfree(vid);
+
+#ifdef ENABLE_NATT
+       if (vid_natt)
+               vfree(vid_natt);
+#endif
+#ifdef ENABLE_DPD
+       if (vid_dpd != NULL)
+               vfree(vid_dpd);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR, KE, Ni
+ *     sig: HDR, KE, Ni
+ *   gssapi: HDR, KE, Ni, GSSi
+ *     rsa: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ *     rev: HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ *               <IDi1_b>Ke_i, [<<Cert-I_b>Ke_i]
+ */
+int
+ident_r2recv(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+#ifdef ENABLE_NATT
+       int natd_seq = 0;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               case ISAKMP_NPTYPE_CR:
+                       plog(LLV_WARNING, LOCATION, iph1->remote,
+                               "CR received, ignore it. "
+                               "It should be in other exchange.\n");
+                       break;
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATD_DRAFT:
+               case ISAKMP_NPTYPE_NATD_RFC:
+#ifdef __APPLE__
+               case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#endif
+                       if (NATT_AVAILABLE(iph1) && iph1->natt_options != NULL &&
+                           pa->type == iph1->natt_options->payload_nat_d)
+                       {
+                               vchar_t *natd_received = NULL;
+                               int natd_verified;
+                               
+                               if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
+                                       goto end;
+                               
+                               if (natd_seq == 0)
+                                       iph1->natt_flags |= NAT_DETECTED;
+                               
+                               natd_verified = natt_compare_addr_hash (iph1,
+                                       natd_received, natd_seq++);
+                               
+                               plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
+                                       natd_seq - 1,
+                                       natd_verified ? "verified" : "doesn't match");
+                               
+                               vfree (natd_received);
+                               break;
+                       }
+                       /* %%%% Be lenient here - some servers send natd payloads */
+                       /* when no nat is detected                                                                */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+#ifdef ENABLE_NATT
+       if (NATT_AVAILABLE(iph1))
+               plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
+                     iph1->natt_flags & NAT_DETECTED ? 
+                               "detected:" : "not detected",
+                     iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
+                     iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
+#endif
+
+       /* payload existency check */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       iph1->status = PHASE1ST_MSG2RECEIVED;
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+#ifdef HAVE_GSSAPI
+       if (gsstoken)
+               vfree(gsstoken);
+#endif
+
+       if (error) {
+               VPTRINIT(iph1->dhpub_p);
+               VPTRINIT(iph1->nonce_p);
+               VPTRINIT(iph1->id_p);
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR, KE, Nr
+ *     sig: HDR, KE, Nr [, CR ]
+ *   gssapi: HDR, KE, Nr, GSSr
+ *     rsa: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ *     rev: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r,
+ */
+int
+ident_r2send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* generate DH public value */
+       if (oakley_dh_generate(iph1->approval->dhgrp,
+                               &iph1->dhpub, &iph1->dhpriv) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+       if (iph1->nonce == NULL)
+               goto end;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+               gssapi_get_rtoken(iph1, NULL);
+#endif
+
+       /* create HDR;KE;NONCE payload */
+       iph1->sendbuf = ident_ir2mx(iph1);
+       if (iph1->sendbuf == NULL)
+               goto end;
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
+#endif
+
+       /* send the packet, add to the schedule to resend */
+       iph1->retry_counter = iph1->rmconf->retry_counter;
+       if (isakmp_ph1resend(iph1) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* compute sharing secret of DH */
+       if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub,
+                               iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0)
+               goto end;
+
+       /* generate SKEYIDs & IV & final cipher key */
+       if (oakley_skeyid(iph1) < 0)
+               goto end;
+       if (oakley_skeyid_dae(iph1) < 0)
+               goto end;
+       if (oakley_compute_enckey(iph1) < 0)
+               goto end;
+       if (oakley_newiv(iph1) < 0)
+               goto end;
+
+       iph1->status = PHASE1ST_MSG2SENT;
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     psk: HDR*, IDi1, HASH_I
+ *     sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I
+ *   gssapi: HDR*, [ IDi1, ] < GSSi(n) | HASH_I >
+ *     rsa: HDR*, HASH_I
+ *     rev: HDR*, HASH_I
+ */
+int
+ident_r3recv(iph1, msg0)
+       struct ph1handle *iph1;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+       int error = -1;
+       int type;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG2SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* decrypting */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "reject the packet, "
+                       "expecting the packet encrypted.\n");
+               goto end;
+       }
+       msg = oakley_do_decrypt(iph1, msg0, iph1->ivm->iv, iph1->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       iph1->pl_hash = NULL;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_ID:
+                       if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_CR:
+                       if (oakley_savecr(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_CERT:
+                       if (oakley_savecert(iph1, pa->ptr) < 0)
+                               goto end;
+                       break;
+               case ISAKMP_NPTYPE_SIG:
+                       if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+#ifdef HAVE_GSSAPI
+               case ISAKMP_NPTYPE_GSS:
+                       if (isakmp_p2ph(&gsstoken, pa->ptr) < 0)
+                               goto end;
+                       gssapi_save_received_token(iph1, gsstoken);
+                       break;
+#endif
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph1);
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+       /* XXX same as ident_i4recv(), should be merged. */
+    {
+       int ng = 0;
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               if (iph1->id_p == NULL || iph1->pl_hash == NULL)
+                       ng++;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+               if (iph1->id_p == NULL || iph1->sig_p == NULL)
+                       ng++;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               if (iph1->pl_hash == NULL)
+                       ng++;
+               break;
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               if (gsstoken == NULL && iph1->pl_hash == NULL)
+                       ng++;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid authmethod %d why ?\n",
+                       iph1->approval->authmethod);
+               goto end;
+       }
+       if (ng) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+    }
+
+       /* verify identifier */
+       if (ipsecdoi_checkid1(iph1) != 0) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid ID payload.\n");
+               goto end;
+       }
+
+       /* validate authentication value */
+#ifdef HAVE_GSSAPI
+       if (gsstoken == NULL) {
+#endif
+               type = oakley_validate_auth(iph1);
+               if (type != 0) {
+                       if (type == -1) {
+                               /* msg printed inner oakley_validate_auth() */
+                               goto end;
+                       }
+                       EVT_PUSH(iph1->local, iph1->remote, 
+                           EVTT_PEERPH1AUTH_FAILED, NULL);
+                       isakmp_info_send_n1(iph1, type, NULL);
+                       goto end;
+               }
+#ifdef HAVE_GSSAPI
+       }
+#endif
+
+       if (oakley_checkcr(iph1) < 0) {
+               /* Ignore this error in order to be interoperability. */
+               ;
+       }
+
+       /*
+        * XXX: Should we do compare two addresses, ph1handle's and ID
+        * payload's.
+        */
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote, "peer's ID\n");
+       plogdump(LLV_DEBUG, iph1->id_p->v, iph1->id_p->l);
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->ive->l);
+
+#ifdef HAVE_GSSAPI
+       iph1->status = gsstoken != NULL ? PHASE1ST_MSG2RECEIVED :
+           PHASE1ST_MSG3RECEIVED;
+#else
+       iph1->status = PHASE1ST_MSG3RECEIVED;
+#endif
+
+       error = 0;
+
+end:
+       if (pbuf)
+               vfree(pbuf);
+       if (msg)
+               vfree(msg);
+#ifdef HAVE_GSSAPI
+       if (gsstoken)
+               vfree(gsstoken);
+#endif
+
+       if (error) {
+               VPTRINIT(iph1->id_p);
+               oakley_delcert(iph1->cert_p);
+               iph1->cert_p = NULL;
+               oakley_delcert(iph1->crl_p);
+               iph1->crl_p = NULL;
+               VPTRINIT(iph1->sig_p);
+               oakley_delcert(iph1->cr_p);
+               iph1->cr_p = NULL;
+       }
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     psk: HDR*, IDr1, HASH_R
+ *     sig: HDR*, IDr1, [ CERT, ] SIG_R
+ *   gssapi: HDR*, IDr1, < GSSr(n) | HASH_R >
+ *     rsa: HDR*, HASH_R
+ *     rev: HDR*, HASH_R
+ */
+int
+ident_r3send(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       int error = -1;
+       int dohash = 1;
+#ifdef HAVE_GSSAPI
+       int len;
+#endif
+
+       /* validity check */
+       if (iph1->status != PHASE1ST_MSG3RECEIVED) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph1->status);
+               goto end;
+       }
+
+       /* make ID payload into isakmp status */
+       if (ipsecdoi_setid1(iph1) < 0)
+               goto end;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+           gssapi_more_tokens(iph1)) {
+               gssapi_get_rtoken(iph1, &len);
+               if (len != 0)
+                       dohash = 0;
+       }
+#endif
+
+       if (dohash) {
+               /* generate HASH to send */
+               plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_R\n");
+               iph1->hash = oakley_ph1hash_common(iph1, GENERATE);
+               if (iph1->hash == NULL)
+                       goto end;
+       } else
+               iph1->hash = NULL;
+
+       /* set encryption flag */
+       iph1->flags |= ISAKMP_FLAG_E;
+
+       /* create HDR;ID;HASH payload */
+       iph1->sendbuf = ident_ir3mx(iph1);
+       if (iph1->sendbuf == NULL)
+               goto end;
+
+       /* send HDR;ID;HASH to responder */
+       if (isakmp_send(iph1, iph1->sendbuf) < 0)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* see handler.h about IV synchronization. */
+       memcpy(iph1->ivm->ive->v, iph1->ivm->iv->v, iph1->ivm->iv->l);
+
+       iph1->status = PHASE1ST_ESTABLISHED;
+
+       error = 0;
+
+end:
+
+       return error;
+}
+
+/*
+ * This is used in main mode for:
+ * initiator's 3rd exchange send to responder
+ *     psk: HDR, KE, Ni
+ *     sig: HDR, KE, Ni
+ *     rsa: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ *     rev: HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ *               <IDi1_b>Ke_i, [<<Cert-I_b>Ke_i]
+ * responders 2nd exchnage send to initiator
+ *     psk: HDR, KE, Nr
+ *     sig: HDR, KE, Nr [, CR ]
+ *     rsa: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ *     rev: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r,
+ */
+static vchar_t *
+ident_ir2mx(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf = 0;
+       struct payload_list *plist = NULL;
+       int need_cr = 0;
+       vchar_t *cr = NULL;
+       vchar_t *vid = NULL;
+       int error = -1;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstoken = NULL;
+#endif
+#ifdef ENABLE_NATT
+       vchar_t *natd[2] = { NULL, NULL };
+#endif
+
+       /* create CR if need */
+       if (iph1->side == RESPONDER
+        && iph1->rmconf->send_cr
+        && oakley_needcr(iph1->approval->authmethod)
+        && iph1->rmconf->peerscertfile == NULL) {
+               need_cr = 1;
+               cr = oakley_getcr(iph1);
+               if (cr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get cr buffer.\n");
+                       goto end;
+               }
+       }
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+               gssapi_get_token_to_send(iph1, &gsstoken);
+#endif
+
+       /* create isakmp KE payload */
+       plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE);
+
+       /* create isakmp NONCE payload */
+       plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+               plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
+#endif
+
+       /* append vendor id, if needed */
+       if (vid)
+               plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
+
+       /* create isakmp CR payload if needed */
+       if (need_cr)
+               plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+
+#ifdef ENABLE_NATT
+       /* generate and append NAT-D payloads */
+       if (NATT_AVAILABLE(iph1) && iph1->status == PHASE1ST_MSG2RECEIVED)
+       {
+               if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->remote));
+                       goto end;
+               }
+
+               if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "NAT-D hashing failed for %s\n", saddr2str(iph1->local));
+                       goto end;
+               }
+
+               plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n");
+#ifdef __APPLE__
+               /* old Apple version sends natd payloads in the wrong order */
+               if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+               } else
+#endif
+               {
+                       plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d);
+                       plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
+               }
+       }
+#endif
+       
+       buf = isakmp_plist_set_all (&plist, iph1);
+       
+       error = 0;
+
+end:
+       if (error && buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+       if (cr)
+               vfree(cr);
+#ifdef HAVE_GSSAPI
+       if (gsstoken)
+               vfree(gsstoken);
+#endif
+       if (vid)
+               vfree(vid);
+
+#ifdef ENABLE_NATT
+       if (natd[0])
+               vfree(natd[0]);
+       if (natd[1])
+               vfree(natd[1]);
+#endif
+
+       return buf;
+}
+
+/*
+ * This is used in main mode for:
+ * initiator's 4th exchange send to responder
+ *     psk: HDR*, IDi1, HASH_I
+ *     sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I
+ *   gssapi: HDR*, [ IDi1, ] < GSSi(n) | HASH_I >
+ *     rsa: HDR*, HASH_I
+ *     rev: HDR*, HASH_I
+ * responders 3rd exchnage send to initiator
+ *     psk: HDR*, IDr1, HASH_R
+ *     sig: HDR*, IDr1, [ CERT, ] SIG_R
+ *   gssapi: HDR*, [ IDr1, ] < GSSr(n) | HASH_R >
+ *     rsa: HDR*, HASH_R
+ *     rev: HDR*, HASH_R
+ */
+static vchar_t *
+ident_ir3mx(iph1)
+       struct ph1handle *iph1;
+{
+       struct payload_list *plist = NULL;
+       vchar_t *buf = NULL, *new = NULL;
+       int need_cr = 0;
+       int need_cert = 0;
+       vchar_t *cr = NULL;
+       int error = -1;
+#ifdef HAVE_GSSAPI
+       int nptype;
+       vchar_t *gsstoken = NULL;
+       vchar_t *gsshash = NULL;
+#endif
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               /* create isakmp ID payload */
+               plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+               /* create isakmp HASH payload */
+               plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH);
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+               if (oakley_getmycert(iph1) < 0)
+                       goto end;
+
+               if (oakley_getsign(iph1) < 0)
+                       goto end;
+
+               /* create CR if need */
+               if (iph1->side == INITIATOR
+                && iph1->rmconf->send_cr
+                && oakley_needcr(iph1->approval->authmethod)
+                && iph1->rmconf->peerscertfile == NULL) {
+                       need_cr = 1;
+                       cr = oakley_getcr(iph1);
+                       if (cr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get cr buffer.\n");
+                               goto end;
+                       }
+               }
+
+               if (iph1->cert != NULL && iph1->rmconf->send_cert)
+                       need_cert = 1;
+
+               /* add ID payload */
+               plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+
+               /* add CERT payload if there */
+               if (need_cert)
+                       plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+               /* add SIG payload */
+               plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
+
+               /* create isakmp CR payload */
+               if (need_cr)
+                       plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+               break;
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               if (iph1->hash != NULL) {
+                       gsshash = gssapi_wraphash(iph1);
+                       if (gsshash == NULL)
+                               goto end;
+               } else {
+                       gssapi_get_token_to_send(iph1, &gsstoken);
+               }
+
+               if (!gssapi_id_sent(iph1)) {
+                       /* create isakmp ID payload */
+                       plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
+                       gssapi_set_id_sent(iph1);
+               }
+
+               if (iph1->hash != NULL)
+                       /* create isakmp HASH payload */
+                       plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH);
+               else
+                       plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
+               break;
+#endif
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not supported authentication type %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid authentication type %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+       }
+
+       buf = isakmp_plist_set_all (&plist, iph1);
+       
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(buf, iph1->local, iph1->remote, 1);
+#endif
+
+       /* encoding */
+       new = oakley_do_encrypt(iph1, buf, iph1->ivm->ive, iph1->ivm->iv);
+       if (new == NULL)
+               goto end;
+
+       vfree(buf);
+
+       buf = new;
+
+       error = 0;
+
+end:
+       if (cr)
+               vfree(cr);
+       if (error && buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+
+       return buf;
+}
diff --git a/ipsec-tools/racoon/isakmp_ident.h b/ipsec-tools/racoon/isakmp_ident.h
new file mode 100644 (file)
index 0000000..38fb875
--- /dev/null
@@ -0,0 +1,50 @@
+/* $Id: isakmp_ident.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_IDENT_H
+#define _ISAKMP_IDENT_H
+
+extern int ident_i1send __P((struct ph1handle *, vchar_t *));
+extern int ident_i2recv __P((struct ph1handle *, vchar_t *));
+extern int ident_i2send __P((struct ph1handle *, vchar_t *));
+extern int ident_i3recv __P((struct ph1handle *, vchar_t *));
+extern int ident_i3send __P((struct ph1handle *, vchar_t *));
+extern int ident_i4recv __P((struct ph1handle *, vchar_t *));
+extern int ident_i4send __P((struct ph1handle *, vchar_t *));
+
+extern int ident_r1recv __P((struct ph1handle *, vchar_t *));
+extern int ident_r1send __P((struct ph1handle *, vchar_t *));
+extern int ident_r2recv __P((struct ph1handle *, vchar_t *));
+extern int ident_r2send __P((struct ph1handle *, vchar_t *));
+extern int ident_r3recv __P((struct ph1handle *, vchar_t *));
+extern int ident_r3send __P((struct ph1handle *, vchar_t *));
+
+#endif /* _ISAKMP_IDENT_H */
diff --git a/ipsec-tools/racoon/isakmp_inf.c b/ipsec-tools/racoon/isakmp_inf.c
new file mode 100644 (file)
index 0000000..a681061
--- /dev/null
@@ -0,0 +1,1799 @@
+/* $Id: isakmp_inf.c,v 1.14.4.9 2005/08/02 15:09:26 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet/in.h>
+#include <sys/queue.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "libpfkey.h"
+
+#include "var.h"
+#include "vmbuf.h"
+#include "schedule.h"
+#include "str2val.h"
+#include "misc.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "sockmisc.h"
+#include "isakmp_var.h"
+#include "evt.h"
+#include "isakmp.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h" 
+#endif
+#include "isakmp_inf.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "policy.h"
+#include "algorithm.h"
+#include "proposal.h"
+#include "admin.h"
+#include "strnames.h"
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#include "vpn_control_var.h"
+#include "vpn_control.h"
+
+/* information exchange */
+static int isakmp_info_recv_n __P((struct ph1handle *, vchar_t *, int));
+static int isakmp_info_recv_d __P((struct ph1handle *, vchar_t *));
+
+#ifdef ENABLE_DPD
+static int isakmp_info_recv_r_u __P((struct ph1handle *,
+       struct isakmp_pl_ru *, u_int32_t));
+static int isakmp_info_recv_r_u_ack __P((struct ph1handle *,
+       struct isakmp_pl_ru *, u_int32_t));
+static void isakmp_info_send_r_u __P((void *));
+#endif
+
+#ifdef ENABLE_VPNCONTROL_PORT
+static int isakmp_info_recv_lb __P((struct ph1handle *, struct isakmp_pl_lb *lb, int));
+#endif
+
+static void purge_isakmp_spi __P((int, isakmp_index *, size_t));
+static void purge_ipsec_spi __P((struct sockaddr *, int, u_int32_t *, size_t));
+static void info_recv_initialcontact __P((struct ph1handle *));
+
+/* \f%%%
+ * Information Exchange
+ */
+/*
+ * receive Information
+ */
+int
+isakmp_info_recv(iph1, msg0)
+       struct ph1handle *iph1;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       int error = -1;
+       struct isakmp *isakmp;
+       struct isakmp_gen *gen;
+       void *p;
+       vchar_t *hash, *payload;
+       struct isakmp_gen *nd;
+       u_int8_t np;
+       int encrypted;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "receive Information.\n");
+
+       encrypted = ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E);
+
+       /* Use new IV to decrypt Informational message. */
+       if (encrypted) {
+
+               struct isakmp_ivm *ivm;
+
+               /* compute IV */
+               ivm = oakley_newiv2(iph1, ((struct isakmp *)msg0->v)->msgid);
+               if (ivm == NULL)
+                       return -1;
+
+               msg = oakley_do_decrypt(iph1, msg0, ivm->iv, ivm->ive);
+               oakley_delivm(ivm);
+               if (msg == NULL)
+                       return -1;
+
+       } else
+               msg = vdup(msg0);
+
+       /* Safety check */
+       if (msg->l < sizeof(*isakmp) + sizeof(*gen)) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "ignore information because the "
+                       "message is way too short\n");
+               goto end;
+       }
+
+       isakmp = (struct isakmp *)msg->v;
+       gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp));
+       np = gen->np;
+
+       if (encrypted) {
+               if (isakmp->np != ISAKMP_NPTYPE_HASH) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "ignore information because the "
+                           "message has no hash payload.\n");
+                       goto end;
+               }
+
+               if (iph1->status != PHASE1ST_ESTABLISHED) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "ignore information because ISAKMP-SA "
+                           "has not been established yet.\n");
+                       goto end;
+               }
+
+               /* Safety check */
+               if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                               "ignore information because the "
+                               "message is too short\n");
+                       goto end;
+               }
+
+               p = (caddr_t) gen + sizeof(struct isakmp_gen);
+               nd = (struct isakmp_gen *) ((caddr_t) gen + ntohs(gen->len));
+
+               /* nd length check */
+               if (ntohs(nd->len) > msg->l - (sizeof(struct isakmp) +
+                   ntohs(gen->len))) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "too long payload length (broken message?)\n");
+                       goto end;
+               }
+
+               if (ntohs(nd->len) < sizeof(*nd)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "too short payload length (broken message?)\n");
+                       goto end;
+               }
+
+               payload = vmalloc(ntohs(nd->len));
+               if (payload == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "cannot allocate memory\n");
+                       goto end;
+               }
+
+               memcpy(payload->v, (caddr_t) nd, ntohs(nd->len));
+
+               /* compute HASH */
+               hash = oakley_compute_hash1(iph1, isakmp->msgid, payload);
+               if (hash == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "cannot compute hash\n");
+
+                       vfree(payload);
+                       goto end;
+               }
+               
+               if (ntohs(gen->len) - sizeof(struct isakmp_gen) != hash->l) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "ignore information due to hash length mismatch\n");
+
+                       vfree(hash);
+                       vfree(payload);
+                       goto end;
+               }
+
+               if (memcmp(p, hash->v, hash->l) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "ignore information due to hash mismatch\n");
+
+                       vfree(hash);
+                       vfree(payload);
+                       goto end;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL, "hash validated.\n");
+
+               vfree(hash);
+               vfree(payload);
+       } else {
+               /* make sure the packet were encrypted after the beginning of phase 1. */
+               switch (iph1->etype) {
+               case ISAKMP_ETYPE_AGG:
+               case ISAKMP_ETYPE_BASE:
+               case ISAKMP_ETYPE_IDENT:
+                       if ((iph1->side == INITIATOR && iph1->status < PHASE1ST_MSG3SENT)
+                        || (iph1->side == RESPONDER && iph1->status < PHASE1ST_MSG2SENT)) {
+                               break;
+                       }
+                       /*FALLTHRU*/
+               default:
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "%s message must be encrypted\n",
+                               s_isakmp_nptype(np));
+                       goto end;
+               }
+       }
+
+       switch (np) {
+       case ISAKMP_NPTYPE_N:
+               isakmp_info_recv_n(iph1, msg, encrypted);
+               break;
+       case ISAKMP_NPTYPE_D:
+               if (encrypted)
+                       isakmp_info_recv_d(iph1, msg);
+               else
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "unencrypted information message with delete payload received\n");
+               break;
+       case ISAKMP_NPTYPE_NONCE:
+               /* XXX to be 6.4.2 ike-01.txt */
+               /* XXX IV is to be synchronized. */
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "ignore Acknowledged Informational\n");
+               break;
+       default:
+               /* don't send information, see isakmp_ident_r1() */
+               error = 0;
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "reject the packet, "
+                       "received unexpecting payload type %d.\n",
+                       gen->np);
+               break;
+       }
+
+    end:
+       if (msg != NULL)
+               vfree(msg);
+
+       return 0;
+}
+
+/*
+ * send Delete payload (for ISAKMP SA) in Informational exchange.
+ */
+int
+isakmp_info_send_d1(iph1)
+       struct ph1handle *iph1;
+{
+       struct isakmp_pl_d *d;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+
+       if (iph1->status != PHASE2ST_ESTABLISHED)
+               return 0;
+
+       /* create delete payload */
+
+       /* send SPIs of inbound SAs. */
+       /* XXX should send outbound SAs's ? */
+       tlen = sizeof(*d) + sizeof(isakmp_index);
+       payload = vmalloc(tlen);
+       if (payload == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                       "failed to get buffer for payload.\n");
+               return errno;
+       }
+
+       d = (struct isakmp_pl_d *)payload->v;
+       d->h.np = ISAKMP_NPTYPE_NONE;
+       d->h.len = htons(tlen);
+       d->doi = htonl(IPSEC_DOI);
+       d->proto_id = IPSECDOI_PROTO_ISAKMP;
+       d->spi_size = sizeof(isakmp_index);
+       d->num_spi = htons(1);
+       memcpy(d + 1, &iph1->index, sizeof(isakmp_index));
+
+       error = isakmp_info_send_common(iph1, payload,
+                                       ISAKMP_NPTYPE_D, 0);
+       vfree(payload);
+
+       return error;
+}
+
+/*
+ * send Delete payload (for IPsec SA) in Informational exchange, based on
+ * pfkey msg.  It sends always single SPI.
+ */
+int
+isakmp_info_send_d2(iph2)
+       struct ph2handle *iph2;
+{
+       struct ph1handle *iph1;
+       struct saproto *pr;
+       struct isakmp_pl_d *d;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+       u_int8_t *spi;
+
+       if (iph2->status != PHASE2ST_ESTABLISHED)
+               return 0;
+
+       /*
+        * don't send delete information if there is no phase 1 handler.
+        * It's nonsensical to negotiate phase 1 to send the information.
+        */
+       iph1 = getph1byaddr(iph2->src, iph2->dst); 
+       if (iph1 == NULL)
+               return 0;
+
+       /* create delete payload */
+       for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+
+               /* send SPIs of inbound SAs. */
+               /*
+                * XXX should I send outbound SAs's ?
+                * I send inbound SAs's SPI only at the moment because I can't
+                * decode any more if peer send encoded packet without aware of
+                * deletion of SA.  Outbound SAs don't come under the situation.
+                */
+               tlen = sizeof(*d) + pr->spisize;
+               payload = vmalloc(tlen);
+               if (payload == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                               "failed to get buffer for payload.\n");
+                       return errno;
+               }
+
+               d = (struct isakmp_pl_d *)payload->v;
+               d->h.np = ISAKMP_NPTYPE_NONE;
+               d->h.len = htons(tlen);
+               d->doi = htonl(IPSEC_DOI);
+               d->proto_id = pr->proto_id;
+               d->spi_size = pr->spisize;
+               d->num_spi = htons(1);
+               /*
+                * XXX SPI bits are left-filled, for use with IPComp.
+                * we should be switching to variable-length spi field...
+                */
+               spi = (u_int8_t *)&pr->spi;
+               spi += sizeof(pr->spi);
+               spi -= pr->spisize;
+               memcpy(d + 1, spi, pr->spisize);
+
+               error = isakmp_info_send_common(iph1, payload,
+                                               ISAKMP_NPTYPE_D, 0);
+               vfree(payload);
+       }
+
+       return error;
+}
+
+/*
+ * send Notification payload (for without ISAKMP SA) in Informational exchange
+ */
+int
+isakmp_info_send_nx(isakmp, remote, local, type, data)
+       struct isakmp *isakmp;
+       struct sockaddr *remote, *local;
+       int type;
+       vchar_t *data;
+{
+       struct ph1handle *iph1 = NULL;
+       struct remoteconf *rmconf;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = -1;
+       struct isakmp_pl_n *n;
+       int spisiz = 0;         /* see below */
+
+       /* search appropreate configuration */
+       rmconf = getrmconf(remote);
+       if (rmconf == NULL) {
+               plog(LLV_ERROR, LOCATION, remote,
+                       "no configuration found for peer address.\n");
+               goto end;
+       }
+
+       /* add new entry to isakmp status table. */
+       iph1 = newph1();
+       if (iph1 == NULL)
+               return -1;
+
+       memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t));
+       isakmp_newcookie((char *)&iph1->index.r_ck, remote, local);
+       iph1->status = PHASE1ST_START;
+       iph1->rmconf = rmconf;
+       iph1->side = INITIATOR;
+       iph1->version = isakmp->v;
+       iph1->flags = 0;
+       iph1->msgid = 0;        /* XXX */
+#ifdef ENABLE_HYBRID
+       if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL)
+               return -1;
+#endif
+#ifdef ENABLE_FRAG
+       iph1->frag = 0;
+       iph1->frag_chain = NULL;
+#endif
+
+       /* copy remote address */
+       if (copy_ph1addresses(iph1, rmconf, remote, local) < 0)
+               return -1;
+
+       tlen = sizeof(*n) + spisiz;
+       if (data)
+               tlen += data->l;
+       payload = vmalloc(tlen);
+       if (payload == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       n = (struct isakmp_pl_n *)payload->v;
+       n->h.np = ISAKMP_NPTYPE_NONE;
+       n->h.len = htons(tlen);
+       n->doi = htonl(IPSEC_DOI);
+       n->proto_id = IPSECDOI_KEY_IKE;
+       n->spi_size = spisiz;
+       n->type = htons(type);
+       if (spisiz)
+               memset(n + 1, 0, spisiz);       /*XXX*/
+       if (data)
+               memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l);
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       {
+               u_int32_t address;
+               if (type == ISAKMP_INTERNAL_ERROR ||
+                       type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) {
+                       if (remote->sa_family == AF_INET)
+                               address = ((struct sockaddr_in *)remote)->sin_addr.s_addr;
+                       else
+                               address = 0;
+                       (void)vpncontrol_notify_ike_failed(type, FROM_LOCAL, address,
+                                       (data ? data->l : 0), (data ? data->v : NULL));
+               }
+       }
+#endif
+
+       error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0);
+       vfree(payload);
+
+    end:
+       if (iph1 != NULL)
+               delph1(iph1);
+
+       return error;
+}
+
+/*
+ * send Notification payload (for ISAKMP SA) in Informational exchange
+ */
+int
+isakmp_info_send_n1(iph1, type, data)
+       struct ph1handle *iph1;
+       int type;
+       vchar_t *data;
+{
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+       struct isakmp_pl_n *n;
+       int spisiz;
+
+       /*
+        * note on SPI size: which description is correct?  I have chosen
+        * this to be 0.
+        *
+        * RFC2408 3.1, 2nd paragraph says: ISAKMP SA is identified by
+        * Initiator/Responder cookie and SPI has no meaning, SPI size = 0.
+        * RFC2408 3.1, first paragraph on page 40: ISAKMP SA is identified
+        * by cookie and SPI has no meaning, 0 <= SPI size <= 16.
+        * RFC2407 4.6.3.3, INITIAL-CONTACT is required to set to 16.
+        */
+       if (type == ISAKMP_NTYPE_INITIAL_CONTACT ||
+                       type == ISAKMP_NTYPE_LOAD_BALANCE)
+               spisiz = sizeof(isakmp_index);
+       else
+               spisiz = 0;
+
+       tlen = sizeof(*n) + spisiz;
+       if (data)
+               tlen += data->l;
+       payload = vmalloc(tlen);
+       if (payload == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               return errno;
+       }
+
+       n = (struct isakmp_pl_n *)payload->v;
+       n->h.np = ISAKMP_NPTYPE_NONE;
+       n->h.len = htons(tlen);
+       n->doi = htonl(iph1->rmconf->doitype);
+       n->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX to be configurable ? */
+       n->spi_size = spisiz;
+       n->type = htons(type);
+       if (spisiz)
+               memcpy(n + 1, &iph1->index, sizeof(isakmp_index));
+       if (data)
+               memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l);
+
+#ifdef ENABLE_VPNCONTROL_PORT  
+       {
+               u_int32_t address;
+               
+               if (type == ISAKMP_INTERNAL_ERROR ||
+                       type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) {
+                       if (iph1->remote->sa_family == AF_INET)
+                               address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
+                       else
+                               address = 0;
+                       (void)vpncontrol_notify_ike_failed(type, FROM_LOCAL, address, 
+                                       (data ? data->l : 0), (data ? data->v : NULL));
+               }
+       }
+#endif
+
+       error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph1->flags);
+       vfree(payload);
+
+       return error;
+}
+
+/*
+ * send Notification payload (for IPsec SA) in Informational exchange
+ */
+int
+isakmp_info_send_n2(iph2, type, data)
+       struct ph2handle *iph2;
+       int type;
+       vchar_t *data;
+{
+       struct ph1handle *iph1 = iph2->ph1;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+       struct isakmp_pl_n *n;
+       struct saproto *pr;
+
+       if (!iph2->approval)
+               return EINVAL;
+
+       pr = iph2->approval->head;
+
+       /* XXX must be get proper spi */
+       tlen = sizeof(*n) + pr->spisize;
+       if (data)
+               tlen += data->l;
+       payload = vmalloc(tlen);
+       if (payload == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               return errno;
+       }
+
+       n = (struct isakmp_pl_n *)payload->v;
+       n->h.np = ISAKMP_NPTYPE_NONE;
+       n->h.len = htons(tlen);
+       n->doi = htonl(IPSEC_DOI);              /* IPSEC DOI (1) */
+       n->proto_id = pr->proto_id;             /* IPSEC AH/ESP/whatever*/
+       n->spi_size = pr->spisize;
+       n->type = htons(type);
+       *(u_int32_t *)(n + 1) = pr->spi;
+       if (data)
+               memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l);
+
+       iph2->flags |= ISAKMP_FLAG_E;   /* XXX Should we do FLAG_A ? */
+       error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph2->flags);
+       vfree(payload);
+
+       return error;
+}
+
+/*
+ * send Information
+ * When ph1->skeyid_a == NULL, send message without encoding.
+ */
+int
+isakmp_info_send_common(iph1, payload, np, flags)
+       struct ph1handle *iph1;
+       vchar_t *payload;
+       u_int32_t np;
+       int flags;
+{
+       struct ph2handle *iph2 = NULL;
+       vchar_t *hash = NULL;
+       struct isakmp *isakmp;
+       struct isakmp_gen *gen;
+       char *p;
+       int tlen;
+       int error = -1;
+
+       /* add new entry to isakmp status table */
+       iph2 = newph2();
+       if (iph2 == NULL)
+               goto end;
+
+       iph2->dst = dupsaddr(iph1->remote);
+       iph2->src = dupsaddr(iph1->local);
+       switch (iph1->remote->sa_family) {
+       case AF_INET:
+#ifndef ENABLE_NATT
+               ((struct sockaddr_in *)iph2->dst)->sin_port = 0;
+               ((struct sockaddr_in *)iph2->src)->sin_port = 0;
+#endif
+               break;
+#ifdef INET6
+       case AF_INET6:
+               ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0;
+               ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", iph1->remote->sa_family);
+               delph2(iph2);
+               goto end;
+       }
+       iph2->ph1 = iph1;
+       iph2->side = INITIATOR;
+       iph2->status = PHASE2ST_START;
+       iph2->msgid = isakmp_newmsgid2(iph1);
+
+       /* get IV and HASH(1) if skeyid_a was generated. */
+       if (iph1->skeyid_a != NULL) {
+               iph2->ivm = oakley_newiv2(iph1, iph2->msgid);
+               if (iph2->ivm == NULL) {
+                       delph2(iph2);
+                       goto end;
+               }
+
+               /* generate HASH(1) */
+               hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload);
+               if (hash == NULL) {
+                       delph2(iph2);
+                       goto end;
+               }
+
+               /* initialized total buffer length */
+               tlen = hash->l;
+               tlen += sizeof(*gen);
+       } else {
+               /* IKE-SA is not established */
+               hash = NULL;
+
+               /* initialized total buffer length */
+               tlen = 0;
+       }
+       if ((flags & ISAKMP_FLAG_A) == 0)
+               iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E);
+       else
+               iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A);
+
+       insph2(iph2);
+       bindph12(iph1, iph2);
+
+       tlen += sizeof(*isakmp) + payload->l;
+
+       /* create buffer for isakmp payload */
+       iph2->sendbuf = vmalloc(tlen);
+       if (iph2->sendbuf == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto err;
+       }
+
+       /* create isakmp header */
+       isakmp = (struct isakmp *)iph2->sendbuf->v;
+       memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t));
+       memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t));
+       isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH;
+       isakmp->v = iph1->version;
+       isakmp->etype = ISAKMP_ETYPE_INFO;
+       isakmp->flags = iph2->flags;
+       memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid));
+       isakmp->len   = htonl(tlen);
+       p = (char *)(isakmp + 1);
+
+       /* create HASH payload */
+       if (hash != NULL) {
+               gen = (struct isakmp_gen *)p;
+               gen->np = np & 0xff;
+               gen->len = htons(sizeof(*gen) + hash->l);
+               p += sizeof(*gen);
+               memcpy(p, hash->v, hash->l);
+               p += hash->l;
+       }
+
+       /* add payload */
+       memcpy(p, payload->v, payload->l);
+       p += payload->l;
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1);
+#endif
+
+       /* encoding */
+       if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) {
+               vchar_t *tmp;
+
+               tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, iph2->ivm->ive,
+                               iph2->ivm->iv);
+               VPTRINIT(iph2->sendbuf);
+               if (tmp == NULL)
+                       goto err;
+               iph2->sendbuf = tmp;
+       }
+
+       /* HDR*, HASH(1), N */
+       if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) {
+               VPTRINIT(iph2->sendbuf);
+               goto err;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "sendto Information %s.\n", s_isakmp_nptype(np));
+
+       /*
+        * don't resend notify message because peer can use Acknowledged
+        * Informational if peer requires the reply of the notify message.
+        */
+
+       /* XXX If Acknowledged Informational required, don't delete ph2handle */
+       error = 0;
+       VPTRINIT(iph2->sendbuf);
+       goto err;       /* XXX */
+
+end:
+       if (hash)
+               vfree(hash);
+       return error;
+
+err:
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+       goto end;
+}
+
+/*
+ * add a notify payload to buffer by reallocating buffer.
+ * If buf == NULL, the function only create a notify payload.
+ *
+ * XXX Which is SPI to be included, inbound or outbound ?
+ */
+vchar_t *
+isakmp_add_pl_n(buf0, np_p, type, pr, data)
+       vchar_t *buf0;
+       u_int8_t **np_p;
+       int type;
+       struct saproto *pr;
+       vchar_t *data;
+{
+       vchar_t *buf = NULL;
+       struct isakmp_pl_n *n;
+       int tlen;
+       int oldlen = 0;
+
+       if (*np_p)
+               **np_p = ISAKMP_NPTYPE_N;
+
+       tlen = sizeof(*n) + pr->spisize;
+
+       if (data)
+               tlen += data->l;
+       if (buf0) {
+               oldlen = buf0->l;
+               buf = vrealloc(buf0, buf0->l + tlen);
+       } else
+               buf = vmalloc(tlen);
+       if (!buf) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get a payload buffer.\n");
+               return NULL;
+       }
+
+       n = (struct isakmp_pl_n *)(buf->v + oldlen);
+       n->h.np = ISAKMP_NPTYPE_NONE;
+       n->h.len = htons(tlen);
+       n->doi = htonl(IPSEC_DOI);              /* IPSEC DOI (1) */
+       n->proto_id = pr->proto_id;             /* IPSEC AH/ESP/whatever*/
+       n->spi_size = pr->spisize;
+       n->type = htons(type);
+       *(u_int32_t *)(n + 1) = pr->spi;        /* XXX */
+       if (data)
+               memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l);
+
+       /* save the pointer of next payload type */
+       *np_p = &n->h.np;
+
+       return buf;
+}
+
+/*
+ * handling to receive Notification payload
+ */
+static int
+isakmp_info_recv_n(iph1, msg, encrypted)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+       int encrypted;
+{
+       struct isakmp_pl_n *n = NULL;
+       u_int type;
+       vchar_t *pbuf;
+       struct isakmp_parse_t *pa, *pap;
+       char *spi;
+
+       if (!(pbuf = isakmp_parse(msg)))
+               return -1;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+       for (pap = pa; pap->type; pap++) {
+               switch (pap->type) {
+               case ISAKMP_NPTYPE_HASH:
+                       /* do something here */
+                       break;
+               case ISAKMP_NPTYPE_NONCE:
+                       /* send to ack */
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       n = (struct isakmp_pl_n *)pap->ptr;
+                       break;
+               default:
+                       vfree(pbuf);
+                       return -1;
+               }
+       }
+       vfree(pbuf);
+       if (!n)
+               return -1;
+
+       type = ntohs(n->type);
+
+       switch (type) {
+       case ISAKMP_NTYPE_CONNECTED:
+       case ISAKMP_NTYPE_RESPONDER_LIFETIME:
+       case ISAKMP_NTYPE_REPLAY_STATUS:
+               /* do something */
+               break;
+       case ISAKMP_NTYPE_INITIAL_CONTACT:
+               if (encrypted)
+                       info_recv_initialcontact(iph1);
+               else
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                            "unencrypted INITIAL_CONTACT message received");
+               break;
+#ifdef ENABLE_DPD
+       case ISAKMP_NTYPE_R_U_THERE:
+               if (encrypted)
+                       isakmp_info_recv_r_u(iph1, (struct isakmp_pl_ru *)n,
+                                    ((struct isakmp *)msg->v)->msgid);
+               else
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                            "unencrypted R_U_THERE message received");
+               break;
+       case ISAKMP_NTYPE_R_U_THERE_ACK:
+               if (encrypted)
+                       isakmp_info_recv_r_u_ack(iph1, (struct isakmp_pl_ru *)n,
+                                        ((struct isakmp *)msg->v)->msgid);
+               else
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                            "unencrypted R_U_THERE_ACK received");
+               break;
+#endif
+
+#ifdef ENABLE_VPNCONTROL_PORT
+       case ISAKMP_NTYPE_LOAD_BALANCE:
+               isakmp_info_recv_lb(iph1, (struct isakmp_pl_lb *)n, encrypted);
+               break;
+#endif
+
+       default:
+               if (encrypted) {
+                       u_int32_t msgid = ((struct isakmp *)msg->v)->msgid;
+                       struct ph2handle *iph2;
+
+                       /* XXX there is a potential of dos attack. */
+                       if (msgid == 0) {
+                               /* delete ph1 */
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "delete phase1 handle.\n");
+                               return -1;
+                       } else {
+                               iph2 = getph2bymsgid(iph1, msgid);
+                               if (iph2 == NULL) {
+                                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                                               "unknown notify message, "
+                                               "no phase2 handle found.\n");
+                               } else {
+                                       /* sanity check */
+                                       if (n->h.len < (sizeof(struct isakmp_pl_n) + n->spi_size))
+                                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                                       "notification payload length invalid.\n");
+                                       else {          
+                                               
+#ifdef ENABLE_VPNCONTROL_PORT
+
+                                               u_int32_t address;
+                                               u_int16_t data_len = n->h.len - (sizeof(struct isakmp_pl_n) + n->spi_size);
+                                               u_int8_t *data_ptr = ((u_int8_t *)n) + (n->h.len - data_len);
+                                               
+                                               if (type == ISAKMP_INTERNAL_ERROR ||
+                                                       type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) {
+                                                       if (iph1->remote->sa_family == AF_INET)
+                                                               address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
+                                                       else
+                                                               address = 0;
+                                                       
+                                                       vpncontrol_notify_ike_failed(type, FROM_REMOTE, address, data_len, data_ptr);
+                                               }
+#endif
+                                               /* delete ph2 */
+                                               unbindph12(iph2);
+                                               remph2(iph2);
+                                               delph2(iph2);
+                                       }
+                               }
+                       }
+               } else
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                            "unencrypted notification message received");
+               break;
+       }
+
+       /* get spi and allocate */
+       if (ntohs(n->h.len) < sizeof(*n) + n->spi_size) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid spi_size in notification payload.\n");
+               return -1;
+       }
+       spi = val2str((char *)(n + 1), n->spi_size);
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+               "notification message %d:%s, "
+               "doi=%d proto_id=%d spi=%s(size=%d).\n",
+               type, s_isakmp_notify_msg(type),
+               ntohl(n->doi), n->proto_id, spi, n->spi_size);
+
+       racoon_free(spi);
+
+       return(0);
+}
+
+void
+purge_isakmp_spi(proto, spi, n)
+       int proto;
+       isakmp_index *spi;      /*network byteorder*/
+       size_t n;
+{
+       struct ph1handle *iph1;
+       size_t i;
+
+       for (i = 0; i < n; i++) {
+               iph1 = getph1byindex(&spi[i]);
+               if (!iph1)
+                       continue;
+
+               plog(LLV_INFO, LOCATION, NULL,
+                       "purged ISAKMP-SA proto_id=%s spi=%s.\n",
+                       s_ipsecdoi_proto(proto),
+                       isakmp_pindex(&spi[i], 0));
+
+               if (iph1->sce)
+                       SCHED_KILL(iph1->sce);
+               iph1->status = PHASE1ST_EXPIRED;
+               iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+       }
+}
+
+static void
+purge_ipsec_spi(dst0, proto, spi, n)
+       struct sockaddr *dst0;
+       int proto;
+       u_int32_t *spi; /*network byteorder*/
+       size_t n;
+{
+       vchar_t *buf = NULL;
+       struct sadb_msg *msg, *next, *end;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       struct ph2handle *iph2;
+       size_t i;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+
+       buf = pfkey_dump_sadb(ipsecdoi2pfkey_proto(proto));
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey_dump_sadb returned nothing.\n");
+               return;
+       }
+
+       msg = (struct sadb_msg *)buf->v;
+       end = (struct sadb_msg *)(buf->v + buf->l);
+
+       while (msg < end) {
+               if ((msg->sadb_msg_len << 3) < sizeof(*msg))
+                       break;
+               next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3));
+               if (msg->sadb_msg_type != SADB_DUMP) {
+                       msg = next;
+                       continue;
+               }
+
+               if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey_check (%s)\n", ipsec_strerror());
+                       msg = next;
+                       continue;
+               }
+
+               sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
+               if (!sa
+                || !mhp[SADB_EXT_ADDRESS_SRC]
+                || !mhp[SADB_EXT_ADDRESS_DST]) {
+                       msg = next;
+                       continue;
+               }
+               src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+               dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+               if (sa->sadb_sa_state != SADB_SASTATE_MATURE
+                && sa->sadb_sa_state != SADB_SASTATE_DYING) {
+                       msg = next;
+                       continue;
+               }
+
+               /* XXX n^2 algorithm, inefficient */
+
+               /* don't delete inbound SAs at the moment */
+               /* XXX should we remove SAs with opposite direction as well? */
+               if (CMPSADDR(dst0, dst)) {
+                       msg = next;
+                       continue;
+               }
+
+               for (i = 0; i < n; i++) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "check spi(packet)=%u spi(db)=%u.\n",
+                               ntohl(spi[i]), ntohl(sa->sadb_sa_spi));
+                       if (spi[i] != sa->sadb_sa_spi)
+                               continue;
+
+                       pfkey_send_delete(lcconf->sock_pfkey,
+                               msg->sadb_msg_satype,
+                               IPSEC_MODE_ANY,
+                               src, dst, sa->sadb_sa_spi);
+
+                       /*
+                        * delete a relative phase 2 handler.
+                        * continue to process if no relative phase 2 handler
+                        * exists.
+                        */
+                       iph2 = getph2bysaidx(src, dst, proto, spi[i]);
+                       if (iph2) {
+                               delete_spd(iph2);
+                               unbindph12(iph2);
+                               remph2(iph2);
+                               delph2(iph2);
+                       }
+
+                       plog(LLV_INFO, LOCATION, NULL,
+                               "purged IPsec-SA proto_id=%s spi=%u.\n",
+                               s_ipsecdoi_proto(proto),
+                               ntohl(spi[i]));
+               }
+
+               msg = next;
+       }
+
+       if (buf)
+               vfree(buf);
+}
+
+/*
+ * delete all phase2 sa relatived to the destination address.
+ * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore
+ * an INITIAL-CONTACT if we have contacted the peer.  This matches the
+ * Sun IKE behavior, and makes rekeying work much better when the peer
+ * restarts.
+ */
+static void
+info_recv_initialcontact(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf = NULL;
+       struct sadb_msg *msg, *next, *end;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       int proto_id, i;
+       struct ph2handle *iph2;
+#if 0
+       char *loc, *rem;
+#endif
+
+       if (f_local)
+               return;
+
+#if 0
+       loc = strdup(saddrwop2str(iph1->local));
+       rem = strdup(saddrwop2str(iph1->remote));
+
+       /*
+        * Purge all IPSEC-SAs for the peer.  We can do this
+        * the easy way (using a PF_KEY SADB_DELETE extension)
+        * or we can do it the hard way.
+        */
+       for (i = 0; i < pfkey_nsatypes; i++) {
+               proto_id = pfkey2ipsecdoi_proto(pfkey_satypes[i].ps_satype);
+
+               plog(LLV_INFO, LOCATION, NULL,
+                   "purging %s SAs for %s -> %s\n",
+                   pfkey_satypes[i].ps_name, loc, rem);
+               if (pfkey_send_delete_all(lcconf->sock_pfkey,
+                   pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY,
+                   iph1->local, iph1->remote) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "delete_all %s -> %s failed for %s (%s)\n",
+                           loc, rem,
+                           pfkey_satypes[i].ps_name, ipsec_strerror());
+                       goto the_hard_way;
+               }
+
+               deleteallph2(iph1->local, iph1->remote, proto_id);
+
+               plog(LLV_INFO, LOCATION, NULL,
+                   "purging %s SAs for %s -> %s\n",
+                   pfkey_satypes[i].ps_name, rem, loc);
+               if (pfkey_send_delete_all(lcconf->sock_pfkey,
+                   pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY,
+                   iph1->remote, iph1->local) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "delete_all %s -> %s failed for %s (%s)\n",
+                           rem, loc,
+                           pfkey_satypes[i].ps_name, ipsec_strerror());
+                       goto the_hard_way;
+               }
+
+               deleteallph2(iph1->remote, iph1->local, proto_id);
+       }
+
+       racoon_free(loc);
+       racoon_free(rem);
+       return;
+
+ the_hard_way:
+       racoon_free(loc);
+       racoon_free(rem);
+#endif
+
+       buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey_dump_sadb returned nothing.\n");
+               return;
+       }
+
+       msg = (struct sadb_msg *)buf->v;
+       end = (struct sadb_msg *)(buf->v + buf->l);
+
+       while (msg < end) {
+               if ((msg->sadb_msg_len << 3) < sizeof(*msg))
+                       break;
+               next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3));
+               if (msg->sadb_msg_type != SADB_DUMP) {
+                       msg = next;
+                       continue;
+               }
+
+               if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey_check (%s)\n", ipsec_strerror());
+                       msg = next;
+                       continue;
+               }
+
+               if (mhp[SADB_EXT_SA] == NULL
+                || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+                || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+                       msg = next;
+                       continue;
+               }
+               sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+               src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+               dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+               if (sa->sadb_sa_state != SADB_SASTATE_MATURE
+                && sa->sadb_sa_state != SADB_SASTATE_DYING) {
+                       msg = next;
+                       continue;
+               }
+
+               /*
+                * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that
+                * announces the sender of the message was rebooted.
+                * it is interpreted to delete all SAs which source address
+                * is the sender of the message.
+                * racoon only deletes SA which is matched both the
+                * source address and the destination accress.
+                */
+#ifdef ENABLE_NATT
+               /* 
+                * XXX RFC 3947 says that whe MUST NOT use IP+port to find old SAs
+                * from this peer !
+                */
+               if(iph1->natt_flags & NAT_DETECTED){
+                       if (CMPSADDR(iph1->local, src) == 0 &&
+                               CMPSADDR(iph1->remote, dst) == 0)
+                               ;
+                       else if (CMPSADDR(iph1->remote, src) == 0 &&
+                                        CMPSADDR(iph1->local, dst) == 0)
+                               ;
+                       else {
+                               msg = next;
+                               continue;
+                       }
+               } else
+#endif
+               /* If there is no NAT-T, we don't have to check addr + port...
+                * XXX what about a configuration with a remote peers which is not
+                * NATed, but which NATs some other peers ?
+                * Here, the INITIAl-CONTACT would also flush all those NATed peers !!
+                */
+               if (cmpsaddrwop(iph1->local, src) == 0 &&
+                   cmpsaddrwop(iph1->remote, dst) == 0)
+                       ;
+               else if (cmpsaddrwop(iph1->remote, src) == 0 &&
+                   cmpsaddrwop(iph1->local, dst) == 0)
+                       ;
+               else {
+                       msg = next;
+                       continue;
+               }
+
+               /*
+                * Make sure this is an SATYPE that we manage.
+                * This is gross; too bad we couldn't do it the
+                * easy way.
+                */
+               for (i = 0; i < pfkey_nsatypes; i++) {
+                       if (pfkey_satypes[i].ps_satype ==
+                           msg->sadb_msg_satype)
+                               break;
+               }
+               if (i == pfkey_nsatypes) {
+                       msg = next;
+                       continue;
+               }
+
+               plog(LLV_INFO, LOCATION, NULL,
+                       "purging spi=%u.\n", ntohl(sa->sadb_sa_spi));
+               pfkey_send_delete(lcconf->sock_pfkey,
+                       msg->sadb_msg_satype,
+                       IPSEC_MODE_ANY, src, dst, sa->sadb_sa_spi);
+
+               /*
+                * delete a relative phase 2 handler.
+                * continue to process if no relative phase 2 handler
+                * exists.
+                */
+               proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+               iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
+               if (iph2) {
+                       delete_spd(iph2);
+                       unbindph12(iph2);
+                       remph2(iph2);
+                       delph2(iph2);
+               }
+
+               msg = next;
+       }
+
+       vfree(buf);
+}
+
+/*
+ * handling to receive Deletion payload
+ */
+static int
+isakmp_info_recv_d(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+       struct isakmp_pl_d *d;
+       int tlen, num_spi;
+       vchar_t *pbuf;
+       struct isakmp_parse_t *pa, *pap;
+       int protected = 0;
+       union {
+               u_int32_t spi32;
+               u_int16_t spi16[2];
+       } spi;
+
+       /* validate the type of next payload */
+       if (!(pbuf = isakmp_parse(msg)))
+               return -1;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+       for (pap = pa; pap->type; pap++) {
+               switch (pap->type) {
+               case ISAKMP_NPTYPE_D:
+                       break;
+               case ISAKMP_NPTYPE_HASH:
+                       if (pap == pa) {
+                               protected++;
+                               break;
+                       }
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "received next payload type %d "
+                               "in wrong place (must be the first payload).\n",
+                               pap->type);
+                       vfree(pbuf);
+                       return -1;
+               default:
+                       /* don't send information, see isakmp_ident_r1() */
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "reject the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pap->type);
+                       vfree(pbuf);
+                       return 0;
+               }
+       }
+
+       if (!protected) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "delete payload is not proteted, "
+                       "ignored.\n");
+               vfree(pbuf);
+               return -1;
+       }
+
+       /* process a delete payload */
+       for (pap = pa; pap->type; pap++) {
+               if (pap->type != ISAKMP_NPTYPE_D)
+                       continue;
+
+               d = (struct isakmp_pl_d *)pap->ptr;
+
+               if (ntohl(d->doi) != IPSEC_DOI) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "delete payload with invalid doi:%d.\n",
+                               ntohl(d->doi));
+#ifdef ENABLE_HYBRID
+                       /*
+                        * At deconnexion time, Cisco VPN client does this
+                        * with a zero DOI. Don't give up in that situation.
+                        */
+                       if (((iph1->mode_cfg->flags &
+                           ISAKMP_CFG_VENDORID_UNITY) == 0) || (d->doi != 0))
+                               continue;
+#else
+                       continue;
+#endif
+               }
+
+               num_spi = ntohs(d->num_spi);
+               tlen = ntohs(d->h.len) - sizeof(struct isakmp_pl_d);
+
+               if (tlen != num_spi * d->spi_size) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "deletion payload with invalid length.\n");
+                       vfree(pbuf);
+                       return -1;
+               }
+
+               switch (d->proto_id) {
+               case IPSECDOI_PROTO_ISAKMP:
+                       if (d->spi_size != sizeof(isakmp_index)) {
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "delete payload with strange spi "
+                                       "size %d(proto_id:%d)\n",
+                                       d->spi_size, d->proto_id);
+                               continue;
+                       }
+
+                       if (iph1->scr)
+                               SCHED_KILL(iph1->scr);
+
+                       purge_remote(iph1);
+                       break;
+
+               case IPSECDOI_PROTO_IPSEC_AH:
+               case IPSECDOI_PROTO_IPSEC_ESP:
+                       if (d->spi_size != sizeof(u_int32_t)) {
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "delete payload with strange spi "
+                                       "size %d(proto_id:%d)\n",
+                                       d->spi_size, d->proto_id);
+                               continue;
+                       }
+                       EVT_PUSH(iph1->local, iph1->remote, 
+                           EVTT_PEER_DELETE, NULL);
+                       purge_ipsec_spi(iph1->remote, d->proto_id,
+                           (u_int32_t *)(d + 1), num_spi);
+                       break;
+
+               case IPSECDOI_PROTO_IPCOMP:
+                       /* need to handle both 16bit/32bit SPI */
+                       memset(&spi, 0, sizeof(spi));
+                       if (d->spi_size == sizeof(spi.spi16[1])) {
+                               memcpy(&spi.spi16[1], d + 1,
+                                   sizeof(spi.spi16[1]));
+                       } else if (d->spi_size == sizeof(spi.spi32))
+                               memcpy(&spi.spi32, d + 1, sizeof(spi.spi32));
+                       else {
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "delete payload with strange spi "
+                                       "size %d(proto_id:%d)\n",
+                                       d->spi_size, d->proto_id);
+                               continue;
+                       }
+                       purge_ipsec_spi(iph1->remote, d->proto_id,
+                           &spi.spi32, num_spi);
+                       break;
+
+               default:
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "deletion message received, "
+                               "invalid proto_id: %d\n",
+                               d->proto_id);
+                       continue;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL, "purged SAs.\n");
+       }
+
+       vfree(pbuf);
+
+       return 0;
+}
+
+void
+isakmp_check_notify(gen, iph1)
+       struct isakmp_gen *gen;         /* points to Notify payload */
+       struct ph1handle *iph1;
+{
+       struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen;
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+               "Notify Message received\n");
+
+       switch (ntohs(notify->type)) {
+       case ISAKMP_NTYPE_CONNECTED:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore CONNECTED notification.\n");
+               break;
+       case ISAKMP_NTYPE_RESPONDER_LIFETIME:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore RESPONDER-LIFETIME notification.\n");
+               break;
+       case ISAKMP_NTYPE_REPLAY_STATUS:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore REPLAY-STATUS notification.\n");
+               break;
+       case ISAKMP_NTYPE_INITIAL_CONTACT:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore INITIAL-CONTACT notification, "
+                       "because it is only accepted after phase1.\n");
+               break;
+       case ISAKMP_NTYPE_LOAD_BALANCE:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore LOAD-BALANCE notification, "
+                       "because it is only accepted after phase1.\n");
+               break;
+       case ISAKMP_NTYPE_HEARTBEAT:
+               plog(LLV_WARNING, LOCATION, iph1->remote,
+                       "ignore HEARTBEAT notification\n");
+               break;
+       default:
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "received unknown notification type %u.\n",
+                   ntohs(notify->type));
+       }
+
+       return;
+}
+
+#ifdef ENABLE_VPNCONTROL_PORT
+static int
+isakmp_info_recv_lb(iph1, n, encrypted)
+       struct ph1handle *iph1;
+       struct isakmp_pl_lb *n;
+       int encrypted;
+{
+
+       if (iph1->side != INITIATOR)
+       {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "LOAD-BALANCE notification ignored - we are not the initiator.\n");
+               return 0;
+       }
+       if (iph1->remote->sa_family != AF_INET) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "LOAD-BALANCE notification ignored - only supported for IPv4.\n");
+               return 0;
+       }
+       if (!encrypted) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "LOAD-BALANCE notification ignored - not protected.\n");
+               return 0;
+       }
+       if (ntohs(n->h.len) != sizeof(struct isakmp_pl_lb)) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "Invalid length of payload\n");
+               return -1;
+       }       
+       vpncontrol_notify_ike_failed(ISAKMP_NTYPE_LOAD_BALANCE, FROM_REMOTE,
+               ((struct sockaddr_in*)iph1->remote)->sin_addr.s_addr, 4, (u_int8_t*)(&(n->address)));
+       
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+                       "received LOAD_BALANCE notification - redirect address=%x.\n",
+                               ntohl(n->address));
+
+       return 0;
+}
+#endif
+
+#ifdef ENABLE_DPD
+static int
+isakmp_info_recv_r_u (iph1, ru, msgid)
+       struct ph1handle *iph1;
+       struct isakmp_pl_ru *ru;
+       u_int32_t msgid;
+{
+       struct isakmp_pl_ru *ru_ack;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+                "DPD R-U-There received\n");
+
+       /* XXX should compare cookies with iph1->index?
+          Or is this already done by calling function?  */
+       tlen = sizeof(*ru_ack);
+       payload = vmalloc(tlen);
+       if (payload == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               return errno;
+       }
+
+       ru_ack = (struct isakmp_pl_ru *)payload->v;
+       ru_ack->h.np = ISAKMP_NPTYPE_NONE;
+       ru_ack->h.len = htons(tlen);
+       ru_ack->doi = htonl(IPSEC_DOI);
+       ru_ack->type = htons(ISAKMP_NTYPE_R_U_THERE_ACK);
+       ru_ack->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ? */
+       ru_ack->spi_size = sizeof(isakmp_index);
+       memcpy(ru_ack->i_ck, ru->i_ck, sizeof(cookie_t));
+       memcpy(ru_ack->r_ck, ru->r_ck, sizeof(cookie_t));       
+       ru_ack->data = ru->data;
+
+       /* XXX Should we do FLAG_A ?  */
+       error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N,
+                                       ISAKMP_FLAG_E);
+       vfree(payload);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "received a valid R-U-THERE, ACK sent\n");
+
+       /* Should we mark tunnel as active ? */
+       return error;
+}
+
+static int
+isakmp_info_recv_r_u_ack (iph1, ru, msgid)
+       struct ph1handle *iph1;
+       struct isakmp_pl_ru *ru;
+       u_int32_t msgid;
+{
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+                "DPD R-U-There-Ack received\n");
+
+       /* XXX Maintain window of acceptable sequence numbers ?
+        * => ru->data <= iph2->dpd_seq &&
+        *    ru->data >= iph2->dpd_seq - iph2->dpd_fails ? */
+       if (ntohl(ru->data) != iph1->dpd_seq-1) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                        "Wrong DPD sequence number (%d, %d expected).\n", 
+                        ntohl(ru->data), iph1->dpd_seq-1);
+               return 0;
+       }
+
+       if (memcmp(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)) ||
+           memcmp(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t))) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                        "Cookie mismatch in DPD ACK!.\n");
+               return 0;
+       }
+
+       iph1->dpd_fails = 0;
+
+       /* Useless ??? */
+       iph1->dpd_lastack = time(NULL);
+
+       if (iph1->dpd_r_u != NULL)
+               SCHED_KILL(iph1->dpd_r_u);
+
+       isakmp_sched_r_u(iph1, 0);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "received an R-U-THERE-ACK\n");
+
+       return 0;
+}
+
+
+/*
+ * send Delete payload (for ISAKMP SA) in Informational exchange.
+ */
+static void
+isakmp_info_send_r_u(arg)
+       void *arg;
+{
+       struct ph1handle *iph1 = arg;
+
+       /* create R-U-THERE payload */
+       struct isakmp_pl_ru *ru;
+       vchar_t *payload = NULL;
+       int tlen;
+       int error = 0;
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote, "DPD monitoring....\n");
+
+       if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) {
+               EVT_PUSH(iph1->local, iph1->remote, EVTT_DPD_TIMEOUT, NULL);
+               purge_remote(iph1);
+               plog(LLV_DEBUG, LOCATION, iph1->remote,
+                        "DPD: remote seems to be dead\n");
+
+               /* Do not reschedule here: phase1 is deleted,
+                * DPD will be reactivated when a new ph1 will be negociated
+                */
+               return;
+       }
+
+       /* TODO: check recent activity to avoid useless sends... */
+
+       /* XXX: why do we have a NULL LIST_FIRST even when a Phase2 exists ??? */
+#if 0
+       if (LIST_FIRST(&iph1->ph2tree) == NULL){
+               /* XXX: No Ph2 => no need to test ph1 ?
+                */
+               /* Reschedule the r_u_there....
+                  XXX: reschedule when a new ph2 ?
+                */
+               isakmp_sched_r_u(iph1, 0);
+               plog(LLV_DEBUG, LOCATION, iph1->remote,
+                        "no phase2 handler, rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_interval);
+               return 0;
+       }
+#endif
+
+       tlen = sizeof(*ru);
+       payload = vmalloc(tlen);
+       if (payload == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                        "failed to get buffer for payload.\n");
+               return;
+       }
+       ru = (struct isakmp_pl_ru *)payload->v;
+       ru->h.np = ISAKMP_NPTYPE_NONE;
+       ru->h.len = htons(tlen);
+       ru->doi = htonl(IPSEC_DOI);
+       ru->type = htons(ISAKMP_NTYPE_R_U_THERE);
+       ru->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ?*/
+       ru->spi_size = sizeof(isakmp_index);
+
+       memcpy(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t));
+       memcpy(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t));
+
+       if (iph1->dpd_seq == 0){
+               /* generate a random seq which is not too big */
+               srand(time(NULL));
+               iph1->dpd_seq = rand() & 0x0fff;
+       }
+
+       ru->data = htonl(iph1->dpd_seq);
+
+       error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0);
+       vfree(payload);
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+                "DPD R-U-There sent (%d)\n", error);
+
+       /* will be decreased if ACK received... */
+       iph1->dpd_fails++;
+
+       /* XXX should be increased only when ACKed ? */
+       iph1->dpd_seq++;
+
+       /* Reschedule the r_u_there with a short delay,
+        * will be deleted/rescheduled if ACK received before */
+       isakmp_sched_r_u(iph1, 1);
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+                "rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_retry);
+}
+
+/* Schedule a new R-U-THERE */
+int
+isakmp_sched_r_u(iph1, retry)
+       struct ph1handle *iph1;
+       int retry;
+{
+       if(iph1 == NULL ||
+          iph1->rmconf == NULL)
+               return 1;
+
+
+       if(iph1->dpd_support == 0 ||
+          iph1->rmconf->dpd_interval == 0)
+               return 0;
+
+       if(retry)
+               iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_retry,
+                                         isakmp_info_send_r_u, iph1);
+       else
+               sched_new(iph1->rmconf->dpd_interval,
+                         isakmp_info_send_r_u, iph1);
+
+       return 0;
+}
+#endif
diff --git a/ipsec-tools/racoon/isakmp_inf.h b/ipsec-tools/racoon/isakmp_inf.h
new file mode 100644 (file)
index 0000000..4f22ece
--- /dev/null
@@ -0,0 +1,55 @@
+/* $Id: isakmp_inf.h,v 1.4 2004/11/16 15:44:46 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_INF_H
+#define _ISAKMP_INF_H
+
+struct saproto;
+extern int isakmp_info_recv __P((struct ph1handle *, vchar_t *));
+extern int isakmp_info_send_d1 __P((struct ph1handle *));
+extern int isakmp_info_send_d2 __P((struct ph2handle *));
+extern int isakmp_info_send_nx __P((struct isakmp *,
+       struct sockaddr *, struct sockaddr *, int, vchar_t *));
+extern int isakmp_info_send_n1 __P((struct ph1handle *, int, vchar_t *));
+extern int isakmp_info_send_n2 __P((struct ph2handle *, int, vchar_t *));
+extern int isakmp_info_send_common __P((struct ph1handle *,
+       vchar_t *, u_int32_t, int));
+
+extern vchar_t * isakmp_add_pl_n __P((vchar_t *, u_int8_t **, int,
+       struct saproto *, vchar_t *));
+
+extern void isakmp_check_notify __P((struct isakmp_gen *, struct ph1handle *));
+
+#ifdef ENABLE_DPD
+extern int isakmp_sched_r_u __P((struct ph1handle *, int));
+#endif
+
+#endif /* _ISAKMP_INF_H */
diff --git a/ipsec-tools/racoon/isakmp_newg.c b/ipsec-tools/racoon/isakmp_newg.c
new file mode 100644 (file)
index 0000000..0db0107
--- /dev/null
@@ -0,0 +1,230 @@
+/*     $KAME: isakmp_newg.c,v 1.10 2002/09/27 05:55:52 itojun Exp $    */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "cfparse_proto.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_newg.h"
+#include "oakley.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "handler.h"
+#include "pfkey.h"
+#include "admin.h"
+#include "str2val.h"
+#include "vendorid.h"
+
+/*
+ * New group mode as responder
+ */
+int
+isakmp_newgroup_r(iph1, msg)
+       struct ph1handle *iph1;
+       vchar_t *msg;
+{
+#if 0
+       struct isakmp *isakmp = (struct isakmp *)msg->v;
+       struct isakmp_pl_hash *hash = NULL;
+       struct isakmp_pl_sa *sa = NULL;
+       int error = -1;
+       vchar_t *buf;
+       struct oakley_sa *osa;
+       int len;
+
+       /* validate the type of next payload */
+       /*
+        * ISAKMP_ETYPE_NEWGRP,
+        * ISAKMP_NPTYPE_HASH, (ISAKMP_NPTYPE_VID), ISAKMP_NPTYPE_SA,
+        * ISAKMP_NPTYPE_NONE
+        */
+    {
+       vchar_t *pbuf = NULL;
+       struct isakmp_parse_t *pa;
+
+       if ((pbuf = isakmp_parse(msg)) == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_HASH:
+                       if (hash) {
+                               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "received multiple payload type %d.\n",
+                                       pa->type);
+                               vfree(pbuf);
+                               goto end;
+                       }
+                       hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_SA:
+                       if (sa) {
+                               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "received multiple payload type %d.\n",
+                                       pa->type);
+                               vfree(pbuf);
+                               goto end;
+                       }
+                       sa = (struct isakmp_pl_sa *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_VID:
+                       (void)check_vendorid(pa->ptr);
+                       break;
+               default:
+                       isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       vfree(pbuf);
+                       goto end;
+               }
+       }
+       vfree(pbuf);
+
+       if (!hash || !sa) {
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "no HASH, or no SA payload.\n");
+               goto end;
+       }
+    }
+
+       /* validate HASH */
+    {
+       char *r_hash;
+       vchar_t *my_hash = NULL;
+       int result;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "validate HASH\n");
+
+       len = sizeof(isakmp->msgid) + ntohs(sa->h.len);
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+       memcpy(buf->v, &isakmp->msgid, sizeof(isakmp->msgid));
+       memcpy(buf->v + sizeof(isakmp->msgid), sa, ntohs(sa->h.len));
+
+       plog(LLV_DEBUG, LOCATION, NULL, "hash source\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       my_hash = isakmp_prf(iph1->skeyid_a, buf, iph1);
+       vfree(buf);
+       if (my_hash == NULL)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "hash result\n");
+       plogdump(LLV_DEBUG, my_hash->v, my_hash->l);
+
+       r_hash = (char *)hash + sizeof(*hash);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "original hash\n"));
+       plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)));
+
+       result = memcmp(my_hash->v, r_hash, my_hash->l);
+       vfree(my_hash);
+
+       if (result) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "HASH mismatch.\n");
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_HASH_INFORMATION, NULL);
+               goto end;
+       }
+    }
+
+       /* check SA payload and get new one for use */
+       buf = ipsecdoi_get_proposal((struct ipsecdoi_sa *)sa,
+                                       OAKLEY_NEWGROUP_MODE);
+       if (buf == NULL) {
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL);
+               goto end;
+       }
+
+       /* save sa parameters */
+       osa = ipsecdoi_get_oakley(buf);
+       if (osa == NULL) {
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL);
+               goto end;
+       }
+       vfree(buf);
+
+       switch (osa->dhgrp) {
+       case OAKLEY_ATTR_GRP_DESC_MODP768:
+       case OAKLEY_ATTR_GRP_DESC_MODP1024:
+       case OAKLEY_ATTR_GRP_DESC_MODP1536:
+               /*XXX*/
+       default:
+               isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL);
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "dh group %d isn't supported.\n", osa->dhgrp);
+               goto end;
+       }
+
+       plog(LLV_INFO, LOCATION, iph1->remote,
+               "got new dh group %s.\n", isakmp_pindex(&iph1->index, 0));
+
+       error = 0;
+
+end:
+       if (error) {
+               if (iph1 != NULL)
+                       (void)isakmp_free_ph1(iph1);
+       }
+       return error;
+#endif
+       return 0;
+}
+
diff --git a/ipsec-tools/racoon/isakmp_newg.h b/ipsec-tools/racoon/isakmp_newg.h
new file mode 100644 (file)
index 0000000..2a52b1e
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id: isakmp_newg.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_NEWG_H
+#define _ISAKMP_NEWG_H
+
+extern int isakmp_newgroup_r __P((struct ph1handle *, vchar_t *));
+
+#endif /* _ISAKMP_NEWG_H */
diff --git a/ipsec-tools/racoon/isakmp_quick.c b/ipsec-tools/racoon/isakmp_quick.c
new file mode 100644 (file)
index 0000000..fc3c259
--- /dev/null
@@ -0,0 +1,2238 @@
+/* $Id: isakmp_quick.c,v 1.13.2.7 2005/07/20 08:02:05 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include "var.h"
+#include "vmbuf.h"
+#include "schedule.h"
+#include "misc.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_inf.h"
+#include "isakmp_quick.h"
+#include "oakley.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "crypto_openssl.h"
+#include "pfkey.h"
+#include "policy.h"
+#include "algorithm.h"
+#include "sockmisc.h"
+#include "proposal.h"
+#include "sainfo.h"
+#include "admin.h"
+#include "strnames.h"
+#include "nattraversal.h"
+
+/* quick mode */
+static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *));
+static int get_sainfo_r __P((struct ph2handle *));
+static int get_proposal_r __P((struct ph2handle *));
+
+/* \f%%%
+ * Quick Mode
+ */
+/*
+ * begin Quick Mode as initiator.  send pfkey getspi message to kernel.
+ */
+int
+quick_i1prep(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg; /* must be null pointer */
+{
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_STATUS2) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       iph2->msgid = isakmp_newmsgid2(iph2->ph1);
+       iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid);
+       if (iph2->ivm == NULL)
+               return 0;
+
+       iph2->status = PHASE2ST_GETSPISENT;
+
+       /* don't anything if local test mode. */
+       if (f_local) {
+               error = 0;
+               goto end;
+       }
+
+       /* send getspi message */
+       if (pk_sendgetspi(iph2) < 0)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
+
+       iph2->sce = sched_new(lcconf->wait_ph2complete,
+               pfkey_timeover_stub, iph2);
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * send to responder
+ *     HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
+ */
+int
+quick_i1send(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg; /* must be null pointer */
+{
+       vchar_t *body = NULL;
+       vchar_t *hash = NULL;
+       vchar_t *natoa_i = NULL;
+       vchar_t *natoa_r = NULL;
+       int             natoa_type = 0;
+       struct isakmp_gen *gen;
+       char *p;
+       int tlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+       int pfsgroup, idci, idcr;
+       int np;
+       struct ipsecdoi_id_b *id, *id_p;
+
+       /* validity check */
+       if (msg != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "msg has to be NULL in this function.\n");
+               goto end;
+       }
+       if (iph2->status != PHASE2ST_GETSPIDONE) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* create SA payload for my proposal */
+       if (ipsecdoi_setph2proposal(iph2) < 0)
+               goto end;
+
+       /* generate NONCE value */
+       iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
+       if (iph2->nonce == NULL)
+               goto end;
+
+       /*
+        * DH value calculation is kicked out into cfparse.y.
+        * because pfs group can not be negotiated, it's only to be checked
+        * acceptable.
+        */
+       /* generate KE value if need */
+       pfsgroup = iph2->proposal->pfs_group;
+       if (pfsgroup) {
+               /* DH group settting if PFS is required. */
+               if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to set DH value.\n");
+                       goto end;
+               }
+               if (oakley_dh_generate(iph2->pfsgrp,
+                               &iph2->dhpub, &iph2->dhpriv) < 0) {
+                       goto end;
+               }
+       }
+
+       /* generate ID value */
+       if (ipsecdoi_setid2(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "IDci:");
+       plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l);
+       plog(LLV_DEBUG, LOCATION, NULL, "IDcr:");
+       plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l);
+
+       /*
+        * we do not attach IDci nor IDcr, under the following condition:
+        * - all proposals are transport mode
+        * - no MIP6 or proxy
+        * - id payload suggests to encrypt all the traffic (no specific
+        *   protocol type)
+        */
+       id = (struct ipsecdoi_id_b *)iph2->id->v;
+       id_p = (struct ipsecdoi_id_b *)iph2->id_p->v;
+       if (id->proto_id == 0
+        && id_p->proto_id == 0
+        && iph2->ph1->rmconf->support_proxy == 0
+        && ipsecdoi_transportmode(iph2->proposal)) {
+               idci = idcr = 0;
+       } else
+               idci = idcr = 1;
+
+       /* create SA;NONCE payload, and KE if need, and IDii, IDir. */
+       tlen = + sizeof(*gen) + iph2->sa->l
+               + sizeof(*gen) + iph2->nonce->l;
+       if (pfsgroup)
+               tlen += (sizeof(*gen) + iph2->dhpub->l);
+       if (idci)
+               tlen += sizeof(*gen) + iph2->id->l;
+       if (idcr)
+               tlen += sizeof(*gen) + iph2->id_p->l;
+
+#ifdef NOT_NOW
+#ifdef ENABLE_NATT     
+       /* 
+        * create natoa payloads if needed but only
+        * if transport mode proposals are present
+        */
+       if (ipsecdoi_tunnelmode(iph2) != 1) {
+               natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r);
+               if (natoa_type == -1)
+                       goto end;
+               else if (natoa_type != 0) {
+                       tlen += sizeof(*gen) + natoa_i->l;
+                       tlen += sizeof(*gen) + natoa_r->l;
+               }
+       }
+#endif
+#endif
+
+       body = vmalloc(tlen);
+       if (body == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       p = body->v;
+
+       /* add SA payload */
+       p = set_isakmp_payload(p, iph2->sa, ISAKMP_NPTYPE_NONCE);
+
+       /* add NONCE payload */
+       if (pfsgroup)
+               np = ISAKMP_NPTYPE_KE;
+       else if (idci || idcr)
+               np = ISAKMP_NPTYPE_ID;
+       else
+#ifdef NOT_NOW
+               np = (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
+#else
+               np = ISAKMP_NPTYPE_NONE;
+#endif
+       p = set_isakmp_payload(p, iph2->nonce, np);
+
+       /* add KE payload if need. */
+#ifdef NOT_NOW
+       np = (idci || idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
+#else
+       np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
+#endif
+       if (pfsgroup)
+               p = set_isakmp_payload(p, iph2->dhpub, np);
+
+       /* IDci */
+#ifdef NOT_NOW
+       np = (idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
+#else
+       np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
+#endif
+       if (idci)
+               p = set_isakmp_payload(p, iph2->id, np);
+
+       /* IDcr */
+       if (idcr)
+#ifdef NOT_NOW
+               p = set_isakmp_payload(p, iph2->id_p, natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
+               
+       /* natoa */
+       if (natoa_type) {
+               p = set_isakmp_payload(p, natoa_i, natoa_type);
+               p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE);
+       }
+#else
+               p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE);
+#endif
+
+       /* generate HASH(1) */
+       hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body);
+       if (hash == NULL)
+               goto end;
+
+       /* send isakmp payload */
+       iph2->sendbuf = quick_ir1mx(iph2, body, hash);
+       if (iph2->sendbuf == NULL)
+               goto end;
+
+       /* send the packet, add to the schedule to resend */
+       iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
+       if (isakmp_ph2resend(iph2) == -1)
+               goto end;
+
+       /* change status of isakmp status entry */
+       iph2->status = PHASE2ST_MSG1SENT;
+
+       error = 0;
+
+end:
+       if (body != NULL)
+               vfree(body);
+       if (hash != NULL)
+               vfree(hash);
+#ifdef NOT_NOW
+       if (natoa_i)
+               vfree(natoa_i);
+       if (natoa_r)
+               vfree(natoa_r);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from responder
+ *     HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
+ */
+int
+quick_i2recv(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *hbuf = NULL;   /* for hash computing. */
+       vchar_t *pbuf = NULL;   /* for payload parsing */
+       struct isakmp_parse_t *pa;
+       struct isakmp *isakmp = (struct isakmp *)msg0->v;
+       struct isakmp_pl_hash *hash = NULL;
+       int f_id;
+       char *p;
+       int tlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* decrypt packet */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "Packet wasn't encrypted.\n");
+               goto end;
+       }
+       msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* create buffer for validating HASH(2) */
+       /*
+        * ordering rule:
+        *      1. the first one must be HASH
+        *      2. the second one must be SA (added in isakmp-oakley-05!)
+        *      3. two IDs must be considered as IDci, then IDcr
+        */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* HASH payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_HASH) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_HASH);
+               goto end;
+       }
+       hash = (struct isakmp_pl_hash *)pa->ptr;
+       pa++;
+
+       /*
+        * this restriction was introduced in isakmp-oakley-05.
+        * we do not check this for backward compatibility.
+        * TODO: command line/config file option to enable/disable this code
+        */
+       /* HASH payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_WARNING, LOCATION, iph2->ph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_HASH);
+       }
+
+       /* allocate buffer for computing HASH(2) */
+       tlen = iph2->nonce->l
+               + ntohl(isakmp->len) - sizeof(*isakmp);
+       hbuf = vmalloc(tlen);
+       if (hbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer.\n");
+               goto end;
+       }
+       p = hbuf->v + iph2->nonce->l;   /* retain the space for Ni_b */
+
+       /*
+        * parse the payloads.
+        * copy non-HASH payloads into hbuf, so that we can validate HASH.
+        */
+       iph2->sa_ret = NULL;
+       f_id = 0;       /* flag to use checking ID */
+       tlen = 0;       /* count payload length except of HASH payload. */
+       for (; pa->type; pa++) {
+
+               /* copy to buffer for HASH */
+               /* Don't modify the payload */
+               memcpy(p, pa->ptr, pa->len);
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_SA:
+                       if (iph2->sa_ret != NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "Ignored, multiple SA "
+                                       "isn't supported.\n");
+                               break;
+                       }
+                       if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_ID:
+                   {
+                       vchar_t *vp;
+
+                       /* check ID value */
+                       if (f_id == 0) {
+                               /* for IDci */
+                               f_id = 1;
+                               vp = iph2->id;
+                       } else {
+                               /* for IDcr */
+                               vp = iph2->id_p;
+                       }
+
+                       /* These ids may not match when natt is used with some devices.
+                        * RFC 2407 says that the protocol and port fields should be ignored
+                        * if they are zero, therefore they need to be checked individually.
+                        */
+                       struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v;
+                       struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr;
+                       
+                       if (id_ptr->type != idp_ptr->b.type
+                               || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id)
+                               || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port)
+                               || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id), 
+                                               vp->l - sizeof(struct ipsecdoi_id_b))) {
+                               //%%% BUG_FIX - to support some servers
+                               if (iph2->ph1->natt_flags & NAT_DETECTED) {
+                                       plog(LLV_WARNING, LOCATION, NULL,
+                                               "mismatched ID was returned - ignored because nat traversal is being used.\n");
+                                       break;
+                               }
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "mismatched ID was returned.\n");
+                               error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+                               goto end;
+                               }
+                       }
+
+                       break;
+
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph2->ph1);
+                       break;
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATOA_DRAFT:
+               case ISAKMP_NPTYPE_NATOA_BADDRAFT:
+               case ISAKMP_NPTYPE_NATOA_RFC:
+                       /* Ignore original source/destination messages */
+                       break;
+#endif
+
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+
+               p += pa->len;
+
+               /* compute true length of payload. */
+               tlen += pa->len;
+       }
+
+       /* payload existency check */
+       if (hash == NULL || iph2->sa_ret == NULL || iph2->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* Fixed buffer for calculating HASH */
+       memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l);
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "HASH allocated:hbuf->l=%zu actual:tlen=%zu\n",
+               hbuf->l, tlen + iph2->nonce->l);
+       /* adjust buffer length for HASH */
+       hbuf->l = iph2->nonce->l + tlen;
+
+       /* validate HASH(2) */
+    {
+       char *r_hash;
+       vchar_t *my_hash = NULL;
+       int result;
+
+       r_hash = (char *)hash + sizeof(*hash);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(2) received:");
+       plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
+
+       my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
+       if (my_hash == NULL)
+               goto end;
+
+       result = memcmp(my_hash->v, r_hash, my_hash->l);
+       vfree(my_hash);
+
+       if (result) {
+               plog(LLV_DEBUG, LOCATION, iph2->ph1->remote,
+                       "HASH(2) mismatch.\n");
+               error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               goto end;
+       }
+    }
+
+       /* validity check SA payload sent from responder */
+       if (ipsecdoi_checkph2proposal(iph2) < 0) {
+               error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+               goto end;
+       }
+
+       /* change status of isakmp status entry */
+       iph2->status = PHASE2ST_STATUS6;
+
+       error = 0;
+
+end:
+       if (hbuf)
+               vfree(hbuf);
+       if (pbuf)
+               vfree(pbuf);
+       if (msg)
+               vfree(msg);
+
+       if (error) {
+               VPTRINIT(iph2->sa_ret);
+               VPTRINIT(iph2->nonce_p);
+               VPTRINIT(iph2->dhpub_p);
+               VPTRINIT(iph2->id);
+               VPTRINIT(iph2->id_p);
+       }
+
+       return error;
+}
+
+/*
+ * send to responder
+ *     HDR*, HASH(3)
+ */
+int
+quick_i2send(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *buf = NULL;
+       vchar_t *hash = NULL;
+       char *p = NULL;
+       int tlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_STATUS6) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* generate HASH(3) */
+    {
+       vchar_t *tmp = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) generate\n");
+
+       tmp = vmalloc(iph2->nonce->l + iph2->nonce_p->l);
+       if (tmp == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer.\n");
+               goto end;
+       }
+       memcpy(tmp->v, iph2->nonce->v, iph2->nonce->l);
+       memcpy(tmp->v + iph2->nonce->l, iph2->nonce_p->v, iph2->nonce_p->l);
+
+       hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
+       vfree(tmp);
+
+       if (hash == NULL)
+               goto end;
+    }
+
+       /* create buffer for isakmp payload */
+       tlen = sizeof(struct isakmp)
+               + sizeof(struct isakmp_gen) + hash->l;
+       buf = vmalloc(tlen);
+       if (buf == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       /* create isakmp header */
+       p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
+       if (p == NULL)
+               goto end;
+
+       /* add HASH(3) payload */
+       p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1);
+#endif
+
+       /* encoding */
+       iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
+       if (iph2->sendbuf == NULL)
+               goto end;
+
+       /* if there is commit bit, need resending */
+       if (ISSET(iph2->flags, ISAKMP_FLAG_C)) {
+               /* send the packet, add to the schedule to resend */
+               iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
+               if (isakmp_ph2resend(iph2) == -1)
+                       goto end;
+       } else {
+               /* send the packet */
+               if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0)
+                       goto end;
+       }
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local,
+                       iph2->sendbuf, msg0) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* compute both of KEYMATs */
+       if (oakley_compute_keymat(iph2, INITIATOR) < 0)
+               goto end;
+
+       iph2->status = PHASE2ST_ADDSA;
+
+       /* don't anything if local test mode. */
+       if (f_local) {
+               error = 0;
+               goto end;
+       }
+
+       /* if there is commit bit don't set up SA now. */
+       if (ISSET(iph2->flags, ISAKMP_FLAG_C)) {
+               iph2->status = PHASE2ST_COMMIT;
+               error = 0;
+               goto end;
+       }
+
+       /* Do UPDATE for initiator */
+       plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n");
+       if (pk_sendupdate(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n");
+
+       /* Do ADD for responder */
+       if (pk_sendadd(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n");
+
+       error = 0;
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       if (msg != NULL)
+               vfree(msg);
+       if (hash != NULL)
+               vfree(hash);
+
+       return error;
+}
+
+/*
+ * receive from responder
+ *     HDR#*, HASH(4), notify
+ */
+int
+quick_i3recv(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *pbuf = NULL;   /* for payload parsing */
+       struct isakmp_parse_t *pa;
+       struct isakmp_pl_hash *hash = NULL;
+       vchar_t *notify = NULL;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_COMMIT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* decrypt packet */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "Packet wasn't encrypted.\n");
+               goto end;
+       }
+       msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_HASH:
+                       hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph2->ph1);
+                       notify = vmalloc(pa->len);
+                       if (notify == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get notify buffer.\n");
+                               goto end;
+                       }
+                       memcpy(notify->v, pa->ptr, notify->l);
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+       if (hash == NULL) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* validate HASH(4) */
+    {
+       char *r_hash;
+       vchar_t *my_hash = NULL;
+       vchar_t *tmp = NULL;
+       int result;
+
+       r_hash = (char *)hash + sizeof(*hash);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) validate:");
+       plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
+
+       my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
+       vfree(tmp);
+       if (my_hash == NULL)
+               goto end;
+
+       result = memcmp(my_hash->v, r_hash, my_hash->l);
+       vfree(my_hash);
+
+       if (result) {
+               plog(LLV_DEBUG, LOCATION, iph2->ph1->remote,
+                       "HASH(4) mismatch.\n");
+               error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               goto end;
+       }
+    }
+
+       iph2->status = PHASE2ST_ADDSA;
+       iph2->flags ^= ISAKMP_FLAG_C;   /* reset bit */
+
+       /* don't anything if local test mode. */
+       if (f_local) {
+               error = 0;
+               goto end;
+       }
+
+       /* Do UPDATE for initiator */
+       plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n");
+       if (pk_sendupdate(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n");
+
+       /* Do ADD for responder */
+       if (pk_sendadd(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n");
+
+       error = 0;
+
+end:
+       if (msg != NULL)
+               vfree(msg);
+       if (pbuf != NULL)
+               vfree(pbuf);
+       if (notify != NULL)
+               vfree(notify);
+
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
+ */
+int
+quick_r1recv(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *hbuf = NULL;   /* for hash computing. */
+       vchar_t *pbuf = NULL;   /* for payload parsing */
+       struct isakmp_parse_t *pa;
+       struct isakmp *isakmp = (struct isakmp *)msg0->v;
+       struct isakmp_pl_hash *hash = NULL;
+       char *p;
+       int tlen;
+       int f_id_order; /* for ID payload detection */
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_START) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* decrypting */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "Packet wasn't encrypted.\n");
+               error = ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               goto end;
+       }
+       /* decrypt packet */
+       msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* create buffer for using to validate HASH(1) */
+       /*
+        * ordering rule:
+        *      1. the first one must be HASH
+        *      2. the second one must be SA (added in isakmp-oakley-05!)
+        *      3. two IDs must be considered as IDci, then IDcr
+        */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+       pa = (struct isakmp_parse_t *)pbuf->v;
+
+       /* HASH payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_HASH) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_HASH);
+               error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX;
+               goto end;
+       }
+       hash = (struct isakmp_pl_hash *)pa->ptr;
+       pa++;
+
+       /*
+        * this restriction was introduced in isakmp-oakley-05.
+        * we do not check this for backward compatibility.
+        * TODO: command line/config file option to enable/disable this code
+        */
+       /* HASH payload is fixed postion */
+       if (pa->type != ISAKMP_NPTYPE_SA) {
+               plog(LLV_WARNING, LOCATION, iph2->ph1->remote,
+                       "received invalid next payload type %d, "
+                       "expecting %d.\n",
+                       pa->type, ISAKMP_NPTYPE_SA);
+               error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX;
+       }
+
+       /* allocate buffer for computing HASH(1) */
+       tlen = ntohl(isakmp->len) - sizeof(*isakmp);
+       hbuf = vmalloc(tlen);
+       if (hbuf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer.\n");
+               goto end;
+       }
+       p = hbuf->v;
+
+       /*
+        * parse the payloads.
+        * copy non-HASH payloads into hbuf, so that we can validate HASH.
+        */
+       iph2->sa = NULL;        /* we don't support multi SAs. */
+       iph2->nonce_p = NULL;
+       iph2->dhpub_p = NULL;
+       iph2->id_p = NULL;
+       iph2->id = NULL;
+       tlen = 0;       /* count payload length except of HASH payload. */
+
+       /*
+        * IDi2 MUST be immediatelly followed by IDr2.  We allowed the
+        * illegal case, but logged.  First ID payload is to be IDi2.
+        * And next ID payload is to be IDr2.
+        */
+       f_id_order = 0;
+
+       for (; pa->type; pa++) {
+
+               /* copy to buffer for HASH */
+               /* Don't modify the payload */
+               memcpy(p, pa->ptr, pa->len);
+
+               if (pa->type != ISAKMP_NPTYPE_ID)
+                       f_id_order = 0;
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_SA:
+                       if (iph2->sa != NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "Multi SAs isn't supported.\n");
+                               goto end;
+                       }
+                       if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_NONCE:
+                       if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_KE:
+                       if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+                               goto end;
+                       break;
+
+               case ISAKMP_NPTYPE_ID:
+                       if (iph2->id_p == NULL) {
+                               /* for IDci */
+                               f_id_order++;
+
+                               if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0)
+                                       goto end;
+
+                       } else if (iph2->id == NULL) {
+                               /* for IDcr */
+                               if (f_id_order == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "IDr2 payload is not "
+                                               "immediatelly followed "
+                                               "by IDi2. We allowed.\n");
+                                       /* XXX we allowed in this case. */
+                               }
+
+                               if (isakmp_p2ph(&iph2->id, pa->ptr) < 0)
+                                       goto end;
+                       } else {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "received too many ID payloads.\n");
+                               plogdump(LLV_ERROR, iph2->id->v, iph2->id->l);
+                               error = ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                               goto end;
+                       }
+                       break;
+
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph2->ph1);
+                       break;
+
+#ifdef ENABLE_NATT
+               case ISAKMP_NPTYPE_NATOA_DRAFT:
+               case ISAKMP_NPTYPE_NATOA_BADDRAFT:
+               case ISAKMP_NPTYPE_NATOA_RFC:
+                       /* Ignore original source/destination messages */
+                       break;
+#endif
+
+               default:
+                       plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                               "ignore the packet, "
+                               "received unexpected payload type %d.\n",
+                               pa->type);
+                       error = ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+                       goto end;
+               }
+
+               p += pa->len;
+
+               /* compute true length of payload. */
+               tlen += pa->len;
+       }
+
+       /* payload existency check */
+       if (hash == NULL || iph2->sa == NULL || iph2->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "expected isakmp payloads missing.\n");
+               error = ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               goto end;
+       }
+
+       if (iph2->id_p) {
+               plog(LLV_DEBUG, LOCATION, NULL, "received IDci2:");
+               plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l);
+       }
+       if (iph2->id) {
+               plog(LLV_DEBUG, LOCATION, NULL, "received IDcr2:");
+               plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l);
+       }
+
+       /* adjust buffer length for HASH */
+       hbuf->l = tlen;
+
+       /* validate HASH(1) */
+    {
+       char *r_hash;
+       vchar_t *my_hash = NULL;
+       int result;
+
+       r_hash = (caddr_t)hash + sizeof(*hash);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(1) validate:");
+       plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
+
+       my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
+       if (my_hash == NULL)
+               goto end;
+
+       result = memcmp(my_hash->v, r_hash, my_hash->l);
+       vfree(my_hash);
+
+       if (result) {
+               plog(LLV_DEBUG, LOCATION, iph2->ph1->remote,
+                       "HASH(1) mismatch.\n");
+               error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               goto end;
+       }
+    }
+
+       /* get sainfo */
+       error = get_sainfo_r(iph2);
+       if (error) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get sainfo.\n");
+               goto end;
+       }
+
+       /* check the existence of ID payload and create responder's proposal */
+       error = get_proposal_r(iph2);
+       switch (error) {
+       case -2:
+               /* generate a policy template from peer's proposal */
+               if (set_proposal_from_proposal(iph2)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to generate a proposal template "
+                               "from client's proposal.\n");
+                       return ISAKMP_INTERNAL_ERROR;
+               }
+               /*FALLTHROUGH*/
+       case 0:
+               /* select single proposal or reject it. */
+               if (ipsecdoi_selectph2proposal(iph2) < 0) {
+                       error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+                       goto end;
+               }
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get proposal for responder.\n");
+               goto end;
+       }
+
+       /* check KE and attribute of PFS */
+       if (iph2->dhpub_p != NULL && iph2->approval->pfs_group == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no PFS is specified, but peer sends KE.\n");
+               error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+               goto end;
+       }
+       if (iph2->dhpub_p == NULL && iph2->approval->pfs_group != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "PFS is specified, but peer doesn't sends KE.\n");
+               error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+               goto end;
+       }
+
+       /*
+        * save the packet from the initiator in order to resend the
+        * responder's first packet against this packet.
+        */
+       iph2->msg1 = vdup(msg0);
+
+       /* change status of isakmp status entry */
+       iph2->status = PHASE2ST_STATUS2;
+
+       error = 0;
+
+end:
+       if (hbuf)
+               vfree(hbuf);
+       if (msg)
+               vfree(msg);
+       if (pbuf)
+               vfree(pbuf);
+
+       if (error) {
+               VPTRINIT(iph2->sa);
+               VPTRINIT(iph2->nonce_p);
+               VPTRINIT(iph2->dhpub_p);
+               VPTRINIT(iph2->id);
+               VPTRINIT(iph2->id_p);
+       }
+
+       return error;
+}
+
+/*
+ * call pfkey_getspi.
+ */
+int
+quick_r1prep(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg;
+{
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_STATUS2) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       iph2->status = PHASE2ST_GETSPISENT;
+
+       /* send getspi message */
+       if (pk_sendgetspi(iph2) < 0)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
+
+       iph2->sce = sched_new(lcconf->wait_ph2complete,
+               pfkey_timeover_stub, iph2);
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * send to initiator
+ *     HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
+ */
+int
+quick_r2send(iph2, msg)
+       struct ph2handle *iph2;
+       vchar_t *msg;
+{
+       vchar_t *body = NULL;
+       vchar_t *hash = NULL;
+       vchar_t *natoa_i = NULL;
+       vchar_t *natoa_r = NULL;
+       int             natoa_type = 0;
+       int             encmode;
+       struct isakmp_gen *gen;
+       char *p;
+       int tlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+       int pfsgroup;
+       u_int8_t *np_p = NULL;
+
+       /* validity check */
+       if (msg != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "msg has to be NULL in this function.\n");
+               goto end;
+       }
+       if (iph2->status != PHASE2ST_GETSPIDONE) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* update responders SPI */
+       if (ipsecdoi_updatespi(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "failed to update spi.\n");
+               goto end;
+       }
+
+       /* generate NONCE value */
+       iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
+       if (iph2->nonce == NULL)
+               goto end;
+
+       /* generate KE value if need */
+       pfsgroup = iph2->approval->pfs_group;
+       if (iph2->dhpub_p != NULL && pfsgroup != 0) {
+               /* DH group settting if PFS is required. */
+               if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to set DH value.\n");
+                       goto end;
+               }
+               /* generate DH public value */
+               if (oakley_dh_generate(iph2->pfsgrp,
+                               &iph2->dhpub, &iph2->dhpriv) < 0) {
+                       goto end;
+               }
+       }
+
+       /* create SA;NONCE payload, and KE and ID if need */
+       tlen = sizeof(*gen) + iph2->sa_ret->l
+               + sizeof(*gen) + iph2->nonce->l;
+       if (iph2->dhpub_p != NULL && pfsgroup != 0)
+               tlen += (sizeof(*gen) + iph2->dhpub->l);
+       if (iph2->id_p != NULL)
+               tlen += (sizeof(*gen) + iph2->id_p->l
+                       + sizeof(*gen) + iph2->id->l);
+
+#ifdef NOT_NOW
+#ifdef ENABLE_NATT
+       /* create natoa payloads if needed */
+       encmode = iph2->approval->head->encmode;
+       if (encmode == IPSECDOI_ATTR_ENC_MODE_TRNS ||
+               encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC ||
+               encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT) {
+
+               natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r);
+               if (natoa_type == -1)
+                       goto end;
+               else if (natoa_type != 0) {
+                       tlen += sizeof(*gen) + natoa_i->l;
+                       tlen += sizeof(*gen) + natoa_r->l;
+               }
+       }
+#endif
+#endif
+
+
+       body = vmalloc(tlen);
+       if (body == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+       p = body->v;
+
+       /* make SA payload */ 
+       p = set_isakmp_payload(body->v, iph2->sa_ret, ISAKMP_NPTYPE_NONCE);
+
+       /* add NONCE payload */
+       np_p = &((struct isakmp_gen *)p)->np;   /* XXX */
+       p = set_isakmp_payload(p, iph2->nonce,
+               (iph2->dhpub_p != NULL && pfsgroup != 0)
+                               ? ISAKMP_NPTYPE_KE
+                               : (iph2->id_p != NULL
+                                       ? ISAKMP_NPTYPE_ID
+#ifdef NOT_NOW
+                                       : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)));
+#else
+                                       : ISAKMP_NPTYPE_ID));
+#endif
+
+       /* add KE payload if need. */
+       if (iph2->dhpub_p != NULL && pfsgroup != 0) {
+               np_p = &((struct isakmp_gen *)p)->np;   /* XXX */
+               p = set_isakmp_payload(p, iph2->dhpub,
+                       (iph2->id_p == NULL)
+#ifdef NOT_NOW
+                               ? (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)
+#else
+                               ? ISAKMP_NPTYPE_NONE
+#endif
+                               : ISAKMP_NPTYPE_ID);
+       }
+
+       /* add ID payloads received. */
+       if (iph2->id_p != NULL) {
+               /* IDci */
+               p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID);
+               /* IDcr */
+               np_p = &((struct isakmp_gen *)p)->np;   /* XXX */
+#ifdef NOT_NOW
+               p = set_isakmp_payload(p, iph2->id, (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE));
+#else
+               p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE);
+#endif
+       }
+
+       /* add a RESPONDER-LIFETIME notify payload if needed */
+    {
+       vchar_t *data = NULL;
+       struct saprop *pp = iph2->approval;
+       struct saproto *pr;
+
+       if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_SEC) {
+               u_int32_t v = htonl((u_int32_t)pp->lifetime);
+               data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE,
+                                       IPSECDOI_ATTR_SA_LD_TYPE_SEC);
+               if (!data)
+                       goto end;
+               data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
+                                       (caddr_t)&v, sizeof(v));
+               if (!data)
+                       goto end;
+       }
+       if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_KB) {
+               u_int32_t v = htonl((u_int32_t)pp->lifebyte);
+               data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE,
+                                       IPSECDOI_ATTR_SA_LD_TYPE_KB);
+               if (!data)
+                       goto end;
+               data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
+                                       (caddr_t)&v, sizeof(v));
+               if (!data)
+                       goto end;
+       }
+
+       /*
+        * XXX Is there only single RESPONDER-LIFETIME payload in a IKE message
+        * in the case of SA bundle ?
+        */
+       if (data) {
+               for (pr = pp->head; pr; pr = pr->next) {
+                       body = isakmp_add_pl_n(body, &np_p,
+                                       ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data);
+                       if (!body) {
+                               vfree(data);
+                               return error;   /* XXX */
+                       }
+               }
+               vfree(data);
+       }
+    }
+
+#ifdef NOT_NOW
+       /* natoa */
+       if (natoa_type) {
+               p = set_isakmp_payload(p, natoa_i, natoa_type);
+               p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE);
+       }
+#endif
+
+       /* generate HASH(2) */
+    {
+       vchar_t *tmp;
+
+       tmp = vmalloc(iph2->nonce_p->l + body->l);
+       if (tmp == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer.\n");
+               goto end;
+       }
+       memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l);
+       memcpy(tmp->v + iph2->nonce_p->l, body->v, body->l);
+
+       hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp);
+       vfree(tmp);
+
+       if (hash == NULL)
+               goto end;
+    }
+
+       /* send isakmp payload */
+       iph2->sendbuf = quick_ir1mx(iph2, body, hash);
+       if (iph2->sendbuf == NULL)
+               goto end;
+
+       /* send the packet, add to the schedule to resend */
+       iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
+       if (isakmp_ph2resend(iph2) == -1)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       /* change status of isakmp status entry */
+       iph2->status = PHASE2ST_MSG1SENT;
+
+       error = 0;
+
+end:
+       if (body != NULL)
+               vfree(body);
+       if (hash != NULL)
+               vfree(hash);
+#ifdef NOT_NOW
+       if (natoa_i)
+               vfree(natoa_i);
+       if (natoa_r)
+               vfree(natoa_r);
+#endif
+
+       return error;
+}
+
+/*
+ * receive from initiator
+ *     HDR*, HASH(3)
+ */
+int
+quick_r3recv(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       vchar_t *pbuf = NULL;   /* for payload parsing */
+       struct isakmp_parse_t *pa;
+       struct isakmp_pl_hash *hash = NULL;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_MSG1SENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* decrypt packet */
+       if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "Packet wasn't encrypted.\n");
+               goto end;
+       }
+       msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
+       if (msg == NULL)
+               goto end;
+
+       /* validate the type of next payload */
+       pbuf = isakmp_parse(msg);
+       if (pbuf == NULL)
+               goto end;
+
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++) {
+
+               switch (pa->type) {
+               case ISAKMP_NPTYPE_HASH:
+                       hash = (struct isakmp_pl_hash *)pa->ptr;
+                       break;
+               case ISAKMP_NPTYPE_N:
+                       isakmp_check_notify(pa->ptr, iph2->ph1);
+                       break;
+               default:
+                       /* don't send information, see ident_r1recv() */
+                       plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                               "ignore the packet, "
+                               "received unexpecting payload type %d.\n",
+                               pa->type);
+                       goto end;
+               }
+       }
+
+       /* payload existency check */
+       if (hash == NULL) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "few isakmp message received.\n");
+               goto end;
+       }
+
+       /* validate HASH(3) */
+       /* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */
+    {
+       char *r_hash;
+       vchar_t *my_hash = NULL;
+       vchar_t *tmp = NULL;
+       int result;
+
+       r_hash = (char *)hash + sizeof(*hash);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) validate:");
+       plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
+
+       tmp = vmalloc(iph2->nonce_p->l + iph2->nonce->l);
+       if (tmp == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer.\n");
+               goto end;
+       }
+       memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l);
+       memcpy(tmp->v + iph2->nonce_p->l, iph2->nonce->v, iph2->nonce->l);
+
+       my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
+       vfree(tmp);
+       if (my_hash == NULL)
+               goto end;
+
+       result = memcmp(my_hash->v, r_hash, my_hash->l);
+       vfree(my_hash);
+
+       if (result) {
+               plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+                       "HASH(3) mismatch.\n");
+               error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               goto end;
+       }
+    }
+
+       /* if there is commit bit, don't set up SA now. */
+       if (ISSET(iph2->flags, ISAKMP_FLAG_C)) {
+               iph2->status = PHASE2ST_COMMIT;
+       } else
+               iph2->status = PHASE2ST_STATUS6;
+
+       error = 0;
+
+end:
+       if (pbuf != NULL)
+               vfree(pbuf);
+       if (msg != NULL)
+               vfree(msg);
+
+       return error;
+}
+
+/*
+ * send to initiator
+ *     HDR#*, HASH(4), notify
+ */
+int
+quick_r3send(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *buf = NULL;
+       vchar_t *myhash = NULL;
+       struct isakmp_pl_n *n;
+       vchar_t *notify = NULL;
+       char *p;
+       int tlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_COMMIT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* generate HASH(4) */
+       /* XXX What can I do in the case of multiple different SA */
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) generate\n");
+
+       /* XXX What should I do if there are multiple SAs ? */
+       tlen = sizeof(struct isakmp_pl_n) + iph2->approval->head->spisize;
+       notify = vmalloc(tlen);
+       if (notify == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get notify buffer.\n");
+               goto end;
+       }
+       n = (struct isakmp_pl_n *)notify->v;
+       n->h.np = ISAKMP_NPTYPE_NONE;
+       n->h.len = htons(tlen);
+       n->doi = htonl(IPSEC_DOI);
+       n->proto_id = iph2->approval->head->proto_id;
+       n->spi_size = sizeof(iph2->approval->head->spisize);
+       n->type = htons(ISAKMP_NTYPE_CONNECTED);
+       memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize);
+
+       myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
+       if (myhash == NULL)
+               goto end;
+
+       /* create buffer for isakmp payload */
+       tlen = sizeof(struct isakmp)
+               + sizeof(struct isakmp_gen) + myhash->l
+               + notify->l;
+       buf = vmalloc(tlen);
+       if (buf == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       /* create isakmp header */
+       p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
+       if (p == NULL)
+               goto end;
+
+       /* add HASH(4) payload */
+       p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N);
+
+       /* add notify payload */
+       memcpy(p, notify->v, notify->l);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1);
+#endif
+
+       /* encoding */
+       iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
+       if (iph2->sendbuf == NULL)
+               goto end;
+
+       /* send the packet */
+       if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0)
+               goto end;
+
+       /* the sending message is added to the received-list. */
+       if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0) == -1) {
+               plog(LLV_ERROR , LOCATION, NULL,
+                       "failed to add a response packet to the tree.\n");
+               goto end;
+       }
+
+       iph2->status = PHASE2ST_COMMIT;
+
+       error = 0;
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       if (myhash != NULL)
+               vfree(myhash);
+       if (notify != NULL)
+               vfree(notify);
+
+       return error;
+}
+
+/*
+ * set SA to kernel.
+ */
+int
+quick_r3prep(iph2, msg0)
+       struct ph2handle *iph2;
+       vchar_t *msg0;
+{
+       vchar_t *msg = NULL;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* validity check */
+       if (iph2->status != PHASE2ST_STATUS6) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatched %d.\n", iph2->status);
+               goto end;
+       }
+
+       /* compute both of KEYMATs */
+       if (oakley_compute_keymat(iph2, RESPONDER) < 0)
+               goto end;
+
+       iph2->status = PHASE2ST_ADDSA;
+       iph2->flags ^= ISAKMP_FLAG_C;   /* reset bit */
+
+       /* don't anything if local test mode. */
+       if (f_local) {
+               error = 0;
+               goto end;
+       }
+
+       /* Do UPDATE as responder */
+       plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n");
+       if (pk_sendupdate(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n");
+
+       /* Do ADD for responder */
+       if (pk_sendadd(iph2) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n");
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n");
+
+       /*
+        * set policies into SPD if the policy is generated
+        * from peer's policy.
+        */
+       if (iph2->spidx_gen) {
+
+               struct policyindex *spidx;
+               struct sockaddr_storage addr;
+               u_int8_t pref;
+               struct sockaddr *src = iph2->src;
+               struct sockaddr *dst = iph2->dst;
+
+               /* make inbound policy */
+               iph2->src = dst;
+               iph2->dst = src;
+               if (pk_sendspdupdate2(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey spdupdate2(inbound) failed.\n");
+                       goto end;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey spdupdate2(inbound) sent.\n");
+
+               spidx = (struct policyindex *)iph2->spidx_gen;
+#ifdef HAVE_POLICY_FWD
+               /* make forward policy if required */
+               if (tunnel_mode_prop(iph2->approval)) {
+                       spidx->dir = IPSEC_DIR_FWD;
+                       if (pk_sendspdupdate2(iph2) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "pfkey spdupdate2(forward) failed.\n");
+                               goto end;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "pfkey spdupdate2(forward) sent.\n");
+               }
+#endif
+
+               /* make outbound policy */
+               iph2->src = src;
+               iph2->dst = dst;
+               spidx->dir = IPSEC_DIR_OUTBOUND;
+               addr = spidx->src;
+               spidx->src = spidx->dst;
+               spidx->dst = addr;
+               pref = spidx->prefs;
+               spidx->prefs = spidx->prefd;
+               spidx->prefd = pref;
+
+               if (pk_sendspdupdate2(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey spdupdate2(outbound) failed.\n");
+                       goto end;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey spdupdate2(outbound) sent.\n");
+
+               /* spidx_gen is unnecessary any more */
+               delsp_bothdir((struct policyindex *)iph2->spidx_gen);
+               racoon_free(iph2->spidx_gen);
+               iph2->spidx_gen = NULL;
+               iph2->generated_spidx=1;
+       }
+
+       error = 0;
+
+end:
+       if (msg != NULL)
+               vfree(msg);
+
+       return error;
+}
+
+/*
+ * create HASH, body (SA, NONCE) payload with isakmp header.
+ */
+static vchar_t *
+quick_ir1mx(iph2, body, hash)
+       struct ph2handle *iph2;
+       vchar_t *body, *hash;
+{
+       struct isakmp *isakmp;
+       vchar_t *buf = NULL, *new = NULL;
+       char *p;
+       int tlen;
+       struct isakmp_gen *gen;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* create buffer for isakmp payload */
+       tlen = sizeof(*isakmp)
+               + sizeof(*gen) + hash->l
+               + body->l;
+       buf = vmalloc(tlen);
+       if (buf == NULL) { 
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send.\n");
+               goto end;
+       }
+
+       /* re-set encryption flag, for serurity. */
+       iph2->flags |= ISAKMP_FLAG_E;
+
+       /* set isakmp header */
+       p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
+       if (p == NULL)
+               goto end;
+
+       /* add HASH payload */
+       /* XXX is next type always SA ? */
+       p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_SA);
+
+       /* add body payload */
+       memcpy(p, body->v, body->l);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1);
+#endif
+
+       /* encoding */
+       new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
+       if (new == NULL)
+               goto end;
+
+       vfree(buf);
+
+       buf = new;
+
+       error = 0;
+
+end:
+       if (error && buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+
+       return buf;
+}
+
+/*
+ * get remote's sainfo.
+ * NOTE: this function is for responder.
+ */
+static int
+get_sainfo_r(iph2)
+       struct ph2handle *iph2;
+{
+       vchar_t *idsrc = NULL, *iddst = NULL;
+       int prefixlen;
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       if (iph2->id_p == NULL) {
+               switch (iph2->src->sa_family) {
+               case AF_INET:
+                       prefixlen = sizeof(struct in_addr) << 3;
+                       break;
+               case AF_INET6:
+                       prefixlen = sizeof(struct in6_addr) << 3;
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid family: %d\n", iph2->src->sa_family);
+                       goto end;
+               }
+               idsrc = ipsecdoi_sockaddr2id(iph2->src, prefixlen,
+                                       IPSEC_ULPROTO_ANY);
+       } else {
+               idsrc = vdup(iph2->id);
+       }
+       if (idsrc == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to set ID for source.\n");
+               goto end;
+       }
+
+       if (iph2->id == NULL) {
+               switch (iph2->dst->sa_family) {
+               case AF_INET:
+                       prefixlen = sizeof(struct in_addr) << 3;
+                       break;
+               case AF_INET6:
+                       prefixlen = sizeof(struct in6_addr) << 3;
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid family: %d\n", iph2->dst->sa_family);
+                       goto end;
+               }
+               iddst = ipsecdoi_sockaddr2id(iph2->dst, prefixlen,
+                                       IPSEC_ULPROTO_ANY);
+       } else {
+               iddst = vdup(iph2->id_p);
+       }
+       if (iddst == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to set ID for destination.\n");
+               goto end;
+       }
+
+       iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p);
+       if (iph2->sainfo == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get sainfo.\n");
+               goto end;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "get sa info: %s\n", sainfo2str(iph2->sainfo));
+
+       error = 0;
+end:
+       if (idsrc)
+               vfree(idsrc);
+       if (iddst)
+               vfree(iddst);
+
+       return error;
+}
+
+/*
+ * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types
+ * are IP address and same address family.
+ * Then get remote's policy from SPD copied from kernel.
+ * If the type of ID payload is address or subnet type, then the index is
+ * made from the payload.  If there is no ID payload, or the type of ID
+ * payload is NOT address type, then the index is made from the address
+ * pair of phase 1.
+ * NOTE: This function is only for responder.
+ */
+static int
+get_proposal_r(iph2)
+       struct ph2handle *iph2;
+{
+       struct policyindex spidx;
+       struct secpolicy *sp_in, *sp_out;
+       int idi2type = 0;       /* switch whether copy IDs into id[src,dst]. */
+       int error = ISAKMP_INTERNAL_ERROR;
+
+       /* check the existence of ID payload */
+       if ((iph2->id_p != NULL && iph2->id == NULL)
+        || (iph2->id_p == NULL && iph2->id != NULL)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Both IDs wasn't found in payload.\n");
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+
+       /* make sure if id[src,dst] is null. */
+       if (iph2->src_id || iph2->dst_id) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Why do ID[src,dst] exist already.\n");
+               return ISAKMP_INTERNAL_ERROR;
+       }
+
+       memset(&spidx, 0, sizeof(spidx));
+
+#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
+
+       /* make a spidx; a key to search SPD */
+       spidx.dir = IPSEC_DIR_INBOUND;
+       spidx.ul_proto = 0;
+
+       /*
+        * make destination address in spidx from either ID payload
+        * or phase 1 address into a address in spidx.
+        */
+       if (iph2->id != NULL
+        && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
+         || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR
+         || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET
+         || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+               /* get a destination address of a policy */
+               error = ipsecdoi_id2sockaddr(iph2->id,
+                               (struct sockaddr *)&spidx.dst,
+                               &spidx.prefd, &spidx.ul_proto);
+               if (error)
+                       return error;
+
+#ifdef INET6
+               /*
+                * get scopeid from the SA address.
+                * note that the phase 1 source address is used as
+                * a destination address to search for a inbound policy entry
+                * because rcoon is responder.
+                */
+               if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) {
+                       error = setscopeid((struct sockaddr *)&spidx.dst,
+                                           iph2->src);
+                       if (error)
+                               return error;
+               }
+#endif
+
+               if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
+                || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR)
+                       idi2type = _XIDT(iph2->id);
+
+       } else {
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "get a destination address of SP index "
+                       "from phase1 address "
+                       "due to no ID payloads found "
+                       "OR because ID type is not address.\n");
+
+               /*
+                * copy the SOURCE address of IKE into the DESTINATION address
+                * of the key to search the SPD because the direction of policy
+                * is inbound.
+                */
+               memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src));
+               switch (spidx.dst.ss_family) {
+               case AF_INET:
+                       spidx.prefd = sizeof(struct in_addr) << 3;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       spidx.prefd = sizeof(struct in6_addr) << 3;
+                       break;
+#endif
+               default:
+                       spidx.prefd = 0;
+                       break;
+               }
+       }
+
+       /* make source address in spidx */
+       if (iph2->id_p != NULL
+        && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR
+         || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR
+         || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET
+         || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+               /* get a source address of inbound SA */
+               error = ipsecdoi_id2sockaddr(iph2->id_p,
+                               (struct sockaddr *)&spidx.src,
+                               &spidx.prefs, &spidx.ul_proto);
+               if (error)
+                       return error;
+
+#ifdef INET6
+               /*
+                * get scopeid from the SA address.
+                * for more detail, see above of this function.
+                */
+               if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) {
+                       error = setscopeid((struct sockaddr *)&spidx.src,
+                                           iph2->dst);
+                       if (error)
+                               return error;
+               }
+#endif
+
+               /* make id[src,dst] if both ID types are IP address and same */
+               if (_XIDT(iph2->id_p) == idi2type
+                && spidx.dst.ss_family == spidx.src.ss_family) {
+                       iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst);
+                       iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src);
+               }
+
+       } else {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "get a source address of SP index "
+                       "from phase1 address "
+                       "due to no ID payloads found "
+                       "OR because ID type is not address.\n");
+
+               /* see above comment. */
+               memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
+               switch (spidx.src.ss_family) {
+               case AF_INET:
+                       spidx.prefs = sizeof(struct in_addr) << 3;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       spidx.prefs = sizeof(struct in6_addr) << 3;
+                       break;
+#endif
+               default:
+                       spidx.prefs = 0;
+                       break;
+               }
+       }
+
+#undef _XIDT
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "get a src address from ID payload "
+               "%s prefixlen=%u ul_proto=%u\n",
+               saddr2str((struct sockaddr *)&spidx.src),
+               spidx.prefs, spidx.ul_proto);
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "get dst address from ID payload "
+               "%s prefixlen=%u ul_proto=%u\n",
+               saddr2str((struct sockaddr *)&spidx.dst),
+               spidx.prefd, spidx.ul_proto);
+
+       /*
+        * convert the ul_proto if it is 0
+        * because 0 in ID payload means a wild card.
+        */
+       if (spidx.ul_proto == 0)
+               spidx.ul_proto = IPSEC_ULPROTO_ANY;
+
+       /* get inbound policy */
+       sp_in = getsp_r(&spidx);
+       if (sp_in == NULL || sp_in->policy == IPSEC_POLICY_GENERATE) {
+               if (iph2->ph1->rmconf->gen_policy) {
+                       plog(LLV_INFO, LOCATION, NULL,
+                               "no policy found, "
+                               "try to generate the policy : %s\n",
+                               spidx2str(&spidx));
+                       iph2->spidx_gen = racoon_malloc(sizeof(spidx));
+                       if (!iph2->spidx_gen) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "buffer allocation failed.\n");
+                               return ISAKMP_INTERNAL_ERROR;
+                       }
+                       memcpy(iph2->spidx_gen, &spidx, sizeof(spidx));
+                       return -2;      /* special value */
+               }
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no policy found: %s\n", spidx2str(&spidx));
+               return ISAKMP_INTERNAL_ERROR;
+       }
+       /* Refresh existing generated policies
+        */
+       if (iph2->ph1->rmconf->gen_policy) {
+               plog(LLV_INFO, LOCATION, NULL,
+                        "Update the generated policy : %s\n",
+                        spidx2str(&spidx));
+               iph2->spidx_gen = racoon_malloc(sizeof(spidx));
+               if (!iph2->spidx_gen) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                "buffer allocation failed.\n");
+                       return ISAKMP_INTERNAL_ERROR;
+               }
+               memcpy(iph2->spidx_gen, &spidx, sizeof(spidx));
+       }
+
+       /* get outbound policy */
+    {
+       struct sockaddr_storage addr;
+       u_int8_t pref;
+
+       spidx.dir = IPSEC_DIR_OUTBOUND;
+       addr = spidx.src;
+       spidx.src = spidx.dst;
+       spidx.dst = addr;
+       pref = spidx.prefs;
+       spidx.prefs = spidx.prefd;
+       spidx.prefd = pref;
+
+       sp_out = getsp_r(&spidx);
+       if (!sp_out) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "no outbound policy found: %s\n",
+                       spidx2str(&spidx));
+       }
+    }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "suitable SP found:%s\n", spidx2str(&spidx));
+
+       /*
+        * In the responder side, the inbound policy should be using IPsec.
+        * outbound policy is not checked currently.
+        */
+       if (sp_in->policy != IPSEC_POLICY_IPSEC) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "policy found, but no IPsec required: %s\n",
+                       spidx2str(&spidx));
+               return ISAKMP_INTERNAL_ERROR;
+       }
+
+       /* set new proposal derived from a policy into the iph2->proposal. */
+       if (set_proposal_from_policy(iph2, sp_in, sp_out) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to create saprop.\n");
+               return ISAKMP_INTERNAL_ERROR;
+       }
+
+       return 0;
+}
diff --git a/ipsec-tools/racoon/isakmp_quick.h b/ipsec-tools/racoon/isakmp_quick.h
new file mode 100644 (file)
index 0000000..4768b53
--- /dev/null
@@ -0,0 +1,48 @@
+/* $Id: isakmp_quick.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_QUICK_H
+#define _ISAKMP_QUICK_H
+
+extern int quick_i1prep __P((struct ph2handle *, vchar_t *));
+extern int quick_i1send __P((struct ph2handle *, vchar_t *));
+extern int quick_i2recv __P((struct ph2handle *, vchar_t *));
+extern int quick_i2send __P((struct ph2handle *, vchar_t *));
+extern int quick_i3recv __P((struct ph2handle *, vchar_t *));
+
+extern int quick_r1recv __P((struct ph2handle *, vchar_t *));
+extern int quick_r1prep __P((struct ph2handle *, vchar_t *));
+extern int quick_r2send __P((struct ph2handle *, vchar_t *));
+extern int quick_r3recv __P((struct ph2handle *, vchar_t *));
+extern int quick_r3send __P((struct ph2handle *, vchar_t *));
+extern int quick_r3prep __P((struct ph2handle *, vchar_t *));
+
+#endif /* _ISAKMP_QUICK_H */
diff --git a/ipsec-tools/racoon/isakmp_unity.c b/ipsec-tools/racoon/isakmp_unity.c
new file mode 100644 (file)
index 0000000..21a1962
--- /dev/null
@@ -0,0 +1,172 @@
+/* $Id: isakmp_unity.c,v 1.5.4.1 2005/05/10 09:45:46 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "handler.h"
+#include "isakmp_xauth.h"
+#include "isakmp_unity.h"
+#include "isakmp_cfg.h"
+#include "strnames.h"
+
+vchar_t *
+isakmp_unity_req(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       int type;
+       vchar_t *reply_attr = NULL;
+
+       if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_UNITY) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Unity mode config request but the peer "
+                   "did not declare itself as  unity compliant\n");
+               return NULL;
+       }
+
+       type = ntohs(attr->type);
+
+       /* Handle short attributes */
+       if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
+               type &= ~ISAKMP_GEN_MASK;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                    "Short attribute %d = %d\n", 
+                    type, ntohs(attr->lorv));
+
+               switch (type) {
+               default:
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                            "Ignored short attribute %d\n", type);
+                       break;
+               }
+
+               return reply_attr;
+       }
+
+       switch(type) {
+       case UNITY_BANNER: {
+#define MAXMOTD 65536
+               char buf[MAXMOTD + 1];
+               int fd;
+               char *filename = &isakmp_cfg_config.motd[0];
+               size_t len;
+
+               if ((fd = open(filename, O_RDONLY, 0)) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot open \"%s\"\n", filename);
+                       return NULL;
+               }
+
+               if ((len = read(fd, buf, MAXMOTD)) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot read \"%s\"\n", filename);
+                       close(fd);
+                       return NULL;
+               }
+               close(fd);
+
+               buf[len] = '\0';
+               reply_attr = isakmp_cfg_string(iph1, attr, buf);
+
+               break;
+       }
+
+       case UNITY_PFS:
+               reply_attr = isakmp_cfg_short(iph1, attr, 
+                   isakmp_cfg_config.pfs_group);
+               break;
+
+       case UNITY_SAVE_PASSWD:
+               reply_attr = isakmp_cfg_short(iph1, attr, 
+                   isakmp_cfg_config.save_passwd);
+               break;
+
+       case UNITY_DDNS_HOSTNAME:
+               reply_attr = isakmp_cfg_copy(iph1, attr);
+               break;
+
+       case UNITY_DEF_DOMAIN:
+       case UNITY_FW_TYPE:
+       case UNITY_SPLITDNS_NAME:
+       case UNITY_SPLIT_INCLUDE:
+       case UNITY_NATT_PORT:
+       case UNITY_BACKUP_SERVERS:
+       default:
+               plog(LLV_DEBUG, LOCATION, NULL,
+                    "Ignored attribute %d\n", type);
+               return NULL;
+               break;
+       }
+
+       return reply_attr;
+}
+
+
diff --git a/ipsec-tools/racoon/isakmp_unity.h b/ipsec-tools/racoon/isakmp_unity.h
new file mode 100644 (file)
index 0000000..4f09af1
--- /dev/null
@@ -0,0 +1,45 @@
+/*     $KAME$ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus 
+ * 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.
+ */
+
+/* ISAKMP mode config attributes specific to the Unity vendor Id */
+#define UNITY_BANNER           28672
+#define UNITY_SAVE_PASSWD      28673
+#define UNITY_DEF_DOMAIN       28674
+#define UNITY_SPLITDNS_NAME    28675
+#define UNITY_SPLIT_INCLUDE    28676
+#define UNITY_NATT_PORT                28677
+#define UNITY_LOCAL_LAN                28678
+#define UNITY_PFS              28679
+#define UNITY_FW_TYPE          28680
+#define UNITY_BACKUP_SERVERS   28681
+#define UNITY_DDNS_HOSTNAME    28682
+
+vchar_t *isakmp_unity_req(struct ph1handle *, struct isakmp_data *);
diff --git a/ipsec-tools/racoon/isakmp_var.h b/ipsec-tools/racoon/isakmp_var.h
new file mode 100644 (file)
index 0000000..ef32d5b
--- /dev/null
@@ -0,0 +1,136 @@
+/* $Id: isakmp_var.h,v 1.9.2.1 2005/05/07 17:26:06 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ISAKMP_VAR_H
+#define _ISAKMP_VAR_H
+
+#include "vmbuf.h"
+
+#define PORT_ISAKMP 500
+#define PORT_ISAKMP_NATT 4500
+
+#define DEFAULT_NONCE_SIZE     16
+
+typedef u_char cookie_t[8];
+typedef u_char msgid_t[4];
+
+typedef struct { /* i_cookie + r_cookie */
+       cookie_t i_ck;
+       cookie_t r_ck;
+} isakmp_index;
+
+struct isakmp_gen;
+struct sched;
+
+struct sockaddr;
+struct ph1handle;
+struct ph2handle;
+struct remoteconf;
+struct isakmp_gen;
+struct ipsecdoi_pl_id; /* XXX */
+struct isakmp_pl_ke;   /* XXX */
+struct isakmp_pl_nonce;        /* XXX */
+
+extern int isakmp_handler __P((int));
+extern int isakmp_ph1begin_i __P((struct remoteconf *, struct sockaddr *,
+       struct sockaddr *));
+
+extern vchar_t *isakmp_parsewoh __P((int, struct isakmp_gen *, int));
+extern vchar_t *isakmp_parse __P((vchar_t *));
+
+extern int isakmp_init __P((void));
+extern void isakmp_cleanup __P((void));
+
+extern const char *isakmp_pindex __P((const isakmp_index *, const u_int32_t));
+extern int isakmp_open __P((void));
+extern void isakmp_close __P((void));
+#ifdef __APPLE__
+extern void isakmp_close_sockets __P((void));
+extern void isakmp_close_unused __P((void));
+#endif
+extern int isakmp_send __P((struct ph1handle *, vchar_t *));
+
+extern void isakmp_ph1resend_stub __P((void *));
+extern int isakmp_ph1resend __P((struct ph1handle *));
+extern void isakmp_ph2resend_stub __P((void *));
+extern int isakmp_ph2resend __P((struct ph2handle *));
+extern void isakmp_ph1expire_stub __P((void *));
+extern void isakmp_ph1expire __P((struct ph1handle *));
+extern void isakmp_ph1delete_stub __P((void *));
+extern void isakmp_ph1delete __P((struct ph1handle *));
+extern void isakmp_ph2expire_stub __P((void *));
+extern void isakmp_ph2expire __P((struct ph2handle *));
+extern void isakmp_ph2delete_stub __P((void *));
+extern void isakmp_ph2delete __P((struct ph2handle *));
+
+extern int isakmp_post_acquire __P((struct ph2handle *));
+extern int isakmp_post_getspi __P((struct ph2handle *));
+extern void isakmp_chkph1there_stub __P((void *));
+extern void isakmp_chkph1there __P((struct ph2handle *));
+
+extern caddr_t isakmp_set_attr_v __P((caddr_t, int, caddr_t, int));
+extern caddr_t isakmp_set_attr_l __P((caddr_t, int, u_int32_t));
+extern vchar_t *isakmp_add_attr_v __P((vchar_t *, int, caddr_t, int));
+extern vchar_t *isakmp_add_attr_l __P((vchar_t *, int, u_int32_t));
+
+extern int isakmp_newcookie __P((caddr_t, struct sockaddr *, struct sockaddr *));
+
+extern int isakmp_p2ph __P((vchar_t **, struct isakmp_gen *));
+
+extern u_int32_t isakmp_newmsgid2 __P((struct ph1handle *));
+extern caddr_t set_isakmp_header1 __P((vchar_t *, struct ph1handle *, int));
+extern caddr_t set_isakmp_header2 __P((vchar_t *, struct ph2handle *, int));
+extern caddr_t set_isakmp_payload __P((caddr_t, vchar_t *, int));
+
+extern struct payload_list *isakmp_plist_append __P((struct payload_list *plist, 
+       vchar_t *payload, int payload_type));
+extern vchar_t *isakmp_plist_set_all __P((struct payload_list **plist,
+       struct ph1handle *iph1));
+
+#ifdef HAVE_PRINT_ISAKMP_C
+extern void isakmp_printpacket __P((vchar_t *, struct sockaddr *,
+       struct sockaddr *, int));
+#endif
+
+extern int copy_ph1addresses __P(( struct ph1handle *,
+       struct remoteconf *, struct sockaddr *, struct sockaddr *));
+extern void log_ph1established __P((const struct ph1handle *));
+
+extern void script_hook __P((struct ph1handle *, int)); 
+extern int script_env_append __P((char ***, int *, char *, char *));
+extern int script_exec __P((int, int, char * const *));
+
+void purge_remote __P((struct ph1handle *));
+void delete_spd __P((struct ph2handle *));
+#ifdef INET6
+u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *));
+#endif 
+#endif /* _ISAKMP_VAR_H */
diff --git a/ipsec-tools/racoon/isakmp_xauth.c b/ipsec-tools/racoon/isakmp_xauth.c
new file mode 100644 (file)
index 0000000..1bf87c1
--- /dev/null
@@ -0,0 +1,995 @@
+/* $Id: isakmp_xauth.c,v 1.17.2.5 2005/05/20 07:31:09 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004-2005 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "crypto_openssl.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "admin.h"
+#include "privsep.h"
+#include "evt.h"
+#include "handler.h"
+#include "throttle.h"
+#include "remoteconf.h"
+#include "isakmp_inf.h"
+#include "isakmp_xauth.h"
+#include "isakmp_unity.h"
+#include "isakmp_cfg.h"
+#include "strnames.h"
+#include "ipsec_doi.h"
+#include "remoteconf.h"
+#include "localconf.h"
+
+#ifdef HAVE_LIBRADIUS
+#include <radlib.h>
+
+struct rad_handle *radius_auth_state = NULL;
+struct rad_handle *radius_acct_state = NULL;
+#endif
+
+#ifdef HAVE_LIBPAM
+#ifdef __APPLE__
+#include <pam/pam_appl.h>
+#else
+#include <security/pam_appl.h>
+#endif
+
+static char *PAM_usr = NULL;
+static char *PAM_pwd = NULL;
+static int PAM_conv(int, const struct pam_message **, 
+    struct pam_response **, void *);
+static struct pam_conv PAM_chat = { &PAM_conv, NULL };
+#endif
+
+
+void 
+xauth_sendreq(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buffer;
+       struct isakmp_pl_attr *attr;
+       struct isakmp_data *typeattr;
+       struct isakmp_data *usrattr;
+       struct isakmp_data *pwdattr;
+       struct xauth_state *xst = &iph1->mode_cfg->xauth;
+       size_t tlen;
+
+       /* Status checks */
+       if (iph1->status != PHASE1ST_ESTABLISHED) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth request while phase 1 is not completed\n");
+               return;
+       }
+
+       if (xst->status != XAUTHST_NOTYET) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth request whith Xauth state %d\n", xst->status);
+               return;
+       }
+
+       plog(LLV_INFO, LOCATION, NULL, "Sending Xauth request\n");
+
+       tlen = sizeof(*attr) +
+              + sizeof(*typeattr) +
+              + sizeof(*usrattr) +
+              + sizeof(*pwdattr);
+       
+       if ((buffer = vmalloc(tlen)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n");
+               return;
+       }
+       
+       attr = (struct isakmp_pl_attr *)buffer->v;
+       memset(attr, 0, tlen);
+
+       attr->h.len = htons(tlen);
+       attr->type = ISAKMP_CFG_REQUEST;
+       attr->id = htons(eay_random());
+
+       typeattr = (struct isakmp_data *)(attr + 1);
+       typeattr->type = htons(XAUTH_TYPE | ISAKMP_GEN_TV);
+       typeattr->lorv = htons(XAUTH_TYPE_GENERIC);
+
+       usrattr = (struct isakmp_data *)(typeattr + 1);
+       usrattr->type = htons(XAUTH_USER_NAME | ISAKMP_GEN_TLV);
+       usrattr->lorv = htons(0);
+
+       pwdattr = (struct isakmp_data *)(usrattr + 1);
+       pwdattr->type = htons(XAUTH_USER_PASSWORD | ISAKMP_GEN_TLV);
+       pwdattr->lorv = htons(0);
+
+       isakmp_cfg_send(iph1, buffer, 
+           ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
+       
+       vfree(buffer);
+
+       xst->status = XAUTHST_REQSENT;
+
+       return;
+}
+
+void 
+xauth_attr_reply(iph1, attr, id)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+       int id;
+{
+       char **outlet = NULL;
+       size_t alen = 0;
+       int type;
+       struct xauth_state *xst = &iph1->mode_cfg->xauth;
+
+       if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth reply but peer did not declare "
+                   "itself as Xauth capable\n");
+               return;
+       }
+
+       if (xst->status != XAUTHST_REQSENT) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth reply while Xauth state is %d\n", xst->status);
+               return;
+       }
+
+       type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
+       switch (type) {
+       case XAUTH_TYPE:
+               switch (ntohs(attr->lorv)) {
+               case XAUTH_TYPE_GENERIC:
+                       xst->authtype = XAUTH_TYPE_GENERIC;
+                       break;
+               default:
+                       plog(LLV_WARNING, LOCATION, NULL, 
+                           "Unexpected authentication type %d\n", 
+                           ntohs(type));
+                       return;
+               }
+               break;
+
+       case XAUTH_USER_NAME:
+               outlet = &xst->authdata.generic.usr;
+               break;
+
+       case XAUTH_USER_PASSWORD:
+               outlet = &xst->authdata.generic.pwd; 
+               break;
+
+       default:
+               plog(LLV_WARNING, LOCATION, NULL, 
+                   "ignored Xauth attribute %d\n", type);
+               break;
+       }
+
+       if (outlet != NULL) {
+               alen = ntohs(attr->lorv);
+
+               if ((*outlet = racoon_malloc(alen + 1)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot allocate memory for Xauth Data\n");
+                       return;
+               }
+
+               memcpy(*outlet, attr + 1, alen);
+               (*outlet)[alen] = '\0';
+               outlet = NULL;
+       }
+
+       
+       if ((xst->authdata.generic.usr != NULL) &&
+          (xst->authdata.generic.pwd != NULL)) {
+               int port;
+               int res;
+               char *usr = xst->authdata.generic.usr;
+               char *pwd = xst->authdata.generic.pwd;
+               time_t throttle_delay = 0;
+
+#if 0  /* Real debug, don't do that at home */
+               plog(LLV_DEBUG, LOCATION, NULL, 
+                   "Got username \"%s\", password \"%s\"\n", usr, pwd);
+#endif
+               strncpy(iph1->mode_cfg->login, usr, LOGINLEN);
+               iph1->mode_cfg->login[LOGINLEN] = '\0';
+
+               res = -1;
+               if ((port = isakmp_cfg_getport(iph1)) == -1) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Port pool depleted\n");
+                       goto skip_auth;
+               }       
+
+               switch (isakmp_cfg_config.authsource) {
+               case ISAKMP_CFG_AUTH_SYSTEM:
+                       res = privsep_xauth_login_system(usr, pwd);
+                       break;
+#ifdef HAVE_LIBRADIUS
+               case ISAKMP_CFG_AUTH_RADIUS:
+                       res = xauth_login_radius(iph1, usr, pwd);
+                       break;
+#endif
+#ifdef HAVE_LIBPAM
+               case ISAKMP_CFG_AUTH_PAM:
+                       res = privsep_xauth_login_pam(iph1->mode_cfg->port, 
+                           iph1->remote, usr, pwd);
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Unexpected authentication source\n");
+                       res = -1;
+                       break;
+               }
+
+               /*
+                * On failure, throttle the connexion for the remote host
+                * in order to make password attacks more difficult.
+                */
+               throttle_delay = throttle_host(iph1->remote, res) - time(NULL);
+               if (throttle_delay > 0) {
+                       char *str;
+
+                       str = saddrwop2str(iph1->remote);
+
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Throttling in action for %s: delay %lds\n",
+                           str, (unsigned long)throttle_delay);
+                       res = -1;
+               } else {
+                       throttle_delay = 0;
+               }
+
+skip_auth:
+               if (throttle_delay != 0) {
+                       struct xauth_reply_arg *xra;
+
+                       if ((xra = racoon_malloc(sizeof(*xra))) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "malloc failed, bypass throttling\n");
+                               xauth_reply(iph1, port, id, res);
+                               return;
+                       }
+
+                       /*
+                        * We need to store the ph1, but it might have
+                        * disapeared when xauth_reply is called, so
+                        * store the index instead.
+                        */
+                       xra->index = iph1->index;
+                       xra->port = port;
+                       xra->id = id;
+                       xra->res = res;
+                       sched_new(throttle_delay, xauth_reply_stub, xra);
+               } else {
+                       xauth_reply(iph1, port, id, res);
+               }
+       }
+
+       return;
+}
+
+void 
+xauth_reply_stub(args)
+       void *args;
+{
+       struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args;
+       struct ph1handle *iph1;
+
+       if ((iph1 = getph1byindex(&xra->index)) != NULL)
+               xauth_reply(iph1, xra->port, xra->id, xra->res);
+       else
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Delayed Xauth reply: phase 1 no longer exists.\n"); 
+
+       racoon_free(xra);
+       return;
+}
+
+void 
+xauth_reply(iph1, port, id, res)
+       struct ph1handle *iph1;
+       int port;
+       int id;
+{
+       struct xauth_state *xst = &iph1->mode_cfg->xauth;
+       char *usr = xst->authdata.generic.usr;
+
+       if (res != 0) {
+               if (port != -1)
+                       isakmp_cfg_putport(iph1, port);
+
+               plog(LLV_INFO, LOCATION, NULL, 
+                   "login failed for user \"%s\"\n", usr);
+               
+               xauth_sendstatus(iph1, XAUTH_STATUS_FAIL, id);
+               xst->status = XAUTHST_NOTYET;
+
+               /* Delete Phase 1 SA */
+               if (iph1->status == PHASE1ST_ESTABLISHED)
+                       isakmp_info_send_d1(iph1);
+               remph1(iph1);
+               delph1(iph1);
+
+               return;
+       }
+
+       xst->status = XAUTHST_OK;
+       plog(LLV_INFO, LOCATION, NULL, 
+           "login succeeded for user \"%s\"\n", usr);
+
+       xauth_sendstatus(iph1, XAUTH_STATUS_OK, id);
+
+       return;
+}
+
+void
+xauth_sendstatus(iph1, status, id)
+       struct ph1handle *iph1;
+       int status;
+       int id;
+{
+       vchar_t *buffer;
+       struct isakmp_pl_attr *attr;
+       struct isakmp_data *stattr;
+       size_t tlen;
+
+       tlen = sizeof(*attr) +
+              + sizeof(*stattr); 
+       
+       if ((buffer = vmalloc(tlen)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n");
+               return;
+       }
+       
+       attr = (struct isakmp_pl_attr *)buffer->v;
+       memset(attr, 0, tlen);
+
+       attr->h.len = htons(tlen);
+       attr->type = ISAKMP_CFG_SET;
+       attr->id = htons(id);
+
+       stattr = (struct isakmp_data *)(attr + 1);
+       stattr->type = htons(XAUTH_STATUS | ISAKMP_GEN_TV);
+       stattr->lorv = htons(status);
+
+       isakmp_cfg_send(iph1, buffer, 
+           ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
+       
+       vfree(buffer);
+
+       return; 
+}
+
+#ifdef HAVE_LIBRADIUS
+int
+xauth_radius_init(void)
+{
+       /* For first time use, initialize Radius */
+       if ((isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_RADIUS) &&
+           (radius_auth_state == NULL)) {
+               if ((radius_auth_state = rad_auth_open()) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot init libradius\n");
+                       return -1;
+               }
+
+               if (rad_config(radius_auth_state, NULL) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot open librarius config file: %s\n", 
+                           rad_strerror(radius_auth_state));
+                       rad_close(radius_auth_state);
+                       radius_auth_state = NULL;
+                       return -1;
+               }
+       }
+
+       if ((isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS) &&
+           (radius_acct_state == NULL)) {
+               if ((radius_acct_state = rad_auth_open()) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot init libradius\n");
+                       return -1;
+               }
+
+               if (rad_config(radius_acct_state, NULL) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot open librarius config file: %s\n", 
+                           rad_strerror(radius_acct_state));
+                       rad_close(radius_acct_state);
+                       radius_acct_state = NULL;
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int
+xauth_login_radius(iph1, usr, pwd)
+       struct ph1handle *iph1;
+       char *usr;
+       char *pwd;
+{
+       int res;
+       const void *data;
+       size_t len;
+       int type;
+
+       if (rad_create_request(radius_auth_state, RAD_ACCESS_REQUEST) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "rad_create_request failed: %s\n", 
+                   rad_strerror(radius_auth_state));
+               return -1;
+       }
+       
+       if (rad_put_string(radius_auth_state, RAD_USER_NAME, usr) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "rad_put_string failed: %s\n", 
+                   rad_strerror(radius_auth_state));
+               return -1;
+       }
+
+       if (rad_put_string(radius_auth_state, RAD_USER_PASSWORD, pwd) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "rad_put_string failed: %s\n", 
+                   rad_strerror(radius_auth_state));
+               return -1;
+       }
+
+       if (isakmp_cfg_radius_common(radius_auth_state, iph1->mode_cfg->port) != 0)
+               return -1;
+
+       switch (res = rad_send_request(radius_auth_state)) {
+       case RAD_ACCESS_ACCEPT:
+               while ((type = rad_get_attr(radius_auth_state, &data, &len)) != 0) {
+                       switch (type) {
+                       case RAD_FRAMED_IP_ADDRESS:
+                               iph1->mode_cfg->addr4 = rad_cvt_addr(data);
+                               iph1->mode_cfg->flags 
+                                   |= ISAKMP_CFG_ADDR4_RADIUS;
+                               break;
+
+                       case RAD_FRAMED_IP_NETMASK:
+                               iph1->mode_cfg->mask4 = rad_cvt_addr(data);
+                               iph1->mode_cfg->flags 
+                                   |= ISAKMP_CFG_MASK4_RADIUS;
+                               break;
+
+                       default:
+                               plog(LLV_INFO, LOCATION, NULL,
+                                   "Unexpected attribute: %d\n", type);
+                               break;
+                       }
+               }
+
+               return 0;
+               break;
+
+       case RAD_ACCESS_REJECT:
+               return -1;
+               break;
+
+       case -1:
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "rad_send_request failed: %s\n", 
+                   rad_strerror(radius_auth_state));
+               return -1;
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "rad_send_request returned %d\n", res);
+               return -1;
+               break;
+       }
+
+       return -1;
+}
+#endif
+
+#ifdef HAVE_LIBPAM
+static int 
+PAM_conv(msg_count, msg, rsp, dontcare)
+       int msg_count;
+       const struct pam_message **msg;
+       struct pam_response **rsp;
+       void *dontcare;
+{
+       int i;
+       int replies = 0;
+       struct pam_response *reply = NULL;
+
+       if ((reply = racoon_malloc(sizeof(*reply) * msg_count)) == NULL) 
+               return PAM_CONV_ERR;
+       bzero(reply, sizeof(*reply) * msg_count);
+
+       for (i = 0; i < msg_count; i++) {
+               switch (msg[i]->msg_style) {
+               case PAM_PROMPT_ECHO_ON:
+                       /* Send the username, libpam frees resp */
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = strdup(PAM_usr);
+                       break;
+
+               case PAM_PROMPT_ECHO_OFF:
+                       /* Send the password, libpam frees resp */
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = strdup(PAM_pwd);
+                       break;
+
+               case PAM_TEXT_INFO:
+               case PAM_ERROR_MSG:
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = NULL;
+                       break;
+
+               default:
+                       if (reply != NULL)
+                               racoon_free(reply);
+                       return PAM_CONV_ERR;
+                       break;
+               }
+       }
+
+       if (reply != NULL)
+               *rsp = reply;
+
+       return PAM_SUCCESS;
+}
+
+int
+xauth_login_pam(port, raddr, usr, pwd)
+       int port;
+       struct sockaddr *raddr;
+       char *usr;
+       char *pwd;
+{
+       int error;
+       int res;
+       const void *data;
+       size_t len;
+       int type;
+       char *remote;
+       pam_handle_t *pam = NULL;
+
+       if (isakmp_cfg_config.port_pool == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "isakmp_cfg_config.port_pool == NULL\n");
+               return -1;
+       }
+
+       if ((error = pam_start("racoon", usr, 
+           &PAM_chat, &isakmp_cfg_config.port_pool[port].pam)) != 0) {
+               if (isakmp_cfg_config.port_pool[port].pam == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, "pam_start failed\n");
+                       return -1;
+               } else {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "pam_start failed: %s\n", 
+                           pam_strerror(isakmp_cfg_config.port_pool[port].pam,
+                           error));
+                       goto out;
+               }
+       }
+       pam = isakmp_cfg_config.port_pool[port].pam;
+
+       if ((remote = strdup(saddrwop2str(raddr))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "cannot allocate memory: %s\n", strerror(errno)); 
+               goto out;
+       }
+       
+       if ((error = pam_set_item(pam, PAM_RHOST, remote)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "pam_set_item failed: %s\n", 
+                   pam_strerror(pam, error));
+               goto out;
+       }
+
+       PAM_usr = usr;
+       PAM_pwd = pwd;
+       error = pam_authenticate(pam, 0);
+       PAM_usr = NULL;
+       PAM_pwd = NULL;
+       if (error != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "pam_authenticate failed: %s\n", 
+                   pam_strerror(pam, error));
+               goto out;
+       }
+
+       if ((error = pam_acct_mgmt(pam, 0)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "pam_acct_mgmt failed: %s\n", 
+                   pam_strerror(pam, error));
+               goto out;
+       }
+
+       if ((error = pam_setcred(pam, 0)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "pam_setcred failed: %s\n", 
+                   pam_strerror(pam, error));
+               goto out;
+       }
+
+       return 0;
+
+out:
+       pam_end(pam, error);
+       isakmp_cfg_config.port_pool[port].pam = NULL;
+       return -1;
+}
+#endif
+
+int
+xauth_login_system(usr, pwd)
+       char *usr;
+       char *pwd;
+{
+       struct passwd *pw;
+       char *cryptpwd;
+       char *syscryptpwd;
+#ifdef HAVE_SHADOW_H
+       struct spwd *spw;
+
+       if ((spw = getspnam(usr)) == NULL)
+               return -1;
+
+       syscryptpwd = spw->sp_pwdp;
+#endif
+
+       if ((pw = getpwnam(usr)) == NULL)
+               return -1;
+
+#ifndef HAVE_SHADOW_H
+       syscryptpwd = pw->pw_passwd;
+#endif
+
+       /* No root login. Ever. */
+       if (pw->pw_uid == 0)
+               return -1;
+
+       if ((cryptpwd = crypt(pwd, syscryptpwd)) == NULL)
+               return -1;
+
+       if (strcmp(cryptpwd, syscryptpwd) == 0)
+               return 0;
+
+       return -1;
+}
+
+int 
+xauth_check(iph1)
+       struct ph1handle *iph1;
+{
+       struct xauth_state *xst = &iph1->mode_cfg->xauth;
+
+       /* If we don't use Xauth, then we pass */
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+       /* The following are not yet implemented */
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
+       case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
+               if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Hybrid auth negotiated but peer did not "
+                           "announced as Xauth capable\n");
+                       return -1;
+               }
+
+               if (xst->status != XAUTHST_OK) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Hybrid auth negotiated but peer did not "
+                           "succeed Xauth exchange\n");
+                       return -1;
+               }
+
+               return 0;
+               break;
+       default:
+               return 0;
+               break;
+       }
+
+       return 0;
+}
+
+vchar_t *
+isakmp_xauth_req(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       int type;
+       size_t dlen = 0;
+       int ashort = 0;
+       int value = 0;
+       vchar_t *buffer = NULL;
+       char *data;
+       vchar_t *usr = NULL;
+       vchar_t *pwd = NULL;
+       size_t skip = 0;
+       int freepwd = 0;
+
+       if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth mode config request but peer "
+                   "did not declare itself as Xauth capable\n");
+               return NULL;
+       }
+
+       type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
+
+       /* Sanity checks */
+       switch(type) {
+       case XAUTH_TYPE:
+               if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Unexpected long XAUTH_TYPE attribute\n");
+                       return NULL;
+               }
+               if (ntohs(attr->lorv) != XAUTH_TYPE_GENERIC) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Unsupported Xauth authentication %d\n", 
+                           ntohs(attr->lorv));
+                       return NULL;
+               }
+               ashort = 1;
+               dlen = 0;
+               value = XAUTH_TYPE_GENERIC;
+               break;
+
+       case XAUTH_USER_NAME:
+               if (iph1->rmconf->idvtype != IDTYPE_LOGIN) {
+                       plog(LLV_ERROR, LOCATION, NULL, "Xauth performed "
+                           "while identifier is not a login\n");
+                       return NULL;
+               }
+
+               if (iph1->rmconf->idv == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, "Xauth performed "
+                           "with no login supplied\n");
+                       return NULL;
+               }
+
+               dlen = iph1->rmconf->idv->l;
+               break;
+
+       case XAUTH_USER_PASSWORD:
+               if (iph1->rmconf->idvtype != IDTYPE_LOGIN) 
+                       return NULL;
+
+               if (iph1->rmconf->idv == NULL)
+                       return NULL;
+
+               skip = sizeof(struct ipsecdoi_id_b);
+               if ((usr = vmalloc(iph1->rmconf->idv->l + skip)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot allocate memory\n");
+                       return NULL;
+               }
+
+               memset(usr->v, 0, skip);
+               memcpy(usr->v + skip, 
+                   iph1->rmconf->idv->v, 
+                   iph1->rmconf->idv->l);
+
+               if (iph1->rmconf->key) {
+                       /* A key given through racoonctl */
+                       pwd = iph1->rmconf->key;
+               } else {
+                       if ((pwd = getpskbyname(usr)) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "No password was found for login %s\n", 
+                                   iph1->rmconf->idv->v);
+                               vfree(usr);
+                               return NULL;
+                       }
+                       /* We have to free it before returning */
+                       freepwd = 1;
+               }
+               vfree(usr);
+
+               dlen = pwd->l;
+
+               break;
+
+       default:
+               plog(LLV_WARNING, LOCATION, NULL,
+                   "Ignored attribute %d\n", type);
+               return NULL;
+               break;
+       }
+
+       if ((buffer = vmalloc(sizeof(*attr) + dlen)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory\n");
+               goto out;
+       }
+
+       attr = (struct isakmp_data *)buffer->v;
+       if (ashort) {
+               attr->type = htons(type | ISAKMP_GEN_TV);
+               attr->lorv = htons(value);
+               goto out;
+       }
+
+       attr->type = htons(type | ISAKMP_GEN_TLV);
+       attr->lorv = htons(dlen);
+       data = (char *)(attr + 1);
+
+       switch(type) {
+       case XAUTH_USER_NAME:
+               memcpy(data, iph1->rmconf->idv->v, dlen);
+               break;
+       case XAUTH_USER_PASSWORD:
+               memcpy(data, pwd->v, dlen);
+               break;
+       default:
+               break;
+       }
+
+out:
+       if (freepwd)
+               vfree(pwd);
+
+       return buffer;
+}
+
+vchar_t *
+isakmp_xauth_set(iph1, attr)
+       struct ph1handle *iph1;
+       struct isakmp_data *attr;
+{
+       int type;
+       vchar_t *buffer = NULL;
+       char *data;
+
+       if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Xauth mode config set but peer "
+                   "did not declare itself as Xauth capable\n");
+               return NULL;
+       }
+
+       type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
+
+       switch(type) {
+       case XAUTH_STATUS:
+               /* If we got a failure, delete iph1 */
+               if (ntohs(attr->lorv) != XAUTH_STATUS_OK) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Xauth authentication failed\n");
+
+                       EVT_PUSH(iph1->local, iph1->remote, 
+                           EVTT_XAUTH_FAILED, NULL);
+
+                       iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1;
+               } else {
+                       EVT_PUSH(iph1->local, 
+                           iph1->remote, EVTT_XAUTH_SUCCESS, NULL);
+               }
+
+
+               /* We acknowledge it */
+               break;
+       default:
+               plog(LLV_WARNING, LOCATION, NULL,
+                   "Ignored attribute %d\n", type);
+               return NULL;
+               break;
+       }
+
+       if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory\n");
+               return NULL;
+       }
+
+       attr = (struct isakmp_data *)buffer->v;
+       attr->type = htons(type | ISAKMP_GEN_TV);
+       attr->lorv = htons(0);
+
+       return buffer;
+}
+
+
+void 
+xauth_rmstate(xst)
+       struct xauth_state *xst;
+{
+       switch (xst->authtype) {
+       case XAUTH_TYPE_GENERIC:
+               if (xst->authdata.generic.usr)
+                       racoon_free(xst->authdata.generic.usr);
+
+               if (xst->authdata.generic.pwd)
+                       racoon_free(xst->authdata.generic.pwd);
+
+               break;
+
+       case XAUTH_TYPE_CHAP:
+       case XAUTH_TYPE_OTP:
+       case XAUTH_TYPE_SKEY:
+               plog(LLV_WARNING, LOCATION, NULL, 
+                   "Unsupported authtype %d\n", xst->authtype);
+               break;
+
+       default:
+               plog(LLV_WARNING, LOCATION, NULL, 
+                   "Unexpected authtype %d\n", xst->authtype);
+               break;
+       }
+
+       return;
+}
+
diff --git a/ipsec-tools/racoon/isakmp_xauth.h b/ipsec-tools/racoon/isakmp_xauth.h
new file mode 100644 (file)
index 0000000..5d4bdbb
--- /dev/null
@@ -0,0 +1,96 @@
+/*     $KAME$ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus 
+ * 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.
+ */
+
+/* ISAKMP mode config attribute types specific to the Xauth vendor ID */
+#define        XAUTH_TYPE                16520
+#define        XAUTH_USER_NAME           16521
+#define        XAUTH_USER_PASSWORD       16522
+#define        XAUTH_PASSCODE            16523
+#define        XAUTH_MESSAGE             16524
+#define        XAUTH_CHALLENGE           16525
+#define        XAUTH_DOMAIN              16526
+#define        XAUTH_STATUS              16527
+#define        XAUTH_NEXT_PIN            16528
+#define        XAUTH_ANSWER              16529
+
+/* Types for XAUTH_TYPE */
+#define        XAUTH_TYPE_GENERIC      0
+#define        XAUTH_TYPE_CHAP         1
+#define        XAUTH_TYPE_OTP          2
+#define        XAUTH_TYPE_SKEY         3
+
+/* Values for XAUTH_STATUS */
+#define        XAUTH_STATUS_FAIL       0
+#define        XAUTH_STATUS_OK         1
+
+struct xauth_state {
+       int status;
+       int vendorid;
+       int authtype;
+       union {
+               struct authgeneric {
+                       char *usr;
+                       char *pwd;
+               } generic;
+       } authdata;
+};
+
+/* status */
+#define XAUTHST_NOTYET 0
+#define XAUTHST_REQSENT        1
+#define XAUTHST_OK     2
+
+struct xauth_reply_arg {
+       isakmp_index index;
+       int port;
+       int id;
+       int res;
+};
+
+struct ph1handle;
+void xauth_sendreq(struct ph1handle *);
+void xauth_attr_reply(struct ph1handle *, struct isakmp_data *, int);
+int xauth_login_system(char *, char *);
+void xauth_sendstatus(struct ph1handle *, int, int);
+int xauth_check(struct ph1handle *);
+vchar_t *isakmp_xauth_req(struct ph1handle *, struct isakmp_data *);
+vchar_t *isakmp_xauth_set(struct ph1handle *, struct isakmp_data *);
+void xauth_rmstate(struct xauth_state *);
+void xauth_reply_stub(void *);
+void xauth_reply(struct ph1handle *, int, int, int);
+
+#ifdef HAVE_LIBRADIUS
+int xauth_login_radius(struct ph1handle *, char *, char *);
+int xauth_radius_init(void);
+#endif
+#ifdef HAVE_LIBPAM
+int xauth_login_pam(int, struct sockaddr *, char *, char *);
+#endif
diff --git a/ipsec-tools/racoon/kmpstat.c b/ipsec-tools/racoon/kmpstat.c
new file mode 100644 (file)
index 0000000..b9eec1a
--- /dev/null
@@ -0,0 +1,230 @@
+/*     $KAME: kmpstat.c,v 1.33 2004/08/16 08:20:28 itojun Exp $        */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <err.h>
+#include <sys/ioctl.h> 
+
+#include "libpfkey.h"
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+#include "sockmisc.h"
+
+#include "racoonctl.h"
+#include "admin.h"
+#include "schedule.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_xauth.h"
+#include "isakmp_var.h"
+#include "isakmp_cfg.h"
+#include "isakmp_unity.h"
+#include "oakley.h"
+#include "handler.h"
+#include "pfkey.h"
+#include "admin.h"
+#include "evt.h"
+#include "admin_var.h"
+#include "ipsec_doi.h"
+
+u_int32_t racoonctl_interface = RACOONCTL_INTERFACE;
+u_int32_t racoonctl_interface_major = RACOONCTL_INTERFACE_MAJOR;
+
+static int so;
+u_int32_t loglevel = 0;
+
+int
+com_init()
+{
+       struct sockaddr_un name;
+
+       memset(&name, 0, sizeof(name));
+       name.sun_family = AF_UNIX;
+       snprintf(name.sun_path, sizeof(name.sun_path),
+               "%s", ADMINSOCK_PATH);
+
+       so = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (so < 0)
+               return -1;
+
+       if (connect(so, (struct sockaddr *)&name, sizeof(name)) < 0) {
+               (void)close(so);
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+com_send(combuf)
+       vchar_t *combuf;
+{
+       int len;
+
+       if ((len = send(so, combuf->v, combuf->l, 0)) == -1) {
+               perror("send");
+               (void)close(so);
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+com_recv(combufp) 
+       vchar_t **combufp;
+{
+       struct admin_com h, *com;
+       caddr_t buf;
+       int len;
+       int l = 0;
+       caddr_t p;
+
+       if (combufp == NULL)
+               return -1;
+
+       /* receive by PEEK */ 
+       if ((len = recv(so, &h, sizeof(h), MSG_PEEK)) == -1)
+               goto bad1;
+
+       /* sanity check */
+       if (len < sizeof(h))
+               goto bad1;
+
+       if (h.ac_errno) {
+               errno = h.ac_errno;
+               goto bad1;
+       }
+
+       /* allocate buffer */
+       if ((*combufp = vmalloc(h.ac_len)) == NULL)
+               goto bad1;
+
+       /* read real message */
+       p = (*combufp)->v;
+       while (l < len) {
+               if ((len = recv(so, p, h.ac_len, 0)) < 0) {
+                       perror("recv");
+                       goto bad2;
+               }
+               l += len;
+               p += len;
+       }
+       
+       return 0;
+
+bad2:
+       vfree(*combufp);
+bad1:
+       *combufp = NULL;
+       return -1;
+}
+
+/*
+ * Dumb plog functions (used by sockmisc.c) 
+ */
+void
+plog(int pri, const char *func, struct sockaddr *sa, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vprintf(fmt, ap);
+       va_end(ap);
+}
+
+void
+plogdump(pri, data, len) 
+       int pri;
+       void *data;
+       size_t len;
+{
+       return;
+}
+
+struct sockaddr *
+get_sockaddr(family, name, port)
+       int family;
+       char *name, *port;
+{
+       struct addrinfo hint, *ai;
+       int error;
+
+       memset(&hint, 0, sizeof(hint));
+       hint.ai_family = PF_UNSPEC;
+       hint.ai_family = family;
+       hint.ai_socktype = SOCK_STREAM;
+
+       error = getaddrinfo(name, port, &hint, &ai);
+       if (error != 0) {
+               printf("%s: %s/%s\n", gai_strerror(error), name, port);
+               return NULL;
+       }
+
+       return ai->ai_addr;
+}
diff --git a/ipsec-tools/racoon/localconf.c b/ipsec-tools/racoon/localconf.c
new file mode 100644 (file)
index 0000000..73f01f9
--- /dev/null
@@ -0,0 +1,479 @@
+/*     $KAME: localconf.c,v 1.33 2001/08/09 07:32:19 sakane Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "algorithm.h"
+#include "admin.h"
+#include "privsep.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "grabmyaddr.h"
+#include "vendorid.h"
+#include "str2val.h"
+#include "safefile.h"
+#include "admin.h"
+#include "gcmalloc.h"
+#include "session.h"
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#endif
+
+struct localconf *lcconf;
+
+static void setdefault __P((void));
+
+void
+initlcconf()
+{
+       lcconf = racoon_calloc(1, sizeof(*lcconf));
+       if (lcconf == NULL)
+               errx(1, "failed to allocate local conf.");
+
+       setdefault();
+       lcconf->sock_vpncontrol = -1;   /* not to be done during flush */
+       lcconf->racoon_conf = LC_DEFAULT_CF;
+}
+
+void
+flushlcconf()
+{
+       int i;
+
+       setdefault();
+       clear_myaddr();
+       for (i = 0; i < LC_PATHTYPE_MAX; i++) {
+               if (lcconf->pathinfo[i]) {
+                       racoon_free(lcconf->pathinfo[i]);
+                       lcconf->pathinfo[i] = NULL;
+               }
+       }
+       for (i = 0; i < LC_IDENTTYPE_MAX; i++) {
+               if (lcconf->ident[i])
+                       vfree(lcconf->ident[i]);
+               lcconf->ident[i] = NULL;
+       }
+}
+
+static void
+setdefault()
+{
+       lcconf->uid = 0;
+       lcconf->gid = 0;
+       lcconf->chroot = NULL;
+       lcconf->autograbaddr = 1;
+       lcconf->port_isakmp = PORT_ISAKMP;
+       lcconf->port_isakmp_natt = PORT_ISAKMP_NATT;
+       lcconf->default_af = AF_INET;
+       lcconf->pad_random = LC_DEFAULT_PAD_RANDOM;
+       lcconf->pad_randomlen = LC_DEFAULT_PAD_RANDOMLEN;
+       lcconf->pad_maxsize = LC_DEFAULT_PAD_MAXSIZE;
+       lcconf->pad_strict = LC_DEFAULT_PAD_STRICT;
+       lcconf->pad_excltail = LC_DEFAULT_PAD_EXCLTAIL;
+       lcconf->retry_counter = LC_DEFAULT_RETRY_COUNTER;
+       lcconf->retry_interval = LC_DEFAULT_RETRY_INTERVAL;
+       lcconf->count_persend = LC_DEFAULT_COUNT_PERSEND;
+       lcconf->secret_size = LC_DEFAULT_SECRETSIZE;
+       lcconf->retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1;
+       lcconf->wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE;
+       lcconf->strict_address = FALSE;
+       lcconf->complex_bundle = TRUE; /*XXX FALSE;*/
+       lcconf->gss_id_enc = LC_GSSENC_UTF16LE; /* Windows compatibility */
+       lcconf->natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL;
+       lcconf->auto_exit_delay = 0;
+       lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_SET;
+}
+
+/*
+ * get PSK by string.
+ */
+vchar_t *
+getpskbyname(id0)
+       vchar_t *id0;
+{
+       char *id;
+       vchar_t *key = NULL;
+
+       id = racoon_calloc(1, 1 + id0->l - sizeof(struct ipsecdoi_id_b));
+       if (id == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get psk buffer.\n");
+               goto end;
+       }
+       memcpy(id, id0->v + sizeof(struct ipsecdoi_id_b),
+               id0->l - sizeof(struct ipsecdoi_id_b));
+       id[id0->l - sizeof(struct ipsecdoi_id_b)] = '\0';
+
+       key = privsep_getpsk(id, id0->l - sizeof(struct ipsecdoi_id_b));
+
+end:
+       if (id)
+               racoon_free(id);
+       return key;
+}
+
+#ifdef __APPLE__
+/*
+ * get PSK from keyChain.
+ */
+vchar_t *
+getpskfromkeychain(const char *name, u_int8_t etype, int secrettype, vchar_t *id_p)
+{
+       SecKeychainRef keychain = NULL;
+       vchar_t *key = NULL;
+       void *cur_password = NULL;
+       UInt32 cur_password_len = 0;
+       OSStatus status;
+       char serviceName[] = "com.apple.net.racoon";
+
+       status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+       if (status != noErr) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to set system keychain domain.\n");
+               goto end;
+       }
+
+       status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
+                                             &keychain);
+       if (status != noErr) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get system keychain domain.\n");
+               goto end;
+       }
+
+       if (secrettype == SECRETTYPE_KEYCHAIN_BY_ID && etype == ISAKMP_ETYPE_AGG) {
+               /* try looking up based on peers id */
+               
+               char* peer_id;
+               int idlen = id_p->l - sizeof(struct ipsecdoi_id_b);
+               u_int8_t id_type = ((struct ipsecdoi_id_b *)(id_p->v))->type;
+
+               switch (id_type) {
+                       case IPSECDOI_ID_IPV4_ADDR:
+                       case IPSECDOI_ID_IPV6_ADDR:
+                       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+                       case IPSECDOI_ID_IPV4_ADDR_RANGE:
+                       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+                       case IPSECDOI_ID_IPV6_ADDR_RANGE:
+                       case IPSECDOI_ID_DER_ASN1_DN:
+                       case IPSECDOI_ID_DER_ASN1_GN:
+                               goto end;
+                               break;
+                               
+                       case IPSECDOI_ID_FQDN:
+                       case IPSECDOI_ID_USER_FQDN:
+                       case IPSECDOI_ID_KEY_ID:
+                               peer_id = racoon_malloc(idlen);
+                               if (peer_id == NULL)
+                                       goto end;
+                               memcpy(peer_id, id_p->v + sizeof(struct ipsecdoi_id_b), idlen);
+                               *(peer_id + idlen) = '\0';
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "getting shared secret from keychain using %s.\n", peer_id);
+
+                               break;
+                       default:
+                               goto end;
+                               break;
+               }
+                                               
+               status = SecKeychainFindGenericPassword(keychain,
+                                                               strlen(serviceName),
+                                                               serviceName,
+                                                               idlen,
+                                                               peer_id,
+                                                               &cur_password_len,
+                                                               &cur_password,
+                                                               NULL);
+
+               if (status == noErr)
+                       goto end;
+               /* otherwise fall through to use the default value */
+       }
+       
+       /*      use the value in remote config sharedsecret field
+               this is either the value specified for lookup or the 
+               default when lookup by id fails.
+       */
+       status = SecKeychainFindGenericPassword(keychain,
+                                                       strlen(serviceName),
+                                                       serviceName,
+                                                       strlen(name),
+                                                       name,
+                                                       &cur_password_len,
+                                                       &cur_password,
+                                                       NULL);
+                                                               
+       /* try find it using using only name. */
+       if (status == errSecItemNotFound) 
+               status = SecKeychainFindGenericPassword(keychain,
+                                                       strlen(name),
+                                                       name,
+                                                       0,
+                                                       0,
+                                                       &cur_password_len,
+                                                       &cur_password,
+                                                       NULL);
+
+       switch (status) {
+
+               case noErr :
+                       goto end;
+                       break;
+
+               case errSecItemNotFound :
+                       break;
+
+               default :
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get preshared key from system keychain (error %d).\n", status);
+       }
+
+end:
+
+        if (cur_password) {
+                key = vmalloc(cur_password_len + 1);
+                if (key == NULL) {
+                        plog(LLV_ERROR, LOCATION, NULL,
+                                "failed to allocate key buffer.\n");
+                } else {
+                                       memcpy(key->v, cur_password, key->l);
+                                       key->v[cur_password_len] = 0;
+                }
+                       free(cur_password);
+        }
+        
+        if (keychain)
+            CFRelease(keychain);
+
+       return key;
+}
+#endif
+
+/*
+ * get PSK by address.
+ */
+vchar_t *
+getpskbyaddr(remote)
+       struct sockaddr *remote;
+{
+       vchar_t *key = NULL;
+       char addr[NI_MAXHOST], port[NI_MAXSERV];
+
+       GETNAMEINFO(remote, addr, port);
+
+       key = privsep_getpsk(addr, strlen(addr));
+
+       return key;
+}
+
+vchar_t *
+getpsk(str, len)
+       const char *str;
+       const int len;
+{
+       FILE *fp;
+       char buf[1024]; /* XXX how is variable length ? */
+       vchar_t *key = NULL;
+       char *p, *q;
+       size_t keylen;
+       char *k = NULL;
+
+       if (safefile(lcconf->pathinfo[LC_PATHTYPE_PSK], 1) == 0)
+               fp = fopen(lcconf->pathinfo[LC_PATHTYPE_PSK], "r");
+       else
+               fp = NULL;
+       if (fp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to open pre_share_key file %s\n",
+                       lcconf->pathinfo[LC_PATHTYPE_PSK]);
+               return NULL;
+       }
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               /* comment line */
+               if (buf[0] == '#')
+                       continue;
+
+               /* search the end of 1st string. */
+               for (p = buf; *p != '\0' && !isspace((int)*p); p++)
+                       ;
+               if (*p == '\0')
+                       continue;       /* no 2nd parameter */
+               *p = '\0';
+               /* search the 1st of 2nd string. */
+               while (isspace((int)*++p))
+                       ;
+               if (*p == '\0')
+                       continue;       /* no 2nd parameter */
+               p--;
+               if (strncmp(buf, str, len) == 0 && buf[len] == '\0') {
+                       p++;
+                       keylen = 0;
+                       for (q = p; *q != '\0' && *q != '\n'; q++)
+                               keylen++;
+                       *q = '\0';
+
+                       /* fix key if hex string */
+                       if (strncmp(p, "0x", 2) == 0) {
+                               k = str2val(p + 2, 16, &keylen);
+                               if (k == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "failed to get psk buffer.\n");
+                                       goto end;
+                               }
+                               p = k;
+                       }
+
+                       key = vmalloc(keylen);
+                       if (key == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to allocate key buffer.\n");
+                               goto end;
+                       }
+                       memcpy(key->v, p, key->l);
+                       if (k)
+                               racoon_free(k);
+                       goto end;
+               }
+       }
+
+end:
+       fclose(fp);
+       return key;
+}
+
+/*
+ * get a file name of a type specified.
+ */
+void
+getpathname(path, len, type, name)
+       char *path;
+       int len, type;
+       const char *name;
+{
+       snprintf(path, len, "%s%s%s", 
+               name[0] == '/' ? "" : lcconf->pathinfo[type],
+               name[0] == '/' ? "" : "/",
+               name);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "filename: %s\n", path);
+}
+
+#if 0 /* DELETEIT */
+static int lc_doi2idtype[] = {
+       -1,
+       -1,
+       LC_IDENTTYPE_FQDN,
+       LC_IDENTTYPE_USERFQDN,
+       -1,
+       -1,
+       -1,
+       -1,
+       -1,
+       LC_IDENTTYPE_CERTNAME,
+       -1,
+       LC_IDENTTYPE_KEYID,
+};
+
+/*
+ * convert DOI value to idtype
+ * OUT -1   : NG
+ *     other: converted.
+ */
+int
+doi2idtype(idtype)
+       int idtype;
+{
+       if (ARRAYLEN(lc_doi2idtype) > idtype)
+               return lc_doi2idtype[idtype];
+       return -1;
+}
+#endif
+
+static int lc_sittype2doi[] = {
+       IPSECDOI_SIT_IDENTITY_ONLY,
+       IPSECDOI_SIT_SECRECY,
+       IPSECDOI_SIT_INTEGRITY,
+};
+
+/*
+ * convert sittype to DOI value.
+ * OUT -1   : NG
+ *     other: converted.
+ */
+int
+sittype2doi(sittype)
+       int sittype;
+{
+       if (ARRAYLEN(lc_sittype2doi) > sittype)
+               return lc_sittype2doi[sittype];
+       return -1;
+}
+
+static int lc_doitype2doi[] = {
+       IPSEC_DOI,
+};
+
+/*
+ * convert doitype to DOI value.
+ * OUT -1   : NG
+ *     other: converted.
+ */
+int
+doitype2doi(doitype)
+       int doitype;
+{
+       if (ARRAYLEN(lc_doitype2doi) > doitype)
+               return lc_doitype2doi[doitype];
+       return -1;
+}
+
diff --git a/ipsec-tools/racoon/localconf.h b/ipsec-tools/racoon/localconf.h
new file mode 100644 (file)
index 0000000..f99d1a7
--- /dev/null
@@ -0,0 +1,167 @@
+/* $Id: localconf.h,v 1.9.2.3 2005/11/06 17:18:26 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALCONF_H
+#define _LOCALCONF_H
+
+/* local configuration */
+
+#define LC_DEFAULT_CF  SYSCONFDIR "/racoon.conf"
+
+#define LC_PATHTYPE_INCLUDE    0
+#define LC_PATHTYPE_PSK                1
+#define LC_PATHTYPE_CERT       2
+#define LC_PATHTYPE_BACKUPSA   3
+#define LC_PATHTYPE_SCRIPT     4
+#define LC_PATHTYPE_PIDFILE    5
+#define LC_PATHTYPE_LOGFILE    6
+#define LC_PATHTYPE_MAX                7
+
+#define LC_DEFAULT_PAD_MAXSIZE         20
+#define LC_DEFAULT_PAD_RANDOM          TRUE
+#define LC_DEFAULT_PAD_RANDOMLEN       FALSE
+#define LC_DEFAULT_PAD_STRICT          FALSE
+#define LC_DEFAULT_PAD_EXCLTAIL                TRUE
+#define LC_DEFAULT_RETRY_COUNTER       5
+#define LC_DEFAULT_RETRY_INTERVAL      10
+#define LC_DEFAULT_COUNT_PERSEND       1
+#define LC_DEFAULT_RETRY_CHECKPH1      30
+#define LC_DEFAULT_WAIT_PH2COMPLETE    30
+#define LC_DEFAULT_NATT_KA_INTERVAL    20
+
+#define LC_DEFAULT_SECRETSIZE  16      /* 128 bits */
+
+#define LC_IDENTTYPE_MAX       5       /* XXX */
+
+#define        LC_GSSENC_UTF16LE       0       /* GSS ID in UTF-16LE */
+#define        LC_GSSENC_LATIN1        1       /* GSS ID in ISO-Latin-1 */
+#define        LC_GSSENC_MAX           2
+
+#define LC_AUTOEXITSTATE_SET           0x00000001
+#define LC_AUTOEXITSTATE_CLIENT                0x00000010
+#define LC_AUTOEXITSTATE_ENABLED       0x00000011      /* both VPN client and set */
+
+
+struct vpnctl_socket_elem {
+       LIST_ENTRY(vpnctl_socket_elem) chain;
+       int                     sock;
+       LIST_HEAD(_bound_addrs, bound_addr) bound_addresses;
+};
+
+struct bound_addr {
+       LIST_ENTRY(bound_addr) chain;
+       u_int32_t       address;
+};
+
+struct redirect {
+       LIST_ENTRY(redirect) chain;
+       u_int32_t       cluster_address;
+       u_int32_t       redirect_address;
+       u_int16_t       force;
+};
+
+
+struct localconf {
+       char *racoon_conf;              /* configuration filename */
+
+       uid_t uid;
+       gid_t gid;
+       char *chroot;                   /* chroot path */
+       u_int16_t port_isakmp;          /* port for isakmp as default */
+       u_int16_t port_isakmp_natt;     /* port for NAT-T use */
+       u_int16_t port_admin;           /* port for admin */
+       int default_af;                 /* default address family */
+
+       int sock_admin;
+       int sock_vpncontrol;
+       int sock_pfkey;
+       int rtsock;                     /* routing socket */
+       LIST_HEAD(_vpnctl_socket_elem_, vpnctl_socket_elem) vpnctl_comm_socks;
+       LIST_HEAD(_redirect_, redirect) redirect_addresses;
+       int auto_exit_state;            /* auto exit state */
+       int     auto_exit_delay;                /* auto exit delay until exit */
+       struct sched *auto_exit_sched;  /* auto exit schedule */
+       
+       int autograbaddr;
+       struct myaddrs *myaddrs;
+
+       char *logfile_param;    /* from command line */
+       char *pathinfo[LC_PATHTYPE_MAX];
+       vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */
+
+       int pad_random;
+       int pad_randomlen;
+       int pad_maxsize;
+       int pad_strict;
+       int pad_excltail;
+
+       int retry_counter;              /* times to retry. */
+       int retry_interval;             /* interval each retry. */
+       int count_persend;              /* the number of packets each retry. */
+                               /* above 3 values are copied into a handler. */
+
+       int retry_checkph1;
+       int wait_ph2complete;
+
+       int natt_ka_interval;           /* NAT-T keepalive interval. */
+
+       int secret_size;
+       int strict_address;             /* strictly check addresses. */
+
+       int complex_bundle;
+               /*
+                * If we want to make a packet "IP2 AH ESP IP1 ULP",
+                * the SPD in KAME expresses AH transport + ESP tunnel.
+                * So racoon sent the proposal contained such the order.
+                * But lots of implementation interprets AH tunnel + ESP
+                * tunnel in this case.  racoon has changed the format,
+                * usually uses this format.  If the option, 'complex_bundle'
+                * is enable, racoon uses old format.
+                */
+
+       int gss_id_enc;                 /* GSS ID encoding to use */
+};
+
+extern struct localconf *lcconf;
+
+extern void initlcconf __P((void));
+extern void flushlcconf __P((void));
+extern vchar_t *getpskbyname __P((vchar_t *));
+extern vchar_t *getpskbyaddr __P((struct sockaddr *));
+#ifdef __APPLE__
+extern vchar_t *getpskfromkeychain __P((const char *, u_int8_t, int, vchar_t *));
+#endif
+extern void getpathname __P((char *, int, int, const char *));
+extern int sittype2doi __P((int));
+extern int doitype2doi __P((int));
+extern vchar_t *getpsk __P((const char *, const int)); 
+
+#endif /* _LOCALCONF_H */
diff --git a/ipsec-tools/racoon/logger.c b/ipsec-tools/racoon/logger.c
new file mode 100644 (file)
index 0000000..03a3ac6
--- /dev/null
@@ -0,0 +1,260 @@
+/*     $KAME: logger.c,v 1.9 2002/09/03 14:37:03 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "logger.h"
+#include "var.h"
+#include "gcmalloc.h"
+
+struct log *
+log_open(siz, fname)
+       size_t siz;
+       char *fname;
+{
+       struct log *p;
+
+       p = (struct log *)racoon_malloc(sizeof(*p));
+       if (p == NULL)
+               return NULL;
+       memset(p, 0, sizeof(*p));
+
+       p->buf = (char **)racoon_malloc(sizeof(char *) * siz);
+       if (p->buf == NULL) {
+               racoon_free(p);
+               return NULL;
+       }
+       memset(p->buf, 0, sizeof(char *) * siz);
+
+       p->tbuf = (time_t *)racoon_malloc(sizeof(time_t *) * siz);
+       if (p->tbuf == NULL) {
+               racoon_free(p->buf);
+               racoon_free(p);
+               return NULL;
+       }
+       memset(p->tbuf, 0, sizeof(time_t *) * siz);
+
+       p->siz = siz;
+       if (fname)
+               p->fname = strdup(fname);
+
+       return p;
+}
+
+/*
+ * append string to ring buffer.
+ * string must be \n-terminated (since we add timestamps).
+ * even if not, we'll add \n to avoid formatting mistake (see log_close()).
+ */
+void
+log_add(p, str)
+       struct log *p;
+       char *str;
+{
+       /* syslog if p->fname == NULL? */
+       if (p->buf[p->head])
+               racoon_free(p->buf[p->head]);
+       p->buf[p->head] = strdup(str);
+       p->tbuf[p->head] = time(NULL);
+       p->head++;
+       p->head %= p->siz;
+}
+
+/*
+ * write out string to the log file, as is.
+ * \n-termination is up to the caller.  if you don't add \n, the file
+ * format may be broken.
+ */
+int
+log_print(p, str)
+       struct log *p;
+       char *str;
+{
+       FILE *fp;
+
+       if (p->fname == NULL)
+               return -1;      /*XXX syslog?*/
+       fp = fopen(p->fname, "a");
+       if (fp == NULL)
+               return -1;
+       fprintf(fp, "%s", str);
+       fclose(fp);
+
+       return 0;
+}
+
+int
+log_vprint(struct log *p, const char *fmt, ...)
+{
+       va_list ap;
+
+       FILE *fp;
+
+       if (p->fname == NULL)
+               return -1;      /*XXX syslog?*/
+       fp = fopen(p->fname, "a");
+       if (fp == NULL)
+               return -1;
+       va_start(ap, fmt);
+       vfprintf(fp, fmt, ap);
+       va_end(ap);
+
+       fclose(fp);
+
+       return 0;
+}
+
+int
+log_vaprint(struct log *p, const char *fmt, va_list ap)
+{
+       FILE *fp;
+
+       if (p->fname == NULL)
+               return -1;      /*XXX syslog?*/
+       fp = fopen(p->fname, "a");
+       if (fp == NULL)
+               return -1;
+       vfprintf(fp, fmt, ap);
+       fclose(fp);
+
+       return 0;
+}
+
+/*
+ * write out content of ring buffer, and reclaim the log structure
+ */
+int
+log_close(p)
+       struct log *p;
+{
+       FILE *fp;
+       int i, j;
+       char ts[256];
+       struct tm *tm;
+
+       if (p->fname == NULL)
+               goto nowrite;
+       fp = fopen(p->fname, "a");
+       if (fp == NULL)
+               goto nowrite;
+
+       for (i = 0; i < p->siz; i++) {
+               j = (p->head + i) % p->siz;
+               if (p->buf[j]) {
+                       tm = localtime(&p->tbuf[j]);
+                       strftime(ts, sizeof(ts), "%B %d %T", tm);
+                       fprintf(fp, "%s: %s\n", ts, p->buf[j]);
+                       if (*(p->buf[j] + strlen(p->buf[j]) - 1) != '\n')
+                               fprintf(fp, "\n");
+               }
+       }
+       fclose(fp);
+
+nowrite:
+       log_free(p);
+       return 0;
+}
+
+void
+log_free(p)
+       struct log *p;
+{
+       int i;
+
+       for (i = 0; i < p->siz; i++)
+               racoon_free(p->buf[i]);
+       racoon_free(p->buf);
+       racoon_free(p->tbuf);
+       if (p->fname)
+               racoon_free(p->fname);
+       racoon_free(p);
+}
+
+#ifdef TEST
+struct log *l;
+
+void
+vatest(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       log_vaprint(l, fmt, ap);
+       va_end(ap);
+}
+
+int
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       int i;
+
+       l = log_open(30, "/tmp/hoge");
+       if (l == NULL)
+               errx(1, "hoge");
+
+       for (i = 0; i < 50; i++) {
+               log_add(l, "foo");
+               log_add(l, "baa");
+               log_add(l, "baz");
+       }
+       log_print(l, "hoge\n");
+       log_vprint(l, "hoge %s\n", "this is test");
+       vatest("%s %s\n", "this is", "vprint test");
+       abort();
+       log_free(l);
+}
+
+#endif
+
diff --git a/ipsec-tools/racoon/logger.h b/ipsec-tools/racoon/logger.h
new file mode 100644 (file)
index 0000000..a5bfb3f
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: logger.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOGGER_H
+#define _LOGGER_H
+
+struct log {
+       int head;
+       int siz;
+       char **buf;
+       time_t *tbuf;
+       char *fname;
+};
+
+extern struct log *log_open __P((size_t, char *));
+extern void log_add __P((struct log *, char *));
+extern int log_print __P((struct log *, char *));
+extern int log_vprint __P((struct log *, const char *, ...));
+extern int log_vaprint __P((struct log *, const char *, va_list));
+extern int log_close __P((struct log *));
+extern void log_free __P((struct log *));
+
+#endif /* _LOGGER_H */
diff --git a/ipsec-tools/racoon/main.c b/ipsec-tools/racoon/main.c
new file mode 100644 (file)
index 0000000..f325c90
--- /dev/null
@@ -0,0 +1,469 @@
+/* $Id: main.c,v 1.14.2.3 2005/11/06 17:18:26 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <paths.h>
+#include <err.h>
+
+/*
+ * If we're using a debugging malloc library, this may define our
+ * wrapper stubs.
+ */
+#define        RACOON_MAIN_PROGRAM
+#include "gcmalloc.h"
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "cfparse_proto.h"
+#include "isakmp_var.h"
+#ifdef HAVE_LIBRADIUS
+#include "isakmp.h"
+#include "isakmp_xauth.h"
+#endif
+#include "remoteconf.h"
+#include "localconf.h"
+#include "session.h"
+#include "oakley.h"
+#include "pfkey.h"
+#include "crypto_openssl.h"
+#include "backupsa.h"
+#include "vendorid.h"
+
+//#include "package_version.h"
+
+int f_local = 0;       /* local test mode.  behave like a wall. */
+int vflag = 1;         /* for print-isakmp.c */
+static int loading_sa = 0;     /* install sa when racoon boots up. */
+static int dump_config = 0;    /* dump parsed config file. */
+static int exec_done = 0;      /* we've already been exec'd */
+
+#ifdef TOP_PACKAGE
+static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")";
+#else /* TOP_PACKAGE */
+static char version[] = "@(#) racoon / IPsec-tools";
+#endif /* TOP_PACKAGE */
+
+int main __P((int, char **));
+static void usage __P((void));
+static void parse __P((int, char **));
+static void restore_params __P((void));
+static void save_params __P((void));
+static void saverestore_params __P((int));
+static void cleanup_pidfile __P((void));
+
+pid_t racoon_pid = 0;
+int print_pid = 1;     /* for racoon only */
+
+void
+usage()
+{
+       printf("usage: racoon [-BdFve%s] %s[-f (file)] [-l (file)] [-p (port)]\n",
+#ifdef INET6
+               "46",
+#else
+               "",
+#endif
+#ifdef ENABLE_ADMINPORT
+               "[-a (port)] "
+#else
+               ""
+#endif
+               );
+       printf("   -B: install SA to the kernel from the file "
+               "specified by the configuration file.\n");
+       printf("   -d: debug level, more -d will generate more debug message.\n");
+       printf("   -C: dump parsed config file.\n");
+       printf("   -L: include location in debug messages\n");
+       printf("   -F: run in foreground, do not become daemon.\n");
+       printf("   -v: be more verbose\n");
+       printf("   -e: enable auto exit\n");
+#ifdef INET6
+       printf("   -4: IPv4 mode.\n");
+       printf("   -6: IPv6 mode.\n");
+#endif
+#ifdef ENABLE_ADMINPORT
+       printf("   -a: port number for admin port.\n");
+#endif
+       printf("   -f: pathname for configuration file.\n");
+       printf("   -l: pathname for log file.\n");
+       printf("   -p: port number for isakmp (default: %d).\n", PORT_ISAKMP);
+       printf("   -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT);
+       exit(1);
+}
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       int error;
+
+       if (geteuid() != 0) {
+               errx(1, "must be root to invoke this program.");
+               /* NOTREACHED*/
+       }
+
+       /*
+        * Don't let anyone read files I write.  Although some files (such as
+        * the PID file) can be other readable, we dare to use the global mask,
+        * because racoon uses fopen(3), which can't specify the permission
+        * at the creation time.
+        */
+       umask(077);
+       if (umask(077) != 077) {
+               errx(1, "could not set umask");
+               /* NOTREACHED*/
+       }
+
+#ifdef DEBUG_RECORD_MALLOCATION
+       DRM_init();
+#endif
+
+       eay_init();
+       initlcconf();
+       initrmconf();
+       oakley_dhinit();
+       compute_vendorids();
+
+       parse(ac, av);
+       if (lcconf->logfile_param)
+               plogset(lcconf->logfile_param);
+       ploginit();
+
+       plog(LLV_INFO, LOCATION, NULL, "***** racoon started: pid=%d  started by: %d\n", getpid(), getppid());
+       plog(LLV_INFO, LOCATION, NULL, "%s\n", version);
+       plog(LLV_INFO, LOCATION, NULL, "@(#)"
+           "This product linked %s (http://www.openssl.org/)"
+           "\n", eay_version());
+
+       if (pfkey_init() < 0) {
+               errx(1, "something error happened "
+                       "while pfkey initializing.");
+               /* NOTREACHED*/
+       }
+
+       /*
+        * in order to prefer the parameters by command line,
+        * saving some parameters before parsing configuration file.
+        */
+       save_params();
+       error = cfparse();
+       if (error != 0)
+               errx(1, "failed to parse configuration file.");
+       restore_params();
+       if (lcconf->logfile_param == NULL)
+               plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
+               
+#ifdef ENABLE_NATT
+       /* Tell the kernel which port to use for UDP encapsulation */
+       {
+               int udp_port = PORT_ISAKMP_NATT;
+               if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &udp_port, sizeof(udp_port)) != 0)
+                       errx(1, "couldn't set net.inet.ipsec.esp_port to %d. (%s)",
+                               udp_port, strerror(errno));
+       }
+#endif
+
+#ifdef HAVE_LIBRADIUS
+       if (xauth_radius_init() != 0) {
+               errx(1, "could not initialize libradius");
+               /* NOTREACHED*/
+       }
+#endif
+
+       if (dump_config)
+               dumprmconf ();
+
+       /*
+        * install SAs from the specified file.  If the file is not specified
+        * by the configuration file, racoon will exit.
+        */
+       if (loading_sa && !f_local) {
+               if (backupsa_from_file() != 0)
+                       errx(1, "something error happened "
+                               "SA recovering.");
+       }
+
+       if (f_foreground)
+               close(0);
+       else if (exec_done) {
+               if (atexit(cleanup_pidfile) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "cannot register pidfile cleanup");
+               }
+       } else {
+               #define MAX_EXEC_ARGS 32
+               
+               char *args[MAX_EXEC_ARGS + 1];
+               char *env[1] = {0};     
+               int     i;
+               
+               if (ac > MAX_EXEC_ARGS) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "too many arguments.\n");
+                       exit(1);
+               }
+               
+               if (daemon(0, 0) < 0) {
+                       errx(1, "failed to be daemon. (%s)",
+                               strerror(errno));
+               }
+               
+               /* Radar 5129006 - Prevent non-root user from killing racoon
+                * when launched by setuid process
+                */
+               if (setuid(0)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "cannot set uid.\n");
+                       exit(1);
+               }
+               if (setgid(0)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "cannot set gid.\n");
+                       exit(1);
+               }
+               
+               /* setup args to re-exec - for CoreFoundation issues */
+               args[0] = PATHRACOON;   
+               for (i = 1; i < ac; i++)
+                       args[i] = *(av + i);
+               args[ac] = "-x";                /* tells racoon its been exec'd */
+               args[ac+1] = 0;
+               
+               execve(PATHRACOON, args, env);
+               plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to exec racoon. (%s)", strerror(errno));
+               exit(1);
+       }
+
+       session();
+       
+       exit(0);
+}
+
+
+static void
+cleanup_pidfile()
+{
+       char pid_file[MAXPATHLEN];
+       pid_t p = getpid();
+
+       /* if it's not child process, clean everything */
+       if (racoon_pid == p) {
+               if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 
+                       strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
+               else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 
+                       strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
+               else {
+                       strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
+                       strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
+               }
+               (void) unlink(pid_file);
+       }
+}
+
+
+static void
+parse(ac, av)
+       int ac;
+       char **av;
+{
+       extern char *optarg;
+       extern int optind;
+       int c;
+#ifdef YYDEBUG
+       extern int yydebug;
+#endif
+
+       pname = strrchr(*av, '/');
+       if (pname)
+               pname++;
+       else
+               pname = *av;
+
+#if 0  /* for debugging */
+       loglevel += 2;
+       plogset("/tmp/racoon.log");
+#endif
+
+       while ((c = getopt(ac, av, "dLFp:P:a:f:l:veZBCx"
+#ifdef YYDEBUG
+                       "y"
+#endif
+#ifdef INET6
+                       "46"
+#endif
+                       )) != -1) {
+               switch (c) {
+               case 'd':
+                       loglevel++;
+                       break;
+               case 'L':
+                       print_location = 1;
+                       break;
+               case 'F':
+                       printf("Foreground mode.\n");
+                       f_foreground = 1;
+                       break;
+               case 'p':
+                       lcconf->port_isakmp = atoi(optarg);
+                       break;
+               case 'P':
+                       lcconf->port_isakmp_natt = atoi(optarg);
+                       break;
+               case 'a':
+#ifdef ENABLE_ADMINPORT
+                       lcconf->port_admin = atoi(optarg);
+                       break;
+#else
+                       fprintf(stderr, "%s: the option is disabled "
+                           "in the configuration\n", pname);
+                       exit(1);
+#endif
+               case 'f':
+                       lcconf->racoon_conf = optarg;
+                       break;
+               case 'l':
+                       lcconf->logfile_param = optarg;
+                       break;
+               case 'v':
+                       vflag++;
+                       break;
+               case 'e':
+                       lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT;
+                       break;
+               case 'x':
+                       exec_done = 1;
+                       break;
+               case 'Z':
+                       /*
+                        * only local test.
+                        * To specify -Z option and to choice a appropriate
+                        * port number for ISAKMP, you can launch some racoons
+                        * on the local host for debug.
+                        * pk_sendadd() on initiator side is always failed
+                        * even if this flag is used.  Because there is same
+                        * spi in the SAD which is inserted by pk_sendgetspi()
+                        * on responder side.
+                        */
+                       printf("Local test mode.\n");
+                       f_local = 1;
+                       break;
+#ifdef YYDEBUG
+               case 'y':
+                       yydebug = 1;
+                       break;
+#endif
+#ifdef INET6
+               case '4':
+                       lcconf->default_af = AF_INET;
+                       break;
+               case '6':
+                       lcconf->default_af = AF_INET6;
+                       break;
+#endif
+               case 'B':
+                       loading_sa++;
+                       break;
+               case 'C':
+                       dump_config++;
+                       break;
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       }
+       ac -= optind;
+       av += optind;
+
+       if (ac != 0) {
+               usage();
+               /* NOTREACHED */
+       }
+
+       return;
+}
+
+static void
+restore_params()
+{
+       saverestore_params(1);
+}
+
+static void
+save_params()
+{
+       saverestore_params(0);
+}
+
+static void
+saverestore_params(f)
+       int f;
+{
+       static u_int16_t s_port_isakmp;
+#ifdef ENABLE_ADMINPORT
+       static u_int16_t s_port_admin;
+#endif
+
+       /* 0: save, 1: restore */
+       if (f) {
+               lcconf->port_isakmp = s_port_isakmp;
+#ifdef ENABLE_ADMINPORT
+               lcconf->port_admin = s_port_admin;
+#endif
+       } else {
+               s_port_isakmp = lcconf->port_isakmp;
+#ifdef ENABLE_ADMINPORT
+               s_port_admin = lcconf->port_admin;
+#endif
+       }
+}
diff --git a/ipsec-tools/racoon/misc.c b/ipsec-tools/racoon/misc.c
new file mode 100644 (file)
index 0000000..07e5390
--- /dev/null
@@ -0,0 +1,169 @@
+/*     $KAME: misc.c,v 1.23 2001/08/16 14:37:29 itojun Exp $   */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "debug.h"
+
+#if 0
+static int bindump __P((void *, size_t));
+
+static int
+bindump(buf0, len)
+        void *buf0;
+        size_t len;
+{
+       unsigned char *buf = (unsigned char *)buf0;
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               if ((buf[i] & 0x80) || !isprint(buf[i]))
+                       printf("\\x%x", buf[i]);
+               else
+                       printf("%c", buf[i]);
+       }
+       printf("\n");
+
+       return 0;
+}
+#endif
+
+int
+hexdump(buf0, len)
+       void *buf0;
+       size_t len;
+{
+       caddr_t buf = (caddr_t)buf0;
+       size_t 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]);
+       }
+       printf("\n");
+
+       return 0;
+}
+
+char *
+bit2str(n, bl)
+       int n, bl;
+{
+#define MAXBITLEN 128
+       static char b[MAXBITLEN + 1];
+       int i;
+
+       if (bl > MAXBITLEN)
+               return "Failed to convert.";    /* NG */
+       memset(b, '0', bl);
+       b[bl] = '\0';
+
+       for (i = 0; i < bl; i++) {
+               if (n & (1 << i))
+                       b[bl - 1 - i] = '1';
+       }
+
+       return b;
+}
+
+const char *
+debug_location(file, line, func)
+       const char *file;
+       int line;
+       const char *func;
+{
+       static char buf[1024];
+       const char *p;
+
+       /* truncate pathname */
+       p = strrchr(file, '/');
+       if (p)
+               p++;
+       else
+               p = file;
+
+       if (func)
+               snprintf(buf, sizeof(buf), "%s:%d:%s()", p, line, func);
+       else
+               snprintf(buf, sizeof(buf), "%s:%d", p, line);
+
+       return buf;
+}
+
+/*
+ * get file size.
+ * -1: error occured.
+ */
+int
+getfsize(path)
+       char *path;
+{
+        struct stat st;
+
+        if (stat(path, &st) != 0)
+                return -1;
+        else
+                return st.st_size;
+}
+
+/*
+ * calculate the difference between two times.
+ * t1: start
+ * t2: end
+ */
+double
+timedelta(t1, t2)
+       struct timeval *t1, *t2;
+{
+       if (t2->tv_usec >= t1->tv_usec)
+               return t2->tv_sec - t1->tv_sec +
+                       (double)(t2->tv_usec - t1->tv_usec) / 1000000;
+
+       return t2->tv_sec - t1->tv_sec - 1 +
+               (double)(1000000 + t2->tv_usec - t1->tv_usec) / 1000000;
+}
diff --git a/ipsec-tools/racoon/misc.h b/ipsec-tools/racoon/misc.h
new file mode 100644 (file)
index 0000000..8f90cc9
--- /dev/null
@@ -0,0 +1,61 @@
+/* $Id: misc.h,v 1.6.10.1 2005/11/06 17:18:26 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#define BIT2STR(b) bit2str(b, sizeof(b)<<3)
+
+#ifdef HAVE_FUNC_MACRO
+#define LOCATION        debug_location(__FILE__, __LINE__, __func__)
+#else
+#define LOCATION        debug_location(__FILE__, __LINE__, NULL)
+#endif
+
+extern int hexdump __P((void *, size_t));
+extern char *bit2str __P((int, int));
+extern void *get_newbuf __P((void *, size_t));
+extern const char *debug_location __P((const char *, int, const char *));
+extern int getfsize __P((char *));
+struct timeval;
+extern double timedelta __P((struct timeval *, struct timeval *));
+
+#ifndef HAVE_STRLCPY
+#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
+#endif
+
+#ifndef HAVE_STRLCAT
+#define strlcat(d,s,l) strncat(d,s,(l)-strlen(d)-1)
+#endif
+
+#include "libpfkey.h"
+
+#endif /* _MISC_H */
diff --git a/ipsec-tools/racoon/nattraversal.c b/ipsec-tools/racoon/nattraversal.c
new file mode 100644 (file)
index 0000000..a9c02b1
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef __linux__
+#include <linux/udp.h>
+#endif
+#if defined(__NetBSD__) || defined (__FreeBSD__)
+#include <netinet/udp.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "remoteconf.h"
+#include "sockmisc.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "ipsec_doi.h"
+#include "vendorid.h"
+#include "handler.h"
+#include "crypto_openssl.h"
+#include "schedule.h"
+#include "nattraversal.h"
+#include "grabmyaddr.h"
+
+struct natt_ka_addrs {
+  struct sockaddr      *src;
+  struct sockaddr      *dst;
+  unsigned             in_use;
+
+  TAILQ_ENTRY(natt_ka_addrs) chain;
+};
+
+static TAILQ_HEAD(_natt_ka_addrs, natt_ka_addrs) ka_tree;
+
+/*
+ * check if the given vid is NAT-T.
+ */
+int
+natt_vendorid (int vid)
+{
+  return (
+#ifdef ENABLE_NATT_00
+         vid == VENDORID_NATT_00 ||
+#endif
+#ifdef ENABLE_NATT_01
+         vid == VENDORID_NATT_01 ||
+#endif
+#ifdef ENABLE_NATT_02
+         vid == VENDORID_NATT_02 ||
+         vid == VENDORID_NATT_02_N ||
+#endif
+#ifdef ENABLE_NATT_03
+         vid == VENDORID_NATT_03 ||
+#endif
+#ifdef ENABLE_NATT_04
+         vid == VENDORID_NATT_04 ||
+#endif
+#ifdef ENABLE_NATT_05
+         vid == VENDORID_NATT_05 ||
+#endif
+#ifdef ENABLE_NATT_06
+         vid == VENDORID_NATT_06 ||
+#endif
+#ifdef ENABLE_NATT_07
+         vid == VENDORID_NATT_07 ||
+#endif
+#ifdef ENABLE_NATT_08
+         vid == VENDORID_NATT_08 ||
+#endif
+#ifdef ENABLE_NATT_APPLE
+         vid == VENDORID_NATT_APPLE ||
+#endif
+         /* Always enable NATT RFC if ENABLE_NATT
+          */
+         vid == VENDORID_NATT_RFC);
+}
+
+vchar_t *
+natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr)
+{
+  vchar_t *natd;
+  vchar_t *buf;
+  char *ptr;
+  void *addr_ptr, *addr_port;
+  size_t buf_size, addr_size;
+
+  plog (LLV_INFO, LOCATION, addr, "Hashing %s with algo #%d %s\n",
+       saddr2str(addr), iph1->approval->hashtype, 
+       (iph1->rmconf->nat_traversal == NATT_FORCE)?"(NAT-T forced)":"");
+  
+  if (addr->sa_family == AF_INET) {
+    addr_size = sizeof (struct in_addr);       /* IPv4 address */
+    addr_ptr = &((struct sockaddr_in *)addr)->sin_addr;
+    addr_port = &((struct sockaddr_in *)addr)->sin_port;
+  }
+  else if (addr->sa_family == AF_INET6) {
+    addr_size = sizeof (struct in6_addr);      /* IPv6 address */
+    addr_ptr = &((struct sockaddr_in6 *)addr)->sin6_addr;
+    addr_port = &((struct sockaddr_in6 *)addr)->sin6_port;
+  }
+  else {
+    plog (LLV_ERROR, LOCATION, addr, "Unsupported address family #0x%x\n", addr->sa_family);
+    return NULL;
+  }
+
+  buf_size = 2 * sizeof (cookie_t);    /* CKY-I + CKY+R */
+  buf_size += addr_size + 2;   /* Address + Port */
+  
+  if ((buf = vmalloc (buf_size)) == NULL)
+    return NULL;
+
+  ptr = buf->v;
+  
+  /* Copy-in CKY-I */
+  memcpy (ptr, iph1->index.i_ck, sizeof (cookie_t));
+  ptr += sizeof (cookie_t);
+  
+  /* Copy-in CKY-I */
+  memcpy (ptr, iph1->index.r_ck, sizeof (cookie_t));
+  ptr += sizeof (cookie_t);
+  
+  /* Copy-in Address (or zeroes if NATT_FORCE) */
+  if (iph1->rmconf->nat_traversal == NATT_FORCE)
+    memset (ptr, 0, addr_size);
+  else
+    memcpy (ptr, addr_ptr, addr_size);
+  ptr += addr_size;
+
+  /* Copy-in Port number */
+  memcpy (ptr, addr_port, 2);
+
+  natd = oakley_hash (buf, iph1);
+  vfree(buf);
+
+  return natd;
+}
+
+int 
+natt_compare_addr_hash (struct ph1handle *iph1, vchar_t *natd_received,
+                       int natd_seq)
+{
+  vchar_t *natd_computed;
+  u_int32_t flag;
+  int verified = 0;
+
+  if (iph1->rmconf->nat_traversal == NATT_FORCE)
+    return verified;
+
+#ifdef __APPLE__
+       /* old APPLE version sends natd payload in the wrong order */
+  if (iph1->natt_options->version == VENDORID_NATT_APPLE) {
+         if (natd_seq == 0) {
+               natd_computed = natt_hash_addr (iph1, iph1->remote);
+               flag = NAT_DETECTED_PEER;
+         }
+         else {
+               natd_computed = natt_hash_addr (iph1, iph1->local);
+               flag = NAT_DETECTED_ME;
+         }
+       } else
+#endif
+       {
+               if (natd_seq == 0) {
+                       natd_computed = natt_hash_addr (iph1, iph1->local);
+                       flag = NAT_DETECTED_ME;
+               }
+               else {
+                       natd_computed = natt_hash_addr (iph1, iph1->remote);
+                       flag = NAT_DETECTED_PEER;
+               }
+       }
+
+  if (natd_received->l == natd_computed->l &&
+      memcmp (natd_received->v, natd_computed->v, natd_received->l) == 0) {
+    iph1->natt_flags &= ~flag;
+    verified = 1;
+  }
+
+  vfree (natd_computed);
+
+  return verified;
+}
+
+int
+natt_udp_encap (int encmode)
+{
+  return (encmode == IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC || 
+         encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC ||
+         encmode == IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT ||
+         encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT);
+}
+
+int
+natt_fill_options (struct ph1natt_options *opts, int version)
+{
+  if (! opts)
+    return -1;
+
+  opts->version = version;
+
+  switch (version) {
+#ifndef __APPLE__
+    case VENDORID_NATT_00:
+    case VENDORID_NATT_01:
+      opts->float_port = 0; /* No port floating for those drafts */
+      opts->payload_nat_d = ISAKMP_NPTYPE_NATD_DRAFT;
+      opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_DRAFT;
+      opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT;
+      opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT;
+      opts->encaps_type = UDP_ENCAP_ESPINUDP_NON_IKE;
+               break;
+#endif
+
+    case VENDORID_NATT_02:
+    case VENDORID_NATT_02_N:
+    case VENDORID_NATT_03:
+      opts->float_port = lcconf->port_isakmp_natt;
+      opts->payload_nat_d = ISAKMP_NPTYPE_NATD_DRAFT;
+      opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_DRAFT;
+      opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT;
+      opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT;
+      opts->encaps_type = UDP_ENCAP_ESPINUDP;
+      break;
+    case VENDORID_NATT_04:
+    case VENDORID_NATT_05:
+    case VENDORID_NATT_06:
+    case VENDORID_NATT_07:
+    case VENDORID_NATT_08:
+#ifdef __APPLE__
+       case VENDORID_NATT_APPLE:
+      opts->float_port = lcconf->port_isakmp_natt;
+      opts->payload_nat_d = ISAKMP_NPTYPE_NATD_BADDRAFT;
+      opts->payload_nat_oa = ISAKMP_NPTYPE_NONE;
+      opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC;
+      opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC;
+      opts->encaps_type = UDP_ENCAP_ESPINUDP;
+      break;
+#endif
+    case VENDORID_NATT_RFC:
+      opts->float_port = lcconf->port_isakmp_natt;
+      opts->payload_nat_d = ISAKMP_NPTYPE_NATD_RFC;
+      opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_RFC;
+      opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC;
+      opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC;
+      opts->encaps_type = UDP_ENCAP_ESPINUDP;
+         break;
+    default:
+      plog(LLV_ERROR, LOCATION, NULL, 
+          "unsupported NAT-T version: %s\n",
+          vid_string_by_id(version));
+      return -1;
+  }
+  opts->mode_udp_diff = opts->mode_udp_tunnel - IPSECDOI_ATTR_ENC_MODE_TUNNEL;
+
+  return 0;
+}
+
+#ifdef NOT_NOW
+static int
+create_natoa_payloads(struct ph2handle *iph2, vchar_t **natoa_i, vchar_t **natoa_r)
+{
+       int natoa_type = 0;
+       int natt_type;
+       vchar_t         *i;
+       vchar_t         *r;
+       u_int8_t        *p;
+       size_t          src_size;
+       size_t          dst_size;
+       
+       *natoa_i = *natoa_r = NULL;
+       
+
+       /* create natoa payloads if natt being used */
+       /* don't send if type == apple                          */
+       if ((natt_type = natd_hasnat(iph2->ph1)) != 0)
+               if (natt_type == natt_type_rfc)
+                       natoa_type = ISAKMP_NPTYPE_NATOA_RFC;
+               else if (natt_type == natt_type_02 || natt_type == natt_type_02N)
+                       natoa_type = ISAKMP_NPTYPE_NATOA_DRAFT;
+       
+       if (natoa_type == 0)
+               return 0;
+               
+       switch (iph2->src->sa_family) {
+               case AF_INET:
+                       src_size = sizeof(in_addr_t);
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       src_size = sizeof(struct in6_addr);
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid address family: %d\n", iph2->src->sa_family);
+                       return -1;              
+       }
+               
+       switch (iph2->dst->sa_family) {
+               case AF_INET:
+                       dst_size = sizeof(in_addr_t);
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       dst_size = sizeof(struct in6_addr);
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid address family: %d\n", iph2->dst->sa_family);
+                       return -1;              
+       }
+
+       i = vmalloc(sizeof(struct isakmp_pl_natoa) + src_size - sizeof(struct isakmp_gen));     
+       r = vmalloc(sizeof(struct isakmp_pl_natoa) + dst_size - sizeof(struct isakmp_gen));
+       if (i == NULL || r == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer for natoa payload.\n");
+               return -1;
+       }
+       
+       /* copy src address */
+       p = i->v;
+       
+       switch (iph2->src->sa_family) {
+               case AF_INET:
+                       *p = IPSECDOI_ID_IPV4_ADDR;
+                       bcopy(&(((struct sockaddr_in *)iph2->src)->sin_addr.s_addr), p + sizeof(u_int32_t), src_size);
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       *p = IPSECDOI_ID_IPV6_ADDR;
+                       bcopy(&(((struct sockaddr_in6 *)iph2->src)->sin6_addr), p + sizeof(u_int32_t), src_size);
+                       break;
+#endif
+       }
+
+       /* copy dst address */
+       p = r->v;
+       
+       switch (iph2->dst->sa_family) {
+               case AF_INET:
+                       *p = IPSECDOI_ID_IPV4_ADDR;
+                       bcopy(&(((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr), p + sizeof(u_int32_t), dst_size);
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       *p = IPSECDOI_ID_IPV6_ADDR;
+                       bcopy(&(((struct sockaddr_in6 *)iph2->dst)->sin6_addr), p + sizeof(u_int32_t), dst_size);
+                       break;
+#endif
+       }
+       
+       *natoa_i = i;
+       *natoa_r = r;
+       return natoa_type;
+}      
+#endif 
+       
+
+void
+natt_float_ports (struct ph1handle *iph1)
+{
+       
+       if (! (iph1->natt_flags && NAT_DETECTED) )
+               return;
+       if (! iph1->natt_options->float_port){
+               /* Drafts 00 / 01, just schedule keepalive */
+#ifndef __APPLE__
+               natt_keepalive_add_ph1 (iph1);
+#endif
+               return;
+       }
+       
+       /*
+        * Only switch ports if port == isakmp port.
+        * In the case where ports are set from policy or from
+        * remote config we could be talking to a device behind
+        * a nat using the translated port.
+        */
+       if (*get_port_ptr(iph1->local) == htons(lcconf->port_isakmp))
+               set_port (iph1->local, iph1->natt_options->float_port);
+       if (*get_port_ptr(iph1->remote) == htons(lcconf->port_isakmp))
+               set_port (iph1->remote, iph1->natt_options->float_port);
+       iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER;
+
+       
+#ifndef __APPLE__
+       natt_keepalive_add_ph1 (iph1);
+#endif
+}
+
+void
+natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric)
+{
+  if (! iph1->natt_options)
+    iph1->natt_options = racoon_calloc (1, sizeof (*iph1->natt_options));
+
+  if (! iph1->natt_options) {
+    plog (LLV_ERROR, LOCATION, NULL,
+         "Allocating memory for natt_options failed!\n");
+    return;
+  }
+  
+  if (iph1->natt_options->version < vid_numeric)
+    if (natt_fill_options (iph1->natt_options, vid_numeric) == 0)
+      iph1->natt_flags |= NAT_ANNOUNCED;
+}
+
+#ifndef __APPLE__
+/* NAT keepalive functions */
+static void
+natt_keepalive_send (void *param)
+{
+  struct natt_ka_addrs *ka, *next = NULL;
+  char keepalive_packet[] = { 0xff };
+  size_t len;
+  int s;
+
+  for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) {
+    next = TAILQ_NEXT(ka, chain);
+    
+    s = getsockmyaddr(ka->src);
+    if (s == -1) {
+      TAILQ_REMOVE (&ka_tree, ka, chain);
+      racoon_free (ka);
+      continue;
+    }
+    plog (LLV_DEBUG, LOCATION, NULL, "KA: %s\n", 
+         saddr2str_fromto("%s->%s", ka->src, ka->dst));
+    len = sendfromto(s, keepalive_packet, sizeof (keepalive_packet),
+                    ka->src, ka->dst, 1);
+    if (len == -1)
+      plog(LLV_ERROR, LOCATION, NULL, "KA: sendfromto failed: %s\n",
+          strerror (errno));
+  }
+  
+  sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL);
+}
+
+void
+natt_keepalive_init (void)
+{
+  TAILQ_INIT(&ka_tree);
+
+  /* To disable sending KAs set natt_ka_interval=0 */
+  if (lcconf->natt_ka_interval > 0)
+    sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL);
+}
+
+int
+natt_keepalive_add (struct sockaddr *src, struct sockaddr *dst)
+{
+  struct natt_ka_addrs *ka = NULL, *new_addr;
+  
+  TAILQ_FOREACH (ka, &ka_tree, chain) {
+    if (cmpsaddrstrict(ka->src, src) == 0 && 
+       cmpsaddrstrict(ka->dst, dst) == 0) {
+      ka->in_use++;
+      plog (LLV_INFO, LOCATION, NULL, "KA found: %s (in_use=%u)\n",
+           saddr2str_fromto("%s->%s", src, dst), ka->in_use);
+      return 0;
+    }
+  }
+
+  plog (LLV_INFO, LOCATION, NULL, "KA list add: %s\n", saddr2str_fromto("%s->%s", src, dst));
+
+  new_addr = (struct natt_ka_addrs *)racoon_malloc(sizeof(*new_addr));
+  if (! new_addr) {
+    plog (LLV_ERROR, LOCATION, NULL, "Can't allocate new KA list item\n");
+    return -1;
+  }
+
+  new_addr->src = dupsaddr(src);
+  new_addr->dst = dupsaddr(dst);
+  new_addr->in_use = 1;
+  TAILQ_INSERT_TAIL(&ka_tree, new_addr, chain);
+
+  return 0;
+}
+
+int
+natt_keepalive_add_ph1 (struct ph1handle *iph1)
+{
+  int ret = 0;
+  
+  /* Should only the NATed host send keepalives?
+     If yes, add '(iph1->natt_flags & NAT_DETECTED_ME)'
+     to the following condition. */
+  if (iph1->natt_flags & NAT_DETECTED &&
+      ! (iph1->natt_flags & NAT_KA_QUEUED)) {
+    ret = natt_keepalive_add (iph1->local, iph1->remote);
+    if (ret == 0)
+      iph1->natt_flags |= NAT_KA_QUEUED;
+  }
+
+  return ret;
+}
+
+void
+natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst)
+{
+  struct natt_ka_addrs *ka, *next = NULL;
+
+  plog (LLV_INFO, LOCATION, NULL, "KA remove: %s\n", saddr2str_fromto("%s->%s", src, dst));
+
+  for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) {
+    next = TAILQ_NEXT(ka, chain);
+    plog (LLV_DEBUG, LOCATION, NULL, "KA tree dump: %s (in_use=%u)\n",
+         saddr2str_fromto("%s->%s", src, dst), ka->in_use);
+
+    if (cmpsaddrstrict(ka->src, src) == 0 && 
+       cmpsaddrstrict(ka->dst, dst) == 0 &&
+       -- ka->in_use <= 0) {
+
+      plog (LLV_DEBUG, LOCATION, NULL, "KA removing this one...\n");
+
+      TAILQ_REMOVE (&ka_tree, ka, chain);
+      racoon_free (ka);
+      /* Should we break here? Every pair of addresses should 
+         be inserted only once, but who knows :-) Lets traverse 
+        the whole list... */
+    }
+  }
+}
+#endif /* __APPLE__ */
+
+static struct remoteconf *
+natt_enabled_in_rmconf_stub (struct remoteconf *rmconf, void *data)
+{
+  return (rmconf->nat_traversal ? rmconf : NULL);
+}
+
+int
+natt_enabled_in_rmconf ()
+{
+  return foreachrmconf (natt_enabled_in_rmconf_stub, NULL) != NULL;
+}
+
+
+struct payload_list *
+isakmp_plist_append_natt_vids (struct payload_list *plist, vchar_t *vid_natt[MAX_NATT_VID_COUNT]){
+       int i, vid_natt_i = 0;
+
+       if(vid_natt == NULL)
+               return NULL;
+
+       for (i = 0; i < MAX_NATT_VID_COUNT; i++)
+               vid_natt[i]=NULL;
+       
+       /* Puts the olders VIDs last, as some implementations may choose the first
+        * NATT VID given
+        */
+
+       /* Always set RFC VID
+        */
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_RFC)) != NULL)
+               vid_natt_i++;
+#ifdef ENABLE_NATT_APPLE
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_APPLE)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_08
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_08)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_07
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_07)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_06
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_06)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_05
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_05)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_04
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_04)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_03
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_03)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_02
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02)) != NULL)
+               vid_natt_i++;
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02_N)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_01
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_01)) != NULL)
+               vid_natt_i++;
+#endif
+#ifdef ENABLE_NATT_00
+       if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_00)) != NULL)
+               vid_natt_i++;
+#endif
+       /* set VID payload for NAT-T */
+       for (i = 0; i < vid_natt_i; i++)
+               plist = isakmp_plist_append(plist, vid_natt[i], ISAKMP_NPTYPE_VID);
+       
+       return plist;
+}
diff --git a/ipsec-tools/racoon/nattraversal.h b/ipsec-tools/racoon/nattraversal.h
new file mode 100644 (file)
index 0000000..f03c76c
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+#ifndef _NATTRAVERSAL_H
+#define _NATTRAVERSAL_H
+
+#include "vendorid.h"
+
+#ifdef __APPLE__
+#define UDP_ENCAP_ESPINUDP     2       /* to make it compile - we don't use this */
+#endif
+
+#define        NAT_ANNOUNCED           (1L<<0)
+#define        NAT_DETECTED_ME         (1L<<1)
+#define        NAT_DETECTED_PEER       (1L<<2)
+#define        NAT_PORTS_CHANGED       (1L<<3)
+#define        NAT_KA_QUEUED           (1L<<4)
+#define        NAT_ADD_NON_ESP_MARKER  (1L<<5)
+
+#define        NATT_AVAILABLE(ph1)     ((iph1)->natt_flags & NAT_ANNOUNCED)
+
+#define        NAT_DETECTED    (NAT_DETECTED_ME | NAT_DETECTED_PEER)
+
+#define        NON_ESP_MARKER_LEN      sizeof(u_int32_t)
+#define        NON_ESP_MARKER_USE(iph1)        ((iph1)->natt_flags & NAT_ADD_NON_ESP_MARKER)
+
+/* These are the values from parsing "remote {}" 
+   block of the config file. */
+#define NATT_OFF       FALSE   /* = 0 */
+#define NATT_ON                TRUE    /* = 1 */
+#define NATT_FORCE     2
+
+struct ph1natt_options {
+  int          version;
+  u_int16_t    float_port;
+  u_int16_t    mode_udp_tunnel;
+  u_int16_t    mode_udp_transport;
+  u_int16_t    encaps_type; /* ESPINUDP / ESPINUDP_NON_IKE */
+  u_int16_t    mode_udp_diff;
+  u_int16_t    payload_nat_d;
+  u_int16_t    payload_nat_oa;
+};
+
+struct ph2natt {
+  u_int8_t     type;
+  u_int16_t    sport;
+  u_int16_t    dport;
+  struct sockaddr      *oa;
+  u_int16_t    frag;
+};
+
+int natt_vendorid (int vid);
+vchar_t *natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr);
+int natt_compare_addr_hash (struct ph1handle *iph1, vchar_t *natd_received, int natd_seq);
+int natt_udp_encap (int encmode);
+int natt_fill_options (struct ph1natt_options *opts, int version);
+void natt_float_ports (struct ph1handle *iph1);
+void natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric);
+#ifdef NOT_NOW
+int create_natoa_payloads(struct ph2handle *iph2, vchar_t **, vchar_t **);
+#endif
+
+struct payload_list *
+isakmp_plist_append_natt_vids (struct payload_list *plist, vchar_t *vid_natt[MAX_NATT_VID_COUNT]);
+
+#ifndef __APPLE__
+/* NAT keepalive functions */
+void natt_keepalive_init (void);
+int natt_keepalive_add (struct sockaddr *src, struct sockaddr *dst);
+int natt_keepalive_add_ph1 (struct ph1handle *iph1);
+void natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst);
+#endif
+
+/* Walk through all rmconfigs and tell if NAT-T is enabled in at least one. */
+int natt_enabled_in_rmconf (void);
+
+#endif /* _NATTRAVERSAL_H */
diff --git a/ipsec-tools/racoon/netdb_dnssec.h b/ipsec-tools/racoon/netdb_dnssec.h
new file mode 100644 (file)
index 0000000..b83273d
--- /dev/null
@@ -0,0 +1,72 @@
+/* $Id: netdb_dnssec.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NETDB_DNSSEC_H
+#define _NETDB_DNSSEC_H
+
+#ifndef T_CERT
+#define T_CERT 37              /* defined by RFC2538 section 2 */
+#endif
+
+/* RFC2538 section 2.1 */
+#define DNSSEC_TYPE_PKIX       1
+#define DNSSEC_TYPE_SPKI       2
+#define DNSSEC_TYPE_PGP                3
+#define DNSSEC_TYPE_URI                4
+#define DNSSEC_TYPE_OID                5
+
+/* RFC2535 section 3.2 */
+#define DNSSEC_ALG_RSAMD5      1
+#define DNSSEC_ALG_DH          2
+#define DNSSEC_ALG_DSA         3
+#define DNSSEC_ALG_ECC         4
+#define DNSSEC_ALG_PRIVATEDNS  5
+#define DNSSEC_ALG_PRIVATEOID  6
+
+/*
+ * Structures returned by network data base library.  All addresses are
+ * supplied in host order, and returned in network order (suitable for
+ * use in system calls).
+ */
+struct certinfo {
+       int ci_type;                    /* certificate type */
+       int ci_keytag;                  /* keytag */
+       int ci_algorithm;               /* algorithm */
+       int ci_flags;                   /* currently, 1:valid or 0:uncertain */
+       size_t ci_certlen;              /* length of certificate */
+       char *ci_cert;                  /* certificate */
+       struct certinfo *ci_next;       /* next structure */
+};
+
+extern void freecertinfo __P((struct certinfo *));
+extern int getcertsbyname __P((char *, struct certinfo **));
+
+#endif /* _NETDB_DNSSEC_H */
diff --git a/ipsec-tools/racoon/oakley.c b/ipsec-tools/racoon/oakley.c
new file mode 100644 (file)
index 0000000..1d52885
--- /dev/null
@@ -0,0 +1,3626 @@
+/* $Id: oakley.c,v 1.17.2.5 2005/10/04 09:54:27 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>        /* XXX for subjectaltname */
+#include <netinet/in.h>        /* XXX for subjectaltname */
+
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "str2val.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h" 
+#endif                
+#include "oakley.h"
+#include "admin.h"
+#include "privsep.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "policy.h"
+#include "handler.h"
+#include "ipsec_doi.h"
+#include "algorithm.h"
+#include "dhgroup.h"
+#include "sainfo.h"
+#include "proposal.h"
+#include "crypto_openssl.h"
+#ifdef __APPLE__
+#include "crypto_cssm.h"
+#include "open_dir.h"
+#endif
+#include "dnssec.h"
+#include "sockmisc.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+#include "rsalist.h"
+#ifdef __APPLE__
+#include <CoreFoundation/CFData.h>
+#endif
+
+
+#ifdef HAVE_GSSAPI
+#include "gssapi.h"
+#endif
+
+#define OUTBOUND_SA    0
+#define INBOUND_SA     1
+
+#ifdef __APPLE__
+#define CERT_CHECKID_FROM_PEER                 0
+#define CERT_CHECKID_FROM_RMCONFIG     1
+#endif
+
+#define INITDHVAL(a, s, d, t)                                                  \
+do {                                                                           \
+       vchar_t buf;                                                           \
+       buf.v = str2val((s), 16, &buf.l);                                      \
+       memset(&a, 0, sizeof(struct dhgroup));                                 \
+       a.type = (t);                                                          \
+       a.prime = vdup(&buf);                                                  \
+       a.gen1 = 2;                                                            \
+       a.gen2 = 0;                                                            \
+       racoon_free(buf.v);                                                    \
+} while(0);
+
+struct dhgroup dh_modp768;
+struct dhgroup dh_modp1024;
+struct dhgroup dh_modp1536;
+struct dhgroup dh_modp2048;
+struct dhgroup dh_modp3072;
+struct dhgroup dh_modp4096;
+struct dhgroup dh_modp6144;
+struct dhgroup dh_modp8192;
+
+
+static int oakley_check_dh_pub __P((vchar_t *, vchar_t **));
+static int oakley_compute_keymat_x __P((struct ph2handle *, int, int));
+static int get_cert_fromlocal __P((struct ph1handle *, int));
+static int get_plainrsa_fromlocal __P((struct ph1handle *, int));
+#ifdef __APPLE__
+static int oakley_check_certid __P((struct ph1handle *iph1, int));
+static int oakley_check_certid_1 __P((struct ph1handle*, int, int, void*));
+#else
+static int oakley_check_certid __P((struct ph1handle *iph1));
+#endif
+static int check_typeofcertname __P((int, int));
+static cert_t *save_certbuf __P((struct isakmp_gen *));
+static cert_t *save_certx509 __P((X509 *));
+static int oakley_padlen __P((int, int));
+
+#ifdef __APPLE__
+static int base64toCFData(vchar_t *, CFDataRef*);
+#endif
+
+int
+oakley_get_defaultlifetime()
+{
+       return OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
+}
+
+int
+oakley_dhinit()
+{
+       /* set DH MODP */
+       INITDHVAL(dh_modp768, OAKLEY_PRIME_MODP768,
+               OAKLEY_ATTR_GRP_DESC_MODP768, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp1024, OAKLEY_PRIME_MODP1024,
+               OAKLEY_ATTR_GRP_DESC_MODP1024, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp1536, OAKLEY_PRIME_MODP1536,
+               OAKLEY_ATTR_GRP_DESC_MODP1536, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp2048, OAKLEY_PRIME_MODP2048,
+               OAKLEY_ATTR_GRP_DESC_MODP2048, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp3072, OAKLEY_PRIME_MODP3072,
+               OAKLEY_ATTR_GRP_DESC_MODP3072, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp4096, OAKLEY_PRIME_MODP4096,
+               OAKLEY_ATTR_GRP_DESC_MODP4096, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp6144, OAKLEY_PRIME_MODP6144,
+               OAKLEY_ATTR_GRP_DESC_MODP6144, OAKLEY_ATTR_GRP_TYPE_MODP);
+       INITDHVAL(dh_modp8192, OAKLEY_PRIME_MODP8192,
+               OAKLEY_ATTR_GRP_DESC_MODP8192, OAKLEY_ATTR_GRP_TYPE_MODP);
+
+       return 0;
+}
+
+void
+oakley_dhgrp_free(dhgrp)
+       struct dhgroup *dhgrp;
+{
+       if (dhgrp->prime)
+               vfree(dhgrp->prime);
+       if (dhgrp->curve_a)
+               vfree(dhgrp->curve_a);
+       if (dhgrp->curve_b)
+               vfree(dhgrp->curve_b);
+       if (dhgrp->order)
+               vfree(dhgrp->order);
+       racoon_free(dhgrp);
+}
+
+/*
+ * RFC2409 5
+ * The length of the Diffie-Hellman public value MUST be equal to the
+ * length of the prime modulus over which the exponentiation was
+ * performed, prepending zero bits to the value if necessary.
+ */
+static int
+oakley_check_dh_pub(prime, pub0)
+       vchar_t *prime, **pub0;
+{
+       vchar_t *tmp;
+       vchar_t *pub = *pub0;
+
+       if (prime->l == pub->l)
+               return 0;
+
+       if (prime->l < pub->l) {
+               /* what should i do ? */
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid public information was generated.\n");
+               return -1;
+       }
+
+       /* prime->l > pub->l */
+       tmp = vmalloc(prime->l);
+       if (tmp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get DH buffer.\n");
+               return -1;
+       }
+       memcpy(tmp->v + prime->l - pub->l, pub->v, pub->l);
+
+       vfree(*pub0);
+       *pub0 = tmp;
+
+       return 0;
+}
+
+/*
+ * compute sharing secret of DH
+ * IN: *dh, *pub, *priv, *pub_p
+ * OUT: **gxy
+ */
+int
+oakley_dh_compute(dh, pub, priv, pub_p, gxy)
+       const struct dhgroup *dh;
+       vchar_t *pub, *priv, *pub_p, **gxy;
+{
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+       if ((*gxy = vmalloc(dh->prime->l)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get DH buffer.\n");
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+       switch (dh->type) {
+       case OAKLEY_ATTR_GRP_TYPE_MODP:
+               if (eay_dh_compute(dh->prime, dh->gen1, pub, priv, pub_p, gxy) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to compute dh value.\n");
+                       return -1;
+               }
+               break;
+       case OAKLEY_ATTR_GRP_TYPE_ECP:
+       case OAKLEY_ATTR_GRP_TYPE_EC2N:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "dh type %d isn't supported.\n", dh->type);
+               return -1;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid dh type %d.\n", dh->type);
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__,
+               s_attr_isakmp_group(dh->type), dh->prime->l << 3,
+               timedelta(&start, &end));
+#endif
+
+       plog(LLV_DEBUG, LOCATION, NULL, "compute DH's shared.\n");
+       plogdump(LLV_DEBUG, (*gxy)->v, (*gxy)->l);
+
+       return 0;
+}
+
+/*
+ * generate values of DH
+ * IN: *dh
+ * OUT: **pub, **priv
+ */
+int
+oakley_dh_generate(dh, pub, priv)
+       const struct dhgroup *dh;
+       vchar_t **pub, **priv;
+{
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+       gettimeofday(&start, NULL);
+#endif
+       switch (dh->type) {
+       case OAKLEY_ATTR_GRP_TYPE_MODP:
+               if (eay_dh_generate(dh->prime, dh->gen1, dh->gen2, pub, priv) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to compute dh value.\n");
+                       return -1;
+               }
+               break;
+
+       case OAKLEY_ATTR_GRP_TYPE_ECP:
+       case OAKLEY_ATTR_GRP_TYPE_EC2N:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "dh type %d isn't supported.\n", dh->type);
+               return -1;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid dh type %d.\n", dh->type);
+               return -1;
+       }
+
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__,
+               s_attr_isakmp_group(dh->type), dh->prime->l << 3,
+               timedelta(&start, &end));
+#endif
+
+       if (oakley_check_dh_pub(dh->prime, pub) != 0)
+               return -1;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "compute DH's private.\n");
+       plogdump(LLV_DEBUG, (*priv)->v, (*priv)->l);
+       plog(LLV_DEBUG, LOCATION, NULL, "compute DH's public.\n");
+       plogdump(LLV_DEBUG, (*pub)->v, (*pub)->l);
+
+       return 0;
+}
+
+/*
+ * copy pre-defined dhgroup values.
+ */
+int
+oakley_setdhgroup(group, dhgrp)
+       int group;
+       struct dhgroup **dhgrp;
+{
+       struct dhgroup *g;
+
+       *dhgrp = NULL;  /* just make sure, initialize */
+
+       g = alg_oakley_dhdef_group(group);
+       if (g == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid DH parameter grp=%d.\n", group);
+               return -1;
+       }
+
+       if (!g->type || !g->prime || !g->gen1) {
+               /* unsuported */
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unsupported DH parameters grp=%d.\n", group);
+               return -1;
+       }
+
+       *dhgrp = racoon_calloc(1, sizeof(struct dhgroup));
+       if (*dhgrp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get DH buffer.\n");
+               return 0;
+       }
+
+       /* set defined dh vlaues */
+       memcpy(*dhgrp, g, sizeof(*g));
+       (*dhgrp)->prime = vdup(g->prime);
+
+       return 0;
+}
+
+/*
+ * PRF
+ *
+ * NOTE: we do not support prf with different input/output bitwidth,
+ * so we do not implement RFC2409 Appendix B (DOORAK-MAC example) in
+ * oakley_compute_keymat().  If you add support for such prf function,
+ * modify oakley_compute_keymat() accordingly.
+ */
+vchar_t *
+oakley_prf(key, buf, iph1)
+       vchar_t *key, *buf;
+       struct ph1handle *iph1;
+{
+       vchar_t *res = NULL;
+       int type;
+
+       if (iph1->approval == NULL) {
+               /*
+                * it's before negotiating hash algorithm.
+                * We use md5 as default.
+                */
+               type = OAKLEY_ATTR_HASH_ALG_MD5;
+       } else
+               type = iph1->approval->hashtype;
+
+       res = alg_oakley_hmacdef_one(type, key, buf);
+       if (res == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid hmac algorithm %d.\n", type);
+               return NULL;
+       }
+
+       return res;
+}
+
+/*
+ * hash
+ */
+vchar_t *
+oakley_hash(buf, iph1)
+       vchar_t *buf;
+       struct ph1handle *iph1;
+{
+       vchar_t *res = NULL;
+       int type;
+
+       if (iph1->approval == NULL) {
+               /*
+                * it's before negotiating hash algorithm.
+                * We use md5 as default.
+                */
+               type = OAKLEY_ATTR_HASH_ALG_MD5;
+       } else
+               type = iph1->approval->hashtype;
+
+       res = alg_oakley_hashdef_one(type, buf);
+       if (res == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid hash algorithm %d.\n", type);
+               return NULL;
+       }
+
+       return res;
+}
+
+/*
+ * compute KEYMAT
+ *   see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05.
+ */
+int
+oakley_compute_keymat(iph2, side)
+       struct ph2handle *iph2;
+       int side;
+{
+       int error = -1;
+
+       /* compute sharing secret of DH when PFS */
+       if (iph2->approval->pfs_group && iph2->dhpub_p) {
+               if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub,
+                               iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0)
+                       goto end;
+       }
+
+       /* compute keymat */
+       if (oakley_compute_keymat_x(iph2, side, INBOUND_SA) < 0
+        || oakley_compute_keymat_x(iph2, side, OUTBOUND_SA) < 0)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT computed.\n");
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/*
+ * compute KEYMAT.
+ * KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b).
+ * If PFS is desired and KE payloads were exchanged,
+ *   KEYMAT = prf(SKEYID_d, g(qm)^xy | protocol | SPI | Ni_b | Nr_b)
+ *
+ * NOTE: we do not support prf with different input/output bitwidth,
+ * so we do not implement RFC2409 Appendix B (DOORAK-MAC example).
+ */
+static int
+oakley_compute_keymat_x(iph2, side, sa_dir)
+       struct ph2handle *iph2;
+       int side;
+       int sa_dir;
+{
+       vchar_t *buf = NULL, *res = NULL, *bp;
+       char *p;
+       int len;
+       int error = -1;
+       int pfs = 0;
+       int dupkeymat;  /* generate K[1-dupkeymat] */
+       struct saproto *pr;
+       struct satrns *tr;
+       int encklen, authklen, l;
+
+       pfs = ((iph2->approval->pfs_group && iph2->dhgxy) ? 1 : 0);
+       
+       len = pfs ? iph2->dhgxy->l : 0;
+       len += (1
+               + sizeof(u_int32_t)     /* XXX SPI size */
+               + iph2->nonce->l
+               + iph2->nonce_p->l);
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get keymat buffer.\n");
+               goto end;
+       }
+
+       for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+               p = buf->v;
+
+               /* if PFS */
+               if (pfs) {
+                       memcpy(p, iph2->dhgxy->v, iph2->dhgxy->l);
+                       p += iph2->dhgxy->l;
+               }
+
+               p[0] = pr->proto_id;
+               p += 1;
+
+               memcpy(p, (sa_dir == INBOUND_SA ? &pr->spi : &pr->spi_p),
+                       sizeof(pr->spi));
+               p += sizeof(pr->spi);
+
+               bp = (side == INITIATOR ? iph2->nonce : iph2->nonce_p);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               bp = (side == INITIATOR ? iph2->nonce_p : iph2->nonce);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               /* compute IV */
+               plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT compute with\n");
+               plogdump(LLV_DEBUG, buf->v, buf->l);
+
+               /* res = K1 */
+               res = oakley_prf(iph2->ph1->skeyid_d, buf, iph2->ph1);
+               if (res == NULL)
+                       goto end;
+
+               /* compute key length needed */
+               encklen = authklen = 0;
+               switch (pr->proto_id) {
+               case IPSECDOI_PROTO_IPSEC_ESP:
+                       for (tr = pr->head; tr; tr = tr->next) {
+                               l = alg_ipsec_encdef_keylen(tr->trns_id,
+                                   tr->encklen);
+                               if (l > encklen)
+                                       encklen = l;
+
+                               l = alg_ipsec_hmacdef_hashlen(tr->authtype);
+                               if (l > authklen)
+                                       authklen = l;
+                       }
+                       break;
+               case IPSECDOI_PROTO_IPSEC_AH:
+                       for (tr = pr->head; tr; tr = tr->next) {
+                               l = alg_ipsec_hmacdef_hashlen(tr->trns_id);
+                               if (l > authklen)
+                                       authklen = l;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL, "encklen=%d authklen=%d\n",
+                       encklen, authklen);
+
+               dupkeymat = (encklen + authklen) / 8 / res->l;
+               dupkeymat += 2; /* safety mergin */
+               if (dupkeymat < 3)
+                       dupkeymat = 3;
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "generating %zu bits of key (dupkeymat=%d)\n",
+                       dupkeymat * 8 * res->l, dupkeymat);
+               if (0 < --dupkeymat) {
+                       vchar_t *prev = res;    /* K(n-1) */
+                       vchar_t *seed = NULL;   /* seed for Kn */
+                       size_t l;
+
+                       /*
+                        * generating long key (isakmp-oakley-08 5.5)
+                        *   KEYMAT = K1 | K2 | K3 | ...
+                        * where
+                        *   src = [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b
+                        *   K1 = prf(SKEYID_d, src)
+                        *   K2 = prf(SKEYID_d, K1 | src)
+                        *   K3 = prf(SKEYID_d, K2 | src)
+                        *   Kn = prf(SKEYID_d, K(n-1) | src)
+                        */
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "generating K1...K%d for KEYMAT.\n",
+                               dupkeymat + 1);
+
+                       seed = vmalloc(prev->l + buf->l);
+                       if (seed == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get keymat buffer.\n");
+                               if (prev && prev != res)
+                                       vfree(prev);
+                               goto end;
+                       }
+
+                       while (dupkeymat--) {
+                               vchar_t *this = NULL;   /* Kn */
+
+                               memcpy(seed->v, prev->v, prev->l);
+                               memcpy(seed->v + prev->l, buf->v, buf->l);
+                               this = oakley_prf(iph2->ph1->skeyid_d, seed,
+                                                       iph2->ph1);
+                               if (!this) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "oakley_prf memory overflow\n");
+                                       if (prev && prev != res)
+                                               vfree(prev);
+                                       vfree(this);
+                                       vfree(seed);
+                                       goto end;
+                               }
+
+                               l = res->l;
+                               res = vrealloc(res, l + this->l);
+                               if (res == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "failed to get keymat buffer.\n");
+                                       if (prev && prev != res)
+                                               vfree(prev);
+                                       vfree(this);
+                                       vfree(seed);
+                                       goto end;
+                               }
+                               memcpy(res->v + l, this->v, this->l);
+
+                               if (prev && prev != res)
+                                       vfree(prev);
+                               prev = this;
+                               this = NULL;
+                       }
+
+                       if (prev && prev != res)
+                               vfree(prev);
+                       vfree(seed);
+               }
+
+               plogdump(LLV_DEBUG, res->v, res->l);
+
+               if (sa_dir == INBOUND_SA)
+                       pr->keymat = res;
+               else
+                       pr->keymat_p = res;
+               res = NULL;
+       }
+
+       error = 0;
+
+end:
+       if (error) {
+               for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+                       if (pr->keymat) {
+                               vfree(pr->keymat);
+                               pr->keymat = NULL;
+                       }
+                       if (pr->keymat_p) {
+                               vfree(pr->keymat_p);
+                               pr->keymat_p = NULL;
+                       }
+               }
+       }
+
+       if (buf != NULL)
+               vfree(buf);
+       if (res)
+               vfree(res);
+
+       return error;
+}
+
+#if notyet
+/*
+ * NOTE: Must terminate by NULL.
+ */
+vchar_t *
+oakley_compute_hashx(struct ph1handle *iph1, ...)
+{
+       vchar_t *buf, *res;
+       vchar_t *s;
+       caddr_t p;
+       int len;
+
+       va_list ap;
+
+       /* get buffer length */
+       va_start(ap, iph1);
+       len = 0;
+        while ((s = va_arg(ap, vchar_t *)) != NULL) {
+               len += s->l
+        }
+       va_end(ap);
+
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               return NULL;
+       }
+
+       /* set buffer */
+       va_start(ap, iph1);
+       p = buf->v;
+        while ((s = va_arg(ap, char *)) != NULL) {
+               memcpy(p, s->v, s->l);
+               p += s->l;
+       }
+       va_end(ap);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(iph1->skeyid_a, buf, iph1);
+       vfree(buf);
+       if (res == NULL)
+               return NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+       return res;
+}
+#endif
+
+/*
+ * compute HASH(3) prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b)
+ *   see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05.
+ */
+vchar_t *
+oakley_compute_hash3(iph1, msgid, body)
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+       vchar_t *body;
+{
+       vchar_t *buf = 0, *res = 0;
+       int len;
+       int error = -1;
+
+       /* create buffer */
+       len = 1 + sizeof(u_int32_t) + body->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+
+       buf->v[0] = 0;
+
+       memcpy(buf->v + 1, (char *)&msgid, sizeof(msgid));
+
+       memcpy(buf->v + 1 + sizeof(u_int32_t), body->v, body->l);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(iph1->skeyid_a, buf, iph1);
+       if (res == NULL)
+               goto end;
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       return res;
+}
+
+/*
+ * compute HASH type of prf(SKEYID_a, M-ID | buffer)
+ *     e.g.
+ *     for quick mode HASH(1):
+ *             prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ])
+ *     for quick mode HASH(2):
+ *             prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ])
+ *     for Informational exchange:
+ *             prf(SKEYID_a, M-ID | N/D)
+ */
+vchar_t *
+oakley_compute_hash1(iph1, msgid, body)
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+       vchar_t *body;
+{
+       vchar_t *buf = NULL, *res = NULL;
+       char *p;
+       int len;
+       int error = -1;
+
+       /* create buffer */
+       len = sizeof(u_int32_t) + body->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+
+       p = buf->v;
+
+       memcpy(buf->v, (char *)&msgid, sizeof(msgid));
+       p += sizeof(u_int32_t);
+
+       memcpy(p, body->v, body->l);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(iph1->skeyid_a, buf, iph1);
+       if (res == NULL)
+               goto end;
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       return res;
+}
+
+/*
+ * compute phase1 HASH
+ * main/aggressive
+ *   I-digest = prf(SKEYID, g^i | g^r | CKY-I | CKY-R | SAi_b | ID_i1_b)
+ *   R-digest = prf(SKEYID, g^r | g^i | CKY-R | CKY-I | SAi_b | ID_r1_b)
+ * for gssapi, also include all GSS tokens, and call gss_wrap on the result
+ */
+vchar_t *
+oakley_ph1hash_common(iph1, sw)
+       struct ph1handle *iph1;
+       int sw;
+{
+       vchar_t *buf = NULL, *res = NULL, *bp;
+       char *p, *bp2;
+       int len, bl;
+       int error = -1;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsstokens = NULL;
+#endif
+
+       /* create buffer */
+       len = iph1->dhpub->l
+               + iph1->dhpub_p->l
+               + sizeof(cookie_t) * 2
+               + iph1->sa->l
+               + (sw == GENERATE ? iph1->id->l : iph1->id_p->l);
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+               if (iph1->gi_i != NULL && iph1->gi_r != NULL) {
+                       bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r);
+                       len += bp->l;
+               }
+               if (sw == GENERATE)
+                       gssapi_get_itokens(iph1, &gsstokens);
+               else
+                       gssapi_get_rtokens(iph1, &gsstokens);
+               if (gsstokens == NULL)
+                       return NULL;
+               len += gsstokens->l;
+       }
+#endif
+
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+
+       p = buf->v;
+
+       bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       if (iph1->side == INITIATOR)
+               bp2 = (sw == GENERATE ?
+                     (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck);
+       else
+               bp2 = (sw == GENERATE ?
+                     (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck);
+       bl = sizeof(cookie_t);
+       memcpy(p, bp2, bl);
+       p += bl;
+
+       if (iph1->side == INITIATOR)
+               bp2 = (sw == GENERATE ?
+                     (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck);
+       else
+               bp2 = (sw == GENERATE ?
+                     (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck);
+       bl = sizeof(cookie_t);
+       memcpy(p, bp2, bl);
+       p += bl;
+
+       bp = iph1->sa;
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       bp = (sw == GENERATE ? iph1->id : iph1->id_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+#ifdef HAVE_GSSAPI
+       if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+               if (iph1->gi_i != NULL && iph1->gi_r != NULL) {
+                       bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r);
+                       memcpy(p, bp->v, bp->l);
+                       p += bp->l;
+               }
+               memcpy(p, gsstokens->v, gsstokens->l);
+               p += gsstokens->l;
+       }
+#endif
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(iph1->skeyid, buf, iph1);
+       if (res == NULL)
+               goto end;
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+#ifdef HAVE_GSSAPI
+       if (gsstokens != NULL)
+               vfree(gsstokens);
+#endif
+       return res;
+}
+
+/*
+ * compute HASH_I on base mode.
+ * base:psk,rsa
+ *   HASH_I = prf(SKEYID, g^xi | CKY-I | CKY-R | SAi_b | IDii_b)
+ * base:sig
+ *   HASH_I = prf(hash(Ni_b | Nr_b), g^xi | CKY-I | CKY-R | SAi_b | IDii_b)
+ */
+vchar_t *
+oakley_ph1hash_base_i(iph1, sw)
+       struct ph1handle *iph1;
+       int sw;
+{
+       vchar_t *buf = NULL, *res = NULL, *bp;
+       vchar_t *hashkey = NULL;
+       vchar_t *hash = NULL;   /* for signature mode */
+       char *p;
+       int len;
+       int error = -1;
+
+       /* sanity check */
+       if (iph1->etype != ISAKMP_ETYPE_BASE) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid etype for this hash function\n");
+               return NULL;
+       }
+
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               if (iph1->skeyid == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n");
+                       return NULL;
+               }
+               hashkey = iph1->skeyid;
+               break;
+
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+#endif
+               /* make hash for seed */
+               len = iph1->nonce->l + iph1->nonce_p->l;
+               buf = vmalloc(len);
+               if (buf == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get hash buffer\n");
+                       goto end;
+               }
+               p = buf->v;
+
+               bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               hash = oakley_hash(buf, iph1);
+               if (hash == NULL)
+                       goto end;
+               vfree(buf);
+               buf = NULL;
+
+               hashkey = hash;
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not supported authentication method %d\n",
+                       iph1->approval->authmethod);
+               return NULL;
+
+       }
+
+       len = (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l)
+               + sizeof(cookie_t) * 2
+               + iph1->sa->l
+               + (sw == GENERATE ? iph1->id->l : iph1->id_p->l);
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+       p = buf->v;
+
+       bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       memcpy(p, &iph1->index.i_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       memcpy(p, &iph1->index.r_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+
+       memcpy(p, iph1->sa->v, iph1->sa->l);
+       p += iph1->sa->l;
+
+       bp = (sw == GENERATE ? iph1->id : iph1->id_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH_I with:\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(hashkey, buf, iph1);
+       if (res == NULL)
+               goto end;
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH_I computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+end:
+       if (hash != NULL)
+               vfree(hash);
+       if (buf != NULL)
+               vfree(buf);
+       return res;
+}
+
+/*
+ * compute HASH_R on base mode for signature method.
+ * base:
+ * HASH_R = prf(hash(Ni_b | Nr_b), g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b)
+ */
+vchar_t *
+oakley_ph1hash_base_r(iph1, sw)
+       struct ph1handle *iph1;
+       int sw;
+{
+       vchar_t *buf = NULL, *res = NULL, *bp;
+       vchar_t *hash = NULL;
+       char *p;
+       int len;
+       int error = -1;
+
+       /* sanity check */
+       if (iph1->etype != ISAKMP_ETYPE_BASE) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid etype for this hash function\n");
+               return NULL;
+       }
+       if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG
+#ifdef ENABLE_HYBRID
+        && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I
+        && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I
+#endif
+        && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not supported authentication method %d\n",
+                       iph1->approval->authmethod);
+               return NULL;
+       }
+
+       /* make hash for seed */
+       len = iph1->nonce->l + iph1->nonce_p->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+       p = buf->v;
+
+       bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       hash = oakley_hash(buf, iph1);
+       if (hash == NULL)
+               goto end;
+       vfree(buf);
+       buf = NULL;
+
+       /* make really hash */
+       len = (sw == GENERATE ? iph1->dhpub_p->l : iph1->dhpub->l)
+               + (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l)
+               + sizeof(cookie_t) * 2
+               + iph1->sa->l
+               + (sw == GENERATE ? iph1->id_p->l : iph1->id->l);
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get hash buffer\n");
+               goto end;
+       }
+       p = buf->v;
+
+
+       bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       memcpy(p, &iph1->index.i_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       memcpy(p, &iph1->index.r_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+
+       memcpy(p, iph1->sa->v, iph1->sa->l);
+       p += iph1->sa->l;
+
+       bp = (sw == GENERATE ? iph1->id_p : iph1->id);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* compute HASH */
+       res = oakley_prf(hash, buf, iph1);
+       if (res == NULL)
+               goto end;
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n");
+       plogdump(LLV_DEBUG, res->v, res->l);
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       if (hash)
+               vfree(hash);
+       return res;
+}
+
+/*
+ * compute each authentication method in phase 1.
+ * OUT:
+ *     0:      OK
+ *     -1:     error
+ *     other:  error to be reply with notification.
+ *             the value is notification type.
+ */
+int
+oakley_validate_auth(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *my_hash = NULL;
+       int result;
+#ifdef HAVE_GSSAPI
+       vchar_t *gsshash = NULL;
+#endif
+#ifdef ENABLE_STATS
+       struct timeval start, end;
+#endif
+
+#ifdef ENABLE_STATS
+       gettimeofday(&start, NULL);
+#endif
+       switch (iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+               /* validate HASH */
+           {
+               char *r_hash;
+
+               if (iph1->id_p == NULL || iph1->pl_hash == NULL) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "few isakmp message received.\n");
+                       return ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               }
+
+               r_hash = (caddr_t)(iph1->pl_hash + 1);
+
+               plog(LLV_DEBUG, LOCATION, NULL, "HASH received:");
+               plogdump(LLV_DEBUG, r_hash,
+                       ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash));
+
+               switch (iph1->etype) {
+               case ISAKMP_ETYPE_IDENT:
+               case ISAKMP_ETYPE_AGG:
+                       my_hash = oakley_ph1hash_common(iph1, VALIDATE);
+                       break;
+               case ISAKMP_ETYPE_BASE:
+                       if (iph1->side == INITIATOR)
+                               my_hash = oakley_ph1hash_common(iph1, VALIDATE);
+                       else
+                               my_hash = oakley_ph1hash_base_i(iph1, VALIDATE);
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid etype %d\n", iph1->etype);
+                       return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE;
+               }
+               if (my_hash == NULL)
+                       return ISAKMP_INTERNAL_ERROR;
+
+               result = memcmp(my_hash->v, r_hash, my_hash->l);
+               vfree(my_hash);
+
+               if (result) {
+                       plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n");
+                       return ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL, "HASH for PSK validated.\n");
+           }
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+#endif
+           {
+               int error = 0;
+               int certtype = 0;
+
+               /* validation */
+               if (iph1->id_p == NULL) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "no ID payload was passed.\n");
+                       return ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               }
+               if (iph1->sig_p == NULL) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "no SIG payload was passed.\n");
+                       return ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL, "SIGN passed:\n");
+               plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l);
+
+               /* get peer's cert */
+               switch (iph1->rmconf->getcert_method) {
+               case ISAKMP_GETCERT_PAYLOAD:
+                       if (iph1->cert_p == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no peer's CERT payload found.\n");
+                               return ISAKMP_INTERNAL_ERROR;
+                       }
+                       break;
+               case ISAKMP_GETCERT_LOCALFILE:
+                       switch (iph1->rmconf->certtype) {
+                               case ISAKMP_CERT_X509SIGN:
+                                       if (iph1->rmconf->peerscertfile == NULL) {
+                                               plog(LLV_ERROR, LOCATION, NULL,
+                                                       "no peer's CERT file found.\n");
+                                               return ISAKMP_INTERNAL_ERROR;
+                                       }
+
+                                       /* don't use cached cert */
+                                       if (iph1->cert_p != NULL) {
+                                               oakley_delcert(iph1->cert_p);
+                                               iph1->cert_p = NULL;
+                                       }
+
+                                       error = get_cert_fromlocal(iph1, 0);
+                                       break;
+
+                               case ISAKMP_CERT_PLAINRSA:
+                                       error = get_plainrsa_fromlocal(iph1, 0);
+                                       break;
+                       }
+                       if (error)
+                               return ISAKMP_INTERNAL_ERROR;
+                       break;
+               case ISAKMP_GETCERT_DNS:
+                       if (iph1->rmconf->peerscertfile != NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "why peer's CERT file is defined "
+                                       "though getcert method is dns ?\n");
+                               return ISAKMP_INTERNAL_ERROR;
+                       }
+
+                       /* don't use cached cert */
+                       if (iph1->cert_p != NULL) {
+                               oakley_delcert(iph1->cert_p);
+                               iph1->cert_p = NULL;
+                       }
+
+                       iph1->cert_p = dnssec_getcert(iph1->id_p);
+                       if (iph1->cert_p == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no CERT RR found.\n");
+                               return ISAKMP_INTERNAL_ERROR;
+                       }
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid getcert_mothod: %d\n",
+                               iph1->rmconf->getcert_method);
+                       return ISAKMP_INTERNAL_ERROR;
+               }
+
+               /* compare ID payload and certificate name */
+               if (iph1->rmconf->verify_cert &&
+#ifdef __APPLE__
+                   (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) != 0)
+#else
+                       (error = oakley_check_certid(iph1)) != 0)
+#endif
+                       return error;
+                       
+#ifdef __APPLE__
+
+               /* check configured peers identifier against cert IDs                           */
+               /* allows checking of specified ID against multiple ids in the cert */
+               /* such as multiple domain names                                                                        */
+               if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER &&
+                       (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_RMCONFIG)) != 0)
+                       return error;
+
+               /* check cert common name against Open Directory authentication group */
+               if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_OPEN_DIR) {
+                       
+                       vchar_t *user_id = NULL;
+                       
+                       user_id = eay_get_x509_common_name(&iph1->cert_p->cert);
+                       if (user_id) {
+                               // the following functions will check if user_id == 0
+                               if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group) == 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                       "the peer is not authorized for access.\n");
+                                       vfree(user_id);
+                                       return ISAKMP_NTYPE_AUTHENTICATION_FAILED;
+                               }
+                               vfree(user_id);
+                       } else {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "the peer is not authorized for access - user ID not found.\n");
+                                       return ISAKMP_NTYPE_AUTHENTICATION_FAILED;
+                       }
+               }
+#endif
+
+               /* verify certificate */
+               if (iph1->rmconf->verify_cert
+                && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) {
+                       certtype = iph1->rmconf->certtype;
+#ifdef ENABLE_HYBRID
+                       switch (iph1->approval->authmethod) {
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+                       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+                               certtype = iph1->cert_p->type;
+                               break;
+                       default:
+                               break;
+                       }
+#endif
+                       switch (certtype) {
+                       case ISAKMP_CERT_X509SIGN:
+#ifdef __APPLE__
+                               if (iph1->rmconf->cert_verification == VERIFICATION_MODULE_SEC_FRAMEWORK)
+                                       error = crypto_cssm_check_x509cert(&iph1->cert_p->cert);
+                               else 
+#endif
+                               {
+                                       char path[MAXPATHLEN];
+                                       char *ca;
+
+                                       if (iph1->rmconf->cacertfile != NULL) {
+                                               getpathname(path, sizeof(path), 
+                                               LC_PATHTYPE_CERT, 
+                                               iph1->rmconf->cacertfile);
+                                               ca = path;
+                                       } else {
+                                               ca = NULL;
+                                       }
+
+                                       error = eay_check_x509cert(&iph1->cert_p->cert,
+                                               lcconf->pathinfo[LC_PATHTYPE_CERT], 
+                                               ca, 0);
+                               }
+                               break;
+                       
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no supported certtype %d\n", certtype);
+                               return ISAKMP_INTERNAL_ERROR;
+                       }
+                       if (error != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "the peer's certificate is not verified.\n");
+                               return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY;
+                       }
+               }
+
+
+               plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n");
+
+               /* compute hash */
+               switch (iph1->etype) {
+               case ISAKMP_ETYPE_IDENT:
+               case ISAKMP_ETYPE_AGG:
+                       my_hash = oakley_ph1hash_common(iph1, VALIDATE);
+                       break;
+               case ISAKMP_ETYPE_BASE:
+                       if (iph1->side == INITIATOR)
+                               my_hash = oakley_ph1hash_base_r(iph1, VALIDATE);
+                       else
+                               my_hash = oakley_ph1hash_base_i(iph1, VALIDATE);
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid etype %d\n", iph1->etype);
+                       return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE;
+               }
+               if (my_hash == NULL)
+                       return ISAKMP_INTERNAL_ERROR;
+
+
+               certtype = iph1->rmconf->certtype;
+#ifdef ENABLE_HYBRID
+               switch (iph1->approval->authmethod) {
+               case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+               case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+                       certtype = iph1->cert_p->type;
+                       break;
+               default:
+                       break;
+               }
+#endif
+               /* check signature */
+               switch (certtype) {
+               case ISAKMP_CERT_X509SIGN:
+               case ISAKMP_CERT_DNS:
+                       error = eay_check_x509sign(my_hash,
+                                       iph1->sig_p,
+                                       &iph1->cert_p->cert);
+                       break;
+               case ISAKMP_CERT_PLAINRSA:
+                       iph1->rsa_p = rsa_try_check_rsasign(my_hash,
+                                       iph1->sig_p, iph1->rsa_candidates);
+                       error = iph1->rsa_p ? 0 : -1;
+
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no supported certtype %d\n",
+                               certtype);
+                       vfree(my_hash);
+                       return ISAKMP_INTERNAL_ERROR;
+               }
+
+               vfree(my_hash);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid SIG.\n");
+                       return ISAKMP_NTYPE_INVALID_SIGNATURE;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL, "SIG authenticated\n");
+           }
+               break;
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+           {
+               if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, "
+                           "hybrid auth is enabled, "
+                           "but peer is no Xauth compliant\n");
+                       return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED;
+                       break;
+               }
+               plog(LLV_INFO, LOCATION, NULL, "No SIG was passed, "
+                   "but hybrid auth is enabled\n");
+
+               return 0;
+               break;
+           }
+#endif
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+               switch (iph1->etype) {
+               case ISAKMP_ETYPE_IDENT:
+               case ISAKMP_ETYPE_AGG:
+                       my_hash = oakley_ph1hash_common(iph1, VALIDATE);
+                       break;
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid etype %d\n", iph1->etype);
+                       return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE;
+               }
+
+               if (my_hash == NULL) {
+                       if (gssapi_more_tokens(iph1))
+                               return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE;
+                       else
+                               return ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               }
+
+               gsshash = gssapi_unwraphash(iph1);
+               if (gsshash == NULL) {
+                       vfree(my_hash);
+                       return ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               }
+
+               result = memcmp(my_hash->v, gsshash->v, my_hash->l);
+               vfree(my_hash);
+               vfree(gsshash);
+
+               if (result) {
+                       plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n");
+                       return ISAKMP_NTYPE_INVALID_HASH_INFORMATION;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL, "hash compared OK\n");
+               break;
+#endif
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               if (iph1->id_p == NULL || iph1->pl_hash == NULL) {
+                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                               "few isakmp message received.\n");
+                       return ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+               }
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "not supported authmethod type %s\n",
+                       s_oakley_attr_method(iph1->approval->authmethod));
+               return ISAKMP_INTERNAL_ERROR;
+       default:
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "invalid authmethod %d why ?\n",
+                       iph1->approval->authmethod);
+               return ISAKMP_INTERNAL_ERROR;
+       }
+#ifdef ENABLE_STATS
+       gettimeofday(&end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f", __func__,
+               s_oakley_attr_method(iph1->approval->authmethod),
+               timedelta(&start, &end));
+#endif
+
+       return 0;
+}
+
+/* get my certificate
+ * NOTE: include certificate type.
+ */
+int
+oakley_getmycert(iph1)
+       struct ph1handle *iph1;
+{
+       switch (iph1->rmconf->certtype) {
+               case ISAKMP_CERT_X509SIGN:
+                       if (iph1->cert)
+                               return 0;
+                       return get_cert_fromlocal(iph1, 1);
+
+               case ISAKMP_CERT_PLAINRSA:
+                       if (iph1->rsa)
+                               return 0;
+                       return get_plainrsa_fromlocal(iph1, 1);
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Unknown certtype #%d\n",
+                            iph1->rmconf->certtype);
+                       return -1;
+       }
+
+}
+
+/*
+ * get a CERT from local file.
+ * IN:
+ *     my != 0 my cert.
+ *     my == 0 peer's cert.
+ */
+static int
+get_cert_fromlocal(iph1, my)
+       struct ph1handle *iph1;
+       int my;
+{
+       char path[MAXPATHLEN];
+       vchar_t *cert = NULL;
+       cert_t **certpl;
+       char *certfile;
+       int error = -1;
+
+       if (my) {
+               certfile = iph1->rmconf->mycertfile;
+               certpl = &iph1->cert;
+       } else {
+               certfile = iph1->rmconf->peerscertfile;
+               certpl = &iph1->cert_p;
+       }
+
+#ifdef __APPLE__
+       if (!certfile && iph1->rmconf->identity_in_keychain == 0) {
+#else
+       if (!certfile) {
+#endif
+               plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n");
+               return 0;
+       }
+
+       switch (iph1->rmconf->certtype) {
+       case ISAKMP_CERT_X509SIGN:
+#ifdef __APPLE__
+               if (iph1->rmconf->identity_in_keychain) {
+                       CFDataRef dataRef;
+                       
+                       if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef))
+                               goto end;
+                       cert = crypto_cssm_get_x509cert(dataRef);
+                       CFRelease(dataRef);
+                       break;
+               } // else fall thru
+#endif
+       case ISAKMP_CERT_DNS:
+               /* make public file name */
+               getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile);
+               cert = eay_get_x509cert(path);
+               if (cert) {
+                       char *p = NULL;
+                       p = eay_get_x509text(cert);
+                       plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
+                       racoon_free(p);
+               };
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "not supported certtype %d\n",
+                       iph1->rmconf->certtype);
+               goto end;
+       }
+
+       if (!cert) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get %s CERT.\n",
+                       my ? "my" : "peers");
+               goto end;
+       }
+
+       *certpl = oakley_newcert();
+       if (!*certpl) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cert buffer.\n");
+               goto end;
+       }
+       (*certpl)->pl = vmalloc(cert->l + 1);
+       if ((*certpl)->pl == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cert buffer\n");
+               oakley_delcert(*certpl);
+               *certpl = NULL;
+               goto end;
+       }
+       memcpy((*certpl)->pl->v + 1, cert->v, cert->l);
+       (*certpl)->pl->v[0] = iph1->rmconf->certtype;
+       (*certpl)->type = iph1->rmconf->certtype;
+       (*certpl)->cert.v = (*certpl)->pl->v + 1;
+       (*certpl)->cert.l = (*certpl)->pl->l - 1;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n");
+       plogdump(LLV_DEBUG, (*certpl)->pl->v, (*certpl)->pl->l);
+
+       error = 0;
+
+end:
+       if (cert != NULL)
+               vfree(cert);
+
+       return error;
+}
+
+static int
+get_plainrsa_fromlocal(iph1, my)
+       struct ph1handle *iph1;
+       int my;
+{
+       char path[MAXPATHLEN];
+       vchar_t *cert = NULL;
+       char *certfile;
+       int error = -1;
+
+       iph1->rsa_candidates = rsa_lookup_keys(iph1, my);
+       if (!iph1->rsa_candidates || rsa_list_count(iph1->rsa_candidates) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "%s RSA key not found for %s\n",
+                       my ? "Private" : "Public",
+                       saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote));
+               goto end;
+       }
+
+       if (my && rsa_list_count(iph1->rsa_candidates) > 1) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "More than one (=%lu) private PlainRSA key found for %s\n",
+                       rsa_list_count(iph1->rsa_candidates),
+                       saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote));
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "This may have unpredictable results, i.e. wrong key could be used!\n");
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "Consider using only one single private key for all peers...\n");
+       }
+       if (my) {
+               iph1->rsa = ((struct rsa_key *)genlist_next(iph1->rsa_candidates, NULL))->rsa;
+               genlist_free(iph1->rsa_candidates, NULL);
+               iph1->rsa_candidates = NULL;
+       }
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/* get signature */
+int
+oakley_getsign(iph1)
+       struct ph1handle *iph1;
+{
+       char path[MAXPATHLEN];
+       vchar_t *privkey = NULL;
+       int error = -1;
+
+       switch (iph1->rmconf->certtype) {
+       case ISAKMP_CERT_X509SIGN:
+#ifdef __APPLE__
+               // cert in keychain - use cssm to sign
+               if (iph1->rmconf->identity_in_keychain) {
+                       CFDataRef dataRef;
+                       
+                       if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef))
+                               goto end;
+                       iph1->sig = crypto_cssm_getsign(dataRef, iph1->hash);
+                       CFRelease(dataRef);
+                       break;
+               } // else fall thru
+#endif
+       case ISAKMP_CERT_DNS:
+               if (iph1->rmconf->myprivfile == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n");
+                       goto end;
+               }
+
+               /* make private file name */
+               getpathname(path, sizeof(path),
+                       LC_PATHTYPE_CERT,
+                       iph1->rmconf->myprivfile);
+               privkey = privsep_eay_get_pkcs1privkey(path);
+               if (privkey == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get private key.\n");
+                       goto end;
+               }
+               plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n");
+               plogdump(LLV_DEBUG2, privkey->v, privkey->l);
+
+               iph1->sig = eay_get_x509sign(iph1->hash, privkey);
+               break;
+       case ISAKMP_CERT_PLAINRSA:
+               iph1->sig = eay_get_rsasign(iph1->hash, iph1->rsa);
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                    "Unknown certtype #%d\n",
+                    iph1->rmconf->certtype);
+               goto end;
+       }
+
+       if (iph1->sig == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "failed to sign.\n");
+               goto end;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "SIGN computed:\n");
+       plogdump(LLV_DEBUG, iph1->sig->v, iph1->sig->l);
+
+       error = 0;
+
+end:
+       if (privkey != NULL)
+               vfree(privkey);
+
+       return error;
+}
+
+#ifdef __APPLE__
+
+/*
+ * compare certificate name and ID value.
+ */
+static int
+oakley_check_certid(iph1, which_id)
+       struct ph1handle *iph1;
+       int which_id;
+{
+       struct ipsecdoi_id_b *id_b;
+       int idlen;
+       u_int8_t doi_type = 255;
+       void *peers_id = NULL;
+       struct genlist_entry *gpb = NULL;
+
+       if (which_id == CERT_CHECKID_FROM_PEER) {
+               /* use ID from peer */
+               if (iph1->id_p == NULL || iph1->cert_p == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
+               doi_type = id_b->type;
+               peers_id = id_b + 1;
+               idlen = iph1->id_p->l - sizeof(*id_b);
+               
+               return oakley_check_certid_1(iph1, doi_type, idlen, peers_id);
+
+       } else {
+               /* use ID from remote configuration */  
+               /* check each ID in list                        */
+               struct idspec *id_spec;
+               
+               for (id_spec = genlist_next (iph1->rmconf->idvl_p, &gpb); id_spec; id_spec = genlist_next (0, &gpb)) {
+                       
+                       if (id_spec->idtype == IDTYPE_ADDRESS) {
+                               switch (((struct sockaddr *)(id_spec->id->v))->sa_family) {                                                     
+                                       case AF_INET:
+                                               doi_type = IPSECDOI_ID_IPV4_ADDR;
+                                               idlen = sizeof(struct in_addr);
+                                               peers_id = &(((struct sockaddr_in *)(id_spec->id->v))->sin_addr.s_addr);
+                                               break;
+       #ifdef INET6
+                                       case AF_INET6:
+                                               doi_type = IPSECDOI_ID_IPV6_ADDR;
+                                               idlen = sizeof(struct in6_addr);
+                                               peers_id = &(((struct sockaddr_in6 *)(id_spec->id->v))->sin6_addr.s6_addr);
+                                               break;
+       #endif
+                                       default:
+                                               plog(LLV_ERROR, LOCATION, NULL,
+                                                       "unknown address type for peers identifier.\n");
+                                               return ISAKMP_NTYPE_AUTHENTICATION_FAILED;
+                                               break;
+                               }
+                               
+                       } else {
+                               doi_type = idtype2doi(id_spec->idtype);
+                               peers_id = id_spec->id->v;
+                               idlen = id_spec->id->l;
+                       }
+                       if (oakley_check_certid_1(iph1, doi_type, idlen, peers_id) == 0)
+                               return 0;
+               }
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+}
+  
+static int
+oakley_check_certid_1(iph1, idtype, idlen, id)
+       struct ph1handle *iph1;
+       int idtype;
+       int idlen;
+       void *id;
+{
+
+       vchar_t *name = NULL;
+       char *altname = NULL;
+       int type, len;
+       int error;
+
+       switch (idtype) {
+       case IPSECDOI_ID_DER_ASN1_DN:
+               name = eay_get_x509asn1subjectname(&iph1->cert_p->cert);
+               if (!name) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get subjectName\n");
+                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+               }
+               if (idlen != name->l) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid ID length in phase 1.\n");
+                       vfree(name);
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               error = memcmp(id, name->v, idlen);
+               vfree(name);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "ID mismatched with subjectName.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               return 0;
+       case IPSECDOI_ID_IPV4_ADDR:                     
+       case IPSECDOI_ID_IPV6_ADDR:
+       {
+
+               /* 
+                * Openssl returns the IPAddress as an ASN1 octet string (binary format)
+                * followed by a trailing NULL.  5 bytes for IPv4 and 17 bytes for IPv6
+                */     
+               #define SUBJ_ALT_NAME_IPV4_ADDRESS_LEN  5
+               #define SUBJ_ALT_NAME_IPV6_ADDRESS_LEN  17
+               
+               int pos;
+               
+               if (idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr)
+                       || idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid address length passed.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+
+               for (pos = 1; ; pos++) {
+                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) !=0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get subjectAltName\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       /* it's the end condition of the loop. */
+                       if (!altname) {
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+
+                       if (check_typeofcertname(idtype, type) != 0) {
+                               /* wrong type - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
+               
+                       if (len == SUBJ_ALT_NAME_IPV4_ADDRESS_LEN) { /* IPv4 */
+                               if (idtype != IPSECDOI_ID_IPV4_ADDR) {
+                                       /* wrong IP address type - skip this one */                             
+                                       racoon_free(altname);
+                                       altname = NULL;
+                                       continue;
+                               }
+                       }
+#ifdef INET6
+                       else if (len == SUBJ_ALT_NAME_IPV6_ADDRESS_LEN) { /* IPv6 */
+                               if (idtype != IPSECDOI_ID_IPV6_ADDR) {
+                                       /* wrong IP address type - skip this one */                             
+                                       racoon_free(altname);
+                                       altname = NULL;
+                                       continue;
+                               }
+                       }
+#endif
+                       else {
+                               /* invalid IP address length in certificate - bad or bogus certificate */
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid IP address in certificate.\n");
+                               racoon_free(altname);
+                               altname = NULL;
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+                       
+                       /* compare the addresses */             
+                       error = memcmp(id, altname, idlen);
+                       racoon_free(altname);
+                       if (error != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "ID mismatched with subjectAltName.\n");
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+                       return 0;
+               }
+       }
+       case IPSECDOI_ID_FQDN:
+       case IPSECDOI_ID_USER_FQDN:
+       {
+               int pos;
+
+               for (pos = 1; ; pos++) {
+                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get subjectAltName\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       /* it's the end condition of the loop. */
+                       if (!altname) {
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+
+                       if (check_typeofcertname(idtype, type) != 0) {
+                               /* wrong general type - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
+
+                       if (idlen != strlen(altname)) {
+                               /* wrong length - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
+                       error = memcmp(id, altname, idlen);
+                       racoon_free(altname);
+                       if (error) {
+                               plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n");
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+                       return 0;
+               }
+       }
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Impropper ID type passed: %s.\n",
+                       s_ipsecdoi_ident(idtype));
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }       
+       /*NOTREACHED*/
+}
+
+#else  /* __APPLE__ */
+
+/*
+ * compare certificate name and ID value.
+ */
+static int
+oakley_check_certid(iph1)
+       struct ph1handle *iph1;
+{
+       struct ipsecdoi_id_b *id_b;
+       vchar_t *name = NULL;
+       char *altname = NULL;
+       int idlen, type;
+       int error;
+
+       if (iph1->id_p == NULL || iph1->cert_p == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n");
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+
+       id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
+       idlen = iph1->id_p->l - sizeof(*id_b);
+
+       switch (id_b->type) {
+       case IPSECDOI_ID_DER_ASN1_DN:
+               name = eay_get_x509asn1subjectname(&iph1->cert_p->cert);
+               if (!name) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get subjectName\n");
+                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+               }
+               if (idlen != name->l) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid ID length in phase 1.\n");
+                       vfree(name);
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               error = memcmp(id_b + 1, name->v, idlen);
+               vfree(name);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "ID mismatched with subjectAltName.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               return 0;
+       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV6_ADDR:
+       {
+               /*
+                * converting to binary from string because openssl return
+                * a string even if object is a binary.
+                * XXX fix it !  access by ASN.1 directly without.
+                */
+               struct addrinfo hints, *res;
+               caddr_t a = NULL;
+               int pos;
+
+               for (pos = 1; ; pos++) {
+                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
+                                       &altname, &type, pos) !=0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get subjectAltName\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       /* it's the end condition of the loop. */
+                       if (!altname) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no proper subjectAltName.\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       if (check_typeofcertname(id_b->type, type) == 0)
+                               break;
+
+                       /* next name */
+                       racoon_free(altname);
+                       altname = NULL;
+               }
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = PF_UNSPEC;
+               hints.ai_socktype = SOCK_RAW;
+               hints.ai_flags = AI_NUMERICHOST;
+               error = getaddrinfo(altname, NULL, &hints, &res);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no proper subjectAltName.\n");
+                       racoon_free(altname);
+                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+               }
+               switch (res->ai_family) {
+               case AF_INET:
+                       a = (caddr_t)&((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       a = (caddr_t)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr;
+                       break;
+#endif
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "family not supported: %d.\n", res->ai_family);
+                       racoon_free(altname);
+                       freeaddrinfo(res);
+                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+               }
+               error = memcmp(id_b + 1, a, idlen);
+               freeaddrinfo(res);
+               vfree(name);
+               if (error != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "ID mismatched with subjectAltName.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               return 0;
+       }
+       case IPSECDOI_ID_FQDN:
+       case IPSECDOI_ID_USER_FQDN:
+       {
+               int pos;
+
+               for (pos = 1; ; pos++) {
+                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
+                                       &altname, &type, pos) != 0){
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get subjectAltName\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       /* it's the end condition of the loop. */
+                       if (!altname) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "no proper subjectAltName.\n");
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+
+                       if (check_typeofcertname(id_b->type, type) == 0)
+                               break;
+
+                       /* next name */
+                       racoon_free(altname);
+                       altname = NULL;
+               }
+               if (idlen != strlen(altname)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Invalid ID length in phase 1.\n");
+                       racoon_free(altname);
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               if (check_typeofcertname(id_b->type, type) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "ID type mismatched. ID: %s CERT: %s.\n",
+                               s_ipsecdoi_ident(id_b->type),
+                               s_ipsecdoi_ident(type));
+                       racoon_free(altname);
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               error = memcmp(id_b + 1, altname, idlen);
+               if (error) {
+                       plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n");
+                       racoon_free(altname);
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
+               racoon_free(altname);
+               return 0;
+       }
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Impropper ID type passed: %s.\n",
+                       s_ipsecdoi_ident(id_b->type));
+               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+       }
+       /*NOTREACHED*/
+}
+
+#endif /* __APPLE__ */
+
+static int
+check_typeofcertname(doi, genid)
+       int doi, genid;
+{
+       switch (doi) {
+       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+       case IPSECDOI_ID_IPV6_ADDR:
+       case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+       case IPSECDOI_ID_IPV4_ADDR_RANGE:
+       case IPSECDOI_ID_IPV6_ADDR_RANGE:
+               if (genid != GENT_IPADD)
+                       return -1;
+               return 0;
+       case IPSECDOI_ID_FQDN:
+               if (genid != GENT_DNS)
+                       return -1;
+               return 0;
+       case IPSECDOI_ID_USER_FQDN:
+               if (genid != GENT_EMAIL)
+                       return -1;
+               return 0;
+       case IPSECDOI_ID_DER_ASN1_DN: /* should not be passed to this function*/
+       case IPSECDOI_ID_DER_ASN1_GN:
+       case IPSECDOI_ID_KEY_ID:
+       default:
+               return -1;
+       }
+       /*NOTREACHED*/
+}
+
+/*
+ * save certificate including certificate type.
+ */
+int
+oakley_savecert(iph1, gen)
+       struct ph1handle *iph1;
+       struct isakmp_gen *gen;
+{
+       cert_t **c;
+       u_int8_t type;
+       STACK_OF(X509) *certs=NULL;
+       PKCS7 *p7;
+
+       type = *(u_int8_t *)(gen + 1) & 0xff;
+
+       switch (type) {
+       case ISAKMP_CERT_DNS:
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "CERT payload is unnecessary in DNSSEC. "
+                       "ignore this CERT payload.\n");
+               return 0;
+       case ISAKMP_CERT_PKCS7:
+       case ISAKMP_CERT_PGP:
+       case ISAKMP_CERT_X509SIGN:
+       case ISAKMP_CERT_KERBEROS:
+       case ISAKMP_CERT_SPKI:
+               c = &iph1->cert_p;
+               break;
+       case ISAKMP_CERT_CRL:
+               c = &iph1->crl_p;
+               break;
+       case ISAKMP_CERT_X509KE:
+       case ISAKMP_CERT_X509ATTR:
+       case ISAKMP_CERT_ARL:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "No supported such CERT type %d\n", type);
+               return -1;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid CERT type %d\n", type);
+               return -1;
+       }
+
+       /* XXX choice the 1th cert, ignore after the cert. */ 
+       /* XXX should be processed. */
+       if (*c) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "ignore 2nd CERT payload.\n");
+               return 0;
+       }
+
+       if (type == ISAKMP_CERT_PKCS7) {
+               u_char *bp;
+               int i;
+
+               /* Skip the header */
+               bp = (u_char *)(gen + 1);
+               /* And the first byte is the certificate type, 
+                * we know that already
+                */
+               bp++;
+               p7 = d2i_PKCS7(NULL, (void *)&bp, 
+                   ntohs(gen->len) - sizeof(*gen) - 1);
+
+               if (!p7) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Failed to parse PKCS#7 CERT.\n");
+                       return -1;
+               }
+
+               /* Copied this from the openssl pkcs7 application;
+                * there"s little by way of documentation for any of
+                * it. I can only presume it"s correct.
+                */
+               
+               i = OBJ_obj2nid(p7->type);
+               switch (i) {
+               case NID_pkcs7_signed:
+                       certs=p7->d.sign->cert;
+                       break;
+               case NID_pkcs7_signedAndEnveloped:
+                       certs=p7->d.signed_and_enveloped->cert;
+                       break;
+               default:
+                        break;
+               }
+
+               if (!certs) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "CERT PKCS#7 bundle contains no certs.\n");
+                       PKCS7_free(p7);
+                       return -1;
+               }
+
+               for (i = 0; i < sk_X509_num(certs); i++) {
+                       int len;
+                       u_char *bp;
+                       X509 *cert = sk_X509_value(certs,i);
+
+                       plog(LLV_DEBUG, LOCATION, NULL, 
+                            "Trying PKCS#7 cert %d.\n", i);
+
+                       /* We'll just try each cert in turn */
+                       *c = save_certx509(cert);
+
+                       if (!*c) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                    "Failed to get CERT buffer.\n");
+                               continue;
+                       }
+
+                       /* Ignore cert if it doesn't match identity
+                        * XXX If verify cert is disabled, we still just take
+                        * the first certificate....
+                        */
+                       if(iph1->rmconf->verify_cert &&
+                          oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) {
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                    "Discarding CERT: does not match ID.\n");
+                               oakley_delcert((*c));
+                               *c = NULL;
+                               continue;
+                       }
+
+                       {
+                               char *p = eay_get_x509text(&(*c)->cert);
+                               plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n");
+                               plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+                               plog(LLV_DEBUG, LOCATION, NULL, "%s", 
+                                    p ? p : "\n");
+                               racoon_free(p);
+                       }
+                       break;
+               }
+               PKCS7_free(p7);
+
+       } else {
+               *c = save_certbuf(gen);
+               if (!*c) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Failed to get CERT buffer.\n");
+                       return -1;
+               }
+
+               switch ((*c)->type) {
+               case ISAKMP_CERT_DNS:
+                       plog(LLV_WARNING, LOCATION, NULL,
+                            "CERT payload is unnecessary in DNSSEC. "
+                            "ignore it.\n");
+                       return 0;
+               case ISAKMP_CERT_PGP:
+               case ISAKMP_CERT_X509SIGN:
+               case ISAKMP_CERT_KERBEROS:
+               case ISAKMP_CERT_SPKI:
+                       /* Ignore cert if it doesn't match identity
+                        * XXX If verify cert is disabled, we still just take
+                        * the first certificate....
+                        */
+                       if(iph1->rmconf->verify_cert &&
+                          oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)){
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                    "Discarding CERT: does not match ID.\n");
+                               oakley_delcert((*c));
+                               *c = NULL;
+                               return 0;
+                       }
+
+                       {
+                               char *p = eay_get_x509text(&(*c)->cert);
+                               plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n");
+                               plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+                               plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
+                               racoon_free(p);
+                       }
+                       break;
+               case ISAKMP_CERT_CRL:
+                       plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n");
+                       plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+                       break;
+               case ISAKMP_CERT_X509KE:
+               case ISAKMP_CERT_X509ATTR:
+               case ISAKMP_CERT_ARL:
+               default:
+                       /* XXX */
+                       oakley_delcert((*c));
+                       *c = NULL;
+                       return 0;
+               }
+       }
+       
+       return 0;
+}
+
+/*
+ * save certificate including certificate type.
+ */
+int
+oakley_savecr(iph1, gen)
+       struct ph1handle *iph1;
+       struct isakmp_gen *gen;
+{
+       cert_t **c;
+       u_int8_t type;
+
+       type = *(u_int8_t *)(gen + 1) & 0xff;
+
+       switch (type) {
+       case ISAKMP_CERT_DNS:
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "CERT payload is unnecessary in DNSSEC\n");
+               /*FALLTHRU*/
+       case ISAKMP_CERT_PKCS7:
+       case ISAKMP_CERT_PGP:
+       case ISAKMP_CERT_X509SIGN:
+       case ISAKMP_CERT_KERBEROS:
+       case ISAKMP_CERT_SPKI:
+               c = &iph1->cr_p;
+               break;
+       case ISAKMP_CERT_X509KE:
+       case ISAKMP_CERT_X509ATTR:
+       case ISAKMP_CERT_ARL:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "No supported such CR type %d\n", type);
+               return -1;
+       case ISAKMP_CERT_CRL:
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid CR type %d\n", type);
+               return -1;
+       }
+
+       *c = save_certbuf(gen);
+       if (!*c) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Failed to get CR buffer.\n");
+               return -1;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n");
+       plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+
+       return 0;
+}
+
+static cert_t *
+save_certbuf(gen)
+       struct isakmp_gen *gen;
+{
+       cert_t *new;
+
+       new = oakley_newcert();
+       if (!new) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Failed to get CERT buffer.\n");
+               return NULL;
+       }
+
+       new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen));
+       if (new->pl == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Failed to copy CERT from packet.\n");
+               oakley_delcert(new);
+               new = NULL;
+               return NULL;
+       }
+       memcpy(new->pl->v, gen + 1, new->pl->l);
+       new->type = new->pl->v[0] & 0xff;
+       new->cert.v = new->pl->v + 1;
+       new->cert.l = new->pl->l - 1;
+
+       return new;
+}
+
+static cert_t *
+save_certx509(cert)
+       X509 *cert;
+{
+       cert_t *new;
+        int len;
+        u_char *bp;
+
+       new = oakley_newcert();
+       if (!new) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Failed to get CERT buffer.\n");
+               return NULL;
+       }
+
+        len = i2d_X509(cert, NULL);
+       new->pl = vmalloc(len);
+       if (new->pl == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Failed to copy CERT from packet.\n");
+               oakley_delcert(new);
+               new = NULL;
+               return NULL;
+       }
+        bp = (u_char *) new->pl->v;
+        len = i2d_X509(cert, &bp);
+       new->type = ISAKMP_CERT_X509SIGN;
+       new->cert.v = new->pl->v;
+       new->cert.l = new->pl->l;
+
+       return new;
+}
+
+/*
+ * get my CR.
+ * NOTE: No Certificate Authority field is included to CR payload at the
+ * moment. Becuase any certificate authority are accepted without any check.
+ * The section 3.10 in RFC2408 says that this field SHOULD not be included,
+ * if there is no specific certificate authority requested.
+ */
+vchar_t *
+oakley_getcr(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf;
+
+       buf = vmalloc(1);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cr buffer\n");
+               return NULL;
+       }
+       buf->v[0] = iph1->rmconf->certtype;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n",
+               s_isakmp_certtype(iph1->rmconf->certtype));
+       if (buf->l > 1)
+               plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       return buf;
+}
+
+/*
+ * check peer's CR.
+ */
+int
+oakley_checkcr(iph1)
+       struct ph1handle *iph1;
+{
+       if (iph1->cr_p == NULL)
+               return 0;
+
+       plog(LLV_DEBUG, LOCATION, iph1->remote,
+               "peer transmitted CR: %s\n",
+               s_isakmp_certtype(iph1->cr_p->type));
+
+       if (iph1->cr_p->type != iph1->rmconf->certtype) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "such a cert type isn't supported: %d\n",
+                       (char)iph1->cr_p->type);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * check to need CR payload.
+ */
+int
+oakley_needcr(type)
+       int type;
+{
+       switch (type) {
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+#endif
+               return 1;
+       default:
+               return 0;
+       }
+       /*NOTREACHED*/
+}
+
+/*
+ * compute SKEYID
+ * see seciton 5. Exchanges in RFC 2409
+ * psk: SKEYID = prf(pre-shared-key, Ni_b | Nr_b)
+ * sig: SKEYID = prf(Ni_b | Nr_b, g^ir)
+ * enc: SKEYID = prf(H(Ni_b | Nr_b), CKY-I | CKY-R)
+ */
+int
+oakley_skeyid(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf = NULL, *bp;
+       char *p;
+       int len;
+       int error = -1;
+
+       /* SKEYID */
+       switch(iph1->approval->authmethod) {
+       case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+#ifdef __APPLE__
+       if (iph1->rmconf->shared_secret) {
+
+                       switch (iph1->rmconf->secrettype) {
+                               case SECRETTYPE_KEY:
+                                       /* in psk file - use KEY from remote configuration to locate it */
+                                       iph1->authstr = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1);
+                                       break;
+                               case SECRETTYPE_KEYCHAIN:
+                                       /* in the system keychain */
+                                       iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL);
+                                       break;
+                               case SECRETTYPE_KEYCHAIN_BY_ID:
+                                       /* in the system keychain - use peer id */
+                                       iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, iph1->id_p);
+                                       break;
+                               case SECRETTYPE_USE:
+                                       /* in the remote configuration */
+                               default:
+                                       iph1->authstr = vdup(iph1->rmconf->shared_secret);
+                       }
+
+               }
+               else
+#endif
+               if (iph1->etype != ISAKMP_ETYPE_IDENT) {
+                       iph1->authstr = getpskbyname(iph1->id_p);
+                       if (iph1->authstr == NULL) {
+                               if (iph1->rmconf->verify_identifier) {
+                                       plog(LLV_ERROR, LOCATION, iph1->remote,
+                                               "couldn't find the pskey.\n");
+                                       goto end;
+                               }
+                               plog(LLV_NOTIFY, LOCATION, iph1->remote,
+                                       "couldn't find the proper pskey, "
+                                       "try to get one by the peer's address.\n");
+                       }
+               }
+               if (iph1->authstr == NULL) {
+                       /*
+                        * If the exchange type is the main mode or if it's
+                        * failed to get the psk by ID, racoon try to get
+                        * the psk by remote IP address.
+                        * It may be nonsense.
+                        */
+                       iph1->authstr = getpskbyaddr(iph1->remote);
+                       if (iph1->authstr == NULL) {
+                               plog(LLV_ERROR, LOCATION, iph1->remote,
+                                       "couldn't find the pskey for %s.\n",
+                                       saddrwop2str(iph1->remote));
+                               goto end;
+                       }
+               }
+               plog(LLV_DEBUG, LOCATION, NULL, "the psk found.\n");
+               /* should be secret PSK */
+               plog(LLV_DEBUG2, LOCATION, NULL, "psk: ");
+               plogdump(LLV_DEBUG2, iph1->authstr->v, iph1->authstr->l);
+
+               len = iph1->nonce->l + iph1->nonce_p->l;
+               buf = vmalloc(len);
+               if (buf == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get skeyid buffer\n");
+                       goto end;
+               }
+               p = buf->v;
+
+               bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p);
+               plog(LLV_DEBUG, LOCATION, NULL, "nonce 1: ");
+               plogdump(LLV_DEBUG, bp->v, bp->l);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce);
+               plog(LLV_DEBUG, LOCATION, NULL, "nonce 2: ");
+               plogdump(LLV_DEBUG, bp->v, bp->l);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               iph1->skeyid = oakley_prf(iph1->authstr, buf, iph1);
+               if (iph1->skeyid == NULL)
+                       goto end;
+               break;
+
+       case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+       case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+       case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+#endif
+#ifdef HAVE_GSSAPI
+       case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+#endif
+               len = iph1->nonce->l + iph1->nonce_p->l;
+               buf = vmalloc(len);
+               if (buf == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get nonce buffer\n");
+                       goto end;
+               }
+               p = buf->v;
+
+               bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p);
+               plog(LLV_DEBUG, LOCATION, NULL, "nonce1: ");
+               plogdump(LLV_DEBUG, bp->v, bp->l);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce);
+               plog(LLV_DEBUG, LOCATION, NULL, "nonce2: ");
+               plogdump(LLV_DEBUG, bp->v, bp->l);
+               memcpy(p, bp->v, bp->l);
+               p += bp->l;
+
+               iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1);
+               if (iph1->skeyid == NULL)
+                       goto end;
+               break;
+       case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+       case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "not supported authentication method %s\n",
+                       s_oakley_attr_method(iph1->approval->authmethod));
+               goto end;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid authentication method %d\n",
+                       iph1->approval->authmethod);
+               goto end;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "SKEYID computed:\n");
+       plogdump(LLV_DEBUG, iph1->skeyid->v, iph1->skeyid->l);
+
+       error = 0;
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       return error;
+}
+
+/*
+ * compute SKEYID_[dae]
+ * see seciton 5. Exchanges in RFC 2409
+ * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0)
+ * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1)
+ * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2)
+ */
+int
+oakley_skeyid_dae(iph1)
+       struct ph1handle *iph1;
+{
+       vchar_t *buf = NULL;
+       char *p;
+       int len;
+       int error = -1;
+
+       if (iph1->skeyid == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n");
+               goto end;
+       }
+
+       /* SKEYID D */
+       /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */
+       len = iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get skeyid buffer\n");
+               goto end;
+       }
+       p = buf->v;
+
+       memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l);
+       p += iph1->dhgxy->l;
+       memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       *p = 0;
+       iph1->skeyid_d = oakley_prf(iph1->skeyid, buf, iph1);
+       if (iph1->skeyid_d == NULL)
+               goto end;
+
+       vfree(buf);
+       buf = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_d computed:\n");
+       plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid->l);
+
+       /* SKEYID A */
+       /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */
+       len = iph1->skeyid_d->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get skeyid buffer\n");
+               goto end;
+       }
+       p = buf->v;
+       memcpy(p, iph1->skeyid_d->v, iph1->skeyid_d->l);
+       p += iph1->skeyid_d->l;
+       memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l);
+       p += iph1->dhgxy->l;
+       memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       *p = 1;
+       iph1->skeyid_a = oakley_prf(iph1->skeyid, buf, iph1);
+       if (iph1->skeyid_a == NULL)
+               goto end;
+
+       vfree(buf);
+       buf = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_a computed:\n");
+       plogdump(LLV_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l);
+
+       /* SKEYID E */
+       /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */
+       len = iph1->skeyid_a->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get skeyid buffer\n");
+               goto end;
+       }
+       p = buf->v;
+       memcpy(p, iph1->skeyid_a->v, iph1->skeyid_a->l);
+       p += iph1->skeyid_a->l;
+       memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l);
+       p += iph1->dhgxy->l;
+       memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t));
+       p += sizeof(cookie_t);
+       *p = 2;
+       iph1->skeyid_e = oakley_prf(iph1->skeyid, buf, iph1);
+       if (iph1->skeyid_e == NULL)
+               goto end;
+
+       vfree(buf);
+       buf = NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_e computed:\n");
+       plogdump(LLV_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l);
+
+       error = 0;
+
+end:
+       if (buf != NULL)
+               vfree(buf);
+       return error;
+}
+
+/*
+ * compute final encryption key.
+ * see Appendix B.
+ */
+int
+oakley_compute_enckey(iph1)
+       struct ph1handle *iph1;
+{
+       u_int keylen, prflen;
+       int error = -1;
+
+       /* RFC2409 p39 */
+       keylen = alg_oakley_encdef_keylen(iph1->approval->enctype,
+                                       iph1->approval->encklen);
+       if (keylen == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algoritym %d, "
+                       "or invalid key length %d.\n",
+                       iph1->approval->enctype,
+                       iph1->approval->encklen);
+               goto end;
+       }
+       iph1->key = vmalloc(keylen >> 3);
+       if (iph1->key == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get key buffer\n");
+               goto end;
+       }
+
+       /* set prf length */
+       prflen = alg_oakley_hashdef_hashlen(iph1->approval->hashtype);
+       if (prflen == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid hash type %d.\n", iph1->approval->hashtype);
+               goto end;
+       }
+
+       /* see isakmp-oakley-08 5.3. */
+       if (iph1->key->l <= iph1->skeyid_e->l) {
+               /*
+                * if length(Ka) <= length(SKEYID_e)
+                *      Ka = first length(K) bit of SKEYID_e
+                */
+               memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l);
+       } else {
+               vchar_t *buf = NULL, *res = NULL;
+               u_char *p, *ep;
+               int cplen;
+               int subkey;
+
+               /*
+                * otherwise,
+                *      Ka = K1 | K2 | K3
+                * where
+                *      K1 = prf(SKEYID_e, 0)
+                *      K2 = prf(SKEYID_e, K1)
+                *      K3 = prf(SKEYID_e, K2)
+                */
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "len(SKEYID_e) < len(Ka) (%zu < %zu), "
+                       "generating long key (Ka = K1 | K2 | ...)\n",
+                       iph1->skeyid_e->l, iph1->key->l);
+
+               if ((buf = vmalloc(prflen >> 3)) == 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get key buffer\n");
+                       goto end;
+               }
+               p = (u_char *)iph1->key->v;
+               ep = p + iph1->key->l;
+
+               subkey = 1;
+               while (p < ep) {
+                       if (p == (u_char *)iph1->key->v) {
+                               /* just for computing K1 */
+                               buf->v[0] = 0;
+                               buf->l = 1;
+                       }
+                       res = oakley_prf(iph1->skeyid_e, buf, iph1);
+                       if (res == NULL) {
+                               vfree(buf);
+                               goto end;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "compute intermediate encryption key K%d\n",
+                               subkey);
+                       plogdump(LLV_DEBUG, buf->v, buf->l);
+                       plogdump(LLV_DEBUG, res->v, res->l);
+
+                       cplen = (res->l < ep - p) ? res->l : ep - p;
+                       memcpy(p, res->v, cplen);
+                       p += cplen;
+
+                       buf->l = prflen >> 3;   /* to cancel K1 speciality */
+                       if (res->l != buf->l) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "internal error: res->l=%zu buf->l=%zu\n",
+                                       res->l, buf->l);
+                               vfree(res);
+                               vfree(buf);
+                               goto end;
+                       }
+                       memcpy(buf->v, res->v, res->l);
+                       vfree(res);
+                       subkey++;
+               }
+
+               vfree(buf);
+       }
+
+       /*
+        * don't check any weak key or not.
+        * draft-ietf-ipsec-ike-01.txt Appendix B.
+        * draft-ietf-ipsec-ciph-aes-cbc-00.txt Section 2.3.
+        */
+#if 0
+       /* weakkey check */
+       if (iph1->approval->enctype > ARRAYLEN(oakley_encdef)
+        || oakley_encdef[iph1->approval->enctype].weakkey == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "encryption algoritym %d isn't supported.\n",
+                       iph1->approval->enctype);
+               goto end;
+       }
+       if ((oakley_encdef[iph1->approval->enctype].weakkey)(iph1->key)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "weakkey was generated.\n");
+               goto end;
+       }
+#endif
+
+       plog(LLV_DEBUG, LOCATION, NULL, "final encryption key computed:\n");
+       plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l);
+
+       error = 0;
+
+end:
+       return error;
+}
+
+/* allocated new buffer for CERT */
+cert_t *
+oakley_newcert()
+{
+       cert_t *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get cert's buffer\n");
+               return NULL;
+       }
+
+       new->pl = NULL;
+
+       return new;
+}
+
+/* delete buffer for CERT */
+void
+oakley_delcert(cert)
+       cert_t *cert;
+{
+       if (!cert)
+               return;
+       if (cert->pl)
+               VPTRINIT(cert->pl);
+       racoon_free(cert);
+}
+
+/*
+ * compute IV and set to ph1handle
+ *     IV = hash(g^xi | g^xr)
+ * see 4.1 Phase 1 state in draft-ietf-ipsec-ike.
+ */
+int
+oakley_newiv(iph1)
+       struct ph1handle *iph1;
+{
+       struct isakmp_ivm *newivm = NULL;
+       vchar_t *buf = NULL, *bp;
+       char *p;
+       int len;
+
+       /* create buffer */
+       len = iph1->dhpub->l + iph1->dhpub_p->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get iv buffer\n");
+               return -1;
+       }
+
+       p = buf->v;
+
+       bp = (iph1->side == INITIATOR ? iph1->dhpub : iph1->dhpub_p);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       bp = (iph1->side == INITIATOR ? iph1->dhpub_p : iph1->dhpub);
+       memcpy(p, bp->v, bp->l);
+       p += bp->l;
+
+       /* allocate IVm */
+       newivm = racoon_calloc(1, sizeof(struct isakmp_ivm));
+       if (newivm == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get iv buffer\n");
+               vfree(buf);
+               return -1;
+       }
+
+       /* compute IV */
+       newivm->iv = oakley_hash(buf, iph1);
+       if (newivm->iv == NULL) {
+               vfree(buf);
+               oakley_delivm(newivm);
+               return -1;
+       }
+
+       /* adjust length of iv */
+       newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype);
+       if (newivm->iv->l == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algoriym %d.\n",
+                       iph1->approval->enctype);
+               vfree(buf);
+               oakley_delivm(newivm);
+               return -1;
+       }
+
+       /* create buffer to save iv */
+       if ((newivm->ive = vdup(newivm->iv)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "vdup (%s)\n", strerror(errno));
+               vfree(buf);
+               oakley_delivm(newivm);
+               return -1;
+       }
+
+       vfree(buf);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "IV computed:\n");
+       plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l);
+
+       iph1->ivm = newivm;
+
+       return 0;
+}
+
+/*
+ * compute IV for the payload after phase 1.
+ * It's not limited for phase 2.
+ * if pahse 1 was encrypted.
+ *     IV = hash(last CBC block of Phase 1 | M-ID)
+ * if phase 1 was not encrypted.
+ *     IV = hash(phase 1 IV | M-ID)
+ * see 4.2 Phase 2 state in draft-ietf-ipsec-ike.
+ */
+struct isakmp_ivm *
+oakley_newiv2(iph1, msgid)
+       struct ph1handle *iph1;
+       u_int32_t msgid;
+{
+       struct isakmp_ivm *newivm = NULL;
+       vchar_t *buf = NULL;
+       char *p;
+       int len;
+       int error = -1;
+
+       /* create buffer */
+       len = iph1->ivm->iv->l + sizeof(msgid_t);
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get iv buffer\n");
+               goto end;
+       }
+
+       p = buf->v;
+
+       memcpy(p, iph1->ivm->iv->v, iph1->ivm->iv->l);
+       p += iph1->ivm->iv->l;
+
+       memcpy(p, &msgid, sizeof(msgid));
+
+       plog(LLV_DEBUG, LOCATION, NULL, "compute IV for phase2\n");
+       plog(LLV_DEBUG, LOCATION, NULL, "phase1 last IV:\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* allocate IVm */
+       newivm = racoon_calloc(1, sizeof(struct isakmp_ivm));
+       if (newivm == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get iv buffer\n");
+               goto end;
+       }
+
+       /* compute IV */
+       if ((newivm->iv = oakley_hash(buf, iph1)) == NULL)
+               goto end;
+
+       /* adjust length of iv */
+       newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype);
+       if (newivm->iv->l == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algoriym %d.\n",
+                       iph1->approval->enctype);
+               goto end;
+       }
+
+       /* create buffer to save new iv */
+       if ((newivm->ive = vdup(newivm->iv)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "vdup (%s)\n", strerror(errno));
+               goto end;
+       }
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "phase2 IV computed:\n");
+       plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l);
+
+end:
+       if (error && newivm != NULL){
+               oakley_delivm(newivm);
+               newivm=NULL;
+       }
+       if (buf != NULL)
+               vfree(buf);
+       return newivm;
+}
+
+void
+oakley_delivm(ivm)
+       struct isakmp_ivm *ivm;
+{
+       if (ivm == NULL)
+               return;
+
+       if (ivm->iv != NULL)
+               vfree(ivm->iv);
+       if (ivm->ive != NULL)
+               vfree(ivm->ive);
+       racoon_free(ivm);
+
+       return;
+}
+
+/*
+ * decrypt packet.
+ *   save new iv and old iv.
+ */
+vchar_t *
+oakley_do_decrypt(iph1, msg, ivdp, ivep)
+       struct ph1handle *iph1;
+       vchar_t *msg, *ivdp, *ivep;
+{
+       vchar_t *buf = NULL, *new = NULL;
+       char *pl;
+       int len;
+       u_int8_t padlen;
+       int blen;
+       int error = -1;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "begin decryption.\n");
+
+       blen = alg_oakley_encdef_blocklen(iph1->approval->enctype);
+       if (blen == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algoriym %d.\n",
+                       iph1->approval->enctype);
+               goto end;
+       }
+
+       /* save IV for next, but not sync. */
+       memset(ivep->v, 0, ivep->l);
+       memcpy(ivep->v, (caddr_t)&msg->v[msg->l - blen], blen);
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "IV was saved for next processing:\n");
+       plogdump(LLV_DEBUG, ivep->v, ivep->l);
+
+       pl = msg->v + sizeof(struct isakmp);
+
+       len = msg->l - sizeof(struct isakmp);
+
+       /* create buffer */
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to decrypt.\n");
+               goto end;
+       }
+       memcpy(buf->v, pl, len);
+
+       /* do decrypt */
+       new = alg_oakley_encdef_decrypt(iph1->approval->enctype,
+                                       buf, iph1->key, ivdp);
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "decryption %d failed.\n", iph1->approval->enctype);
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "with key:\n");
+       plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l);
+
+       vfree(buf);
+       buf = NULL;
+       if (new == NULL)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "decrypted payload by IV:\n");
+       plogdump(LLV_DEBUG, ivdp->v, ivdp->l);
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "decrypted payload, but not trimed.\n");
+       plogdump(LLV_DEBUG, new->v, new->l);
+
+       /* get padding length */
+       if (lcconf->pad_excltail)
+               padlen = new->v[new->l - 1] + 1;
+       else
+               padlen = new->v[new->l - 1];
+       plog(LLV_DEBUG, LOCATION, NULL, "padding len=%u\n", padlen);
+
+       /* trim padding */
+       if (lcconf->pad_strict) {
+               if (padlen > new->l) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid padding len=%u, buflen=%zu.\n",
+                               padlen, new->l);
+                       plogdump(LLV_ERROR, new->v, new->l);
+                       goto end;
+               }
+               new->l -= padlen;
+               plog(LLV_DEBUG, LOCATION, NULL, "trimmed padding\n");
+       } else {
+               plog(LLV_DEBUG, LOCATION, NULL, "skip to trim padding.\n");
+       }
+
+       /* create new buffer */
+       len = sizeof(struct isakmp) + new->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to decrypt.\n");
+               goto end;
+       }
+       memcpy(buf->v, msg->v, sizeof(struct isakmp));
+       memcpy(buf->v + sizeof(struct isakmp), new->v, new->l);
+       ((struct isakmp *)buf->v)->len = htonl(buf->l);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "decrypted.\n");
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+#ifdef HAVE_PRINT_ISAKMP_C
+       isakmp_printpacket(buf, iph1->remote, iph1->local, 1);
+#endif
+
+       error = 0;
+
+end:
+       if (error && buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+       if (new != NULL)
+               vfree(new);
+
+       return buf;
+}
+
+/*
+ * encrypt packet.
+ */
+vchar_t *
+oakley_do_encrypt(iph1, msg, ivep, ivp)
+       struct ph1handle *iph1;
+       vchar_t *msg, *ivep, *ivp;
+{
+       vchar_t *buf = 0, *new = 0;
+       char *pl;
+       int len;
+       u_int padlen;
+       int blen;
+       int error = -1;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "begin encryption.\n");
+
+       /* set cbc block length */
+       blen = alg_oakley_encdef_blocklen(iph1->approval->enctype);
+       if (blen == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algoriym %d.\n",
+                       iph1->approval->enctype);
+               goto end;
+       }
+
+       pl = msg->v + sizeof(struct isakmp);
+       len = msg->l - sizeof(struct isakmp);
+
+       /* add padding */
+       padlen = oakley_padlen(len, blen);
+       plog(LLV_DEBUG, LOCATION, NULL, "pad length = %u\n", padlen);
+
+       /* create buffer */
+       buf = vmalloc(len + padlen);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to encrypt.\n");
+               goto end;
+       }
+        if (padlen) {
+                int i;
+               char *p = &buf->v[len];
+               if (lcconf->pad_random) {
+                       for (i = 0; i < padlen; i++)
+                               *p++ = eay_random() & 0xff;
+               }
+        }
+        memcpy(buf->v, pl, len);
+
+       /* make pad into tail */
+       if (lcconf->pad_excltail)
+               buf->v[len + padlen - 1] = padlen - 1;
+       else
+               buf->v[len + padlen - 1] = padlen;
+
+       plogdump(LLV_DEBUG, buf->v, buf->l);
+
+       /* do encrypt */
+       new = alg_oakley_encdef_encrypt(iph1->approval->enctype,
+                                       buf, iph1->key, ivep);
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "encryption %d failed.\n", iph1->approval->enctype);
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "with key:\n");
+       plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l);
+
+       vfree(buf);
+       buf = NULL;
+       if (new == NULL)
+               goto end;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "encrypted payload by IV:\n");
+       plogdump(LLV_DEBUG, ivep->v, ivep->l);
+
+       /* save IV for next */
+       memset(ivp->v, 0, ivp->l);
+       memcpy(ivp->v, (caddr_t)&new->v[new->l - blen], blen);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "save IV for next:\n");
+       plogdump(LLV_DEBUG, ivp->v, ivp->l);
+
+       /* create new buffer */
+       len = sizeof(struct isakmp) + new->l;
+       buf = vmalloc(len);
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to encrypt.\n");
+               goto end;
+       }
+       memcpy(buf->v, msg->v, sizeof(struct isakmp));
+       memcpy(buf->v + sizeof(struct isakmp), new->v, new->l);
+       ((struct isakmp *)buf->v)->len = htonl(buf->l);
+
+       error = 0;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "encrypted.\n");
+
+end:
+       if (error && buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+       if (new != NULL)
+               vfree(new);
+
+       return buf;
+}
+
+/* culculate padding length */
+static int
+oakley_padlen(len, base)
+       int len, base;
+{
+       int padlen;
+
+       padlen = base - len % base;
+
+       if (lcconf->pad_randomlen)
+               padlen += ((eay_random() % (lcconf->pad_maxsize + 1) + 1) *
+                   base);
+
+       return padlen;
+}
+
+#ifdef __APPLE__
+/* -----------------------------------------------------------------------------
+The base-64 encoding packs three 8-bit bytes into four 7-bit ASCII
+characters.  If the number of bytes in the original data isn't divisable
+by three, "=" characters are used to pad the encoded data.  The complete
+set of characters used in base-64 are:
+     'A'..'Z' => 00..25
+     'a'..'z' => 26..51
+     '0'..'9' => 52..61
+     '+'      => 62
+     '/'      => 63
+     '='      => pad
+
+----------------------------------------------------------------------------- */
+static const signed char base64_DecodeTable[128] = {
+    /* 000 */ -1, -1, -1, -1, -1, -1, -1, -1,
+    /* 010 */ -1, -1, -1, -1, -1, -1, -1, -1,
+    /* 020 */ -1, -1, -1, -1, -1, -1, -1, -1,
+    /* 030 */ -1, -1, -1, -1, -1, -1, -1, -1,
+    /* ' ' */ -1, -1, -1, -1, -1, -1, -1, -1,
+    /* '(' */ -1, -1, -1, 62, -1, -1, -1, 63,
+    /* '0' */ 52, 53, 54, 55, 56, 57, 58, 59,
+    /* '8' */ 60, 61, -1, -1, -1,  0, -1, -1,
+    /* '@' */ -1,  0,  1,  2,  3,  4,  5,  6,
+    /* 'H' */  7,  8,  9, 10, 11, 12, 13, 14,
+    /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22,
+    /* 'X' */ 23, 24, 25, -1, -1, -1, -1, -1,
+    /* '`' */ -1, 26, 27, 28, 29, 30, 31, 32,
+    /* 'h' */ 33, 34, 35, 36, 37, 38, 39, 40,
+    /* 'p' */ 41, 42, 43, 44, 45, 46, 47, 48,
+    /* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1
+};
+
+static int base64toCFData(vchar_t *textin, CFDataRef *dataRef)
+{
+    uint8_t    *tmpbuf;
+    uint8_t            c;
+    int                tmpbufpos = 0;
+    int                numeq = 0;
+    int                acc = 0;
+    int                cntr = 0;
+    uint8_t            *textcur = textin->v;
+    int                        len = textin->l;
+    int                i;
+
+    tmpbuf = malloc(len);              // len of result will be less than encoded len
+    if (tmpbuf == NULL) {
+       yyerror("memory error - could not allocate buffer for certificate reference conversion from base-64.");
+       return -1;
+    }
+       
+    for (i = 0; i < len; i++) {
+        c = *(textcur++);
+        if (c == '=')
+            numeq++;
+        else if (!isspace(c))
+            numeq = 0;
+        if (base64_DecodeTable[c] < 0)
+            continue;
+        cntr++;
+        acc <<= 6;
+        acc += base64_DecodeTable[c];
+        if (0 == (cntr & 0x3)) {
+            tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff;
+            if (numeq < 2)
+                tmpbuf[tmpbufpos++] = (acc >> 8) & 0xff;
+            if (numeq < 1)
+                tmpbuf[tmpbufpos++] = acc & 0xff;
+        }
+    }
+    *dataRef = CFDataCreate(NULL, tmpbuf, tmpbufpos);
+    free(tmpbuf);
+       if (*dataRef)
+               return 0;
+       else
+               return -1;
+  
+}
+#endif
diff --git a/ipsec-tools/racoon/oakley.h b/ipsec-tools/racoon/oakley.h
new file mode 100644 (file)
index 0000000..66edfef
--- /dev/null
@@ -0,0 +1,218 @@
+/* $Id: oakley.h,v 1.9 2004/10/24 17:37:00 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _OAKLEY_H
+#define _OAKLEY_H
+
+#include "vmbuf.h"
+
+/* refer to RFC 2409 */
+
+/* Attribute Classes */
+#define OAKLEY_ATTR_ENC_ALG            1 /* B */
+#define   OAKLEY_ATTR_ENC_ALG_DES              1
+#define   OAKLEY_ATTR_ENC_ALG_IDEA             2
+#define   OAKLEY_ATTR_ENC_ALG_BLOWFISH         3
+#define   OAKLEY_ATTR_ENC_ALG_RC5              4
+#define   OAKLEY_ATTR_ENC_ALG_3DES             5
+#define   OAKLEY_ATTR_ENC_ALG_CAST             6
+#define   OAKLEY_ATTR_ENC_ALG_AES              7
+                                       /*      65001 - 65535 Private Use */
+#define OAKLEY_ATTR_HASH_ALG           2 /* B */
+#define   OAKLEY_ATTR_HASH_ALG_MD5             1
+#define   OAKLEY_ATTR_HASH_ALG_SHA             2
+#define   OAKLEY_ATTR_HASH_ALG_TIGER           3
+#if defined(WITH_SHA2)
+#define   OAKLEY_ATTR_HASH_ALG_SHA2_256                4
+#define   OAKLEY_ATTR_HASH_ALG_SHA2_384                5
+#define   OAKLEY_ATTR_HASH_ALG_SHA2_512                6
+#endif
+                                       /*      65001 - 65535 Private Use */
+#define OAKLEY_ATTR_AUTH_METHOD                3 /* B */
+#define   OAKLEY_ATTR_AUTH_METHOD_PSKEY                1
+#define   OAKLEY_ATTR_AUTH_METHOD_DSSSIG       2
+#define   OAKLEY_ATTR_AUTH_METHOD_RSASIG       3
+#define   OAKLEY_ATTR_AUTH_METHOD_RSAENC       4
+#define   OAKLEY_ATTR_AUTH_METHOD_RSAREV       5
+#define   OAKLEY_ATTR_AUTH_METHOD_EGENC                6
+#define   OAKLEY_ATTR_AUTH_METHOD_EGREV                7
+       /* Hybrid Auth */
+#ifdef ENABLE_HYBRID    
+#define   OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I 64221
+#define          OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R  64222
+#define   OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I 64223
+#define   OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R 64224
+
+                                       /*      65001 - 65535 Private Use */
+
+        /* Plain Xauth, Not implemented */
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I  65001
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R  65002
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I 65003
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R 65004
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I 65005
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R 65006
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I 65007
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R 65008
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I 65009
+#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R 65010
+#endif
+
+       /*
+        * The following are valid when the Vendor ID is one of
+        * the following:
+        *
+        *      MD5("A GSS-API Authentication Method for IKE")
+        *      MD5("GSSAPI") (recognized by Windows 2000)
+        *      MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000)
+        */
+#define   OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB   65001
+#define OAKLEY_ATTR_GRP_DESC           4 /* B */
+#define   OAKLEY_ATTR_GRP_DESC_MODP768         1
+#define   OAKLEY_ATTR_GRP_DESC_MODP1024                2
+#define   OAKLEY_ATTR_GRP_DESC_EC2N155         3
+#define   OAKLEY_ATTR_GRP_DESC_EC2N185         4
+#define   OAKLEY_ATTR_GRP_DESC_MODP1536                5
+#define   OAKLEY_ATTR_GRP_DESC_MODP2048                14
+#define   OAKLEY_ATTR_GRP_DESC_MODP3072                15
+#define   OAKLEY_ATTR_GRP_DESC_MODP4096                16
+#define   OAKLEY_ATTR_GRP_DESC_MODP6144                17
+#define   OAKLEY_ATTR_GRP_DESC_MODP8192                18
+                                       /*      32768 - 65535 Private Use */
+#define OAKLEY_ATTR_GRP_TYPE           5 /* B */
+#define   OAKLEY_ATTR_GRP_TYPE_MODP            1
+#define   OAKLEY_ATTR_GRP_TYPE_ECP             2
+#define   OAKLEY_ATTR_GRP_TYPE_EC2N            3
+                                       /*      65001 - 65535 Private Use */
+#define OAKLEY_ATTR_GRP_PI             6 /* V */
+#define OAKLEY_ATTR_GRP_GEN_ONE                7 /* V */
+#define OAKLEY_ATTR_GRP_GEN_TWO                8 /* V */
+#define OAKLEY_ATTR_GRP_CURVE_A                9 /* V */
+#define OAKLEY_ATTR_GRP_CURVE_B                10 /* V */
+#define OAKLEY_ATTR_SA_LD_TYPE         11 /* B */
+#define   OAKLEY_ATTR_SA_LD_TYPE_DEFAULT       1
+#define   OAKLEY_ATTR_SA_LD_TYPE_SEC           1
+#define   OAKLEY_ATTR_SA_LD_TYPE_KB            2
+#define   OAKLEY_ATTR_SA_LD_TYPE_MAX           3
+                                       /*      65001 - 65535 Private Use */
+#define OAKLEY_ATTR_SA_LD              12 /* V */
+#define   OAKLEY_ATTR_SA_LD_SEC_DEFAULT                28800 /* 8 hours */
+#define OAKLEY_ATTR_PRF                        13 /* B */
+#define OAKLEY_ATTR_KEY_LEN            14 /* B */
+#define OAKLEY_ATTR_FIELD_SIZE         15 /* B */
+#define OAKLEY_ATTR_GRP_ORDER          16 /* V */
+#define OAKLEY_ATTR_BLOCK_SIZE         17 /* B */
+                               /*      16384 - 32767 Private Use */
+
+       /*
+        * The following are valid when the Vendor ID is one of
+        * the following:
+        *
+        *      MD5("A GSS-API Authentication Method for IKE")
+        *      MD5("GSSAPI") (recognized by Windows 2000)
+        *      MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000)
+        */
+#define OAKLEY_ATTR_GSS_ID             16384
+
+#define MAXPADLWORD    20
+
+struct dhgroup {
+       int type;
+       vchar_t *prime;
+       int gen1;
+       int gen2;
+       vchar_t *curve_a;
+       vchar_t *curve_b;
+       vchar_t *order;
+};
+
+/* certificate holder */
+typedef struct cert_t_tag {
+       u_int8_t type;          /* type of CERT, must be same to pl->v[0]*/
+       vchar_t cert;           /* pointer to the CERT */
+       vchar_t *pl;            /* CERT payload minus isakmp general header */
+} cert_t;
+
+struct ph1handle;
+struct ph2handle;
+struct isakmp_ivm;
+
+extern int oakley_get_defaultlifetime __P((void));
+
+extern int oakley_dhinit __P((void));
+extern void oakley_dhgrp_free __P((struct dhgroup *));
+extern int oakley_dh_compute __P((const struct dhgroup *,
+       vchar_t *, vchar_t *, vchar_t *, vchar_t **));
+extern int oakley_dh_generate __P((const struct dhgroup *,
+       vchar_t **, vchar_t **));
+extern int oakley_setdhgroup __P((int, struct dhgroup **));
+
+extern vchar_t *oakley_prf __P((vchar_t *, vchar_t *, struct ph1handle *));
+extern vchar_t *oakley_hash __P((vchar_t *, struct ph1handle *));
+
+extern int oakley_compute_keymat __P((struct ph2handle *, int));
+
+#if notyet
+extern vchar_t *oakley_compute_hashx __P((void));
+#endif
+extern vchar_t *oakley_compute_hash3 __P((struct ph1handle *,
+       u_int32_t, vchar_t *));
+extern vchar_t *oakley_compute_hash1 __P((struct ph1handle *,
+       u_int32_t, vchar_t *));
+extern vchar_t *oakley_ph1hash_common __P((struct ph1handle *, int));
+extern vchar_t *oakley_ph1hash_base_i __P((struct ph1handle *, int));
+extern vchar_t *oakley_ph1hash_base_r __P((struct ph1handle *, int));
+
+extern int oakley_validate_auth __P((struct ph1handle *));
+extern int oakley_getmycert __P((struct ph1handle *));
+extern int oakley_getsign __P((struct ph1handle *));
+extern vchar_t *oakley_getcr __P((struct ph1handle *));
+extern int oakley_checkcr __P((struct ph1handle *));
+extern int oakley_needcr __P((int));
+struct isakmp_gen;
+extern int oakley_savecert __P((struct ph1handle *, struct isakmp_gen *));
+extern int oakley_savecr __P((struct ph1handle *, struct isakmp_gen *));
+
+extern int oakley_skeyid __P((struct ph1handle *));
+extern int oakley_skeyid_dae __P((struct ph1handle *));
+
+extern int oakley_compute_enckey __P((struct ph1handle *));
+extern cert_t *oakley_newcert __P((void));
+extern void oakley_delcert __P((cert_t *));
+extern int oakley_newiv __P((struct ph1handle *));
+extern struct isakmp_ivm *oakley_newiv2 __P((struct ph1handle *, u_int32_t));
+extern void oakley_delivm __P((struct isakmp_ivm *));
+extern vchar_t *oakley_do_decrypt __P((struct ph1handle *,
+       vchar_t *, vchar_t *, vchar_t *));
+extern vchar_t *oakley_do_encrypt __P((struct ph1handle *,
+       vchar_t *, vchar_t *, vchar_t *));
+
+#endif /* _OAKLEY_H */
diff --git a/ipsec-tools/racoon/open_dir.c b/ipsec-tools/racoon/open_dir.c
new file mode 100644 (file)
index 0000000..952d0ce
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <DirectoryService/DirServices.h>
+#include <DirectoryService/DirServicesUtils.h>
+#include <DirectoryService/DirServicesConst.h>
+#include <CoreFoundation/CFString.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include "vmbuf.h"
+#include "remoteconf.h"
+#include "plog.h"
+#include "misc.h"
+#include "gcmalloc.h"
+#include "open_dir.h"
+
+#define BUF_LEN                1024
+
+
+static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, 
+                tDirNodeReference *searchNodeRef, unsigned long *count);
+static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, 
+                char *attr, tAttributeValueEntryPtr *attr_value);
+static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, 
+                char *group_name, char *user_name, char *userGID, int *authorized);
+
+
+//----------------------------------------------------------------------
+//     open_dir_authorize_id
+//----------------------------------------------------------------------
+int open_dir_authorize_id(vchar_t *id, vchar_t *group)
+{
+
+    tDirReference                      dirRef;
+    tDirStatus                                 dsResult = eDSNoErr;
+    int                                                authorized = 0;
+    tDirNodeReference          searchNodeRef;
+    tAttributeValueEntryPtr    groupID = NULL;
+    tAttributeValueEntryPtr    recordName = NULL;
+    unsigned long                      searchNodeCount;
+    char*                                      user_name = NULL;
+    char*                                      group_name = NULL;
+    
+    if (id == 0 || id->l < 1) {
+        plog(LLV_ERROR, LOCATION, NULL, "invalid user name.\n");
+        goto end;
+    }  
+       user_name = racoon_malloc(id->l + 1);
+       if (user_name == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "out of memory - unable to allocate space for user name.\n");
+               goto end;
+       }
+       bcopy(id->v, user_name, id->l);
+       *(user_name + id->l) = 0;
+               
+       if (group && group->l > 0) {
+               group_name = racoon_malloc(group->l + 1);
+               if (group_name == NULL) {
+                       plog(LLV_NOTIFY, LOCATION, NULL, "out of memeory - unable to allocate space for group name.\n");
+                       goto end;
+               }
+               bcopy(group->v, group_name, group->l);
+               *(group_name + group->l) = 0;
+       }
+                       
+    if ((dsResult = dsOpenDirService(&dirRef)) == eDSNoErr) {  
+        // get the search node ref
+        if ((dsResult = open_dir_get_search_node_ref(dirRef, 1, &searchNodeRef, &searchNodeCount)) == eDSNoErr) {
+            // get the user's primary group ID
+               if (dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrRecordName, &recordName) == eDSNoErr) {
+                       if (recordName != 0) {
+                               if (group_name != 0) {
+                                               if ((dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDS1AttrPrimaryGroupID, &groupID)) == eDSNoErr) {
+                                                       // check if user is member of the group
+                                                       dsResult = open_dir_check_group_membership(dirRef, searchNodeRef, group_name, 
+                                                               recordName->fAttributeValueData.fBufferData, groupID->fAttributeValueData.fBufferData, &authorized);
+                                               }
+                                       } else
+                                               authorized = 1; // no group required - user record found                
+                               } 
+            }
+            if (groupID)
+                dsDeallocAttributeValueEntry(dirRef, groupID);
+            if (recordName)
+               dsDeallocAttributeValueEntry(dirRef, recordName);
+            dsCloseDirNode(searchNodeRef);             // close the search node
+        }
+        dsCloseDirService(dirRef);
+    }
+
+end:    
+    if (authorized)
+        plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' authorized for access\n", user_name);
+    else
+        plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' not authorized for access\n", user_name);
+    if (user_name)
+       free(user_name);
+    if (group_name)
+       free(group_name);
+    return authorized;
+}
+
+
+//----------------------------------------------------------------------
+//     open_dir_get_search_node_ref
+//----------------------------------------------------------------------
+static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, 
+                tDirNodeReference *searchNodeRef, unsigned long *count)
+{
+    tDirStatus                 dsResult = -1;
+    tDataBufferPtr             searchNodeDataBufferPtr = 0;
+    tDataListPtr               searchNodeNameDataListPtr = 0;
+
+    unsigned long              outNodeCount;
+    tContextData               continueData = 0;
+    
+    *searchNodeRef = 0;
+    *count = 0;
+    
+    // allocate required buffers and data lists
+    if ((searchNodeDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n");
+        goto cleanup;
+    }
+    if ((searchNodeNameDataListPtr = dsDataListAllocate(dirRef)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+        
+    // find authentication search node(s)
+    if ((dsResult = dsFindDirNodes(dirRef, searchNodeDataBufferPtr, 0, eDSAuthenticationSearchNodeName, 
+                                                                &outNodeCount, &continueData)) == eDSNoErr) {
+        if (outNodeCount != 0) {
+                            
+            // get the seach node name and open the node
+            if ((dsResult = dsGetDirNodeName(dirRef, searchNodeDataBufferPtr, index, 
+                                                        &searchNodeNameDataListPtr)) == eDSNoErr) {
+                if ((dsResult = dsOpenDirNode(dirRef, searchNodeNameDataListPtr, searchNodeRef)) == eDSNoErr) {
+                    *count = outNodeCount; 
+                }
+            }
+        }
+        if (continueData)
+            dsReleaseContinueData(dirRef, continueData);
+    }
+    
+cleanup:
+    if (searchNodeDataBufferPtr)
+        dsDataBufferDeAllocate(dirRef, searchNodeDataBufferPtr);
+    if (searchNodeNameDataListPtr)
+        dsDataListDeallocate(dirRef, searchNodeNameDataListPtr);
+    
+    return dsResult;
+}
+
+//----------------------------------------------------------------------
+//     open_dir_get_user_attr
+//----------------------------------------------------------------------
+static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, 
+                char *attr, tAttributeValueEntryPtr *attr_value)
+{
+
+    tDirStatus                 dsResult = -1;
+   
+    tDataBufferPtr             userRcdDataBufferPtr = 0;
+    tDataListPtr               recordNameDataListPtr = 0;
+    tDataListPtr               recordTypeDataListPtr = 0;  
+    tDataListPtr               attrTypeDataListPtr = 0;
+    tContextData               continueData = 0;
+
+    unsigned long              outRecordCount;
+    int                                userRcdFound = 0;
+    u_int32_t                  userRecordIndex, attrIndex;
+    
+    *attr_value        = 0;
+                                             
+    if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n");
+        goto cleanup;
+    }
+    if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, user_name, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+    if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+    if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSNAttrRecordName, kDS1AttrDistinguishedName, attr, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+                                                                 
+    // find the user record(s), extracting the user name and requested attribute
+    do {
+        dsResult = dsGetRecordList(searchNodeRef, userRcdDataBufferPtr, recordNameDataListPtr, eDSExact,
+                    recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData);
+        
+        // if buffer too small - allocate a larger one
+        if (dsResult == eDSBufferTooSmall) {
+            u_int32_t  size = userRcdDataBufferPtr->fBufferSize * 2;
+            
+            dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr);
+            if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) {
+                plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n");
+               dsResult = -1;
+               goto cleanup;
+            }
+        }
+    } while (dsResult == eDSBufferTooSmall);
+
+    if (dsResult == eDSNoErr) {
+        // for each user record
+        for (userRecordIndex = 1; (userRecordIndex <= outRecordCount) && (dsResult == eDSNoErr) 
+                                                        && (userRcdFound == 0); userRecordIndex++) {
+                            
+            tAttributeListRef  attrListRef;
+            tRecordEntryPtr    userRcdEntryPtr;
+                
+            // get the user record entry from the data buffer
+            if ((dsResult = dsGetRecordEntry(searchNodeRef, userRcdDataBufferPtr, userRecordIndex, 
+                                                    &attrListRef, &userRcdEntryPtr)) == eDSNoErr) {
+                // for each attribute
+                for (attrIndex = 1; (attrIndex <= userRcdEntryPtr->fRecordAttributeCount) 
+                                                            && (dsResult == eDSNoErr); attrIndex++) {
+                
+                    tAttributeValueListRef     attrValueListRef;
+                    tAttributeEntryPtr         attrInfoPtr;
+                    tAttributeValueEntryPtr    attrValuePtr;
+                
+                    if ((dsResult = dsGetAttributeEntry(searchNodeRef, userRcdDataBufferPtr, 
+                                        attrListRef, attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) {
+                        if ((dsResult = dsGetAttributeValue(searchNodeRef, userRcdDataBufferPtr, 1, 
+                                        attrValueListRef, &attrValuePtr)) == eDSNoErr) { 
+                                
+                            // check for user record name or attribute searching for
+                            if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrRecordName)) {
+                                if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) 
+                                    userRcdFound = 1;
+                            }
+                            if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrDistinguishedName)) {
+                                if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) 
+                                    userRcdFound = 1;
+                            }
+                            if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, attr)) {
+                                *attr_value = attrValuePtr;    // return the attribute value
+                                attrValuePtr = 0;              // set to zero so we don't deallocate it
+                            }
+                            if (attrValuePtr)
+                                dsDeallocAttributeValueEntry(dirRef, attrValuePtr);
+                        }
+                        dsCloseAttributeValueList(attrValueListRef);
+                        dsDeallocAttributeEntry(dirRef, attrInfoPtr);
+                    }
+                }
+                // make sure we've processed both attributes and we have a match on user name
+                if(userRcdFound == 0 || *attr_value == 0) {
+                    userRcdFound = 0;
+                    if (*attr_value)
+                       dsDeallocAttributeValueEntry(dirRef, *attr_value);
+                    *attr_value = 0;
+                }            
+                dsCloseAttributeList(attrListRef);
+                dsDeallocRecordEntry(dirRef, userRcdEntryPtr);
+            }
+        }
+    }
+        
+cleanup:
+       if (continueData)
+               dsReleaseContinueData(searchNodeRef, continueData);
+    if (userRcdDataBufferPtr)
+        dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr);
+    if (recordNameDataListPtr)
+        dsDataListDeallocate(dirRef, recordNameDataListPtr);
+    if (recordTypeDataListPtr)
+        dsDataListDeallocate(dirRef, recordTypeDataListPtr); 
+    if (attrTypeDataListPtr)
+        dsDataListDeallocate(dirRef, attrTypeDataListPtr); 
+        
+    return dsResult;
+    
+}
+
+
+//----------------------------------------------------------------------
+//     open_dir_check_group_membership
+//----------------------------------------------------------------------
+static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, 
+                char *group_name, char *user_name, char *userGID, int *authorized)
+{
+    tDirStatus                 dsResult = -1;
+   
+    tDataBufferPtr             groupRcdDataBufferPtr = 0;
+    tDataListPtr               recordNameDataListPtr = 0;
+    tDataListPtr               recordTypeDataListPtr = 0;  
+    tDataListPtr               attrTypeDataListPtr = 0;
+    tContextData               continueData = 0;
+
+    unsigned long              outRecordCount;
+    u_int32_t                  attrIndex, valueIndex;
+    
+    *authorized        = 0;
+                                             
+    if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n");
+        goto cleanup;
+    }
+    if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, group_name, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+    if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeGroups, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+    if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDS1AttrPrimaryGroupID, kDSNAttrGroupMembership, 0)) == 0) {
+        plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n");
+        goto cleanup;
+    }
+
+    // find the group record, extracting the group ID and group membership attribute
+    do {
+        dsResult = dsGetRecordList(searchNodeRef, groupRcdDataBufferPtr, recordNameDataListPtr, eDSExact,
+                            recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData);
+        // if buffer too small - allocate a larger one
+        if (dsResult == eDSBufferTooSmall) {
+            u_int32_t  size = groupRcdDataBufferPtr->fBufferSize * 2;
+            
+            dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr);
+            if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) {
+                plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n");
+                dsResult = -1;
+                goto cleanup;
+            }
+        }
+    } while (dsResult == eDSBufferTooSmall);
+    
+    if (dsResult == eDSNoErr) {
+                             
+        tAttributeListRef      attrListRef;
+        tRecordEntryPtr                groupRcdEntryPtr;
+        
+        // get the group record entry
+        if ((dsResult = dsGetRecordEntry(searchNodeRef, groupRcdDataBufferPtr, 1, &attrListRef, &groupRcdEntryPtr)) == eDSNoErr) {
+
+            // for each attribute
+            for (attrIndex = 1; (attrIndex <= groupRcdEntryPtr->fRecordAttributeCount) && (dsResult == eDSNoErr)
+                                    && (*authorized == 0); attrIndex++) {
+                    
+                tAttributeValueListRef attrValueListRef;
+                tAttributeEntryPtr     attrInfoPtr;
+                tAttributeValueEntryPtr        attrValuePtr;
+            
+                if ((dsResult = dsGetAttributeEntry(searchNodeRef, groupRcdDataBufferPtr, attrListRef, 
+                                                        attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) {
+                    
+                    // group ID attribute ?
+                    if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrPrimaryGroupID)) {
+                       if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, 1, 
+                                                            attrValueListRef, &attrValuePtr)) == eDSNoErr) {  
+                            
+                            // check for match on primary group ID
+                            if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, userGID))
+                                *authorized = 1;
+                            dsDeallocAttributeValueEntry(dirRef, attrValuePtr);
+                        }
+                    } else if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrGroupMembership)) {
+                        // for each value check for user's name in the group
+                        for (valueIndex = 1; (valueIndex <= attrInfoPtr->fAttributeValueCount) 
+                                                && (dsResult == eDSNoErr) && (*authorized == 0); valueIndex++) {
+                            
+                            if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, 
+                                                    valueIndex, attrValueListRef, &attrValuePtr)) == eDSNoErr) {                                
+                                if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name))
+                                    *authorized = 1;
+                                dsDeallocAttributeValueEntry(dirRef, attrValuePtr);
+                            }
+                        }
+                    }
+                    dsCloseAttributeValueList(attrValueListRef);
+                    dsDeallocAttributeEntry(dirRef, attrInfoPtr);
+                }
+            }
+            dsCloseAttributeList(attrListRef);
+            dsDeallocRecordEntry(dirRef, groupRcdEntryPtr);
+        }
+    }
+        
+cleanup:
+       if (continueData)
+               dsReleaseContinueData(searchNodeRef, continueData);
+    if (groupRcdDataBufferPtr)
+        dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr);
+    if (recordNameDataListPtr)
+        dsDataListDeallocate(dirRef, recordNameDataListPtr);
+    if (recordTypeDataListPtr)
+        dsDataListDeallocate(dirRef, recordTypeDataListPtr); 
+    if (attrTypeDataListPtr)
+        dsDataListDeallocate(dirRef, attrTypeDataListPtr); 
+        
+    return dsResult;
+}
+
diff --git a/ipsec-tools/racoon/open_dir.h b/ipsec-tools/racoon/open_dir.h
new file mode 100644 (file)
index 0000000..89f1f2c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OPEN_DIR_H__
+#define __OPEN_DIR_H__
+
+extern int open_dir_authorize_id(vchar_t *id, vchar_t *group);
+
+
+#endif /* __OPEN_DIR_H__ */
+
diff --git a/ipsec-tools/racoon/pfkey.h b/ipsec-tools/racoon/pfkey.h
new file mode 100644 (file)
index 0000000..62aede2
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id: pfkey.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PFKEY_H
+#define _PFKEY_H
+
+struct pfkey_satype {
+       u_int8_t        ps_satype;
+       const char      *ps_name;
+};
+
+extern const struct pfkey_satype pfkey_satypes[];
+extern const int pfkey_nsatypes;
+
+extern int pfkey_handler __P((void));
+extern vchar_t *pfkey_dump_sadb __P((int));
+extern void pfkey_flush_sadb __P((u_int));
+extern int pfkey_init __P((void));
+
+extern struct pfkey_st *pfkey_getpst __P((caddr_t *, int, int));
+
+extern int pk_checkalg __P((int, int, int));
+
+struct ph2handle;
+extern int pk_sendgetspi __P((struct ph2handle *));
+extern int pk_sendupdate __P((struct ph2handle *));
+extern int pk_sendadd __P((struct ph2handle *));
+extern int pk_sendeacquire __P((struct ph2handle *));
+extern int pk_sendspdupdate2 __P((struct ph2handle *));
+extern int pk_sendspdadd2 __P((struct ph2handle *));
+extern int pk_sendspddelete __P((struct ph2handle *));
+
+extern void pfkey_timeover_stub __P((void *));
+extern void pfkey_timeover __P((struct ph2handle *));
+
+extern u_int pfkey2ipsecdoi_proto __P((u_int));
+extern u_int ipsecdoi2pfkey_proto __P((u_int));
+extern u_int pfkey2ipsecdoi_mode __P((u_int));
+extern u_int ipsecdoi2pfkey_mode __P((u_int));
+
+extern int pfkey_convertfromipsecdoi __P(( u_int, u_int, u_int,
+       u_int *, u_int *, u_int *, u_int *, u_int *));
+extern u_int32_t pk_getseq __P((void));
+extern const char *sadbsecas2str
+       __P((struct sockaddr *, struct sockaddr *, int, u_int32_t, int));
+
+#endif /* _PFKEY_H */
diff --git a/ipsec-tools/racoon/pfkey_racoon.c b/ipsec-tools/racoon/pfkey_racoon.c
new file mode 100644 (file)
index 0000000..7152a4e
--- /dev/null
@@ -0,0 +1,3037 @@
+/* $Id: pfkey.c,v 1.31.2.10 2005/10/03 14:52:19 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef ENABLE_NATT
+# ifdef __linux__
+#  include <linux/udp.h>
+# endif
+# if defined(__NetBSD__) || defined(__FreeBSD__)
+#  include <netinet/udp.h>
+# endif
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include <netinet/in.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include "libpfkey.h"
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_inf.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "pfkey.h"
+#include "handler.h"
+#include "policy.h"
+#include "algorithm.h"
+#include "sainfo.h"
+#include "proposal.h"
+#include "admin.h"
+#include "privsep.h"
+#include "strnames.h"
+#include "backupsa.h"
+#include "gcmalloc.h"
+#include "nattraversal.h"
+#include "crypto_openssl.h"
+#include "grabmyaddr.h"
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+
+#if defined(SADB_X_EALG_RIJNDAELCBC) && !defined(SADB_X_EALG_AESCBC)
+#define SADB_X_EALG_AESCBC  SADB_X_EALG_RIJNDAELCBC
+#endif
+
+/* prototype */
+static u_int ipsecdoi2pfkey_aalg __P((u_int));
+static u_int ipsecdoi2pfkey_ealg __P((u_int));
+static u_int ipsecdoi2pfkey_calg __P((u_int));
+static u_int ipsecdoi2pfkey_alg __P((u_int, u_int));
+static u_int keylen_aalg __P((u_int));
+static u_int keylen_ealg __P((u_int, int));
+
+static int pk_recvgetspi __P((caddr_t *));
+static int pk_recvupdate __P((caddr_t *));
+static int pk_recvadd __P((caddr_t *));
+static int pk_recvdelete __P((caddr_t *));
+static int pk_recvacquire __P((caddr_t *));
+static int pk_recvexpire __P((caddr_t *));
+static int pk_recvflush __P((caddr_t *));
+static int getsadbpolicy __P((caddr_t *, int *, int, struct ph2handle *));
+static int pk_recvspdupdate __P((caddr_t *));
+static int pk_recvspdadd __P((caddr_t *));
+static int pk_recvspddelete __P((caddr_t *));
+static int pk_recvspdexpire __P((caddr_t *));
+static int pk_recvspdget __P((caddr_t *));
+static int pk_recvspddump __P((caddr_t *));
+static int pk_recvspdflush __P((caddr_t *));
+static struct sadb_msg *pk_recv __P((int, int *));
+
+static int (*pkrecvf[]) __P((caddr_t *)) = {
+NULL,
+pk_recvgetspi,
+pk_recvupdate,
+pk_recvadd,
+pk_recvdelete,
+NULL,  /* SADB_GET */
+pk_recvacquire,
+NULL,  /* SABD_REGISTER */
+pk_recvexpire,
+pk_recvflush,
+NULL,  /* SADB_DUMP */
+NULL,  /* SADB_X_PROMISC */
+NULL,  /* SADB_X_PCHANGE */
+pk_recvspdupdate,
+pk_recvspdadd,
+pk_recvspddelete,
+pk_recvspdget,
+NULL,  /* SADB_X_SPDACQUIRE */
+pk_recvspddump,
+pk_recvspdflush,
+NULL,  /* SADB_X_SPDSETIDX */
+pk_recvspdexpire,
+NULL,  /* SADB_X_SPDDELETE2 */
+NULL,  /* SADB_X_NAT_T_NEW_MAPPING */
+NULL, /* SADB_X_MIGRATE */
+#if (SADB_MAX > 24)
+#error "SADB extra message?"
+#endif
+};
+
+static int addnewsp __P((caddr_t *));
+
+/* cope with old kame headers - ugly */
+#ifndef SADB_X_AALG_MD5
+#define SADB_X_AALG_MD5                SADB_AALG_MD5   
+#endif
+#ifndef SADB_X_AALG_SHA
+#define SADB_X_AALG_SHA                SADB_AALG_SHA
+#endif
+#ifndef SADB_X_AALG_NULL
+#define SADB_X_AALG_NULL       SADB_AALG_NULL
+#endif
+
+#ifndef SADB_X_EALG_BLOWFISHCBC
+#define SADB_X_EALG_BLOWFISHCBC        SADB_EALG_BLOWFISHCBC
+#endif
+#ifndef SADB_X_EALG_CAST128CBC
+#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC
+#endif
+#ifndef SADB_X_EALG_RC5CBC
+#ifdef SADB_EALG_RC5CBC
+#define SADB_X_EALG_RC5CBC     SADB_EALG_RC5CBC
+#endif
+#endif
+
+/*
+ * PF_KEY packet handler
+ *     0: success
+ *     -1: fail
+ */
+int
+pfkey_handler()
+{
+       struct sadb_msg *msg;
+       int len;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       int error = -1;
+
+       /* receive pfkey message. */
+       len = 0;
+       msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len);
+       if (msg == NULL) {
+               if (len < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to recv from pfkey (%s)\n",
+                               strerror(errno));
+                       goto end;
+               } else {
+                       /* short message - msg not ready */
+                       return 0;
+               }
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n",
+               s_pfkey_type(msg->sadb_msg_type));
+       plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3);
+
+       /* validity check */
+       if (msg->sadb_msg_errno) {
+               int pri;
+
+               /* when SPD is empty, treat the state as no error. */
+               if (msg->sadb_msg_type == SADB_X_SPDDUMP &&
+                   msg->sadb_msg_errno == ENOENT)
+                       pri = LLV_DEBUG;
+               else
+                       pri = LLV_ERROR;
+
+               plog(pri, LOCATION, NULL,
+                       "pfkey %s failed: %s\n",
+                       s_pfkey_type(msg->sadb_msg_type),
+                       strerror(msg->sadb_msg_errno));
+
+               goto end;
+       }
+
+       /* check pfkey message. */
+       if (pfkey_align(msg, mhp)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed pfkey align (%s)\n",
+                       ipsec_strerror());
+               goto end;
+       }
+       if (pfkey_check(mhp)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed pfkey check (%s)\n",
+                       ipsec_strerror());
+               goto end;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+
+       /* safety check */
+       if (msg->sadb_msg_type >= ARRAYLEN(pkrecvf)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unknown PF_KEY message type=%u\n",
+                       msg->sadb_msg_type);
+               goto end;
+       }
+
+       if (pkrecvf[msg->sadb_msg_type] == NULL) {
+               plog(LLV_INFO, LOCATION, NULL,
+                       "unsupported PF_KEY message %s\n",
+                       s_pfkey_type(msg->sadb_msg_type));
+               goto end;
+       }
+
+       if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0)
+               goto end;
+
+       error = 0;
+end:
+       if (msg)
+               racoon_free(msg);
+       return(error);
+}
+
+/*
+ * dump SADB
+ */
+vchar_t *
+pfkey_dump_sadb(satype)
+       int satype;
+{
+       int s = -1;
+       vchar_t *buf = NULL;
+       pid_t pid = getpid();
+       struct sadb_msg *msg = NULL;
+       size_t bl, ml;
+       int len;
+
+       if ((s = privsep_pfkey_open()) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed pfkey open: %s\n",
+                       ipsec_strerror());
+               return NULL;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n");
+       if (pfkey_send_dump(s, satype) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed dump: %s\n", ipsec_strerror());
+               goto fail;
+       }
+
+       while (1) {
+               if (msg)
+                       racoon_free(msg);
+               msg = pk_recv(s, &len);
+               if (msg == NULL) {
+                       if (len < 0)
+                               goto done;
+                       else
+                               continue;
+               }
+
+               if (msg->sadb_msg_type != SADB_DUMP || msg->sadb_msg_pid != pid)
+                       continue;
+
+               ml = msg->sadb_msg_len << 3;
+               bl = buf ? buf->l : 0;
+               buf = vrealloc(buf, bl + ml);
+               if (buf == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to reallocate buffer to dump.\n");
+                       goto fail;
+               }
+               memcpy(buf->v + bl, msg, ml);
+
+               if (msg->sadb_msg_seq == 0)
+                       break;
+       }
+       goto done;
+
+fail:
+       if (buf)
+               vfree(buf);
+       buf = NULL;
+done:
+       if (msg)
+               racoon_free(msg);
+       if (s >= 0)
+               privsep_pfkey_close(s);
+       return buf;
+}
+
+#ifdef ENABLE_ADMINPORT
+/*
+ * flush SADB
+ */
+void
+pfkey_flush_sadb(proto)
+       u_int proto;
+{
+       int satype;
+
+       /* convert to SADB_SATYPE */
+       if ((satype = admin2pfkey_proto(proto)) < 0)
+               return;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_flush\n");
+       if (pfkey_send_flush(lcconf->sock_pfkey, satype) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed send flush (%s)\n", ipsec_strerror());
+               return;
+       }
+
+       return;
+}
+#endif
+
+/*
+ * These are the SATYPEs that we manage.  We register to get
+ * PF_KEY messages related to these SATYPEs, and we also use
+ * this list to determine which SATYPEs to delete SAs for when
+ * we receive an INITIAL-CONTACT.
+ */
+const struct pfkey_satype pfkey_satypes[] = {
+       { SADB_SATYPE_AH,       "AH" },
+       { SADB_SATYPE_ESP,      "ESP" },
+       { SADB_X_SATYPE_IPCOMP, "IPCOMP" },
+};
+const int pfkey_nsatypes =
+    sizeof(pfkey_satypes) / sizeof(pfkey_satypes[0]);
+
+/*
+ * PF_KEY initialization
+ */
+int
+pfkey_init()
+{
+       int i, reg_fail;
+
+       if ((lcconf->sock_pfkey = privsep_pfkey_open()) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed pfkey open (%s)\n", ipsec_strerror());
+               return -1;
+       }
+
+       for (i = 0, reg_fail = 0; i < pfkey_nsatypes; i++) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                   "call pfkey_send_register for %s\n",
+                   pfkey_satypes[i].ps_name);
+               if (pfkey_send_register(lcconf->sock_pfkey,
+                                       pfkey_satypes[i].ps_satype) < 0 ||
+                   pfkey_recv_register(lcconf->sock_pfkey) < 0) {
+                       plog(LLV_WARNING, LOCATION, NULL,
+                           "failed to register %s (%s)\n",
+                           pfkey_satypes[i].ps_name,
+                           ipsec_strerror());
+                       reg_fail++;
+               }
+       }
+
+       if (reg_fail == pfkey_nsatypes) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to regist any protocol.\n");
+               pfkey_close(lcconf->sock_pfkey);
+               return -1;
+       }
+
+       initsp();
+
+       if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec sending spddump failed: %s\n",
+                       ipsec_strerror());
+               pfkey_close(lcconf->sock_pfkey);
+               return -1;
+       }
+#if 0
+       if (pfkey_promisc_toggle(1) < 0) {
+               pfkey_close(lcconf->sock_pfkey);
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+/* %%% for conversion */
+/* IPSECDOI_ATTR_AUTH -> SADB_AALG */
+static u_int
+ipsecdoi2pfkey_aalg(hashtype)
+       u_int hashtype;
+{
+       switch (hashtype) {
+       case IPSECDOI_ATTR_AUTH_HMAC_MD5:
+               return SADB_AALG_MD5HMAC;
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
+               return SADB_AALG_SHA1HMAC;
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
+#if (defined SADB_X_AALG_SHA2_256) && !defined(SADB_X_AALG_SHA2_256HMAC)
+               return SADB_X_AALG_SHA2_256;
+#else
+               return SADB_X_AALG_SHA2_256HMAC;
+#endif
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
+#if (defined SADB_X_AALG_SHA2_384) && !defined(SADB_X_AALG_SHA2_384HMAC)
+               return SADB_X_AALG_SHA2_384;
+#else
+               return SADB_X_AALG_SHA2_384HMAC;
+#endif
+       case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
+#if (defined SADB_X_AALG_SHA2_512) && !defined(SADB_X_AALG_SHA2_512HMAC)
+               return SADB_X_AALG_SHA2_512;
+#else
+               return SADB_X_AALG_SHA2_512HMAC;
+#endif
+       case IPSECDOI_ATTR_AUTH_KPDK:           /* need special care */
+               return SADB_AALG_NONE;
+
+       /* not supported */
+       case IPSECDOI_ATTR_AUTH_DES_MAC:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Not supported hash type: %u\n", hashtype);
+               return ~0;
+
+       case 0: /* reserved */
+       default:
+               return SADB_AALG_NONE;
+
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid hash type: %u\n", hashtype);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* IPSECDOI_ESP -> SADB_EALG */
+static u_int
+ipsecdoi2pfkey_ealg(t_id)
+       u_int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_ESP_DES_IV64:             /* sa_flags |= SADB_X_EXT_OLD */
+               return SADB_EALG_DESCBC;
+       case IPSECDOI_ESP_DES:
+               return SADB_EALG_DESCBC;
+       case IPSECDOI_ESP_3DES:
+               return SADB_EALG_3DESCBC;
+#ifdef SADB_X_EALG_RC5CBC
+       case IPSECDOI_ESP_RC5:
+               return SADB_X_EALG_RC5CBC;
+#endif
+       case IPSECDOI_ESP_CAST:
+               return SADB_X_EALG_CAST128CBC;
+       case IPSECDOI_ESP_BLOWFISH:
+               return SADB_X_EALG_BLOWFISHCBC;
+       case IPSECDOI_ESP_DES_IV32:     /* flags |= (SADB_X_EXT_OLD|
+                                                       SADB_X_EXT_IV4B)*/
+               return SADB_EALG_DESCBC;
+       case IPSECDOI_ESP_NULL:
+               return SADB_EALG_NULL;
+#ifdef SADB_X_EALG_AESCBC
+       case IPSECDOI_ESP_AES:
+               return SADB_X_EALG_AESCBC;
+#endif
+#ifdef SADB_X_EALG_TWOFISHCBC
+       case IPSECDOI_ESP_TWOFISH:
+               return SADB_X_EALG_TWOFISHCBC;
+#endif
+
+       /* not supported */
+       case IPSECDOI_ESP_3IDEA:
+       case IPSECDOI_ESP_IDEA:
+       case IPSECDOI_ESP_RC4:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Not supported transform: %u\n", t_id);
+               return ~0;
+
+       case 0: /* reserved */
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid transform id: %u\n", t_id);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* IPCOMP -> SADB_CALG */
+static u_int
+ipsecdoi2pfkey_calg(t_id)
+       u_int t_id;
+{
+       switch (t_id) {
+       case IPSECDOI_IPCOMP_OUI:
+               return SADB_X_CALG_OUI;
+       case IPSECDOI_IPCOMP_DEFLATE:
+               return SADB_X_CALG_DEFLATE;
+       case IPSECDOI_IPCOMP_LZS:
+               return SADB_X_CALG_LZS;
+
+       case 0: /* reserved */
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid transform id: %u\n", t_id);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* IPSECDOI_PROTO -> SADB_SATYPE */
+u_int
+ipsecdoi2pfkey_proto(proto)
+       u_int proto;
+{
+       switch (proto) {
+       case IPSECDOI_PROTO_IPSEC_AH:
+               return SADB_SATYPE_AH;
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               return SADB_SATYPE_ESP;
+       case IPSECDOI_PROTO_IPCOMP:
+               return SADB_X_SATYPE_IPCOMP;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid ipsec_doi proto: %u\n", proto);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+static u_int
+ipsecdoi2pfkey_alg(algclass, type)
+       u_int algclass, type;
+{
+       switch (algclass) {
+       case IPSECDOI_ATTR_AUTH:
+               return ipsecdoi2pfkey_aalg(type);
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               return ipsecdoi2pfkey_ealg(type);
+       case IPSECDOI_PROTO_IPCOMP:
+               return ipsecdoi2pfkey_calg(type);
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid ipsec_doi algclass: %u\n", algclass);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* SADB_SATYPE -> IPSECDOI_PROTO */
+u_int
+pfkey2ipsecdoi_proto(satype)
+       u_int satype;
+{
+       switch (satype) {
+       case SADB_SATYPE_AH:
+               return IPSECDOI_PROTO_IPSEC_AH;
+       case SADB_SATYPE_ESP:
+               return IPSECDOI_PROTO_IPSEC_ESP;
+       case SADB_X_SATYPE_IPCOMP:
+               return IPSECDOI_PROTO_IPCOMP;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "Invalid pfkey proto: %u\n", satype);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */
+u_int
+ipsecdoi2pfkey_mode(mode)
+       u_int mode;
+{
+       switch (mode) {
+       case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
+#ifdef ENABLE_NATT
+       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
+       case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
+#endif
+               return IPSEC_MODE_TUNNEL;
+       case IPSECDOI_ATTR_ENC_MODE_TRNS:
+#ifdef ENABLE_NATT
+       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
+       case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
+#endif
+               return IPSEC_MODE_TRANSPORT;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */
+u_int
+pfkey2ipsecdoi_mode(mode)
+       u_int mode;
+{
+       switch (mode) {
+       case IPSEC_MODE_TUNNEL:
+               return IPSECDOI_ATTR_ENC_MODE_TUNNEL;
+       case IPSEC_MODE_TRANSPORT:
+               return IPSECDOI_ATTR_ENC_MODE_TRNS;
+       case IPSEC_MODE_ANY:
+               return IPSECDOI_ATTR_ENC_MODE_ANY;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode);
+               return ~0;
+       }
+       /*NOTREACHED*/
+}
+
+/* default key length for encryption algorithm */
+static u_int
+keylen_aalg(hashtype)
+       u_int hashtype;
+{
+       int res;
+
+       if (hashtype == 0)
+               return SADB_AALG_NONE;
+
+       res = alg_ipsec_hmacdef_hashlen(hashtype);
+       if (res == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid hmac algorithm %u.\n", hashtype);
+               return ~0;
+       }
+       return res;
+}
+
+/* default key length for encryption algorithm */
+static u_int
+keylen_ealg(enctype, encklen)
+       u_int enctype;
+       int encklen;
+{
+       int res;
+
+       res = alg_ipsec_encdef_keylen(enctype, encklen);
+       if (res == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid encryption algorithm %u.\n", enctype);
+               return ~0;
+       }
+       return res;
+}
+
+int
+pfkey_convertfromipsecdoi(proto_id, t_id, hashtype,
+               e_type, e_keylen, a_type, a_keylen, flags)
+       u_int proto_id;
+       u_int t_id;
+       u_int hashtype;
+       u_int *e_type;
+       u_int *e_keylen;
+       u_int *a_type;
+       u_int *a_keylen;
+       u_int *flags;
+{
+       *flags = 0;
+       switch (proto_id) {
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               if ((*e_type = ipsecdoi2pfkey_ealg(t_id)) == ~0)
+                       goto bad;
+               if ((*e_keylen = keylen_ealg(t_id, *e_keylen)) == ~0)
+                       goto bad;
+               *e_keylen >>= 3;
+
+               if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0)
+                       goto bad;
+               if ((*a_keylen = keylen_aalg(hashtype)) == ~0)
+                       goto bad;
+               *a_keylen >>= 3;
+
+               if (*e_type == SADB_EALG_NONE) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no ESP algorithm.\n");
+                       goto bad;
+               }
+               break;
+
+       case IPSECDOI_PROTO_IPSEC_AH:
+               if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0)
+                       goto bad;
+               if ((*a_keylen = keylen_aalg(hashtype)) == ~0)
+                       goto bad;
+               *a_keylen >>= 3;
+
+               if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 
+                && hashtype == IPSECDOI_ATTR_AUTH_KPDK) {
+                       /* AH_MD5 + Auth(KPDK) = RFC1826 keyed-MD5 */
+                       *a_type = SADB_X_AALG_MD5;
+                       *flags |= SADB_X_EXT_OLD;
+               }
+               *e_type = SADB_EALG_NONE;
+               *e_keylen = 0;
+               if (*a_type == SADB_AALG_NONE) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no AH algorithm.\n");
+                       goto bad;
+               }
+               break;
+
+       case IPSECDOI_PROTO_IPCOMP:
+               if ((*e_type = ipsecdoi2pfkey_calg(t_id)) == ~0)
+                       goto bad;
+               *e_keylen = 0;
+
+               *flags = SADB_X_EXT_RAWCPI;
+
+               *a_type = SADB_AALG_NONE;
+               *a_keylen = 0;
+               if (*e_type == SADB_X_CALG_NONE) {
+                       plog(LLV_ERROR, LOCATION, NULL, "no IPCOMP algorithm.\n");
+                       goto bad;
+               }
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL, "unknown IPsec protocol.\n");
+               goto bad;
+       }
+
+       return 0;
+
+    bad:
+       errno = EINVAL;
+       return -1;
+}
+
+/* called from scheduler */
+void
+pfkey_timeover_stub(p)
+       void *p;
+{
+
+       pfkey_timeover((struct ph2handle *)p);
+}
+
+void
+pfkey_timeover(iph2)
+       struct ph2handle *iph2;
+{
+       plog(LLV_ERROR, LOCATION, NULL,
+               "%s give up to get IPsec-SA due to time up to wait.\n",
+               saddrwop2str(iph2->dst));
+       SCHED_KILL(iph2->sce);
+
+       /* If initiator side, send error to kernel by SADB_ACQUIRE. */
+       if (iph2->side == INITIATOR)
+               pk_sendeacquire(iph2);
+
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+
+       return;
+}
+
+/*%%%*/
+/* send getspi message per ipsec protocol per remote address */
+/*
+ * the local address and remote address in ph1handle are dealed
+ * with destination address and source address respectively.
+ * Because SPI is decided by responder.
+ */
+int
+pk_sendgetspi(iph2)
+       struct ph2handle *iph2;
+{
+       struct sockaddr *src = NULL, *dst = NULL;
+       u_int satype, mode;
+       struct saprop *pp;
+       struct saproto *pr;
+       u_int32_t minspi, maxspi;
+       int proxy = 0;
+
+       if (iph2->side == INITIATOR) {
+               pp = iph2->proposal;
+               proxy = iph2->ph1->rmconf->support_proxy;
+       } else {
+               pp = iph2->approval;
+               if (iph2->sainfo && iph2->sainfo->id_i)
+                       proxy = 1;
+       }
+
+       /* for mobile IPv6 */
+       if (proxy && iph2->src_id && iph2->dst_id &&
+           ipsecdoi_transportmode(pp)) {
+               src = iph2->src_id;
+               dst = iph2->dst_id;
+       } else {
+               src = iph2->src;
+               dst = iph2->dst;
+       }
+
+       for (pr = pp->head; pr != NULL; pr = pr->next) {
+
+               /* validity check */
+               satype = ipsecdoi2pfkey_proto(pr->proto_id);
+               if (satype == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proto_id %d\n", pr->proto_id);
+                       return -1;
+               }
+               /* this works around a bug in Linux kernel where it allocates 4 byte
+                  spi's for IPCOMP */
+               else if (satype == SADB_X_SATYPE_IPCOMP) {
+                       minspi = 0x100;
+                       maxspi = 0xffff;
+               }
+               else {
+                       minspi = 0;
+                       maxspi = 0;
+               }
+               mode = ipsecdoi2pfkey_mode(pr->encmode);
+               if (mode == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid encmode %d\n", pr->encmode);
+                       return -1;
+               }
+
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n");
+               if (pfkey_send_getspi(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               dst,                    /* src of SA */
+                               src,                    /* dst of SA */
+                               minspi, maxspi,
+                               pr->reqid_in, iph2->seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "ipseclib failed send getspi (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "pfkey GETSPI sent: %s\n",
+                       sadbsecas2str(dst, src, satype, 0, mode));
+       }
+
+       return 0;
+}
+
+/*
+ * receive GETSPI from kernel.
+ */
+static int
+pk_recvgetspi(mhp) 
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_sa *sa;
+       struct ph2handle *iph2;
+       struct sockaddr *dst;
+       int proto_id;
+       int allspiok, notfound;
+       struct saprop *pp;
+       struct saproto *pr;
+
+       /* validity check */
+       if (mhp[SADB_EXT_SA] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb getspi message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */
+
+       /* the message has to be processed or not ? */
+       if (msg->sadb_msg_pid != getpid()) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "%s message is not interesting "
+                       "because pid %d is not mine.\n",
+                       s_pfkey_type(msg->sadb_msg_type),
+                       msg->sadb_msg_pid);
+               return -1;
+       }
+
+       iph2 = getph2byseq(msg->sadb_msg_seq);
+       if (iph2 == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "seq %d of %s message not interesting.\n",
+                       msg->sadb_msg_seq,
+                       s_pfkey_type(msg->sadb_msg_type));
+               return -1;
+       }
+
+       if (iph2->status != PHASE2ST_GETSPISENT) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatch (db:%d msg:%d)\n",
+                       iph2->status, PHASE2ST_GETSPISENT);
+               return -1;
+       }
+
+       /* set SPI, and check to get all spi whether or not */
+       allspiok = 1;
+       notfound = 1;
+       proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+       pp = iph2->side == INITIATOR ? iph2->proposal : iph2->approval;
+
+       for (pr = pp->head; pr != NULL; pr = pr->next) {
+               if (pr->proto_id == proto_id && pr->spi == 0) {
+                       pr->spi = sa->sadb_sa_spi;
+                       notfound = 0;
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "pfkey GETSPI succeeded: %s\n",
+                               sadbsecas2str(iph2->dst, iph2->src,
+                                   msg->sadb_msg_satype,
+                                   sa->sadb_sa_spi,
+                                   ipsecdoi2pfkey_mode(pr->encmode)));
+               }
+               if (pr->spi == 0)
+                       allspiok = 0;   /* not get all spi */
+       }
+
+       if (notfound) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "get spi for unknown address %s\n",
+                       saddrwop2str(iph2->dst));
+               return -1;
+       }
+
+       if (allspiok) {
+               /* update status */
+               iph2->status = PHASE2ST_GETSPIDONE;
+               if (isakmp_post_getspi(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to start post getspi.\n");
+                       unbindph12(iph2);
+                       remph2(iph2);
+                       delph2(iph2);
+                       iph2 = NULL;
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * set inbound SA
+ */
+int
+pk_sendupdate(iph2)
+       struct ph2handle *iph2;
+{
+       struct saproto *pr;
+       struct sockaddr *src = NULL, *dst = NULL;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int satype, mode;
+       u_int64_t lifebyte = 0;
+       u_int wsize = 4;  /* XXX static size of window */ 
+       int proxy = 0;
+       struct ph2natt natt;
+
+       /* sanity check */
+       if (iph2->approval == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no approvaled SAs found.\n");
+       }
+
+       if (iph2->side == INITIATOR)
+               proxy = iph2->ph1->rmconf->support_proxy;
+       else if (iph2->sainfo && iph2->sainfo->id_i)
+               proxy = 1;
+
+       /* for mobile IPv6 */
+       if (proxy && iph2->src_id && iph2->dst_id &&
+           ipsecdoi_transportmode(iph2->approval)) {
+               src = iph2->src_id;
+               dst = iph2->dst_id;
+       } else {
+               src = iph2->src;
+               dst = iph2->dst;
+       }
+
+       for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+               /* validity check */
+               satype = ipsecdoi2pfkey_proto(pr->proto_id);
+               if (satype == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proto_id %d\n", pr->proto_id);
+                       return -1;
+               }
+               else if (satype == SADB_X_SATYPE_IPCOMP) {
+                       /* IPCOMP has no replay window */
+                       wsize = 0;
+               }
+#ifdef ENABLE_SAMODE_UNSPECIFIED
+               mode = IPSEC_MODE_ANY;
+#else
+               mode = ipsecdoi2pfkey_mode(pr->encmode);
+               if (mode == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid encmode %d\n", pr->encmode);
+                       return -1;
+               }
+#endif
+
+               /* set algorithm type and key length */
+               e_keylen = pr->head->encklen;
+               if (pfkey_convertfromipsecdoi(
+                               pr->proto_id,
+                               pr->head->trns_id,
+                               pr->head->authtype,
+                               &e_type, &e_keylen,
+                               &a_type, &a_keylen, &flags) < 0)
+                       return -1;
+
+#if 0
+               lifebyte = iph2->approval->lifebyte * 1024,
+#else
+               lifebyte = 0;
+#endif
+
+#ifdef __APPLE__
+#ifdef ENABLE_NATT
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n");
+               if (pr->udp_encap) {
+                       memset (&natt, 0, sizeof (natt));
+                       natt.sport = extract_port (iph2->ph1->remote);
+                       flags |= SADB_X_EXT_NATT;
+                       if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
+                               flags |= SADB_X_EXT_NATT_KEEPALIVE;
+                       else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
+                               mode == IPSEC_MODE_TRANSPORT &&
+                               src->sa_family == AF_INET)
+                                       flags |= SADB_X_EXT_NATT_MULTIPLEUSERS;
+               } else {
+                       memset (&natt, 0, sizeof (natt));
+               }
+
+               if (pfkey_send_update(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               dst,
+                               src,
+                               pr->spi,
+                               pr->reqid_in,
+                               wsize,  
+                               pr->keymat->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq, natt.sport) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send update (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#else
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n");
+               if (pfkey_send_update(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               dst,
+                               src,
+                               pr->spi,
+                               pr->reqid_in,
+                               wsize,  
+                               pr->keymat->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq, 0) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send update (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#endif /* ENABLE_NATT */
+#else
+#ifdef ENABLE_NATT
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update_nat\n");
+               if (pr->udp_encap) {
+                       memset (&natt, 0, sizeof (natt));
+                       natt.type = iph2->ph1->natt_options->encaps_type;
+                       natt.sport = extract_port (iph2->ph1->remote);
+                       natt.dport = extract_port (iph2->ph1->local);
+                       natt.oa = NULL;         // FIXME: Here comes OA!!!
+                       natt.frag = iph2->ph1->rmconf->esp_frag;
+               } else {
+                       memset (&natt, 0, sizeof (natt));
+               }
+
+               if (pfkey_send_update_nat(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               dst,
+                               src,
+                               pr->spi,
+                               pr->reqid_in,
+                               wsize,  
+                               pr->keymat->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq,
+                               natt.type, natt.sport, natt.dport, natt.oa,
+                               natt.frag) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send update_nat (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#else
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n");
+               if (pfkey_send_update(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               dst,
+                               src,
+                               pr->spi,
+                               pr->reqid_in,
+                               wsize,  
+                               pr->keymat->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send update (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#endif /* ENABLE_NATT */
+#endif /* __APPLE__ */
+
+               if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
+                       continue;
+
+               /*
+                * It maybe good idea to call backupsa_to_file() after
+                * racoon will receive the sadb_update messages.
+                * But it is impossible because there is not key in the
+                * information from the kernel.
+                */
+               if (backupsa_to_file(satype, mode, dst, src,
+                               pr->spi, pr->reqid_in, 4,
+                               pr->keymat->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, iph2->approval->lifebyte * 1024,
+                               iph2->approval->lifetime, 0,
+                               iph2->seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "backuped SA failed: %s\n",
+                               sadbsecas2str(dst, src,
+                               satype, pr->spi, mode));
+               }
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "backuped SA: %s\n",
+                       sadbsecas2str(dst, src,
+                       satype, pr->spi, mode));
+       }
+
+       return 0;
+}
+
+static int
+pk_recvupdate(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       struct ph2handle *iph2;
+       u_int proto_id, encmode, sa_mode;
+       int incomplete = 0;
+       struct saproto *pr;
+
+       /* ignore this message because of local test mode. */
+       if (f_local)
+               return 0;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_SA] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb update message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+       sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+
+       sa_mode = mhp[SADB_X_EXT_SA2] == NULL
+               ? IPSEC_MODE_ANY
+               : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+
+       /* the message has to be processed or not ? */
+       if (msg->sadb_msg_pid != getpid()) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "%s message is not interesting "
+                       "because pid %d is not mine.\n",
+                       s_pfkey_type(msg->sadb_msg_type),
+                       msg->sadb_msg_pid);
+               return -1;
+       }
+
+       iph2 = getph2byseq(msg->sadb_msg_seq);
+       if (iph2 == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "seq %d of %s message not interesting.\n",
+                       msg->sadb_msg_seq,
+                       s_pfkey_type(msg->sadb_msg_type));
+               return -1;
+       }
+
+       if (iph2->status != PHASE2ST_ADDSA) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "status mismatch (db:%d msg:%d)\n",
+                       iph2->status, PHASE2ST_ADDSA);
+               return -1;
+       }
+
+       /* check to complete all keys ? */
+       for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+               proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+               if (proto_id == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proto_id %d\n", msg->sadb_msg_satype);
+                       return -1;
+               }
+               encmode = pfkey2ipsecdoi_mode(sa_mode);
+               if (encmode == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid encmode %d\n", sa_mode);
+                       return -1;
+               }
+
+               if (pr->proto_id == proto_id
+                && pr->spi == sa->sadb_sa_spi) {
+                       pr->ok = 1;
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "pfkey UPDATE succeeded: %s\n",
+                               sadbsecas2str(iph2->dst, iph2->src,
+                                   msg->sadb_msg_satype,
+                                   sa->sadb_sa_spi,
+                                   sa_mode));
+
+                       plog(LLV_INFO, LOCATION, NULL,
+                               "IPsec-SA established: %s\n",
+                               sadbsecas2str(iph2->dst, iph2->src,
+                                       msg->sadb_msg_satype, sa->sadb_sa_spi,
+                                       sa_mode));
+               }
+
+               if (pr->ok == 0)
+                       incomplete = 1;
+       }
+
+       if (incomplete)
+               return 0;
+
+       /* turn off the timer for calling pfkey_timeover() */
+       SCHED_KILL(iph2->sce);
+       
+       /* update status */
+       iph2->status = PHASE2ST_ESTABLISHED;
+
+#ifdef ENABLE_STATS
+       gettimeofday(&iph2->end, NULL);
+       syslog(LOG_NOTICE, "%s(%s): %8.6f",
+               "phase2", "quick", timedelta(&iph2->start, &iph2->end));
+#endif
+
+       /* count up */
+       iph2->ph1->ph2cnt++;
+
+       /* turn off schedule */
+       if (iph2->scr)
+               SCHED_KILL(iph2->scr);
+
+       /*
+        * since we are going to reuse the phase2 handler, we need to
+        * remain it and refresh all the references between ph1 and ph2 to use.
+        */
+       unbindph12(iph2);
+
+       iph2->sce = sched_new(iph2->approval->lifetime,
+           isakmp_ph2expire_stub, iph2);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       return 0;
+}
+
+/*
+ * set outbound SA
+ */
+int
+pk_sendadd(iph2)
+       struct ph2handle *iph2;
+{
+       struct saproto *pr;
+       struct sockaddr *src = NULL, *dst = NULL;
+       u_int e_type, e_keylen, a_type, a_keylen, flags;
+       u_int satype, mode;
+       u_int64_t lifebyte = 0;
+       u_int wsize = 4; /* XXX static size of window */ 
+       int proxy = 0;
+       struct ph2natt natt;
+
+       /* sanity check */
+       if (iph2->approval == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no approvaled SAs found.\n");
+       }
+
+       if (iph2->side == INITIATOR)
+               proxy = iph2->ph1->rmconf->support_proxy;
+       else if (iph2->sainfo && iph2->sainfo->id_i)
+               proxy = 1;
+
+       /* for mobile IPv6 */
+       if (proxy && iph2->src_id && iph2->dst_id &&
+           ipsecdoi_transportmode(iph2->approval)) {
+               src = iph2->src_id;
+               dst = iph2->dst_id;
+       } else {
+               src = iph2->src;
+               dst = iph2->dst;
+       }
+
+       for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
+               /* validity check */
+               satype = ipsecdoi2pfkey_proto(pr->proto_id);
+               if (satype == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proto_id %d\n", pr->proto_id);
+                       return -1;
+               }
+               else if (satype == SADB_X_SATYPE_IPCOMP) {
+                       /* no replay window for IPCOMP */
+                       wsize = 0;
+               }
+#ifdef ENABLE_SAMODE_UNSPECIFIED
+               mode = IPSEC_MODE_ANY;
+#else
+               mode = ipsecdoi2pfkey_mode(pr->encmode);
+               if (mode == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid encmode %d\n", pr->encmode);
+                       return -1;
+               }
+#endif
+
+               /* set algorithm type and key length */
+               e_keylen = pr->head->encklen;
+               if (pfkey_convertfromipsecdoi(
+                               pr->proto_id,
+                               pr->head->trns_id,
+                               pr->head->authtype,
+                               &e_type, &e_keylen,
+                               &a_type, &a_keylen, &flags) < 0)
+                       return -1;
+
+#if 0
+               lifebyte = iph2->approval->lifebyte * 1024,
+#else
+               lifebyte = 0;
+#endif
+
+#ifdef __APPLE__
+#ifdef ENABLE_NATT
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
+
+               if (pr->udp_encap) {
+                       memset (&natt, 0, sizeof (natt));
+                       natt.dport = extract_port (iph2->ph1->remote);
+                       flags |= SADB_X_EXT_NATT;
+                       if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
+                               flags |= SADB_X_EXT_NATT_KEEPALIVE;
+                       else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
+                               mode == IPSEC_MODE_TRANSPORT &&
+                               dst->sa_family == AF_INET)
+                                       flags |= SADB_X_EXT_NATT_MULTIPLEUSERS;
+               } else {
+                       memset (&natt, 0, sizeof (natt));
+
+                       /* Remove port information, that SA doesn't use it */
+                       //set_port(src, 0);
+                       //set_port(dst, 0);
+               }
+
+               if (pfkey_send_add(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               pr->spi_p,
+                               pr->reqid_out,
+                               wsize,  
+                               pr->keymat_p->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq,natt.dport) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send add (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#else
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
+
+               /* Remove port information, it is not used without NAT-T */
+               //set_port(src, 0);
+               //set_port(dst, 0);
+
+               if (pfkey_send_add(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               pr->spi_p,
+                               pr->reqid_out,
+                               wsize,
+                               pr->keymat_p->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq, 0) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send add (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#endif /* ENABLE_NATT */
+#else /* __APPLE__ */
+#ifdef ENABLE_NATT
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add_nat\n");
+
+               if (pr->udp_encap) {
+                       memset (&natt, 0, sizeof (natt));
+                       natt.type = UDP_ENCAP_ESPINUDP;
+                       natt.sport = extract_port (iph2->ph1->local);
+                       natt.dport = extract_port (iph2->ph1->remote);
+                       natt.oa = NULL;         // FIXME: Here comes OA!!!
+                       natt.frag = iph2->ph1->rmconf->esp_frag;
+               } else {
+                       memset (&natt, 0, sizeof (natt));
+
+                       /* Remove port information, that SA doesn't use it */
+                       set_port(src, 0);
+                       set_port(dst, 0);
+               }
+
+               if (pfkey_send_add_nat(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               pr->spi_p,
+                               pr->reqid_out,
+                               wsize,  
+                               pr->keymat_p->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq,
+                               natt.type, natt.sport, natt.dport, natt.oa,
+                               natt.frag) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send add_nat (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#else
+               plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
+
+               /* Remove port information, it is not used without NAT-T */
+               set_port(src, 0);
+               set_port(dst, 0);
+
+               if (pfkey_send_add(
+                               lcconf->sock_pfkey,
+                               satype,
+                               mode,
+                               src,
+                               dst,
+                               pr->spi_p,
+                               pr->reqid_out,
+                               wsize,
+                               pr->keymat_p->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, lifebyte, iph2->approval->lifetime, 0,
+                               iph2->seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "libipsec failed send add (%s)\n",
+                               ipsec_strerror());
+                       return -1;
+               }
+#endif /* ENABLE_NATT */
+#endif /* __APPLE__ */
+
+               if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
+                       continue;
+
+               /*
+                * It maybe good idea to call backupsa_to_file() after
+                * racoon will receive the sadb_update messages.
+                * But it is impossible because there is not key in the
+                * information from the kernel.
+                */
+               if (backupsa_to_file(satype, mode, src, dst,
+                               pr->spi_p, pr->reqid_out, 4,
+                               pr->keymat_p->v,
+                               e_type, e_keylen, a_type, a_keylen, flags,
+                               0, iph2->approval->lifebyte * 1024,
+                               iph2->approval->lifetime, 0,
+                               iph2->seq) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "backuped SA failed: %s\n",
+                               sadbsecas2str(src, dst,
+                               satype, pr->spi_p, mode));
+               }
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "backuped SA: %s\n",
+                       sadbsecas2str(src, dst,
+                       satype, pr->spi_p, mode));
+       }
+
+       return 0;
+}
+
+static int
+pk_recvadd(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       struct ph2handle *iph2;
+       u_int sa_mode;
+
+       /* ignore this message because of local test mode. */
+       if (f_local)
+               return 0;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_SA] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb add message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+       sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+
+       sa_mode = mhp[SADB_X_EXT_SA2] == NULL
+               ? IPSEC_MODE_ANY
+               : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+
+       /* the message has to be processed or not ? */
+       if (msg->sadb_msg_pid != getpid()) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "%s message is not interesting "
+                       "because pid %d is not mine.\n",
+                       s_pfkey_type(msg->sadb_msg_type),
+                       msg->sadb_msg_pid);
+               return -1;
+       }
+
+       iph2 = getph2byseq(msg->sadb_msg_seq);
+       if (iph2 == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "seq %d of %s message not interesting.\n",
+                       msg->sadb_msg_seq,
+                       s_pfkey_type(msg->sadb_msg_type));
+               return -1;
+       }
+
+       /*
+        * NOTE don't update any status of phase2 handle
+        * because they must be updated by SADB_UPDATE message
+        */
+
+       plog(LLV_INFO, LOCATION, NULL,
+               "IPsec-SA established: %s\n",
+               sadbsecas2str(iph2->src, iph2->dst,
+                       msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode));
+                       
+#ifdef ENABLE_VPNCONTROL_PORT
+               {
+                       u_int32_t address;
+                       
+                       if (iph2->dst->sa_family == AF_INET)
+                               address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
+                       else
+                               address = 0;
+                       vpncontrol_notify_phase_change(0, FROM_LOCAL, NULL, iph2);
+               }       
+#endif
+
+       plog(LLV_DEBUG, LOCATION, NULL, "===\n");
+       return 0;
+}
+
+static int
+pk_recvexpire(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       struct ph2handle *iph2;
+       u_int proto_id, sa_mode;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_SA] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || (mhp[SADB_EXT_LIFETIME_HARD] != NULL
+         && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb expire message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+       src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+       sa_mode = mhp[SADB_X_EXT_SA2] == NULL
+               ? IPSEC_MODE_ANY
+               : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
+
+       proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+       if (proto_id == ~0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid proto_id %d\n", msg->sadb_msg_satype);
+               return -1;
+       }
+
+       plog(LLV_INFO, LOCATION, NULL,
+               "IPsec-SA expired: %s\n",
+               sadbsecas2str(src, dst,
+                       msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode));
+
+       iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
+       if (iph2 == NULL) {
+               /*
+                * Ignore it because two expire messages are come up.
+                * phase2 handler has been deleted already when 2nd message
+                * is received.
+                */
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "no such a SA found: %s\n",
+                       sadbsecas2str(src, dst,
+                           msg->sadb_msg_satype, sa->sadb_sa_spi,
+                           sa_mode));
+               return 0;
+       }
+       if (iph2->status != PHASE2ST_ESTABLISHED) {
+               /*
+                * If the status is not equal to PHASE2ST_ESTABLISHED,
+                * racoon ignores this expire message.  There are two reason.
+                * One is that the phase 2 probably starts because there is
+                * a potential that racoon receives the acquire message
+                * without receiving a expire message.  Another is that racoon
+                * may receive the multiple expire messages from the kernel.
+                */
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "the expire message is received "
+                       "but the handler has not been established.\n");
+               return 0;
+       }
+
+       /* turn off the timer for calling isakmp_ph2expire() */ 
+       SCHED_KILL(iph2->sce);
+
+       iph2->status = PHASE2ST_EXPIRED;
+
+       /* INITIATOR, begin phase 2 exchange. */
+       /* allocate buffer for status management of pfkey message */
+       if (iph2->side == INITIATOR) {
+
+               initph2(iph2);
+
+               /* update status for re-use */
+               iph2->status = PHASE2ST_STATUS2;
+
+               /* start isakmp initiation by using ident exchange */
+               if (isakmp_post_acquire(iph2) < 0) {
+                       plog(LLV_ERROR, LOCATION, iph2->dst,
+                               "failed to begin ipsec sa "
+                               "re-negotication.\n");
+                       unbindph12(iph2);
+                       remph2(iph2);
+                       delph2(iph2);
+                       return -1;
+               }
+
+               return 0;
+               /*NOTREACHED*/
+       }
+
+       /* If not received SADB_EXPIRE, INITIATOR delete ph2handle. */
+       /* RESPONDER always delete ph2handle, keep silent.  RESPONDER doesn't
+        * manage IPsec SA, so delete the list */
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+
+       return 0;
+}
+
+static int
+pk_recvacquire(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_x_policy *xpl;
+       struct secpolicy *sp_out = NULL, *sp_in = NULL;
+#define MAXNESTEDSA    5       /* XXX */
+       struct ph2handle *iph2[MAXNESTEDSA];
+       struct sockaddr *src, *dst;
+       int n;  /* # of phase 2 handler */
+
+       /* ignore this message because of local test mode. */
+       if (f_local)
+               return 0;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb acquire message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+       src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+       /* ignore if type is not IPSEC_POLICY_IPSEC */
+       if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "ignore ACQUIRE message. type is not IPsec.\n");
+               return 0;
+       }
+
+       /* ignore it if src is multicast address */
+    {
+       struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+       if ((sa->sa_family == AF_INET
+         && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr)))
+#ifdef INET6
+        || (sa->sa_family == AF_INET6
+         && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr))
+#endif
+       ) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "ignore due to multicast address: %s.\n",
+                       saddrwop2str(sa));
+               return 0;
+       }
+    }
+       
+       /* ignore, if we do not listen on source address */
+       {
+               /* reasons behind:
+                * - if we'll contact peer from address we do not listen -
+                *   we will be unable to complete negotiation;
+                * - if we'll negotiate using address we're listening -
+                *   remote peer will send packets to address different
+                *   than one in the policy, so kernel will drop them;
+                * => therefore this acquire is not for us! --Aidas
+                */
+               struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+               struct myaddrs *p;
+               int do_listen = 0;
+               for (p = lcconf->myaddrs; p; p = p->next) {
+                       if (!cmpsaddrwop(p->addr, sa)) {
+                               do_listen = 1;
+                               break;
+                       }
+               }
+
+               if (!do_listen) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "ignore because do not listen on source address : %s.\n",
+                               saddrwop2str(sa));
+                       return 0;
+               }
+       }
+
+       /*
+        * If there is a phase 2 handler against the policy identifier in
+        * the acquire message, and if
+        *    1. its state is less than PHASE2ST_ESTABLISHED, then racoon
+        *       should ignore such a acquire message because the phase 2
+        *       is just negotiating.
+        *    2. its state is equal to PHASE2ST_ESTABLISHED, then racoon
+        *       has to prcesss such a acquire message because racoon may
+        *       lost the expire message.
+        */
+       iph2[0] = getph2byid(src, dst, xpl->sadb_x_policy_id);
+       if (iph2[0] != NULL) {
+               if (iph2[0]->status < PHASE2ST_ESTABLISHED) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "ignore the acquire because ph2 found\n");
+                       return -1;
+               }
+               if (iph2[0]->status == PHASE2ST_EXPIRED)
+                       iph2[0] = NULL;
+               /*FALLTHROUGH*/
+       }
+
+       /* search for proper policyindex */
+       sp_out = getspbyspid(xpl->sadb_x_policy_id);
+       if (sp_out == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n",
+                       xpl->sadb_x_policy_id);
+               return -1;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx));
+
+       /* get inbound policy */
+    {
+       struct policyindex spidx;
+
+       spidx.dir = IPSEC_DIR_INBOUND;
+       memcpy(&spidx.src, &sp_out->spidx.dst, sizeof(spidx.src));
+       memcpy(&spidx.dst, &sp_out->spidx.src, sizeof(spidx.dst));
+       spidx.prefs = sp_out->spidx.prefd;
+       spidx.prefd = sp_out->spidx.prefs;
+       spidx.ul_proto = sp_out->spidx.ul_proto;
+
+       sp_in = getsp(&spidx);
+       if (sp_in) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "suitable inbound SP found: %s.\n",
+                       spidx2str(&sp_in->spidx));
+       } else {
+               plog(LLV_NOTIFY, LOCATION, NULL,
+                       "no in-bound policy found: %s\n",
+                       spidx2str(&spidx));
+       }
+    }
+
+       memset(iph2, 0, MAXNESTEDSA);
+
+       n = 0;
+
+       /* allocate a phase 2 */
+       iph2[n] = newph2();
+       if (iph2[n] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate phase2 entry.\n");
+               return -1;
+       }
+       iph2[n]->side = INITIATOR;
+       iph2[n]->spid = xpl->sadb_x_policy_id;
+       iph2[n]->satype = msg->sadb_msg_satype;
+       iph2[n]->seq = msg->sadb_msg_seq;
+       iph2[n]->status = PHASE2ST_STATUS2;
+
+       /* set end addresses of SA */
+       iph2[n]->dst = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]));
+       if (iph2[n]->dst == NULL) {
+               delph2(iph2[n]);
+               return -1;
+       }
+       iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]));
+       if (iph2[n]->src == NULL) {
+               delph2(iph2[n]);
+               return -1;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "new acquire %s\n", spidx2str(&sp_out->spidx));
+
+       /* get sainfo */
+    {
+       vchar_t *idsrc, *iddst;
+
+       idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src,
+                               sp_out->spidx.prefs, sp_out->spidx.ul_proto);
+       if (idsrc == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID for %s\n",
+                       spidx2str(&sp_out->spidx));
+               delph2(iph2[n]);
+               return -1;
+       }
+       iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst,
+                               sp_out->spidx.prefd, sp_out->spidx.ul_proto);
+       if (iddst == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get ID for %s\n",
+                       spidx2str(&sp_out->spidx));
+               vfree(idsrc);
+               delph2(iph2[n]);
+               return -1;
+       }
+       iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL);
+       vfree(idsrc);
+       vfree(iddst);
+       if (iph2[n]->sainfo == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get sainfo.\n");
+               delph2(iph2[n]);
+               return -1;
+               /* XXX should use the algorithm list from register message */
+       }
+    }
+
+       if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to create saprop.\n");
+               delph2(iph2[n]);
+               return -1;
+       }
+       insph2(iph2[n]);
+
+       /* start isakmp initiation by using ident exchange */
+       /* XXX should be looped if there are multiple phase 2 handler. */
+       if (isakmp_post_acquire(iph2[n]) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to begin ipsec sa negotication.\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       while (n >= 0) {
+               unbindph12(iph2[n]);
+               remph2(iph2[n]);
+               delph2(iph2[n]);
+               iph2[n] = NULL;
+               n--;
+       }
+       return -1;
+}
+
+static int
+pk_recvdelete(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_sa *sa;
+       struct sockaddr *src, *dst;
+       struct ph2handle *iph2 = NULL;
+       u_int proto_id;
+
+       /* ignore this message because of local test mode. */
+       if (f_local)
+               return 0;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_SA] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb delete message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+       sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+       src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+       dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+       /* the message has to be processed or not ? */
+       if (msg->sadb_msg_pid == getpid()) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "%s message is not interesting "
+                       "because the message was originated by me.\n",
+                       s_pfkey_type(msg->sadb_msg_type));
+               return -1;
+       }
+
+       proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
+       if (proto_id == ~0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid proto_id %d\n", msg->sadb_msg_satype);
+               return -1;
+       }
+
+       iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
+       if (iph2 == NULL) {
+               /* ignore */
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no iph2 found: %s\n",
+                       sadbsecas2str(src, dst, msg->sadb_msg_satype,
+                               sa->sadb_sa_spi, IPSEC_MODE_ANY));
+               return 0;
+       }
+
+       plog(LLV_ERROR, LOCATION, NULL,
+               "pfkey DELETE received: %s\n",
+               sadbsecas2str(iph2->src, iph2->dst,
+                       msg->sadb_msg_satype, sa->sadb_sa_spi, IPSEC_MODE_ANY));
+
+       /* send delete information */
+       if (iph2->status == PHASE2ST_ESTABLISHED)
+               isakmp_info_send_d2(iph2);
+
+       unbindph12(iph2);
+       remph2(iph2);
+       delph2(iph2);
+
+       return 0;
+}
+
+static int
+pk_recvflush(mhp)
+       caddr_t *mhp;
+{
+       /* ignore this message because of local test mode. */
+       if (f_local)
+               return 0;
+
+       /* sanity check */
+       if (mhp[0] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb flush message passed.\n");
+               return -1;
+       }
+
+       flushph2();
+
+       return 0;
+}
+
+static int
+getsadbpolicy(policy0, policylen0, type, iph2)
+       caddr_t *policy0;
+       int *policylen0, type;
+       struct ph2handle *iph2;
+{
+       struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen;
+       struct sadb_x_policy *xpl;
+       struct sadb_x_ipsecrequest *xisr;
+       struct saproto *pr;
+       caddr_t policy, p;
+       int policylen;
+       int xisrlen;
+       u_int satype, mode;
+
+       /* get policy buffer size */
+       policylen = sizeof(struct sadb_x_policy);
+       if (type != SADB_X_SPDDELETE) {
+               for (pr = iph2->approval->head; pr; pr = pr->next) {
+                       xisrlen = sizeof(*xisr);
+                       if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) {
+                               xisrlen += (sysdep_sa_len(iph2->src)
+                                         + sysdep_sa_len(iph2->dst));
+                       }
+
+                       policylen += PFKEY_ALIGN8(xisrlen);
+               }
+       }
+
+       /* make policy structure */
+       policy = racoon_malloc(policylen);
+       if (!policy) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "buffer allocation failed.\n");
+               return -1;
+       }
+
+       xpl = (struct sadb_x_policy *)policy;
+       xpl->sadb_x_policy_len = PFKEY_UNIT64(policylen);
+       xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+       xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+       xpl->sadb_x_policy_dir = spidx->dir;
+       xpl->sadb_x_policy_id = 0;
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       xpl->sadb_x_policy_priority = PRIORITY_DEFAULT;
+#endif
+
+       /* no need to append policy information any more if type is SPDDELETE */
+       if (type == SADB_X_SPDDELETE)
+               goto end;
+
+       xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
+
+       for (pr = iph2->approval->head; pr; pr = pr->next) {
+
+               satype = doi2ipproto(pr->proto_id);
+               if (satype == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid proto_id %d\n", pr->proto_id);
+                       goto err;
+               }
+               mode = ipsecdoi2pfkey_mode(pr->encmode);
+               if (mode == ~0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid encmode %d\n", pr->encmode);
+                       goto err;
+               }
+
+               /* 
+                * the policy level cannot be unique because the policy
+                * is defined later than SA, so req_id cannot be bound to SA.
+                */
+               xisr->sadb_x_ipsecrequest_proto = satype;
+               xisr->sadb_x_ipsecrequest_mode = mode;
+               xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
+               xisr->sadb_x_ipsecrequest_reqid = 0;
+               p = (caddr_t)(xisr + 1);
+
+               xisrlen = sizeof(*xisr);
+
+               if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) {
+                       int src_len, dst_len;
+
+                       src_len = sysdep_sa_len(iph2->src);
+                       dst_len = sysdep_sa_len(iph2->dst);
+                       xisrlen += src_len + dst_len;
+
+                       memcpy(p, iph2->src, src_len);
+                       p += src_len;
+
+                       memcpy(p, iph2->dst, dst_len);
+                       p += dst_len;
+               }
+
+               xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen);
+       }
+
+end:
+       *policy0 = policy;
+       *policylen0 = policylen;
+
+       return 0;
+
+err:
+       if (policy)
+               racoon_free(policy);
+
+       return -1;
+}
+
+int
+pk_sendspdupdate2(iph2)
+       struct ph2handle *iph2;
+{
+       struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen;
+       caddr_t policy = NULL;
+       int policylen = 0;
+       u_int64_t ltime, vtime;
+
+       ltime = iph2->approval->lifetime;
+       vtime = 0;
+
+       if (getsadbpolicy(&policy, &policylen, SADB_X_SPDUPDATE, iph2)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getting sadb policy failed.\n");
+               return -1;
+       }
+
+       if (pfkey_send_spdupdate2(
+                       lcconf->sock_pfkey,
+                       (struct sockaddr *)&spidx->src,
+                       spidx->prefs,
+                       (struct sockaddr *)&spidx->dst,
+                       spidx->prefd,
+                       spidx->ul_proto,
+                       ltime, vtime,
+                       policy, policylen, 0) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed send spdupdate2 (%s)\n",
+                       ipsec_strerror());
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdupdate2\n");
+
+end:
+       if (policy)
+               racoon_free(policy);
+
+       return 0;
+}
+
+static int
+pk_recvspdupdate(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+       struct policyindex spidx;
+       struct secpolicy *sp;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spdupdate message passed.\n");
+               return -1;
+       }
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &spidx);
+#endif
+
+       sp = getsp(&spidx);
+       if (sp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "such policy does not already exist: \"%s\"\n",
+                       spidx2str(&spidx));
+       } else {
+               remsp(sp);
+               delsp(sp);
+       }
+
+       if (addnewsp(mhp) < 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * this function has to be used by responder side.
+ */
+int
+pk_sendspdadd2(iph2)
+       struct ph2handle *iph2;
+{
+       struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen;
+       caddr_t policy = NULL;
+       int policylen = 0;
+       u_int64_t ltime, vtime;
+
+       ltime = iph2->approval->lifetime;
+       vtime = 0;
+
+       if (getsadbpolicy(&policy, &policylen, SADB_X_SPDADD, iph2)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getting sadb policy failed.\n");
+               return -1;
+       }
+
+       if (pfkey_send_spdadd2(
+                       lcconf->sock_pfkey,
+                       (struct sockaddr *)&spidx->src,
+                       spidx->prefs,
+                       (struct sockaddr *)&spidx->dst,
+                       spidx->prefd,
+                       spidx->ul_proto,
+                       ltime, vtime,
+                       policy, policylen, 0) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed send spdadd2 (%s)\n",
+                       ipsec_strerror());
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdadd2\n");
+
+end:
+       if (policy)
+               racoon_free(policy);
+
+       return 0;
+}
+
+static int
+pk_recvspdadd(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+       struct policyindex spidx;
+       struct secpolicy *sp;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spdadd message passed.\n");
+               return -1;
+       }
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &spidx);
+#endif
+
+       sp = getsp(&spidx);
+       if (sp != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "such policy already exists. "
+                       "anyway replace it: %s\n",
+                       spidx2str(&spidx));
+               remsp(sp);
+               delsp(sp);
+       }
+
+       if (addnewsp(mhp) < 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * this function has to be used by responder side.
+ */
+int
+pk_sendspddelete(iph2)
+       struct ph2handle *iph2;
+{
+       struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen;
+       caddr_t policy = NULL;
+       int policylen;
+
+       if (getsadbpolicy(&policy, &policylen, SADB_X_SPDDELETE, iph2)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getting sadb policy failed.\n");
+               return -1;
+       }
+
+       if (pfkey_send_spddelete(
+                       lcconf->sock_pfkey,
+                       (struct sockaddr *)&spidx->src,
+                       spidx->prefs,
+                       (struct sockaddr *)&spidx->dst,
+                       spidx->prefd,
+                       spidx->ul_proto,
+                       policy, policylen, 0) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "libipsec failed send spddelete (%s)\n",
+                       ipsec_strerror());
+               goto end;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spddelete\n");
+
+end:
+       if (policy)
+               racoon_free(policy);
+
+       return 0;
+}
+
+static int
+pk_recvspddelete(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+       struct policyindex spidx;
+       struct secpolicy *sp;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spddelete message passed.\n");
+               return -1;
+       }
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &spidx);
+#endif
+
+       sp = getsp(&spidx);
+       if (sp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no policy found: %s\n",
+                       spidx2str(&spidx));
+               return -1;
+       }
+
+       remsp(sp);
+       delsp(sp);
+
+       return 0;
+}
+
+static int
+pk_recvspdexpire(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+       struct policyindex spidx;
+       struct secpolicy *sp;
+
+       /* sanity check */
+       if (mhp[0] == NULL
+        || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spdexpire message passed.\n");
+               return -1;
+       }
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &spidx);
+#endif
+
+       sp = getsp(&spidx);
+       if (sp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "no policy found: %s\n",
+                       spidx2str(&spidx));
+               return -1;
+       }
+
+       remsp(sp);
+       delsp(sp);
+
+       return 0;
+}
+
+static int
+pk_recvspdget(mhp)
+       caddr_t *mhp;
+{
+       /* sanity check */
+       if (mhp[0] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spdget message passed.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+pk_recvspddump(mhp)
+       caddr_t *mhp;
+{
+       struct sadb_msg *msg;
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+       struct policyindex spidx;
+       struct secpolicy *sp;
+
+       /* sanity check */
+       if (mhp[0] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spddump message passed.\n");
+               return -1;
+       }
+       msg = (struct sadb_msg *)mhp[0];
+
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+       if (saddr == NULL || daddr == NULL || xpl == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spddump message passed.\n");
+               return -1;
+       }
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &spidx);
+#endif
+
+       sp = getsp(&spidx);
+       if (sp != NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "such policy already exists. "
+                       "anyway replace it: %s\n",
+                       spidx2str(&spidx));
+               remsp(sp);
+               delsp(sp);
+       }
+
+       if (addnewsp(mhp) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int
+pk_recvspdflush(mhp)
+       caddr_t *mhp;
+{
+       /* sanity check */
+       if (mhp[0] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spdflush message passed.\n");
+               return -1;
+       }
+
+       flushsp();
+
+       return 0;
+}
+
+/*
+ * send error against acquire message to kenrel.
+ */
+int
+pk_sendeacquire(iph2)
+       struct ph2handle *iph2;
+{
+       struct sadb_msg *newmsg;
+       int len;
+
+       len = sizeof(struct sadb_msg);
+       newmsg = racoon_calloc(1, len);
+       if (newmsg == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get buffer to send acquire.\n");
+               return -1;
+       }
+
+       memset(newmsg, 0, len);
+       newmsg->sadb_msg_version = PF_KEY_V2;
+       newmsg->sadb_msg_type = SADB_ACQUIRE;
+       newmsg->sadb_msg_errno = ENOENT;        /* XXX */
+       newmsg->sadb_msg_satype = iph2->satype;
+       newmsg->sadb_msg_len = PFKEY_UNIT64(len);
+       newmsg->sadb_msg_reserved = 0;
+       newmsg->sadb_msg_seq = iph2->seq;
+       newmsg->sadb_msg_pid = (u_int32_t)getpid();
+
+       /* send message */
+       len = pfkey_send(lcconf->sock_pfkey, newmsg, len);
+
+       racoon_free(newmsg);
+
+       return 0;
+}
+
+/*
+ * check if the algorithm is supported or not.
+ * OUT  0: ok
+ *     -1: ng
+ */
+int
+pk_checkalg(class, calg, keylen)
+       int class, calg, keylen;
+{
+       int sup, error;
+       u_int alg;
+       struct sadb_alg alg0;
+
+       switch (algclass2doi(class)) {
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               sup = SADB_EXT_SUPPORTED_ENCRYPT;
+               break;
+       case IPSECDOI_ATTR_AUTH:
+               sup = SADB_EXT_SUPPORTED_AUTH;
+               break;
+       case IPSECDOI_PROTO_IPCOMP:
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "compression algorithm can not be checked "
+                       "because sadb message doesn't support it.\n");
+               return 0;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid algorithm class.\n");
+               return -1;
+       }
+       alg = ipsecdoi2pfkey_alg(algclass2doi(class), algtype2doi(class, calg));
+       if (alg == ~0)
+               return -1;
+
+       if (keylen == 0) {
+               if (ipsec_get_keylen(sup, alg, &alg0)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "%s.\n", ipsec_strerror());
+                       return -1;
+               }
+               keylen = alg0.sadb_alg_minbits;
+       }
+
+       error = ipsec_check_keylen(sup, alg, keylen);
+       if (error)
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "%s.\n", ipsec_strerror());
+
+       return error;
+}
+
+/*
+ * differences with pfkey_recv() in libipsec/pfkey.c:
+ * - never performs busy wait loop.
+ * - returns NULL and set *lenp to negative on fatal failures
+ * - returns NULL and set *lenp to non-negative on non-fatal failures
+ * - returns non-NULL on success
+ */
+static struct sadb_msg *
+pk_recv(so, lenp)
+       int so;
+       int *lenp;
+{
+       struct sadb_msg buf, *newmsg;
+       int reallen;
+
+       *lenp = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK);
+       if (*lenp < 0)
+               return NULL;    /*fatal*/
+       else if (*lenp < sizeof(buf))
+               return NULL;
+
+       reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+       if ((newmsg = racoon_calloc(1, reallen)) == NULL)
+               return NULL;
+
+       *lenp = recv(so, (caddr_t)newmsg, reallen, MSG_PEEK);
+       if (*lenp < 0) {
+               racoon_free(newmsg);
+               return NULL;    /*fatal*/
+       } else if (*lenp != reallen) {
+               racoon_free(newmsg);
+               return NULL;
+       }
+
+       *lenp = recv(so, (caddr_t)newmsg, reallen, 0);
+       if (*lenp < 0) {
+               racoon_free(newmsg);
+               return NULL;    /*fatal*/
+       } else if (*lenp != reallen) {
+               racoon_free(newmsg);
+               return NULL;
+       }
+
+       return newmsg;
+}
+
+/* see handler.h */
+u_int32_t
+pk_getseq()
+{
+       return eay_random();
+}
+
+static int
+addnewsp(mhp)
+       caddr_t *mhp;
+{
+       struct secpolicy *new;
+       struct sadb_address *saddr, *daddr;
+       struct sadb_x_policy *xpl;
+
+       /* sanity check */
+       if (mhp[SADB_EXT_ADDRESS_SRC] == NULL
+        || mhp[SADB_EXT_ADDRESS_DST] == NULL
+        || mhp[SADB_X_EXT_POLICY] == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "inappropriate sadb spd management message passed.\n");
+               return -1;
+       }
+
+       saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+       daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+       xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+
+#ifdef __linux__
+       /* bsd skips over per-socket policies because there will be no
+        * src and dst extensions in spddump messages. On Linux the only
+        * way to achieve the same is check for policy id.
+        */
+       if (xpl->sadb_x_policy_id % 8 >= 3) return 0;
+#endif
+
+       new = newsp();
+       if (new == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer\n");
+               return -1;
+       }
+
+       new->spidx.dir = xpl->sadb_x_policy_dir;
+       new->id = xpl->sadb_x_policy_id;
+       new->policy = xpl->sadb_x_policy_type;
+       new->req = NULL;
+
+       /* check policy */
+       switch (xpl->sadb_x_policy_type) {
+       case IPSEC_POLICY_DISCARD:
+       case IPSEC_POLICY_GENERATE:
+       case IPSEC_POLICY_NONE:
+       case IPSEC_POLICY_ENTRUST:
+       case IPSEC_POLICY_BYPASS:
+               break;
+
+       case IPSEC_POLICY_IPSEC:
+           {
+               int tlen;
+               struct sadb_x_ipsecrequest *xisr;
+               struct ipsecrequest **p_isr = &new->req;
+
+               /* validity check */
+               if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid msg length.\n");
+                       return -1;
+               }
+
+               tlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl);
+               xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
+
+               while (tlen > 0) {
+
+                       /* length check */
+                       if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid msg length.\n");
+                               return -1;
+                       }
+
+                       /* allocate request buffer */
+                       *p_isr = newipsecreq();
+                       if (*p_isr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to get new ipsecreq.\n");
+                               return -1;
+                       }
+
+                       /* set values */
+                       (*p_isr)->next = NULL;
+
+                       switch (xisr->sadb_x_ipsecrequest_proto) {
+                       case IPPROTO_ESP:
+                       case IPPROTO_AH:
+                       case IPPROTO_IPCOMP:
+                               break;
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid proto type: %u\n",
+                                       xisr->sadb_x_ipsecrequest_proto);
+                               return -1;
+                       }
+                       (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto;
+
+                       switch (xisr->sadb_x_ipsecrequest_mode) {
+                       case IPSEC_MODE_TRANSPORT:
+                       case IPSEC_MODE_TUNNEL:
+                               break;
+                       case IPSEC_MODE_ANY:
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid mode: %u\n",
+                                       xisr->sadb_x_ipsecrequest_mode);
+                               return -1;
+                       }
+                       (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode;
+
+                       switch (xisr->sadb_x_ipsecrequest_level) {
+                       case IPSEC_LEVEL_DEFAULT:
+                       case IPSEC_LEVEL_USE:
+                       case IPSEC_LEVEL_REQUIRE:
+                               break;
+                       case IPSEC_LEVEL_UNIQUE:
+                               (*p_isr)->saidx.reqid =
+                                       xisr->sadb_x_ipsecrequest_reqid;
+                               break;
+
+                       default:
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid level: %u\n",
+                                       xisr->sadb_x_ipsecrequest_level);
+                               return -1;
+                       }
+                       (*p_isr)->level = xisr->sadb_x_ipsecrequest_level;
+
+                       /* set IP addresses if there */
+                       if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+                               struct sockaddr *paddr;
+
+                               paddr = (struct sockaddr *)(xisr + 1);
+                               bcopy(paddr, &(*p_isr)->saidx.src,
+                                       sysdep_sa_len(paddr));
+
+                               paddr = (struct sockaddr *)((caddr_t)paddr
+                                                       + sysdep_sa_len(paddr));
+                               bcopy(paddr, &(*p_isr)->saidx.dst,
+                                       sysdep_sa_len(paddr));
+                       }
+
+                       (*p_isr)->sp = new;
+
+                       /* initialization for the next. */
+                       p_isr = &(*p_isr)->next;
+                       tlen -= xisr->sadb_x_ipsecrequest_len;
+
+                       /* validity check */
+                       if (tlen < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "becoming tlen < 0\n");
+                       }
+
+                       xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr
+                                        + xisr->sadb_x_ipsecrequest_len);
+               }
+           }
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid policy type.\n");
+               return -1;
+       }
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       xpl->sadb_x_policy_priority,
+                       &new->spidx);
+#else
+       KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+                       saddr + 1,
+                       daddr + 1,
+                       saddr->sadb_address_prefixlen,
+                       daddr->sadb_address_prefixlen,
+                       saddr->sadb_address_proto,
+                       &new->spidx);
+#endif
+
+       inssp(new);
+
+       return 0;
+}
+
+/* proto/mode/src->dst spi */
+const char *
+sadbsecas2str(src, dst, proto, spi, mode)
+       struct sockaddr *src, *dst;
+       int proto;
+       u_int32_t spi;
+       int mode;
+{
+       static char buf[256];
+       u_int doi_proto, doi_mode = 0;
+       char *p;
+       int blen, i;
+
+       doi_proto = pfkey2ipsecdoi_proto(proto);
+       if (doi_proto == ~0)
+               return NULL;
+       if (mode) {
+               doi_mode = pfkey2ipsecdoi_mode(mode);
+               if (doi_mode == ~0)
+                       return NULL;
+       }
+
+       blen = sizeof(buf) - 1;
+       p = buf;
+
+       i = snprintf(p, blen, "%s%s%s ",
+               s_ipsecdoi_proto(doi_proto),
+               mode ? "/" : "",
+               mode ? s_ipsecdoi_encmode(doi_mode) : "");
+       if (i < 0 || i >= blen)
+               return NULL;
+       p += i;
+       blen -= i;
+
+       i = snprintf(p, blen, "%s->", saddr2str(src));
+       if (i < 0 || i >= blen)
+               return NULL;
+       p += i;
+       blen -= i;
+
+       i = snprintf(p, blen, "%s ", saddr2str(dst));
+       if (i < 0 || i >= blen)
+               return NULL;
+       p += i;
+       blen -= i;
+
+       if (spi) {
+               snprintf(p, blen, "spi=%lu(0x%lx)", (unsigned long)ntohl(spi),
+                   (unsigned long)ntohl(spi));
+       }
+
+       return buf;
+}
diff --git a/ipsec-tools/racoon/plainrsa-gen.8 b/ipsec-tools/racoon/plainrsa-gen.8
new file mode 100644 (file)
index 0000000..0f059f8
--- /dev/null
@@ -0,0 +1,137 @@
+.\" $Id: plainrsa-gen.8,v 1.2.10.1 2005/04/18 11:10:55 manubsd Exp $
+.\"
+.\" Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+.\" Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+.\" 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.
+.\"
+.Dd June 14, 2004
+.Dt PLAINRSA-GEN 8
+.Os
+.\"
+.Sh NAME
+.Nm plainrsa-gen
+.Nd generator for Plain RSA keys
+.\"
+.Sh SYNOPSIS
+.Nm plainrsa-gen
+.Bk -words
+.Op Fl b Ar bits
+.Op Fl e Ar pubexp
+.Op Fl f Ar outfile
+.Op Fl h
+.Ek
+.\"
+.Sh DESCRIPTION
+.Nm
+can be used to generate
+.Li Plain RSA keys
+for authentication purposes.
+Using
+.Li Plain RSA keys
+is optional.
+Other possibilities are
+.Li Pre-shared keys
+or
+.Li X.509 certificates .
+.\"
+.Bl -tag -width Ds
+.It Fl b Ar bits
+bit length of the key.
+Default is
+.Li 1024 ,
+recommended length is
+.Li 2048
+or even
+.Li 4096
+bits.
+Note that generating longer keys takes more time.
+.It Fl e Ar pubexp
+value of the RSA public exponent.
+Default is
+.Li 0x3 .
+Don't change this unless you really know what you are doing!
+.It Fl f Ar outfile
+write the resulting key to
+.Ar outfile
+instead of
+.Li stdout .
+If the file already exists it won't be overwritten.
+You wouldn't like to lose your private key by accident, would you?
+.El
+.\"
+.Sh OUTPUT FILE FORMAT
+This is the secret
+.Li private key
+that should
+.Ic never
+leave your computer:
+.Bd -literal
+: RSA  {
+       # RSA 1024 bits
+       # pubkey=0sAQOrWlcwbAIdNSMhDt...
+       Modulus: 0xab5a57306c021d3523...
+       PublicExponent: 0x03
+       PrivateExponent: 0x723c3a2048...
+       Prime1: 0xd309b30e6adf9d85c01...
+       Prime2: 0xcfdc2a8aa5b2b3c90e3...
+       Exponent1: 0x8cb122099c9513ae...
+       Exponent2: 0x8a92c7071921cd30...
+       Coefficient: 0x722751305eafe9...
+  }
+.Ed
+.Pp
+The line
+.Li pubkey=0sAQOrW...
+of the
+.Li private key
+contains a
+.Li public key
+that should be stored in the other peer's configuration in this format:
+.Bd -literal
+: PUB 0sAQOrWlcwbAIdNSMhDt...
+.Ed
+.\"
+.Pp
+You can also specify
+.Li from
+and
+.Li to
+addresses for which the key is valid:
+.Bd -literal
+0.0.0.0/0 10.20.30.0/24 : PUB 0sAQOrWlcwbAIdNSMhDt...
+.Ed
+.\"
+.Sh SEE ALSO
+.Xr racoon.conf 5 ,
+.Xr racoon 8
+.\"
+.Sh HISTORY
+.Nm
+was written by
+.An Michal Ludvig Aq michal@logix.cz
+and first appeared in
+.Ic ipsec-tools 0.4 .
diff --git a/ipsec-tools/racoon/plainrsa-gen.c b/ipsec-tools/racoon/plainrsa-gen.c
new file mode 100644 (file)
index 0000000..974f3cb
--- /dev/null
@@ -0,0 +1,209 @@
+/* $Id: plainrsa-gen.c,v 1.4.8.2 2005/04/21 09:07:20 monas Exp $ */
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+/* This file contains a generator for FreeS/WAN-style ipsec.secrets RSA keys. */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "crypto_openssl.h"
+
+//#include "package_version.h"
+
+int print_pid = 0;
+
+void
+usage (char *argv0)
+{
+       //%%% fprintf(stderr, "Plain RSA key generator, part of %s\n", TOP_PACKAGE_STRING);
+       fprintf(stderr, "Plain RSA key generator\n");
+       fprintf(stderr, "By Michal Ludvig (http://www.logix.cz/michal)\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Usage: %s [options]\n", argv0);
+       fprintf(stderr, "\n");
+       fprintf(stderr, "  -b bits       Generate <bits> long RSA key (default=1024)\n");
+       fprintf(stderr, "  -e pubexp     Public exponent to use (default=0x3)\n");
+       fprintf(stderr, "  -f filename   Filename to store the key to (default=stdout)\n");
+       fprintf(stderr, "  -h            Help\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Report bugs to <ipsec-tools-devel@lists.sourceforge.net>\n");
+       exit(1);
+}
+
+/*
+ * See RFC 2065, section 3.5 for details about the output format.
+ */
+vchar_t *
+mix_b64_pubkey(RSA *key)
+{
+       char *binbuf;
+       long binlen, ret;
+       vchar_t *res;
+       
+       binlen = 1 + BN_num_bytes(key->e) + BN_num_bytes(key->n);
+       binbuf = malloc(binlen);
+       memset(binbuf, 0, binlen);
+       binbuf[0] = BN_bn2bin(key->e, (unsigned char *) &binbuf[1]);
+       ret = BN_bn2bin(key->n, (unsigned char *) (&binbuf[binbuf[0] + 1]));
+       if (1 + binbuf[0] + ret != binlen) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                    "Pubkey generation failed. This is really strange...\n");
+               return NULL;
+       }
+
+       return base64_encode(binbuf, binlen);
+}
+
+char *
+lowercase(char *input)
+{
+       char *ptr = input;
+       while (*ptr) {
+               if (*ptr >= 'A' && *ptr <= 'F')
+                       *ptr -= 'A' - 'a';
+               *ptr++;
+       }
+
+       return input;
+}
+
+int
+gen_rsa_key(FILE *fp, size_t bits, unsigned long exp)
+{
+       RSA *key;
+       vchar_t *pubkey64 = NULL;
+
+       key = RSA_generate_key(bits, exp, NULL, NULL);
+       if (!key) {
+               fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror());
+               return -1;
+       }
+       
+       pubkey64 = mix_b64_pubkey(key);
+       if (!pubkey64) {
+               fprintf(stderr, "mix_b64_pubkey(): %s\n", eay_strerror());
+               return -1;
+       }
+       
+       fprintf(fp, "# : PUB 0s%s\n", pubkey64->v);
+       fprintf(fp, ": RSA\t{\n");
+       fprintf(fp, "\t# RSA %zu bits\n", bits);
+       fprintf(fp, "\t# pubkey=0s%s\n", pubkey64->v);
+       fprintf(fp, "\tModulus: 0x%s\n", lowercase(BN_bn2hex(key->n)));
+       fprintf(fp, "\tPublicExponent: 0x%s\n", lowercase(BN_bn2hex(key->e)));
+       fprintf(fp, "\tPrivateExponent: 0x%s\n", lowercase(BN_bn2hex(key->d)));
+       fprintf(fp, "\tPrime1: 0x%s\n", lowercase(BN_bn2hex(key->p)));
+       fprintf(fp, "\tPrime2: 0x%s\n", lowercase(BN_bn2hex(key->q)));
+       fprintf(fp, "\tExponent1: 0x%s\n", lowercase(BN_bn2hex(key->dmp1)));
+       fprintf(fp, "\tExponent2: 0x%s\n", lowercase(BN_bn2hex(key->dmq1)));
+       fprintf(fp, "\tCoefficient: 0x%s\n", lowercase(BN_bn2hex(key->iqmp)));
+       fprintf(fp, "  }\n");
+
+       vfree(pubkey64);
+
+       return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+       FILE *fp = stdout;
+       size_t bits = 1024;
+       unsigned int pubexp = 0x3;
+       struct stat st;
+       extern char *optarg;
+       extern int optind;
+       int c;
+       char *fname = NULL;
+
+       while ((c = getopt(argc, argv, "e:b:f:h")) != -1)
+               switch (c) {
+                       case 'e':
+                               if (strncmp(optarg, "0x", 2) == 0)
+                                       sscanf(optarg, "0x%x", &pubexp);
+                               else
+                                       pubexp = atoi(optarg);
+                               break;
+                       case 'b':
+                               bits = atoi(optarg);
+                               break;
+                       case 'f':
+                               fname = optarg;
+                               break;
+                       case 'h':
+                       default:
+                               usage(argv[0]);
+               }
+
+       if (fname) {
+               if (stat(fname, &st) >= 0) {
+                       fprintf(stderr, "%s: file exists! Please use a different name.\n", fname);
+                       exit(1);
+               }
+
+               umask(0077);
+               fp = fopen(fname, "w");
+               if (fp == NULL) {
+                       fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+                       exit(1);
+               }
+       }
+
+       ploginit();
+       eay_init();
+
+       gen_rsa_key(fp, bits, pubexp);
+
+       fclose(fp);
+
+       return 0;
+}
diff --git a/ipsec-tools/racoon/plog.c b/ipsec-tools/racoon/plog.c
new file mode 100644 (file)
index 0000000..6b00980
--- /dev/null
@@ -0,0 +1,270 @@
+/* $Id: plog.c,v 1.6.10.1 2005/12/07 10:19:51 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <ctype.h>
+#include <err.h>
+
+#include "var.h"
+#include "misc.h"
+#include "plog.h"
+#include "logger.h"
+#include "debug.h"
+#include "gcmalloc.h"
+
+#ifndef VA_COPY
+# define VA_COPY(dst,src) memcpy(&(dst), &(src), sizeof(va_list))
+#endif
+
+extern int print_pid;
+
+char *pname = NULL;
+u_int32_t loglevel = LLV_BASE;
+int f_foreground = 0;
+
+int print_location = 0;
+
+static struct log *logp = NULL;
+static char *logfile = NULL;
+
+static char *plog_common __P((int, const char *, const char *));
+
+static struct plogtags {
+       char *name;
+       int priority;
+} ptab[] = {
+       { "(not defined)",      0, },
+       { "INFO",               LOG_INFO, },
+       { "NOTIFY",             LOG_INFO, },
+       { "WARNING",    LOG_INFO, },
+       { "ERROR",              LOG_INFO, },
+       { "ERROR",              LOG_ERR, },
+       { "DEBUG",              LOG_DEBUG, },
+       { "DEBUG2",             LOG_DEBUG, },
+};
+
+static char *
+plog_common(pri, fmt, func)
+       int pri;
+       const char *fmt, *func;
+{
+       static char buf[800];   /* XXX shoule be allocated every time ? */
+       char *p;
+       int reslen, len;
+
+       p = buf;
+       reslen = sizeof(buf);
+
+       if (logfile || f_foreground) {
+               time_t t;
+               struct tm *tm;
+
+               t = time(0);
+               tm = localtime(&t);
+               len = strftime(p, reslen, "%Y-%m-%d %T: ", tm);
+               p += len;
+               reslen -= len;
+       }
+
+       if (pri < ARRAYLEN(ptab)) {
+               if (print_pid)
+                       len = snprintf(p, reslen, "[%d] %s: ", getpid(), ptab[pri].name);
+               else
+                       len = snprintf(p, reslen, "%s: ", ptab[pri].name);                      
+               if (len >= 0 && len < reslen) {
+                       p += len;
+                       reslen -= len;
+               } else
+                       *p = '\0';
+       }
+
+       if (print_location)
+               snprintf(p, reslen, "%s: %s", func, fmt);
+       else
+               snprintf(p, reslen, "%s", fmt);
+#ifdef BROKEN_PRINTF
+    while ((p = strstr(buf,"%z")) != NULL)
+               p[1] = 'l';
+#endif
+
+       return buf;
+}
+
+void
+plog(int pri, const char *func, struct sockaddr *sa, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       plogv(pri, func, sa, fmt, ap);
+       va_end(ap);
+}
+
+void
+plogv(int pri, const char *func, struct sockaddr *sa,
+       const char *fmt, va_list ap)
+{
+       char *newfmt;
+       va_list ap_bak;
+
+       if (pri > loglevel)
+               return;
+
+       newfmt = plog_common(pri, fmt, func);
+
+       VA_COPY(ap_bak, ap);
+       
+       if (f_foreground)
+               vprintf(newfmt, ap);
+
+       if (logfile)
+               log_vaprint(logp, newfmt, ap_bak);
+       else {
+               if (pri < ARRAYLEN(ptab))
+                       vsyslog(ptab[pri].priority, newfmt, ap_bak);
+               else
+                       vsyslog(LOG_ALERT, newfmt, ap_bak);
+       }
+}
+
+void
+plogdump(pri, data, len)
+       int pri;
+       void *data;
+       size_t len;
+{
+       caddr_t buf;
+       size_t buflen;
+       int i, j;
+
+       if (pri > loglevel)
+               return;
+
+       /*
+        * 2 words a bytes + 1 space 4 bytes + 1 newline 32 bytes
+        * + 2 newline + '\0'
+        */
+       buflen = (len * 2) + (len / 4) + (len / 32) + 3;
+       buf = racoon_malloc(buflen);
+
+       i = 0;
+       j = 0;
+       while (j < len) {
+               if (j % 32 == 0)
+                       buf[i++] = '\n';
+               else
+               if (j % 4 == 0)
+                       buf[i++] = ' ';
+               snprintf(&buf[i], buflen - i, "%02x",
+                       ((unsigned char *)data)[j] & 0xff);
+               i += 2;
+               j++;
+       }
+       if (buflen - i >= 2) {
+               buf[i++] = '\n';
+               buf[i] = '\0';
+       }
+       plog(pri, LOCATION, NULL, "%s", buf);
+
+       racoon_free(buf);
+}
+
+void
+ploginit()
+{
+       if (logfile) {
+               logp = log_open(250, logfile);
+               if (logp == NULL)
+                       errx(1, "ERROR: failed to open log file %s.", logfile);
+               return;
+       }
+                       
+       openlog(pname, LOG_NDELAY, LOG_DAEMON);
+}
+
+void
+plogset(file)
+       char *file;
+{
+       if (logfile != NULL)
+               racoon_free(logfile);
+       logfile = strdup(file);
+}
+
+void
+plogreset(file)
+       char *file;
+{
+       
+       /* if log paths equal - do nothing */
+       if (logfile == NULL && file == NULL)
+               return;
+       if (logfile != NULL && file != NULL)
+               if (!strcmp(logfile, file))
+                       return;
+               
+       if (logfile == NULL)    /* no logfile was specified  - daemon was used */
+               closelog();     /* close it */
+       else {
+               log_close(logp);
+               logp = NULL;
+               racoon_free(logfile);
+               logfile = NULL;
+       }
+       
+       if (file)
+               plogset(file);
+       ploginit();
+}                      
+                       
diff --git a/ipsec-tools/racoon/plog.h b/ipsec-tools/racoon/plog.h
new file mode 100644 (file)
index 0000000..d1448df
--- /dev/null
@@ -0,0 +1,78 @@
+/* $Id: plog.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PLOG_H
+#define _PLOG_H
+
+#include "config.h"
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <syslog.h>
+
+/*
+ * INFO: begin negotiation, SA establishment/deletion/expiration.
+ * NOTIFY: just notifiable.
+ * WARNING: not error strictly.
+ * ERROR: system call error. also invalid parameter/format.
+ * ERROR2: error causing exit - to be logged to syslog.
+ * DEBUG1: debugging informatioin.
+ * DEBUG2: too more verbose. e.g. parsing config.
+ */
+#define LLV_INFO       1
+#define LLV_NOTIFY     2
+#define LLV_WARNING    3
+#define LLV_ERROR      4
+#define LLV_ERROR2     5
+#define LLV_DEBUG      6
+#define LLV_DEBUG2     7
+#define LLV_BASE       5       /* always logging less than or equal to this value. */
+
+extern char *pname;
+extern u_int32_t loglevel;
+extern int f_foreground;
+extern int print_location;
+
+struct sockaddr;
+extern void plog __P((int, const char *, struct sockaddr *, const char *, ...))
+       __attribute__ ((__format__ (__printf__, 4, 5)));
+extern void plogv __P((int, const char *, struct sockaddr *,
+       const char *, va_list));
+extern void plogdump __P((int, void *, size_t));
+extern void ploginit __P((void));
+extern void plogset __P((char *));
+extern void plogreset __P((char *));
+
+#endif /* _PLOG_H */
diff --git a/ipsec-tools/racoon/policy.c b/ipsec-tools/racoon/policy.c
new file mode 100644 (file)
index 0000000..d553d26
--- /dev/null
@@ -0,0 +1,481 @@
+/*     $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "policy.h"
+#include "localconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "handler.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+#include "session.h"
+
+static TAILQ_HEAD(_sptree, secpolicy) sptree;
+
+/* perform exact match against security policy table. */
+struct secpolicy *
+getsp(spidx)
+       struct policyindex *spidx;
+{
+       struct secpolicy *p;
+
+       for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
+               if (!cmpspidxstrict(spidx, &p->spidx))
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * perform non-exact match against security policy table, only if this is
+ * transport mode SA negotiation.  for example, 0.0.0.0/0 -> 0.0.0.0/0
+ * entry in policy.txt can be returned when we're negotiating transport
+ * mode SA.  this is how the kernel works.
+ */
+#if 1
+struct secpolicy *
+getsp_r(spidx)
+       struct policyindex *spidx;
+{
+       struct secpolicy *p;
+
+       for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
+               if (!cmpspidxwild(spidx, &p->spidx))
+                       return p;
+       }
+
+       return NULL;
+}
+#else
+struct secpolicy *
+getsp_r(spidx, iph2)
+       struct policyindex *spidx;
+       struct ph2handle *iph2;
+{
+       struct secpolicy *p;
+       u_int8_t prefixlen;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n");
+
+       if (spidx->src.ss_family != spidx->dst.ss_family) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "address family mismatch, src:%d dst:%d\n",
+                               spidx->src.ss_family,
+                               spidx->dst.ss_family);
+               return NULL;
+       }
+       switch (spidx->src.ss_family) {
+       case AF_INET:
+               prefixlen = sizeof(struct in_addr) << 3;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               prefixlen = sizeof(struct in6_addr) << 3;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid family: %d\n", spidx->src.ss_family);
+               return NULL;
+       }
+
+       /* is it transport mode SA negotiation? */
+       plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n",
+               saddr2str(iph2->src));
+       plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n",
+               saddr2str((struct sockaddr *)&spidx->src));
+       if (cmpsaddrwop(iph2->src, (struct sockaddr *)&spidx->src)
+        || spidx->prefs != prefixlen)
+               return NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n",
+               saddr2str(iph2->dst));
+       plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n",
+               saddr2str((struct sockaddr *)&spidx->dst));
+       if (cmpsaddrwop(iph2->dst, (struct sockaddr *)&spidx->dst)
+        || spidx->prefd != prefixlen)
+               return NULL;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
+
+       for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
+               if (!cmpspidx_wild(spidx, &p->spidx))
+                       return p;
+       }
+
+       return NULL;
+}
+#endif
+
+struct secpolicy *
+getspbyspid(spid)
+       u_int32_t spid;
+{
+       struct secpolicy *p;
+
+       for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
+               if (p->id == spid)
+                       return p;
+       }
+
+       return NULL;
+}
+
+/*
+ * compare policyindex.
+ * a: subject b: db
+ * OUT:        0:      equal
+ *     1:      not equal
+ */
+int
+cmpspidxstrict(a, b)
+       struct policyindex *a, *b;
+{
+       plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
+       plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b));
+
+       /* XXX don't check direction now, but it's to be checked carefully. */
+       if (a->dir != b->dir
+        || a->prefs != b->prefs
+        || a->prefd != b->prefd
+        || a->ul_proto != b->ul_proto)
+               return 1;
+
+       if (cmpsaddrstrict((struct sockaddr *)&a->src,
+                          (struct sockaddr *)&b->src))
+               return 1;
+       if (cmpsaddrstrict((struct sockaddr *)&a->dst,
+                          (struct sockaddr *)&b->dst))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * compare policyindex, with wildcard address/protocol match.
+ * a: subject b: db, can contain wildcard things.
+ * OUT:        0:      equal
+ *     1:      not equal
+ */
+int
+cmpspidxwild(a, b)
+       struct policyindex *a, *b;
+{
+       struct sockaddr_storage sa1, sa2;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
+       plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b));
+
+       if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
+               return 1;
+
+       if (!(a->ul_proto == IPSEC_ULPROTO_ANY ||
+             b->ul_proto == IPSEC_ULPROTO_ANY ||
+             a->ul_proto == b->ul_proto))
+               return 1;
+
+       if (a->src.ss_family != b->src.ss_family)
+               return 1;
+       if (a->dst.ss_family != b->dst.ss_family)
+               return 1;
+
+#ifndef __linux__
+       /* compare src address */
+       if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unexpected error: "
+                       "src.ss_len:%d dst.ss_len:%d\n",
+                       a->src.ss_len, b->src.ss_len);
+               return 1;
+       }
+#endif
+       mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src,
+               b->prefs);
+       mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src,
+               b->prefs);
+       plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
+               a, b->prefs, saddr2str((struct sockaddr *)&sa1));
+       plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
+               b, b->prefs, saddr2str((struct sockaddr *)&sa2));
+       if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
+               return 1;
+
+#ifndef __linux__
+       /* compare dst address */
+       if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) {
+               plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n");
+               exit(1);
+       }
+#endif
+       mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst,
+               b->prefd);
+       mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst,
+               b->prefd);
+       plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
+               a, b->prefd, saddr2str((struct sockaddr *)&sa1));
+       plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
+               b, b->prefd, saddr2str((struct sockaddr *)&sa2));
+       if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
+               return 1;
+
+       return 0;
+}
+
+struct secpolicy *
+newsp()
+{
+       struct secpolicy *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+void
+delsp(sp)
+       struct secpolicy *sp;
+{
+       struct ipsecrequest *req = NULL, *next;
+
+       for (req = sp->req; req; req = next) {
+               next = req->next;
+               racoon_free(req);
+       }
+       
+       racoon_free(sp);
+}
+
+void
+delsp_bothdir(spidx0)
+       struct policyindex *spidx0;
+{
+       struct policyindex spidx;
+       struct secpolicy *sp;
+       struct sockaddr_storage src, dst;
+       u_int8_t prefs, prefd;
+
+       memcpy(&spidx, spidx0, sizeof(spidx));
+       switch (spidx.dir) {
+       case IPSEC_DIR_INBOUND:
+#ifdef HAVE_POLICY_FWD
+       case IPSEC_DIR_FWD:
+#endif
+               src   = spidx.src;
+               dst   = spidx.dst;
+               prefs = spidx.prefs;
+               prefd = spidx.prefd;
+               break;
+       case IPSEC_DIR_OUTBOUND:
+               src   = spidx.dst;
+               dst   = spidx.src;
+               prefs = spidx.prefd;
+               prefd = spidx.prefs;
+               break;
+       default:
+               return;
+       }
+
+       spidx.src   = src;
+       spidx.dst   = dst;
+       spidx.prefs = prefs;
+       spidx.prefd = prefd;
+       spidx.dir   = IPSEC_DIR_INBOUND;
+
+       sp = getsp(&spidx);
+       if (sp) {
+               remsp(sp);
+               delsp(sp);
+       }
+
+#ifdef HAVE_POLICY_FWD
+       spidx.dir   = IPSEC_DIR_FWD;
+
+       sp = getsp(&spidx);
+       if (sp) {
+               remsp(sp);
+               delsp(sp);
+       }
+#endif
+
+       spidx.src   = dst;
+       spidx.dst   = src;
+       spidx.prefs = prefd;
+       spidx.prefd = prefs;
+       spidx.dir   = IPSEC_DIR_OUTBOUND;
+
+       sp = getsp(&spidx);
+       if (sp) {
+               remsp(sp);
+               delsp(sp);
+       }
+}
+
+void
+inssp(new)
+       struct secpolicy *new;
+{
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       struct secpolicy *p;
+
+       TAILQ_FOREACH(p, &sptree, chain) {
+               if (new->spidx.priority < p->spidx.priority) {
+                       TAILQ_INSERT_BEFORE(p, new, chain);
+                       return;
+               }
+       }
+       if (p == NULL)
+#endif
+               TAILQ_INSERT_TAIL(&sptree, new, chain);
+
+       check_auto_exit();
+       return;
+}
+
+void
+remsp(sp)
+       struct secpolicy *sp;
+{
+       TAILQ_REMOVE(&sptree, sp, chain);
+       check_auto_exit();
+}
+
+void
+flushsp()
+{
+       struct secpolicy *p, *next;
+
+       for (p = TAILQ_FIRST(&sptree); p; p = next) {
+               next = TAILQ_NEXT(p, chain);
+               remsp(p);
+               delsp(p);
+       }
+}
+
+int
+policies_installed(void)
+{
+       if (TAILQ_EMPTY(&sptree))
+               return 0;
+       else
+               return 1;
+}
+
+void
+initsp()
+{
+       TAILQ_INIT(&sptree);
+}
+
+struct ipsecrequest *
+newipsecreq()
+{
+       struct ipsecrequest *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+const char *
+spidx2str(spidx)
+       const struct policyindex *spidx;
+{
+       /* addr/pref[port] addr/pref[port] ul dir act */
+       static char buf[256];
+       char *p, *a, *b;
+       int blen, i;
+
+       blen = sizeof(buf) - 1;
+       p = buf;
+
+       a = saddr2str((const struct sockaddr *)&spidx->src);
+       for (b = a; *b != '\0'; b++)
+               if (*b == '[') {
+                       *b = '\0';
+                       b++;
+                       break;
+               }
+       i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b);
+       if (i < 0 || i >= blen)
+               return NULL;
+       p += i;
+       blen -= i;
+
+       a = saddr2str((const struct sockaddr *)&spidx->dst);
+       for (b = a; *b != '\0'; b++)
+               if (*b == '[') {
+                       *b = '\0';
+                       b++;
+                       break;
+               }
+       i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b);
+       if (i < 0 || i >= blen)
+               return NULL;
+       p += i;
+       blen -= i;
+
+       snprintf(p, blen, "proto=%s dir=%s",
+               s_proto(spidx->ul_proto), s_direction(spidx->dir));
+
+       return buf;
+}
diff --git a/ipsec-tools/racoon/policy.h b/ipsec-tools/racoon/policy.h
new file mode 100644 (file)
index 0000000..858b4b7
--- /dev/null
@@ -0,0 +1,136 @@
+/* $Id: policy.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _POLICY_H
+#define _POLICY_H
+
+#include <sys/queue.h>
+
+/* refs. ipsec.h */
+/*
+ * Security Policy Index
+ * NOTE: Ensure to be same address family and upper layer protocol.
+ * NOTE: ul_proto, port number, uid, gid:
+ *     ANY: reserved for waldcard.
+ *     0 to (~0 - 1): is one of the number of each value.
+ */
+struct policyindex {
+       u_int8_t dir;                   /* direction of packet flow, see blow */
+       struct sockaddr_storage src;    /* IP src address for SP */
+       struct sockaddr_storage dst;    /* IP dst address for SP */
+       u_int8_t prefs;                 /* prefix length in bits for src */
+       u_int8_t prefd;                 /* prefix length in bits for dst */
+       u_int16_t ul_proto;             /* upper layer Protocol */
+       u_int32_t priority;             /* priority for the policy */
+};
+
+/* Security Policy Data Base */
+struct secpolicy {
+       TAILQ_ENTRY(secpolicy) chain;
+
+       struct policyindex spidx;       /* selector */
+       u_int32_t id;                   /* It's unique number on the system. */
+
+       u_int policy;           /* DISCARD, NONE or IPSEC, see keyv2.h */
+       struct ipsecrequest *req;
+                               /* pointer to the ipsec request tree, */
+                               /* if policy == IPSEC else this value == NULL.*/
+};
+
+/* Security Assocciation Index */
+/* NOTE: Ensure to be same address family */
+struct secasindex {
+       struct sockaddr_storage src;    /* srouce address for SA */
+       struct sockaddr_storage dst;    /* destination address for SA */
+       u_int16_t proto;                /* IPPROTO_ESP or IPPROTO_AH */
+       u_int8_t mode;                  /* mode of protocol, see ipsec.h */
+       u_int32_t reqid;                /* reqid id who owned this SA */
+                                       /* see IPSEC_MANUAL_REQID_MAX. */
+};
+
+/* Request for IPsec */
+struct ipsecrequest {
+       struct ipsecrequest *next;
+                               /* pointer to next structure */
+                               /* If NULL, it means the end of chain. */
+
+       struct secasindex saidx;/* hint for search proper SA */
+                               /* if __ss_len == 0 then no address specified.*/
+       u_int level;            /* IPsec level defined below. */
+
+       struct secpolicy *sp;   /* back pointer to SP */
+};
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _priority, idx)              \
+do {                                                                         \
+       bzero((idx), sizeof(struct policyindex));                            \
+       (idx)->dir = (_dir);                                                 \
+       (idx)->prefs = (ps);                                                 \
+       (idx)->prefd = (pd);                                                 \
+       (idx)->ul_proto = (ulp);                                             \
+       (idx)->priority = (_priority);                                        \
+       memcpy(&(idx)->src, (s), sysdep_sa_len((struct sockaddr *)(s)));          \
+       memcpy(&(idx)->dst, (d), sysdep_sa_len((struct sockaddr *)(d)));          \
+} while (0)
+#else
+#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx)              \
+do {                                                                         \
+       bzero((idx), sizeof(struct policyindex));                            \
+       (idx)->dir = (_dir);                                                 \
+       (idx)->prefs = (ps);                                                 \
+       (idx)->prefd = (pd);                                                 \
+       (idx)->ul_proto = (ulp);                                             \
+       memcpy(&(idx)->src, (s), sysdep_sa_len((struct sockaddr *)(s)));          \
+       memcpy(&(idx)->dst, (d), sysdep_sa_len((struct sockaddr *)(d)));          \
+} while (0)
+#endif
+
+struct ph2handle;
+struct policyindex;
+extern struct secpolicy *getsp __P((struct policyindex *));
+extern struct secpolicy *getsp_r __P((struct policyindex *));
+struct secpolicy *getspbyspid __P((u_int32_t));
+extern int cmpspidxstrict __P((struct policyindex *, struct policyindex *));
+extern int cmpspidxwild __P((struct policyindex *, struct policyindex *));
+extern struct secpolicy *newsp __P((void));
+extern void delsp __P((struct secpolicy *));
+extern void delsp_bothdir __P((struct policyindex *));
+extern void inssp __P((struct secpolicy *));
+extern void remsp __P((struct secpolicy *));
+extern void flushsp __P((void));
+extern void initsp __P((void));
+extern struct ipsecrequest *newipsecreq __P((void));
+extern int policies_installed __P((void));
+
+extern const char *spidx2str __P((const struct policyindex *));
+
+#endif /* _POLICY_H */
diff --git a/ipsec-tools/racoon/privsep.c b/ipsec-tools/racoon/privsep.c
new file mode 100644 (file)
index 0000000..8dc4fd1
--- /dev/null
@@ -0,0 +1,1210 @@
+/* $Id: privsep.c,v 1.6.2.7 2005/08/08 11:25:01 vanhu Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <string.h>
+#ifdef __NetBSD__
+#include <stdlib.h>    /* for setproctitle */
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+
+#include <sys/socket.h>
+#include <sys/param.h>
+
+#include "gcmalloc.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "plog.h"
+#include "var.h"
+#include "libpfkey.h"
+
+#include "crypto_openssl.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#ifdef ENABLE_HYBRID
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
+#include "localconf.h"
+#include "remoteconf.h"
+#include "admin.h"
+#include "privsep.h"
+
+static int privsep_sock[2] = { -1, -1 };
+
+static int privsep_recv(int, struct privsep_com_msg **, size_t *);
+static int privsep_send(int, struct privsep_com_msg *, size_t);
+static int safety_check(struct privsep_com_msg *, int i);
+#ifdef HAVE_LIBPAM
+static int port_check(int);
+#endif
+static int unsafe_env(char *const *);
+static int unknown_name(int);
+static int unknown_script(int);
+static int unsafe_path(char *, int);
+static char *script_name2path(int);
+
+static int
+privsep_send(sock, buf, len)
+       int sock;
+       struct privsep_com_msg *buf;
+       size_t len;
+{
+       if (buf == NULL)
+               return 0;
+
+       if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "privsep_send failed: %s\n", 
+                   strerror(errno));
+               return -1;
+       }
+
+       racoon_free((char *)buf);
+
+       return 0;
+}
+
+
+static int
+privsep_recv(sock, bufp, lenp)
+       int sock;
+       struct privsep_com_msg **bufp;
+       size_t *lenp;
+{
+       struct admin_com com;
+       struct admin_com *combuf;
+       size_t len;
+
+       *bufp = NULL;
+       *lenp = 0;
+
+       /* Get the header */
+       while ((len = recvfrom(sock, (char *)&com, 
+           sizeof(com), MSG_PEEK, NULL, NULL)) == -1) {
+               if (errno == EINTR)
+                       continue;
+
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "privsep_recv failed: %s\n",
+                   strerror(errno));
+               return -1;
+       }
+       
+       /* Check for short packets */
+       if (len < sizeof(com)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "corrupted privsep message (short header)\n");
+               return -1;
+       }
+
+       /* Allocate buffer for the whole message */
+       if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "failed to allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+
+       /* Get the whole buffer */
+       while ((len = recvfrom(sock, (char *)combuf, 
+           com.ac_len, 0, NULL, NULL)) == -1) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "failed to recv privsep command: %s\n", 
+                   strerror(errno));
+               return -1;
+       }
+
+       /* We expect len to match */
+       if (len != com.ac_len) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "corrupted privsep message (short packet)\n");
+               return -1;
+       }
+
+       *bufp = (struct privsep_com_msg *)combuf;
+       *lenp = len;
+
+       return 0;
+}
+
+int
+privsep_init(void)
+{
+       int i;
+       pid_t child_pid;
+
+       /* If running as root, we don't use the privsep code path */
+       if (lcconf->uid == 0)
+               return 0;
+
+       /*
+        * When running privsep, certificate and script paths
+        * are mandatory, as they enable us to check path safety
+        * in the privilegied instance
+        */
+       if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) ||
+           (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) {
+               plog(LLV_ERROR, LOCATION, NULL, "privilege separation "
+                   "require path cert and path script in the config file\n");
+               return -1;
+       }
+
+       if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate privsep_sock: %s\n", strerror(errno));
+               return -1;
+       }
+
+       switch (child_pid = fork()) {
+       case -1:
+               plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n", 
+                   strerror(errno));
+               return -1;
+               break;
+
+       case 0: /* Child: drop privileges */
+               if (lcconf->chroot != NULL) {
+                       if (chdir(lcconf->chroot) != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Cannot chdir(%s): %s\n", lcconf->chroot, 
+                                   strerror(errno));
+                               return -1;
+                       }
+                       if (chroot(lcconf->chroot) != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Cannot chroot(%s): %s\n", lcconf->chroot, 
+                                   strerror(errno));
+                               return -1;
+                       }
+               }
+
+               if (setgid(lcconf->gid) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot setgid(%d): %s\n", lcconf->gid,
+                           strerror(errno));
+                       return -1;
+               }
+
+               if (setegid(lcconf->gid) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot setegid(%d): %s\n", lcconf->gid,
+                           strerror(errno));
+                       return -1;
+               }
+
+               if (setuid(lcconf->uid) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot setuid(%d): %s\n", lcconf->uid,
+                           strerror(errno));
+                       return -1;
+               }
+
+               if (seteuid(lcconf->uid) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL, 
+                           "Cannot seteuid(%d): %s\n", lcconf->uid,
+                           strerror(errno));
+                       return -1;
+               }
+
+               return 0;
+               break;
+
+       default: /* Parent: privilegied process */
+               break;
+       }
+
+       /* 
+        * Close everything except the socketpair, 
+        * and stdout if running in the forground.
+        */
+       for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) {
+               if (i == privsep_sock[0])
+                       continue;
+               if (i == privsep_sock[1])
+                       continue;
+               if ((f_foreground) && (i == 1))
+                       continue;
+               (void)close(i);
+       }
+
+       /* Above trickery closed the log file, reopen it */
+       ploginit();
+
+       plog(LLV_INFO, LOCATION, NULL, 
+           "racoon privilegied process running with PID %d\n", getpid());
+
+#ifdef __NetBSD__
+       setproctitle("[priv]");
+#endif
+       
+       /* 
+        * Don't catch any signal 
+        * This duplicate session:signals[], which is static...
+        */
+       signal(SIGHUP, SIG_DFL);
+       signal(SIGINT, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+       signal(SIGUSR1, SIG_DFL);
+       signal(SIGUSR2, SIG_DFL);
+       signal(SIGCHLD, SIG_DFL);
+
+       while (1) {
+               size_t len;
+               struct privsep_com_msg *combuf;
+               struct privsep_com_msg *reply;
+               char *data;
+               size_t *buflen;
+               size_t totallen;
+               char *bufs[PRIVSEP_NBUF_MAX];
+               int i;
+
+               if (privsep_recv(privsep_sock[0], &combuf, &len) != 0)
+                       goto out;
+
+               /* Safety checks and gather the data */
+               if (len < sizeof(*combuf)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "corrupted privsep message (short buflen)\n");
+                       goto out;
+               }
+
+               data = (char *)(combuf + 1);
+               totallen = sizeof(*combuf);
+               for (i = 0; i < PRIVSEP_NBUF_MAX; i++) {
+                       bufs[i] = (char *)data;
+                       data += combuf->bufs.buflen[i];
+                       totallen += combuf->bufs.buflen[i];
+               }
+
+               if (totallen > len) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "corrupted privsep message (bufs too big)\n");
+                       goto out;
+               }
+       
+               /* Prepare the reply buffer */
+               if ((reply = racoon_malloc(sizeof(*reply))) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Cannot allocate reply buffer: %s\n", 
+                           strerror(errno));
+                       goto out;
+               }
+               bzero(reply, sizeof(*reply));
+               reply->hdr.ac_cmd = combuf->hdr.ac_cmd;
+               reply->hdr.ac_len = sizeof(*reply);
+
+               switch(combuf->hdr.ac_cmd) {
+               /* 
+                * XXX Improvement: instead of returning the key, 
+                * stuff eay_get_pkcs1privkey and eay_get_x509sign
+                * together and sign the hash in the privilegied 
+                * instance? 
+                * pro: the key remains inaccessibleato
+                * con: a compromised unpriv racoon can still sign anything
+                */
+               case PRIVSEP_EAY_GET_PKCS1PRIVKEY: {
+                       vchar_t *privkey;
+
+                       /* Make sure the string is NULL terminated */
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+                       bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
+
+                       if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "privsep_eay_get_pkcs1privkey: "
+                                   "unsafe key \"%s\"\n", bufs[0]);
+                       }
+
+                       if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){
+                               reply->hdr.ac_errno = errno;
+                               break;
+                       }
+
+                       reply->bufs.buflen[0] = privkey->l;
+                       reply->hdr.ac_len = sizeof(*reply) + privkey->l;
+                       reply = racoon_realloc(reply, reply->hdr.ac_len);
+                       if (reply == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "Cannot allocate reply buffer: %s\n", 
+                                   strerror(errno));
+                               goto out;
+                       }
+
+                       memcpy(reply + 1, privkey->v, privkey->l);
+                       vfree(privkey);
+                       break;
+               }
+               
+               case PRIVSEP_SCRIPT_EXEC: {
+                       int script;
+                       int name;
+                       char **envp = NULL;
+                       int envc = 0;
+                       int count = 0;
+                       int i;
+
+                       /*
+                        * First count the bufs, and make sure strings
+                        * are NULL terminated. 
+                        *
+                        * We expect: script, name, envp[], void
+                        */ 
+                       count++;        /* script */
+                       count++;        /* name */
+
+                       for (; count < PRIVSEP_NBUF_MAX; count++) {
+                               if (combuf->bufs.buflen[count] == 0)
+                                       break;
+                               bufs[count]
+                                   [combuf->bufs.buflen[count] - 1] = '\0';
+                               envc++;
+                       }
+
+                       /* count a void buf and perform safety check */
+                       count++;
+                       if (count >= PRIVSEP_NBUF_MAX) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "privsep_script_exec: too many args\n");
+                               goto out;
+                       }
+
+
+                       /* 
+                        * Allocate the arrays for envp 
+                        */
+                       envp = racoon_malloc((envc + 1) * sizeof(char *));
+                       if (envp == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "cannot allocate memory: %s\n",
+                                   strerror(errno));
+                               goto out;
+                       }
+                       bzero(envp, (envc + 1) * sizeof(char *));
+
+       
+                       /*
+                        * Populate script, name and envp 
+                        */
+                       count = 0;
+
+                       if (combuf->bufs.buflen[count] != sizeof(script)) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "privsep_script_exec: corrupted message\n");
+                               goto out;
+                       }
+                       memcpy((char *)&script, bufs[count++], sizeof(script));
+
+                       if (combuf->bufs.buflen[count] != sizeof(name)) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "privsep_script_exec: corrupted message\n");
+                               goto out;
+                       }
+                       memcpy((char *)&name, bufs[count++], sizeof(name));
+
+                       for (i = 0; combuf->bufs.buflen[count]; count++)
+                               envp[i++] = bufs[count];
+
+                       count++;                /* void */
+
+                       /* 
+                        * Check env for dangerous variables
+                        * Check script path and name
+                        * Perform fork and execve
+                        */
+                       if ((unsafe_env(envp) == 0) &&
+                           (unknown_name(name) == 0) &&
+                           (unknown_script(script) == 0) &&
+                           (unsafe_path(script_name2path(script), 
+                           LC_PATHTYPE_SCRIPT) == 0))
+                               (void)script_exec(script, name, envp);
+                       else
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "privsep_script_exec: "
+                                   "unsafe script \"%s\"\n", 
+                                   script_name2path(script));
+
+                       racoon_free(envp);
+                       break;
+               }
+
+               case PRIVSEP_GETPSK: {
+                       vchar_t *psk;
+                       int keylen;
+
+                       /* Make sure the string is NULL terminated */
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+                       bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
+
+                       if (combuf->bufs.buflen[1] != sizeof(keylen)) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "privsep_getpsk: corrupted message\n");
+                               goto out;
+                       }
+                       memcpy(&keylen, bufs[1], sizeof(keylen));
+                       if ((psk = getpsk(bufs[0], keylen)) == NULL) {
+                               reply->hdr.ac_errno = errno;
+                               break;
+                       }
+
+                       reply->bufs.buflen[0] = psk->l;
+                       reply->hdr.ac_len = sizeof(*reply) + psk->l;
+                       reply = racoon_realloc(reply, reply->hdr.ac_len); 
+                       if (reply == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "Cannot allocate reply buffer: %s\n", 
+                                   strerror(errno));
+                               goto out;
+                       }
+
+                       memcpy(reply + 1, psk->v, psk->l);
+                       vfree(psk);
+                       break;
+               }
+
+#ifdef ENABLE_HYBRID
+               case PRIVSEP_XAUTH_LOGIN_SYSTEM: {
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+                       bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
+
+                       if (safety_check(combuf, 1) != 0)
+                               break;
+                       bufs[1][combuf->bufs.buflen[1] - 1] = '\0';
+
+                       errno = 0;
+                       if (xauth_login_system(bufs[0], bufs[1]) != 0) {
+                               if (errno == 0)
+                                       reply->hdr.ac_errno = EINVAL;
+                               else
+                                       reply->hdr.ac_errno = errno;
+                       }
+                       break;
+               }
+#ifdef HAVE_LIBPAM
+               case PRIVSEP_ACCOUNTING_PAM: {
+                       int port;
+                       int inout;
+
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+                       if (safety_check(combuf, 1) != 0)
+                               break;
+
+                       memcpy(&port, bufs[0], sizeof(port));
+                       memcpy(&inout, bufs[1], sizeof(inout));
+
+                       if (port_check(port) != 0)
+                               break;
+
+                       errno = 0;
+                       if (isakmp_cfg_accounting_pam(port, inout) != 0) {
+                               if (errno == 0)
+                                       reply->hdr.ac_errno = EINVAL;
+                               else
+                                       reply->hdr.ac_errno = errno;
+                       }
+                       break;
+               }
+
+               case PRIVSEP_XAUTH_LOGIN_PAM: {
+                       int port;
+                       struct sockaddr *raddr;
+
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+                       if (safety_check(combuf, 1) != 0)
+                               break;
+                       if (safety_check(combuf, 2) != 0)
+                               break;
+                       if (safety_check(combuf, 3) != 0)
+                               break;
+
+                       memcpy(&port, bufs[0], sizeof(port));
+                       raddr = (struct sockaddr *)bufs[1];
+                       
+                       bufs[2][combuf->bufs.buflen[2] - 1] = '\0';
+                       bufs[3][combuf->bufs.buflen[3] - 1] = '\0';
+
+                       if (port_check(port) != 0)
+                               break;
+
+                       errno = 0;
+                       if (xauth_login_pam(port, 
+                           raddr, bufs[2], bufs[3]) != 0) {
+                               if (errno == 0)
+                                       reply->hdr.ac_errno = EINVAL;
+                               else
+                                       reply->hdr.ac_errno = errno;
+                       }
+                       break;
+               }
+
+               case PRIVSEP_CLEANUP_PAM: {
+                       int port;
+
+                       if (safety_check(combuf, 0) != 0)
+                               break;
+
+                       memcpy(&port, bufs[0], sizeof(port));
+
+                       if (port_check(port) != 0)
+                               break;
+
+                       cleanup_pam(port);
+                       reply->hdr.ac_errno = 0;
+
+                       break;
+               }
+#endif /* HAVE_LIBPAM */
+#endif /* ENABLE_HYBRID */
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "unexpected privsep command %d\n", 
+                           combuf->hdr.ac_cmd);
+                       goto out;
+                       break;
+               }
+
+               /* This frees reply */
+               if (privsep_send(privsep_sock[0], 
+                   reply, reply->hdr.ac_len) != 0)
+                       goto out;
+
+               racoon_free(combuf);
+       }
+
+out:
+       plog(LLV_INFO, LOCATION, NULL, "privsep exit\n");
+       _exit(0);
+}
+
+
+vchar_t *
+privsep_eay_get_pkcs1privkey(path) 
+       char *path;
+{
+       vchar_t *privkey;
+       struct privsep_com_msg *msg;
+       size_t len;
+
+       if (geteuid() == 0)
+               return eay_get_pkcs1privkey(path);
+
+       len = sizeof(*msg) + strlen(path) + 1;
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return NULL;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY;
+       msg->hdr.ac_len = len;
+       msg->bufs.buflen[0] = len - sizeof(*msg);
+       memcpy(msg + 1, path, msg->bufs.buflen[0]);
+
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return NULL;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return NULL;
+
+       if (msg->hdr.ac_errno != 0) {
+               errno = msg->hdr.ac_errno;
+               goto out;
+       }
+
+       if ((privkey = vmalloc(len - sizeof(*msg))) == NULL)
+               goto out;
+
+       memcpy(privkey->v, msg + 1, privkey->l);
+       racoon_free(msg);
+       return privkey;
+
+out:
+       racoon_free(msg);
+       return NULL;
+}
+
+/*
+ * No prigilege separation trick here, we just open PFKEY before
+ * dropping root privs and we remember it later.
+ */
+static int  pfkey_socket = -1;
+int
+privsep_pfkey_open(void)
+{
+       int ps;
+
+       if (pfkey_socket != -1)
+               return pfkey_socket;
+
+       ps = pfkey_open();
+       if (ps != -1)
+               pfkey_socket = ps;
+
+       return ps;
+}
+
+/*
+ * Consequence of the above trickery: don't 
+ * really close PFKEY as we never re-open it.
+ */
+void
+privsep_pfkey_close(ps)
+       int ps;
+{
+       return;
+}
+
+int
+privsep_script_exec(script, name, envp)
+       int script;
+       int name;
+       char *const envp[];
+{
+       int count = 0;
+       char *const *c;
+       char *data;
+       size_t len;
+       struct privsep_com_msg *msg;
+
+       if (geteuid() == 0)
+               return script_exec(script, name, envp);
+
+       if ((msg = racoon_malloc(sizeof(*msg))) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+
+       bzero(msg, sizeof(*msg));
+       msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC;
+       msg->hdr.ac_len = sizeof(*msg);
+
+       /*
+        * We send: 
+        * script, name, envp[0], ... envp[N], void
+        */
+
+       /*
+        * Safety check on the counts: PRIVSEP_NBUF_MAX max
+        */
+       count = 0;
+       count++;                                        /* script */
+       count++;                                        /* name */
+       for (c = envp; *c; c++)                         /* envp */
+               count++;
+       count++;                                        /* void */
+
+       if (count > PRIVSEP_NBUF_MAX) {
+               plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: "
+                   "privsep_script_exec count > PRIVSEP_NBUF_MAX\n");
+               racoon_free(msg);
+               return -1;
+       }
+
+
+       /*
+        * Compute the length
+        */
+       count = 0;
+       msg->bufs.buflen[count] = sizeof(script);       /* script */
+       msg->hdr.ac_len += msg->bufs.buflen[count++];
+
+       msg->bufs.buflen[count] = sizeof(name);         /* name */
+       msg->hdr.ac_len += msg->bufs.buflen[count++];
+
+       for (c = envp; *c; c++) {                       /* envp */
+               msg->bufs.buflen[count] = strlen(*c) + 1;
+               msg->hdr.ac_len += msg->bufs.buflen[count++];
+       }
+
+       msg->bufs.buflen[count] = 0;                    /* void */
+       msg->hdr.ac_len += msg->bufs.buflen[count++];
+
+       if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       
+       /*
+        * Now copy the data
+        */
+       data = (char *)(msg + 1);
+       count = 0;
+
+       memcpy(data, (char *)&script, msg->bufs.buflen[count]); /* script */
+       data += msg->bufs.buflen[count++];
+
+       memcpy(data, (char *)&name, msg->bufs.buflen[count]);   /* name */
+       data += msg->bufs.buflen[count++];
+
+       for (c = envp; *c; c++) {                               /* envp */
+               memcpy(data, *c, msg->bufs.buflen[count]); 
+               data += msg->bufs.buflen[count++];
+       }
+
+       count++;                                                /* void */
+
+       /*
+        * And send it!
+        */
+       if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0)
+               return -1;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return -1;
+
+       if (msg->hdr.ac_errno != 0) {
+               errno = msg->hdr.ac_errno;
+               racoon_free(msg);
+               return -1;
+       }
+
+       racoon_free(msg);
+       return 0;
+}
+
+vchar_t *
+privsep_getpsk(str, keylen)
+       const char *str;
+       int keylen;
+{
+       vchar_t *psk;
+       struct privsep_com_msg *msg;
+       size_t len;
+       int *keylenp;
+       char *data;
+
+       if (geteuid() == 0)
+               return getpsk(str, keylen);
+
+       len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen);
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return NULL;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_GETPSK;
+       msg->hdr.ac_len = len;
+
+       data = (char *)(msg + 1);
+       msg->bufs.buflen[0] = strlen(str) + 1;
+       memcpy(data, str, msg->bufs.buflen[0]);
+
+       data += msg->bufs.buflen[0];
+       msg->bufs.buflen[1] = sizeof(keylen);
+       memcpy(data, &keylen, sizeof(keylen));
+
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return NULL;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return NULL;
+
+       if (msg->hdr.ac_errno != 0) {
+               errno = msg->hdr.ac_errno;
+               goto out;
+       }
+
+       if ((psk = vmalloc(len - sizeof(*msg))) == NULL)
+               goto out;
+
+       memcpy(psk->v, msg + 1, psk->l);
+       racoon_free(msg);
+       return psk;
+
+out:
+       racoon_free(msg);
+       return NULL;
+}
+
+#ifdef ENABLE_HYBRID
+int
+privsep_xauth_login_system(usr, pwd)
+       char *usr;
+       char *pwd;
+{
+       struct privsep_com_msg *msg;
+       size_t len;
+       char *data;
+
+       if (geteuid() == 0)
+               return xauth_login_system(usr, pwd);
+
+       len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1;
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM;
+       msg->hdr.ac_len = len;
+
+       data = (char *)(msg + 1);
+       msg->bufs.buflen[0] = strlen(usr) + 1;
+       memcpy(data, usr, msg->bufs.buflen[0]);
+       data += msg->bufs.buflen[0];
+
+       msg->bufs.buflen[1] = strlen(pwd) + 1;
+       memcpy(data, pwd, msg->bufs.buflen[1]);
+       
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return -1;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return -1;
+
+       if (msg->hdr.ac_errno != 0) {
+               racoon_free(msg);
+               return -1;
+       }
+
+       racoon_free(msg);
+       return 0;
+}
+#endif /* ENABLE_HYBRID */
+
+#ifdef HAVE_LIBPAM
+static int
+port_check(port)
+       int port;
+{
+       if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep: port %d outside of allowed range [0,%zu]\n",
+                   port, isakmp_cfg_config.pool_size - 1);
+               return -1;
+       }
+
+       return 0;
+}
+#endif
+
+static int 
+safety_check(msg, index)
+       struct privsep_com_msg *msg;
+       int index;
+{
+       if (index >= PRIVSEP_NBUF_MAX) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep: Corrupted message, too many buffers\n");
+               return -1;
+       }
+               
+       if (msg->bufs.buflen[index] == 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep: Corrupted message, unexpected void buffer\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Filter unsafe environement variables
+ */
+static int
+unsafe_env(envp)
+       char *const *envp;
+{
+       char *const *e;
+       char *const *be;
+       char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL };
+
+       for (e = envp; *e; e++) {
+               for (be = bad_env; *be; be++) {
+                       if (strncmp(*e, *be, strlen(*be)) == 0) {
+                               goto found;
+                       }
+               }
+       }
+
+       return 0;
+found:
+       plog(LLV_ERROR, LOCATION, NULL, 
+           "privsep_script_exec: unsafe environement variable\n");
+       return -1;
+}
+
+/*                       
+ * Check path safety     
+ */                     
+static int                  
+unsafe_path(script, pathtype)
+       char *script;
+       int pathtype;
+{
+       char *path;
+       char rpath[MAXPATHLEN + 1];
+       size_t len;
+
+       if (script == NULL)
+               return -1; 
+
+       path = lcconf->pathinfo[pathtype];
+
+       /* No path was given for scripts: skip the check */
+       if (path == NULL)
+               return 0;
+
+       if (realpath(script, rpath) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "script path \"%s\" is invalid\n", script);
+               return -1;
+       }
+
+       len = strlen(path);
+       if (strncmp(path, rpath, len) != 0)
+               return -1;
+
+       return 0;
+}
+
+static char *
+script_name2path(name)
+       int name;
+{
+       vchar_t **sp;
+
+       if (script_paths == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "script_name2path: script_paths was not initialized\n");
+               return NULL;
+       }
+
+       sp = (vchar_t **)(script_paths->v);
+
+       return sp[name]->v;
+}
+
+/*
+ * Check the script path index is correct
+ */
+static int 
+unknown_script(script)
+       int script;
+{
+       if (script_paths == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep_script_exec: script_paths was not initialized\n");
+               return -1;
+       }
+
+       if ((script < 0) || (script > (script_paths->l / sizeof(vchar_t *)))) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep_script_exec: unsafe script index\n");
+               return -1;
+       }
+
+        return 0;
+}
+
+static int 
+unknown_name(name)
+       int name;
+{
+       if ((name < 0) || (name > SCRIPT_MAX)) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "privsep_script_exec: unsafe name index\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+#ifdef HAVE_LIBPAM
+int 
+privsep_accounting_pam(port, inout)
+       int port;
+       int inout;
+{
+       struct privsep_com_msg *msg;
+       size_t len;
+       int *port_data;
+       int *inout_data;
+       int result;
+
+       if (geteuid() == 0)
+               return isakmp_cfg_accounting_pam(port, inout);
+
+       len = sizeof(*msg) + sizeof(port) + sizeof(inout);
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM;
+       msg->hdr.ac_len = len;
+       msg->bufs.buflen[0] = sizeof(port);
+       msg->bufs.buflen[1] = sizeof(inout);
+
+       port_data = (int *)(msg + 1);
+       inout_data = (int *)(port_data + 1);
+
+       *port_data = port;
+       *inout_data = inout;
+
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return -1;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return -1;
+
+       if (msg->hdr.ac_errno != 0) {
+               errno = msg->hdr.ac_errno;
+               goto out;
+       }
+
+       racoon_free(msg);
+       return 0;
+
+out:
+       racoon_free(msg);
+       return -1;
+}
+
+int 
+privsep_xauth_login_pam(port, raddr, usr, pwd)
+       int port;
+       struct sockaddr *raddr;
+       char *usr;
+       char *pwd;
+{
+       struct privsep_com_msg *msg;
+       size_t len;
+       char *data;
+       int result;
+
+       if (geteuid() == 0)
+               return xauth_login_pam(port, raddr, usr, pwd);
+
+       len = sizeof(*msg) 
+           + sizeof(port)
+           + sysdep_sa_len(raddr) 
+           + strlen(usr) + 1
+           + strlen(pwd) + 1;
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM;
+       msg->hdr.ac_len = len;
+       msg->bufs.buflen[0] = sizeof(port);
+       msg->bufs.buflen[1] = sysdep_sa_len(raddr);
+       msg->bufs.buflen[2] = strlen(usr) + 1;
+       msg->bufs.buflen[3] = strlen(pwd) + 1;
+
+       data = (char *)(msg + 1);
+       memcpy(data, &port, msg->bufs.buflen[0]);
+
+       data += sizeof(msg->bufs.buflen[0]);
+       memcpy(data, raddr, msg->bufs.buflen[1]);
+
+       data += msg->bufs.buflen[1];
+       memcpy(data, usr, msg->bufs.buflen[2]);
+
+       data += msg->bufs.buflen[2];
+       memcpy(data, pwd, msg->bufs.buflen[3]);
+
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return -1;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return -1;
+
+       if (msg->hdr.ac_errno != 0) {
+               errno = msg->hdr.ac_errno;
+               goto out;
+       }
+
+       racoon_free(msg);
+       return 0;
+
+out:
+       racoon_free(msg);
+       return -1;
+}
+
+void
+privsep_cleanup_pam(port)
+       int port;
+{
+       struct privsep_com_msg *msg;
+       size_t len;
+       char *data;
+       int result;
+
+       if (geteuid() == 0)
+               return cleanup_pam(port);
+
+       len = sizeof(*msg) + sizeof(port);
+       if ((msg = racoon_malloc(len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return;
+       }
+       bzero(msg, len);
+       msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM;
+       msg->hdr.ac_len = len;
+       msg->bufs.buflen[0] = sizeof(port);
+
+       data = (char *)(msg + 1);
+       memcpy(data, &port, msg->bufs.buflen[0]);
+
+       if (privsep_send(privsep_sock[1], msg, len) != 0)
+               return;
+
+       if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+               return;
+
+       if (msg->hdr.ac_errno != 0)
+               errno = msg->hdr.ac_errno;
+
+       racoon_free(msg);
+       return;
+}
+#endif
diff --git a/ipsec-tools/racoon/privsep.h b/ipsec-tools/racoon/privsep.h
new file mode 100644 (file)
index 0000000..10e3aa2
--- /dev/null
@@ -0,0 +1,69 @@
+/* $Id: privsep.h,v 1.3 2005/02/10 02:02:56 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * 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.
+ */
+
+#ifndef _PRIVSEP_H
+#define _PRIVSEP_H
+
+#define PRIVSEP_EAY_GET_PKCS1PRIVKEY   0x0801  /* admin_com_bufs follows */
+#define PRIVSEP_SCRIPT_EXEC            0x0803  /* admin_com_bufs follows */
+#define PRIVSEP_GETPSK                 0x0804  /* admin_com_bufs follows */
+#define PRIVSEP_XAUTH_LOGIN_SYSTEM     0x0805  /* admin_com_bufs follows */
+#define PRIVSEP_ACCOUNTING_PAM         0x0806  /* admin_com_bufs follows */
+#define PRIVSEP_XAUTH_LOGIN_PAM                0x0807  /* admin_com_bufs follows */
+#define PRIVSEP_CLEANUP_PAM            0x0808  /* admin_com_bufs follows */
+
+#define PRIVSEP_NBUF_MAX 16
+#define PRIVSEP_BUFLEN_MAX 4096
+struct admin_com_bufs {
+       size_t buflen[PRIVSEP_NBUF_MAX];
+       /* Followed by the buffers */
+};
+
+struct privsep_com_msg {
+       struct admin_com hdr;
+       struct admin_com_bufs bufs;
+};
+
+int privsep_init __P((void));
+
+vchar_t *privsep_eay_get_pkcs1privkey __P((char *));
+int privsep_pfkey_open __P((void));
+void privsep_pfkey_close __P((int));
+int privsep_script_exec __P((int, int, char * const *));
+vchar_t *privsep_getpsk __P((const char *, const int));
+int privsep_xauth_login_system __P((char *, char *));
+#ifdef HAVE_LIBPAM
+int privsep_accounting_pam __P((int, int));
+int privsep_xauth_login_pam __P((int, struct sockaddr *, char *, char *));
+void privsep_cleanup_pam __P((int));
+#endif
+
+#endif /* _PRIVSEP_H */
diff --git a/ipsec-tools/racoon/proposal.c b/ipsec-tools/racoon/proposal.c
new file mode 100644 (file)
index 0000000..a2f053a
--- /dev/null
@@ -0,0 +1,1189 @@
+/* $Id: proposal.c,v 1.13.8.5 2005/07/28 05:05:52 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "policy.h"
+#include "pfkey.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "algorithm.h"
+#include "proposal.h"
+#include "sainfo.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "oakley.h"
+#include "handler.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+
+/* %%%
+ * modules for ipsec sa spec
+ */
+struct saprop *
+newsaprop()
+{
+       struct saprop *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+struct saproto *
+newsaproto()
+{
+       struct saproto *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+/* set saprop to last part of the prop tree */
+void
+inssaprop(head, new)
+       struct saprop **head;
+       struct saprop *new;
+{
+       struct saprop *p;
+
+       if (*head == NULL) {
+               *head = new;
+               return;
+       }
+
+       for (p = *head; p->next; p = p->next)
+               ;
+       p->next = new;
+
+       return;
+}
+
+/* set saproto to the end of the proto tree in saprop */
+void
+inssaproto(pp, new)
+       struct saprop *pp;
+       struct saproto *new;
+{
+       struct saproto *p;
+
+       for (p = pp->head; p && p->next; p = p->next)
+               ;
+       if (p == NULL)
+               pp->head = new;
+       else
+               p->next = new;
+
+       return;
+}
+
+/* set saproto to the top of the proto tree in saprop */
+void
+inssaprotorev(pp, new)
+      struct saprop *pp;
+      struct saproto *new;
+{
+      new->next = pp->head;
+      pp->head = new;
+
+      return;
+}
+
+struct satrns *
+newsatrns()
+{
+       struct satrns *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+/* set saproto to last part of the proto tree in saprop */
+void
+inssatrns(pr, new)
+       struct saproto *pr;
+       struct satrns *new;
+{
+       struct satrns *tr;
+
+       for (tr = pr->head; tr && tr->next; tr = tr->next)
+               ;
+       if (tr == NULL)
+               pr->head = new;
+       else
+               tr->next = new;
+
+       return;
+}
+
+/*
+ * take a single match between saprop.  allocate a new proposal and return it
+ * for future use (like picking single proposal from a bundle).
+ *     pp1: peer's proposal.
+ *     pp2: my proposal.
+ * NOTE: In the case of initiator, must be ensured that there is no
+ * modification of the proposal by calling cmp_aproppair_i() before
+ * this function.
+ * XXX cannot understand the comment!
+ */
+struct saprop *
+cmpsaprop_alloc(ph1, pp1, pp2, side)
+       struct ph1handle *ph1;
+       const struct saprop *pp1, *pp2;
+       int side;
+{
+       struct saprop *newpp = NULL;
+       struct saproto *pr1, *pr2, *newpr = NULL;
+       struct satrns *tr1, *tr2, *newtr;
+       const int ordermatters = 0;
+       int npr1, npr2;
+       int spisizematch;
+
+       newpp = newsaprop();
+       if (newpp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate saprop.\n");
+               return NULL;
+       }
+       newpp->prop_no = pp1->prop_no;
+
+       /* see proposal.h about lifetime/key length and PFS selection. */
+
+       /* check time/bytes lifetime and PFS */
+       switch (ph1->rmconf->pcheck_level) {
+       case PROP_CHECK_OBEY:
+               newpp->lifetime = pp1->lifetime;
+               newpp->lifebyte = pp1->lifebyte;
+               newpp->pfs_group = pp1->pfs_group;
+               break;
+
+       case PROP_CHECK_STRICT:
+               if (pp1->lifetime > pp2->lifetime) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "long lifetime proposed: "
+                               "my:%d peer:%d\n",
+                               (int)pp2->lifetime, (int)pp1->lifetime);
+                       goto err;
+               }
+               if (pp1->lifebyte > pp2->lifebyte) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "long lifebyte proposed: "
+                               "my:%d peer:%d\n",
+                               pp2->lifebyte, pp1->lifebyte);
+                       goto err;
+               }
+               newpp->lifetime = pp1->lifetime;
+               newpp->lifebyte = pp1->lifebyte;
+
+    prop_pfs_check:
+               if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfs group mismatched: "
+                               "my:%d peer:%d\n",
+                               pp2->pfs_group, pp1->pfs_group);
+                       goto err;
+               }
+               newpp->pfs_group = pp1->pfs_group;
+               break;
+
+       case PROP_CHECK_CLAIM:
+               /* lifetime */
+               if (pp1->lifetime <= pp2->lifetime) {
+                       newpp->lifetime = pp1->lifetime;
+               } else {
+                       newpp->lifetime = pp2->lifetime;
+                       newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
+                       plog(LLV_NOTIFY, LOCATION, NULL,
+                               "use own lifetime: "
+                               "my:%d peer:%d\n",
+                               (int)pp2->lifetime, (int)pp1->lifetime);
+               }
+
+               /* lifebyte */
+               if (pp1->lifebyte > pp2->lifebyte) {
+                       newpp->lifebyte = pp2->lifebyte;
+                       newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
+                       plog(LLV_NOTIFY, LOCATION, NULL,
+                               "use own lifebyte: "
+                               "my:%d peer:%d\n",
+                               pp2->lifebyte, pp1->lifebyte);
+               }
+               newpp->lifebyte = pp1->lifebyte;
+
+               goto prop_pfs_check;
+               break;
+
+       case PROP_CHECK_EXACT:
+               if (pp1->lifetime != pp2->lifetime) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "lifetime mismatched: "
+                               "my:%d peer:%d\n",
+                               (int)pp2->lifetime, (int)pp1->lifetime);
+                       goto err;
+               }
+
+               if (pp1->lifebyte != pp2->lifebyte) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "lifebyte mismatched: "
+                               "my:%d peer:%d\n",
+                               pp2->lifebyte, pp1->lifebyte);
+                       goto err;
+               }
+               if (pp1->pfs_group != pp2->pfs_group) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfs group mismatched: "
+                               "my:%d peer:%d\n",
+                               pp2->pfs_group, pp1->pfs_group);
+                       goto err;
+               }
+               newpp->lifetime = pp1->lifetime;
+               newpp->lifebyte = pp1->lifebyte;
+               newpp->pfs_group = pp1->pfs_group;
+               break;
+
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid pcheck_level why?.\n");
+               goto err;
+       }
+
+       npr1 = npr2 = 0;
+       for (pr1 = pp1->head; pr1; pr1 = pr1->next)
+               npr1++;
+       for (pr2 = pp2->head; pr2; pr2 = pr2->next)
+               npr2++;
+       if (npr1 != npr2)
+               goto err;
+
+       /* check protocol order */
+       pr1 = pp1->head;
+       pr2 = pp2->head;
+
+       while (1) {
+               if (!ordermatters) {
+                       /*
+                        * XXX does not work if we have multiple proposals
+                        * with the same proto_id
+                        */
+                       switch (side) {
+                       case RESPONDER:
+                               if (!pr2)
+                                       break;
+                               for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
+                                       if (pr1->proto_id == pr2->proto_id)
+                                               break;
+                               }
+                               break;
+                       case INITIATOR:
+                               if (!pr1)
+                                       break;
+                               for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
+                                       if (pr2->proto_id == pr1->proto_id)
+                                               break;
+                               }
+                               break;
+                       }
+               }
+               if (!pr1 || !pr2)
+                       break;
+
+               if (pr1->proto_id != pr2->proto_id) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "proto_id mismatched: "
+                               "my:%s peer:%s\n",
+                               s_ipsecdoi_proto(pr2->proto_id),
+                               s_ipsecdoi_proto(pr1->proto_id));
+                       goto err;
+               }
+               spisizematch = 0;
+               if (pr1->spisize == pr2->spisize)
+                       spisizematch = 1;
+               else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
+                       /*
+                        * draft-shacham-ippcp-rfc2393bis-05.txt:
+                        * need to accept 16bit and 32bit SPI (CPI) for IPComp.
+                        */
+                       if (pr1->spisize == sizeof(u_int16_t) &&
+                           pr2->spisize == sizeof(u_int32_t)) {
+                               spisizematch = 1;
+                       } else if (pr2->spisize == sizeof(u_int16_t) &&
+                                pr1->spisize == sizeof(u_int32_t)) {
+                               spisizematch = 1;
+                       }
+                       if (spisizematch) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "IPComp SPI size promoted "
+                                   "from 16bit to 32bit\n");
+                       }
+               }
+               if (!spisizematch) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "spisize mismatched: "
+                               "my:%d peer:%d\n",
+                               (int)pr2->spisize, (int)pr1->spisize);
+                       goto err;
+               }
+
+#ifdef ENABLE_NATT
+               if ((ph1->natt_flags & NAT_DETECTED) && 
+                   natt_udp_encap (pr2->encmode))
+               {
+                       plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
+                            s_ipsecdoi_encmode(pr2->encmode),
+                            s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
+                       pr2->encmode -= ph1->natt_options->mode_udp_diff;
+                       pr2->udp_encap = 1;
+               }
+
+               if ((ph1->natt_flags & NAT_DETECTED) &&
+                   natt_udp_encap (pr1->encmode))
+               {
+                       plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
+                            s_ipsecdoi_encmode(pr1->encmode),
+                            pr1->encmode,
+                            s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
+                            pr1->encmode - ph1->natt_options->mode_udp_diff);
+                       pr1->encmode -= ph1->natt_options->mode_udp_diff;
+                       pr1->udp_encap = 1;
+               }
+#endif
+
+               if (pr1->encmode != pr2->encmode) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "encmode mismatched: "
+                               "my:%s peer:%s\n",
+                               s_ipsecdoi_encmode(pr2->encmode),
+                               s_ipsecdoi_encmode(pr1->encmode));
+                       goto err;
+               }
+
+               for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
+                       for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
+                               if (cmpsatrns(pr1->proto_id, tr1, tr2) == 0)
+                                       goto found;
+                       }
+               }
+
+               goto err;
+
+           found:
+               newpr = newsaproto();
+               if (newpr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to allocate saproto.\n");
+                       goto err;
+               }
+               newpr->proto_id = pr1->proto_id;
+               newpr->spisize = pr1->spisize;
+               newpr->encmode = pr1->encmode;
+               newpr->spi = pr2->spi;          /* copy my SPI */
+               newpr->spi_p = pr1->spi;        /* copy peer's SPI */
+               newpr->reqid_in = pr2->reqid_in;
+               newpr->reqid_out = pr2->reqid_out;
+#ifdef ENABLE_NATT
+               newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
+#endif
+
+               newtr = newsatrns();
+               if (newtr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to allocate satrns.\n");
+                       goto err;
+               }
+               newtr->trns_no = tr1->trns_no;
+               newtr->trns_id = tr1->trns_id;
+               newtr->encklen = tr1->encklen;
+               newtr->authtype = tr1->authtype;
+
+               inssatrns(newpr, newtr);
+               inssaproto(newpp, newpr);
+
+               pr1 = pr1->next;
+               pr2 = pr2->next;
+       }
+
+       /* XXX should check if we have visited all items or not */
+       if (!ordermatters) {
+               switch (side) {
+               case RESPONDER:
+                       if (!pr2)
+                               pr1 = NULL;
+                       break;
+               case INITIATOR:
+                       if (!pr1)
+                               pr2 = NULL;
+                       break;
+               }
+       }
+
+       /* should be matched all protocols in a proposal */
+       if (pr1 != NULL || pr2 != NULL)
+               goto err;
+
+       return newpp;
+
+err:
+       flushsaprop(newpp);
+       return NULL;
+}
+
+/* take a single match between saprop.  returns 0 if pp1 equals to pp2. */
+int
+cmpsaprop(pp1, pp2)
+       const struct saprop *pp1, *pp2;
+{
+       if (pp1->pfs_group != pp2->pfs_group) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "pfs_group mismatch. mine:%d peer:%d\n",
+                       pp1->pfs_group, pp2->pfs_group);
+               /* FALLTHRU */
+       }
+
+       if (pp1->lifetime > pp2->lifetime) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "less lifetime proposed. mine:%d peer:%d\n",
+                       (int)pp1->lifetime, (int)pp2->lifetime);
+               /* FALLTHRU */
+       }
+       if (pp1->lifebyte > pp2->lifebyte) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "less lifebyte proposed. mine:%d peer:%d\n",
+                       pp1->lifebyte, pp2->lifebyte);
+               /* FALLTHRU */
+       }
+
+       return 0;
+}
+
+/*
+ * take a single match between satrns.  returns 0 if tr1 equals to tr2.
+ * tr1: peer's satrns
+ * tr2: my satrns
+ */
+int
+cmpsatrns(proto_id, tr1, tr2)
+       int proto_id;
+       const struct satrns *tr1, *tr2;
+{
+       if (tr1->trns_id != tr2->trns_id) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "trns_id mismatched: "
+                       "my:%s peer:%s\n",
+                       s_ipsecdoi_trns(proto_id, tr2->trns_id),
+                       s_ipsecdoi_trns(proto_id, tr1->trns_id));
+               return 1;
+       }
+
+       if (tr1->authtype != tr2->authtype) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "authtype mismatched: "
+                       "my:%s peer:%s\n",
+                       s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
+                       s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
+               return 1;
+       }
+
+       /* XXX
+        * At this moment for interoperability, the responder obey
+        * the initiator.  It should be defined a notify message.
+        */
+       if (tr1->encklen > tr2->encklen) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "less key length proposed, "
+                       "mine:%d peer:%d.  Use initiaotr's one.\n",
+                       tr2->encklen, tr1->encklen);
+               /* FALLTHRU */
+       }
+
+       return 0;
+}
+
+int
+set_satrnsbysainfo(pr, sainfo)
+       struct saproto *pr;
+       struct sainfo *sainfo;
+{
+       struct sainfoalg *a, *b;
+       struct satrns *newtr;
+       int t;
+
+       switch (pr->proto_id) {
+       case IPSECDOI_PROTO_IPSEC_AH:
+               if (sainfo->algs[algclass_ipsec_auth] == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no auth algorithm found\n");
+                       goto err;
+               }
+               t = 1;
+               for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
+
+                       if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
+                               continue;
+                               
+                       /* allocate satrns */
+                       newtr = newsatrns();
+                       if (newtr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to allocate satrns.\n");
+                               goto err;
+                       }
+
+                       newtr->trns_no = t++;
+                       newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
+                       newtr->authtype = a->alg;
+
+                       inssatrns(pr, newtr);
+               }
+               break;
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               if (sainfo->algs[algclass_ipsec_enc] == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no encryption algorithm found\n");
+                       goto err;
+               }
+               t = 1;
+               for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
+                       for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
+                               /* allocate satrns */
+                               newtr = newsatrns();
+                               if (newtr == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "failed to allocate satrns.\n");
+                                       goto err;
+                               }
+
+                               newtr->trns_no = t++;
+                               newtr->trns_id = a->alg;
+                               newtr->encklen = a->encklen;
+                               newtr->authtype = b->alg;
+
+                               inssatrns(pr, newtr);
+                       }
+               }
+               break;
+       case IPSECDOI_PROTO_IPCOMP:
+               if (sainfo->algs[algclass_ipsec_comp] == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no ipcomp algorithm found\n");
+                       goto err;
+               }
+               t = 1;
+               for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
+
+                       /* allocate satrns */
+                       newtr = newsatrns();
+                       if (newtr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to allocate satrns.\n");
+                               goto err;
+                       }
+
+                       newtr->trns_no = t++;
+                       newtr->trns_id = a->alg;
+                       newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
+
+                       inssatrns(pr, newtr);
+               }
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unknown proto_id (%d).\n", pr->proto_id);
+               goto err;
+       }
+
+       /* no proposal found */
+       if (pr->head == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
+               return -1;
+       }
+
+       return 0;
+
+err:
+       flushsatrns(pr->head);
+       return -1;
+}
+
+struct saprop *
+aproppair2saprop(p0)
+       struct prop_pair *p0;
+{
+       struct prop_pair *p, *t;
+       struct saprop *newpp;
+       struct saproto *newpr;
+       struct satrns *newtr;
+       u_int8_t *spi;
+
+       if (p0 == NULL)
+               return NULL;
+
+       /* allocate ipsec a sa proposal */
+       newpp = newsaprop();
+       if (newpp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate saprop.\n");
+               return NULL;
+       }
+       newpp->prop_no = p0->prop->p_no;
+       /* lifetime & lifebyte must be updated later */
+
+       for (p = p0; p; p = p->next) {
+
+               /* allocate ipsec sa protocol */
+               newpr = newsaproto();
+               if (newpr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to allocate saproto.\n");
+                       goto err;
+               }
+
+               /* check spi size */
+               /* XXX should be handled isakmp cookie */
+               if (sizeof(newpr->spi) < p->prop->spi_size) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid spi size %d.\n", p->prop->spi_size);
+                       goto err;
+               }
+
+               /*
+                * XXX SPI bits are left-filled, for use with IPComp.
+                * we should be switching to variable-length spi field...
+                */
+               newpr->proto_id = p->prop->proto_id;
+               newpr->spisize = p->prop->spi_size;
+               memset(&newpr->spi, 0, sizeof(newpr->spi));
+               spi = (u_int8_t *)&newpr->spi;
+               spi += sizeof(newpr->spi);
+               spi -= p->prop->spi_size;
+               memcpy(spi, p->prop + 1, p->prop->spi_size);
+               newpr->reqid_in = 0;
+               newpr->reqid_out = 0;
+
+               for (t = p; t; t = t->tnext) {
+
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "prop#=%d prot-id=%s spi-size=%d "
+                               "#trns=%d trns#=%d trns-id=%s\n",
+                               t->prop->p_no,
+                               s_ipsecdoi_proto(t->prop->proto_id),
+                               t->prop->spi_size, t->prop->num_t,
+                               t->trns->t_no,
+                               s_ipsecdoi_trns(t->prop->proto_id,
+                               t->trns->t_id));
+
+                       /* allocate ipsec sa transform */
+                       newtr = newsatrns();
+                       if (newtr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "failed to allocate satrns.\n");
+                               goto err;
+                       }
+
+                       if (ipsecdoi_t2satrns(t->trns, newpp, newpr, newtr) < 0) {
+                               flushsaprop(newpp);
+                               return NULL;
+                       }
+
+                       inssatrns(newpr, newtr);
+               }
+
+               /*
+                * If the peer does not specify encryption mode, use 
+                * transport mode by default.  This is to conform to
+                * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
+                * that unspecified == transport), as well as RFC2407
+                * (unspecified == implementation dependent default).
+                */
+               if (newpr->encmode == 0)
+                       newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
+
+               inssaproto(newpp, newpr);
+       }
+
+       return newpp;
+
+err:
+       flushsaprop(newpp);
+       return NULL;
+}
+
+void
+flushsaprop(head)
+       struct saprop *head;
+{
+       struct saprop *p, *save;
+
+       for (p = head; p != NULL; p = save) {
+               save = p->next;
+               flushsaproto(p->head);
+               racoon_free(p);
+       }
+
+       return;
+}
+
+void
+flushsaproto(head)
+       struct saproto *head;
+{
+       struct saproto *p, *save;
+
+       for (p = head; p != NULL; p = save) {
+               save = p->next;
+               flushsatrns(p->head);
+               vfree(p->keymat);
+               vfree(p->keymat_p);
+               racoon_free(p);
+       }
+
+       return;
+}
+
+void
+flushsatrns(head)
+       struct satrns *head;
+{
+       struct satrns *p, *save;
+
+       for (p = head; p != NULL; p = save) {
+               save = p->next;
+               racoon_free(p);
+       }
+
+       return;
+}
+
+/*
+ * print multiple proposals
+ */
+void
+printsaprop(pri, pp)
+       const int pri;
+       const struct saprop *pp;
+{
+       const struct saprop *p;
+
+       if (pp == NULL) {
+               plog(pri, LOCATION, NULL, "(null)");
+               return;
+       }
+
+       for (p = pp; p; p = p->next) {
+               printsaprop0(pri, p);
+       }
+
+       return;
+}
+
+/*
+ * print one proposal.
+ */
+void
+printsaprop0(pri, pp)
+       int pri;
+       const struct saprop *pp;
+{
+       const struct saproto *p;
+
+       if (pp == NULL)
+               return;
+
+       for (p = pp->head; p; p = p->next) {
+               printsaproto(pri, p);
+       }
+
+       return;
+}
+
+void
+printsaproto(pri, pr)
+       const int pri;
+       const struct saproto *pr;
+{
+       struct satrns *tr;
+
+       if (pr == NULL)
+               return;
+
+       plog(pri, LOCATION, NULL,
+               " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
+               "encmode=%s reqid=%d:%d)\n",
+               s_ipsecdoi_proto(pr->proto_id),
+               (int)pr->spisize,
+               (unsigned long)ntohl(pr->spi),
+               (unsigned long)ntohl(pr->spi_p),
+               s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
+               (int)pr->reqid_in, (int)pr->reqid_out);
+
+       for (tr = pr->head; tr; tr = tr->next) {
+               printsatrns(pri, pr->proto_id, tr);
+       }
+
+       return;
+}
+
+void
+printsatrns(pri, proto_id, tr)
+       const int pri;
+       const int proto_id;
+       const struct satrns *tr;
+{
+       if (tr == NULL)
+               return;
+
+       switch (proto_id) {
+       case IPSECDOI_PROTO_IPSEC_AH:
+               plog(pri, LOCATION, NULL,
+                       "  (trns_id=%s authtype=%s)\n",
+                       s_ipsecdoi_trns(proto_id, tr->trns_id),
+                       s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
+               break;
+       case IPSECDOI_PROTO_IPSEC_ESP:
+               plog(pri, LOCATION, NULL,
+                       "  (trns_id=%s encklen=%d authtype=%s)\n",
+                       s_ipsecdoi_trns(proto_id, tr->trns_id),
+                       tr->encklen,
+                       s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
+               break;
+       case IPSECDOI_PROTO_IPCOMP:
+               plog(pri, LOCATION, NULL,
+                       "  (trns_id=%s)\n",
+                       s_ipsecdoi_trns(proto_id, tr->trns_id));
+               break;
+       default:
+               plog(pri, LOCATION, NULL,
+                       "(unknown proto_id %d)\n", proto_id);
+       }
+
+       return;
+}
+
+void
+print_proppair0(pri, p, level)
+       int pri; 
+       struct prop_pair *p;
+       int level;
+{
+       char spc[21];
+
+       memset(spc, ' ', sizeof(spc));
+       spc[sizeof(spc) - 1] = '\0';
+       if (level < 20) {
+               spc[level] = '\0';
+       }
+
+       plog(pri, LOCATION, NULL,
+               "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
+       if (p->next)
+               print_proppair0(pri, p->next, level + 1);
+       if (p->tnext)
+               print_proppair0(pri, p->tnext, level + 1);
+}
+
+void
+print_proppair(pri, p)
+       int pri;
+       struct prop_pair *p;
+{
+       print_proppair0(pri, p, 1);
+}
+
+int
+set_proposal_from_policy(iph2, sp_main, sp_sub)
+       struct ph2handle *iph2;
+       struct secpolicy *sp_main, *sp_sub;
+{
+       struct saprop *newpp;
+       struct ipsecrequest *req;
+       int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */
+
+       newpp = newsaprop();
+       if (newpp == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate saprop.\n");
+               goto err;
+       }
+       newpp->prop_no = 1;
+       newpp->lifetime = iph2->sainfo->lifetime;
+       newpp->lifebyte = iph2->sainfo->lifebyte;
+       newpp->pfs_group = iph2->sainfo->pfs_group;
+
+       if (lcconf->complex_bundle)
+               goto skip1;
+
+       /*
+        * decide the encryption mode of this SA bundle.
+        * the mode becomes tunnel mode when there is even one policy
+        * of tunnel mode in the SPD.  otherwise the mode becomes
+        * transport mode.
+        */
+       encmodesv = IPSEC_MODE_TRANSPORT;
+       for (req = sp_main->req; req; req = req->next) {
+               if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
+                       encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
+#ifdef ENABLE_NATT
+                       if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
+                               encmodesv += iph2->ph1->natt_options->mode_udp_diff;
+#endif
+                       break;
+               }
+       }
+
+    skip1:
+       for (req = sp_main->req; req; req = req->next) {
+               struct saproto *newpr;
+               caddr_t paddr = NULL;
+
+               /*
+                * check if SA bundle ?
+                * nested SAs negotiation is NOT supported.
+                *       me +--- SA1 ---+ peer1
+                *       me +--- SA2 --------------+ peer2
+                */
+#ifdef __linux__
+               if (req->saidx.src.ss_family && req->saidx.dst.ss_family) {
+#else
+               if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
+#endif
+                       /* check the end of ip addresses of SA */
+                       if (iph2->side == INITIATOR)
+                               paddr = (caddr_t)&req->saidx.dst;
+                       else
+                               paddr = (caddr_t)&req->saidx.src;
+               }
+
+               /* allocate ipsec sa protocol */
+               newpr = newsaproto();
+               if (newpr == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to allocate saproto.\n");
+                       goto err;
+               }
+
+               newpr->proto_id = ipproto2doi(req->saidx.proto);
+               if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
+                       newpr->spisize = 2;
+               else
+                       newpr->spisize = 4;
+               if (lcconf->complex_bundle) {
+                       newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
+#ifdef ENABLE_NATT
+                       if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
+                               newpr->encmode += iph2->ph1->natt_options->mode_udp_diff;
+#endif
+               }
+               else
+                       newpr->encmode = encmodesv;
+
+               if (iph2->side == INITIATOR)
+                       newpr->reqid_out = req->saidx.reqid;
+               else
+                       newpr->reqid_in = req->saidx.reqid;
+
+               if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get algorithms.\n");
+                       goto err;
+               }
+
+               /* set new saproto */
+               inssaprotorev(newpp, newpr);
+       }
+
+       /* get reqid_in from inbound policy */
+       if (sp_sub) {
+               struct saproto *pr;
+
+               req = sp_sub->req;
+               pr = newpp->head;
+               while (req && pr) {
+                       if (iph2->side == INITIATOR)
+                               pr->reqid_in = req->saidx.reqid;
+                       else
+                               pr->reqid_out = req->saidx.reqid;
+                       pr = pr->next;
+                       req = req->next;
+               }
+               if (pr || req) {
+                       plog(LLV_NOTIFY, LOCATION, NULL,
+                               "There is a difference "
+                               "between the in/out bound policies in SPD.\n");
+               }
+       }
+
+       iph2->proposal = newpp;
+
+       printsaprop0(LLV_DEBUG, newpp);
+
+       return 0;
+err:
+       return -1;
+}
+
+/*
+ * generate a policy from peer's proposal.
+ * this function unconditionally chooses the first proposal the in SA payload
+ * passed by peer.
+ */
+int
+set_proposal_from_proposal(iph2)
+       struct ph2handle *iph2;
+{
+        struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
+       struct saproto *newpr = NULL, *pr;
+       struct prop_pair **pair;
+       int error = -1;
+       int i;
+
+       /* get proposal pair */
+       pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+       if (pair == NULL)
+               goto end;
+
+       /*
+        * make my proposal according as the client proposal.
+        * XXX assumed there is only one proposal even if it's the SA bundle.
+        */
+        for (i = 0; i < MAXPROPPAIRLEN; i++) {
+                if (pair[i] == NULL)
+                        continue;
+               pp_peer = aproppair2saprop(pair[i]);
+               if (pp_peer == NULL)
+                       goto end;
+
+               pp0 = newsaprop();
+               if (pp0 == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to allocate saprop.\n");
+                       goto end;
+               }
+               pp0->prop_no = 1;
+               pp0->lifetime = iph2->sainfo->lifetime;
+               pp0->lifebyte = iph2->sainfo->lifebyte;
+               pp0->pfs_group = iph2->sainfo->pfs_group;
+
+               if (pp_peer->next != NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pp_peer is inconsistency, ignore it.\n");
+                       /*FALLTHROUGH*/
+               }
+
+               for (pr = pp_peer->head; pr; pr = pr->next) { 
+
+                       newpr = newsaproto();
+                       if (newpr == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                   "failed to allocate saproto.\n");
+                               goto end;
+                       }
+                       newpr->proto_id = pr->proto_id;
+                       newpr->spisize = pr->spisize;
+                       newpr->encmode = pr->encmode;
+                       newpr->spi = 0;
+                       newpr->spi_p = pr->spi; /* copy peer's SPI */
+                       newpr->reqid_in = 0;
+                       newpr->reqid_out = 0;
+               }
+
+               if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "failed to get algorithms.\n");
+                       goto end;
+               }
+
+               inssaproto(pp0, newpr);
+               inssaprop(&newpp, pp0);
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
+       printsaprop0(LLV_DEBUG, newpp);  
+
+       iph2->proposal = newpp;
+
+       error = 0;
+
+end:
+       if (error && newpp)
+               flushsaprop(newpp);
+
+       if (pp_peer)
+               flushsaprop(pp_peer);
+       free_proppair(pair);
+       return error;
+}
+
+int
+tunnel_mode_prop(p)
+       struct saprop *p;
+{
+       struct saproto *pr;
+
+       for (pr = p->head; pr; pr = pr->next)
+               if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL)
+                       return 1;
+       return 0;
+}
diff --git a/ipsec-tools/racoon/proposal.h b/ipsec-tools/racoon/proposal.h
new file mode 100644 (file)
index 0000000..e95752b
--- /dev/null
@@ -0,0 +1,211 @@
+/* $Id: proposal.h,v 1.5.10.1 2005/05/12 19:34:10 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PROPOSAL_H
+#define _PROPOSAL_H
+
+#include <sys/queue.h>
+
+/*
+ *   A. chained list of transform, only for single proto_id
+ *      (this is same as set of transforms in single proposal payload)
+ *   B. proposal.  this will point to multiple (A) items (order is important
+ *      here so pointer to (A) must be ordered array, or chained list). 
+ *      this covers multiple proposal on a packet if proposal # is the same.
+ *   C. finally, (B) needs to be connected as chained list.
+ * 
+ *     head ---> prop[.......] ---> prop[...] ---> prop[...] ---> ...
+ *                    | | | |
+ *                    | | | +- proto4  <== must preserve order here
+ *                    | | +--- proto3
+ *                    | +----- proto2
+ *                    +------- proto1[trans1, trans2, trans3, ...]
+ *
+ *   incoming packets needs to be parsed to construct the same structure
+ *   (check "prop_pair" too).
+ */
+/* SA proposal specification */
+struct saprop {
+       int prop_no;
+       time_t lifetime;
+       int lifebyte;
+       int pfs_group;                  /* pfs group */
+       int claim;                      /* flag to send RESPONDER-LIFETIME. */
+                                       /* XXX assumed DOI values are 1 or 2. */
+
+       struct saproto *head;
+       struct saprop *next;
+};
+
+/* SA protocol specification */
+struct saproto {
+       int proto_id;
+       size_t spisize;                 /* spi size */
+       int encmode;                    /* encryption mode */
+
+       int udp_encap;                  /* UDP encapsulation */
+
+       /* XXX should be vchar_t * */
+       /* these are network byte order */
+       u_int32_t spi;                  /* inbound. i.e. --SA-> me */
+       u_int32_t spi_p;                /* outbound. i.e. me -SA-> */
+
+       vchar_t *keymat;                /* KEYMAT */
+       vchar_t *keymat_p;              /* peer's KEYMAT */
+
+       int reqid_out;                  /* request id (outbound) */
+       int reqid_in;                   /* request id (inbound) */
+
+       int ok;                         /* if 1, success to set SA in kenrel */
+
+       struct satrns *head;            /* header of transform */
+       struct saproto *next;           /* next protocol */
+};
+
+/* SA algorithm specification */
+struct satrns {
+       int trns_no;
+       int trns_id;                    /* transform id */
+       int encklen;                    /* key length of encryption algorithm */
+       int authtype;                   /* authentication algorithm if ESP */
+
+       struct satrns *next;            /* next transform */
+};
+
+/*
+ * prop_pair: (proposal number, transform number)
+ *
+ *     (SA (P1 (T1 T2)) (P1' (T1' T2')) (P2 (T1" T2")))
+ *
+ *              p[1]      p[2]
+ *      top     (P1,T1)   (P2",T1")
+ *              |  |tnext     |tnext
+ *              |  v          v
+ *              | (P1, T2)   (P2", T2")
+ *              v next
+ *             (P1', T1')
+ *                 |tnext
+ *                 v
+ *                (P1', T2')
+ *
+ * when we convert it to saprop in prop2saprop(), it should become like:
+ * 
+ *              (next)
+ *     saprop --------------------> saprop     
+ *      | (head)                     | (head)
+ *      +-> saproto                  +-> saproto
+ *           | | (head)                     | (head)
+ *           | +-> satrns(P1 T1)            +-> satrns(P2" T1")
+ *           |      | (next)                     | (next)
+ *           |      v                            v
+ *           |     satrns(P1, T2)               satrns(P2", T2")
+ *           v (next)
+ *          saproto
+ *             | (head)
+ *             +-> satrns(P1' T1')
+ *                  | (next)
+ *                  v
+ *                 satrns(P1', T2')
+ */
+struct prop_pair {
+       struct isakmp_pl_p *prop;
+       struct isakmp_pl_t *trns;
+       struct prop_pair *next; /* next prop_pair with same proposal # */
+                               /* (bundle case) */
+       struct prop_pair *tnext; /* next prop_pair in same proposal payload */
+                               /* (multiple tranform case) */
+};
+#define MAXPROPPAIRLEN 256     /* It's enough because field size is 1 octet. */
+
+/*
+ * Lifetime length selection refered to the section 4.5.4 of RFC2407.  It does
+ * not completely conform to the description of RFC.  There are four types of
+ * the behavior.  If the value of "proposal_check" in "remote" directive is;
+ *     "obey"
+ *         the responder obey the initiator anytime.
+ *     "strict"
+ *         If the responder's length is longer than the initiator's one, the
+ *         responder uses the intitiator's one.  Otherwise rejects the proposal.
+ *         If PFS is not required by the responder, the responder obeys the
+ *         proposal.  If PFS is required by both sides and if the responder's
+ *         group is not equal to the initiator's one, then the responder reject
+ *         the proposal.
+ *     "claim"
+ *         If the responder's length is longer than the initiator's one, the
+ *         responder use the intitiator's one.  If the responder's length is
+ *         shorter than the initiator's one, the responder uses own length
+ *         AND send RESPONDER-LIFETIME notify message to a initiator in the
+ *         case of lifetime.
+ *         About PFS, this directive is same as "strict".
+ *     "exact"
+ *         If the initiator's length is not equal to the responder's one, the
+ *         responder rejects the proposal.
+ *         If PFS is required and if the responder's group is not equal to
+ *         the initiator's one, then the responder reject the proposal.
+ * XXX should be defined the behavior of key length.
+ */
+#define PROP_CHECK_OBEY                1
+#define PROP_CHECK_STRICT      2
+#define PROP_CHECK_CLAIM       3
+#define PROP_CHECK_EXACT       4
+
+struct sainfo;
+struct ph1handle;
+struct secpolicy;
+extern struct saprop *newsaprop __P((void));
+extern struct saproto *newsaproto __P((void));
+extern void inssaprop __P((struct saprop **, struct saprop *));
+extern void inssaproto __P((struct saprop *, struct saproto *));
+extern void inssaprotorev __P((struct saprop *, struct saproto *));
+extern struct satrns *newsatrns __P((void));
+extern void inssatrns __P((struct saproto *, struct satrns *));
+extern struct saprop *cmpsaprop_alloc __P((struct ph1handle *,
+       const struct saprop *, const struct saprop *, int));
+extern int cmpsaprop __P((const struct saprop *, const struct saprop *));
+extern int cmpsatrns __P((int, const struct satrns *, const struct satrns *));
+extern int set_satrnsbysainfo __P((struct saproto *, struct sainfo *));
+extern struct saprop *aproppair2saprop __P((struct prop_pair *));
+extern void free_proppair __P((struct prop_pair **));
+extern void flushsaprop __P((struct saprop *));
+extern void flushsaproto __P((struct saproto *));
+extern void flushsatrns __P((struct satrns *));
+extern void printsaprop __P((const int, const struct saprop *));
+extern void printsaprop0 __P((const int, const struct saprop *));
+extern void printsaproto __P((const int, const struct saproto *));
+extern void printsatrns __P((const int, const int, const struct satrns *));
+extern void print_proppair0 __P((int, struct prop_pair *, int));
+extern void print_proppair __P((int, struct prop_pair *));
+extern int set_proposal_from_policy __P((struct ph2handle *,
+       struct secpolicy *, struct secpolicy *));
+extern int set_proposal_from_proposal __P((struct ph2handle *));
+extern int tunnel_mode_prop __P((struct saprop *p));
+
+#endif /* _PROPOSAL_H */
diff --git a/ipsec-tools/racoon/prsa_par.y b/ipsec-tools/racoon/prsa_par.y
new file mode 100644 (file)
index 0000000..b44eafc
--- /dev/null
@@ -0,0 +1,348 @@
+/* $Id: prsa_par.y,v 1.3 2004/11/08 12:04:23 ludvigm Exp $ */
+
+%{
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+/* This file contains a parser for FreeS/WAN-style ipsec.secrets RSA keys. */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "oakley.h"
+#include "isakmp_var.h"
+#include "handler.h"
+#include "crypto_openssl.h"
+#include "sockmisc.h"
+#include "rsalist.h"
+
+extern void prsaerror(const char *str, ...);
+extern int prsawrap (void);
+extern int prsalex (void);
+
+extern char *prsatext;
+extern int prsa_cur_lineno;
+extern char *prsa_cur_fname;
+extern FILE *prsain;
+
+int prsa_cur_lineno = 0;
+char *prsa_cur_fname = NULL;
+struct genlist *prsa_cur_list = NULL;
+enum rsa_key_type prsa_cur_type = RSA_TYPE_ANY;
+
+static RSA *rsa_cur;
+
+void
+prsaerror(const char *s, ...)
+{
+       char fmt[512];
+
+       va_list ap;
+#ifdef HAVE_STDARG_H
+       va_start(ap, s);
+#else
+       va_start(ap);
+#endif
+       snprintf(fmt, sizeof(fmt), "%s:%d: %s",
+               prsa_cur_fname, prsa_cur_lineno, s);
+       plogv(LLV_ERROR, LOCATION, NULL, fmt, ap);
+       va_end(ap);
+}
+
+void
+prsawarning(const char *s, ...)
+{
+       char fmt[512];
+
+       va_list ap;
+#ifdef HAVE_STDARG_H
+       va_start(ap, s);
+#else
+       va_start(ap);
+#endif
+       snprintf(fmt, sizeof(fmt), "%s:%d: %s",
+               prsa_cur_fname, prsa_cur_lineno, s);
+       plogv(LLV_WARNING, LOCATION, NULL, fmt, ap);
+       va_end(ap);
+}
+
+int
+prsawrap()
+{
+       return 1;
+} 
+%}
+%union {
+       BIGNUM *bn;
+       RSA *rsa;
+       char *chr;
+       long num;
+       struct netaddr *naddr;
+}
+
+%token COLON HEX
+%token OBRACE EBRACE COLON HEX
+%token TAG_RSA TAG_PUB TAG_PSK
+%token MODULUS PUBLIC_EXPONENT PRIVATE_EXPONENT 
+%token PRIME1 PRIME2 EXPONENT1 EXPONENT2 COEFFICIENT
+%token ADDR4 ADDR6 ADDRANY SLASH NUMBER BASE64
+
+%type <bn>     HEX
+%type <num>    NUMBER
+%type <chr>    ADDR4 ADDR6 BASE64
+
+%type <rsa>    rsa_statement
+%type <num>    prefix
+%type <naddr>  addr4 addr6 addr
+
+%%
+statements:
+       statements statement
+       | statement
+       ;
+
+statement:
+       addr addr COLON rsa_statement
+       {
+               rsa_key_insert(prsa_cur_list, $1, $2, $4);
+       }
+       | addr COLON rsa_statement 
+       {
+               rsa_key_insert(prsa_cur_list, NULL, $1, $3);
+       }
+       | COLON rsa_statement 
+       {
+               rsa_key_insert(prsa_cur_list, NULL, NULL, $2);
+       }
+       ;
+
+rsa_statement:
+       TAG_RSA OBRACE params EBRACE
+       {
+               if (prsa_cur_type == RSA_TYPE_PUBLIC) {
+                       prsawarning("Using private key for public key purpose.\n");
+                       if (!rsa_cur->n || !rsa_cur->e) {
+                               prsaerror("Incomplete key. Mandatory parameters are missing!\n");
+                               YYABORT;
+                       }
+               }
+               else {
+                       if (!rsa_cur->n || !rsa_cur->e || !rsa_cur->d) {
+                               prsaerror("Incomplete key. Mandatory parameters are missing!\n");
+                               YYABORT;
+                       }
+                       if (!rsa_cur->p || !rsa_cur->q || !rsa_cur->dmp1
+                           || !rsa_cur->dmq1 || !rsa_cur->iqmp) {
+                               if (rsa_cur->p) BN_clear_free(rsa_cur->p);
+                               if (rsa_cur->q) BN_clear_free(rsa_cur->q);
+                               if (rsa_cur->dmp1) BN_clear_free(rsa_cur->dmp1);
+                               if (rsa_cur->dmq1) BN_clear_free(rsa_cur->dmq1);
+                               if (rsa_cur->iqmp) BN_clear_free(rsa_cur->iqmp);
+
+                               rsa_cur->p = NULL;
+                               rsa_cur->q = NULL;
+                               rsa_cur->dmp1 = NULL;
+                               rsa_cur->dmq1 = NULL;
+                               rsa_cur->iqmp = NULL;
+                       }
+               }
+               $$ = rsa_cur;
+               rsa_cur = RSA_new();
+       }
+       | TAG_PUB BASE64
+       {
+               if (prsa_cur_type == RSA_TYPE_PRIVATE) {
+                       prsaerror("Public key in private-key file!\n");
+                       YYABORT;
+               }
+               $$ = base64_pubkey2rsa($2);
+       }
+       | TAG_PUB HEX
+       {
+               if (prsa_cur_type == RSA_TYPE_PRIVATE) {
+                       prsaerror("Public key in private-key file!\n");
+                       YYABORT;
+               }
+               $$ = bignum_pubkey2rsa($2);
+       }
+       ;
+
+addr:
+       addr4
+       | addr6
+       | ADDRANY
+       {
+               $$ = NULL;
+       }
+       ;
+
+addr4:
+       ADDR4 prefix
+       {
+               int err;
+               struct sockaddr_in *sap;
+               
+               if ($2 == -1) $2 = 32;
+               if ($2 < 0 || $2 > 32) {
+                       prsaerror ("Invalid IPv4 prefix\n");
+                       YYABORT;
+               }
+               $$ = calloc (sizeof(struct netaddr), 1);
+               $$->prefix = $2;
+               sap = (struct sockaddr_in *)(&$$->sa);
+               sap->sin_family = AF_INET;
+               err = inet_pton(AF_INET, $1, (struct in_addr*)(&sap->sin_addr));
+               if (err <= 0) {
+                       prsaerror("inet_pton(%s): %s\n", $1, strerror(errno));
+                       YYABORT;
+               }
+       }
+       ;
+
+addr6:
+       ADDR6 prefix
+       {
+               int err;
+               struct sockaddr_in6 *sap;
+               
+               if ($2 == -1) $2 = 128;
+               if ($2 < 0 || $2 > 128) {
+                       prsaerror ("Invalid IPv6 prefix\n");
+                       YYABORT;
+               }
+               $$ = calloc (sizeof(struct netaddr), 1);
+               $$->prefix = $2;
+               sap = (struct sockaddr_in6 *)(&$$->sa);
+               sap->sin6_family = AF_INET6;
+               err = inet_pton(AF_INET6, $1, (struct in6_addr*)(&sap->sin6_addr));
+               if (err <= 0) {
+                       prsaerror("inet_pton(%s): %s\n", $1, strerror(errno));
+                       YYABORT;
+               }
+       }
+       ;
+
+prefix:
+       /* nothing */ { $$ = -1; }
+       | SLASH NUMBER { $$ = $2; }
+       ;
+params:
+       params param
+       | param
+       ;
+
+param:
+       MODULUS COLON HEX 
+       { if (!rsa_cur->n) rsa_cur->n = $3; else { prsaerror ("Modulus already defined\n"); YYABORT; } }
+       | PUBLIC_EXPONENT COLON HEX 
+       { if (!rsa_cur->e) rsa_cur->e = $3; else { prsaerror ("PublicExponent already defined\n"); YYABORT; } }
+       | PRIVATE_EXPONENT COLON HEX 
+       { if (!rsa_cur->d) rsa_cur->d = $3; else { prsaerror ("PrivateExponent already defined\n"); YYABORT; } }
+       | PRIME1 COLON HEX 
+       { if (!rsa_cur->p) rsa_cur->p = $3; else { prsaerror ("Prime1 already defined\n"); YYABORT; } }
+       | PRIME2 COLON HEX 
+       { if (!rsa_cur->q) rsa_cur->q = $3; else { prsaerror ("Prime2 already defined\n"); YYABORT; } }
+       | EXPONENT1 COLON HEX 
+       { if (!rsa_cur->dmp1) rsa_cur->dmp1 = $3; else { prsaerror ("Exponent1 already defined\n"); YYABORT; } }
+       | EXPONENT2 COLON HEX 
+       { if (!rsa_cur->dmq1) rsa_cur->dmq1 = $3; else { prsaerror ("Exponent2 already defined\n"); YYABORT; } }
+       | COEFFICIENT COLON HEX 
+       { if (!rsa_cur->iqmp) rsa_cur->iqmp = $3; else { prsaerror ("Coefficient already defined\n"); YYABORT; } }
+       ;
+%%
+
+int prsaparse(void);
+
+int
+prsa_parse_file(struct genlist *list, char *fname, enum rsa_key_type type)
+{
+       FILE *fp = NULL;
+       int ret;
+       
+       if (!fname)
+               return -1;
+       if (type == RSA_TYPE_PRIVATE) {
+               struct stat st;
+               if (stat(fname, &st) < 0)
+                       return -1;
+               if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Too slack permissions on private key '%s'\n", 
+                               fname);
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "Should be at most 0600, now is 0%o\n",
+                               st.st_mode & 0777);
+                       return -1;
+               }
+       }
+       fp = fopen(fname, "r");
+       if (!fp)
+               return -1;
+       prsain = fp;
+       prsa_cur_lineno = 1;
+       prsa_cur_fname = fname;
+       prsa_cur_list = list;
+       prsa_cur_type = type;
+       rsa_cur = RSA_new();
+       ret = prsaparse();
+       if (rsa_cur) {
+               RSA_free(rsa_cur);
+               rsa_cur = NULL;
+       }
+       fclose (fp);
+       prsain = NULL;
+       return ret;
+}
diff --git a/ipsec-tools/racoon/prsa_tok.l b/ipsec-tools/racoon/prsa_tok.l
new file mode 100644 (file)
index 0000000..be0d26c
--- /dev/null
@@ -0,0 +1,91 @@
+/* $Id: prsa_tok.l,v 1.2 2004/07/12 20:43:51 ludvigm Exp $ */
+
+%{
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+/* This file contains a tokeniser for FreeS/WAN-style ipsec.secrets RSA keys. */
+
+#include <string.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#ifdef __APPLE__
+#include "y.tab.h"
+#else
+#include "prsa_par.h"
+#endif
+
+extern int prsalex (void);
+extern int prsa_cur_lineno;
+
+%}
+
+comment                \#.*
+digit          [0-9]
+octet          (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5])))
+addr4          {octet}\.{octet}\.{octet}\.{octet}
+hex            [0-9a-fA-F]
+word6          {hex}{0,4}
+base64         [A-Za-z0-9+/=]
+addr6          (::({word6}|{addr4})?|({word6}:)+:?({word6}|{addr4})?)
+%%
+\{             { return OBRACE; }
+\}             { return EBRACE; }
+:              { return COLON; }
+RSA            { return TAG_RSA; }
+PSK            { return TAG_PSK; }
+PUB            { return TAG_PUB; }
+0x[0-9a-fA-F]+ { 
+                       BIGNUM *bn = BN_new();
+                       BN_hex2bn(&bn, prsatext+2);
+                       prsalval.bn = bn;
+                       return HEX;
+               }
+0s{base64}+    {
+                       prsalval.chr = strdup(prsatext);
+                       return BASE64;
+               }
+Modulus                { return MODULUS; }
+PublicExponent { return PUBLIC_EXPONENT; }
+PrivateExponent        { return PRIVATE_EXPONENT; }
+Prime1         { return PRIME1; }
+Prime2         { return PRIME2; }
+Exponent1      { return EXPONENT1; }
+Exponent2      { return EXPONENT2; }
+Coefficient    { return COEFFICIENT; }
+\/             { return SLASH; }
+{digit}+       { prsalval.num = atol(prsatext); return NUMBER; }
+any            { return ADDRANY; }
+{addr4}                { prsalval.chr = strdup(prsatext); return ADDR4; }
+{addr6}                { prsalval.chr = strdup(prsatext); return ADDR6; }
+[ \t]*         ;
+\n             { prsa_cur_lineno++; }
+\#.*           ;
+%%
diff --git a/ipsec-tools/racoon/racoon.8 b/ipsec-tools/racoon/racoon.8
new file mode 100644 (file)
index 0000000..8e02322
--- /dev/null
@@ -0,0 +1,157 @@
+.\" $Id: racoon.8,v 1.3.10.1 2005/04/18 11:10:55 manubsd Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd November 20, 2000
+.Dt RACOON 8
+.Os
+.\"
+.Sh NAME
+.Nm racoon
+.Nd IKE (ISAKMP/Oakley) key management daemon
+.\"
+.Sh SYNOPSIS
+.Nm racoon
+.Bk -words
+.Op Fl 46BdFLv
+.Ek
+.Bk -words
+.Op Fl f Ar configfile
+.Ek
+.Bk -words
+.Op Fl l Ar logfile
+.Ek
+.Bk -words
+.Op Fl P Ar isakmp-natt-port
+.Ek
+.Bk -words
+.Op Fl p Ar isakmp-port
+.Ek
+.\"
+.Sh DESCRIPTION
+.Nm
+speaks the IKE
+.Pq ISAKMP/Oakley
+key management protocol,
+to establish security associations with other hosts.
+The SPD
+.Pq Security Policy Database
+in the kernel usually triggers
+.Nm .
+.Nm
+usually sends all informational messages, warnings and error messages to
+.Xr syslogd 8
+with the facility
+.Dv LOG_DAEMON
+and the priority
+.Dv LOG_INFO .
+Debugging messages are sent with the priority
+.Dv LOG_DEBUG .
+You should configure
+.Xr syslog.conf 5
+appropriately to see these messages.
+.Bl -tag -width Ds
+.It Fl 4
+.It Fl 6
+Specify the default address family for the sockets.
+.It Fl B
+Install SA(s) from the file which is specified in
+.Xr racoon.conf 5 .
+.It Fl d
+Increase the debug level.
+Multiple
+.Fl d
+arguments will increase the debug level even more.
+.It Fl F
+Run
+.Nm
+in the foreground.
+.It Fl f Ar configfile
+Use
+.Ar configfile
+as the configuration file instead of the default.
+.It Fl L
+Include
+.Ar file_name:line_number:function_name
+in all messages.
+.It Fl l Ar logfile
+Use
+.Ar logfile
+as the logging file instead of
+.Xr syslogd 8 .
+.It Fl P Ar isakmp-natt-port
+Use
+.Ar isakmp-natt-port
+for NAT-Traversal port-floating.
+The default is 4500.
+.It Fl p Ar isakmp-port
+Listen to the ISAKMP key exchange on port
+.Ar isakmp-port
+instead of the default port number, 500.
+.It Fl v
+This flag causes the packet dump be more verbose, with higher
+debugging level.
+.El
+.Pp
+.Nm
+assumes the presence of the kernel random number device
+.Xr rnd 4
+at
+.Pa /dev/urandom .
+.\"
+.Sh RETURN VALUES
+The command exits with 0 on success, and non-zero on errors.
+.\"
+.Sh FILES
+.Bl -tag -width /private/etc/racoon/remote/anonymous -compact
+.It Pa /private/etc/racoon/racoon.conf 
+default configuration file.
+.It Pa /private/etc/racoon/remote/anonymous 
+default anonymous configuration file.
+.It Pa /private/etc/racoon/psk.txt 
+default pre-shared key file.
+.El
+.\"
+.Sh SEE ALSO
+.Xr ipsec 4 ,
+.Xr racoon.conf 5 ,
+.Xr syslog.conf 5 ,
+.Xr setkey 8 ,
+.Xr syslogd 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in the
+.Dq YIPS
+Yokogawa IPsec implementation.
+.\"
+.Sh SECURITY CONSIDERATIONS
+The use of IKE phase 1 aggressive mode is not recommended,
+as described in
+.Pa http://www.kb.cert.org/vuls/id/886601 .
diff --git a/ipsec-tools/racoon/racoon.conf.5 b/ipsec-tools/racoon/racoon.conf.5
new file mode 100644 (file)
index 0000000..1183e61
--- /dev/null
@@ -0,0 +1,1158 @@
+.\"    $Id: racoon.conf.5,v 1.27.2.12 2005/11/25 16:06:32 manubsd Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd November 23, 2004
+.Dt RACOON.CONF 5
+.Os
+.\"
+.Sh NAME
+.Nm racoon.conf
+.Nd configuration file for racoon
+.\"
+.\" .Sh SYNOPSIS
+.\"
+.Sh DESCRIPTION
+.Nm
+is the configuration file for the
+.Xr racoon 8
+ISAKMP daemon.
+.Xr racoon 8
+negotiates security associations for itself (ISAKMP SA, or phase 1 SA)
+and for kernel IPsec (IPsec SA, or phase 2 SA).
+The file consists of a sequence of directives and statements.
+Each directive is composed by a tag and statements, enclosed by
+.Ql {
+and
+.Ql } .
+Lines beginning with
+.Ql #
+are comments.
+.\"
+.Ss Meta Syntax
+Keywords and special characters that the parser expects exactly are
+displayed using
+.Ic this
+font.
+Parameters are specified with
+.Ar this
+font.
+Square brackets
+.Po
+.Ql \&[
+and
+.Ql \&]
+.Pc
+are used to show optional keywords and parameters.
+Note that
+you have to pay attention when this manual is describing
+.Ar port
+numbers.
+The
+.Ar port
+number is always enclosed by
+.Ql \&[
+and
+.Ql \&] .
+In this case, the port number is not an optional keyword.
+If it is possible to omit the
+.Ar port
+number,
+the expression becomes
+.Bq Bq Ar port .
+The vertical bar
+.Pq Ql \&|
+is used to indicate
+a choice between optional parameters.
+Parentheses
+.Po
+.Ql \&(
+and
+.Ql \&)
+.Pc
+are used to group keywords and parameters when necessary.
+Major parameters are listed below.
+.Pp
+.Bl -tag -width addressx -compact
+.It Ar number
+means a hexadecimal or a decimal number.
+The former must be prefixed with
+.Ql Li 0x .
+.It Ar string
+.It Ar path
+.It Ar file
+means any string enclosed in
+.Ql \&"
+.Pq double quotes .
+.It Ar address
+means IPv6 and/or IPv4 address.
+.It Ar port
+means a TCP/UDP port number.
+The port number is always enclosed by
+.Ql \&[
+and
+.Ql \&] .
+.It Ar timeunit
+is one of following:
+.Ic sec , secs , second , seconds ,
+.Ic min , mins , minute , minutes ,
+.Ic hour , hours .
+.El
+.\"
+.Ss Privilege separation
+.Bl -tag -width Ds -compact
+.It Ic privsep { Ar statements Ic }
+specifies privilege separation parameters.
+When enabled, these enable
+.Xr racoon 8
+to operate with an unprivileged instance doing most of the work, while
+a privileged instance takes care of performing the following operations
+as root: reading PSK and private keys, launching hook scripts, and
+validating passwords against system databases or against PAM.
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic user Ar user ;
+The user to which the unprivileged instance of
+.Xr racoon 8 ,
+should switch.
+This can be a quoted user name or a numeric UID.
+.It Ic group Ar group ;
+The group to which the unprivileged instance of
+.Xr racoon 8 ,
+should switch.
+This can be a quoted group name or a numeric GID.
+.It Ic chroot Ar path ;
+A directory to which the unprivileged instance of
+.Xr racoon 8
+should
+.Xr chroot 2 .
+This directory should hold a tree where the following files must be
+reachable:
+.Bl -tag -width Ds -compact
+.It Pa /dev/random
+.It Pa /dev/urandom
+.It the certificates
+.It the file containing the Xauth banner
+.El
+.Pp
+The PSK file, the private keys, and the hook scripts are accessed through the
+privileged instance of
+.Xr racoon 8
+and do not need to be reachable in the
+.Xr chroot 2 Ap ed
+tree.
+.El
+.El
+.Ss Path Specification
+This section specify various paths used by racoon.
+When running in privilege separation mode,
+.Ic certificate
+and
+.Ic script
+paths are mandatory.
+.Bl -tag -width Ds -compact
+.It Ic path include Ar path ;
+specifies a path to include a file.
+See
+.Sx File Inclusion .
+.It Ic path pre_shared_key Ar file ;
+specifies a file containing pre-shared key(s) for various ID(s).
+See
+.Sx Pre-shared key File .
+.It Ic path certificate Ar path ;
+.Xr racoon 8
+will search this directory if a certificate or certificate request is received.
+If you run with privilege separation,
+.Xr racoon 8
+will refuse to use a certificate stored outside of this directory.
+.It Ic path backupsa Ar file ;
+specifies a file to which SA information which is negotiated by
+racoon should be stored.
+.Xr racoon 8
+will install SA(s) from the file when started with the
+.Fl B
+flag.
+The file is growing because
+.Xr racoon 8
+simply adds SAs to it.
+You should maintain the file manually.
+.It Ic path script Ar path ;
+.Xr racoon 8
+will search this directory for scripts hooks.
+If you run with privilege separation,
+.Xr racoon 8
+will refuse to execute a script stored outside of this directory.
+.It Ic path pidfile Ar file ;
+specifies file where to store PID of process.
+If path starts with
+.Pa /
+it is treated as
+an absolute path, otherwise relative to VARRUN directory specified at
+compilation time.
+Default is
+.Pa racoon.pid .
+.It Ic path logfile Ar file ;
+specifies log file path.
+.El
+.\"
+.Ss File Inclusion
+.Bl -tag -width Ds -compact
+.It Ic include Ar file
+other configuration files can be included.
+.El
+.\"
+.Ss Identifier Specification
+is obsolete.
+It must be defined at each
+.Ic remote
+directive.
+.\"
+.Ss Timer Specification
+.Bl -tag -width Ds -compact
+.It Ic timer { Ar statements Ic }
+specifies various timer values.
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic counter Ar number ;
+the maximum number of retries to send.
+The default is 5.
+.It Ic interval Ar number Ar timeunit ;
+the interval to resend, in seconds.
+The default time is 10 seconds.
+.It Ic persend Ar number ;
+the number of packets per send.
+The default is 1.
+.It Ic phase1 Ar number Ar timeunit ;
+the maximum time it should take to complete phase 1.
+The default time is 15 seconds.
+.It Ic phase2 Ar number Ar timeunit ;
+the maximum time it should take to complete phase 2.
+The default time is 10 seconds.
+.It Ic natt_keepalive Ar number Ar timeunit ;
+interval between sending NAT-Traversal keep-alive packets.
+The default time is 20 seconds.
+Set to 0s to disable keep-alive packets.
+.El
+.El
+.\"
+.Ss Listening Port Specification
+.Bl -tag -width Ds -compact
+.It Ic listen { Ar statements Ic }
+If no
+.Ar listen
+directive is specified,
+.Xr racoon 8
+will listen on all available interface addresses.
+The following is the list of valid statements:
+.Pp
+.Bl -tag -width Ds -compact
+.\" How do I express bold brackets; `[' and `]' .
+.\" Answer: For bold brackets, do "Ic \&[ foo \&]".
+.\" Is the "Bq Ic [ Ar port ] ;" buggy ?
+.It Ic isakmp Ar address Bq Bq Ar port ;
+If this is specified,
+.Xr racoon 8
+will only listen on
+.Ar address .
+The default port is 500, which is specified by IANA.
+You can provide more than one address definition.
+.It Ic isakmp_natt Ar address Bq Ar port ;
+Same as
+.Ic isakmp
+but also sets the socket options to accept UDP-encapsulated ESP traffic for
+NAT-Traversal.
+If you plan to use NAT-T, you should provide at least one address
+with port 4500, which is specified by IANA.
+There is no default.
+.It Ic strict_address ;
+require that all addresses for ISAKMP must be bound.
+This statement will be ignored if you do not specify any address.
+.El
+The
+.Ar listen
+section can also be used to specify the admin socket mode and ownership,
+if racoon was built with support for admin port.
+.Bl -tag -width Ds -compact
+.It Ic adminsock Ar path Op Ar owner\ group\ mode ;
+.Ar path ,
+.Ar owner ,
+and
+.Ar group
+are the socket path, owner, and group; they must be quoted.
+Defaults are
+.Pa /var/racoon/racoon.sock ,
+UID 0, and GID 0.
+.Ar mode
+is the access mode in octal, default is 0600.
+.It Ic adminsock disabled ;
+This directive tells racoon to not listen on the admin socket.
+.El
+.El
+.\"
+.Ss Miscellaneous Global Parameters
+.Bl -tag -width Ds -compact
+.It Ic gss_id_enc Ar enctype ;
+Older versions of
+.Xr racoon 8
+used ISO-Latin-1 as the encoding of the GSS-API identifier attribute.
+For interoperability with Microsoft Windows' GSS-API authentication
+scheme, the default encoding has been changed to UTF-16LE.
+The
+.Ic gss_id_enc
+parameter allows
+.Xr racoon 8
+to be configured to use the old encoding for compatibility with existing
+.Xr racoon 8
+installations.
+The following are valid values for
+.Ar enctype :
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic utf-16le
+Use UTF-16LE to encode the GSS-API identifier attribute.
+This is the default encoding.
+This encoding is compatible with Microsoft Windows.
+.It Ic latin1
+Use ISO-Latin-1 to encode the GSS-API identifier attribute.
+This is the encoding used by older versions of
+.Xr racoon 8 .
+.El
+.El
+.\"
+.Ss Remote Nodes Specifications
+.Bl -tag -width Ds -compact
+.It Xo
+.Ic remote ( Ar address | Ic anonymous )
+.Bq Bq Ar port
+.Bq Ic inherit Ar parent
+.Ic { Ar statements Ic }
+.Xc
+specifies the parameters for IKE phase 1 for each remote node.
+The default port is 500.
+If
+.Ic anonymous
+is specified, the statements apply to all peers which do not match
+any other
+.Ic remote
+directive.
+.Pp
+Sections with
+.Ic inherit Ar parent
+statements (where
+.Ar parent
+is either
+.Ar address
+or a keyword
+.Ic anonymous )
+have all values predefined to those of a given
+.Ar parent .
+In these sections it is enough to redefine only the changed parameters.
+.Pp
+The following are valid statements.
+.Pp
+.Bl -tag -width Ds -compact
+.\"
+.It Ic exchange_mode ( main | aggressive | base ) ;
+defines the exchange mode for phase 1 when racoon is the initiator.
+It also means the acceptable exchange mode when racoon is responder.
+More than one mode can be specified by separating them with a comma.
+All of the modes are acceptable.
+The first exchange mode is what racoon uses when it is the initiator.
+.\"
+.It Ic doi Ic ipsec_doi ;
+means to use IPsec DOI as specified in RFC 2407.
+You can omit this statement.
+.\"
+.It Ic situation Ic identity_only ;
+means to use SIT_IDENTITY_ONLY as specified in RFC 2407.
+You can omit this statement.
+.\"
+.It Ic identifier Ar idtype ;
+is obsolete.
+Instead, use
+.Ic my_identifier .
+.\"
+.It Ic my_identifier Ar idtype ... ;
+specifies the identifier sent to the remote host
+and the type to use in the phase 1 negotiation.
+.Ic address, fqdn , user_fqdn , keyid ,
+and
+.Ic asn1dn
+can be used as an
+.Ar idtype .
+Use them in the following way:
+.Bl -tag -width Ds -compact
+.It Ic my_identifier Ic address Bq Ar address ;
+the type is the IP address.
+This is the default type if you do not specify an identifier to use.
+.It Ic my_identifier Ic user_fqdn Ar string ;
+the type is a USER_FQDN (user fully-qualified domain name).
+.It Ic my_identifier Ic fqdn Ar string ;
+the type is a FQDN (fully-qualified domain name).
+.It Ic my_identifier Ic keyid Ar file ;
+the type is a KEY_ID.
+.It Ic my_identifier Ic asn1dn Bq Ar string ;
+the type is an ASN.1 distinguished name.
+If
+.Ar string
+is omitted,
+.Xr racoon 8
+will get the DN from the Subject field in the certificate.
+.El
+.\"
+.It Ic xauth_login Bq Ar string ;
+specifies the login to use in client-side Hybrid authentication.
+It is available only if
+.Xr racoon 8
+has been built with this option.
+The associated password is looked up in the pre-shared key files,
+using the login
+.Ic string
+as the key id.
+.\"
+.It Ic peers_identifier Ar idtype ... ;
+specifies the peer's identifier to be received.
+If it is not defined then
+.Xr racoon 8
+will not verify the peer's identifier in ID payload transmitted from the peer.
+If it is defined, the behavior of the verification depends on the flag of
+.Ic verify_identifier .
+The usage of
+.Ar idtype
+is the same as
+.Ic my_identifier
+except that the individual component values of an
+.Ic asn1dn
+identifier may specified as
+.Ic *
+to match any value (e.g. "C=XX, O=MyOrg, OU=*, CN=Mine").
+Alternative acceptable peer identifiers may be specified by repeating the
+.Ic peers_identifier
+statement.
+.\"
+.It Ic verify_identifier (on \(ba off) ;
+If you want to verify the peer's identifier,
+set this to on.
+In this case, if the value defined by
+.Ic peers_identifier
+is not the same as the peer's identifier in the ID payload,
+the negotiation will failed.
+The default is off.
+.\"
+.It Ic certificate_type Ar certspec ;
+specifies a certificate specification.
+.Ar certspec
+is one of followings:
+.Bl -tag -width Ds -compact
+.It Ic x509 Ar certfile Ar privkeyfile ;
+.Ar certfile
+means a file name of a certificate.
+.Ar privkeyfile
+means a file name of a secret key.
+.El
+.It Ic ca_type Ar cacertspec ;
+specifies a root certificate authority specification.
+.Ar cacertspec
+is one of followings:
+.Bl -tag -width Ds -compact
+.It Ic x509 Ar cacertfile ;
+.Ar cacertfile
+means a file name of the root certificate authority.
+Default is
+.Pa /etc/openssl/cert.pem
+.El
+.\"
+.It Ic mode_cfg (on \(ba off) ;
+Gather network information through ISAKMP mode configuration.
+Default is off.
+.\"
+.It Ic peers_certfile ( dnssec | Ar certfile ) ;
+If
+.Ic dnssec
+is defined,
+.Xr racoon 8
+will ignore the CERT payload from the peer,
+and try to get the peer's certificate from DNS instead.
+If
+.Ar certfile
+is defined,
+.Xr racoon 8
+will ignore the CERT payload from the peer,
+and will use this certificate as the peer's certificate.
+.\"
+.It Ic script Ar script Ic phase1_up
+.It Ic script Ar script Ic phase1_down
+Shell scripts that get executed when a phase 1 SA goes up or down.
+Both scripts get either
+.Ic phase1_up
+or
+.Ic phase1_down
+as first argument, and the following
+variables are set in their environment:
+.Bl -tag -width Ds -compact
+.It Ev LOCAL_ADDR
+The local address of the phase 1 SA.
+.It Ev LOCAL_PORT
+The local port used for IKE for the phase 1 SA.
+.It Ev REMOTE_ADDR
+The remote address of the phase 1 SA.
+.It Ev REMOTE_PORT
+The remote port used for IKE for the phase 1 SA.
+.El
+The following variables are only set if
+.Ic mode_cfg
+was enabled:
+.Bl -tag -width Ds -compact
+.It INTERNAL_ADDR4
+An IPv4 internal address obtained by ISAKMP mode config.
+.It INTERNAL_NETMASK4
+An IPv4 internal netmask obtained by ISAKMP mode config.
+.It INTERNAL_DNS4
+Internal DNS server IPv4 address obtained by ISAKMP mode config.
+.It INTERNAL_NBNS4
+Internal WINS server IPv4 address obtained by ISAKMP mode config.
+.El
+.\"
+.\"
+.It Ic send_cert (on \(ba off) ;
+If you do not want to send a certificate for some reason, set this to off.
+The default is on.
+.\"
+.It Ic send_cr (on \(ba off) ;
+If you do not want to send a certificate request for some reason, set this to off.
+The default is on.
+.\"
+.It Ic verify_cert (on \(ba off) ;
+If you do not want to verify the peer's certificate for some reason,
+set this to off.
+The default is on.
+.\"
+.It Ic lifetime time Ar number Ar timeunit ;
+Define a lifetime of a certain time
+which will be proposed in the phase 1 negotiations.
+Any proposal will be accepted, and the attribute(s) will be not proposed to
+the peer if you do not specify it (them).
+They can be individually specified in each proposal.
+.\"
+.It Ic ike_frag (on \(ba off) ;
+Enable receiver-side IKE fragmentation, if
+.Xr racoon 8
+has been built with this feature.
+This extension is there to work around
+broken firewalls that do not work with fragmented UDP packets.
+IKE fragmentation is always enabled on the sender-side, and
+it is used if the peer advertises itself as IKE fragmentation capable.
+.\"
+.It Ic esp_frag Ar fraglen ;
+This option is only relevant if you use NAT traversal in tunnel mode.
+Its purpose is to work around broken DSL routers that reject UDP
+fragments, by fragmenting the IP packets before ESP encapsulation.
+The result is ESP over UDP of fragmented packets instead of fragmented
+ESP over UDP packets (i.e., IP:UDP:ESP:frag(IP) instead of
+frag(IP:UDP:ESP:IP)).
+.Ar fraglen
+is the maximum size of the fragments.
+552 should work anywhere,
+but the higher
+.Ar fraglen
+is, the better is the performance.
+.Pp
+Note that because PMTU discovery is broken on many sites, you will
+have to use MSS clamping if you want TCP to work correctly.
+.\"
+.It Ic initial_contact (on \(ba off) ;
+enable this to send an INITIAL-CONTACT message.
+The default value is
+.Ic on .
+This message is useful only when
+the implementation of the responder chooses an old SA when there are multiple
+SAs with different established time, and the initiator reboots.
+If racoon did not send the message,
+the responder would use an old SA even when a new SA was established.
+The KAME stack has the switch in the system wide value
+net.key.preferred_oldsa.
+when the value is zero, the stack always uses a new SA.
+.\"
+.It Ic passive (on \(ba off) ;
+If you do not want to initiate the negotiation, set this to on.
+The default value is
+.Ic off .
+It is useful for a server.
+.\"
+.It Ic proposal_check Ar level ;
+specifies the action of lifetime length and PFS of the phase 2
+selection on the responder side, and the action of lifetime check in
+phase 1.
+The default level is
+.Ic strict .
+If the
+.Ar level
+is:
+.Bl -tag -width Ds -compact
+.It Ic obey
+the responder will obey the initiator anytime.
+.It Ic strict
+If the responder's length is longer than the initiator's one, the
+responder uses the initiator's one.
+Otherwise it rejects the proposal.
+If PFS is not required by the responder, the responder will obey the proposal.
+If PFS is required by both sides and if the responder's group is not equal to
+the initiator's one, then the responder will reject the proposal.
+.It Ic claim
+If the responder's length is longer than the initiator's one, the
+responder will use the initiator's one.
+If the responder's length is
+shorter than the initiator's one, the responder uses its own length
+AND sends a RESPONDER-LIFETIME notify message to an initiator in the
+case of lifetime (phase 2 only).
+For PFS, this directive behaves the same as
+.Ic strict .
+.It Ic exact
+If the initiator's length is not equal to the responder's one, the
+responder will reject the proposal.
+If PFS is required by both sides and if the responder's group is not equal to
+the initiator's one, then the responder will reject the proposal.
+.El
+.\"
+.It Ic support_proxy (on \(ba off) ;
+If this value is set to on, then both values of ID payloads in the
+phase 2 exchange are always used as the addresses of end-point of
+IPsec-SAs.
+The default is off.
+.\"
+.It Ic generate_policy (on \(ba off) ;
+This directive is for the responder.
+Therefore you should set
+.Ic passive
+to on in order that
+.Xr racoon 8
+only becomes a responder.
+If the responder does not have any policy in SPD during phase 2
+negotiation, and the directive is set to on, then
+.Xr racoon 8
+will choose the first proposal in the
+SA payload from the initiator, and generate policy entries from the proposal.
+It is useful to negotiate with clients whose IP address is allocated
+dynamically.
+Note that an inappropriate policy might be installed into the responder's SPD
+by the initiator,
+so other communications might fail if such policies are installed
+due to a policy mismatch between the initiator and the responder.
+This directive is ignored in the initiator case.
+The default value is
+.Ic off .
+.\"
+.\"
+.It Ic nat_traversal (on \(ba off \(ba force) ;
+This directive enables use of the NAT-Traversal IPsec extension
+(NAT-T).
+NAT-T allows one or both peers to reside behind a NAT gateway (i.e.,
+doing address- or port-translation).
+Presence of NAT gateways along the path
+is discovered during phase 1 handshake and if found, NAT-T is negotiated.
+When NAT-T is in charge, all ESP and AH packets of a given connection
+are encapsulated into UDP datagrams (port 4500, by default).
+Possible values are:
+.Bl -tag -width Ds -compact
+.It Ic on
+NAT-T is used when a NAT gateway is detected between the peers.
+.It Ic off
+NAT-T is not proposed/accepted.
+This is the default.
+.It Ic force
+NAT-T is used regardless if a NAT is detected between the peers or not.
+.El
+Please note that NAT-T support is a compile-time option.
+Although it is enabled in the source distribution by default, it
+may not be available in your particular build.
+In that case you will get a
+warning when using any NAT-T related config options.
+.\"
+.It Ic dpd_delay Ar delay ;
+This option activates the DPD and sets the time (in seconds) allowed
+between 2 proof of liveness requests.
+The default value is
+.Ic 0 ,
+which disables DPD monitoring, but still negotiates DPD support.
+.\"
+.It Ic dpd_retry Ar delay ;
+If
+.Ic dpd_delay
+is set, this sets the delay (in seconds) to wait for a proof of
+liveness before considering it as failed and send another request.
+The default value is
+.Ic 5 .
+.\"
+.It Ic dpd_maxfail Ar number ;
+If
+.Ic dpd_delay
+is set, this sets the maximum number of proof of liveness to request
+(without reply) before considering the peer is dead.
+The default value is
+.Ic 5 .
+.\"
+.It Ic nonce_size Ar number ;
+define the byte size of nonce value.
+Racoon can send any value although
+RFC2409 specifies that the value MUST be between 8 and 256 bytes.
+The default size is 16 bytes.
+.\"
+.It Xo
+.Ic proposal { Ar sub-substatements Ic }
+.Xc
+.Bl -tag -width Ds -compact
+.\"
+.It Ic encryption_algorithm Ar algorithm ;
+specify the encryption algorithm used for the phase 1 negotiation.
+This directive must be defined.
+.Ar algorithm
+is one of following:
+.Ic des , 3des , blowfish , cast128 , aes
+.\".Ic rc5 , idea
+for Oakley.
+For other transforms, this statement should not be used.
+.\"
+.It Ic hash_algorithm Ar algorithm ;
+define the hash algorithm used for the phase 1 negotiation.
+This directive must be defined.
+.Ar algorithm
+is one of following:
+.Ic md5, sha1, sha256, sha384, sha512
+for Oakley.
+.\"
+.It Ic authentication_method Ar type ;
+defines the authentication method used for the phase 1 negotiation.
+This directive must be defined.
+.Ar type
+is one of:
+.Ic pre_shared_key , rsasig , gssapi_krb , hybrid_rsa_server ,
+or
+.Ic hybrid_rsa_client .
+.\"
+.It Ic dh_group Ar group ;
+define the group used for the Diffie-Hellman exponentiations.
+This directive must be defined.
+.Ar group
+is one of following:
+.Ic modp768 , modp1024 , modp1536 ,
+.Ic modp2048 , modp3072 , modp4096 ,
+.Ic modp6144 , modp8192 .
+Or you can define 1, 2, 5, 14, 15, 16, 17, or 18 as the DH group number.
+When you want to use aggressive mode,
+you must define the same DH group in each proposal.
+.It Ic lifetime time Ar number Ar timeunit ;
+define lifetime of the phase 1 SA proposal.
+Refer to the description of the
+.Ic lifetime
+directive defined in the
+.Ic remote
+directive.
+.It Ic gss_id Ar string ;
+define the GSS-API endpoint name, to be included as an attribute in the SA,
+if the
+.Ic gssapi_krb
+authentication method is used.
+If this is not defined, the default value of
+.Ql host/hostname
+is used, where hostname is the value returned by the
+.Xr hostname 1
+command.
+.El
+.El
+.El
+.\"
+.Ss Policy Specifications
+The policy directive is obsolete, policies are now in the SPD.
+.Xr racoon 8
+will obey the policy configured into the kernel by
+.Xr setkey 8 ,
+and will construct phase 2 proposals by combining
+.Ic sainfo
+specifications in
+.Nm ,
+and policies in the kernel.
+.\"
+.Ss Sainfo Specifications
+.Bl -tag -width Ds -compact
+.It Xo
+.Ic sainfo ( Ar source_id destination_id | Ic anonymous ) [ from Ar idtype [ Ar string ] ]
+.Ic { Ar statements Ic }
+.Xc
+defines the parameters of the IKE phase 2 (IPsec-SA establishment).
+.Ar source_id
+and
+.Ar destination_id
+are constructed like:
+.Pp
+.Ic address Ar address
+.Bq Ic / Ar prefix
+.Bq Ic [ Ar port ]
+.Ar ul_proto
+.Pp
+or
+.Pp
+.Ic subnet Ar address
+.Bq Ic / Ar prefix
+.Bq Ic [ Ar port ]
+.Ar ul_proto
+.Pp
+or
+.Pp
+.Ar idtype Ar string
+.Pp
+It means exactly the content of ID payload.
+This is not like a filter rule.
+For example, if you define 3ffe:501:4819::/48 as
+.Ar source_id .
+3ffe:501:4819:1000:/64 will not match.
+.Pp
+In case of longest prefix (selecting single host)
+.Ar address
+instructs to send ID type of ADDRESS, while
+.Ar subnet
+instructs to send ID type of SUBNET.
+Otherwise these instructions are identical.
+.Pp
+.Bl -tag -width Ds -compact
+.\"
+.It Ic pfs_group Ar group ;
+define the group of Diffie-Hellman exponentiations.
+If you do not require PFS then you can omit this directive.
+Any proposal will be accepted if you do not specify one.
+.Ar group
+is one of following:
+.Ic modp768 , modp1024 , modp1536 ,
+.Ic modp2048 , modp3072 , modp4096 ,
+.Ic modp6144 , modp8192 .
+Or you can define 1, 2, 5, 14, 15, 16, 17, or 18 as the DH group number.
+.\"
+.It Ic lifetime time Ar number Ar timeunit ;
+define how long an IPsec-SA will be used, in timeunits.
+Any proposal will be accepted, and no attribute(s) will be proposed to
+the peer if you do not specify it(them).
+See the
+.Ic proposal_check
+directive.
+.\"
+.It Ic my_identifier Ar idtype ... ;
+is obsolete.
+It does not make sense to specify an identifier in the phase 2.
+.El
+.\"
+.Pp
+.Xr racoon 8
+does not have a list of security protocols to be negotiated.
+The list of security protocols are passed by SPD in the kernel.
+Therefore you have to define all of the potential algorithms
+in the phase 2 proposals even if there are algorithms which will not be used.
+These algorithms are define by using the following three directives,
+with a single comma as the separator.
+For algorithms that can take variable-length keys, algorithm names
+can be followed by a key length, like
+.Dq Li blowfish 448 .
+.Xr racoon 8
+will compute the actual phase 2 proposals by computing
+the permutation of the specified algorithms,
+and then combining them with the security protocol specified by the SPD.
+For example, if
+.Ic des , 3des , hmac_md5 ,
+and
+.Ic hmac_sha1
+are specified as algorithms, we have four combinations for use with ESP,
+and two for AH.
+Then, based on the SPD settings,
+.Xr racoon 8
+will construct the actual proposals.
+If the SPD entry asks for ESP only, there will be 4 proposals.
+If it asks for both AH and ESP, there will be 8 proposals.
+Note that the kernel may not support the algorithm you have specified.
+.\"
+.Bl -tag -width Ds -compact
+.It Ic encryption_algorithm Ar algorithms ;
+.Ic des , 3des , des_iv64 , des_iv32 ,
+.Ic rc5 , rc4 , idea , 3idea ,
+.Ic cast128 , blowfish , null_enc ,
+.Ic twofish , rijndael , aes
+.Pq used with ESP
+.\"
+.It Ic authentication_algorithm Ar algorithms ;
+.Ic des , 3des , des_iv64 , des_iv32 ,
+.Ic hmac_md5 , hmac_sha1 , hmac_sha256, hmac_sha384, hmac_sha512, non_auth
+.Pq used with ESP authentication and AH
+.\"
+.It Ic compression_algorithm Ar algorithms ;
+.Ic deflate
+.Pq used with IPComp
+.El
+.El
+.\"
+.Ss Logging level
+.Bl -tag -width Ds -compact
+.It Ic log Ar level ;
+define logging level.
+.Ar level
+is one of following:
+.Ic notify , debug ,
+and
+.Ic debug2 .
+The default is
+.Ic notify .
+If you set the logging level too high on slower machines,
+IKE negotiation can fail due to timing constraint changes.
+.El
+.\"
+.Ss Specifying the way to pad
+.Bl -tag -width Ds -compact
+.It Ic padding { Ar statements Ic }
+specified padding format.
+The following are valid statements:
+.Bl -tag -width Ds -compact
+.It Ic randomize (on \(ba off) ;
+enable using a randomized value for padding.
+The default is on.
+.It Ic randomize_length (on \(ba off) ;
+the pad length is random.
+The default is off.
+.It Ic maximum_length Ar number ;
+define a maximum padding length.
+If
+.Ic randomize_length
+is off, this is ignored.
+The default is 20 bytes.
+.It Ic exclusive_tail (on \(ba off) ;
+means to put the number of pad bytes minus one into the last part
+of the padding.
+The default is on.
+.It Ic strict_check (on \(ba off) ;
+means to constrain the peer to set the number of pad bytes.
+The default is off.
+.El
+.El
+.Ss ISAKMP mode configuration settings
+.Bl -tag -width Ds -compact
+.It Ic mode_cfg { Ar statements Ic }
+Defines the information to return for remote hosts' ISAKMP mode config
+requests.
+Also defines the authentication source for remote peers
+authenticating through hybrid auth.
+.Pp
+The following are valid statements:
+.Bl -tag -width Ds -compact
+.It Ic auth_source (system \(ba radius \(ba pam) ;
+Specify the source for authentication of users through hybrid auth.
+.Ar system
+means to use the Unix user database.
+This is the default.
+.Ar radius
+means to use a RADIUS server.
+It works only if
+.Xr racoon 8
+was built with libradius support, and the configuration is done in
+.Xr radius.conf 5 .
+.Ar pam
+means to use PAM.
+It works only if
+.Xr racoon 8
+was built with libpam support.
+.It Ic conf_source (local \(ba radius) ;
+Specify the source for IP addresses and netmask allocated through ISAKMP
+mode config.
+.Ar local
+means to use the local IP pool defined by the
+.Ic network4
+and
+.Ic pool_size
+keywords.
+This is the default.
+.Ar radius
+means to use a RADIUS server.
+It works only if
+.Xr racoon 8
+was built with libradius support, and the configuration is done in
+.Xr radius.conf 5 .
+RADIUS configuration requires RADIUS authentication.
+.It Ic accounting (none \(ba radius \(ba pam) ;
+Enable or disable accounting for Xauth logins and logouts.
+Default is
+.Ar none ,
+which disable accounting.
+.Ar radius
+enable RADIUS accounting.
+It works only if
+.Xr racoon 8
+was built with libradius support, and the configuration is done in
+.Xr radius.conf 5 .
+RADIUS accounting require RADIUS authentication.
+.Ar pam
+enable PAM accounting.
+It works only if
+.Xr racoon 8
+was built with libpam support.
+PAM accounting requires PAM authentication.
+.It Ic pool_size Ar size
+Specify the size of the IP address pool, either local or allocated
+through RADIUS.
+.Ic conf_source
+selects the local pool or the RADIUS configuration, but in both
+configurations, you cannot have more than
+.Ar size
+users connected at the same time.
+The default is 255.
+.It Ic network4 Ar address ;
+.It Ic netmask4 Ar address ;
+The local IP pool base address and network mask from which dynamically
+allocated IPv4 addresses should be taken.
+This is used if
+.Ic conf_source
+is set to
+.Ar local
+or if the RADIUS server returned
+.Ar 255.255.255.254 .
+Default is
+.Ar 0.0.0.0/0.0.0.0 .
+.It Ic dns4 Ar address ;
+The IPv4 address for a DNS server.
+.It Ic nbns4 Ar address ;
+The IPv4 address for a WINS server.
+.It Ic banner Ar path ;
+The path of a file displayed on the client at connection time.
+Default is
+.Ar /etc/motd .
+.It Ic auth_throttle Ar delay ;
+On each failed Xauth authentication attempt, refuse new attempts for
+.Ar delay
+more seconds.
+This is to avoid dictionary attacks on Xauth passwords.
+Default is one second.
+Set to zero to disable authentication delay.
+.It Ic pfs_group Ar group ;
+Sets the PFS group used in the client proposal (Cisco VPN client only).
+Default is 0.
+.It Ic save_passwd (on | off) ;
+Allow the client to save the Xauth password (Cisco VPN client only).
+Default is off.
+.El
+.El
+.Ss Special directives
+.Bl -tag -width Ds -compact
+.It Ic complex_bundle (on \(ba off) ;
+defines the interpretation of proposal in the case of SA bundle.
+Normally
+.Dq IP AH ESP IP payload
+is proposed as
+.Dq AH tunnel and ESP tunnel .
+The interpretation is more common to other IKE implementations, however,
+it allows very limited set of combinations for proposals.
+With the option enabled, it will be proposed as
+.Dq AH transport and ESP tunnel .
+The default value is
+.Ic off .
+.El
+.\"
+.Ss Pre-shared key File
+The pre-shared key file defines pairs of identifiers and corresponding
+shared secret keys which are used in the pre-shared key authentication
+method in phase 1.
+The pair in each line is separated by some number of blanks and/or tab
+characters like in the
+.Xr hosts 5
+file.
+Key can include blanks because everything after the first blanks
+is interpreted as the secret key.
+Lines starting with
+.Ql #
+are ignored.
+Keys which start with
+.Ql 0x
+are interpreted as hexadecimal strings.
+Note that the file must be owned by the user ID running
+.Xr racoon 8
+.Pq usually the privileged user ,
+and must not be accessible by others.
+.\"
+.Sh EXAMPLES
+The following shows how the remote directive should be configured.
+.Bd -literal -offset
+path pre_shared_key "/usr/local/v6/etc/psk.txt" ;
+remote anonymous
+{
+       exchange_mode aggressive,main,base;
+       lifetime time 24 hour;
+       proposal {
+               encryption_algorithm 3des;
+               hash_algorithm sha1;
+               authentication_method pre_shared_key;
+               dh_group 2;
+       }
+}
+
+sainfo anonymous
+{
+       pfs_group 2;
+       lifetime time 12 hour ;
+       encryption_algorithm 3des, blowfish 448, twofish, rijndael ;
+       authentication_algorithm hmac_sha1, hmac_md5 ;
+       compression_algorithm deflate ;
+}
+.Ed
+.Pp
+The following is a sample for the pre-shared key file.
+.Bd -literal -offset
+10.160.94.3     mekmitasdigoat
+172.16.1.133    0x12345678
+194.100.55.1    whatcertificatereally
+3ffe:501:410:ffff:200:86ff:fe05:80fa    mekmitasdigoat
+3ffe:501:410:ffff:210:4bff:fea2:8baa    mekmitasdigoat
+foo@kame.net    mekmitasdigoat
+foo.kame.net    hoge
+.Ed
+.\"
+.Sh SEE ALSO
+.Xr racoon 8 ,
+.Xr racoonctl 8 ,
+.Xr setkey 8
+.\"
+.Sh HISTORY
+The
+.Nm
+configuration file first appeared in the
+.Dq YIPS
+Yokogawa IPsec implementation.
+.\"
+.Sh BUGS
+Some statements may not be handled by
+.Xr racoon 8
+yet.
+.Pp
+Diffie-Hellman computation can take a very long time, and may cause
+unwanted timeouts, specifically when a large D-H group is used.
+.\"
+.Sh SECURITY CONSIDERATIONS
+The use of IKE phase 1 aggressive mode is not recommended,
+as described in
+.Li http://www.kb.cert.org/vuls/id/886601 .
diff --git a/ipsec-tools/racoon/racoonctl.8 b/ipsec-tools/racoon/racoonctl.8
new file mode 100644 (file)
index 0000000..cf292a5
--- /dev/null
@@ -0,0 +1,190 @@
+.\" $Id: racoonctl.8,v 1.2.4.2 2005/04/18 11:10:55 manubsd Exp $
+.\"
+.\" Copyright (C) 2004 Emmanuel Dreyfus
+.\" 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.
+.\"
+.Dd November 16, 2004
+.Dt RACOONCTL 8
+.Os
+.\"
+.Sh NAME
+.Nm racoonctl
+.Nd racoon administrative control tool
+.\"
+.Sh SYNOPSIS
+.Nm
+reload-config
+.Nm
+show-schedule
+.Nm
+.Op Fl l Op Fl l
+show-sa
+.Op isakmp|esp|ah|ipsec
+.Nm
+flush-sa
+.Op isakmp|esp|ah|ipsec
+.Nm
+delete-sa
+.Ar saopts
+.Nm
+establish-sa
+.Op Fl u Ar identity
+.Ar saopts
+.Nm
+vpn-connect
+.Op Fl u identity
+.Ar vpn_gateway
+.Nm
+vpn-disconnect
+.Ar vpn_gateway
+.Nm
+show-event
+.Op Fl l
+.\"
+.Sh DESCRIPTION
+.Nm
+is used to control
+.Xr racoon 8
+operation, if ipsec-tools was configured with adminport support.
+Communication between
+.Nm
+and
+.Xr racoon 8
+is done through a UNIX socket.
+By changing the default mode and ownership
+of the socket, you can allow non-root users to alter
+.Xr racoon 8
+behavior, so do that with caution.
+.Pp
+The following commands are available:
+.Bl -tag -width Ds
+.It reload-config
+This should cause
+.Xr racoon 8
+to reload its configuration file.
+This seems completely broken at the time this man page is written.
+.It show-schedule
+Unknown command.
+.It show-sa Op isakmp|esp|ah|ipsec
+Dump the SA: All the SAs if no SA class is provided, or either ISAKMP SAs,
+IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs.
+Use
+.Fl l
+to increase verbosity.
+.It flush-sa Op isakmp|esp|ah|ipsec
+is used to flush all SAs if no SA class is provided, or a class of SAs,
+either ISAKMP SAs, IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs.
+.It Xo establish-sa
+.Oo Fl u Ar username
+.Oc Ar saopts
+.Xc
+Establish an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA.
+The optional
+.Fl u Ar username
+can be used when establishing an ISAKMP SA while hybrid auth is in use.
+.Nm
+will prompt you for the password associated with
+.Ar username
+and these credentials will be used in the Xauth exchange.
+.Pp
+.Ar saopts
+has the following format:
+.Bl -tag -width Bl
+.It isakmp {inet|inet6} Ar src Ar dst
+.It {esp|ah} {inet|inet6} Ar src/prefixlen/port Ar dst/prefixlen/port
+{icmp|tcp|udp|any}
+.El
+.It Xo vpn-connect
+.Oo Fl u Ar username
+.Oc Ar vpn_gateway
+.Xc
+This is a particular case of the previous command.
+It will establish an ISAKMP SA with
+.Ar vpn_gateway .
+.It delete-sa Ar saopts
+Delete an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA.
+.It vpn-disconnect Ar vpn_gateway
+This is a particular case of the previous command.
+It will kill all SAs associated with
+.Ar vpn_gateway .
+.It show-event Op Fl l
+Dump all events reported by
+.Xr racoon 8 ,
+then quit.
+The
+.Fl l
+flag causes
+.Nm
+to not stop once all the events have been read, but rather to loop
+awaiting and reporting new events.
+.El
+.Pp
+Command shortcuts are available:
+.Bl -tag -width XXX -compact -offset indent
+.It rc
+reload-config
+.It ss
+show-sa
+.It sc
+show-schedule
+.It fs
+flush-sa
+.It ds
+delete-sa
+.It es
+establish-sa
+.It vc
+vpn-connect
+.It vd
+vpn-disconnect
+.It se
+show-event
+.El
+.\"
+.Sh RETURN VALUES
+The command should exit with 0 on success, and non-zero on errors.
+.\"
+.Sh FILES
+.Bl -tag -width 30n -compact
+.It Pa /var/racoon/racoon.sock No or
+.It Pa /var/run/racoon.sock
+.Xr racoon 8
+control socket.
+.El
+.\"
+.Sh SEE ALSO
+.Xr ipsec 4 ,
+.Xr racoon 8
+.Sh HISTORY
+Once was
+.Ic kmpstat
+in the KAME project.
+It turned into
+.Nm
+but remained undocumented for a while.
+.An Emmanuel Dreyfus Aq manu@NetBSD.org
+wrote this man page.
diff --git a/ipsec-tools/racoon/racoonctl.c b/ipsec-tools/racoon/racoonctl.c
new file mode 100644 (file)
index 0000000..e59b1f9
--- /dev/null
@@ -0,0 +1,1585 @@
+/*     $Id: racoonctl.c,v 1.2.2.1 2005/04/21 09:07:20 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <err.h>
+#include <sys/ioctl.h> 
+
+#include "var.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "gcmalloc.h"
+
+#include "racoonctl.h"
+#include "admin.h"
+#include "schedule.h"
+#include "handler.h"
+#include "sockmisc.h"
+#include "vmbuf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#include "isakmp_unity.h"
+#include "ipsec_doi.h"
+#include "evt.h"
+
+char *adminsock_path = ADMINSOCK_PATH;
+
+static void usage __P((void));
+static vchar_t *get_combuf __P((int, char **));
+static int handle_recv __P((vchar_t *));
+static vchar_t *f_reload __P((int, char **));
+static vchar_t *f_getsched __P((int, char **));
+static vchar_t *f_getsa __P((int, char **));
+static vchar_t *f_flushsa __P((int, char **));
+static vchar_t *f_deletesa __P((int, char **));
+static vchar_t *f_exchangesa __P((int, char **));
+static vchar_t *f_vpnc __P((int, char **));
+static vchar_t *f_vpnd __P((int, char **));
+static vchar_t *f_getevt __P((int, char **));
+
+struct cmd_tag {
+       vchar_t *(*func) __P((int, char **));
+       int cmd;
+       char *str;
+} cmdtab[] = {
+       { f_reload,     ADMIN_RELOAD_CONF,      "reload-config" },
+       { f_reload,     ADMIN_RELOAD_CONF,      "rc" },
+       { f_getsched,   ADMIN_SHOW_SCHED,       "show-schedule" },
+       { f_getsched,   ADMIN_SHOW_SCHED,       "sc" },
+       { f_getsa,      ADMIN_SHOW_SA,          "show-sa" },
+       { f_getsa,      ADMIN_SHOW_SA,          "ss" },
+       { f_flushsa,    ADMIN_FLUSH_SA,         "flush-sa" },
+       { f_flushsa,    ADMIN_FLUSH_SA,         "fs" },
+       { f_deletesa,   ADMIN_DELETE_SA,        "delete-sa" },
+       { f_deletesa,   ADMIN_DELETE_SA,        "ds" },
+       { f_exchangesa, ADMIN_ESTABLISH_SA,     "establish-sa" },
+       { f_exchangesa, ADMIN_ESTABLISH_SA,     "es" },
+       { f_vpnc,       ADMIN_ESTABLISH_SA,     "vpn-connect" },
+       { f_vpnc,       ADMIN_ESTABLISH_SA,     "vc" },
+       { f_vpnd,       ADMIN_DELETE_ALL_SA_DST,"vpn-disconnect" },
+       { f_vpnd,       ADMIN_DELETE_ALL_SA_DST,"vd" },
+       { f_getevt,     ADMIN_SHOW_EVT,         "show-event" },
+       { f_getevt,     ADMIN_SHOW_EVT,         "se" },
+       { NULL, 0, NULL },
+};
+
+struct evtmsg {
+       int type;
+       char *msg;
+       enum { UNSPEC, ERROR, INFO } level;
+} evtmsg[] = {
+       { EVTT_PHASE1_UP, "Phase 1 established", INFO },
+       { EVTT_PHASE1_DOWN, "Phase 1 deleted", INFO },
+       { EVTT_XAUTH_SUCCESS, "Xauth exchange passed", INFO },
+       { EVTT_ISAKMP_CFG_DONE, "ISAKMP mode config done", INFO },
+       { EVTT_PHASE2_UP, "Phase 2 established", INFO },
+       { EVTT_PHASE2_DOWN, "Phase 2 deleted", INFO },
+       { EVTT_DPD_TIMEOUT, "Peer not reachable anymore", ERROR },
+       { EVTT_PEER_NO_RESPONSE, "Peer not responding", ERROR },
+       { EVTT_PEER_DELETE, "Peer terminated security association", ERROR },
+       { EVTT_RACOON_QUIT, "Raccon terminated", ERROR },
+       { EVTT_OVERFLOW, "Event queue overflow", ERROR },
+       { EVTT_XAUTH_FAILED, "Xauth exchange failed", ERROR },
+       { EVTT_PEERPH1AUTH_FAILED, "Peer failed phase 1 authentication "
+           "(certificate problem?)", ERROR },
+       { 0, NULL, UNSPEC },
+};
+
+static int get_proto __P((char *));
+static vchar_t *get_index __P((int, char **));
+static int get_family __P((char *));
+static vchar_t *get_comindexes __P((int, int, char **));
+static int get_comindex __P((char *, char **, char **, char **));
+static int get_ulproto __P((char *));
+
+struct proto_tag {
+       int proto;
+       char *str;
+} prototab[] = {
+       { ADMIN_PROTO_ISAKMP,   "isakmp" },
+       { ADMIN_PROTO_IPSEC,    "ipsec" },
+       { ADMIN_PROTO_AH,       "ah" },
+       { ADMIN_PROTO_ESP,      "esp" },
+       { ADMIN_PROTO_INTERNAL, "internal" },
+       { 0, NULL },
+};
+
+struct ulproto_tag {
+       int ul_proto;
+       char *str;
+} ulprototab[] = {
+       { 0,            "any" },
+       { IPPROTO_ICMP, "icmp" },
+       { IPPROTO_TCP,  "tcp" },
+       { IPPROTO_UDP,  "udp" },
+       { 0, NULL },
+};
+
+int so;
+
+static char _addr1_[NI_MAXHOST], _addr2_[NI_MAXHOST];
+
+char *pname;
+int long_format = 0;
+
+#define EVTF_NONE              0x0000  /* Ignore any events */
+#define EVTF_LOOP              0x0001  /* Loop awaiting for new events */
+#define EVTF_CFG_STOP          0x0002  /* Stop after ISAKMP mode config */
+#define EVTF_CFG               0x0004  /* Print ISAKMP mode config info */
+#define EVTF_ALL               0x0008  /* Print any events */
+#define EVTF_PURGE             0x0010  /* Print all available events */
+#define EVTF_PH1DOWN_STOP      0x0020  /* Stop when phase 1 SA gets down */
+#define EVTF_PH1DOWN           0x0040  /* Print that phase 1 SA got down */
+#define EVTF_ERR               0x0080  /* Print any error */
+#define EVTF_ERR_STOP          0x0100  /* Stop on any error */
+
+int evt_filter = EVTF_NONE;
+time_t evt_start;
+
+void dump_isakmp_sa __P((char *, int));
+void dump_internal __P((char *, int));
+char *pindex_isakmp __P((isakmp_index *));
+void print_schedule __P((caddr_t, int));
+void print_evt __P((caddr_t, int));
+void print_cfg __P((caddr_t, int));
+void print_err __P((caddr_t, int));
+void print_ph1down __P((caddr_t, int));
+int evt_poll __P((void));
+char * fixed_addr __P((char *, char *, int));
+
+static void
+usage()
+{
+       printf(
+"Usage:\n"
+"  %s reload-config\n"
+"  %s [-l [-l]] show-sa [protocol]\n"
+"  %s flush-sa [protocol]\n"
+"  %s delete-sa <saopts>\n"
+"  %s establish-sa [-u identity] <saopts>\n"
+"  %s vpn-connect [-u identity] vpn_gateway\n"
+"  %s vpn-disconnect vpn_gateway\n"
+"\n"
+"    <protocol>: \"isakmp\", \"esp\" or \"ah\".\n"
+"        In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n"
+"\n"
+"    <saopts>: \"isakmp\" <family> <src> <dst>\n"
+"            : {\"esp\",\"ah\"} <family> <src/prefixlen/port> <dst/prefixlen/port>\n"
+"                              <ul_proto>\n"
+"    <family>: \"inet\" or \"inet6\"\n"
+"    <ul_proto>: \"icmp\", \"tcp\", \"udp\" or \"any\"\n",
+       pname, pname, pname, pname, pname, pname, pname);
+}
+
+/*
+ * Check for proper racoonctl interface
+ */
+#if ((RACOONCTL_INTERFACE_MAJOR != 1) || (RACOONCTL_INTERFACE < 20041230))
+#error "Incompatible racoonctl interface"
+#endif
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *combuf;
+       int c;
+
+       pname = *av;
+
+       /*
+        * Check for proper racoonctl interface
+        */
+       if ((racoonctl_interface_major != RACOONCTL_INTERFACE_MAJOR) ||
+           (racoonctl_interface < RACOONCTL_INTERFACE))
+               errx(1, "Incompatible racoonctl interface");
+
+#ifdef __linux__
+       /*
+        * Disable GNU extensions that will prevent racoonct vc -u login
+        * from working (GNU getopt(3) does not like options after vc)
+        */
+       setenv("POSIXLY_CORRECT", "1", 0);
+#endif
+       while ((c = getopt(ac, av, "lds:")) != -1) {
+               switch(c) {
+               case 'l':
+                       long_format++;
+                       break;
+
+               case 'd':
+                       loglevel++;
+                       break;
+
+               case 's':
+                       adminsock_path = optarg;
+                       break;
+
+               default:
+                       usage();
+                       exit(0);
+               }
+       }
+
+       ac -= optind;
+       av += optind;
+
+       combuf = get_combuf(ac, av);
+       if (!combuf)
+               err(1, "kmpstat");
+
+       if (loglevel)
+               hexdump(combuf, ((struct admin_com *)combuf)->ac_len);
+
+       com_init();
+
+       if (com_send(combuf) != 0)
+               goto bad;
+
+       vfree(combuf);
+
+       if (com_recv(&combuf) != 0)
+               goto bad;
+       if (handle_recv(combuf) != 0)
+               goto bad;
+
+       vfree(combuf);
+
+       if (evt_filter != EVTF_NONE)
+               if (evt_poll() != 0)
+                       goto bad;       
+       
+       exit(0);
+
+    bad:
+       exit(1);
+}
+
+int
+evt_poll(void) {
+       struct timeval tv;
+       vchar_t *recvbuf;
+       vchar_t *sendbuf;
+
+       if ((sendbuf = f_getevt(0, NULL)) == NULL)
+               errx(1, "Cannot make combuf");
+
+       while (evt_filter & (EVTF_LOOP|EVTF_PURGE)) {
+               com_init();
+               if (com_send(sendbuf) != 0)
+                       errx(1, "Cannot send combuf");
+
+               if (com_recv(&recvbuf) == 0) {
+                       handle_recv(recvbuf);
+                       vfree(recvbuf);
+               }
+
+               tv.tv_sec = 0;
+               tv.tv_usec = 10;
+               (void)select(0, NULL, NULL, NULL, &tv);
+       }
+
+       /* NOTREACHED */
+       return 0;
+}
+
+/* %%% */
+/*
+ * return command buffer.
+ */
+static vchar_t *
+get_combuf(ac, av)
+       int ac;
+       char **av;
+{
+       struct cmd_tag *cp;
+
+       if (ac == 0) {
+               usage();
+               exit(0);
+       }
+
+       /* checking the string of command. */
+       for (cp = &cmdtab[0]; cp->str; cp++) {
+               if (strcmp(*av, cp->str) == 0) {
+                       break;
+               }
+       }
+       if (!cp->str) {
+               printf("Invalid command [%s]\n", *av);
+               errno = EINVAL;
+               return NULL;
+       }
+
+       ac--;
+       av++;
+       return (cp->func)(ac, av);
+}
+
+static vchar_t *
+f_reload(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+
+       buf = vmalloc(sizeof(*head));
+       if (buf == NULL)
+               errx(1, "not enough core");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_RELOAD_CONF;
+       head->ac_errno = 0;
+       head->ac_proto = 0;
+
+       return buf;
+}
+
+static vchar_t *
+f_getevt(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+
+       /*
+        * There are 3 ways of getting here
+        * 1) racoonctl vc => evt_filter = (EVTF_LOOP|EVTF_CFG| ... )
+        * 2) racoonctl es => evt_filter = EVTF_NONE
+        * 3) racoonctl es -l => evt_filter = EVTF_LOOP
+        * Catch the second case: show-event is here to purge all
+        */
+       if (evt_filter == EVTF_NONE)
+               evt_filter = (EVTF_ALL|EVTF_PURGE);
+
+       if ((ac >= 1) && (strcmp(av[0], "-l") == 0))
+               evt_filter |= EVTF_LOOP;
+
+       if (ac >= 2)
+               errx(1, "too many arguments");
+
+       buf = vmalloc(sizeof(*head));
+       if (buf == NULL)
+               errx(1, "not enough core");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_SHOW_EVT;
+       head->ac_errno = 0;
+       head->ac_proto = 0;
+
+       return buf;
+}
+
+static vchar_t *
+f_getsched(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+
+       buf = vmalloc(sizeof(*head));
+       if (buf == NULL)
+               errx(1, "not enough core");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_SHOW_SCHED;
+       head->ac_errno = 0;
+       head->ac_proto = 0;
+
+       return buf;
+}
+
+static vchar_t *
+f_getsa(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+       int proto;
+
+       /* need protocol */
+       if (ac != 1)
+               errx(1, "insufficient arguments");
+       proto = get_proto(*av);
+       if (proto == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       buf = vmalloc(sizeof(*head));
+       if (buf == NULL)
+               errx(1, "not enough core");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_SHOW_SA;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       return buf;
+}
+
+static vchar_t *
+f_flushsa(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+       int proto;
+
+       /* need protocol */
+       if (ac != 1)
+               errx(1, "insufficient arguments");
+       proto = get_proto(*av);
+       if (proto == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       buf = vmalloc(sizeof(*head));
+       if (buf == NULL)
+               errx(1, "not enough core");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_FLUSH_SA;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       return buf;
+}
+
+static vchar_t *
+f_deletesa(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf, *index;
+       struct admin_com *head;
+       int proto;
+
+       /* need protocol */
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+       proto = get_proto(*av);
+       if (proto == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       /* get index(es) */
+       av++;
+       ac--;
+       switch (proto) {
+       case ADMIN_PROTO_ISAKMP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       case ADMIN_PROTO_AH:
+       case ADMIN_PROTO_ESP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return NULL;
+       }
+
+       buf = vmalloc(sizeof(*head) + index->l);
+       if (buf == NULL)
+               return NULL;
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l + index->l;
+       head->ac_cmd = ADMIN_DELETE_SA;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       memcpy(buf->v+sizeof(*head), index->v, index->l);
+
+       return buf;
+}
+
+static vchar_t *
+f_deleteallsadst(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf, *index;
+       struct admin_com *head;
+       int proto;
+
+       /* need protocol */
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+       proto = get_proto(*av);
+       if (proto == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       /* get index(es) */
+       av++;
+       ac--;
+       switch (proto) {
+       case ADMIN_PROTO_ISAKMP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       case ADMIN_PROTO_AH:
+       case ADMIN_PROTO_ESP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return NULL;
+       }
+
+       buf = vmalloc(sizeof(*head) + index->l);
+       if (buf == NULL)
+               return NULL;
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l + index->l;
+       head->ac_cmd = ADMIN_DELETE_ALL_SA_DST;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       memcpy(buf->v+sizeof(*head), index->v, index->l);
+
+       return buf;
+}
+
+static vchar_t *
+f_exchangesa(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf, *index;
+       struct admin_com *head;
+       int proto;
+       int cmd = ADMIN_ESTABLISH_SA;
+       size_t com_len = 0;
+       char *id = NULL;
+       char *key = NULL;
+       struct admin_com_psk *acp;
+
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+
+       /* Optional -u identity */
+       if (strcmp(av[0], "-u") == 0) {
+               if (ac < 2)
+                       errx(1, "-u require an argument");
+
+               id = av[1];
+               if ((key = getpass("Password: ")) == NULL)
+                       errx(1, "getpass() failed: %s", strerror(errno));
+               
+               com_len += sizeof(*acp) + strlen(id) + 1 + strlen(key) + 1;
+               cmd = ADMIN_ESTABLISH_SA_PSK;
+
+               av += 2;
+               ac -= 2;
+       }
+
+       /* need protocol */
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+       if ((proto = get_proto(*av)) == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       /* get index(es) */
+       av++;
+       ac--;
+       switch (proto) {
+       case ADMIN_PROTO_ISAKMP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       case ADMIN_PROTO_AH:
+       case ADMIN_PROTO_ESP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return NULL;
+       }
+
+       com_len += sizeof(*head) + index->l;
+       if ((buf = vmalloc(com_len)) == NULL)
+               errx(1, "Cannot allocate buffer");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = cmd;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       memcpy(buf->v+sizeof(*head), index->v, index->l);
+
+       if (id && key) {
+               char *data;
+               acp = (struct admin_com_psk *)
+                   (buf->v + sizeof(*head) + index->l);
+
+               acp->id_type = IDTYPE_LOGIN;
+               acp->id_len = strlen(id) + 1;
+               acp->key_len = strlen(key) + 1;
+
+               data = (char *)(acp + 1);
+               strcpy(data, id);
+
+               data = (char *)(data + acp->id_len);
+               strcpy(data, key);
+       }
+
+       return buf;
+}
+
+static vchar_t *
+f_vpnc(ac, av)
+       int ac;
+       char **av;
+{
+       char *nav[] = {NULL, NULL, NULL, NULL, NULL, NULL};
+       int nac = 0;
+       char *isakmp = "isakmp";
+       char *inet = "inet";
+       char *srcaddr;
+       struct addrinfo hints, *res;
+       struct sockaddr *src;
+       char *idx;
+
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+
+       evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP);
+       time(&evt_start);
+       
+       /* Optional -u identity */
+       if (strcmp(av[0], "-u") == 0) {
+               if (ac < 2)
+                       errx(1, "-u require an argument");
+
+               nav[nac++] = av[0];
+               nav[nac++] = av[1];
+
+               ac -= 2;
+               av += 2;
+       }
+
+       if (ac < 1)
+               errx(1, "VPN gateway required");        
+       if (ac > 1)
+               warnx("Extra arguments");
+
+       /*
+        * Find the source address
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+       if (getaddrinfo(av[0], "4500", &hints, &res) != 0)
+               errx(1, "Cannot resolve destination address");
+
+       if ((src = getlocaladdr(res->ai_addr)) == NULL)
+               errx(1, "cannot find source address");
+
+       if ((srcaddr = saddr2str(src)) == NULL)
+               errx(1, "cannot read source address");
+
+       /* We get "ip[port]" strip the port */
+       if ((idx = index(srcaddr, '[')) == NULL) 
+               errx(1, "unexpected source address format");
+       *idx = '\0';
+
+       nav[nac++] = isakmp;
+       nav[nac++] = inet;
+       nav[nac++] = srcaddr;
+       nav[nac++] = av[0];
+
+       return f_exchangesa(nac, nav);
+}
+
+static vchar_t *
+f_vpnd(ac, av)
+       int ac;
+       char **av;
+{
+       char *nav[] = {NULL, NULL, NULL, NULL};
+       int nac = 0;
+       char *isakmp = "isakmp";
+       char *inet = "inet";
+       char *anyaddr = "0.0.0.0";
+       char *idx;
+       vchar_t *buf, *index;
+
+       if (ac < 1)
+               errx(1, "VPN gateway required");        
+       if (ac > 1)
+               warnx("Extra arguments");
+
+       evt_filter = 
+           (EVTF_PH1DOWN|EVTF_PH1DOWN_STOP|EVTF_LOOP|EVTF_ERR|EVTF_ERR_STOP);
+
+       nav[nac++] = isakmp;
+       nav[nac++] = inet;
+       nav[nac++] = anyaddr;
+       nav[nac++] = av[0];
+
+       return f_deleteallsadst(nac, nav);
+}
+
+
+static int
+get_proto(str)
+       char *str;
+{
+       struct proto_tag *cp;
+
+       if (str == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* checking the string of command. */
+       for (cp = &prototab[0]; cp->str; cp++) {
+               if (strcmp(str, cp->str) == 0)
+                       return cp->proto;
+       }
+
+       errno = EINVAL;
+       return -1;
+}
+
+static vchar_t *
+get_index(ac, av)
+       int ac;
+       char **av;
+{
+       int family;
+
+       if (ac != 3 && ac != 4) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       /* checking the string of family */
+       family = get_family(*av);
+       if (family == -1)
+               return NULL;
+       av++;
+       ac--;
+
+       return get_comindexes(family, ac, av);
+}
+
+static int
+get_family(str)
+       char *str;
+{
+       if (strcmp("inet", str) == 0)
+               return AF_INET;
+#ifdef INET6
+       else if (strcmp("inet6", str) == 0)
+               return AF_INET6;
+#endif
+       errno = EAFNOSUPPORT;
+       return -1;
+}
+
+static vchar_t *
+get_comindexes(family, ac, av)
+       int family;
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com_indexes *ci;
+       char *p_name = NULL, *p_port = NULL;
+       char *p_prefs = NULL, *p_prefd = NULL;
+       struct sockaddr *src = NULL, *dst = NULL;
+       int ulproto;
+
+       if (ac != 2 && ac != 3) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1)
+               goto bad;
+       src = get_sockaddr(family, p_name, p_port);
+       if (p_name) {
+               racoon_free(p_name);
+               p_name = NULL;
+       }
+       if (p_port) {
+               racoon_free(p_port);
+               p_port = NULL;
+       }
+       if (src == NULL)
+               goto bad;
+       av++;
+       ac--;
+       if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1)
+               goto bad;
+       dst = get_sockaddr(family, p_name, p_port);
+       if (p_name) {
+               racoon_free(p_name);
+               p_name = NULL;
+       }
+       if (p_port) {
+               racoon_free(p_port);
+               p_port = NULL;
+       }
+       if (dst == NULL)
+               goto bad;
+
+       buf = vmalloc(sizeof(*ci));
+       if (buf == NULL)
+               goto bad;
+
+       av++;
+       ac--;
+       if(ac){
+               ulproto = get_ulproto(*av);
+               if (ulproto == -1)
+                       goto bad;
+       }else
+               ulproto=0;
+
+       ci = (struct admin_com_indexes *)buf->v;
+       if(p_prefs)
+               ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */
+       else
+               ci->prefs = 32;
+       if(p_prefd)
+               ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */
+       else
+               ci->prefd = 32;
+       ci->ul_proto = ulproto;
+       memcpy(&ci->src, src, sysdep_sa_len(src));
+       memcpy(&ci->dst, dst, sysdep_sa_len(dst));
+
+       if (p_name)
+               racoon_free(p_name);
+
+       return buf;
+
+   bad:
+       if (p_name)
+               racoon_free(p_name);
+       if (p_port)
+               racoon_free(p_port);
+       if (p_prefs)
+               racoon_free(p_prefs);
+       if (p_prefd)
+               racoon_free(p_prefd);
+       return NULL;
+}
+
+static int
+get_comindex(str, name, port, pref)
+       char *str, **name, **port, **pref;
+{
+       char *p;
+
+       *name = *port = *pref = NULL;
+
+       *name = strdup(str);
+       p = strpbrk(*name, "/[");
+       if (p != NULL) {
+               if (*(p + 1) == '\0')
+                       goto bad;
+               if (*p == '/') {
+                       *p = '\0';
+                       *pref = strdup(p + 1);
+                       p = strchr(*pref, '[');
+                       if (p != NULL) {
+                               if (*(p + 1) == '\0')
+                                       goto bad;
+                               *p = '\0';
+                               *port = strdup(p + 1);
+                               p = strchr(*pref, ']');
+                               if (p == NULL)
+                                       goto bad;
+                               *p = '\0';
+                       }
+               } else if (*p == '[') {
+                       *p = '\0';
+                       *port = strdup(p + 1);
+                       p = strchr(*pref, ']');
+                       if (p == NULL)
+                               goto bad;
+                       *p = '\0';
+               } else {
+                       /* XXX */
+               }
+       }
+
+       return 0;
+
+    bad:
+
+       if (*name)
+               racoon_free(*name);
+       if (*port)
+               racoon_free(*port);
+       if (*pref)
+               racoon_free(*pref);
+       *name = *port = *pref = NULL;
+       return -1;
+}
+
+static int
+get_ulproto(str)
+       char *str;
+{
+       struct ulproto_tag *cp;
+
+       if(str == NULL){
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* checking the string of upper layer protocol. */
+       for (cp = &ulprototab[0]; cp->str; cp++) {
+               if (strcmp(str, cp->str) == 0)
+                       return cp->ul_proto;
+       }
+
+       errno = EINVAL;
+       return -1;
+}
+
+/* %%% */
+void
+dump_isakmp_sa(buf, len)
+       char *buf;
+       int len;
+{
+       struct ph1dump *pd;
+       struct tm *tm;
+       char tbuf[56];
+       caddr_t p = NULL;
+
+/* isakmp status header */
+/* short header;
+ 1234567890123456789012 0000000000000000:0000000000000000 000000000000
+*/
+char *header1 = 
+"Destination            Cookies                           Created";
+
+/* semi long header;
+ 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
+*/
+char *header2 = 
+"Destination            Cookies                           ST S  V E Created             Phase2";
+
+/* long header;
+ 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
+*/
+char *header3 =
+"Source                                        Destination                                   Cookies                           ST S  V E Created             Phase2";
+
+/* phase status header */
+/* short format;
+   side stats source address         destination address   
+   xxx  xxxxx 1234567890123456789012 1234567890123456789012
+*/
+
+       static char *estr[] = { "", "B", "M", "U", "A", "I", };
+
+       switch (long_format) {
+       case 0:
+               printf("%s\n", header1);
+               break;
+       case 1:
+               printf("%s\n", header2);
+               break;
+       case 2:
+       default:
+               printf("%s\n", header3);
+               break;
+       }
+
+       if (len % sizeof(*pd))
+               printf("invalid length %d\n", len);
+       len /= sizeof(*pd);
+
+       pd = (struct ph1dump *)buf;
+
+       while (len-- > 0) {
+               /* source address */
+               if (long_format >= 2) {
+                       GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_);
+                       switch (long_format) {
+                       case 0:
+                               break;
+                       case 1:
+                               p = fixed_addr(_addr1_, _addr2_, 22);
+                               break;
+                       case 2:
+                       default:
+                               p = fixed_addr(_addr1_, _addr2_, 45);
+                               break;
+                       }
+                       printf("%s ", p);
+               }
+
+               /* destination address */
+               GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_);
+               switch (long_format) {
+               case 0:
+               case 1:
+                       p = fixed_addr(_addr1_, _addr2_, 22);
+                       break;
+               case 2:
+               default:
+                       p = fixed_addr(_addr1_, _addr2_, 45);
+                       break;
+               }
+               printf("%s ", p);
+
+               printf("%s ", pindex_isakmp(&pd->index));
+
+               /* statuc, side and version */
+               if (long_format >= 1) {
+                       printf("%2d %c %2x ",
+                               pd->status,
+                               pd->side == INITIATOR ? 'I' : 'R',
+                               pd->version);
+                       if (ARRAYLEN(estr) > pd->etype)
+                               printf("%s ", estr[pd->etype]);
+               }
+
+               /* created date */
+               if (pd->created) {
+                       tm = localtime(&pd->created);
+                       strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
+               } else
+                       snprintf(tbuf, sizeof(tbuf), "                   ");
+               printf("%s ", tbuf);
+
+               /* counter of phase 2 */
+               if (long_format >= 1)
+                       printf("%6d ", pd->ph2cnt);
+
+               printf("\n");
+
+               pd++;
+       }
+
+       return;
+}
+
+/* %%% */
+void
+dump_internal(buf, tlen)
+       char *buf;
+       int tlen;
+{
+       struct ph2handle *iph2;
+       struct sockaddr *addr;
+
+/*
+short header;
+ source address         destination address    
+ 1234567890123456789012 1234567890123456789012 
+*/
+char *short_h1 = 
+"Source                 Destination            ";
+
+/*
+long header;
+ source address                                destination address                           
+ 123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345 
+ 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000
+*/
+char *long_h1 = 
+"Source                                        Destination                                  ";
+
+       printf("%s\n", long_format ? long_h1 : short_h1);
+
+       while (tlen > 0) {
+               iph2 = (struct ph2handle *)buf;
+               addr = (struct sockaddr *)(++iph2);
+
+               GETNAMEINFO(addr, _addr1_, _addr2_);
+               printf("%s ", long_format ?
+                         fixed_addr(_addr1_, _addr2_, 45)
+                       : fixed_addr(_addr1_, _addr2_, 22));
+               addr++;
+               tlen -= sysdep_sa_len(addr);
+
+               GETNAMEINFO(addr, _addr1_, _addr2_);
+               printf("%s ", long_format ?
+                         fixed_addr(_addr1_, _addr2_, 45)
+                       : fixed_addr(_addr1_, _addr2_, 22));
+               addr++;
+               tlen -= sysdep_sa_len(addr);
+
+               printf("\n");
+       }
+
+       return;
+}
+
+/* %%% */
+char *
+pindex_isakmp(index)
+       isakmp_index *index;
+{
+       static char buf[64];
+       u_char *p;
+       int i, j;
+
+       memset(buf, 0, sizeof(buf));
+
+       /* copy index */
+       p = (u_char *)index;
+       for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
+               snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
+               j += 2;
+               switch (i) {
+               case 7:
+#if 0
+               case 15:
+#endif
+                       buf[j++] = ':';
+               }
+       }
+
+       return buf;
+}
+
+/* print schedule */
+char *str_sched_stat[] = {
+"off",
+"on",
+"dead",
+};
+
+char *str_sched_id[] = {
+"PH1resend",
+"PH1lifetime",
+"PH2resend",
+"PSTacquire",
+"PSTlifetime",
+};
+
+void
+print_schedule(buf, len)
+       caddr_t buf;
+       int len;
+{
+       struct scheddump *sc = (struct scheddump *)buf;
+       struct tm *tm;
+       char tbuf[56];
+
+       if (len % sizeof(*sc))
+               printf("invalid length %d\n", len);
+       len /= sizeof(*sc);
+
+       /*      00000000 00000000 00000000 xxx........*/
+       printf("index    tick     xtime    created\n");
+
+       while (len-- > 0) {
+               tm = localtime(&sc->created);
+               strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
+
+               printf("%-8ld %-8ld %-8ld %s\n",
+                       sc->id,
+                       (long)sc->tick,
+                       (long)sc->xtime,
+                       tbuf);
+               sc++;
+       }
+
+       return;
+}
+
+
+void
+print_evt(buf, len)
+       caddr_t buf;
+       int len;
+{
+       struct evtdump *evtdump = (struct evtdump *)buf;
+       int i;
+       char *srcstr;
+       char *dststr;
+       
+       for (i = 0; evtmsg[i].msg; i++)
+               if (evtmsg[i].type == evtdump->type)
+                       break;                          
+       
+       if (evtmsg[i].msg == NULL) 
+               printf("Event %d: ", evtdump->type);
+       else
+               printf("%s : ", evtmsg[i].msg);
+
+       if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL)
+               printf("unknown");
+       else 
+               printf("%s", srcstr);
+       printf(" -> ");
+       if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL)
+               printf("unknown");
+       else 
+               printf("%s", dststr);
+       printf("\n");
+
+       return;
+}
+
+void
+print_err(buf, len)
+       caddr_t buf;
+       int len;
+{
+       struct evtdump *evtdump = (struct evtdump *)buf;
+       int i;
+       
+       
+       for (i = 0; evtmsg[i].msg; i++)
+               if (evtmsg[i].type == evtdump->type)
+                       break;                          
+
+       if (evtmsg[i].level != ERROR)
+               return;
+       
+       if (evtmsg[i].msg == NULL) 
+               printf("Error: Event %d\n", evtdump->type);
+       else
+               printf("Error: %s\n", evtmsg[i].msg);
+
+       if (evt_filter & EVTF_ERR_STOP)
+               evt_filter &= ~EVTF_LOOP;
+
+       return;
+}
+
+/*
+ * Print a message when phase 1 SA goes down
+ */
+void
+print_ph1down(buf, len)
+       caddr_t buf;
+       int len;
+{
+       struct evtdump *evtdump = (struct evtdump *)buf;
+       
+       if (evtdump->type != EVTT_PHASE1_DOWN)
+               return;
+
+       printf("VPN connexion terminated\n");
+
+       if (evt_filter & EVTF_PH1DOWN_STOP)
+               evt_filter &= ~EVTF_LOOP;
+       
+       return;
+}
+
+/*
+ * Print ISAKMP mode config info (IP and banner)
+ */
+void
+print_cfg(buf, len)
+       caddr_t buf;
+       int len;
+{
+       struct evtdump *evtdump = (struct evtdump *)buf;
+       struct isakmp_data *attr;
+       char *banner = NULL;
+       struct in_addr addr4;
+       
+       memset(&addr4, 0, sizeof(addr4));
+
+       if (evtdump->type != EVTT_ISAKMP_CFG_DONE)
+               return;
+
+       len -= sizeof(*evtdump);
+       attr = (struct isakmp_data *)(evtdump + 1);
+
+       while (len > 0) {
+               if (len < sizeof(*attr)) {
+                       printf("short attribute too short\n");
+                       break;
+               }
+
+               if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
+                       /* Short attribute, skip */
+                       len -= sizeof(*attr);
+                       attr++;
+               } else { /* Long attribute */
+                       char *n;
+
+                       if (len < (sizeof(*attr) + ntohs(attr->lorv))) {
+                               printf("long attribute too long\n");
+                               break;
+                       }
+
+                       switch (ntohs(attr->type) & ~ISAKMP_GEN_MASK) {
+                       case INTERNAL_IP4_ADDRESS:
+                               if (ntohs(attr->lorv) < sizeof(addr4)) {
+                                       printf("addr4 attribute too short\n");
+                                       break;
+                               }
+                               memcpy(&addr4, attr + 1, sizeof(addr4));
+                               break;
+
+                       case UNITY_BANNER:
+                               banner = racoon_malloc(ntohs(attr->lorv) + 1);
+                               if (banner == NULL) {
+                                       printf("malloc failed\n");
+                                       break;
+                               }
+                               memcpy(banner, attr + 1, ntohs(attr->lorv));
+                               banner[ntohs(attr->lorv)] = '\0';
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       len -= (sizeof(*attr) + ntohs(attr->lorv));
+                       n = (char *)attr;
+                       attr = (struct isakmp_data *)
+                           (n + sizeof(*attr) + ntohs(attr->lorv));
+               }
+       }
+
+       printf("Bound to address %s\n", inet_ntoa(addr4));
+       if (banner) {
+               struct winsize win;
+               int col = 0;
+               int i;
+
+               if (ioctl(1, TIOCGWINSZ, &win) != 1) 
+                       col = win.ws_col;
+                       
+               for (i = 0; i < col; i++)
+                       printf("%c", '=');
+               printf("\n%s\n", banner);
+               for (i = 0; i < col; i++)
+                       printf("%c", '=');
+               printf("\n");
+       }
+       
+       if (evt_filter & EVTF_CFG_STOP)
+               evt_filter &= ~EVTF_LOOP;
+       
+       return;
+}
+       
+
+char *
+fixed_addr(addr, port, len)
+       char *addr, *port;
+       int len;
+{
+       static char _addr_buf_[BUFSIZ];
+       char *p;
+       int plen, i;
+
+       /* initialize */
+       memset(_addr_buf_, ' ', sizeof(_addr_buf_));
+
+       plen = strlen(port);
+       if (len < plen + 1)
+               return NULL;
+
+       p = _addr_buf_;
+       for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/)
+               *p++ = addr[i++];
+       *p++ = '.';
+
+       for (i = 0; i < plen && port[i] != '\0'; /*noting*/)
+               *p++ = port[i++];
+
+       _addr_buf_[len] = '\0';
+
+       return _addr_buf_;
+}
+
+static int
+handle_recv(combuf)
+       vchar_t *combuf;
+{
+        struct admin_com h, *com;
+        caddr_t buf;
+        int len;
+
+       com = (struct admin_com *)combuf->v;
+       len = com->ac_len - sizeof(*com);
+       buf = combuf->v + sizeof(*com);
+
+       switch (com->ac_cmd) {
+       case ADMIN_SHOW_SCHED:
+               print_schedule(buf, len);
+               break;
+
+       case ADMIN_SHOW_EVT: {
+               struct evtdump *evtdump;
+
+               /* We got no event */
+               if (len == 0) {
+                       /* If we were purging the queue, it is now done */
+                       if (evt_filter & EVTF_PURGE)
+                               evt_filter &= ~EVTF_PURGE;
+                       break;
+               }
+
+               if (len < sizeof(struct evtdump))
+                       errx(1, "Short buffer\n");              
+
+               /* Toss outdated events */
+               evtdump = (struct evtdump *)buf;
+               if (evtdump->timestamp < evt_start)
+                       break;
+
+               if (evt_filter & EVTF_ALL)
+                       print_evt(buf, len);
+               if (evt_filter & EVTF_ERR)
+                       print_err(buf, len);
+               if (evt_filter & EVTF_CFG)
+                       print_cfg(buf, len);
+               if (evt_filter & EVTF_PH1DOWN)
+                       print_ph1down(buf, len);
+               break;
+       }
+
+       case ADMIN_SHOW_SA:
+          {
+               switch (com->ac_proto) {
+               case ADMIN_PROTO_ISAKMP:
+                       dump_isakmp_sa(buf, len);
+                       break;
+               case ADMIN_PROTO_IPSEC:
+               case ADMIN_PROTO_AH:
+               case ADMIN_PROTO_ESP:
+                   {
+                       struct sadb_msg *msg = (struct sadb_msg *)buf;
+
+                       switch (msg->sadb_msg_errno) {
+                       case ENOENT:
+                               switch (msg->sadb_msg_type) {
+                               case SADB_DELETE:
+                               case SADB_GET:
+                                       printf("No entry.\n");
+                                       break;
+                               case SADB_DUMP:
+                                       printf("No SAD entries.\n");
+                                       break;
+                               }
+                               break;
+                       case 0:
+                               while (1) {
+                                       pfkey_sadump(msg);
+                                       if (msg->sadb_msg_seq == 0)
+                                               break;
+                                       msg = (struct sadb_msg *)((caddr_t)msg +
+                                                    PFKEY_UNUNIT64(msg->sadb_msg_len));
+                               }
+                               break;
+                       default:
+                               printf("%s.\n", strerror(msg->sadb_msg_errno));
+                       }
+                   }
+                       break;
+               case ADMIN_PROTO_INTERNAL:
+                       dump_internal(buf, len);
+                       break;
+               default:
+                       printf("Invalid proto [%d]\n", com->ac_proto);
+               }
+
+           }
+               break;
+
+       default:
+               /* IGNORE */
+               break;
+       }
+
+       close(so);
+       return 0;
+
+    bad:
+       close(so);
+       return -1;
+}
diff --git a/ipsec-tools/racoon/racoonctl.h b/ipsec-tools/racoon/racoonctl.h
new file mode 100644 (file)
index 0000000..2b8b5a8
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: racoonctl.h,v 1.2 2004/12/30 11:08:32 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RACOONCTL_H
+#define _RACOONCTL_H
+
+/* bumped on any change to the interface */
+#define RACOONCTL_INTERFACE    20041230
+extern u_int32_t racoonctl_interface;
+
+/* bumped when introducing changes that break backward compatibility */
+#define RACOONCTL_INTERFACE_MAJOR      1       
+extern u_int32_t racoonctl_interface_major;
+
+extern u_int32_t loglevel;
+
+int com_init(void);
+int com_send(vchar_t *);
+int com_recv(vchar_t **);
+struct sockaddr *get_sockaddr(int, char *, char *);
+
+#endif /* _RACOONCTL_H */
+
diff --git a/ipsec-tools/racoon/remoteconf.c b/ipsec-tools/racoon/remoteconf.c
new file mode 100644 (file)
index 0000000..0185db6
--- /dev/null
@@ -0,0 +1,776 @@
+/* $Id: remoteconf.c,v 1.26.2.5 2005/11/06 17:18:26 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "genlist.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "remoteconf.h"
+#include "localconf.h"
+#include "grabmyaddr.h"
+#include "proposal.h"
+#include "vendorid.h"
+#include "gcmalloc.h"
+#include "strnames.h"
+#include "algorithm.h"
+#include "nattraversal.h"
+#include "genlist.h"
+#include "rsalist.h"
+
+static TAILQ_HEAD(_rmtree, remoteconf) rmtree;
+
+/* 
+ * Script hook names and script hook paths
+ */
+char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" };
+vchar_t *script_paths = NULL;
+
+/*%%%*/
+/*
+ * search remote configuration.
+ * don't use port number to search if its value is either IPSEC_PORT_ANY.
+ * If matching anonymous entry, then new entry is copied from anonymous entry.
+ * If no anonymous entry found, then return NULL.
+ * OUT:        NULL:   NG
+ *     Other:  remote configuration entry.
+ */
+struct remoteconf *
+getrmconf_strict(remote, allow_anon)
+       struct sockaddr *remote;
+       int allow_anon;
+{
+       struct remoteconf *p;
+       struct remoteconf *anon = NULL;
+       int withport;
+       char buf[NI_MAXHOST + NI_MAXSERV + 10];
+       char addr[NI_MAXHOST], port[NI_MAXSERV];
+
+       withport = 0;
+
+#ifndef ENABLE_NATT
+       /* 
+        * We never have ports set in our remote configurations, but when
+        * NAT-T is enabled, the kernel can have policies with ports and
+        * send us an acquire message for a destination that has a port set.
+        * If we do this port check here, we don't find the remote config.
+        *
+        * In an ideal world, we would be able to have remote conf with
+        * port, and the port could be a wildcard. That test could be used.
+        */
+       switch (remote->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)remote)->sin_port != IPSEC_PORT_ANY)
+                       withport = 1;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               if (((struct sockaddr_in6 *)remote)->sin6_port != IPSEC_PORT_ANY)
+                       withport = 1;
+               break;
+#endif
+       case AF_UNSPEC:
+               break;
+
+       default:
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "invalid ip address family: %d\n", remote->sa_family);
+               exit(1);
+       }
+#endif /* ENABLE_NATT */
+
+       if (remote->sa_family == AF_UNSPEC)
+               snprintf (buf, sizeof(buf), "%s", "anonymous");
+       else {
+               GETNAMEINFO(remote, addr, port);
+               snprintf(buf, sizeof(buf), "%s%s%s%s", addr,
+                       withport ? "[" : "",
+                       withport ? port : "",
+                       withport ? "]" : "");
+       }
+
+       TAILQ_FOREACH(p, &rmtree, chain) {
+               if ((remote->sa_family == AF_UNSPEC
+                    && remote->sa_family == p->remote->sa_family)
+                || (!withport && cmpsaddrwop(remote, p->remote) == 0)
+                || (withport && cmpsaddrstrict(remote, p->remote) == 0)) {
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "configuration found for %s.\n", buf);
+                       return p;
+               }
+
+               /* save the pointer to the anonymous configuration */
+               if (p->remote->sa_family == AF_UNSPEC)
+                       anon = p;
+       }
+
+       if (allow_anon && anon != NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "anonymous configuration selected for %s.\n", buf);
+               return anon;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "no remote configuration found.\n");
+
+       return NULL;
+}
+
+struct remoteconf *
+getrmconf(remote)
+       struct sockaddr *remote;
+{
+       return getrmconf_strict(remote, 1);
+}
+
+struct remoteconf *
+newrmconf()
+{
+       struct remoteconf *new;
+       int i;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       new->proposal = NULL;
+
+       /* set default */
+       new->doitype = IPSEC_DOI;
+       new->sittype = IPSECDOI_SIT_IDENTITY_ONLY;
+       new->idvtype = IDTYPE_UNDEFINED;
+       new->idvl_p = genlist_init();
+       new->nonce_size = DEFAULT_NONCE_SIZE;
+       new->passive = FALSE;
+       new->ike_frag = FALSE;
+       new->esp_frag = IP_MAXPACKET;
+       new->ini_contact = TRUE;
+       new->mode_cfg = FALSE;
+       new->pcheck_level = PROP_CHECK_STRICT;
+       new->verify_identifier = FALSE;
+       new->verify_cert = TRUE;
+       new->getcert_method = ISAKMP_GETCERT_PAYLOAD;
+       new->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
+       new->cacerttype = ISAKMP_CERT_X509SIGN;
+       new->cacertfile = NULL;
+       new->send_cert = TRUE;
+       new->send_cr = TRUE;
+       new->support_proxy = FALSE;
+       for (i = 0; i <= SCRIPT_MAX; i++)
+               new->script[i] = -1;
+       new->gen_policy = FALSE;
+       new->retry_counter = lcconf->retry_counter;
+       new->retry_interval = lcconf->retry_interval;
+#ifdef __APPLE__
+       new->nat_traversal = NATT_ON;
+       new->natt_multiple_user = FALSE;
+#else
+       new->nat_traversal = NATT_OFF;
+#endif
+       new->rsa_private = genlist_init();
+       new->rsa_public = genlist_init();
+       new->idv = NULL;
+       new->key = NULL;
+
+       new->dpd = TRUE; /* Enable DPD support by default */
+       new->dpd_interval = 0; /* Disable DPD checks by default */
+       new->dpd_retry = 5;
+       new->dpd_maxfails = 5;
+
+       return new;
+}
+
+struct remoteconf *
+copyrmconf(remote)
+       struct sockaddr *remote;
+{
+       struct remoteconf *new, *old;
+
+       old = getrmconf_strict (remote, 0);
+       if (old == NULL) {
+               plog (LLV_ERROR, LOCATION, NULL,
+                     "Remote configuration for '%s' not found!\n",
+                     saddr2str (remote));
+               return NULL;
+       }
+
+       new = duprmconf (old);
+
+       return new;
+}
+
+void *
+dupidvl(entry, arg)
+       void *entry;
+       void *arg;
+{
+       struct idspec *id;
+       struct idspec *old = (struct idspec *) entry;
+       id = newidspec();
+       if (!id) return (void *) -1;
+
+       if (set_identifier(&id->id, old->idtype, old->id) != 0) 
+               return (void *) -1;
+
+       id->idtype = old->idtype;
+
+       genlist_append(arg, id);
+       return NULL;
+}
+
+struct remoteconf *
+duprmconf (rmconf)
+       struct remoteconf *rmconf;
+{
+       struct remoteconf *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+       memcpy (new, rmconf, sizeof (*new));
+       // FIXME: We should duplicate the proposal as well.
+       // This is now handled in the cfparse.y
+       // new->proposal = ...;
+       
+       /* duplicate dynamic structures */
+       if (new->etypes)
+               new->etypes=dupetypes(new->etypes);
+       new->idvl_p = genlist_init();
+       genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p);
+
+       return new;
+}
+
+static void
+idspec_free(void *data)
+{
+       vfree (((struct idspec *)data)->id);
+       free (data);
+}
+
+static void
+proposalspec_free(struct proposalspec *head)
+{
+
+       struct proposalspec* next_propsp = head;
+               
+       while (next_propsp) {
+               struct proposalspec* curr_propsp;
+               struct secprotospec* next_protosp;
+               
+               curr_propsp = next_propsp;
+               next_propsp = next_propsp->next;
+               next_protosp = curr_propsp->spspec;
+               while (next_protosp) {
+                       struct secprotospec* curr_protosp;
+                       
+                       curr_protosp = next_protosp;
+                       next_protosp = next_protosp->next;
+                       
+                       if (curr_protosp->gssid)
+                               free(curr_protosp->gssid);
+                       if (curr_protosp->remote)
+                               free(curr_protosp->remote);
+                       racoon_free(curr_protosp);
+               }
+               racoon_free(curr_propsp);
+       }
+}
+
+void
+delrmconf(rmconf)
+       struct remoteconf *rmconf;
+{
+       if (rmconf->remote)
+               racoon_free(rmconf->remote);
+       if (rmconf->etypes)
+               deletypes(rmconf->etypes);
+       if (rmconf->idv)
+               vfree(rmconf->idv);
+       if (rmconf->idvl_p)
+               genlist_free(rmconf->idvl_p, idspec_free);
+       if (rmconf->dhgrp)
+               oakley_dhgrp_free(rmconf->dhgrp);
+       if (rmconf->proposal)
+               delisakmpsa(rmconf->proposal);
+       if (rmconf->mycertfile)
+               racoon_free(rmconf->mycertfile);
+       if (rmconf->myprivfile)
+               racoon_free(rmconf->myprivfile);
+       if (rmconf->peerscertfile)
+               racoon_free(rmconf->peerscertfile);
+       if (rmconf->cacertfile)
+               racoon_free(rmconf->cacertfile);
+       if (rmconf->prhead)
+               proposalspec_free(rmconf->prhead);
+       if (rmconf->rsa_private)
+               genlist_free(rmconf->rsa_private, rsa_key_free);
+       if (rmconf->rsa_public)
+               genlist_free(rmconf->rsa_public, rsa_key_free); 
+#ifdef __APPLE__
+       if (rmconf->shared_secret)
+               vfree(rmconf->shared_secret);
+       if (rmconf->keychainCertRef)
+               vfree(rmconf->keychainCertRef);
+       if (rmconf->open_dir_auth_group)
+               vfree(rmconf->open_dir_auth_group);
+#endif
+
+       racoon_free(rmconf);
+}
+
+void
+delisakmpsa(sa)
+       struct isakmpsa *sa;
+{
+       if (sa->dhgrp)
+               oakley_dhgrp_free(sa->dhgrp);
+       if (sa->next)
+               delisakmpsa(sa->next);
+#ifdef HAVE_GSSAPI
+       if (sa->gssid)
+               vfree(sa->gssid);
+#endif
+       racoon_free(sa);
+}
+
+struct etypes *
+dupetypes(orig)
+       struct etypes *orig;
+{
+       struct etypes *new;
+
+       if (!orig) 
+               return NULL;
+
+       new = racoon_malloc(sizeof(struct etypes));
+       if (new == NULL) 
+               return NULL;
+
+       new->type = orig->type;
+       new->next = NULL;
+
+       if (orig->next)
+               new->next=dupetypes(orig->next);
+
+       return new;
+}
+
+void
+deletypes(e)
+       struct etypes *e;
+{
+       if (e->next)
+               deletypes(e->next);
+       racoon_free(e);
+}
+
+/*
+ * insert into head of list.
+ */
+void
+insrmconf(new)
+       struct remoteconf *new;
+{
+       TAILQ_INSERT_HEAD(&rmtree, new, chain);
+}
+
+void
+remrmconf(rmconf)
+       struct remoteconf *rmconf;
+{
+       TAILQ_REMOVE(&rmtree, rmconf, chain);
+}
+
+void
+flushrmconf()
+{
+       struct remoteconf *p, *next;
+
+       for (p = TAILQ_FIRST(&rmtree); p; p = next) {
+               next = TAILQ_NEXT(p, chain);
+               remrmconf(p);
+               delrmconf(p);
+       }
+}
+
+void
+initrmconf()
+{
+       TAILQ_INIT(&rmtree);
+}
+
+/* check exchange type to be acceptable */
+struct etypes *
+check_etypeok(rmconf, etype)
+       struct remoteconf *rmconf;
+       u_int8_t etype;
+{
+       struct etypes *e;
+
+       for (e = rmconf->etypes; e != NULL; e = e->next) {
+               if (e->type == etype)
+                       break;
+       }
+
+       return e;
+}
+
+/*%%%*/
+struct isakmpsa *
+newisakmpsa()
+{
+       struct isakmpsa *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       /*
+        * Just for sanity, make sure this is initialized.  This is
+        * filled in for real when the ISAKMP proposal is configured.
+        */
+       new->vendorid = VENDORID_UNKNOWN;
+
+       new->next = NULL;
+       new->rmconf = NULL;
+#ifdef HAVE_GSSAPI
+       new->gssid = NULL;
+#endif
+
+       return new;
+}
+
+/*
+ * insert into tail of list.
+ */
+void
+insisakmpsa(new, rmconf)
+       struct isakmpsa *new;
+       struct remoteconf *rmconf;
+{
+       struct isakmpsa *p;
+
+       new->rmconf = rmconf;
+
+       if (rmconf->proposal == NULL) {
+               rmconf->proposal = new;
+               return;
+       }
+
+       for (p = rmconf->proposal; p->next != NULL; p = p->next)
+               ;
+       p->next = new;
+
+       return;
+}
+
+struct remoteconf *
+foreachrmconf(rmconf_func_t rmconf_func, void *data)
+{
+       struct remoteconf *p, *ret = NULL;
+
+       TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
+               ret = (*rmconf_func)(p, data);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static void *
+dump_peers_identifiers (void *entry, void *arg)
+{
+       struct idspec *id = (struct idspec*) entry;
+       char buf[1024], *pbuf;
+       pbuf = buf;
+       pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), "\tpeers_identifier %s",
+                        s_idtype (id->idtype));
+       if (id->id)
+               pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), " \"%s\"", id->id->v);
+       plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
+       return NULL;
+}
+
+static struct remoteconf *
+dump_rmconf_single (struct remoteconf *p, void *data)
+{
+       struct etypes *etype = p->etypes;
+       struct isakmpsa *prop = p->proposal;
+       char buf[1024], *pbuf;
+
+       pbuf = buf;
+       pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "remote %s", saddr2str(p->remote));
+       if (p->inherited_from)
+               pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), " inherit %s",
+                               saddr2str(p->inherited_from->remote));
+       plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf);
+       pbuf = buf;
+       pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "\texchange_type ");
+       while (etype) {
+               pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), "%s%s", s_etype(etype->type),
+                                etype->next != NULL ? ", " : ";\n");
+               etype = etype->next;
+       }
+       plog(LLV_INFO, LOCATION, NULL, "%s", buf);
+       plog(LLV_INFO, LOCATION, NULL, "\tdoi %s;\n", s_doi(p->doitype));
+       pbuf = buf;
+       pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "\tmy_identifier %s", s_idtype (p->idvtype));
+       if (p->idvtype == IDTYPE_ASN1DN) {
+               plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
+               plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n",
+                       p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*",
+                       p->mycertfile, p->myprivfile);
+               switch (p->getcert_method) {
+                 case 0:
+                       break;
+                 case ISAKMP_GETCERT_PAYLOAD:
+                       plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n");
+                       break;
+                 case ISAKMP_GETCERT_LOCALFILE:
+                       plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile);
+                       break;
+                 case ISAKMP_GETCERT_DNS:
+                       plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n");
+                       break;
+                 default:
+                       plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method);
+               }
+       }
+       else {
+               if (p->idv)
+                       pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), " \"%s\"", p->idv->v);
+               plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
+               genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL);
+       }
+
+       plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n",
+               s_switch (p->send_cert));
+       plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n",
+               s_switch (p->send_cr));
+       plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n",
+               s_switch (p->verify_cert));
+       plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n",
+               s_switch (p->verify_identifier));
+       plog(LLV_INFO, LOCATION, NULL, "\tnat_traversal %s;\n",
+               p->nat_traversal == NATT_FORCE ?
+                       "force" : s_switch (p->nat_traversal));
+#ifdef __APPLE__
+       plog(LLV_INFO, LOCATION, NULL, "\tnatt_multiple_user %s;\n",
+               s_switch (p->natt_multiple_user));
+#endif
+       plog(LLV_INFO, LOCATION, NULL, "\tnonce_size %d;\n",
+               p->nonce_size);
+       plog(LLV_INFO, LOCATION, NULL, "\tpassive %s;\n",
+               s_switch (p->passive));
+       plog(LLV_INFO, LOCATION, NULL, "\tike_frag %s;\n",
+               s_switch (p->ike_frag));
+       plog(LLV_INFO, LOCATION, NULL, "\tesp_frag %d;\n", p->esp_frag);
+       plog(LLV_INFO, LOCATION, NULL, "\tinitial_contact %s;\n",
+               s_switch (p->ini_contact));
+       plog(LLV_INFO, LOCATION, NULL, "\tgenerate_policy %s;\n",
+               s_switch (p->gen_policy));
+       plog(LLV_INFO, LOCATION, NULL, "\tsupport_proxy %s;\n",
+               s_switch (p->support_proxy));
+
+       while (prop) {
+               plog(LLV_INFO, LOCATION, NULL, "\n");
+               plog(LLV_INFO, LOCATION, NULL,
+                       "\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n",
+                       prop->prop_no, prop->trns_no,
+                       saddr2str(prop->rmconf->remote));
+               plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n");
+               plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n",
+                       (long)prop->lifetime);
+               plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime bytes %zd;\n",
+                       prop->lifebyte);
+               plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n",
+                       alg_oakley_dhdef_name(prop->dh_group));
+               plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n", 
+                       alg_oakley_encdef_name(prop->enctype));
+               plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n", 
+                       alg_oakley_hashdef_name(prop->hashtype));
+               plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n", 
+                       alg_oakley_authdef_name(prop->authmethod));
+               plog(LLV_INFO, LOCATION, NULL, "\t}\n");
+               prop = prop->next;
+       }
+       plog(LLV_INFO, LOCATION, NULL, "}\n");
+       plog(LLV_INFO, LOCATION, NULL, "\n");
+
+       return NULL;
+}
+
+void
+dumprmconf()
+{
+       foreachrmconf (dump_rmconf_single, NULL);
+}
+
+struct idspec *
+newidspec()
+{
+       struct idspec *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+       new->idtype = IDTYPE_ADDRESS;
+
+       return new;
+}
+
+int
+script_path_add(path)
+       vchar_t *path;
+{
+       char *script_dir;
+       vchar_t *new_storage;
+       vchar_t *new_path;
+       vchar_t **sp;
+       size_t len;
+       size_t size;
+
+       script_dir = lcconf->pathinfo[LC_PATHTYPE_SCRIPT];
+
+       /* Try to find the script in the script directory */
+       if ((path->v[0] != '/') && (script_dir != NULL)) {
+               len = strlen(script_dir) + sizeof("/") + path->l + 1;
+
+               if ((new_path = vmalloc(len)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "Cannot allocate memory: %s\n", strerror(errno));
+                       return -1;
+               }
+
+               new_path->v[0] = '\0';
+               (void)strlcat(new_path->v, script_dir, len);
+               (void)strlcat(new_path->v, "/", len);
+               (void)strlcat(new_path->v, path->v, len);
+
+               vfree(path);
+               path = new_path;
+       }
+
+       /* First time, initialize */
+       if (script_paths == NULL)
+               len = sizeof(vchar_t *);
+       else
+               len = script_paths->l;
+
+       /* Add a slot for a new path */
+       len += sizeof(vchar_t *);
+       if ((new_storage = vrealloc(script_paths, len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Cannot allocate memory: %s\n", strerror(errno));
+               return -1;
+       }
+       script_paths = new_storage;
+
+       size = len / sizeof(vchar_t *);
+       sp = (vchar_t **)script_paths->v;       
+       sp[size - 1] = NULL;
+       sp[size - 2] = path;
+
+       return (size - 2);
+}
+
+struct isakmpsa *
+dupisakmpsa(sa)
+       struct isakmpsa *sa;
+{
+       struct isakmpsa *res = NULL;
+
+       if (sa == NULL)
+               return NULL;
+
+       res = newisakmpsa();
+       if(res == NULL)
+               return NULL;
+
+       *res = *sa;
+#ifdef HAVE_GSSAPI
+       /* 
+        * XXX gssid
+        */
+#endif
+       res->next=NULL;
+
+       if (sa->dhgrp != NULL)
+               oakley_setdhgroup(sa->dh_group, &(res->dhgrp));
+
+       return res;
+
+}
+
+void
+rsa_key_free(void *entry)
+{
+       struct rsa_key *key = (struct rsa_key *)entry;
+       
+       if (key->src)
+               free(key->src);
+       if (key->dst)
+               free(key->dst);
+       if (key->rsa)
+               RSA_free(key->rsa);
+       free(key);
+}
diff --git a/ipsec-tools/racoon/remoteconf.h b/ipsec-tools/racoon/remoteconf.h
new file mode 100644 (file)
index 0000000..0a9d485
--- /dev/null
@@ -0,0 +1,224 @@
+/* $Id: remoteconf.h,v 1.19.2.1 2005/05/20 00:37:42 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _REMOTECONF_H
+#define _REMOTECONF_H
+
+/* remote configuration */
+
+#include <sys/queue.h>
+#include "genlist.h"
+#ifdef __APPLE__
+#include <CoreFoundation/CFData.h>
+#endif
+#include "algorithm.h"
+
+struct proposalspec {
+       time_t lifetime;                /* for isakmp/ipsec */
+       int lifebyte;                   /* for isakmp/ipsec */
+       struct secprotospec *spspec;    /* the head is always current spec. */
+       struct proposalspec *next;      /* the tail is the most prefered. */
+       struct proposalspec *prev;
+};
+
+struct secprotospec {
+       int prop_no;
+       int trns_no;
+       int strength;           /* for isakmp/ipsec */
+       int encklen;            /* for isakmp/ipsec */
+       time_t lifetime;        /* for isakmp */
+       int lifebyte;           /* for isakmp */
+       int proto_id;           /* for ipsec (isakmp?) */
+       int ipsec_level;        /* for ipsec */
+       int encmode;            /* for ipsec */
+       int vendorid;           /* for isakmp */
+       char *gssid;
+       struct sockaddr *remote;
+       int algclass[MAXALGCLASS];
+
+       struct secprotospec *next;      /* the tail is the most prefiered. */
+       struct secprotospec *prev;
+       struct proposalspec *back;
+};
+
+
+struct etypes {
+       int type;
+       struct etypes *next;
+};
+
+/* Script hooks */
+#define SCRIPT_PHASE1_UP       0
+#define SCRIPT_PHASE1_DOWN     1
+#define SCRIPT_MAX             1
+extern char *script_names[SCRIPT_MAX + 1];
+extern vchar_t *script_paths;
+
+struct remoteconf {
+       struct sockaddr *remote;        /* remote IP address */
+                                       /* if family is AF_UNSPEC, that is
+                                        * for anonymous configuration. */
+
+       struct etypes *etypes;          /* exchange type list. the head
+                                        * is a type to be sent first. */
+       int doitype;                    /* doi type */
+       int sittype;                    /* situation type */
+
+       int idvtype;                    /* my identifier type */
+       vchar_t *idv;                   /* my identifier */
+       vchar_t *key;                   /* my pre-shared key */
+       struct genlist *idvl_p;         /* peer's identifiers list */
+
+#ifdef __APPLE__
+       int     identity_in_keychain;   /* cert and private key is in the keychain */
+       vchar_t *keychainCertRef;       /* peristant keychain ref for cert */
+       int secrettype;                 /* type of secret [use, key, keychain] */
+       vchar_t *shared_secret; /* shared secret */
+       vchar_t *open_dir_auth_group;   /* group to be used to authorize user */
+#endif
+
+       int certtype;                   /* certificate type if need */
+       char *mycertfile;               /* file name of my certificate */
+       char *myprivfile;               /* file name of my private key file */
+       char *peerscertfile;            /* file name of peer's certifcate */
+       int getcert_method;             /* the way to get peer's certificate */
+       int cacerttype;                 /* CA type is needed */
+       char *cacertfile;               /* file name of CA */
+       int getcacert_method;           /* the way to get the CA */
+       int send_cert;                  /* send to CERT or not */
+       int send_cr;                    /* send to CR or not */
+       int verify_cert;                /* verify a CERT strictly */
+#ifdef __APPLE__
+       int cert_verification;  /* openssl or security framework */
+       int cert_verification_option;   /* nothing, peers identifier, or open_dir */
+#endif
+       int verify_identifier;          /* vefify the peer's identifier */
+       int nonce_size;                 /* the number of bytes of nonce */
+       int passive;                    /* never initiate */
+       int ike_frag;                   /* IKE fragmentation */
+       int esp_frag;                   /* ESP fragmentation */
+       int mode_cfg;                   /* Gets config through mode config */
+       int support_proxy;              /* support mip6/proxy */
+       int gen_policy;                 /* generate policy if no policy found */
+       int ini_contact;                /* initial contact */
+       int pcheck_level;               /* level of propocl checking */
+       int nat_traversal;              /* NAT-Traversal */
+#ifdef __APPLE__
+       int natt_multiple_user; /* special handling of multiple users behind a nat - for VPN server */
+#endif
+       int script[SCRIPT_MAX + 1];     /* script hooks index in script_paths */
+       int dh_group;                   /* use it when only aggressive mode */
+       struct dhgroup *dhgrp;          /* use it when only aggressive mode */
+                                       /* above two can't be defined by user*/
+
+       int retry_counter;              /* times to retry. */
+       int retry_interval;             /* interval each retry. */
+                               /* above 2 values are copied from localconf. */
+
+       int dpd;                                /* Negociate DPD support ? */
+       int dpd_retry;                  /* in seconds */
+       int dpd_interval;               /* in seconds */
+       int dpd_maxfails; 
+
+       struct isakmpsa *proposal;      /* proposal list */
+       struct remoteconf *inherited_from;      /* the original rmconf 
+                                                  from which this one 
+                                                  was inherited */
+       struct proposalspec *prhead;
+
+       struct genlist  *rsa_private,   /* lists of PlainRSA keys to use */
+                       *rsa_public;
+       TAILQ_ENTRY(remoteconf) chain;  /* next remote conf */
+};
+
+struct dhgroup;
+
+/* ISAKMP SA specification */
+struct isakmpsa {
+       int prop_no;
+       int trns_no;
+       time_t lifetime;
+       size_t lifebyte;
+       int enctype;
+       int encklen;
+       int authmethod;
+       int hashtype;
+       int vendorid;
+#ifdef HAVE_GSSAPI
+       vchar_t *gssid;
+#endif
+       int dh_group;                   /* don't use it if aggressive mode */
+       struct dhgroup *dhgrp;          /* don't use it if aggressive mode */
+
+       struct isakmpsa *next;          /* next transform */
+       struct remoteconf *rmconf;      /* backpointer to remoteconf */
+};
+
+struct idspec {
+       int idtype;                     /* identifier type */
+       vchar_t *id;                    /* identifier */
+};
+
+typedef struct remoteconf * (rmconf_func_t)(struct remoteconf *rmconf, void *data);
+
+extern struct remoteconf *getrmconf __P((struct sockaddr *));
+extern struct remoteconf *getrmconf_strict
+       __P((struct sockaddr *remote, int allow_anon));
+extern struct remoteconf *copyrmconf __P((struct sockaddr *));
+extern struct remoteconf *newrmconf __P((void));
+extern struct remoteconf *duprmconf __P((struct remoteconf *));
+extern void delrmconf __P((struct remoteconf *));
+extern void delisakmpsa __P((struct isakmpsa *));
+extern void deletypes __P((struct etypes *));
+extern struct etypes * dupetypes __P((struct etypes *));
+extern void insrmconf __P((struct remoteconf *));
+extern void remrmconf __P((struct remoteconf *));
+extern void flushrmconf __P((void));
+extern void initrmconf __P((void));
+extern struct etypes *check_etypeok
+       __P((struct remoteconf *, u_int8_t));
+extern struct remoteconf *foreachrmconf __P((rmconf_func_t rmconf_func,
+                                            void *data));
+
+extern struct isakmpsa *newisakmpsa __P((void));
+extern struct isakmpsa *dupisakmpsa __P((struct isakmpsa *));
+
+extern void insisakmpsa __P((struct isakmpsa *, struct remoteconf *));
+
+extern void dumprmconf __P((void));
+
+extern struct idspec *newidspec __P((void));
+
+extern int script_path_add __P((vchar_t *));
+
+extern void rsa_key_free __P((void *entry));
+
+#endif /* _REMOTECONF_H */
diff --git a/ipsec-tools/racoon/rsalist.c b/ipsec-tools/racoon/rsalist.c
new file mode 100644 (file)
index 0000000..3db208d
--- /dev/null
@@ -0,0 +1,214 @@
+/* $Id: rsalist.c,v 1.3 2004/11/08 12:04:23 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+#include "misc.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "rsalist.h"
+#include "genlist.h"
+#include "remoteconf.h"
+#include "crypto_openssl.h"
+
+#ifndef LIST_FIRST
+#define LIST_FIRST(head)        ((head)->lh_first)
+#endif
+
+#ifndef LIST_NEXT
+#define LIST_NEXT(elm, field)   ((elm)->field.le_next)
+#endif
+
+/* from prsa_tok.l */
+int prsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type);
+
+int
+rsa_key_insert(struct genlist *list, struct netaddr *src,
+              struct netaddr *dst, RSA *rsa)
+{
+       struct rsa_key *rsa_key;
+
+       rsa_key = calloc(sizeof(struct rsa_key), 1);
+       rsa_key->rsa = rsa;
+
+       if (src)
+               rsa_key->src = src;
+       else
+               rsa_key->src = calloc(sizeof(*rsa_key->src), 1);
+
+       if (dst)
+               rsa_key->dst = dst;
+       else
+               rsa_key->dst = calloc(sizeof(*rsa_key->dst), 1);
+
+       genlist_append(list, rsa_key);
+
+       return 0;
+}
+
+static void *
+rsa_key_dump_one(void *entry, void *arg)
+{
+       struct rsa_key *key = entry;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "Entry %s\n",
+            naddrwop2str_fromto("%s -> %s", key->src,
+                                key->dst));
+       if (loglevel > LLV_DEBUG)
+               RSA_print_fp(stdout, key->rsa, 4);
+
+       return NULL;
+}
+
+void
+rsa_key_dump(struct genlist *list)
+{
+       genlist_foreach(list, rsa_key_dump_one, NULL);
+}
+
+static void *
+rsa_list_count_one(void *entry, void *arg)
+{
+       if (arg)
+               (*(unsigned long *)arg)++;
+       return NULL;
+}
+
+unsigned long
+rsa_list_count(struct genlist *list)
+{
+       unsigned long count = 0;
+       genlist_foreach(list, rsa_list_count_one, &count);
+       return count;
+}
+
+struct lookup_result {
+       struct ph1handle *iph1;
+       int max_score;
+       struct genlist *winners;
+};
+       
+static void *
+rsa_lookup_key_one(void *entry, void *data)
+{
+       int local_score, remote_score;
+       struct lookup_result *req = data;
+       struct rsa_key *key = entry;
+
+       local_score = naddr_score(key->src, req->iph1->local);
+       remote_score = naddr_score(key->dst, req->iph1->remote);
+
+       plog(LLV_DEBUG, LOCATION, NULL, "Entry %s scored %d/%d\n",
+               naddrwop2str_fromto("%s -> %s", key->src, key->dst),
+               local_score, remote_score);
+
+       if (local_score >= 0 && remote_score >= 0) {
+               if (local_score + remote_score > req->max_score) {
+                       req->max_score = local_score + remote_score;
+//                     genlist_free(req->winners, NULL);
+               }
+
+               if (local_score + remote_score >= req->max_score) {
+                       genlist_append(req->winners, key);
+               }
+       }
+
+       /* Always traverse the whole list */
+       return NULL;
+}
+
+struct genlist *
+rsa_lookup_keys(struct ph1handle *iph1, int my)
+{
+       struct genlist *list;
+       struct lookup_result r;
+
+       plog(LLV_DEBUG, LOCATION, NULL, "Looking up RSA key for %s\n",
+            saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote));
+
+       r.iph1 = iph1;
+       r.max_score = -1;
+       r.winners = genlist_init();
+
+       if (my)
+               list = iph1->rmconf->rsa_private;
+       else
+               list = iph1->rmconf->rsa_public;
+
+       genlist_foreach(list, rsa_lookup_key_one, &r);
+
+       if (loglevel >= LLV_DEBUG)
+               rsa_key_dump(r.winners);
+
+       return r.winners;
+}
+
+int
+rsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type)
+{
+       int ret;
+       
+       plog(LLV_DEBUG, LOCATION, NULL, "Parsing %s\n", fname);
+       ret = prsa_parse_file(list, fname, type);
+       if (loglevel >= LLV_DEBUG)
+               rsa_key_dump(list);
+       return ret;
+}
+
+RSA *
+rsa_try_check_rsasign(vchar_t *source, vchar_t *sig, struct genlist *list)
+{
+       struct rsa_key *key;
+       struct genlist_entry *gp;
+
+       for(key = genlist_next(list, &gp); key; key = genlist_next(NULL, &gp)) {
+               plog(LLV_DEBUG, LOCATION, NULL, "Checking key %s...\n",
+                       naddrwop2str_fromto("%s -> %s", key->src, key->dst));
+               if (eay_check_rsasign(source, sig, key->rsa) == 0) {
+                       plog(LLV_DEBUG, LOCATION, NULL, " ... YEAH!\n");
+                       return key->rsa;
+               }
+               plog(LLV_DEBUG, LOCATION, NULL, " ... nope.\n");
+       }
+       return NULL;
+}
diff --git a/ipsec-tools/racoon/rsalist.h b/ipsec-tools/racoon/rsalist.h
new file mode 100644 (file)
index 0000000..4ee4c4c
--- /dev/null
@@ -0,0 +1,63 @@
+/* $Id: rsalist.h,v 1.2 2004/07/12 20:43:51 ludvigm Exp $ */
+/*
+ * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
+ * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
+ * 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.
+ */
+
+#ifndef _RSALIST_H
+#define _RSALIST_H
+
+#include <netinet/in.h>
+#include <openssl/rsa.h>
+
+#include "handler.h"
+#include "genlist.h"
+
+enum rsa_key_type {
+       RSA_TYPE_ANY = 0,
+       RSA_TYPE_PUBLIC,
+       RSA_TYPE_PRIVATE
+};
+
+struct rsa_key {
+       struct netaddr *src;
+       struct netaddr *dst;
+       RSA *rsa;
+};
+
+int rsa_key_insert(struct genlist *list, struct netaddr *src, struct netaddr *dst, RSA *rsa);
+void rsa_key_dump(struct genlist *list);
+
+struct genlist *rsa_lookup_keys(struct ph1handle *iph1, int my);
+RSA *rsa_try_check_rsasign(vchar_t *source, vchar_t *sig, struct genlist *list);
+
+unsigned long rsa_list_count(struct genlist *list);
+
+int rsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type);
+
+#endif /* _RSALIST_H */
diff --git a/ipsec-tools/racoon/safefile.c b/ipsec-tools/racoon/safefile.c
new file mode 100644 (file)
index 0000000..b698fa7
--- /dev/null
@@ -0,0 +1,91 @@
+/*     $KAME: safefile.c,v 1.5 2001/03/05 19:54:06 thorpej Exp $       */
+
+/*
+ * Copyright (C) 2000 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include "plog.h"
+#include "debug.h"
+#include "misc.h"
+#include "safefile.h"
+
+int
+safefile(path, secret)
+       const char *path;
+       int secret;
+{
+       struct stat s;
+       uid_t me;
+
+       /* no setuid */
+       if (getuid() != geteuid()) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "setuid'ed execution not allowed\n");
+               return -1;
+       }
+
+       if (stat(path, &s) != 0)
+               return -1;
+
+       /* the file must be owned by the running uid */
+       me = getuid();
+       if (s.st_uid != me) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "%s has invalid owner uid\n", path);
+               return -1;
+       }
+
+       switch (s.st_mode & S_IFMT) {
+       case S_IFREG:
+               break;
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "%s is an invalid file type 0x%x\n", path,
+                   (s.st_mode & S_IFMT));
+               return -1;
+       }
+
+       /* secret file should not be read by others */
+       if (secret) {
+               if ((s.st_mode & S_IRWXG) != 0 || (s.st_mode & S_IRWXO) != 0) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "%s has weak file permission\n", path);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
diff --git a/ipsec-tools/racoon/safefile.h b/ipsec-tools/racoon/safefile.h
new file mode 100644 (file)
index 0000000..2651e7e
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id: safefile.h,v 1.4 2004/07/12 18:32:12 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#ifndef _SAFEFILE_H
+#define _SAFEFILE_H
+
+extern int safefile __P((const char *, int));
+
+#endif /* _SAFEFILE_H */
diff --git a/ipsec-tools/racoon/sainfo.c b/ipsec-tools/racoon/sainfo.c
new file mode 100644 (file)
index 0000000..2ad8797
--- /dev/null
@@ -0,0 +1,250 @@
+/*     $KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <netinet/in.h> 
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "handler.h"
+#include "algorithm.h"
+#include "sainfo.h"
+#include "gcmalloc.h"
+
+static LIST_HEAD(_sitree, sainfo) sitree;
+
+/* %%%
+ * modules for ipsec sa info
+ */
+/*
+ * return matching entry.
+ * no matching entry found and if there is anonymous entry, return it.
+ * else return NULL.
+ * XXX by each data type, should be changed to compare the buffer.
+ * First pass is for sainfo from a specified peer, second for others.
+ */
+struct sainfo *
+getsainfo(src, dst, peer)
+       const vchar_t *src, *dst, *peer;
+{
+       struct sainfo *s = NULL;
+       struct sainfo *anonymous = NULL;
+       int pass = 1;
+
+       if (peer == NULL)
+               pass = 2;
+    again:
+       LIST_FOREACH(s, &sitree, chain) {
+               if (s->id_i != NULL) {
+                       if (pass == 2)
+                               continue;
+                       if (memcmp(peer->v, s->id_i->v, s->id_i->l) != 0)
+                               continue;
+               } else if (pass == 1)
+                       continue;
+               if (s->idsrc == NULL) {
+                       anonymous = s;
+                       continue;
+               }
+
+               /* anonymous ? */
+               if (src == NULL) {
+                       if (anonymous != NULL)
+                               break;
+                       continue;
+               }
+
+               if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0
+                && memcmp(dst->v, s->iddst->v, s->iddst->l) == 0)
+                       return s;
+       }
+
+       if (anonymous) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "anonymous sainfo selected.\n");
+       } else if (pass == 1) {
+               pass = 2;
+               goto again;
+       }
+
+       return anonymous;
+}
+
+struct sainfo *
+newsainfo()
+{
+       struct sainfo *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+       new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX;
+
+       return new;
+}
+
+void
+delsainfo(si)
+       struct sainfo *si;
+{
+       int i;
+
+       for (i = 0; i < MAXALGCLASS; i++)
+               delsainfoalg(si->algs[i]);
+
+       if (si->idsrc)
+               vfree(si->idsrc);
+       if (si->iddst)
+               vfree(si->iddst);
+
+       racoon_free(si);
+}
+
+void
+inssainfo(new)
+       struct sainfo *new;
+{
+       LIST_INSERT_HEAD(&sitree, new, chain);
+}
+
+void
+remsainfo(si)
+       struct sainfo *si;
+{
+       LIST_REMOVE(si, chain);
+}
+
+void
+flushsainfo()
+{
+       struct sainfo *s, *next;
+
+       for (s = LIST_FIRST(&sitree); s; s = next) {
+               next = LIST_NEXT(s, chain);
+               remsainfo(s);
+               delsainfo(s);
+       }
+}
+
+void
+initsainfo()
+{
+       LIST_INIT(&sitree);
+}
+
+struct sainfoalg *
+newsainfoalg()
+{
+       struct sainfoalg *new;
+
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       return new;
+}
+
+void
+delsainfoalg(alg)
+       struct sainfoalg *alg;
+{
+       struct sainfoalg *a, *next;
+
+       for (a = alg; a; a = next) {
+               next = a->next;
+               racoon_free(a);
+       }
+}
+
+void
+inssainfoalg(head, new)
+       struct sainfoalg **head;
+       struct sainfoalg *new;
+{
+       struct sainfoalg *a;
+
+       for (a = *head; a && a->next; a = a->next)
+               ;
+       if (a)
+               a->next = new;
+       else
+               *head = new;
+}
+
+const char *
+sainfo2str(si)
+       const struct sainfo *si;
+{
+       static char buf[256];
+
+       if (si->idsrc == NULL)
+               snprintf(buf, sizeof(buf), "anonymous");
+       else {
+               snprintf(buf, sizeof(buf), "%s", ipsecdoi_id2str(si->idsrc));
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                       " %s", ipsecdoi_id2str(si->iddst));
+       }
+
+       if (si->id_i != NULL)
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                       " from %s", ipsecdoi_id2str(si->id_i));
+
+       return buf;
+}
diff --git a/ipsec-tools/racoon/sainfo.h b/ipsec-tools/racoon/sainfo.h
new file mode 100644 (file)
index 0000000..ec2a72f
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id: sainfo.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SAINFO_H
+#define _SAINFO_H
+
+#include <sys/queue.h>
+
+/* SA info */
+struct sainfo {
+       vchar_t *idsrc;
+       vchar_t *iddst;
+               /*
+                * idsrc and iddst are constructed body of ID payload.
+                * that is (struct ipsecdoi_id_b) + ID value.
+                * If idsrc == NULL, that is anonymous entry.
+                */
+
+       time_t lifetime;
+       int lifebyte;
+       int pfs_group;          /* only use when pfs is required. */
+       vchar_t *id_i;          /* identifier of the authorized initiator */
+       struct sainfoalg *algs[MAXALGCLASS];
+
+       LIST_ENTRY(sainfo) chain;
+};
+
+/* algorithm type */
+struct sainfoalg {
+       int alg;
+       int encklen;                    /* key length if encryption algorithm */
+       struct sainfoalg *next;
+};
+
+extern struct sainfo *getsainfo __P((const vchar_t *,
+       const vchar_t *, const vchar_t *));
+extern struct sainfo *newsainfo __P((void));
+extern void delsainfo __P((struct sainfo *));
+extern void inssainfo __P((struct sainfo *));
+extern void remsainfo __P((struct sainfo *));
+extern void flushsainfo __P((void));
+extern void initsainfo __P((void));
+extern struct sainfoalg *newsainfoalg __P((void));
+extern void delsainfoalg __P((struct sainfoalg *));
+extern void inssainfoalg __P((struct sainfoalg **, struct sainfoalg *));
+extern const char * sainfo2str __P((const struct sainfo *));
+
+#endif /* _SAINFO_H */
diff --git a/ipsec-tools/racoon/schedule.c b/ipsec-tools/racoon/schedule.c
new file mode 100644 (file)
index 0000000..705f4ce
--- /dev/null
@@ -0,0 +1,362 @@
+/*     $KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $       */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "misc.h"
+#include "plog.h"
+#include "schedule.h"
+#include "var.h"
+#include "gcmalloc.h"
+
+#define FIXY2038PROBLEM
+
+#ifndef TAILQ_FOREACH
+#define TAILQ_FOREACH(elm, head, field) \
+        for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field))
+#endif
+
+static struct timeval timeout;
+
+#ifdef FIXY2038PROBLEM
+#define Y2038TIME_T    0x7fffffff
+static time_t launched;                /* time when the program launched. */
+static time_t deltaY2038;
+#endif
+
+static TAILQ_HEAD(_schedtree, sched) sctree;
+
+static void sched_add __P((struct sched *));
+static time_t current_time __P((void));
+
+/*
+ * schedule handler
+ * OUT:
+ *     time to block until next event.
+ *     if no entry, NULL returned.
+ */
+struct timeval *
+schedular()
+{
+       time_t now, delta;
+       struct sched *p, *next = NULL;
+
+       now = current_time();
+
+        for (p = TAILQ_FIRST(&sctree); p; p = next) {
+               /* if the entry has been dead, remove it */
+               if (p->dead)
+                       goto next_schedule;
+
+               /* if the time hasn't come, proceed to the next entry */
+               if (now < p->xtime) {
+                       next = TAILQ_NEXT(p, chain);
+                       continue;
+               }
+
+               /* mark it with dead. and call the function. */
+               p->dead = 1;
+               if (p->func != NULL)
+                       (p->func)(p->param);
+
+          next_schedule:
+               next = TAILQ_NEXT(p, chain);
+               TAILQ_REMOVE(&sctree, p, chain);
+               racoon_free(p);
+       }
+
+       p = TAILQ_FIRST(&sctree);
+       if (p == NULL)
+               return NULL;
+
+       now = current_time();
+
+       delta = p->xtime - now;
+       timeout.tv_sec = delta < 0 ? 0 : delta;
+       timeout.tv_usec = 0;
+
+       return &timeout;
+}
+
+/*
+ * add new schedule to schedule table.
+ */
+struct sched *
+sched_new(tick, func, param)
+       time_t tick;
+       void (*func) __P((void *));
+       void *param;
+{
+       static long id = 1;
+       struct sched *new;
+
+       new = (struct sched *)racoon_malloc(sizeof(*new));
+       if (new == NULL)
+               return NULL;
+
+       memset(new, 0, sizeof(*new));
+       new->func = func;
+       new->param = param;
+
+       new->id = id++;
+       time(&new->created);
+       new->tick = tick;
+
+       new->xtime = current_time() + tick;
+       new->dead = 0;
+
+       /* add to schedule table */
+       sched_add(new);
+
+       return(new);
+}
+
+/* add new schedule to schedule table */
+static void
+sched_add(sc)
+       struct sched *sc;
+{
+       struct sched *p;
+
+       TAILQ_FOREACH(p, &sctree, chain) {
+               if (sc->xtime < p->xtime) {
+                       TAILQ_INSERT_BEFORE(p, sc, chain);
+                       return;
+               }
+       }
+       if (p == NULL)
+               TAILQ_INSERT_TAIL(&sctree, sc, chain);
+
+       return;
+}
+
+/* get current time.
+ * if defined FIXY2038PROBLEM, base time is the time when called sched_init().
+ * Otherwise, conform to time(3).
+ */
+static time_t
+current_time()
+{
+       time_t n;
+#ifdef FIXY2038PROBLEM
+       time_t t;
+
+       time(&n);
+       t = n - launched;
+       if (t < 0)
+               t += deltaY2038;
+
+       return t;
+#else
+       return time(&n);
+#endif
+}
+
+void
+sched_kill(sc)
+       struct sched *sc;
+{
+       sc->dead = 1;
+
+       return;
+}
+
+/* XXX this function is probably unnecessary. */
+void
+sched_scrub_param(param)
+       void *param;
+{
+       struct sched *sc;
+
+       TAILQ_FOREACH(sc, &sctree, chain) {
+               if (sc->param == param) {
+                       if (!sc->dead) {
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                   "an undead schedule has been deleted.\n");
+                       }
+                       sched_kill(sc);
+               }
+       }
+}
+
+/*
+ * for debug
+ */
+int
+sched_dump(buf, len)
+       caddr_t *buf;
+       int *len;
+{
+       caddr_t new;
+       struct sched *p;
+       struct scheddump *dst;
+       int cnt = 0;
+
+       /* initialize */
+       *len = 0;
+       *buf = NULL;
+
+       TAILQ_FOREACH(p, &sctree, chain)
+               cnt++;
+
+       /* no entry */
+       if (cnt == 0)
+               return -1;
+
+       *len = cnt * sizeof(*dst);
+
+       new = racoon_malloc(*len);
+       if (new == NULL)
+               return -1;
+       dst = (struct scheddump *)new;
+
+        p = TAILQ_FIRST(&sctree);
+       while (p) {
+               dst->xtime = p->xtime;
+               dst->id = p->id;
+               dst->created = p->created;
+               dst->tick = p->tick;
+
+               p = TAILQ_NEXT(p, chain);
+               if (p == NULL)
+                       break;
+               dst++;
+       }
+
+       *buf = new;
+
+       return 0;
+}
+
+/* initialize schedule table */
+void
+sched_init()
+{
+#ifdef FIXY2038PROBLEM
+       time(&launched);
+
+       deltaY2038 = Y2038TIME_T - launched;
+#endif
+
+       TAILQ_INIT(&sctree);
+
+       return;
+}
+
+#ifdef STEST
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <err.h>
+
+void
+test(tick)
+       int *tick;
+{
+       printf("execute %d\n", *tick);
+       racoon_free(tick);
+}
+
+void
+getstdin()
+{
+       int *tick;
+       char buf[16];
+
+       read(0, buf, sizeof(buf));
+       if (buf[0] == 'd') {
+               struct scheddump *scbuf, *p;
+               int len;
+               sched_dump((caddr_t *)&scbuf, &len);
+               if (buf == NULL)
+                       return;
+               for (p = scbuf; len; p++) {
+                       printf("xtime=%ld\n", p->xtime);
+                       len -= sizeof(*p);
+               }
+               racoon_free(scbuf);
+               return;
+       }
+
+       tick = (int *)racoon_malloc(sizeof(*tick));
+       *tick = atoi(buf);
+       printf("new queue tick = %d\n", *tick);
+       sched_new(*tick, test, tick);
+}
+
+int
+main()
+{
+       static fd_set mask0;
+       int nfds = 0;
+       fd_set rfds;
+       struct timeval *timeout;
+       int error;
+
+       FD_ZERO(&mask0);
+       FD_SET(0, &mask0);
+       nfds = 1;
+
+       /* initialize */
+       sched_init();
+
+       while (1) {
+               rfds = mask0;
+
+               timeout = schedular();
+
+               error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
+               if (error < 0) {
+                       switch (errno) {
+                       case EINTR: continue;
+                       default:
+                               err(1, "select");
+                       }
+                       /*NOTREACHED*/
+               }
+
+               if (FD_ISSET(0, &rfds))
+                       getstdin();
+       }
+}
+#endif
diff --git a/ipsec-tools/racoon/schedule.h b/ipsec-tools/racoon/schedule.h
new file mode 100644 (file)
index 0000000..bb2df2b
--- /dev/null
@@ -0,0 +1,81 @@
+/* $Id: schedule.h,v 1.4 2004/11/18 15:14:44 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SCHEDULE_H
+#define _SCHEDULE_H
+
+#include <sys/queue.h>
+#include <gnuc.h>
+
+/* scheduling table */
+/* the head is the nearest event. */
+struct sched {
+       time_t xtime;           /* event time which is as time(3). */
+                               /*
+                                * if defined FIXY2038PROBLEM, this time
+                                * is from the time when called sched_init().
+                                */
+       void (*func) __P((void *)); /* call this function when timeout. */
+       void *param;            /* pointer to parameter */
+
+       int dead;               /* dead or alive */
+       long id;                /* for debug */
+       time_t created;         /* for debug */
+       time_t tick;            /* for debug */
+
+       TAILQ_ENTRY(sched) chain;
+};
+
+/* cancel schedule */
+#define SCHED_KILL(s)                                                          \
+do {                                                                           \
+       sched_kill(s);                                                         \
+       s = NULL;                                                              \
+} while(0)
+
+/* must be called after it's called from scheduler. */
+#define SCHED_INIT(s)  (s) = NULL
+
+struct scheddump {
+       time_t xtime;
+       long id;
+       time_t created;
+       time_t tick;
+};
+
+struct timeval *schedular __P((void));
+struct sched *sched_new __P((time_t, void (*func) __P((void *)), void *));
+void sched_kill __P((struct sched *));
+int sched_dump __P((caddr_t *, int *));
+void sched_init __P((void));
+void sched_scrub_param __P((void *));
+
+#endif /* _SCHEDULE_H */
diff --git a/ipsec-tools/racoon/session.c b/ipsec-tools/racoon/session.c
new file mode 100644 (file)
index 0000000..1028290
--- /dev/null
@@ -0,0 +1,659 @@
+/*     $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $        */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(s)        ((unsigned)(s) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(s)  (((s) & 255) == 0)
+#endif
+
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <sys/stat.h>
+#include <paths.h>
+
+#include "libpfkey.h"
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "session.h"
+#include "grabmyaddr.h"
+#include "evt.h"
+#include "cfparse_proto.h"
+#include "isakmp_var.h"
+#include "admin_var.h"
+#include "admin.h"
+#include "privsep.h"
+#include "oakley.h"
+#include "pfkey.h"
+#include "handler.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "backupsa.h"
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#include "vpn_control_var.h"
+#include "policy.h"
+
+extern pid_t racoon_pid;
+static void close_session __P((void));
+static void check_rtsock __P((void *));
+static void initfds __P((void));
+static void init_signal __P((void));
+static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int))));
+static void check_sigreq __P((void));
+static void check_flushsa_stub __P((void *));
+static void check_flushsa __P((void));
+static void auto_exit_do __P((void *));
+static int close_sockets __P((void));
+
+static fd_set mask0;
+static fd_set maskdying;
+static int nfds = 0;
+static volatile sig_atomic_t sigreq[NSIG + 1];
+static int dying = 0;
+static struct sched *check_rtsock_sched = NULL;
+
+int
+session(void)
+{
+       fd_set rfds;
+       struct timeval *timeout;
+       int error;
+       struct myaddrs *p;
+       char pid_file[MAXPATHLEN];
+       FILE *fp;
+       int i, update_fds;
+
+       /* initialize schedular */
+       sched_init();
+
+       initmyaddr();
+
+       if (isakmp_init() < 0) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                               "failed to initialize isakmp");
+               exit(1);
+       }
+
+#ifdef ENABLE_ADMINPORT
+       if (admin_init() < 0) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                               "failed to initialize admin port");
+               exit(1);
+       }
+#endif
+#ifdef ENABLE_VPNCONTROL_PORT
+       if (vpncontrol_init() < 0) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "failed to initialize vpn control port");
+               exit(1);
+       }
+#endif
+
+       init_signal();
+       initfds();
+
+#ifndef __APPLE__
+#ifdef ENABLE_NATT
+       natt_keepalive_init ();
+#endif
+#endif
+
+       if (privsep_init() != 0) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "failed to initialize privsep");
+               exit(1);
+       }
+
+       for (i = 0; i <= NSIG; i++)
+               sigreq[i] = 0;
+
+       /* write .pid file */
+       if (!f_foreground) {
+               racoon_pid = getpid();
+               if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 
+                       strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
+               else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 
+                       strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
+               else {
+                       strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
+                       strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
+               } 
+               fp = fopen(pid_file, "w");
+               if (fp) {
+                       if (fchmod(fileno(fp),
+                               S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
+                               syslog(LOG_ERR, "%s", strerror(errno));
+                               fclose(fp);
+                               exit(1);
+                       }
+                       fprintf(fp, "%ld\n", (long)racoon_pid);
+                       fclose(fp);
+               } else {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "cannot open %s", pid_file);
+               }
+       }
+
+       while (1) {
+               update_fds = 0;
+               /*
+                * asynchronous requests via signal.
+                * make sure to reset sigreq to 0.
+                */
+               check_sigreq();
+
+               /* scheduling */
+               timeout = schedular();
+
+               if (dying)
+                       rfds = maskdying;
+               else
+                       rfds = mask0;
+               error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
+               if (error < 0) {
+                       switch (errno) {
+                       case EINTR:
+                               continue;
+                       default:
+                               plog(LLV_ERROR2, LOCATION, NULL,
+                                       "failed select (%s)\n",
+                                       strerror(errno));
+                               exit(1);
+                       }
+                       /*NOTREACHED*/
+               }
+
+#ifdef ENABLE_ADMINPORT
+               if ((lcconf->sock_admin != -1) &&
+                   (FD_ISSET(lcconf->sock_admin, &rfds)))
+                       admin_handler();
+#endif
+#ifdef ENABLE_VPNCONTROL_PORT
+               {
+                       struct vpnctl_socket_elem *elem;
+                       struct vpnctl_socket_elem *t_elem;
+                       
+                       if ((lcconf->sock_vpncontrol != -1) &&
+                               (FD_ISSET(lcconf->sock_vpncontrol, &rfds))) {
+                               vpncontrol_handler();
+                               update_fds = 1;                 //  in case new socket created - update mask
+                       }
+                       /* The handler may close and remove the list element
+                        * so we can't rely on it being valid after calling
+                        * the handler.
+                        */
+                       LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) {
+                               if ((elem->sock != -1) &&
+                                       (FD_ISSET(elem->sock, &rfds)))
+                                       if (vpncontrol_comm_handler(elem))
+                                               update_fds = 1;         // socket closed by peer - update mask
+                       }
+               }
+#endif
+
+               for (p = lcconf->myaddrs; p; p = p->next) {
+                       if (!p->addr)
+                               continue;
+                       if (FD_ISSET(p->sock, &rfds))
+                               if ((error = isakmp_handler(p->sock)) == -2)
+                                       break;
+               }
+               if (error == -2) {
+                       if (lcconf->autograbaddr) {
+                               /* serious socket problem - close all listening sockets and re-open */
+                               isakmp_close(); 
+                               initfds();
+                               sched_new(5, check_rtsock, NULL);
+                               continue;
+                       } else {
+                               isakmp_close_sockets();
+                               isakmp_open();
+                               initfds();
+                               continue;
+                       }
+               }
+
+               if (FD_ISSET(lcconf->sock_pfkey, &rfds))
+                       pfkey_handler();
+
+               if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) {
+                       if (update_myaddrs() && lcconf->autograbaddr)
+                               if (check_rtsock_sched == NULL) /* only schedule if not already done */
+                                       check_rtsock_sched = sched_new(5, check_rtsock, NULL);
+                       // initfds();   //%%% BUG FIX - not needed here
+               }
+               if (update_fds) {
+                       initfds();
+                       update_fds = 0;
+               }
+       }
+}
+
+
+/* clear all status and exit program. */
+static void
+close_session()
+{
+       flushph1();
+       close_sockets();
+       backupsa_clean();
+
+       plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n");
+       exit(0);
+}
+
+static void
+check_rtsock(p)
+       void *p;
+{      
+
+       check_rtsock_sched = NULL;
+       grab_myaddrs();
+       isakmp_close_unused();
+
+       autoconf_myaddrsport();
+       isakmp_open();
+
+       /* initialize socket list again */
+       initfds();
+}
+
+static void
+initfds()
+{
+       struct myaddrs *p;
+
+       nfds = 0;
+
+       FD_ZERO(&mask0);
+       FD_ZERO(&maskdying);
+
+#ifdef ENABLE_ADMINPORT
+       if (lcconf->sock_admin != -1) {
+               if (lcconf->sock_admin >= FD_SETSIZE) {
+                       plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - admin socket\n");
+                       exit(1);
+               }
+               FD_SET(lcconf->sock_admin, &mask0);
+               /* XXX should we listen on admin socket when dying ?
+                */
+#if 0
+               FD_SET(lcconf->sock_admin, &maskdying);
+#endif
+               nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin);
+       }
+#endif
+#ifdef ENABLE_VPNCONTROL_PORT
+       {
+               struct vpnctl_socket_elem *elem;
+               
+               if (lcconf->sock_vpncontrol != -1) {
+                       if (lcconf->sock_vpncontrol >= FD_SETSIZE) {
+                               plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - vpncontrol socket\n");
+                               exit(1);
+                       }
+                       FD_SET(lcconf->sock_vpncontrol, &mask0);
+                       nfds = (nfds > lcconf->sock_vpncontrol ? nfds : lcconf->sock_vpncontrol);
+               }
+               
+               LIST_FOREACH(elem, &lcconf->vpnctl_comm_socks, chain) {
+                       if (elem->sock != -1) {
+                               if (elem->sock >= FD_SETSIZE) {
+                                       plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun vpnctl_comm socket\n");
+                                       exit(1);
+                               }
+                               FD_SET(elem->sock, &mask0);
+                               nfds = (nfds > elem->sock ? nfds : elem->sock);
+                       }
+               }
+       }
+
+#endif
+
+       if (lcconf->sock_pfkey >= FD_SETSIZE) {
+               plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - pfkey socket\n");
+               exit(1);
+       }
+       FD_SET(lcconf->sock_pfkey, &mask0);
+       FD_SET(lcconf->sock_pfkey, &maskdying);
+       nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey);
+       if (lcconf->rtsock >= 0) {
+               if (lcconf->rtsock >= FD_SETSIZE) {
+                       plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - rt socket\n");
+                       exit(1);
+               }
+               FD_SET(lcconf->rtsock, &mask0);
+               nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock);
+       }
+
+       for (p = lcconf->myaddrs; p; p = p->next) {
+               if (!p->addr)
+                       continue;
+               if (p->sock < 0)
+                       continue;
+               if (p->sock >= FD_SETSIZE) {
+                       plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - isakmp socket\n");
+                       exit(1);
+               }
+               FD_SET(p->sock, &mask0);
+               nfds = (nfds > p->sock ? nfds : p->sock);
+       }
+       nfds++;
+}
+
+static int signals[] = {
+       SIGHUP,
+       SIGINT,
+       SIGTERM,
+       SIGUSR1,
+       SIGUSR2,
+       SIGCHLD,
+       SIGPIPE,
+       0
+};
+
+/*
+ * asynchronous requests will actually dispatched in the
+ * main loop in session().
+ */
+RETSIGTYPE
+signal_handler(sig)
+       int sig;
+{
+       /* Do not just set it to 1, because we may miss some signals by just setting
+        * values to 0/1
+        */
+       sigreq[sig]++;
+}
+
+static void
+check_sigreq()
+{
+       int sig;
+
+       /* 
+        * XXX We are not able to tell if we got 
+        * several time the same signal. This is
+        * not a problem for the current code, 
+        * but we shall remember this limitation.
+        */
+       for (sig = 0; sig <= NSIG; sig++) {
+               if (sigreq[sig] == 0)
+                       continue;
+
+               sigreq[sig]--;
+               switch(sig) {
+               case 0:
+                       return;
+                       
+                       /* Catch up childs, mainly scripts.
+                        */
+               case SIGCHLD:
+           {
+                       pid_t pid;
+                       int s;
+                       
+                       pid = wait(&s);
+           }
+               break;
+
+#ifdef DEBUG_RECORD_MALLOCATION
+               /* 
+                * XXX This operation is signal handler unsafe and may lead to 
+                * crashes and security breaches: See Henning Brauer talk at
+                * EuroBSDCon 2005. Do not run in production with this option
+                * enabled.
+                */
+               case SIGUSR2:
+                       DRM_dump();
+                       break;
+#endif
+
+               case SIGHUP:
+                       /* Save old configuration, load new one...  */
+                       isakmp_close();
+                       close(lcconf->rtsock);
+                       if (cfreparse()) {
+                               plog(LLV_ERROR2, LOCATION, NULL,
+                                        "configuration read failed\n");
+                               exit(1);
+                       }
+                       if (lcconf->logfile_param == NULL)
+                               plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
+                               
+                       initmyaddr();
+                       isakmp_cleanup();
+                       isakmp_init();
+                       initfds();
+                       break;
+
+               case SIGINT:
+               case SIGTERM:                   
+                       plog(LLV_INFO, LOCATION, NULL, 
+                           "caught signal %d\n", sig);
+                       EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
+                       pfkey_send_flush(lcconf->sock_pfkey, 
+                           SADB_SATYPE_UNSPEC);
+                       sched_new(1, check_flushsa_stub, NULL);
+                       dying = 1;
+                       break;
+
+               default:
+                       plog(LLV_INFO, LOCATION, NULL, 
+                           "caught signal %d\n", sig);
+                       break;
+               }
+       }
+}
+
+/*
+ * waiting the termination of processing until sending DELETE message
+ * for all inbound SA will complete.
+ */
+static void
+check_flushsa_stub(p)
+       void *p;
+{
+
+       check_flushsa();
+}
+
+static void
+check_flushsa()
+{
+       vchar_t *buf;
+       struct sadb_msg *msg, *end, *next;
+       struct sadb_sa *sa;
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       int n;
+
+       buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
+       if (buf == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                   "pfkey_dump_sadb: returned nothing.\n");
+               return;
+       }
+
+       msg = (struct sadb_msg *)buf->v;
+       end = (struct sadb_msg *)(buf->v + buf->l);
+
+       /* counting SA except of dead one. */
+       n = 0;
+       while (msg < end) {
+               if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
+                       break;
+               next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len));
+               if (msg->sadb_msg_type != SADB_DUMP) {
+                       msg = next;
+                       continue;
+               }
+
+               if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "pfkey_check (%s)\n", ipsec_strerror());
+                       msg = next;
+                       continue;
+               }
+
+               sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
+               if (!sa) {
+                       msg = next;
+                       continue;
+               }
+
+               if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
+                       n++;
+                       msg = next;
+                       continue;
+               }
+
+               msg = next;
+       }
+
+       if (buf != NULL)
+               vfree(buf);
+
+       if (n) {
+               sched_new(1, check_flushsa_stub, NULL);
+               return;
+       }
+
+       close_session();
+}
+
+void
+auto_exit_do(void *p)
+{
+       EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
+       pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
+       sched_new(1, check_flushsa_stub, NULL);
+       dying = 1;
+}
+
+void
+check_auto_exit(void)
+{
+
+       if (lcconf->auto_exit_sched != NULL) {  /* exit scheduled? */
+               if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED
+                       || vpn_control_connected()                              /* vpn control connected */
+                       || policies_installed())                                /* policies installed in kernel */
+                       SCHED_KILL(lcconf->auto_exit_sched);
+       } else {                                                                /* exit not scheduled */
+               if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED
+                       && !vpn_control_connected()             
+                       && !policies_installed())
+                               if (lcconf->auto_exit_delay == 0)
+                                       auto_exit_do(NULL);             /* immediate exit */
+                               else
+                                       lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL);
+       }
+}
+
+
+static void
+init_signal()
+{
+       int i;
+
+       for (i = 0; signals[i] != 0; i++)
+               if (set_signal(signals[i], signal_handler) < 0) {
+                       plog(LLV_ERROR2, LOCATION, NULL,
+                               "failed to set_signal (%s)\n",
+                               strerror(errno));
+                       exit(1);
+               }
+}
+
+static int
+set_signal(sig, func)
+       int sig;
+       RETSIGTYPE (*func) __P((int));
+{
+       struct sigaction sa;
+
+       memset((caddr_t)&sa, 0, sizeof(sa));
+       sa.sa_handler = func;
+       sa.sa_flags = SA_RESTART;
+
+       if (sigemptyset(&sa.sa_mask) < 0)
+               return -1;
+
+       if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
+               return(-1);
+
+       return 0;
+}
+
+static int
+close_sockets()
+{
+       isakmp_close();
+       pfkey_close(lcconf->sock_pfkey);
+#ifdef ENABLE_ADMINPORT
+       (void)admin_close();
+#endif
+#ifdef ENABLE_VPNCONTROL_PORT
+       vpncontrol_close();
+#endif
+       return 0;
+}
+
diff --git a/ipsec-tools/racoon/session.h b/ipsec-tools/racoon/session.h
new file mode 100644 (file)
index 0000000..6625b0b
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: session.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SESSION_H
+#define _SESSION_H
+
+extern int session __P((void));
+extern RETSIGTYPE signal_handler __P((int));
+extern void check_auto_exit __P((void));
+
+#endif /* _SESSION_H */
diff --git a/ipsec-tools/racoon/sockmisc.c b/ipsec-tools/racoon/sockmisc.c
new file mode 100644 (file)
index 0000000..14399cc
--- /dev/null
@@ -0,0 +1,1105 @@
+/* $Id: sockmisc.c,v 1.17.4.4 2005/10/04 09:54:27 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else
+#include <netinet6/ipsec.h>
+#endif
+
+#if defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
+#define IPV6_RECVDSTADDR IP_RECVDSTADDR
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+#include "gcmalloc.h"
+#include "libpfkey.h"
+
+#ifndef IP_IPSEC_POLICY
+#define IP_IPSEC_POLICY 16     /* XXX: from linux/in.h */
+#endif
+
+#ifndef IPV6_IPSEC_POLICY
+#define IPV6_IPSEC_POLICY 34   /* XXX: from linux/???.h per
+                                  "Tom Lendacky" <toml@us.ibm.com> */
+#endif
+
+const int niflags = 0;
+
+/*
+ * compare two sockaddr without port number.
+ * OUT:        0: equal.
+ *     1: not equal.
+ */
+int
+cmpsaddrwop(addr1, addr2)
+       const struct sockaddr *addr1;
+       const struct sockaddr *addr2;
+{
+       caddr_t sa1, sa2;
+
+       if (addr1 == 0 && addr2 == 0)
+               return 0;
+       if (addr1 == 0 || addr2 == 0)
+               return 1;
+
+#ifdef __linux__
+       if (addr1->sa_family != addr2->sa_family)
+               return 1;
+#else
+       if (addr1->sa_len != addr2->sa_len
+        || addr1->sa_family != addr2->sa_family)
+               return 1;
+
+#endif /* __linux__ */
+
+       switch (addr1->sa_family) {
+       case AF_INET:
+               sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
+               if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
+                       return 1;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
+               if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
+                       return 1;
+               if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+                   ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+                       return 1;
+               break;
+#endif
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * compare two sockaddr with port, taking care wildcard.
+ * addr1 is a subject address, addr2 is in a database entry.
+ * OUT:        0: equal.
+ *     1: not equal.
+ */
+int
+cmpsaddrwild(addr1, addr2)
+       const struct sockaddr *addr1;
+       const struct sockaddr *addr2;
+{
+       caddr_t sa1, sa2;
+       u_short port1, port2;
+
+       if (addr1 == 0 && addr2 == 0)
+               return 0;
+       if (addr1 == 0 || addr2 == 0)
+               return 1;
+
+#ifdef __linux__
+       if (addr1->sa_family != addr2->sa_family)
+               return 1;
+#else
+       if (addr1->sa_len != addr2->sa_len
+        || addr1->sa_family != addr2->sa_family)
+               return 1;
+
+#endif /* __linux__ */
+
+       switch (addr1->sa_family) {
+       case AF_INET:
+               sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
+               port1 = ((struct sockaddr_in *)addr1)->sin_port;
+               port2 = ((struct sockaddr_in *)addr2)->sin_port;
+               if (!(port1 == IPSEC_PORT_ANY ||
+                     port2 == IPSEC_PORT_ANY ||
+                     port1 == port2))
+                       return 1;
+               if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
+                       return 1;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
+               port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
+               port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
+               if (!(port1 == IPSEC_PORT_ANY ||
+                     port2 == IPSEC_PORT_ANY ||
+                     port1 == port2))
+                       return 1;
+               if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
+                       return 1;
+               if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+                   ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+                       return 1;
+               break;
+#endif
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * compare two sockaddr with strict match on port.
+ * OUT:        0: equal.
+ *     1: not equal.
+ */
+int
+cmpsaddrstrict(addr1, addr2)
+       const struct sockaddr *addr1;
+       const struct sockaddr *addr2;
+{
+       caddr_t sa1, sa2;
+       u_short port1, port2;
+
+       if (addr1 == 0 && addr2 == 0)
+               return 0;
+       if (addr1 == 0 || addr2 == 0)
+               return 1;
+
+#ifdef __linux__
+       if (addr1->sa_family != addr2->sa_family)
+               return 1;
+#else
+       if (addr1->sa_len != addr2->sa_len
+        || addr1->sa_family != addr2->sa_family)
+               return 1;
+
+#endif /* __linux__ */
+
+       switch (addr1->sa_family) {
+       case AF_INET:
+               sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
+               port1 = ((struct sockaddr_in *)addr1)->sin_port;
+               port2 = ((struct sockaddr_in *)addr2)->sin_port;
+               if (port1 != port2)
+                       return 1;
+               if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
+                       return 1;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
+               sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
+               port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
+               port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
+               if (port1 != port2)
+                       return 1;
+               if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
+                       return 1;
+               if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+                   ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+                       return 1;
+               break;
+#endif
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+/* get local address against the destination. */
+struct sockaddr *
+getlocaladdr(remote)
+       struct sockaddr *remote;
+{
+       struct sockaddr *local;
+       u_int local_len = sizeof(struct sockaddr_storage);
+       int s;  /* for dummy connection */
+
+       /* allocate buffer */
+       if ((local = racoon_calloc(1, local_len)) == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to get address buffer.\n");
+               goto err;
+       }
+       
+       /* get real interface received packet */
+       if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "socket (%s)\n", strerror(errno));
+               goto err;
+       }
+
+       setsockopt_bypass(s, remote->sa_family);
+       
+       if (connect(s, remote, sysdep_sa_len(remote)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "connect (%s)\n", strerror(errno));
+               close(s);
+               goto err;
+       }
+
+       if (getsockname(s, local, &local_len) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getsockname (%s)\n", strerror(errno));
+               close(s);
+               return NULL;
+       }
+
+       close(s);
+       return local;
+
+    err:
+       if (local != NULL)
+               racoon_free(local);
+       return NULL;
+}
+
+/*
+ * Receive packet, with src/dst information.  It is assumed that necessary
+ * setsockopt() have already performed on socket.
+ */
+int
+recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
+       int s;
+       void *buf;
+       size_t buflen;
+       int flags;
+       struct sockaddr *from;
+       socklen_t *fromlen;
+       struct sockaddr *to;
+       u_int *tolen;
+{
+       int otolen;
+       u_int len;
+       struct sockaddr_storage ss;
+       struct msghdr m;
+       struct cmsghdr *cm;
+       struct iovec iov[2];
+       u_char cmsgbuf[256];
+#if defined(INET6) && defined(INET6_ADVAPI)
+       struct in6_pktinfo *pi;
+#endif /*INET6_ADVAPI*/
+       struct sockaddr_in *sin;
+#ifdef INET6
+       struct sockaddr_in6 *sin6;
+#endif
+
+       len = sizeof(ss);
+       if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getsockname (%s)\n", strerror(errno));
+               return -1;
+       }
+
+       m.msg_name = (caddr_t)from;
+       m.msg_namelen = *fromlen;
+       iov[0].iov_base = (caddr_t)buf;
+       iov[0].iov_len = buflen;
+       m.msg_iov = iov;
+       m.msg_iovlen = 1;
+       memset(cmsgbuf, 0, sizeof(cmsgbuf));
+       cm = (struct cmsghdr *)cmsgbuf;
+       m.msg_control = (caddr_t)cm;
+       m.msg_controllen = sizeof(cmsgbuf);
+       if ((len = recvmsg(s, &m, flags)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "recvmsg (%s)\n", strerror(errno));
+               return -1;
+       }
+       *fromlen = m.msg_namelen;
+
+       otolen = *tolen;
+       *tolen = 0;
+       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
+            m.msg_controllen != 0 && cm;
+            cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
+#if 0
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
+#endif
+#if defined(INET6) && defined(INET6_ADVAPI)
+               if (ss.ss_family == AF_INET6
+                && cm->cmsg_level == IPPROTO_IPV6
+                && cm->cmsg_type == IPV6_PKTINFO
+                && otolen >= sizeof(*sin6)) {
+                       pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+                       *tolen = sizeof(*sin6);
+                       sin6 = (struct sockaddr_in6 *)to;
+                       memset(sin6, 0, sizeof(*sin6));
+                       sin6->sin6_family = AF_INET6;
+#ifndef __linux__
+                       sin6->sin6_len = sizeof(*sin6);
+#endif
+                       memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
+                               sizeof(sin6->sin6_addr));
+                       /* XXX other cases, such as site-local? */
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+                               sin6->sin6_scope_id = pi->ipi6_ifindex;
+                       else
+                               sin6->sin6_scope_id = 0;
+                       sin6->sin6_port =
+                               ((struct sockaddr_in6 *)&ss)->sin6_port;
+                       otolen = -1;    /* "to" already set */
+                       continue;
+               }
+#endif
+#ifdef __linux__
+               if (ss.ss_family == AF_INET
+                && cm->cmsg_level == IPPROTO_IP
+                && cm->cmsg_type == IP_PKTINFO
+                && otolen >= sizeof(sin)) {
+                       struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm));
+                       *tolen = sizeof(*sin);
+                       sin = (struct sockaddr_in *)to;
+                       memset(sin, 0, sizeof(*sin));
+                       sin->sin_family = AF_INET;
+                       memcpy(&sin->sin_addr, &pi->ipi_addr,
+                               sizeof(sin->sin_addr));
+                       sin->sin_port =
+                               ((struct sockaddr_in *)&ss)->sin_port;
+                       otolen = -1;    /* "to" already set */
+                       continue;
+               }
+#endif
+#if defined(INET6) && defined(IPV6_RECVDSTADDR)
+               if (ss.ss_family == AF_INET6
+                     && cm->cmsg_level == IPPROTO_IPV6
+                     && cm->cmsg_type == IPV6_RECVDSTADDR
+                     && otolen >= sizeof(*sin6)) {
+                       *tolen = sizeof(*sin6);
+                       sin6 = (struct sockaddr_in6 *)to;
+                       memset(sin6, 0, sizeof(*sin6));
+                       sin6->sin6_family = AF_INET6;
+                       sin6->sin6_len = sizeof(*sin6);
+                       memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
+                               sizeof(sin6->sin6_addr));
+                       sin6->sin6_port =
+                               ((struct sockaddr_in6 *)&ss)->sin6_port;
+                       otolen = -1;    /* "to" already set */
+                       continue;
+               }
+#endif
+#ifndef __linux__
+               if (ss.ss_family == AF_INET
+                && cm->cmsg_level == IPPROTO_IP
+                && cm->cmsg_type == IP_RECVDSTADDR
+                && otolen >= sizeof(*sin)) {
+                       *tolen = sizeof(*sin);
+                       sin = (struct sockaddr_in *)to;
+                       memset(sin, 0, sizeof(*sin));
+                       sin->sin_family = AF_INET;
+                       sin->sin_len = sizeof(*sin);
+                       memcpy(&sin->sin_addr, CMSG_DATA(cm),
+                               sizeof(sin->sin_addr));
+                       sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
+                       otolen = -1;    /* "to" already set */
+                       continue;
+               }
+#endif
+       }
+
+       return len;
+}
+
+/* send packet, with fixing src/dst address pair. */
+int
+sendfromto(s, buf, buflen, src, dst, cnt)
+       int s, cnt;
+       const void *buf;
+       size_t buflen;
+       struct sockaddr *src;
+       struct sockaddr *dst;
+{
+       struct sockaddr_storage ss;
+       u_int len;
+       int i;
+
+       if (src->sa_family != dst->sa_family) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "address family mismatch\n");
+               return -1;
+       }
+
+       len = sizeof(ss);
+       if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getsockname (%s)\n", strerror(errno));
+               return -1;
+       }
+
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "sockname %s\n", saddr2str((struct sockaddr *)&ss));
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "send packet from %s\n", saddr2str(src));
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "send packet to %s\n", saddr2str(dst));
+
+       if (src->sa_family != ss.ss_family) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "address family mismatch\n");
+               return -1;
+       }
+
+       switch (src->sa_family) {
+#if defined(INET6) && defined(INET6_ADVAPI)
+// XXX: This block wasn't compiled on Linux - does it work?
+       case AF_INET6:
+           {
+               struct msghdr m;
+               struct cmsghdr *cm;
+               struct iovec iov[2];
+               u_char cmsgbuf[256];
+               struct in6_pktinfo *pi;
+               int ifindex;
+               struct sockaddr_in6 src6, dst6;
+
+               memcpy(&src6, src, sizeof(src6));
+               memcpy(&dst6, dst, sizeof(dst6));
+
+               /* XXX take care of other cases, such as site-local */
+               ifindex = 0;
+               if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
+                || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
+                       ifindex = src6.sin6_scope_id;   /*???*/
+               }
+
+               /* XXX some sanity check on dst6.sin6_scope_id */
+
+               /* flowinfo for IKE?  mmm, maybe useful but for now make it 0 */
+               src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;
+
+               memset(&m, 0, sizeof(m));
+               m.msg_name = (caddr_t)&dst6;
+               m.msg_namelen = sizeof(dst6);
+               iov[0].iov_base = (char *)buf;
+               iov[0].iov_len = buflen;
+               m.msg_iov = iov;
+               m.msg_iovlen = 1;
+
+               memset(cmsgbuf, 0, sizeof(cmsgbuf));
+               cm = (struct cmsghdr *)cmsgbuf;
+               m.msg_control = (caddr_t)cm;
+               m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+               cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+               cm->cmsg_level = IPPROTO_IPV6;
+               cm->cmsg_type = IPV6_PKTINFO;
+               pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+               memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr));
+               pi->ipi6_ifindex = ifindex;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "src6 %s %d\n",
+                       saddr2str((struct sockaddr *)&src6),
+                       src6.sin6_scope_id);
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "dst6 %s %d\n",
+                       saddr2str((struct sockaddr *)&dst6),
+                       dst6.sin6_scope_id);
+
+               for (i = 0; i < cnt; i++) {
+                       len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
+                       if (len < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "sendmsg (%s)\n", strerror(errno));
+                               return -1;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "%d times of %d bytes message will be sent "
+                               "to %s\n",
+                               i + 1, len, saddr2str(dst));
+               }
+               plogdump(LLV_DEBUG, (char *)buf, buflen);
+
+               return len;
+           }
+#endif
+#ifdef __linux__
+       case AF_INET:
+           {
+               struct msghdr m;
+               struct cmsghdr *cm;
+               struct iovec iov[2];
+               u_char cmsgbuf[256];
+               struct in_pktinfo *pi;
+               int ifindex = 0;
+               struct sockaddr_in src6, dst6;
+
+               memcpy(&src6, src, sizeof(src6));
+               memcpy(&dst6, dst, sizeof(dst6));
+
+               memset(&m, 0, sizeof(m));
+               m.msg_name = (caddr_t)&dst6;
+               m.msg_namelen = sizeof(dst6);
+               iov[0].iov_base = (char *)buf;
+               iov[0].iov_len = buflen;
+               m.msg_iov = iov;
+               m.msg_iovlen = 1;
+
+               memset(cmsgbuf, 0, sizeof(cmsgbuf));
+               cm = (struct cmsghdr *)cmsgbuf;
+               m.msg_control = (caddr_t)cm;
+               m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+               cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+               cm->cmsg_level = IPPROTO_IP;
+               cm->cmsg_type = IP_PKTINFO;
+               pi = (struct in_pktinfo *)CMSG_DATA(cm);
+               memcpy(&pi->ipi_spec_dst, &src6.sin_addr, sizeof(src6.sin_addr));
+               pi->ipi_ifindex = ifindex;
+
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "src4 %s\n",
+                       saddr2str((struct sockaddr *)&src6));
+               plog(LLV_DEBUG, LOCATION, NULL,
+                       "dst4 %s\n",
+                       saddr2str((struct sockaddr *)&dst6));
+
+               for (i = 0; i < cnt; i++) {
+                       len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
+                       if (len < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "sendmsg (%s)\n", strerror(errno));
+                               return -1;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "%d times of %d bytes message will be sent "
+                               "to %s\n",
+                               i + 1, len, saddr2str(dst));
+               }
+               plogdump(LLV_DEBUG, (char *)buf, buflen);
+
+               return len;
+           }
+#endif /* __linux__ */
+       default:
+           {
+               int needclose = 0;
+               int sendsock;
+
+               if (ss.ss_family == src->sa_family && memcmp(&ss, src, sysdep_sa_len(src)) == 0) {
+                       sendsock = s;
+                       needclose = 0;
+               } else {
+                       int yes = 1;
+                       /*
+                        * Use newly opened socket for sending packets.
+                        * NOTE: this is unsafe, because if the peer is quick enough
+                        * the packet from the peer may be queued into sendsock.
+                        * Better approach is to prepare bind'ed udp sockets for
+                        * each of the interface addresses.
+                        */
+                       sendsock = socket(src->sa_family, SOCK_DGRAM, 0);
+                       if (sendsock < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "socket (%s)\n", strerror(errno));
+                               return -1;
+                       }
+                       if (setsockopt(sendsock, SOL_SOCKET,
+#ifdef __linux__
+                                      SO_REUSEADDR,
+#else
+                                      SO_REUSEPORT,
+#endif
+                                      (void *)&yes, sizeof(yes)) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "setsockopt (%s)\n", strerror(errno));
+                               close(sendsock);
+                               return -1;
+                       }
+#ifdef IPV6_USE_MIN_MTU
+                       if (src->sa_family == AF_INET6 &&
+                           setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+                           (void *)&yes, sizeof(yes)) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "setsockopt (%s)\n", strerror(errno));
+                               close(sendsock);
+                               return -1;
+                       }
+#endif
+                       if (setsockopt_bypass(sendsock, src->sa_family) < 0) {
+                               close(sendsock);
+                               return -1;
+                       }
+
+                       if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "bind 1 (%s)\n", strerror(errno));
+                               close(sendsock);
+                               return -1;
+                       }
+                       needclose = 1;
+               }
+
+               for (i = 0; i < cnt; i++) {
+                       len = sendto(sendsock, buf, buflen, 0, dst, sysdep_sa_len(dst));
+                       if (len < 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "sendto (%s)\n", strerror(errno));
+                               if (needclose)
+                                       close(sendsock);
+                               return len;
+                       }
+                       plog(LLV_DEBUG, LOCATION, NULL,
+                               "%d times of %d bytes message will be sent "
+                               "to %s\n",
+                               i + 1, len, saddr2str(dst));
+               }
+               plogdump(LLV_DEBUG, (char *)buf, buflen);
+
+               if (needclose)
+                       close(sendsock);
+
+               return len;
+           }
+       }
+}
+
+int
+setsockopt_bypass(so, family)
+       int so, family;
+{
+       int level;
+       char *buf;
+       char *policy;
+
+       switch (family) {
+       case AF_INET:
+               level = IPPROTO_IP;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               level = IPPROTO_IPV6;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "unsupported address family %d\n", family);
+               return -1;
+       }
+
+       policy = "in bypass";
+       buf = ipsec_set_policy(policy, strlen(policy));
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "ipsec_set_policy (%s)\n",
+                       ipsec_strerror());
+               return -1;
+       }
+       if (setsockopt(so, level,
+                      (level == IPPROTO_IP ?
+                                IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
+                      buf, ipsec_get_policylen(buf)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "setsockopt (%s)\n",
+                       strerror(errno));
+               return -1;
+       }
+       racoon_free(buf);
+
+       policy = "out bypass";
+       buf = ipsec_set_policy(policy, strlen(policy));
+       if (buf == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "ipsec_set_policy (%s)\n",
+                       ipsec_strerror());
+               return -1;
+       }
+       if (setsockopt(so, level,
+                      (level == IPPROTO_IP ?
+                                IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
+                      buf, ipsec_get_policylen(buf)) < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "setsockopt (%s)\n",
+                       strerror(errno));
+               return -1;
+       }
+       racoon_free(buf);
+
+       return 0;
+}
+
+struct sockaddr *
+newsaddr(len)
+       int len;
+{
+       struct sockaddr *new;
+
+       new = racoon_calloc(1, len);
+       if (new == NULL)
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "%s\n", strerror(errno)); 
+
+#ifdef __linux__
+       if (len == sizeof (struct sockaddr_in6))
+               new->sa_family = AF_INET6;
+       else
+               new->sa_family = AF_INET;
+#else
+       /* initial */
+       new->sa_len = len;
+#endif
+
+       return new;
+}
+
+struct sockaddr *
+dupsaddr(src)
+       struct sockaddr *src;
+{
+       struct sockaddr *dst;
+
+       dst = racoon_calloc(1, sysdep_sa_len(src));
+       if (dst == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "%s\n", strerror(errno)); 
+               return NULL;
+       }
+
+       memcpy(dst, src, sysdep_sa_len(src));
+
+       return dst;
+}
+
+char *
+saddr2str(saddr)
+       const struct sockaddr *saddr;
+{
+       static char buf[NI_MAXHOST + NI_MAXSERV + 10];
+       char addr[NI_MAXHOST], port[NI_MAXSERV];
+
+       if (saddr == NULL)
+               return NULL;
+
+       if (saddr->sa_family == AF_UNSPEC)
+               snprintf (buf, sizeof(buf), "%s", "anonymous");
+       else {
+               GETNAMEINFO(saddr, addr, port);
+               snprintf(buf, sizeof(buf), "%s[%s]", addr, port);
+       }
+
+       return buf;
+}
+
+char *
+saddrwop2str(saddr)
+       const struct sockaddr *saddr;
+{
+       static char buf[NI_MAXHOST + NI_MAXSERV + 10];
+       char addr[NI_MAXHOST];
+
+       if (saddr == NULL)
+               return NULL;
+
+       GETNAMEINFO_NULL(saddr, addr);
+       snprintf(buf, sizeof(buf), "%s", addr);
+
+       return buf;
+}
+
+char *
+naddrwop2str(const struct netaddr *naddr)
+{
+       static char buf[NI_MAXHOST + 10];
+       static const struct sockaddr sa_any;    /* this is initialized to all zeros */
+       
+       if (naddr == NULL)
+               return NULL;
+
+       if (memcmp(&naddr->sa, &sa_any, sizeof(sa_any)) == 0)
+               snprintf(buf, sizeof(buf), "%s", "any");
+       else {
+               snprintf(buf, sizeof(buf), "%s", saddrwop2str(&naddr->sa.sa));
+               snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "/%ld", naddr->prefix);
+       }
+       return buf;
+}
+
+char *
+naddrwop2str_fromto(const char *format, const struct netaddr *saddr,
+                   const struct netaddr *daddr)
+{
+       static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
+       char *src, *dst;
+
+       src = strdup(naddrwop2str(saddr));
+       dst = strdup(naddrwop2str(daddr));
+       /* WARNING: Be careful about the format string! Don't 
+          ever pass in something that a user can modify!!! */
+       snprintf (buf, sizeof(buf), format, src, dst);
+       racoon_free (src);
+       racoon_free (dst);
+
+       return buf;
+}
+
+char *
+saddr2str_fromto(format, saddr, daddr)
+       const char *format;
+       const struct sockaddr *saddr;
+       const struct sockaddr *daddr;
+{
+       static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
+       char *src, *dst;
+
+       src = strdup(saddr2str(saddr));
+       dst = strdup(saddr2str(daddr));
+       /* WARNING: Be careful about the format string! Don't 
+          ever pass in something that a user can modify!!! */
+       snprintf (buf, sizeof(buf), format, src, dst);
+       racoon_free (src);
+       racoon_free (dst);
+
+       return buf;
+}
+
+struct sockaddr *
+str2saddr(host, port)
+       char *host;
+       char *port;
+{
+       struct addrinfo hints, *res;
+       struct sockaddr *saddr;
+       int error;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+       hints.ai_flags = AI_NUMERICHOST;
+       error = getaddrinfo(host, port, &hints, &res);
+       if (error != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "getaddrinfo(%s%s%s): %s\n",
+                       host, port ? "," : "", port ? port : "",
+                       gai_strerror(error));
+               return NULL;
+       }
+       if (res->ai_next != NULL) {
+               plog(LLV_WARNING, LOCATION, NULL,
+                       "getaddrinfo(%s%s%s): "
+                       "resolved to multiple address, "
+                       "taking the first one\n",
+                       host, port ? "," : "", port ? port : "");
+       }
+       saddr = racoon_malloc(res->ai_addrlen);
+       if (saddr == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to allocate buffer.\n");
+               freeaddrinfo(res);
+               return NULL;
+       }
+       memcpy(saddr, res->ai_addr, res->ai_addrlen);
+       freeaddrinfo(res);
+
+       return saddr;
+}
+
+void
+mask_sockaddr(a, b, l)
+       struct sockaddr *a;
+       const struct sockaddr *b;
+       size_t l;
+{
+       size_t i;
+       u_int8_t *p, alen;
+
+       switch (b->sa_family) {
+       case AF_INET:
+               alen = sizeof(struct in_addr);
+               p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               alen = sizeof(struct in6_addr);
+               p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr;
+               break;
+#endif
+       default:
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "invalid address family: %d\n", b->sa_family);
+               exit(1);
+       }
+
+       if ((alen << 3) < l) {
+               plog(LLV_ERROR2, LOCATION, NULL,
+                       "unexpected inconsistency: %d %zu\n", b->sa_family, l);
+               exit(1);
+       }
+
+       memcpy(a, b, sysdep_sa_len(b));
+       p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
+       for (i = l / 8 + 1; i < alen; i++)
+               p[i] = 0x00;
+}
+
+/* Compute a score describing how "accurate" a netaddr is for a given sockaddr.
+ * Examples:
+ *     Return values for address 10.20.30.40 [port 500] and given netaddresses...
+ *             10.10.0.0/16    => -1   ... doesn't match
+ *             0.0.0.0/0       => 0    ... matches, but only 0 bits.
+ *             10.20.0.0/16    => 16   ... 16 bits match
+ *             10.20.30.0/24   => 24   ... guess what ;-)
+ *             10.20.30.40/32  => 32   ... whole address match
+ *             10.20.30.40:500 => 33   ... both address and port match
+ *             10.20.30.40:501 => -1   ... port doesn't match and isn't 0 (=any)
+ */
+int
+naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
+{
+       static const struct netaddr naddr_any;  /* initialized to all-zeros */
+       struct sockaddr sa;
+       uint16_t naddr_port, saddr_port;
+       int port_score;
+
+       if (!naddr || !saddr) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                    "Call with null args: naddr=%p, saddr=%p\n",
+                    naddr, saddr);
+               return -1;
+       }
+
+       /* Wildcard address matches, but only 0 bits. */
+       if (memcmp(naddr, &naddr_any, sizeof(naddr_any)) == 0)
+               return 0;
+
+       /* If families don't match we really can't do much... */
+       if (naddr->sa.sa.sa_family != saddr->sa_family)
+               return -1;
+       
+       /* If port check fail don't bother to check addresses. */
+       naddr_port = extract_port(&naddr->sa.sa);
+       saddr_port = extract_port(saddr);
+       if (naddr_port == 0 || saddr_port == 0) /* wildcard match */
+               port_score = 0;
+       else if (naddr_port == saddr_port)      /* exact match */
+               port_score = 1;
+       else                                    /* mismatch :-) */
+               return -1;
+
+       /* Here it comes - compare network addresses. */
+       mask_sockaddr(&sa, saddr, naddr->prefix);
+       if (loglevel >= LLV_DEBUG) {    /* debug only */
+               char *a1, *a2, *a3;
+               a1 = strdup(naddrwop2str(naddr));
+               a2 = strdup(saddrwop2str(saddr));
+               a3 = strdup(saddrwop2str(&sa));
+               plog(LLV_DEBUG, LOCATION, NULL,
+                    "naddr=%s, saddr=%s (masked=%s)\n",
+                    a1, a2, a3);
+               free(a1);
+               free(a2);
+               free(a3);
+       }
+       if (cmpsaddrwop(&sa, &naddr->sa.sa) == 0)
+               return naddr->prefix + port_score;
+
+       return -1;
+}
+
+/* Some usefull functions for sockaddr port manipulations. */
+u_int16_t
+extract_port (const struct sockaddr *addr)
+{
+  u_int16_t port = -1;
+  
+  if (!addr)
+    return port;
+
+  switch (addr->sa_family) {
+    case AF_INET:
+      port = ((struct sockaddr_in *)addr)->sin_port;
+      break;
+    case AF_INET6:
+      port = ((struct sockaddr_in6 *)addr)->sin6_port;
+      break;
+    default:
+      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
+      break;
+  }
+
+  return ntohs(port);
+}
+
+u_int16_t *
+get_port_ptr (struct sockaddr *addr)
+{
+  u_int16_t *port_ptr;
+
+  if (!addr)
+    return NULL;
+
+  switch (addr->sa_family) {
+    case AF_INET:
+      port_ptr = &(((struct sockaddr_in *)addr)->sin_port);
+      break;
+    case AF_INET6:
+      port_ptr = &(((struct sockaddr_in6 *)addr)->sin6_port);
+      break;
+    default:
+      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
+      return NULL;
+      break;
+  }
+
+  return port_ptr;
+}
+
+u_int16_t *
+set_port (struct sockaddr *addr, u_int16_t new_port)
+{
+  u_int16_t *port_ptr;
+
+  port_ptr = get_port_ptr (addr);
+
+  if (port_ptr)
+    *port_ptr = htons(new_port);
+
+  return port_ptr;
+}
diff --git a/ipsec-tools/racoon/sockmisc.h b/ipsec-tools/racoon/sockmisc.h
new file mode 100644 (file)
index 0000000..828c0b4
--- /dev/null
@@ -0,0 +1,87 @@
+/* $Id: sockmisc.h,v 1.5.10.4 2005/10/04 09:54:27 manubsd Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SOCKMISC_H
+#define _SOCKMISC_H
+
+struct netaddr {
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+               struct sockaddr_in6 sin6;
+       } sa;
+       unsigned long prefix;
+};
+
+extern const int niflags;
+
+extern int cmpsaddrwop __P((const struct sockaddr *, const struct sockaddr *));
+extern int cmpsaddrwild __P((const struct sockaddr *, const struct sockaddr *));
+extern int cmpsaddrstrict __P((const struct sockaddr *, const struct sockaddr *));
+
+#ifdef ENABLE_NATT 
+#define CMPSADDR(saddr1, saddr2) cmpsaddrstrict((saddr1), (saddr2))
+#else 
+#define CMPSADDR(saddr1, saddr2) cmpsaddrwop((saddr1), (saddr2))
+#endif
+
+extern struct sockaddr *getlocaladdr __P((struct sockaddr *));
+
+extern int recvfromto __P((int, void *, size_t, int,
+       struct sockaddr *, socklen_t *, struct sockaddr *, unsigned int *));
+extern int sendfromto __P((int, const void *, size_t,
+       struct sockaddr *, struct sockaddr *, int));
+
+extern int setsockopt_bypass __P((int, int));
+
+extern struct sockaddr *newsaddr __P((int));
+extern struct sockaddr *dupsaddr __P((struct sockaddr *));
+extern char *saddr2str __P((const struct sockaddr *));
+extern char *saddrwop2str __P((const struct sockaddr *));
+extern char *saddr2str_fromto __P((const char *format, 
+                                  const struct sockaddr *saddr, 
+                                  const struct sockaddr *daddr));
+extern struct sockaddr *str2saddr __P((char *, char *));
+extern void mask_sockaddr __P((struct sockaddr *, const struct sockaddr *,
+       size_t));
+
+/* struct netaddr functions */
+extern char *naddrwop2str __P((const struct netaddr *naddr));
+extern char *naddrwop2str_fromto __P((const char *format, const struct netaddr *saddr,
+                                     const struct netaddr *daddr));
+extern int naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr);
+
+/* Some usefull functions for sockaddr port manipulations. */
+extern u_int16_t extract_port __P((const struct sockaddr *addr));
+extern u_int16_t *set_port __P((struct sockaddr *addr, u_int16_t new_port));
+extern u_int16_t *get_port_ptr __P((struct sockaddr *addr));
+
+#endif /* _SOCKMISC_H */
diff --git a/ipsec-tools/racoon/stats.pl b/ipsec-tools/racoon/stats.pl
new file mode 100644 (file)
index 0000000..f509512
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+# usage:
+# % cat /var/log/racoon-stats.log | perl stats.pl
+
+while(<STDIN>) {
+       chomp;
+       ($a, $a, $a, $a, $a, $b) = split(/\s+/, $_, 6);
+       ($a, $c) = split(/:/, $b, 2);
+       $r{$a} += $c;
+       $t{$a}++;
+}
+
+foreach (sort keys %t) {
+       printf "%s: total=%d avg=%8.6f\n", $_, $t{$_}, $r{$_}/$t{$_};
+}
diff --git a/ipsec-tools/racoon/str2val.c b/ipsec-tools/racoon/str2val.c
new file mode 100644 (file)
index 0000000..9a38ee3
--- /dev/null
@@ -0,0 +1,124 @@
+/*     $KAME: str2val.c,v 1.11 2001/08/16 14:37:29 itojun Exp $        */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ctype.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "str2val.h"
+#include "gcmalloc.h"
+
+/*
+ * exchange a value to a hex string.
+ * must free buffer allocated later.
+ */
+caddr_t
+val2str(buf, mlen)
+       const char *buf;
+       size_t mlen;
+{
+       caddr_t new;
+       size_t len = (mlen * 2) + mlen / 8 + 10;
+       size_t i, j;
+
+       if ((new = racoon_malloc(len)) == 0) return(0);
+
+       for (i = 0, j = 0; i < mlen; i++) {
+               snprintf(&new[j], len - j, "%02x", (u_char)buf[i]);
+               j += 2;
+               if (i % 8 == 7) {
+                       new[j++] = ' ';
+                       new[j] = '\0';
+               }
+       }
+       new[j] = '\0';
+
+       return(new);
+}
+
+/*
+ * exchange a string based "base" to a value.
+ */
+char *
+str2val(str, base, len)
+       const char *str;
+       int base;
+       size_t *len;
+{
+       int f;
+       size_t i;
+       char *dst;
+       char *rp;
+       const char *p;
+       char b[3];
+
+       i = 0;
+       for (p = str; *p != '\0'; p++) {
+               if (isxdigit((int)*p))
+                       i++;
+               else if (isspace((int)*p))
+                       ;
+               else
+                       return NULL;
+       }
+       if (i == 0 || (i % 2) != 0)
+               return NULL;
+       i /= 2;
+
+       if ((dst = racoon_malloc(i)) == NULL)
+               return NULL;
+
+       i = 0;
+       f = 0;
+       for (rp = dst, p = str; *p != '\0'; p++) {
+               if (isxdigit((int)*p)) {
+                       if (!f) {
+                               b[0] = *p;
+                               f = 1;
+                       } else {
+                               b[1] = *p;
+                               b[2] = '\0';
+                               *rp++ = (char)strtol(b, NULL, base);
+                               i++;
+                               f = 0;
+                       }
+               }
+       }
+
+       *len = i;
+
+       return(dst);
+}
diff --git a/ipsec-tools/racoon/str2val.h b/ipsec-tools/racoon/str2val.h
new file mode 100644 (file)
index 0000000..4c286cc
--- /dev/null
@@ -0,0 +1,38 @@
+/* $Id: str2val.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _STR2VAL_H
+#define _STR2VAL_H
+
+extern caddr_t val2str __P((const char *, size_t));
+extern char *str2val __P((const char *, int, size_t *));
+
+#endif /* _STR2VAL_H */
diff --git a/ipsec-tools/racoon/strnames.c b/ipsec-tools/racoon/strnames.c
new file mode 100644 (file)
index 0000000..34562ee
--- /dev/null
@@ -0,0 +1,942 @@
+/*     $KAME: strnames.c,v 1.25 2003/11/13 10:53:26 itojun Exp $       */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h> 
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "handler.h"
+#include "pfkey.h"
+#include "strnames.h"
+#include "algorithm.h"
+
+struct ksmap {
+       int key;
+       char *str;
+       char *(*f) __P((int));
+};
+
+char *
+num2str(n)
+       int n;
+{
+       static char buf[20];
+
+       snprintf(buf, sizeof(buf), "%d", n);
+
+       return buf;
+}
+
+/* isakmp.h */
+char *
+s_isakmp_state(t, d, s)
+       int t, d, s;
+{
+       switch (t) {
+       case ISAKMP_ETYPE_AGG:
+               switch (d) {
+               case INITIATOR:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "agg I msg1";
+                       case PHASE1ST_ESTABLISHED:
+                               return "agg I msg2";
+                       default:
+                               break;
+                       }
+               case RESPONDER:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "agg R msg1";
+                       default:
+                               break;
+                       }
+               }
+               break;
+       case ISAKMP_ETYPE_BASE:
+               switch (d) {
+               case INITIATOR:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "base I msg1";
+                       case PHASE1ST_MSG2SENT:
+                               return "base I msg2";
+                       default:
+                               break;
+                       }
+               case RESPONDER:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "base R msg1";
+                       case PHASE1ST_ESTABLISHED:
+                               return "base R msg2";
+                       default:
+                               break;
+                       }
+               }
+               break;
+       case ISAKMP_ETYPE_IDENT:
+               switch (d) {
+               case INITIATOR:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "ident I msg1";
+                       case PHASE1ST_MSG2SENT:
+                               return "ident I msg2";
+                       case PHASE1ST_MSG3SENT:
+                               return "ident I msg3";
+                       default:
+                               break;
+                       }
+               case RESPONDER:
+                       switch (s) {
+                       case PHASE1ST_MSG1SENT:
+                               return "ident R msg1";
+                       case PHASE1ST_MSG2SENT:
+                               return "ident R msg2";
+                       case PHASE1ST_ESTABLISHED:
+                               return "ident R msg3";
+                       default:
+                               break;
+                       }
+               }
+               break;
+       case ISAKMP_ETYPE_QUICK:
+               switch (d) {
+               case INITIATOR:
+                       switch (s) {
+                       case PHASE2ST_MSG1SENT:
+                               return "quick I msg1";
+                       case PHASE2ST_ADDSA:
+                               return "quick I msg2";
+                       default:
+                               break;
+                       }
+               case RESPONDER:
+                       switch (s) {
+                       case PHASE2ST_MSG1SENT:
+                               return "quick R msg1";
+                       case PHASE2ST_COMMIT:
+                               return "quick R msg2";
+                       default:
+                               break;
+                       }
+               }
+               break;
+       default:
+       case ISAKMP_ETYPE_NONE:
+       case ISAKMP_ETYPE_AUTH:
+       case ISAKMP_ETYPE_INFO:
+       case ISAKMP_ETYPE_NEWGRP:
+       case ISAKMP_ETYPE_ACKINFO:
+               break;
+       }
+       /*NOTREACHED*/
+
+       return "???";
+}
+
+static struct ksmap name_isakmp_certtype[] = {
+{ ISAKMP_CERT_NONE,    "NONE",                                 NULL },
+{ ISAKMP_CERT_PKCS7,   "PKCS #7 wrapped X.509 certificate",    NULL },
+{ ISAKMP_CERT_PGP,     "PGP Certificate",                      NULL },
+{ ISAKMP_CERT_DNS,     "DNS Signed Key",                       NULL },
+{ ISAKMP_CERT_X509SIGN,        "X.509 Certificate Signature",          NULL },
+{ ISAKMP_CERT_X509KE,  "X.509 Certificate Key Exchange",       NULL },
+{ ISAKMP_CERT_KERBEROS,        "Kerberos Tokens",                      NULL },
+{ ISAKMP_CERT_CRL,     "Certificate Revocation List (CRL)",    NULL },
+{ ISAKMP_CERT_ARL,     "Authority Revocation List (ARL)",      NULL },
+{ ISAKMP_CERT_SPKI,    "SPKI Certificate",                     NULL },
+{ ISAKMP_CERT_X509ATTR,        "X.509 Certificate Attribute",          NULL },
+};
+
+char *
+s_isakmp_certtype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_isakmp_certtype); i++)
+               if (name_isakmp_certtype[i].key == k)
+                       return name_isakmp_certtype[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_isakmp_etype[] = {
+{ ISAKMP_ETYPE_NONE,   "None",                 NULL },
+{ ISAKMP_ETYPE_BASE,   "Base",                 NULL },
+{ ISAKMP_ETYPE_IDENT,  "Identity Protection",  NULL },
+{ ISAKMP_ETYPE_AUTH,   "Authentication Only",  NULL },
+{ ISAKMP_ETYPE_AGG,    "Aggressive",           NULL },
+{ ISAKMP_ETYPE_INFO,   "Informational",        NULL },
+{ ISAKMP_ETYPE_QUICK,  "Quick",                NULL },
+{ ISAKMP_ETYPE_NEWGRP, "New Group",            NULL },
+{ ISAKMP_ETYPE_ACKINFO,        "Acknowledged Informational",   NULL },
+};
+
+char *
+s_isakmp_etype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_isakmp_etype); i++)
+               if (name_isakmp_etype[i].key == k)
+                       return name_isakmp_etype[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_isakmp_notify_msg[] = {
+{ ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE,   "INVALID-PAYLOAD-TYPE",         NULL },
+{ ISAKMP_NTYPE_DOI_NOT_SUPPORTED,      "DOI-NOT-SUPPORTED",            NULL },
+{ ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED,        "SITUATION-NOT-SUPPORTED",      NULL },
+{ ISAKMP_NTYPE_INVALID_COOKIE,         "INVALID-COOKIE",               NULL },
+{ ISAKMP_NTYPE_INVALID_MAJOR_VERSION,  "INVALID-MAJOR-VERSION",        NULL },
+{ ISAKMP_NTYPE_INVALID_MINOR_VERSION,  "INVALID-MINOR-VERSION",        NULL },
+{ ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE,  "INVALID-EXCHANGE-TYPE",        NULL },
+{ ISAKMP_NTYPE_INVALID_FLAGS,          "INVALID-FLAGS",                NULL },
+{ ISAKMP_NTYPE_INVALID_MESSAGE_ID,     "INVALID-MESSAGE-ID",           NULL },
+{ ISAKMP_NTYPE_INVALID_PROTOCOL_ID,    "INVALID-PROTOCOL-ID",          NULL },
+{ ISAKMP_NTYPE_INVALID_SPI,            "INVALID-SPI",                  NULL },
+{ ISAKMP_NTYPE_INVALID_TRANSFORM_ID,   "INVALID-TRANSFORM-ID",         NULL },
+{ ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES-NOT-SUPPORTED",   NULL },
+{ ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN,     "NO-PROPOSAL-CHOSEN",           NULL },
+{ ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX,    "BAD-PROPOSAL-SYNTAX",          NULL },
+{ ISAKMP_NTYPE_PAYLOAD_MALFORMED,      "PAYLOAD-MALFORMED",            NULL },
+{ ISAKMP_NTYPE_INVALID_KEY_INFORMATION,        "INVALID-KEY-INFORMATION",      NULL },
+{ ISAKMP_NTYPE_INVALID_ID_INFORMATION, "INVALID-ID-INFORMATION",       NULL },
+{ ISAKMP_NTYPE_INVALID_CERT_ENCODING,  "INVALID-CERT-ENCODING",        NULL },
+{ ISAKMP_NTYPE_INVALID_CERTIFICATE,    "INVALID-CERTIFICATE",          NULL },
+{ ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX,        "BAD-CERT-REQUEST-SYNTAX",      NULL },
+{ ISAKMP_NTYPE_INVALID_CERT_AUTHORITY, "INVALID-CERT-AUTHORITY",       NULL },
+{ ISAKMP_NTYPE_INVALID_HASH_INFORMATION, "INVALID-HASH-INFORMATION",   NULL },
+{ ISAKMP_NTYPE_AUTHENTICATION_FAILED,  "AUTHENTICATION-FAILED",        NULL },
+{ ISAKMP_NTYPE_INVALID_SIGNATURE,      "INVALID-SIGNATURE",            NULL },
+{ ISAKMP_NTYPE_ADDRESS_NOTIFICATION,   "ADDRESS-NOTIFICATION",         NULL },
+{ ISAKMP_NTYPE_NOTIFY_SA_LIFETIME,     "NOTIFY-SA-LIFETIME",           NULL },
+{ ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE,        "CERTIFICATE-UNAVAILABLE",      NULL },
+{ ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED-EXCHANGE-TYPE", NULL },
+{ ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS,        "UNEQUAL-PAYLOAD-LENGTHS",      NULL },
+{ ISAKMP_NTYPE_CONNECTED,              "CONNECTED",                    NULL },
+{ ISAKMP_NTYPE_RESPONDER_LIFETIME,     "RESPONDER-LIFETIME",           NULL },
+{ ISAKMP_NTYPE_REPLAY_STATUS,          "REPLAY-STATUS",                NULL },
+{ ISAKMP_NTYPE_INITIAL_CONTACT,                "INITIAL-CONTACT",              NULL },
+{ ISAKMP_LOG_RETRY_LIMIT_REACHED,      "RETRY-LIMIT-REACHED",          NULL },
+};
+
+char *
+s_isakmp_notify_msg(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_isakmp_notify_msg); i++)
+               if (name_isakmp_notify_msg[i].key == k)
+                       return name_isakmp_notify_msg[i].str;
+
+       return num2str(k);
+}
+
+static struct ksmap name_isakmp_nptype[] = {
+{ ISAKMP_NPTYPE_NONE,  "none",         NULL },
+{ ISAKMP_NPTYPE_SA,    "sa",           NULL },
+{ ISAKMP_NPTYPE_P,     "prop",         NULL },
+{ ISAKMP_NPTYPE_T,     "trns",         NULL },
+{ ISAKMP_NPTYPE_KE,    "ke",           NULL },
+{ ISAKMP_NPTYPE_ID,    "id",           NULL },
+{ ISAKMP_NPTYPE_CERT,  "cert",         NULL },
+{ ISAKMP_NPTYPE_CR,    "cr",           NULL },
+{ ISAKMP_NPTYPE_HASH,  "hash",         NULL },
+{ ISAKMP_NPTYPE_SIG,   "sig",          NULL },
+{ ISAKMP_NPTYPE_NONCE, "nonce",        NULL },
+{ ISAKMP_NPTYPE_N,     "notify",       NULL },
+{ ISAKMP_NPTYPE_D,     "delete",       NULL },
+{ ISAKMP_NPTYPE_VID,   "vid",          NULL },
+{ ISAKMP_NPTYPE_GSS,   "gss id",       NULL },
+{ ISAKMP_NPTYPE_NATD_RFC,      "nat-d",        NULL },
+{ ISAKMP_NPTYPE_NATOA_RFC,     "nat-oa",       NULL },
+{ ISAKMP_NPTYPE_NATD_DRAFT,    "nat-d",        NULL },
+{ ISAKMP_NPTYPE_NATOA_DRAFT,   "nat-oa",       NULL },
+{ ISAKMP_NPTYPE_NATD_BADDRAFT, "nat-d",        NULL },
+{ ISAKMP_NPTYPE_NATOA_BADDRAFT,        "nat-oa",       NULL }
+};
+
+char *
+s_isakmp_nptype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_isakmp_nptype); i++)
+               if (name_isakmp_nptype[i].key == k)
+                       return name_isakmp_nptype[i].str;
+       return num2str(k);
+}
+
+/* ipsec_doi.h */
+static struct ksmap name_ipsecdoi_proto[] = {
+{ IPSECDOI_PROTO_ISAKMP,       "ISAKMP",       s_ipsecdoi_trns_isakmp },
+{ IPSECDOI_PROTO_IPSEC_AH,     "AH",           s_ipsecdoi_trns_ah },
+{ IPSECDOI_PROTO_IPSEC_ESP,    "ESP",          s_ipsecdoi_trns_esp },
+{ IPSECDOI_PROTO_IPCOMP,       "IPCOMP",       s_ipsecdoi_trns_ipcomp },
+};
+
+char *
+s_ipsecdoi_proto(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++)
+               if (name_ipsecdoi_proto[i].key == k)
+                       return name_ipsecdoi_proto[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_ipsecdoi_trns_isakmp[] = {
+{ IPSECDOI_KEY_IKE,    "IKE", NULL },
+};
+
+char *
+s_ipsecdoi_trns_isakmp(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_isakmp); i++)
+               if (name_ipsecdoi_trns_isakmp[i].key == k)
+                       return name_ipsecdoi_trns_isakmp[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_ipsecdoi_trns_ah[] = {
+{ IPSECDOI_AH_MD5,     "MD5", NULL },
+{ IPSECDOI_AH_SHA,     "SHA", NULL },
+{ IPSECDOI_AH_DES,     "DES", NULL },
+{ IPSECDOI_AH_SHA256,  "SHA256", NULL },
+{ IPSECDOI_AH_SHA384,  "SHA384", NULL },
+{ IPSECDOI_AH_SHA512,  "SHA512", NULL },
+};
+
+char *
+s_ipsecdoi_trns_ah(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ah); i++)
+               if (name_ipsecdoi_trns_ah[i].key == k)
+                       return name_ipsecdoi_trns_ah[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_ipsecdoi_trns_esp[] = {
+{ IPSECDOI_ESP_DES_IV64,       "DES_IV64",     NULL },
+{ IPSECDOI_ESP_DES,            "DES",          NULL },
+{ IPSECDOI_ESP_3DES,           "3DES",         NULL },
+{ IPSECDOI_ESP_RC5,            "RC5",          NULL },
+{ IPSECDOI_ESP_IDEA,           "IDEA",         NULL },
+{ IPSECDOI_ESP_CAST,           "CAST",         NULL },
+{ IPSECDOI_ESP_BLOWFISH,       "BLOWFISH",     NULL },
+{ IPSECDOI_ESP_3IDEA,          "3IDEA",        NULL },
+{ IPSECDOI_ESP_DES_IV32,       "DES_IV32",     NULL },
+{ IPSECDOI_ESP_RC4,            "RC4",          NULL },
+{ IPSECDOI_ESP_NULL,           "NULL",         NULL },
+{ IPSECDOI_ESP_AES,            "AES",          NULL },
+{ IPSECDOI_ESP_TWOFISH,                "TWOFISH",      NULL },
+};
+
+char *
+s_ipsecdoi_trns_esp(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_esp); i++)
+               if (name_ipsecdoi_trns_esp[i].key == k)
+                       return name_ipsecdoi_trns_esp[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_ipsecdoi_trns_ipcomp[] = {
+{ IPSECDOI_IPCOMP_OUI,         "OUI",          NULL},
+{ IPSECDOI_IPCOMP_DEFLATE,     "DEFLATE",      NULL},
+{ IPSECDOI_IPCOMP_LZS,         "LZS",          NULL},
+};
+
+char *
+s_ipsecdoi_trns_ipcomp(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ipcomp); i++)
+               if (name_ipsecdoi_trns_ipcomp[i].key == k)
+                       return name_ipsecdoi_trns_ipcomp[i].str;
+       return num2str(k);
+}
+
+char *
+s_ipsecdoi_trns(proto, trns)
+       int proto, trns;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++)
+               if (name_ipsecdoi_proto[i].key == proto
+                && name_ipsecdoi_proto[i].f)
+                       return (name_ipsecdoi_proto[i].f)(trns);
+       return num2str(trns);
+}
+
+static struct ksmap name_attr_ipsec[] = {
+{ IPSECDOI_ATTR_SA_LD_TYPE,    "SA Life Type",         s_ipsecdoi_ltype },
+{ IPSECDOI_ATTR_SA_LD,         "SA Life Duration",     NULL },
+{ IPSECDOI_ATTR_GRP_DESC,      "Group Description",    NULL },
+{ IPSECDOI_ATTR_ENC_MODE,      "Encryption Mode",      s_ipsecdoi_encmode },
+{ IPSECDOI_ATTR_AUTH,          "Authentication Algorithm", s_ipsecdoi_auth },
+{ IPSECDOI_ATTR_KEY_LENGTH,    "Key Length",           NULL },
+{ IPSECDOI_ATTR_KEY_ROUNDS,    "Key Rounds",           NULL },
+{ IPSECDOI_ATTR_COMP_DICT_SIZE,        "Compression Dictionary Size",  NULL },
+{ IPSECDOI_ATTR_COMP_PRIVALG,  "Compression Private Algorithm", NULL },
+};
+
+char *
+s_ipsecdoi_attr(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_ipsec); i++)
+               if (name_attr_ipsec[i].key == k)
+                       return name_attr_ipsec[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_ipsec_ltype[] = {
+{ IPSECDOI_ATTR_SA_LD_TYPE_SEC,        "seconds",      NULL },
+{ IPSECDOI_ATTR_SA_LD_TYPE_KB, "kilobytes",    NULL },
+};
+
+char *
+s_ipsecdoi_ltype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_ipsec_ltype); i++)
+               if (name_attr_ipsec_ltype[i].key == k)
+                       return name_attr_ipsec_ltype[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_ipsec_encmode[] = {
+{ IPSECDOI_ATTR_ENC_MODE_ANY,          "Any",          NULL },
+{ IPSECDOI_ATTR_ENC_MODE_TUNNEL,       "Tunnel",       NULL },
+{ IPSECDOI_ATTR_ENC_MODE_TRNS,         "Transport",    NULL },
+{ IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC,        "UDP-Tunnel",   NULL },
+{ IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC,  "UDP-Transport",        NULL },
+{ IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT,      "UDP-Tunnel",   NULL },
+{ IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT,        "UDP-Transport",        NULL },
+};
+
+char *
+s_ipsecdoi_encmode(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_ipsec_encmode); i++)
+               if (name_attr_ipsec_encmode[i].key == k)
+                       return name_attr_ipsec_encmode[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_ipsec_auth[] = {
+{ IPSECDOI_ATTR_AUTH_HMAC_MD5,         "hmac-md5",     NULL },
+{ IPSECDOI_ATTR_AUTH_HMAC_SHA1,                "hmac-sha",     NULL },
+{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_256,    "hmac-sha256",  NULL },
+{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_384,    "hmac-sha384",  NULL },
+{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_512,    "hmac-sha512",  NULL },
+{ IPSECDOI_ATTR_AUTH_DES_MAC,          "des-mac",      NULL },
+{ IPSECDOI_ATTR_AUTH_KPDK,             "kpdk",         NULL },
+};
+
+char *
+s_ipsecdoi_auth(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_ipsec_auth); i++)
+               if (name_attr_ipsec_auth[i].key == k)
+                       return name_attr_ipsec_auth[i].str;
+       return num2str(k);
+}
+
+char *
+s_ipsecdoi_attr_v(type, val)
+       int type, val;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_ipsec); i++)
+               if (name_attr_ipsec[i].key == type
+                && name_attr_ipsec[i].f)
+                       return (name_attr_ipsec[i].f)(val);
+       return num2str(val);
+}
+
+static struct ksmap name_ipsecdoi_ident[] = {
+{ IPSECDOI_ID_IPV4_ADDR,       "IPv4_address", NULL },
+{ IPSECDOI_ID_FQDN,            "FQDN",         NULL },
+{ IPSECDOI_ID_USER_FQDN,       "User_FQDN",    NULL },
+{ IPSECDOI_ID_IPV4_ADDR_SUBNET,        "IPv4_subnet",  NULL },
+{ IPSECDOI_ID_IPV6_ADDR,       "IPv6_address", NULL },
+{ IPSECDOI_ID_IPV6_ADDR_SUBNET,        "IPv6_subnet",  NULL },
+{ IPSECDOI_ID_IPV4_ADDR_RANGE, "IPv4_address_range",   NULL },
+{ IPSECDOI_ID_IPV6_ADDR_RANGE, "IPv6_address_range",   NULL },
+{ IPSECDOI_ID_DER_ASN1_DN,     "DER_ASN1_DN",  NULL },
+{ IPSECDOI_ID_DER_ASN1_GN,     "DER_ASN1_GN",  NULL },
+{ IPSECDOI_ID_KEY_ID,          "KEY_ID",       NULL },
+};
+
+char *
+s_ipsecdoi_ident(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsecdoi_ident); i++)
+               if (name_ipsecdoi_ident[i].key == k)
+                       return name_ipsecdoi_ident[i].str;
+       return num2str(k);
+}
+
+/* oakley.h */
+static struct ksmap name_oakley_attr[] = {
+{ OAKLEY_ATTR_ENC_ALG,         "Encryption Algorithm", s_attr_isakmp_enc },
+{ OAKLEY_ATTR_HASH_ALG,                "Hash Algorithm",       s_attr_isakmp_hash },
+{ OAKLEY_ATTR_AUTH_METHOD,     "Authentication Method", s_oakley_attr_method },
+{ OAKLEY_ATTR_GRP_DESC,                "Group Description",    s_attr_isakmp_desc },
+{ OAKLEY_ATTR_GRP_TYPE,                "Group Type",           s_attr_isakmp_group },
+{ OAKLEY_ATTR_GRP_PI,          "Group Prime/Irreducible Polynomial",   NULL },
+{ OAKLEY_ATTR_GRP_GEN_ONE,     "Group Generator One",  NULL },
+{ OAKLEY_ATTR_GRP_GEN_TWO,     "Group Generator Two",  NULL },
+{ OAKLEY_ATTR_GRP_CURVE_A,     "Group Curve A",        NULL },
+{ OAKLEY_ATTR_GRP_CURVE_B,     "Group Curve B",        NULL },
+{ OAKLEY_ATTR_SA_LD_TYPE,      "Life Type",            s_attr_isakmp_ltype },
+{ OAKLEY_ATTR_SA_LD,           "Life Duration",        NULL },
+{ OAKLEY_ATTR_PRF,             "PRF",                  NULL },
+{ OAKLEY_ATTR_KEY_LEN,         "Key Length",           NULL },
+{ OAKLEY_ATTR_FIELD_SIZE,      "Field Size",           NULL },
+{ OAKLEY_ATTR_GRP_ORDER,       "Group Order",          NULL },
+{ OAKLEY_ATTR_BLOCK_SIZE,      "Block Size",           NULL },
+{ OAKLEY_ATTR_GSS_ID,          "GSS-API endpoint name",NULL },
+};
+
+char *
+s_oakley_attr(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_oakley_attr); i++)
+               if (name_oakley_attr[i].key == k)
+                       return name_oakley_attr[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_enc[] = {
+{ OAKLEY_ATTR_ENC_ALG_DES,     "DES-CBC",              NULL },
+{ OAKLEY_ATTR_ENC_ALG_IDEA,    "IDEA-CBC",             NULL },
+{ OAKLEY_ATTR_ENC_ALG_BLOWFISH,        "Blowfish-CBC",         NULL },
+{ OAKLEY_ATTR_ENC_ALG_RC5,     "RC5-R16-B64-CBC",      NULL },
+{ OAKLEY_ATTR_ENC_ALG_3DES,    "3DES-CBC",             NULL },
+{ OAKLEY_ATTR_ENC_ALG_CAST,    "CAST-CBC",             NULL },
+};
+
+char *
+s_attr_isakmp_enc(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_enc); i++)
+               if (name_attr_isakmp_enc[i].key == k)
+                       return name_attr_isakmp_enc[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_hash[] = {
+{ OAKLEY_ATTR_HASH_ALG_MD5,    "MD5",          NULL },
+{ OAKLEY_ATTR_HASH_ALG_SHA,    "SHA",          NULL },
+{ OAKLEY_ATTR_HASH_ALG_TIGER,  "Tiger",        NULL },
+{ OAKLEY_ATTR_HASH_ALG_SHA2_256,"SHA256",      NULL },
+{ OAKLEY_ATTR_HASH_ALG_SHA2_384,"SHA384",      NULL },
+{ OAKLEY_ATTR_HASH_ALG_SHA2_512,"SHA512",      NULL },
+};
+
+char *
+s_attr_isakmp_hash(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_hash); i++)
+               if (name_attr_isakmp_hash[i].key == k)
+                       return name_attr_isakmp_hash[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_method[] = {
+{ OAKLEY_ATTR_AUTH_METHOD_PSKEY,       "pre-shared key",       NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_DSSSIG,      "DSS signatures",       NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_RSASIG,      "RSA signatures",       NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_RSAENC,      "Encryption with RSA",  NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_RSAREV,      "Revised encryption with RSA",  NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_EGENC,       "Encryption with El-Gamal",     NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_EGREV,       "Revised encryption with El-Gamal",     NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB,  "GSS-API on Kerberos 5", NULL },
+#ifdef ENABLE_HYBRID
+{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I,        "Hybrid DSS server",    NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I,        "Hybrid RSA server",    NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R,        "Hybrid DSS client",    NULL },
+{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R,        "Hybrid RSA client",    NULL },
+#endif
+};
+
+char *
+s_oakley_attr_method(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_method); i++)
+               if (name_attr_isakmp_method[i].key == k)
+                       return name_attr_isakmp_method[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_desc[] = {
+{ OAKLEY_ATTR_GRP_DESC_MODP768,                "768-bit MODP group",   NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP1024,       "1024-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_EC2N155,                "EC2N group on GP[2^155]",      NULL },
+{ OAKLEY_ATTR_GRP_DESC_EC2N185,                "EC2N group on GP[2^185]",      NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP1536,       "1536-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP2048,       "2048-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP3072,       "3072-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP4096,       "4096-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP6144,       "6144-bit MODP group",  NULL },
+{ OAKLEY_ATTR_GRP_DESC_MODP8192,       "8192-bit MODP group",  NULL },
+};
+
+char *
+s_attr_isakmp_desc(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_desc); i++)
+               if (name_attr_isakmp_desc[i].key == k)
+                       return name_attr_isakmp_desc[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_group[] = {
+{ OAKLEY_ATTR_GRP_TYPE_MODP,   "MODP", NULL },
+{ OAKLEY_ATTR_GRP_TYPE_ECP,    "ECP",  NULL },
+{ OAKLEY_ATTR_GRP_TYPE_EC2N,   "EC2N", NULL },
+};
+
+char *
+s_attr_isakmp_group(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_group); i++)
+               if (name_attr_isakmp_group[i].key == k)
+                       return name_attr_isakmp_group[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_attr_isakmp_ltype[] = {
+{ OAKLEY_ATTR_SA_LD_TYPE_SEC,  "seconds",      NULL },
+{ OAKLEY_ATTR_SA_LD_TYPE_KB,   "kilobytes",    NULL },
+};
+
+char *
+s_attr_isakmp_ltype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_attr_isakmp_ltype); i++)
+               if (name_attr_isakmp_ltype[i].key == k)
+                       return name_attr_isakmp_ltype[i].str;
+       return num2str(k);
+}
+
+char *
+s_oakley_attr_v(type, val)
+       int type, val;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_oakley_attr); i++)
+               if (name_oakley_attr[i].key == type
+                && name_oakley_attr[i].f)
+                       return (name_oakley_attr[i].f)(val);
+       return num2str(val);
+}
+
+/* netinet6/ipsec.h */
+static struct ksmap name_ipsec_level[] = {
+{ IPSEC_LEVEL_USE,     "use",          NULL },
+{ IPSEC_LEVEL_REQUIRE, "require",      NULL },
+{ IPSEC_LEVEL_UNIQUE,  "unique",       NULL },
+};
+
+char *
+s_ipsec_level(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_ipsec_level); i++)
+               if (name_ipsec_level[i].key == k)
+                       return name_ipsec_level[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_algclass[] = {
+{ algclass_ipsec_enc,  "ipsec enc",    s_ipsecdoi_trns_esp },
+{ algclass_ipsec_auth, "ipsec auth",   s_ipsecdoi_trns_ah },
+{ algclass_ipsec_comp, "ipsec comp",   s_ipsecdoi_trns_ipcomp },
+{ algclass_isakmp_enc, "isakmp enc",   s_attr_isakmp_enc },
+{ algclass_isakmp_hash,        "isakmp hash",  s_attr_isakmp_hash },
+{ algclass_isakmp_dh,  "isakmp dh",    s_attr_isakmp_desc },
+{ algclass_isakmp_ameth, "isakmp auth method", s_oakley_attr_method },
+};
+
+char *
+s_algclass(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_algclass); i++)
+               if (name_algclass[i].key == k)
+                       return name_algclass[i].str;
+       return num2str(k);
+}
+
+char *
+s_algtype(class, n)
+       int class, n;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_algclass); i++)
+               if (name_algclass[i].key == class
+                && name_algclass[i].f)
+                       return (name_algclass[i].f)(n);
+       return num2str(n);
+}
+
+/* pfkey.h */
+static struct ksmap name_pfkey_type[] = {
+{ SADB_GETSPI,         "GETSPI",       NULL },
+{ SADB_UPDATE,         "UPDATE",       NULL },
+{ SADB_ADD,            "ADD",          NULL },
+{ SADB_DELETE,         "DELETE",       NULL },
+{ SADB_GET,            "GET",          NULL },
+{ SADB_ACQUIRE,                "ACQUIRE",      NULL },
+{ SADB_REGISTER,       "REGISTER",     NULL },
+{ SADB_EXPIRE,         "EXPIRE",       NULL },
+{ SADB_FLUSH,          "FLUSH",        NULL },
+{ SADB_DUMP,           "DUMP",         NULL },
+{ SADB_X_PROMISC,      "X_PRIMISC",    NULL },
+{ SADB_X_PCHANGE,      "X_PCHANGE",    NULL },
+{ SADB_X_SPDUPDATE,    "X_SPDUPDATE",  NULL },
+{ SADB_X_SPDADD,       "X_SPDADD",     NULL },
+{ SADB_X_SPDDELETE,    "X_SPDDELETE",  NULL },
+{ SADB_X_SPDGET,       "X_SPDGET",     NULL },
+{ SADB_X_SPDACQUIRE,   "X_SPDACQUIRE", NULL },
+{ SADB_X_SPDDUMP,      "X_SPDDUMP",    NULL },
+{ SADB_X_SPDFLUSH,     "X_SPDFLUSH",   NULL },
+{ SADB_X_SPDSETIDX,    "X_SPDSETIDX",  NULL },
+{ SADB_X_SPDEXPIRE,    "X_SPDEXPIRE",  NULL },
+{ SADB_X_SPDDELETE2,   "X_SPDDELETE2", NULL },
+#ifndef __APPLE__
+#ifdef ENABLE_NATT
+{ SADB_X_NAT_T_NEW_MAPPING, "X_NAT_T_NEW_MAPPING", NULL },
+#endif
+#endif
+};
+
+char *
+s_pfkey_type(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_pfkey_type); i++)
+               if (name_pfkey_type[i].key == k)
+                       return name_pfkey_type[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_pfkey_satype[] = {
+{ SADB_SATYPE_UNSPEC,  "UNSPEC",       NULL },
+{ SADB_SATYPE_AH,      "AH",           NULL },
+{ SADB_SATYPE_ESP,     "ESP",          NULL },
+{ SADB_SATYPE_RSVP,    "RSVP",         NULL },
+{ SADB_SATYPE_OSPFV2,  "OSPFV2",       NULL },
+{ SADB_SATYPE_RIPV2,   "RIPV2",        NULL },
+{ SADB_SATYPE_MIP,     "MIP",          NULL },
+{ SADB_X_SATYPE_IPCOMP,        "IPCOMP",       NULL },
+};
+
+char *
+s_pfkey_satype(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_pfkey_satype); i++)
+               if (name_pfkey_satype[i].key == k)
+                       return name_pfkey_satype[i].str;
+       return num2str(k);
+}
+
+static struct ksmap name_direction[] = {
+{ IPSEC_DIR_INBOUND,   "in",   NULL },
+{ IPSEC_DIR_OUTBOUND,  "out",  NULL },
+#ifdef HAVE_POLICY_FWD
+{ IPSEC_DIR_FWD,       "fwd",  NULL },
+#endif
+};
+
+char *
+s_direction(k)
+       int k;
+{
+       int i;
+       for (i = 0; i < ARRAYLEN(name_direction); i++)
+               if (name_direction[i].key == k)
+                       return name_direction[i].str;
+       return num2str(k);
+}
+
+char *
+s_proto(k)
+       int k;
+{
+       switch (k) {
+       case IPPROTO_ICMP:
+               return "icmp";
+       case IPPROTO_TCP:
+               return "tcp";
+       case IPPROTO_UDP:
+               return "udp";
+       case IPPROTO_ICMPV6:
+               return "icmpv6";
+       case IPSEC_ULPROTO_ANY:
+               return "any";
+       }
+
+       return num2str(k);
+}
+
+char *
+s_doi(int k)
+{
+  switch (k) {
+    case IPSEC_DOI:
+      return "ipsec_doi";
+    default:
+      return num2str(k);
+  }
+}
+
+char *
+s_etype (int k)
+{
+  switch (k) {
+    case ISAKMP_ETYPE_NONE:
+      return "_none";
+    case ISAKMP_ETYPE_BASE:
+      return "base";
+    case ISAKMP_ETYPE_IDENT:
+      return "main";
+    case ISAKMP_ETYPE_AUTH:
+      return "_auth";
+    case ISAKMP_ETYPE_AGG:
+      return "aggressive";
+    case ISAKMP_ETYPE_INFO:
+      return "_info";
+    case ISAKMP_ETYPE_QUICK:
+      return "_quick";
+    case ISAKMP_ETYPE_NEWGRP:
+      return "_newgrp";
+    case ISAKMP_ETYPE_ACKINFO:
+      return "_ackinfo";
+    default:
+      return num2str(k);
+  }
+}
+
+char *
+s_idtype (int k)
+{
+  switch (k) {
+    case IDTYPE_FQDN:
+      return "fqdn";
+    case IDTYPE_USERFQDN:
+      return "user_fqdn";
+    case IDTYPE_KEYID:
+      return "keyid";
+    case IDTYPE_ADDRESS:
+      return "address";
+    case IDTYPE_ASN1DN:
+      return "asn1dn";
+    default:
+      return num2str(k);
+  }
+}
+
+char *
+s_switch (int k)
+{
+  switch (k) {
+    case FALSE:
+      return "off";
+    case TRUE:
+      return "on";
+    default:
+      return num2str(k);
+  }
+}
diff --git a/ipsec-tools/racoon/strnames.h b/ipsec-tools/racoon/strnames.h
new file mode 100644 (file)
index 0000000..ed60551
--- /dev/null
@@ -0,0 +1,74 @@
+/* $Id: strnames.h,v 1.5 2004/07/12 20:37:13 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _STRNAMES_H
+#define _STRNAMES_H
+
+extern char *num2str __P((int n));
+
+extern char *s_isakmp_state __P((int, int, int));
+extern char *s_isakmp_certtype __P((int));
+extern char *s_isakmp_etype __P((int));
+extern char *s_isakmp_notify_msg __P((int));
+extern char *s_isakmp_nptype __P((int));
+extern char *s_ipsecdoi_proto __P((int));
+extern char *s_ipsecdoi_trns_isakmp __P((int));
+extern char *s_ipsecdoi_trns_ah __P((int));
+extern char *s_ipsecdoi_trns_esp __P((int));
+extern char *s_ipsecdoi_trns_ipcomp __P((int));
+extern char *s_ipsecdoi_trns __P((int, int));
+extern char *s_ipsecdoi_attr __P((int));
+extern char *s_ipsecdoi_ltype __P((int));
+extern char *s_ipsecdoi_encmode __P((int));
+extern char *s_ipsecdoi_auth __P((int));
+extern char *s_ipsecdoi_attr_v __P((int, int));
+extern char *s_ipsecdoi_ident __P((int));
+extern char *s_oakley_attr __P((int));
+extern char *s_attr_isakmp_enc __P((int));
+extern char *s_attr_isakmp_hash __P((int));
+extern char *s_oakley_attr_method __P((int));
+extern char *s_attr_isakmp_desc __P((int));
+extern char *s_attr_isakmp_group __P((int));
+extern char *s_attr_isakmp_ltype __P((int));
+extern char *s_oakley_attr_v __P((int, int));
+extern char *s_ipsec_level __P((int));
+extern char *s_algclass __P((int));
+extern char *s_algtype __P((int, int));
+extern char *s_pfkey_type __P((int));
+extern char *s_pfkey_satype __P((int));
+extern char *s_direction __P((int));
+extern char *s_proto __P((int));
+extern char *s_doi __P((int));
+extern char *s_etype __P((int));
+extern char *s_idtype __P((int));
+extern char *s_switch __P((int));
+
+#endif /* _STRNAMES_H */
diff --git a/ipsec-tools/racoon/throttle.c b/ipsec-tools/racoon/throttle.c
new file mode 100644 (file)
index 0000000..73f6b92
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id: throttle.c,v 1.2 2004/11/30 07:40:13 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h> 
+#else 
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif 
+#endif
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include "vmbuf.h"
+#include "misc.h"
+#include "plog.h"
+#include "throttle.h"
+#include "sockmisc.h"
+#include "libpfkey.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#include "gcmalloc.h"
+
+struct throttle_list throttle_list = TAILQ_HEAD_INITIALIZER(throttle_list);
+
+
+struct throttle_entry *
+throttle_add(addr)
+       struct sockaddr *addr;
+{
+       struct throttle_entry *te;
+       size_t len;
+
+       len = sizeof(*te) 
+           - sizeof(struct sockaddr_storage) 
+           + sysdep_sa_len(addr);
+
+       if ((te = racoon_malloc(len)) == NULL)
+               return NULL;
+
+       te->penalty = time(NULL) + isakmp_cfg_config.auth_throttle;
+       memcpy(&te->host, addr, sysdep_sa_len(addr));
+       TAILQ_INSERT_HEAD(&throttle_list, te, next);
+
+       return te;
+}
+
+int
+throttle_host(addr, authfail) 
+       struct sockaddr *addr;
+       int authfail;
+{
+       struct throttle_entry *te;
+       int found = 0;
+       time_t now;
+
+       if (isakmp_cfg_config.auth_throttle == 0)
+               return 0;
+
+       now = time(NULL);
+
+       TAILQ_FOREACH_REVERSE(te, &throttle_list, throttle_list, next) {
+               /* 
+                * Remove outdated entries 
+                */
+               if (te->penalty < now) {
+                       TAILQ_REMOVE(&throttle_list, te, next);
+                       racoon_free(te);
+                       continue;
+               }
+                       
+               if (cmpsaddrwop(addr, (struct sockaddr *)&te->host) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       /* 
+        * No match, if auth failed, allocate a new throttle entry
+        * give no penalty even on error: this is the first time
+        * and we are indulgent.
+        */
+       if (!found) {
+               if (authfail) {
+                       if ((te = throttle_add(addr)) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, 
+                                   "Throttle insertion failed\n");
+                               return (time(NULL) 
+                                   + isakmp_cfg_config.auth_throttle);
+                       }
+               }
+               return 0;
+       } else {
+               /*
+                * We had a match and auth failed, increase penalty.
+                */
+               if (authfail) {
+                       time_t remaining;
+                       time_t new;
+
+                       remaining = te->penalty - now;
+                       new = remaining + isakmp_cfg_config.auth_throttle;
+
+                       if (new > THROTTLE_PENALTY_MAX)
+                               new = THROTTLE_PENALTY_MAX;
+
+                       te->penalty = now + new;
+               }
+       }
+       
+       return te->penalty;
+}
+
diff --git a/ipsec-tools/racoon/throttle.h b/ipsec-tools/racoon/throttle.h
new file mode 100644 (file)
index 0000000..4de4970
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: throttle.h,v 1.1 2004/11/30 00:46:09 manubsd Exp $ */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * 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.
+ */
+
+#ifndef _THROTTLE_H
+#define _THROTTLE_H
+
+struct throttle_entry {
+       int penalty;
+       TAILQ_ENTRY(throttle_entry) next;
+       struct sockaddr_storage host;
+};
+
+TAILQ_HEAD(throttle_list, throttle_entry);
+
+#define THROTTLE_PENALTY 1
+#define THROTTLE_PENALTY_MAX 10
+
+struct throttle_entry *throttle_add(struct sockaddr *);
+int throttle_host(struct sockaddr *, int);
+
+#endif /* _THROTTLE_H */
diff --git a/ipsec-tools/racoon/var.h b/ipsec-tools/racoon/var.h
new file mode 100644 (file)
index 0000000..e2cb36f
--- /dev/null
@@ -0,0 +1,105 @@
+/* $Id: var.h,v 1.6 2004/11/20 16:16:59 monas Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _VAR_H
+#define _VAR_H
+
+#if !defined(_VAR_H_)
+#define _VAR_H_
+
+#define MAX3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
+
+#define ISSET(exp, bit) (((exp) & (bit)) == (bit))
+
+#define LALIGN(a) \
+    ((a) > 0 ? ((a) &~ (sizeof(long) - 1)) : sizeof(long))
+
+#define RNDUP(a) \
+    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+#define ARRAYLEN(a)    (sizeof(a)/sizeof(a[0]))
+
+#define BUFSIZE    5120
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifdef ENABLE_STATS
+#include <sys/time.h>
+#endif
+#include <sys/socket.h>
+
+/*
+ * use of GETNAMEINFO(x, y, NULL) is not politically correct,
+ * as sizeof(NULL) would be 4, not 0. Also, gcc-3.4.2+ bombs on it.
+ * In such cases, use GETNAMEINFO_NULL(x, y)
+ */
+#include <sys/socket.h>
+#include <netdb.h>
+
+/* var.h is used from non-racoon code (like eaytest), so we can't use niflags */
+#define NIFLAGS        (NI_NUMERICHOST | NI_NUMERICSERV)
+
+#define GETNAMEINFO(x, y, z) \
+do { \
+       if (getnameinfo((x), sysdep_sa_len(x), (y), sizeof(y), (z), sizeof(z), \
+                       NIFLAGS) != 0) { \
+               if (y) \
+                       strncpy((y), "(invalid)", sizeof(y)); \
+               if (z) \
+                       strncpy((z), "(invalid)", sizeof(z)); \
+       } \
+} while (0);
+
+#define GETNAMEINFO_NULL(x, y) \
+do { \
+       if (getnameinfo((x), sysdep_sa_len(x), (y), sizeof(y), NULL, 0, \
+                       NIFLAGS) != 0) { \
+               if (y) \
+                       strncpy((y), "(invalid)", sizeof(y)); \
+       } \
+} while (0);
+
+#include <sys/queue.h>
+#ifndef LIST_FOREACH
+#define LIST_FOREACH(elm, head, field) \
+       for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field))
+#endif
+
+#include "gcmalloc.h"
+
+#endif /*!defined(_VAR_H_)*/
+
+#endif /* _VAR_H */
diff --git a/ipsec-tools/racoon/vendorid.c b/ipsec-tools/racoon/vendorid.c
new file mode 100644 (file)
index 0000000..7a12f5f
--- /dev/null
@@ -0,0 +1,270 @@
+/* $Id: vendorid.c,v 1.7 2005/01/29 16:34:25 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "localconf.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "vendorid.h"
+#include "crypto_openssl.h"
+
+static struct vendor_id all_vendor_ids[] = {
+{ VENDORID_KAME       , "KAME/racoon" },
+{ VENDORID_GSSAPI_LONG, "A GSS-API Authentication Method for IKE" },
+{ VENDORID_GSSAPI     , "GSSAPI" },
+{ VENDORID_MS_NT5     , "MS NT5 ISAKMPOAKLEY" },
+{ VENDORID_NATT_00    , "draft-ietf-ipsec-nat-t-ike-00" },
+{ VENDORID_NATT_01    , "draft-ietf-ipsec-nat-t-ike-01" },
+{ VENDORID_NATT_02    , "draft-ietf-ipsec-nat-t-ike-02" },
+{ VENDORID_NATT_02_N  , "draft-ietf-ipsec-nat-t-ike-02\n" },
+{ VENDORID_NATT_03    , "draft-ietf-ipsec-nat-t-ike-03" },
+{ VENDORID_NATT_04    , "draft-ietf-ipsec-nat-t-ike-04" },
+{ VENDORID_NATT_05    , "draft-ietf-ipsec-nat-t-ike-05" },
+{ VENDORID_NATT_06    , "draft-ietf-ipsec-nat-t-ike-06" },
+{ VENDORID_NATT_07    , "draft-ietf-ipsec-nat-t-ike-07" },
+{ VENDORID_NATT_08    , "draft-ietf-ipsec-nat-t-ike-08" },
+#ifdef __APPLE__
+{ VENDORID_NATT_APPLE , "draft-ietf-ipsec-nat-t-ike" },
+#endif
+{ VENDORID_NATT_RFC   , "RFC 3947" },
+{ VENDORID_XAUTH      , "draft-ietf-ipsra-isakmp-xauth-06.txt" },
+{ VENDORID_UNITY      , "CISCO-UNITY" },
+{ VENDORID_FRAG       , "FRAGMENTATION" },
+/* Just a readable string for DPD ... */
+{ VENDORID_DPD        , "DPD" },
+};
+
+#define NUMVENDORIDS   (sizeof(all_vendor_ids)/sizeof(all_vendor_ids[0]))
+
+#define DPD_MAJOR_VERSION      0x01
+#define DPD_MINOR_VERSION      0x00
+
+const char vendorid_dpd_hash[] = {
+       0xAF, 0xCA, 0xD7, 0x13,
+       0x68, 0xA1, 0xF1, 0xC9,
+       0x6B, 0x86, 0x96, 0xFC,
+       0x77, 0x57, DPD_MAJOR_VERSION, DPD_MINOR_VERSION
+};
+
+
+static vchar_t *vendorid_fixup(int, vchar_t *t);
+
+static struct vendor_id *
+lookup_vendor_id_by_id (int id)
+{
+       int i;
+
+       for (i = 0; i < NUMVENDORIDS; i++)
+               if (all_vendor_ids[i].id == id)
+                       return &all_vendor_ids[i];
+
+       return NULL;
+}
+
+const char *
+vid_string_by_id (int id)
+{
+       struct vendor_id *current;
+
+       if (id == VENDORID_DPD)
+               return vendorid_dpd_hash;
+
+       current = lookup_vendor_id_by_id(id);
+
+       return current ? current->string : NULL;
+}
+
+static struct vendor_id *
+lookup_vendor_id_by_hash (const char *hash)
+{
+       int i;
+       unsigned char *h = (unsigned char *)hash;
+
+       for (i = 0; i < NUMVENDORIDS; i++)
+               if (strncmp(all_vendor_ids[i].hash->v, hash,
+                           all_vendor_ids[i].hash->l) == 0)
+                       return &all_vendor_ids[i];
+
+       return NULL;
+}
+
+void
+compute_vendorids (void)
+{
+       int i;
+       vchar_t vid;
+
+       for (i = 0; i < NUMVENDORIDS; i++) {
+               /* VENDORID_DPD is not a MD5 sum... */
+               if(i == VENDORID_DPD){
+                       all_vendor_ids[i].hash = vmalloc(sizeof(vendorid_dpd_hash));
+                       if (all_vendor_ids[i].hash == NULL) {
+                               plog(LLV_ERROR2, LOCATION, NULL,
+                                       "unable to get memory for VID hash\n");
+                               exit(1); /* this really shouldn't happen */
+                       }
+                       memcpy(all_vendor_ids[i].hash->v, vendorid_dpd_hash,
+                                  sizeof(vendorid_dpd_hash));
+                       continue;
+               }
+
+               vid.v = (char *) all_vendor_ids[i].string;
+               vid.l = strlen(vid.v);
+
+               all_vendor_ids[i].hash = eay_md5_one(&vid);
+               if (all_vendor_ids[i].hash == NULL)
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "unable to hash vendor ID string\n");
+
+               /* Special cases */
+               all_vendor_ids[i].hash =
+                       vendorid_fixup(all_vendor_ids[i].id,
+                                      all_vendor_ids[i].hash);
+       }
+}
+
+/*
+ * set hashed vendor id.
+ * hash function is always MD5.
+ */
+vchar_t *
+set_vendorid(int vendorid)
+{
+       struct vendor_id *current;
+       vchar_t vid, *new;
+
+       if (vendorid == VENDORID_UNKNOWN) {
+               /*
+                * The default unknown ID gets translated to
+                * KAME/racoon.
+                */
+               vendorid = VENDORID_KAME;
+       }
+
+       current = lookup_vendor_id_by_id(vendorid);
+       if (current == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "invalid vendor ID index: %d\n", vendorid);
+               return (NULL);
+       }
+
+       /* The rest of racoon expects a private copy 
+        * of the VID that could be free'd after use.
+        * That's why we don't return the original pointer. */
+       return vdup(current->hash);
+}
+
+/*
+ * Check the vendor ID payload -- return the vendor ID index
+ * if we find a recognized one, or UNKNOWN if we don't.
+ *
+ * gen ... points to Vendor ID payload.
+ */
+int
+check_vendorid(struct isakmp_gen *gen)
+{
+       vchar_t vid, *vidhash;
+       int i, vidlen;
+       struct vendor_id *current;
+
+       if (gen == NULL)
+               return (VENDORID_UNKNOWN);
+
+       vidlen = ntohs(gen->len) - sizeof(*gen);
+
+       current = lookup_vendor_id_by_hash((char *)(gen + 1));
+       if (!current)
+               goto unknown;
+       
+       if (current->hash->l < vidlen)
+               plog(LLV_INFO, LOCATION, NULL,
+                    "received broken Microsoft ID: %s\n",
+                    current->string);
+       else
+               plog(LLV_INFO, LOCATION, NULL,
+                    "received Vendor ID: %s\n",
+                    current->string);
+
+       return current->id;
+
+unknown:
+       plog(LLV_DEBUG, LOCATION, NULL, "received unknown Vendor ID\n");
+       return (VENDORID_UNKNOWN);
+}
+
+static vchar_t * 
+vendorid_fixup(vendorid, vidhash)
+       int vendorid;            
+       vchar_t *vidhash;
+{                         
+       switch(vendorid) {
+       case VENDORID_XAUTH: {  /* The vendor Id is truncated */
+               vchar_t *tmp;                                       
+                                 
+               if ((tmp = vmalloc(8)) == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                           "unable to hash vendor ID string\n");
+                       return NULL;                                
+               }                       
+                 
+               memcpy(tmp->v, vidhash->v, 8);
+               vfree(vidhash);           
+               vidhash = tmp;
+                                  
+               break;
+       } 
+       case VENDORID_UNITY:    /* Two bytes tweak */
+               vidhash->v[14] = 0x01;            
+               vidhash->v[15] = 0x00;
+               break;             
+
+       default:     
+               break;
+       }               
+       
+       return vidhash;
+}                       
diff --git a/ipsec-tools/racoon/vendorid.h b/ipsec-tools/racoon/vendorid.h
new file mode 100644 (file)
index 0000000..d3ecf67
--- /dev/null
@@ -0,0 +1,104 @@
+/* $Id: vendorid.h,v 1.10 2005/01/29 16:34:25 vanhu Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _VENDORID_H
+#define _VENDORID_H
+
+/* The unknown vendor ID. */
+#define        VENDORID_UNKNOWN        -1
+
+/* Our default vendor ID. */
+#define        VENDORID_KAME           0
+
+/*
+ * Refer to draft-ietf-ipsec-isakmp-gss-auth-06.txt.
+ */
+#define        VENDORID_GSSAPI_LONG    1
+#define        VENDORID_GSSAPI         2
+#define        VENDORID_MS_NT5         3
+#define        VENDOR_SUPPORTS_GSSAPI(x)                                       \
+       ((x) == VENDORID_GSSAPI_LONG ||                                 \
+        (x) == VENDORID_GSSAPI ||                                      \
+        (x) == VENDORID_MS_NT5)
+
+/* NAT-T support */
+#define VENDORID_NATT_00       4
+#define VENDORID_NATT_01       5
+#define VENDORID_NATT_02       6
+#define VENDORID_NATT_02_N     7
+#define VENDORID_NATT_03       8
+#define VENDORID_NATT_04       9
+#define VENDORID_NATT_05       10
+#define VENDORID_NATT_06       11
+#define VENDORID_NATT_07       12
+#define VENDORID_NATT_08       13
+
+#ifdef __APPLE__
+#define VENDORID_NATT_APPLE 14
+#define VENDORID_NATT_RFC      15
+/* Hybrid auth */
+#define VENDORID_XAUTH         16
+#define VENDORID_UNITY         17
+/* IKE fragmentation */
+#define VENDORID_FRAG          18
+/* Dead Peer Detection */
+#define VENDORID_DPD           19
+#else /* __APPLE__ */
+#define VENDORID_NATT_RFC      14
+/* Hybrid auth */
+#define VENDORID_XAUTH         15
+#define VENDORID_UNITY         16
+/* IKE fragmentation */
+#define VENDORID_FRAG          17
+/* Dead Peer Detection */
+#define VENDORID_DPD           18
+#endif /* __APPLE__ */
+
+#define VENDORID_NATT_FIRST    VENDORID_NATT_00
+#define VENDORID_NATT_LAST     VENDORID_NATT_RFC
+
+
+#define MAX_NATT_VID_COUNT     (VENDORID_NATT_LAST - VENDORID_NATT_FIRST + 1 )
+
+
+struct vendor_id {
+       int             id;
+       const char      *string;
+       vchar_t         *hash;
+};
+
+vchar_t *set_vendorid __P((int));
+int check_vendorid __P((struct isakmp_gen *));
+
+void compute_vendorids __P((void));
+const char *vid_string_by_id __P((int id));
+
+#endif /* _VENDORID_H */
diff --git a/ipsec-tools/racoon/vmbuf.c b/ipsec-tools/racoon/vmbuf.c
new file mode 100644 (file)
index 0000000..e0204b6
--- /dev/null
@@ -0,0 +1,129 @@
+/*     $KAME: vmbuf.c,v 1.11 2001/11/26 16:54:29 sakane Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#define NONEED_DRM
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "debug.h"
+#include "gcmalloc.h"
+
+vchar_t *
+vmalloc(size)
+       size_t size;
+{
+       vchar_t *var;
+
+       if ((var = (vchar_t *)racoon_malloc(sizeof(*var))) == NULL)
+               return NULL;
+
+       var->l = size;
+       if (size == 0) {
+               var->v = NULL;
+       } else {
+               var->v = (caddr_t)racoon_calloc(1, size);
+               if (var->v == NULL) {
+                       (void)racoon_free(var);
+                       return NULL;
+               }
+       }
+
+       return var;
+}
+
+vchar_t *
+vrealloc(ptr, size)
+       vchar_t *ptr;
+       size_t size;
+{
+       caddr_t v;
+       
+       if (ptr != NULL) {
+               if (ptr->l == 0) {
+                       (void)vfree(ptr);
+                       return vmalloc(size); /* zero-fill it? */
+               }
+
+               if ((v = (caddr_t)racoon_realloc(ptr->v, size)) == NULL) {
+                       (void)vfree(ptr);
+                       return NULL;
+               }
+
+               if ( size > ptr->l)
+                       memset(v + ptr->l, 0, size - ptr->l);
+               ptr->v = v;
+               ptr->l = size;
+       } else {
+               if ((ptr = vmalloc(size)) == NULL)
+                       return NULL;
+       }
+
+       return ptr;
+}
+
+void
+vfree(var)
+       vchar_t *var;
+{
+       if (var == NULL)
+               return;
+
+       if (var->v)
+               (void)racoon_free(var->v);
+
+       (void)racoon_free(var);
+
+       return;
+}
+
+vchar_t *
+vdup(src)
+       vchar_t *src;
+{
+       vchar_t *new;
+
+       if ((new = vmalloc(src->l)) == NULL)
+               return NULL;
+
+       memcpy(new->v, src->v, src->l);
+
+       return new;
+}
diff --git a/ipsec-tools/racoon/vmbuf.h b/ipsec-tools/racoon/vmbuf.h
new file mode 100644 (file)
index 0000000..5191be9
--- /dev/null
@@ -0,0 +1,68 @@
+/* $Id: vmbuf.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _VMBUF_H
+#define _VMBUF_H
+
+#include <sys/types.h>
+
+/*
+ *     bp      v
+ *     v       v
+ *     ........................
+ *             <--------------> l
+ *     <----------------------> bl
+ */
+typedef struct _vchar_t_ {
+#if notyet
+       u_int32_t t;    /* type of the value */
+       vchar_t *n;     /* next vchar_t buffer */
+       size_t bl;      /* length of the buffer */
+       caddr_t bp;     /* pointer to the buffer */
+#endif
+       size_t l;       /* length of the value */
+       caddr_t v;      /* place holder to the pointer to the value */
+} vchar_t;
+
+#define VPTRINIT(p) \
+do { \
+       if (p) { \
+               vfree(p); \
+               (p) = NULL; \
+       } \
+} while(0);
+
+extern vchar_t *vmalloc __P((size_t));
+extern vchar_t *vrealloc __P((vchar_t *, size_t));
+extern void vfree __P((vchar_t *));
+extern vchar_t *vdup __P((vchar_t *));
+
+#endif /* _VMBUF_H */
diff --git a/ipsec-tools/racoon/vpn_control.c b/ipsec-tools/racoon/vpn_control.c
new file mode 100644 (file)
index 0000000..f3217a0
--- /dev/null
@@ -0,0 +1,516 @@
+/* $Id: vpn_control.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */
+
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <System/net/pfkeyv2.h>
+
+#include <netinet/in.h>
+#ifndef HAVE_NETINET6_IPSEC
+#include <netinet/ipsec.h>
+#else 
+#include <netinet6/ipsec.h>
+#endif
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "debug.h"
+
+#include "schedule.h"
+#include "localconf.h"
+#include "remoteconf.h"
+#include "grabmyaddr.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "oakley.h"
+#include "handler.h"
+#include "evt.h"
+#include "pfkey.h"
+#include "ipsec_doi.h"
+#include "vpn_control.h"
+#include "vpn_control_var.h"
+#include "isakmp_inf.h"
+#include "session.h"
+#include "gcmalloc.h"
+
+#ifdef ENABLE_VPNCONTROL_PORT
+char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
+uid_t vpncontrolsock_owner = 0;
+gid_t vpncontrolsock_group = 0;
+mode_t vpncontrolsock_mode = 0600;
+
+static struct sockaddr_un sunaddr;
+static int vpncontrol_process(struct vpnctl_socket_elem *, char *);
+static int vpncontrol_reply(int, char *);
+static void vpncontrol_close_comm(struct vpnctl_socket_elem *);
+
+int
+vpncontrol_handler()
+{
+       struct sockaddr_storage from;
+       socklen_t fromlen = sizeof(from);
+
+       struct vpnctl_socket_elem *sock_elem;
+       
+       sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
+       if (sock_elem == NULL) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "memory error: %s\n", strerror(errno));
+               return -1;
+       }
+       LIST_INIT(&sock_elem->bound_addresses);
+
+       sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
+       if (sock_elem->sock < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to accept vpn_control command: %s\n", strerror(errno));
+               racoon_free(sock_elem);
+               return -1;
+       }
+       LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
+       plog(LLV_NOTIFY, LOCATION, NULL,
+               "accepted connection on vpn control socket.\n");
+               
+       check_auto_exit();
+               
+       return 0;
+}
+
+int
+vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
+{
+       struct vpnctl_hdr hdr;
+       char *combuf = NULL;
+       int len;
+
+       /* get buffer length */
+       while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to recv vpn_control command: %s\n", strerror(errno));
+               goto end;
+       }
+       if (len == 0) {
+               plog(LLV_NOTIFY, LOCATION, NULL,
+                       "vpn_control socket closed by peer.\n");
+               vpncontrol_close_comm(elem);
+               return -1;
+       }
+               
+       /* sanity check */
+       if (len < sizeof(hdr)) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "invalid header length of vpn_control command - len=%d - expected %d\n", len, sizeof(hdr));
+               goto end;
+       }
+
+       /* get buffer to receive */
+       if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to alloc buffer for vpn_control command\n");
+               goto end;
+       }
+
+       /* get real data */
+       while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to recv vpn_control command: %s\n",
+                       strerror(errno));
+               goto end;
+       }
+
+       (void)vpncontrol_process(elem, combuf);
+
+end:
+       if (combuf)
+               racoon_free(combuf);
+       return 0;               // return -1 only if a socket is closed
+}
+
+static int
+vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
+{
+       u_int16_t       error = 0;
+       struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf;
+
+       switch (ntohs(hdr->msg_type)) {
+       
+               case VPNCTL_CMD_BIND:
+                       {
+                               struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf;
+                               struct bound_addr *addr;
+                       
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "received bind command on vpn control socket.\n");
+                               addr = racoon_malloc(sizeof(struct bound_addr));
+                               if (addr == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL, 
+                                               "memory error: %s\n", strerror(errno));
+                                       error = -1;
+                                       break;
+                               }
+                               addr->address = pkt->address;
+                               LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
+                               lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT;     /* client side */
+                       }
+                       break;
+                       
+               case VPNCTL_CMD_UNBIND:
+                       {
+                               struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
+                               struct bound_addr *addr;
+                               struct bound_addr *t_addr;
+
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "received unbind command on vpn control socket.\n");
+                               LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+                                       if (pkt->address == 0xFFFFFFFF ||
+                                               pkt->address == addr->address) {
+                                               LIST_REMOVE(addr, chain);
+                                               racoon_free(addr);
+                                       }
+                               }
+                       }
+                       break;
+
+               case VPNCTL_CMD_REDIRECT:
+                       {
+                               struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
+                               struct redirect *raddr;
+                               struct redirect *t_raddr;
+                               int found = 0;
+                               
+                               plog(LLV_DEBUG, LOCATION, NULL,
+                                       "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
+                               
+                               LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
+                                       if (raddr->cluster_address == redirect_msg->address) {
+                                               if (redirect_msg->redirect_address == 0) {
+                                                       LIST_REMOVE(raddr, chain);
+                                                       racoon_free(raddr);
+                                               } else {
+                                                       raddr->redirect_address = redirect_msg->redirect_address;
+                                                       raddr->force = ntohs(redirect_msg->force);
+                                               }
+                                               found = 1;
+                                               break;
+                                       }
+                               }
+                               if (!found) {
+                                       raddr = racoon_malloc(sizeof(struct redirect));
+                                       if (raddr == NULL) {
+                                               plog(LLV_DEBUG, LOCATION, NULL,
+                                                       "cannot allcoate memory for redirect address.\n");                                      
+                                               error = -1;
+                                               break;
+                                       }
+                                       raddr->cluster_address = redirect_msg->address;
+                                       raddr->redirect_address = redirect_msg->redirect_address;
+                                       raddr->force = ntohs(redirect_msg->force);
+                                       LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
+                                       
+                               }
+                       }
+                       break;
+                       
+               case VPNCTL_CMD_PING:
+                       break;  // just reply for now
+
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "invalid command: %d\n", ntohs(hdr->msg_type));
+                       error = -1;             // for now
+                       break;
+       }
+
+       hdr->len = 0;
+       hdr->result = htons(error);
+       if (vpncontrol_reply(elem->sock, combuf) < 0)
+               return -1;
+
+       return 0;
+
+}
+
+static int
+vpncontrol_reply(int so, char *combuf)
+{
+       size_t tlen;
+
+       tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
+       if (tlen < 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "failed to send vpn_control message: %s\n", strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t address, u_int16_t data_len, u_int8_t *data)
+{
+       struct vpnctl_status_failed *msg; 
+       struct vpnctl_socket_elem *sock_elem;
+       struct bound_addr *bound_addr;
+       size_t tlen, len;
+       
+       len = sizeof(struct vpnctl_status_failed) + data_len;
+       
+       msg = (struct vpnctl_status_failed *)racoon_malloc(len);
+       if (msg == NULL) {
+               plog(LLV_DEBUG, LOCATION, NULL,
+                               "unable to allcate memory for vpn control status message.\n");
+               return -1;
+       }
+               
+       msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
+       msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
+       msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
+       msg->address = address;
+       msg->ike_code = htons(notify_code);
+       msg->from = htons(from);
+       if (data_len > 0)
+               memcpy(msg->data, data, data_len);      
+       plog(LLV_DEBUG, LOCATION, NULL,
+                       "sending vpn_control ike notify failed message - code=%d  from=%s.\n", notify_code,
+                                       (from == FROM_LOCAL ? "local" : "remote"));
+
+       LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
+               LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
+                       if (bound_addr->address == 0xFFFFFFFF ||
+                               bound_addr->address == address) {
+                               tlen = send(sock_elem->sock, msg, len, 0);
+                               if (tlen < 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "unable to send vpn_control ike notify failed: %s\n", strerror(errno));
+                               }
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+
+int
+vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1, struct ph2handle *iph2)
+{
+       struct vpnctl_status_phase_change msg; 
+       struct vpnctl_socket_elem *sock_elem;
+       struct bound_addr *bound_addr;
+       size_t tlen;    
+       u_int32_t address;
+               
+       if (iph1) {
+               if (iph1->remote->sa_family == AF_INET)
+                       address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
+               else
+                       return 0;               // for now
+               msg.hdr.msg_type = htons(start ? 
+                       (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER) 
+                       : VPNCTL_STATUS_PH1_ESTABLISHED);
+       } else {
+               if (iph2->dst->sa_family == AF_INET)
+                       address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
+               else
+                       return 0;               // for now
+               msg.hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
+       }
+       msg.hdr.flags = msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
+       msg.hdr.len = htons(sizeof(struct vpnctl_status_phase_change) - sizeof(struct vpnctl_hdr));
+       msg.address = address;
+
+       LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
+               LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
+                       if (bound_addr->address == 0xFFFFFFFF ||
+                               bound_addr->address == address) {
+                               tlen = send(sock_elem->sock, &msg, sizeof(struct vpnctl_status_phase_change), 0);
+                               if (tlen < 0) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "failed to send vpn_control phase change status: %s\n", strerror(errno));
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+int
+vpncontrol_init()
+{
+       if (vpncontrolsock_path == NULL) {
+               lcconf->sock_vpncontrol = -1;
+               return 0;
+       }
+
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
+               "%s", vpncontrolsock_path);
+
+       lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (lcconf->sock_vpncontrol == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "socket: %s\n", strerror(errno));
+               return -1;
+       }
+
+       unlink(sunaddr.sun_path);
+       if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
+                       sizeof(sunaddr)) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "bind(sockname:%s): %s\n",
+                       sunaddr.sun_path, strerror(errno));
+               (void)close(lcconf->sock_vpncontrol);
+               return -1;
+       }
+
+       if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "chown(%s, %d, %d): %s\n", 
+                   sunaddr.sun_path, vpncontrolsock_owner, 
+                   vpncontrolsock_group, strerror(errno));
+               (void)close(lcconf->sock_vpncontrol);
+               return -1;
+       }
+
+       if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL, 
+                   "chmod(%s, 0%03o): %s\n", 
+                   sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
+               (void)close(lcconf->sock_vpncontrol);
+               return -1;
+       }
+
+       if (listen(lcconf->sock_vpncontrol, 5) != 0) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                       "listen(sockname:%s): %s\n",
+                       sunaddr.sun_path, strerror(errno));
+               (void)close(lcconf->sock_vpncontrol);
+               return -1;
+       }
+       plog(LLV_DEBUG, LOCATION, NULL,
+               "opened %s as racoon management.\n", sunaddr.sun_path);
+
+       return 0;
+}
+
+
+void
+vpncontrol_close()
+{
+       struct vpnctl_socket_elem *elem;
+       struct vpnctl_socket_elem *t_elem;
+       
+       if (lcconf->sock_vpncontrol != -1) {
+               close(lcconf->sock_vpncontrol);
+               lcconf->sock_vpncontrol = -1;
+       }
+       LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
+               vpncontrol_close_comm(elem);
+}
+
+static void
+vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
+{
+       struct bound_addr *addr;
+       struct bound_addr *t_addr;
+       
+       LIST_REMOVE(elem, chain);
+       if (elem->sock != -1)   
+               close(elem->sock);
+       LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+               LIST_REMOVE(addr, chain);
+               racoon_free(addr);
+       }
+       racoon_free(elem);
+       check_auto_exit();
+}
+
+int
+vpn_control_connected(void)
+{
+       if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
+               return 0;
+       else
+               return 1;
+}
+
+#endif
diff --git a/ipsec-tools/racoon/vpn_control.h b/ipsec-tools/racoon/vpn_control.h
new file mode 100644 (file)
index 0000000..cabbb16
--- /dev/null
@@ -0,0 +1,172 @@
+/* $Id: vpn_control.h,v 1.10 2004/12/30 13:45:49 manubsd Exp $ */
+
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _VPN_CONTROL_H
+#define _VPN_CONTROL_H
+
+#define VPNCONTROLSOCK_PATH ADMINPORTDIR "/vpncontrol.sock"
+
+#define FROM_LOCAL     0
+#define FROM_REMOTE 1
+
+extern char *vpncontrolsock_path;
+extern uid_t vpncontrolsock_owner;
+extern gid_t vpncontrolsock_group;
+extern mode_t vpncontrolsock_mode;
+
+
+/*
+ * message types
+ */
+#define VPNCTL_CMD_BIND                                        0x0001
+#define VPNCTL_CMD_UNBIND                              0x0002
+#define VPNCTL_CMD_REDIRECT                            0x0003
+#define VPNCTL_CMD_PING                                        0x0004
+#define VPNCTL_STATUS_IKE_FAILED               0x8001
+#define VPNCTL_STATUS_PH1_START_US             0x8011
+#define VPNCTL_STATUS_PH1_START_PEER   0x8012
+#define VPNCTL_STATUS_PH1_ESTABLISHED  0x8013
+#define VPNCTL_STATUS_PH2_START                        0x8021
+#define VPNCTL_STATUS_PH2_ESTABLISHED  0x8022
+
+
+/* commands and status for vpn control. */
+/* network byte order. */
+
+/* Packet header */
+struct vpnctl_hdr {
+       u_int16_t                       msg_type;
+       u_int16_t                       flags;          
+       u_int32_t                       cookie;
+       u_int32_t                       reserved;
+       u_int16_t                       result; 
+       u_int16_t                       len;                    /* payload length */    
+};
+
+/* Packet formats for commands */
+
+/* bind to receive status for specified address */
+struct vpnctl_cmd_bind {
+       struct vpnctl_hdr               hdr;
+       u_int32_t                               address;        /* 0xFFFFFFFF = all */
+};
+
+/* unbind to stop receiving status for specified address */
+struct vpnctl_cmd_unbind {
+       struct vpnctl_hdr               hdr;
+       u_int32_t                               address;        /* 0xFFFFFFFF = all */
+};
+
+/* redirect client to specified address */
+struct vpnctl_cmd_redirect {
+       struct vpnctl_hdr               hdr;
+       u_int32_t                               address;
+       u_int32_t                               redirect_address;
+       u_int16_t                               force;
+};
+
+
+/*
+ * IKE Notify codes - mirrors codes in isakmp.h
+ */
+#define VPNCTL_NTYPE_INVALID_PAYLOAD_TYPE              1
+#define VPNCTL_NTYPE_DOI_NOT_SUPPORTED                 2
+#define VPNCTL_NTYPE_SITUATION_NOT_SUPPORTED   3
+#define VPNCTL_NTYPE_INVALID_COOKIE                            4
+#define VPNCTL_NTYPE_INVALID_MAJOR_VERSION             5
+#define VPNCTL_NTYPE_INVALID_MINOR_VERSION             6
+#define VPNCTL_NTYPE_INVALID_EXCHANGE_TYPE             7
+#define VPNCTL_NTYPE_INVALID_FLAGS                             8
+#define VPNCTL_NTYPE_INVALID_MESSAGE_ID                        9
+#define VPNCTL_NTYPE_INVALID_PROTOCOL_ID               10
+#define VPNCTL_NTYPE_INVALID_SPI                               11
+#define VPNCTL_NTYPE_INVALID_TRANSFORM_ID              12
+#define VPNCTL_NTYPE_ATTRIBUTES_NOT_SUPPORTED  13
+#define VPNCTL_NTYPE_NO_PROPOSAL_CHOSEN                        14
+#define VPNCTL_NTYPE_BAD_PROPOSAL_SYNTAX               15
+#define VPNCTL_NTYPE_PAYLOAD_MALFORMED                 16
+#define VPNCTL_NTYPE_INVALID_KEY_INFORMATION   17
+#define VPNCTL_NTYPE_INVALID_ID_INFORMATION            18
+#define VPNCTL_NTYPE_INVALID_CERT_ENCODING             19
+#define VPNCTL_NTYPE_INVALID_CERTIFICATE               20
+#define VPNCTL_NTYPE_BAD_CERT_REQUEST_SYNTAX   21
+#define VPNCTL_NTYPE_INVALID_CERT_AUTHORITY            22
+#define VPNCTL_NTYPE_INVALID_HASH_INFORMATION  23
+#define VPNCTL_NTYPE_AUTHENTICATION_FAILED             24
+#define VPNCTL_NTYPE_INVALID_SIGNATURE                 25
+#define VPNCTL_NTYPE_ADDRESS_NOTIFICATION              26
+#define VPNCTL_NTYPE_NOTIFY_SA_LIFETIME                        27
+#define VPNCTL_NTYPE_CERTIFICATE_UNAVAILABLE   28
+#define VPNCTL_NTYPE_UNSUPPORTED_EXCHANGE_TYPE 29
+#define VPNCTL_NTYPE_UNEQUAL_PAYLOAD_LENGTHS   30
+#define VPNCTL_NTYPE_LOAD_BALANCE                              40501
+#define VPNCTL_NTYPE_INTERNAL_ERROR                            -1
+
+
+/* packet format for phase change status */
+struct vpnctl_status_phase_change {
+       struct vpnctl_hdr                       hdr;
+       u_int32_t                                       address;
+};
+
+/* Packet formats for failed status */
+struct vpnctl_status_failed {
+       struct vpnctl_hdr                       hdr;
+       u_int32_t                                       address;
+       u_int16_t                                       ike_code;
+       u_int16_t                                       from;
+       u_int8_t                                        data[0];
+};
+
+
+#endif /* _VPN_CONTROL_H */
diff --git a/ipsec-tools/racoon/vpn_control_var.h b/ipsec-tools/racoon/vpn_control_var.h
new file mode 100644 (file)
index 0000000..59ad69e
--- /dev/null
@@ -0,0 +1,65 @@
+/* $Id: vpn_control_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp $ */
+
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _VPN_CONTROL_VAR_H
+#define _VPN_CONTROL_VAR_H
+
+extern int vpncontrol_handler __P((void));
+extern int vpncontrol_comm_handler __P((struct vpnctl_socket_elem *));
+extern int vpncontrol_notify_ike_failed __P((u_int16_t, u_int16_t, u_int32_t, u_int16_t, u_int8_t*));
+extern int vpncontrol_notify_phase_change __P((int, u_int16_t, struct ph1handle*, struct ph2handle*));
+extern int vpncontrol_init __P((void));
+extern void vpncontrol_close __P((void));
+extern int vpn_control_connected __P((void));
+
+#endif /* _VPN_CONTROL_VAR_H */
diff --git a/ipsec-tools/setkey/Sample/sample-policy01.cf b/ipsec-tools/setkey/Sample/sample-policy01.cf
new file mode 100644 (file)
index 0000000..42c16b2
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# This is for basic policy test on loopback.
+#
+
+spdflush;
+spdadd 127.0.0.1 127.0.0.1 icmp
+       -P out ipsec
+       esp/transport//require ;
+spdadd ::1 ::1 icmp6
+       -P out ipsec
+       esp/transport//require ;
+
+flush;
+add 127.0.0.1 127.0.0.1 esp 0x1000
+       -m transport
+       -E des-cbc "kamekame";
+add ::1 ::1 esp 0x1001
+       -m transport
+       -E des-cbc "hagehage";
+flush;
diff --git a/ipsec-tools/setkey/Sample/sample-policy02.cf b/ipsec-tools/setkey/Sample/sample-policy02.cf
new file mode 100644 (file)
index 0000000..8c5134a
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# this is test configuration for unique policy on loopback.
+#
+
+spdflush;
+# connection to 9999 encrypted, reverse no encrypted.
+spdadd ::1 ::1[9999] tcp
+       -P out ipsec
+       esp/transport//unique:2 ;
+
+# Session encrypted.  Inbound policy check takes place non-strictly.
+spdadd ::1 ::1[9998] tcp
+       -P out ipsec
+       esp/transport//unique:1 ;
+spdadd ::1[9998] ::1 tcp
+       -P in ipsec
+       esp/transport//unique:2 ;
+spdadd ::1[9998] ::1 tcp
+       -P out ipsec
+       esp/transport//unique:1 ;
+
+# Cause new SA to be acquired.
+spdadd ::1 ::1[9997] tcp
+       -P out ipsec
+       esp/transport//unique ;
+
+# Used proper SA.
+spdadd ::1 ::1[9996] tcp
+       -P out ipsec
+       esp/transport//require ;
+
+# reqid will be updated by kernel.
+spdadd ::1 ::1[9995] tcp
+       -P out ipsec
+       esp/transport//unique:28000 ;
+
+flush;
+add ::1 ::1 esp 0x1001
+       -u 1
+       -E des-cbc "kamekame";
+add ::1 ::1 esp 0x1002
+       -u 2
+       -E des-cbc "hogehoge";
diff --git a/ipsec-tools/setkey/Sample/sample.cf b/ipsec-tools/setkey/Sample/sample.cf
new file mode 100644 (file)
index 0000000..c64fd36
--- /dev/null
@@ -0,0 +1,217 @@
+# Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+
+# There are sample scripts for IPsec configuration by manual keying.
+# A security association is uniquely identified by a triple consisting
+# of a Security Parameter Index (SPI), an IP Destination Address, and a
+# security protocol (AH or ESP) identifier.  You must take care of these
+# parameters when you configure by manual keying.
+
+# ESP transport mode is recommended for TCP port number 110 between
+# Host-A and Host-B. Encryption algorithm is blowfish-cbc whose key
+# is "kamekame", and authentication algorithm is hmac-sha1 whose key
+# is "this is the test key".
+#
+#       ============ ESP ============
+#       |                           |
+#    Host-A                        Host-B
+#   fec0::10 -------------------- fec0::11
+#
+# At Host-A and Host-B,
+spdadd fec0::10[any] fec0::11[110] tcp -P out ipsec
+       esp/transport//use ;
+spdadd fec0::11[110] fec0::10[any] tcp -P in ipsec
+       esp/transport//use ;
+add fec0::10 fec0::11 esp 0x10001
+       -m transport
+       -E blowfish-cbc "kamekame"
+       -A hmac-sha1 "this is the test key" ;
+add fec0::11 fec0::10 esp 0x10002
+       -m transport
+       -E blowfish-cbc "kamekame"
+       -A hmac-sha1 "this is the test key" ;
+
+# "[any]" is wildcard of port number.  Note that "[0]" is the number of
+# zero in port number.
+
+# Security protocol is old AH tunnel mode, i.e. RFC1826, with keyed-md5
+# whose key is "this is the test" as authentication algorithm.
+# That protocol takes place between Gateway-A and Gateway-B.
+#
+#                        ======= AH =======
+#                        |                |
+#    Network-A       Gateway-A        Gateway-B        Network-B
+#   10.0.1.0/24 ---- 172.16.0.1 ----- 172.16.0.2 ---- 10.0.2.0/24
+#
+# At Gateway-A:
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec
+       ah/tunnel/172.16.0.1-172.16.0.2/require ;
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec
+       ah/tunnel/172.16.0.2-172.16.0.1/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+       -m any
+       -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+       -m any
+       -A keyed-md5 "this is the test" ;
+
+# If port number field is omitted such above then "[any]" is employed.
+# -m specifies the mode of SA to be used.  "-m any" means wildcard of
+# mode of security protocol.  You can use this SAs for both tunnel and
+# transport mode.
+
+# At Gateway-B.  Attention to the selector and peer's IP address for tunnel.
+spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec
+       ah/tunnel/172.16.0.2-172.16.0.1/require ;
+spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec
+       ah/tunnel/172.16.0.1-172.16.0.2/require ;
+add 172.16.0.1 172.16.0.2 ah-old 0x10003
+       -m tunnel
+       -A keyed-md5 "this is the test" ;
+add 172.16.0.2 172.16.0.1 ah-old 0x10004
+       -m tunnel
+       -A keyed-md5 "this is the test" ;
+
+# AH transport mode followed by ESP tunnel mode is required between
+# Gateway-A and Gateway-B.
+# Encryption algorithm is 3des-cbc, and authentication algorithm for ESP
+# is hmac-sha1.  Authentication algorithm for AH is hmac-md5.
+#
+#                           ========== AH =========
+#                           |  ======= ESP =====  |
+#                           |  |               |  |
+#      Network-A          Gateway-A        Gateway-B           Network-B
+#   fec0:0:0:1::/64 --- fec0:0:0:1::1 ---- fec0:0:0:2::1 --- fec0:0:0:2::/64
+#
+# At Gateway-A:
+spdadd fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out ipsec
+       esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require
+       ah/transport//require ;
+spdadd fec0:0:0:2::/64 fec0:0:0:1::/64 any -P in ipsec
+       esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require
+       ah/transport//require ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10001
+       -m tunnel
+       -E 3des-cbc "kamekame12341234kame1234"
+       -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 ah 0x10001
+       -m transport
+       -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10001
+       -m tunnel
+       -E 3des-cbc "kamekame12341234kame1234"
+       -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 ah 0x10001
+       -m transport
+       -A hmac-md5 "this is the test" ;
+
+# ESP tunnel mode is required between Host-A and Gateway-A.
+# Encryption algorithm is cast128-cbc, and authentication algorithm
+# for ESP is hmac-sha1.
+# ESP transport mode is recommended between Host-A and Host-B.
+# Encryption algorithm is rc5-cbc,  and authentication algorithm
+# for ESP is hmac-md5.
+#
+#       ================== ESP =================
+#       |  ======= ESP =======                 |
+#       |  |                 |                 |
+#      Host-A            Gateway-A           Host-B
+#   fec0:0:0:1::1 ---- fec0:0:0:2::1 ---- fec0:0:0:2::2
+#
+# At Host-A:
+spdadd fec0:0:0:1::1[any] fec0:0:0:2::2[80] tcp -P out ipsec
+       esp/transport//use
+       esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require ;
+spdadd fec0:0:0:2::1[80] fec0:0:0:1::1[any] tcp -P in ipsec
+       esp/transport//use
+       esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require ;
+add fec0:0:0:1::1 fec0:0:0:2::2 esp 0x10001
+       -m transport
+       -E cast128-cbc "12341234"
+       -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10002
+       -E rc5-cbc "kamekame"
+       -A hmac-md5 "this is the test" ;
+add fec0:0:0:2::2 fec0:0:0:1::1 esp 0x10003
+       -m transport
+       -E cast128-cbc "12341234"
+       -A hmac-sha1 "this is the test key" ;
+add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10004
+       -E rc5-cbc "kamekame"
+       -A hmac-md5 "this is the test" ;
+
+# By "get" command, you can get a entry of either SP or SA.
+get fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# Also delete command, you can delete a entry of either SP or SA.
+spddelete fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out;
+delete fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ;
+
+# By dump command, you can dump all entry of either SP or SA.
+dump ;
+spddump ;
+dump esp ;
+flush esp ;
+
+# By flush command, you can flush all entry of either SP or SA.
+flush ;
+spdflush ;
+
+# "flush" and "dump" commands can specify a security protocol.
+dump esp ;
+flush ah ;
+
+# XXX
+add ::1 ::1 esp 10001 -m transport -E null ;
+add ::1 ::1 esp 10002 -m transport -E des-deriv "12341234" ;
+add ::1 ::1 esp-old 10003 -m transport -E des-32iv "12341234" ;
+add ::1 ::1 esp 10004 -m transport -E null -A null ;
+add ::1 ::1 esp 10005 -m transport -E null -A hmac-md5 "1234123412341234" ;
+add ::1 ::1 esp 10006 -m tunnel -E null -A hmac-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10007 -m transport -E null -A keyed-md5 "1234123412341234" ;
+add ::1 ::1 esp 10008 -m any -E null -A keyed-sha1 "12341234123412341234" ;
+add ::1 ::1 esp 10009 -m transport -E des-cbc "testtest" ;
+add ::1 ::1 esp 10010 -m transport -E 3des-cbc "testtest12341234testtest" ;
+add ::1 ::1 esp 10011 -m tunnel -E cast128-cbc "testtest1234" ;
+add ::1 ::1 esp 10012 -m tunnel -E blowfish-cbc "testtest1234" ;
+add ::1 ::1 esp 10013 -m tunnel -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10014 -m any -E rc5-cbc "testtest1234" ;
+add ::1 ::1 esp 10015 -m transport -f zero-pad -E null ;
+add ::1 ::1 esp 10016 -m tunnel -f random-pad -r 8 -lh 100 -ls 80 -E null ;
+add ::1 ::1 esp 10017 -m transport -f seq-pad -f nocyclic-seq -E null ;
+add ::1 ::1 esp 10018 -m transport -E null ;
+#add ::1 ::1 ah 20000 -m transport -A null ;
+add ::1 ::1 ah 20001 -m any -A hmac-md5 "1234123412341234";
+add ::1 ::1 ah 20002 -m tunnel -A hmac-sha1 "12341234123412341234";
+add ::1 ::1 ah 20003 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah-old 20004 -m transport -A keyed-md5 "1234123412341234";
+add ::1 ::1 ah 20005 -m transport -A keyed-sha1 "12341234123412341234";
+#add ::1 ::1 ipcomp 30000 -C oui ;
+add ::1 ::1 ipcomp 30001 -C deflate ;
+#add ::1 ::1 ipcomp 30002 -C lzs ;
+
+# enjoy.
diff --git a/ipsec-tools/setkey/extern.h b/ipsec-tools/setkey/extern.h
new file mode 100644 (file)
index 0000000..3a8a751
--- /dev/null
@@ -0,0 +1,28 @@
+
+
+void parse_init __P((void));
+int parse __P((FILE **));
+int parse_string __P((char *));
+
+int setkeymsg __P((char *, size_t *));
+int sendkeymsg __P((char *, size_t));
+
+int yylex __P((void));
+int yyparse __P((void));
+void yyfatal __P((const char *));
+void yyerror __P((const char *));
+
+extern int f_rfcmode;
+extern int lineno;
+extern int last_msg_type;
+extern u_int32_t last_priority;
+extern int exit_now;
+
+extern u_char m_buf[BUFSIZ];
+extern u_int m_len;
+extern int f_debug;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+extern int last_msg_type;
+extern u_int32_t last_priority;
+#endif
diff --git a/ipsec-tools/setkey/parse.y b/ipsec-tools/setkey/parse.y
new file mode 100644 (file)
index 0000000..6b99dea
--- /dev/null
@@ -0,0 +1,1539 @@
+/*     $KAME: parse.y,v 1.81 2003/07/01 04:01:48 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+%{
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "libpfkey.h"
+#include "vchar.h"
+#include "extern.h"
+
+#define DEFAULT_NATT_PORT      4500
+
+#ifndef UDP_ENCAP_ESPINUDP
+#define UDP_ENCAP_ESPINUDP     2
+#endif
+
+#define ATOX(c) \
+  (isdigit((int)c) ? (c - '0') : \
+    (isupper((int)c) ? (c - 'A' + 10) : (c - 'a' + 10)))
+
+u_int32_t p_spi;
+u_int p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode;
+u_int32_t p_reqid;
+u_int p_key_enc_len, p_key_auth_len;
+const char *p_key_enc;
+const char *p_key_auth;
+time_t p_lt_hard, p_lt_soft;
+size_t p_lb_hard, p_lb_soft;
+
+static u_int p_natt_type;
+static struct addrinfo * p_natt_oa = NULL;
+
+static int p_aiflags = 0, p_aifamily = PF_UNSPEC;
+
+static struct addrinfo *parse_addr __P((char *, char *));
+static int fix_portstr __P((vchar_t *, vchar_t *, vchar_t *));
+static int setvarbuf __P((char *, int *, struct sadb_ext *, int, 
+    const void *, int));
+void parse_init __P((void));
+void free_buffer __P((void));
+
+int setkeymsg0 __P((struct sadb_msg *, unsigned int, unsigned int, size_t));
+static int setkeymsg_spdaddr __P((unsigned int, unsigned int, vchar_t *,
+       struct addrinfo *, int, struct addrinfo *, int));
+static int setkeymsg_spdaddr_tag __P((unsigned int, char *, vchar_t *));
+static int setkeymsg_addr __P((unsigned int, unsigned int,
+       struct addrinfo *, struct addrinfo *, int));
+static int setkeymsg_add __P((unsigned int, unsigned int,
+       struct addrinfo *, struct addrinfo *));
+%}
+
+%union {
+       int num;
+       unsigned long ulnum;
+       vchar_t val;
+       struct addrinfo *res;
+}
+
+%token EOT SLASH BLCL ELCL
+%token ADD GET DELETE DELETEALL FLUSH DUMP EXIT
+%token PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP
+%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
+%token F_MODE MODE F_REQID
+%token F_EXT EXTENSION NOCYCLICSEQ
+%token ALG_AUTH ALG_AUTH_NOKEY
+%token ALG_ENC ALG_ENC_NOKEY ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD
+%token ALG_COMP
+%token F_LIFETIME_HARD F_LIFETIME_SOFT
+%token F_LIFEBYTE_HARD F_LIFEBYTE_SOFT
+%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY
+       /* SPD management */
+%token SPDADD SPDDELETE SPDDUMP SPDFLUSH
+%token F_POLICY PL_REQUESTS
+%token F_AIFLAGS
+%token TAGGED
+
+%type <num> prefix protocol_spec upper_spec
+%type <num> ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD ALG_ENC_NOKEY
+%type <num> ALG_AUTH ALG_AUTH_NOKEY
+%type <num> ALG_COMP
+%type <num> PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP
+%type <num> EXTENSION MODE
+%type <ulnum> DECSTRING
+%type <val> PL_REQUESTS portstr key_string
+%type <val> policy_requests
+%type <val> QUOTEDSTRING HEXSTRING STRING
+%type <val> F_AIFLAGS
+%type <val> upper_misc_spec policy_spec
+%type <res> ipaddr ipandport
+
+%%
+commands
+       :       /*NOTHING*/
+       |       commands command
+               {
+                       free_buffer();
+                       parse_init();
+               }
+       ;
+
+command
+       :       add_command
+       |       get_command
+       |       delete_command
+       |       deleteall_command
+       |       flush_command
+       |       dump_command
+       |       exit_command
+       |       spdadd_command
+       |       spddelete_command
+       |       spddump_command
+       |       spdflush_command
+       ;
+       /* commands concerned with management, there is in tail of this file. */
+
+       /* add command */
+add_command
+       :       ADD ipaddropts ipandport ipandport protocol_spec spi extension_spec algorithm_spec EOT
+               {
+                       int status;
+
+                       status = setkeymsg_add(SADB_ADD, $5, $3, $4);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+       /* delete */
+delete_command
+       :       DELETE ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT
+               {
+                       int status;
+
+                       if ($3->ai_next || $4->ai_next) {
+                               yyerror("multiple address specified");
+                               return -1;
+                       }
+                       if (p_mode != IPSEC_MODE_ANY)
+                               yyerror("WARNING: mode is obsolete");
+
+                       status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 0);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+       /* deleteall command */
+deleteall_command
+       :       DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT
+               {
+                       int status;
+
+                       status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+       /* get command */
+get_command
+       :       GET ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT
+               {
+                       int status;
+
+                       if (p_mode != IPSEC_MODE_ANY)
+                               yyerror("WARNING: mode is obsolete");
+
+                       status = setkeymsg_addr(SADB_GET, $5, $3, $4, 0);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+       /* flush */
+flush_command
+       :       FLUSH protocol_spec EOT
+               {
+                       struct sadb_msg msg;
+                       setkeymsg0(&msg, SADB_FLUSH, $2, sizeof(msg));
+                       sendkeymsg((char *)&msg, sizeof(msg));
+               }
+       ;
+
+       /* dump */
+dump_command
+       :       DUMP protocol_spec EOT
+               {
+                       struct sadb_msg msg;
+                       setkeymsg0(&msg, SADB_DUMP, $2, sizeof(msg));
+                       sendkeymsg((char *)&msg, sizeof(msg));
+               }
+       ;
+
+protocol_spec
+       :       /*NOTHING*/
+               {
+                       $$ = SADB_SATYPE_UNSPEC;
+               }
+       |       PR_ESP
+               {
+                       $$ = SADB_SATYPE_ESP;
+                       if ($1 == 1)
+                               p_ext |= SADB_X_EXT_OLD;
+                       else
+                               p_ext &= ~SADB_X_EXT_OLD;
+               }
+       |       PR_AH
+               {
+                       $$ = SADB_SATYPE_AH;
+                       if ($1 == 1)
+                               p_ext |= SADB_X_EXT_OLD;
+                       else
+                               p_ext &= ~SADB_X_EXT_OLD;
+               }
+       |       PR_IPCOMP
+               {
+                       $$ = SADB_X_SATYPE_IPCOMP;
+               }
+       |       PR_ESPUDP
+               {
+                       $$ = SADB_SATYPE_ESP;
+                       p_ext &= ~SADB_X_EXT_OLD;
+                       p_natt_oa = 0;
+                       p_natt_type = UDP_ENCAP_ESPINUDP;
+               }
+       |       PR_ESPUDP ipaddr
+               {
+                       $$ = SADB_SATYPE_ESP;
+                       p_ext &= ~SADB_X_EXT_OLD;
+                       p_natt_oa = $2;
+                       p_natt_type = UDP_ENCAP_ESPINUDP;
+               }
+       |       PR_TCP
+               {
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+                       $$ = SADB_X_SATYPE_TCPSIGNATURE;
+#endif
+               }
+       ;
+       
+spi
+       :       DECSTRING { p_spi = $1; }
+       |       HEXSTRING
+               {
+                       char *ep;
+                       unsigned long v;
+
+                       ep = NULL;
+                       v = strtoul($1.buf, &ep, 16);
+                       if (!ep || *ep) {
+                               yyerror("invalid SPI");
+                               return -1;
+                       }
+                       if (v & ~0xffffffff) {
+                               yyerror("SPI too big.");
+                               return -1;
+                       }
+
+                       p_spi = v;
+               }
+       ;
+
+algorithm_spec
+       :       esp_spec
+       |       ah_spec
+       |       ipcomp_spec
+       ;
+
+esp_spec
+       :       F_ENC enc_alg F_AUTH auth_alg
+       |       F_ENC enc_alg
+       ;
+
+ah_spec
+       :       F_AUTH auth_alg
+       ;
+
+ipcomp_spec
+       :       F_COMP ALG_COMP
+               {
+                       if ($2 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $2;
+               }
+       |       F_COMP ALG_COMP F_RAWCPI
+               {
+                       if ($2 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $2;
+                       p_ext |= SADB_X_EXT_RAWCPI;
+               }
+       ;
+
+enc_alg
+       :       ALG_ENC_NOKEY {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $1;
+
+                       p_key_enc_len = 0;
+                       p_key_enc = "";
+                       if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+                           p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+               }
+       |       ALG_ENC key_string {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $1;
+
+                       p_key_enc_len = $2.len;
+                       p_key_enc = $2.buf;
+                       if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+                           p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+               }
+       |       ALG_ENC_OLD {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       yyerror("WARNING: obsolete algorithm");
+                       p_alg_enc = $1;
+
+                       p_key_enc_len = 0;
+                       p_key_enc = "";
+                       if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+                           p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+               }
+       |       ALG_ENC_DESDERIV key_string
+               {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $1;
+                       if (p_ext & SADB_X_EXT_OLD) {
+                               yyerror("algorithm mismatched");
+                               return -1;
+                       }
+                       p_ext |= SADB_X_EXT_DERIV;
+
+                       p_key_enc_len = $2.len;
+                       p_key_enc = $2.buf;
+                       if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+                           p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+               }
+       |       ALG_ENC_DES32IV key_string
+               {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_enc = $1;
+                       if (!(p_ext & SADB_X_EXT_OLD)) {
+                               yyerror("algorithm mismatched");
+                               return -1;
+                       }
+                       p_ext |= SADB_X_EXT_IV4B;
+
+                       p_key_enc_len = $2.len;
+                       p_key_enc = $2.buf;
+                       if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+                           p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+               }
+       ;
+
+auth_alg
+       :       ALG_AUTH key_string {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_auth = $1;
+
+                       p_key_auth_len = $2.len;
+                       p_key_auth = $2.buf;
+#ifdef SADB_X_AALG_TCP_MD5
+                       if (p_alg_auth == SADB_X_AALG_TCP_MD5) {
+                               if ((p_key_auth_len < 1) || 
+                                   (p_key_auth_len > 80))
+                                       return -1;
+                       } else 
+#endif
+                       {
+                               if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
+                                   p_alg_auth, 
+                                   PFKEY_UNUNIT64(p_key_auth_len)) < 0) {
+                                       yyerror(ipsec_strerror());
+                                       return -1;
+                               }
+                       }
+               }
+       |       ALG_AUTH_NOKEY {
+                       if ($1 < 0) {
+                               yyerror("unsupported algorithm");
+                               return -1;
+                       }
+                       p_alg_auth = $1;
+
+                       p_key_auth_len = 0;
+                       p_key_auth = NULL;
+               }
+       ;
+
+key_string
+       :       QUOTEDSTRING
+               {
+                       $$ = $1;
+               }
+       |       HEXSTRING
+               {
+                       caddr_t pp_key;
+                       caddr_t bp;
+                       caddr_t yp = $1.buf;
+                       int l;
+
+                       l = strlen(yp) % 2 + strlen(yp) / 2;
+                       if ((pp_key = malloc(l)) == 0) {
+                               yyerror("not enough core");
+                               return -1;
+                       }
+                       memset(pp_key, 0, l);
+
+                       bp = pp_key;
+                       if (strlen(yp) % 2) {
+                               *bp = ATOX(yp[0]);
+                               yp++, bp++;
+                       }
+                       while (*yp) {
+                               *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+                               yp += 2, bp++;
+                       }
+
+                       $$.len = l;
+                       $$.buf = pp_key;
+               }
+       ;
+
+extension_spec
+       :       /*NOTHING*/
+       |       extension_spec extension
+       ;
+
+extension
+       :       F_EXT EXTENSION { p_ext |= $2; }
+       |       F_EXT NOCYCLICSEQ { p_ext &= ~SADB_X_EXT_CYCSEQ; }
+       |       F_MODE MODE { p_mode = $2; }
+       |       F_MODE ANY { p_mode = IPSEC_MODE_ANY; }
+       |       F_REQID DECSTRING { p_reqid = $2; }
+       |       F_REPLAY DECSTRING
+               {
+                       if ((p_ext & SADB_X_EXT_OLD) != 0) {
+                               yyerror("replay prevention cannot be used with "
+                                   "ah/esp-old");
+                               return -1;
+                       }
+                       p_replay = $2;
+               }
+       |       F_LIFETIME_HARD DECSTRING { p_lt_hard = $2; }
+       |       F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2; }
+       |       F_LIFEBYTE_HARD DECSTRING { p_lb_hard = $2; }
+       |       F_LIFEBYTE_SOFT DECSTRING { p_lb_soft = $2; }
+       ;
+
+       /* definition about command for SPD management */
+       /* spdadd */
+spdadd_command
+       :       SPDADD ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT
+               {
+                       int status;
+                       struct addrinfo *src, *dst;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+                       last_msg_type = SADB_X_SPDADD;
+#endif
+
+                       /* fixed port fields if ulp is icmpv6 */
+                       if ($10.buf != NULL) {
+                               if ($9 != IPPROTO_ICMPV6)
+                                       return -1;
+                               free($5.buf);
+                               free($8.buf);
+                               if (fix_portstr(&$10, &$5, &$8))
+                                       return -1;
+                       }
+
+                       src = parse_addr($3.buf, $5.buf);
+                       dst = parse_addr($6.buf, $8.buf);
+                       if (!src || !dst) {
+                               /* yyerror is already called */
+                               return -1;
+                       }
+                       if (src->ai_next || dst->ai_next) {
+                               yyerror("multiple address specified");
+                               freeaddrinfo(src);
+                               freeaddrinfo(dst);
+                               return -1;
+                       }
+
+                       status = setkeymsg_spdaddr(SADB_X_SPDADD, $9, &$11,
+                           src, $4, dst, $7);
+                       freeaddrinfo(src);
+                       freeaddrinfo(dst);
+                       if (status < 0)
+                               return -1;
+               }
+       |       SPDADD TAGGED QUOTEDSTRING policy_spec EOT
+               {
+                       int status;
+
+                       status = setkeymsg_spdaddr_tag(SADB_X_SPDADD,
+                           $3.buf, &$4);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+spddelete_command
+       :       SPDDELETE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT
+               {
+                       int status;
+                       struct addrinfo *src, *dst;
+
+                       /* fixed port fields if ulp is icmpv6 */
+                       if ($10.buf != NULL) {
+                               if ($9 != IPPROTO_ICMPV6)
+                                       return -1;
+                               free($5.buf);
+                               free($8.buf);
+                               if (fix_portstr(&$10, &$5, &$8))
+                                       return -1;
+                       }
+
+                       src = parse_addr($3.buf, $5.buf);
+                       dst = parse_addr($6.buf, $8.buf);
+                       if (!src || !dst) {
+                               /* yyerror is already called */
+                               return -1;
+                       }
+                       if (src->ai_next || dst->ai_next) {
+                               yyerror("multiple address specified");
+                               freeaddrinfo(src);
+                               freeaddrinfo(dst);
+                               return -1;
+                       }
+
+                       status = setkeymsg_spdaddr(SADB_X_SPDDELETE, $9, &$11,
+                           src, $4, dst, $7);
+                       freeaddrinfo(src);
+                       freeaddrinfo(dst);
+                       if (status < 0)
+                               return -1;
+               }
+       ;
+
+spddump_command:
+               SPDDUMP EOT
+               {
+                       struct sadb_msg msg;
+                       setkeymsg0(&msg, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC,
+                           sizeof(msg));
+                       sendkeymsg((char *)&msg, sizeof(msg));
+               }
+       ;
+
+spdflush_command
+       :
+               SPDFLUSH EOT
+               {
+                       struct sadb_msg msg;
+                       setkeymsg0(&msg, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC,
+                           sizeof(msg));
+                       sendkeymsg((char *)&msg, sizeof(msg));
+               }
+       ;
+
+ipaddropts
+       :       /* nothing */
+       |       ipaddropts ipaddropt
+       ;
+
+ipaddropt
+       :       F_AIFLAGS
+               {
+                       char *p;
+
+                       for (p = $1.buf + 1; *p; p++)
+                               switch (*p) {
+                               case '4':
+                                       p_aifamily = AF_INET;
+                                       break;
+#ifdef INET6
+                               case '6':
+                                       p_aifamily = AF_INET6;
+                                       break;
+#endif
+                               case 'n':
+                                       p_aiflags = AI_NUMERICHOST;
+                                       break;
+                               default:
+                                       yyerror("invalid flag");
+                                       return -1;
+                               }
+               }
+       ;
+
+ipaddr
+       :       STRING
+               {
+                       $$ = parse_addr($1.buf, NULL);
+                       if ($$ == NULL) {
+                               /* yyerror already called by parse_addr */
+                               return -1;
+                       }
+               }
+       ;
+
+ipandport
+       :       STRING
+               {
+                       $$ = parse_addr($1.buf, NULL);
+                       if ($$ == NULL) {
+                               /* yyerror already called by parse_addr */
+                               return -1;
+                       }
+               }
+       |       STRING portstr
+               {
+                       $$ = parse_addr($1.buf, $2.buf);
+                       if ($$ == NULL) {
+                               /* yyerror already called by parse_addr */
+                               return -1;
+                       }
+               }
+       ;
+
+prefix
+       :       /*NOTHING*/ { $$ = -1; }
+       |       SLASH DECSTRING { $$ = $2; }
+       ;
+
+portstr
+       :       /*NOTHING*/
+               {
+                       $$.buf = strdup("0");
+                       if (!$$.buf) {
+                               yyerror("insufficient memory");
+                               return -1;
+                       }
+                       $$.len = strlen($$.buf);
+               }
+       |       BLCL ANY ELCL
+               {
+                       $$.buf = strdup("0");
+                       if (!$$.buf) {
+                               yyerror("insufficient memory");
+                               return -1;
+                       }
+                       $$.len = strlen($$.buf);
+               }
+       |       BLCL DECSTRING ELCL
+               {
+                       char buf[20];
+                       snprintf(buf, sizeof(buf), "%lu", $2);
+                       $$.buf = strdup(buf);
+                       if (!$$.buf) {
+                               yyerror("insufficient memory");
+                               return -1;
+                       }
+                       $$.len = strlen($$.buf);
+               }
+       |       BLCL STRING ELCL
+               {
+                       $$ = $2;
+               }
+       ;
+
+upper_spec
+       :       DECSTRING { $$ = $1; }
+       |       ANY { $$ = IPSEC_ULPROTO_ANY; }
+       |       PR_TCP { 
+                               $$ = IPPROTO_TCP; 
+                       }
+       |       STRING
+               {
+                       struct protoent *ent;
+
+                       ent = getprotobyname($1.buf);
+                       if (ent)
+                               $$ = ent->p_proto;
+                       else {
+                               if (strcmp("icmp6", $1.buf) == 0) {
+                                       $$ = IPPROTO_ICMPV6;
+                               } else if(strcmp("ip4", $1.buf) == 0) {
+                                       $$ = IPPROTO_IPV4;
+                               } else {
+                                       yyerror("invalid upper layer protocol");
+                                       return -1;
+                               }
+                       }
+                       endprotoent();
+               }
+       ;
+
+upper_misc_spec
+       :       /*NOTHING*/
+               {
+                       $$.buf = NULL;
+                       $$.len = 0;
+               }
+       |       STRING
+               {
+                       $$.buf = strdup($1.buf);
+                       if (!$$.buf) {
+                               yyerror("insufficient memory");
+                               return -1;
+                       }
+                       $$.len = strlen($$.buf);
+               }
+       ;
+
+policy_spec
+       :       F_POLICY policy_requests
+               {
+                       char *policy;
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+                       struct sadb_x_policy *xpl;
+#endif
+
+                       policy = ipsec_set_policy($2.buf, $2.len);
+                       if (policy == NULL) {
+                               yyerror(ipsec_strerror());
+                               return -1;
+                       }
+
+                       $$.buf = policy;
+                       $$.len = ipsec_get_policylen(policy);
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+                       xpl = (struct sadb_x_policy *) $$.buf;
+                       last_priority = xpl->sadb_x_policy_priority;
+#endif
+               }
+       ;
+
+policy_requests
+       :       PL_REQUESTS { $$ = $1; }
+       ;
+
+       /* exit */
+exit_command
+       :       EXIT EOT
+               {
+                       exit_now = 1;
+                       YYACCEPT;
+               }
+       ;
+%%
+
+int
+setkeymsg0(msg, type, satype, l)
+       struct sadb_msg *msg;
+       unsigned int type;
+       unsigned int satype;
+       size_t l;
+{
+
+       msg->sadb_msg_version = PF_KEY_V2;
+       msg->sadb_msg_type = type;
+       msg->sadb_msg_errno = 0;
+       msg->sadb_msg_satype = satype;
+       msg->sadb_msg_reserved = 0;
+       msg->sadb_msg_seq = 0;
+       msg->sadb_msg_pid = getpid();
+       msg->sadb_msg_len = PFKEY_UNIT64(l);
+       return 0;
+}
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_spdaddr(type, upper, policy, srcs, splen, dsts, dplen)
+       unsigned int type;
+       unsigned int upper;
+       vchar_t *policy;
+       struct addrinfo *srcs;
+       int splen;
+       struct addrinfo *dsts;
+       int dplen;
+{
+       struct sadb_msg *msg;
+       char buf[BUFSIZ];
+       int l, l0;
+       struct sadb_address m_addr;
+       struct addrinfo *s, *d;
+       int n;
+       int plen;
+       struct sockaddr *sa;
+       int salen;
+       struct sadb_x_policy *sp;
+#ifdef HAVE_POLICY_FWD
+       struct sadb_x_ipsecrequest *ps = NULL;
+       int saved_level, saved_id = 0;
+#endif
+
+       msg = (struct sadb_msg *)buf;
+
+       if (!srcs || !dsts)
+               return -1;
+
+       /* fix up length afterwards */
+       setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0);
+       l = sizeof(struct sadb_msg);
+
+       sp = (struct sadb_x_policy*) (buf + l);
+       memcpy(buf + l, policy->buf, policy->len);
+       l += policy->len;
+
+       l0 = l;
+       n = 0;
+
+       /* do it for all src/dst pairs */
+       for (s = srcs; s; s = s->ai_next) {
+               for (d = dsts; d; d = d->ai_next) {
+                       /* rewind pointer */
+                       l = l0;
+
+                       if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+                               continue;
+                       switch (s->ai_addr->sa_family) {
+                       case AF_INET:
+                               plen = sizeof(struct in_addr) << 3;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               plen = sizeof(struct in6_addr) << 3;
+                               break;
+#endif
+                       default:
+                               continue;
+                       }
+
+                       /* set src */
+                       sa = s->ai_addr;
+                       salen = sysdep_sa_len(s->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+                       m_addr.sadb_address_proto = upper;
+                       m_addr.sadb_address_prefixlen =
+                           (splen >= 0 ? splen : plen);
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), (caddr_t)sa, salen);
+
+                       /* set dst */
+                       sa = d->ai_addr;
+                       salen = sysdep_sa_len(d->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+                       m_addr.sadb_address_proto = upper;
+                       m_addr.sadb_address_prefixlen =
+                           (dplen >= 0 ? dplen : plen);
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+
+                       msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+                       sendkeymsg(buf, l);
+
+#ifdef HAVE_POLICY_FWD
+                       /* create extra call for FWD policy */
+                       if (f_rfcmode && sp->sadb_x_policy_dir == IPSEC_DIR_INBOUND) {
+                               sp->sadb_x_policy_dir = IPSEC_DIR_FWD;
+                               ps = (struct sadb_x_ipsecrequest*) (sp+1);
+
+                               /* if request level is unique, change it to
+                                * require for fwd policy */
+                               /* XXX: currently, only first policy is updated
+                                * only. Update following too... */
+                               saved_level = ps->sadb_x_ipsecrequest_level;
+                               if (saved_level == IPSEC_LEVEL_UNIQUE) {
+                                       saved_id = ps->sadb_x_ipsecrequest_reqid;
+                                       ps->sadb_x_ipsecrequest_reqid=0;
+                                       ps->sadb_x_ipsecrequest_level=IPSEC_LEVEL_REQUIRE;
+                               }
+
+                               sendkeymsg(buf, l);
+                               /* restoring for next message */
+                               sp->sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+                               if (saved_level == IPSEC_LEVEL_UNIQUE) {
+                                       ps->sadb_x_ipsecrequest_reqid = saved_id;
+                                       ps->sadb_x_ipsecrequest_level = saved_level;
+                               }
+                       }
+#endif
+
+                       n++;
+               }
+       }
+
+       if (n == 0)
+               return -1;
+       else
+               return 0;
+}
+
+static int
+setkeymsg_spdaddr_tag(type, tag, policy)
+       unsigned int type;
+       char *tag;
+       vchar_t *policy;
+{
+       struct sadb_msg *msg;
+       char buf[BUFSIZ];
+       int l, l0;
+#ifdef SADB_X_EXT_TAG
+       struct sadb_x_tag m_tag;
+#endif
+       int n;
+
+       msg = (struct sadb_msg *)buf;
+
+       /* fix up length afterwards */
+       setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0);
+       l = sizeof(struct sadb_msg);
+
+       memcpy(buf + l, policy->buf, policy->len);
+       l += policy->len;
+
+       l0 = l;
+       n = 0;
+
+#ifdef SADB_X_EXT_TAG
+       memset(&m_tag, 0, sizeof(m_tag));
+       m_tag.sadb_x_tag_len = PFKEY_UNIT64(sizeof(m_tag));
+       m_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG;
+       if (strlcpy(m_tag.sadb_x_tag_name, tag,
+           sizeof(m_tag.sadb_x_tag_name)) >= sizeof(m_tag.sadb_x_tag_name))
+               return -1;
+       memcpy(buf + l, &m_tag, sizeof(m_tag));
+       l += sizeof(m_tag);
+#endif
+
+       msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+       sendkeymsg(buf, l);
+
+       return 0;
+}
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_addr(type, satype, srcs, dsts, no_spi)
+       unsigned int type;
+       unsigned int satype;
+       struct addrinfo *srcs;
+       struct addrinfo *dsts;
+       int no_spi;
+{
+       struct sadb_msg *msg;
+       char buf[BUFSIZ];
+       int l, l0, len;
+       struct sadb_sa m_sa;
+       struct sadb_x_sa2 m_sa2;
+       struct sadb_address m_addr;
+       struct addrinfo *s, *d;
+       int n;
+       int plen;
+       struct sockaddr *sa;
+       int salen;
+
+       msg = (struct sadb_msg *)buf;
+
+       if (!srcs || !dsts)
+               return -1;
+
+       /* fix up length afterwards */
+       setkeymsg0(msg, type, satype, 0);
+       l = sizeof(struct sadb_msg);
+
+       if (!no_spi) {
+               len = sizeof(struct sadb_sa);
+               m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+               m_sa.sadb_sa_exttype = SADB_EXT_SA;
+               m_sa.sadb_sa_spi = htonl(p_spi);
+               m_sa.sadb_sa_replay = p_replay;
+               m_sa.sadb_sa_state = 0;
+               m_sa.sadb_sa_auth = p_alg_auth;
+               m_sa.sadb_sa_encrypt = p_alg_enc;
+               m_sa.sadb_sa_flags = p_ext;
+
+               memcpy(buf + l, &m_sa, len);
+               l += len;
+
+               len = sizeof(struct sadb_x_sa2);
+               m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len);
+               m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+               m_sa2.sadb_x_sa2_mode = p_mode;
+               m_sa2.sadb_x_sa2_reqid = p_reqid;
+
+               memcpy(buf + l, &m_sa2, len);
+               l += len;
+       }
+
+       l0 = l;
+       n = 0;
+
+       /* do it for all src/dst pairs */
+       for (s = srcs; s; s = s->ai_next) {
+               for (d = dsts; d; d = d->ai_next) {
+                       /* rewind pointer */
+                       l = l0;
+
+                       if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+                               continue;
+                       switch (s->ai_addr->sa_family) {
+                       case AF_INET:
+                               plen = sizeof(struct in_addr) << 3;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               plen = sizeof(struct in6_addr) << 3;
+                               break;
+#endif
+                       default:
+                               continue;
+                       }
+
+                       /* set src */
+                       sa = s->ai_addr;
+                       salen = sysdep_sa_len(s->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+                       m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+                       m_addr.sadb_address_prefixlen = plen;
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+
+                       /* set dst */
+                       sa = d->ai_addr;
+                       salen = sysdep_sa_len(d->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+                       m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+                       m_addr.sadb_address_prefixlen = plen;
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+
+                       msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+                       sendkeymsg(buf, l);
+
+                       n++;
+               }
+       }
+
+       if (n == 0)
+               return -1;
+       else
+               return 0;
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static u_int16_t get_port (struct addrinfo *addr)
+{
+       struct sockaddr *s = addr->ai_addr;
+       u_int16_t port = 0;
+
+       switch (s->sa_family) {
+       case AF_INET:
+         {
+               struct sockaddr_in *sin4 = (struct sockaddr_in *)s;
+               port = ntohs(sin4->sin_port);
+               break;
+         }
+       case AF_INET6:
+         {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)s;
+               port = ntohs(sin6->sin6_port);
+               break;
+         }
+       }
+
+       if (port == 0)
+               port = DEFAULT_NATT_PORT;
+
+       return port;
+}
+#endif
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_add(type, satype, srcs, dsts)
+       unsigned int type;
+       unsigned int satype;
+       struct addrinfo *srcs;
+       struct addrinfo *dsts;
+{
+       struct sadb_msg *msg;
+       char buf[BUFSIZ];
+       int l, l0, len;
+       struct sadb_sa m_sa;
+       struct sadb_x_sa2 m_sa2;
+       struct sadb_address m_addr;
+       struct addrinfo *s, *d;
+       int n;
+       int plen;
+       struct sockaddr *sa;
+       int salen;
+
+       msg = (struct sadb_msg *)buf;
+
+       if (!srcs || !dsts)
+               return -1;
+
+       /* fix up length afterwards */
+       setkeymsg0(msg, type, satype, 0);
+       l = sizeof(struct sadb_msg);
+
+       /* set encryption algorithm, if present. */
+       if (satype != SADB_X_SATYPE_IPCOMP && p_key_enc) {
+               union {
+                       struct sadb_key key;
+                       struct sadb_ext ext;
+               } m;
+
+               m.key.sadb_key_len =
+                       PFKEY_UNIT64(sizeof(m.key)
+                                  + PFKEY_ALIGN8(p_key_enc_len));
+               m.key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+               m.key.sadb_key_bits = p_key_enc_len * 8;
+               m.key.sadb_key_reserved = 0;
+
+               setvarbuf(buf, &l, &m.ext, sizeof(m.key),
+                       p_key_enc, p_key_enc_len);
+       }
+
+       /* set authentication algorithm, if present. */
+       if (p_key_auth) {
+               union {
+                       struct sadb_key key;
+                       struct sadb_ext ext;
+               } m;
+
+               m.key.sadb_key_len =
+                       PFKEY_UNIT64(sizeof(m.key)
+                                  + PFKEY_ALIGN8(p_key_auth_len));
+               m.key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+               m.key.sadb_key_bits = p_key_auth_len * 8;
+               m.key.sadb_key_reserved = 0;
+
+               setvarbuf(buf, &l, &m.ext, sizeof(m.key),
+                       p_key_auth, p_key_auth_len);
+       }
+
+       /* set lifetime for HARD */
+       if (p_lt_hard != 0 || p_lb_hard != 0) {
+               struct sadb_lifetime m_lt;
+               u_int slen = sizeof(struct sadb_lifetime);
+
+               m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen);
+               m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+               m_lt.sadb_lifetime_allocations = 0;
+               m_lt.sadb_lifetime_bytes = p_lb_hard;
+               m_lt.sadb_lifetime_addtime = p_lt_hard;
+               m_lt.sadb_lifetime_usetime = 0;
+
+               memcpy(buf + l, &m_lt, slen);
+               l += slen;
+       }
+
+       /* set lifetime for SOFT */
+       if (p_lt_soft != 0 || p_lb_soft != 0) {
+               struct sadb_lifetime m_lt;
+               u_int slen = sizeof(struct sadb_lifetime);
+
+               m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen);
+               m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+               m_lt.sadb_lifetime_allocations = 0;
+               m_lt.sadb_lifetime_bytes = p_lb_soft;
+               m_lt.sadb_lifetime_addtime = p_lt_soft;
+               m_lt.sadb_lifetime_usetime = 0;
+
+               memcpy(buf + l, &m_lt, slen);
+               l += slen;
+       }
+
+       len = sizeof(struct sadb_sa);
+       m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+       m_sa.sadb_sa_exttype = SADB_EXT_SA;
+       m_sa.sadb_sa_spi = htonl(p_spi);
+       m_sa.sadb_sa_replay = p_replay;
+       m_sa.sadb_sa_state = 0;
+       m_sa.sadb_sa_auth = p_alg_auth;
+       m_sa.sadb_sa_encrypt = p_alg_enc;
+       m_sa.sadb_sa_flags = p_ext;
+
+       memcpy(buf + l, &m_sa, len);
+       l += len;
+
+       len = sizeof(struct sadb_x_sa2);
+       m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len);
+       m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+       m_sa2.sadb_x_sa2_mode = p_mode;
+       m_sa2.sadb_x_sa2_reqid = p_reqid;
+
+       memcpy(buf + l, &m_sa2, len);
+       l += len;
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+       if (p_natt_type) {
+               struct sadb_x_nat_t_type natt_type;
+
+               len = sizeof(struct sadb_x_nat_t_type);
+               memset(&natt_type, 0, len);
+               natt_type.sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
+               natt_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+               natt_type.sadb_x_nat_t_type_type = p_natt_type;
+
+               memcpy(buf + l, &natt_type, len);
+               l += len;
+
+               if (p_natt_oa) {
+                       sa = p_natt_oa->ai_addr;
+                       switch (sa->sa_family) {
+                       case AF_INET:
+                               plen = sizeof(struct in_addr) << 3;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               plen = sizeof(struct in6_addr) << 3;
+                               break;
+#endif
+                       default:
+                               return -1;
+                       }
+                       salen = sysdep_sa_len(sa);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_X_EXT_NAT_T_OA;
+                       m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+                       m_addr.sadb_address_prefixlen = plen;
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+               }
+       }
+#endif
+
+       l0 = l;
+       n = 0;
+
+       /* do it for all src/dst pairs */
+       for (s = srcs; s; s = s->ai_next) {
+               for (d = dsts; d; d = d->ai_next) {
+                       /* rewind pointer */
+                       l = l0;
+
+                       if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+                               continue;
+                       switch (s->ai_addr->sa_family) {
+                       case AF_INET:
+                               plen = sizeof(struct in_addr) << 3;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               plen = sizeof(struct in6_addr) << 3;
+                               break;
+#endif
+                       default:
+                               continue;
+                       }
+
+                       /* set src */
+                       sa = s->ai_addr;
+                       salen = sysdep_sa_len(s->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+                       m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+                       m_addr.sadb_address_prefixlen = plen;
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+
+                       /* set dst */
+                       sa = d->ai_addr;
+                       salen = sysdep_sa_len(d->ai_addr);
+                       m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+                           PFKEY_ALIGN8(salen));
+                       m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+                       m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+                       m_addr.sadb_address_prefixlen = plen;
+                       m_addr.sadb_address_reserved = 0;
+
+                       setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+                           sizeof(m_addr), sa, salen);
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+                       if (p_natt_type) {
+                               struct sadb_x_nat_t_port natt_port;
+
+                               /* NATT_SPORT */
+                               len = sizeof(struct sadb_x_nat_t_port);
+                               memset(&natt_port, 0, len);
+                               natt_port.sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
+                               natt_port.sadb_x_nat_t_port_exttype =
+                                       SADB_X_EXT_NAT_T_SPORT;
+                               natt_port.sadb_x_nat_t_port_port = htons(get_port(s));
+                               
+                               memcpy(buf + l, &natt_port, len);
+                               l += len;
+
+                               /* NATT_DPORT */
+                               natt_port.sadb_x_nat_t_port_exttype =
+                                       SADB_X_EXT_NAT_T_DPORT;
+                               natt_port.sadb_x_nat_t_port_port = htons(get_port(d));
+                               
+                               memcpy(buf + l, &natt_port, len);
+                               l += len;
+                       }
+#endif
+                       msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+                       sendkeymsg(buf, l);
+
+                       n++;
+               }
+       }
+
+       if (n == 0)
+               return -1;
+       else
+               return 0;
+}
+
+static struct addrinfo *
+parse_addr(host, port)
+       char *host;
+       char *port;
+{
+       struct addrinfo hints, *res = NULL;
+       int error;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = p_aifamily;
+       hints.ai_socktype = SOCK_DGRAM;         /*dummy*/
+       hints.ai_protocol = IPPROTO_UDP;        /*dummy*/
+       hints.ai_flags = p_aiflags;
+       error = getaddrinfo(host, port, &hints, &res);
+       if (error != 0) {
+               yyerror(gai_strerror(error));
+               return NULL;
+       }
+       return res;
+}
+
+static int
+fix_portstr(spec, sport, dport)
+       vchar_t *spec, *sport, *dport;
+{
+       const char *p, *p2 = "0";
+       char *q;
+       u_int l;
+
+       l = 0;
+       for (q = spec->buf; *q != ',' && *q != '\0' && l < spec->len; q++, l++)
+               ;
+       if (*q != '\0') {
+               if (*q == ',') {
+                       *q = '\0';
+                       p2 = ++q;
+               }
+               for (p = p2; *p != '\0' && l < spec->len; p++, l++)
+                       ;
+               if (*p != '\0' || *p2 == '\0') {
+                       yyerror("invalid an upper layer protocol spec");
+                       return -1;
+               }
+       }
+
+       sport->buf = strdup(spec->buf);
+       if (!sport->buf) {
+               yyerror("insufficient memory");
+               return -1;
+       }
+       sport->len = strlen(sport->buf);
+       dport->buf = strdup(p2);
+       if (!dport->buf) {
+               yyerror("insufficient memory");
+               return -1;
+       }
+       dport->len = strlen(dport->buf);
+
+       return 0;
+}
+
+static int
+setvarbuf(buf, off, ebuf, elen, vbuf, vlen)
+       char *buf;
+       int *off;
+       struct sadb_ext *ebuf;
+       int elen;
+       const void *vbuf;
+       int vlen;
+{
+       memset(buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len));
+       memcpy(buf + *off, (caddr_t)ebuf, elen);
+       memcpy(buf + *off + elen, vbuf, vlen);
+       (*off) += PFKEY_ALIGN8(elen + vlen);
+
+       return 0;
+}
+
+void
+parse_init()
+{
+       p_spi = 0;
+
+       p_ext = SADB_X_EXT_CYCSEQ;
+       p_alg_enc = SADB_EALG_NONE;
+       p_alg_auth = SADB_AALG_NONE;
+       p_mode = IPSEC_MODE_ANY;
+       p_reqid = 0;
+       p_replay = 0;
+       p_key_enc_len = p_key_auth_len = 0;
+       p_key_enc = p_key_auth = 0;
+       p_lt_hard = p_lt_soft = 0;
+       p_lb_hard = p_lb_soft = 0;
+
+       p_aiflags = 0;
+       p_aifamily = PF_UNSPEC;
+
+       /* Clear out any natt OA information */
+       if (p_natt_oa)
+               freeaddrinfo (p_natt_oa);
+       p_natt_oa = NULL;
+       p_natt_type = 0;
+
+       return;
+}
+
+void
+free_buffer()
+{
+       /* we got tons of memory leaks in the parser anyways, leave them */
+
+       return;
+}
diff --git a/ipsec-tools/setkey/scriptdump.pl b/ipsec-tools/setkey/scriptdump.pl
new file mode 100644 (file)
index 0000000..f5b9f25
--- /dev/null
@@ -0,0 +1,55 @@
+#! @LOCALPREFIX@/bin/perl
+
+if ($< != 0) {
+       print STDERR "must be root to invoke this\n";
+       exit 1;
+}
+
+$mode = 'add';
+while ($i = shift @ARGV) {
+       if ($i eq '-d') {
+               $mode = 'delete';
+       } else {
+               print STDERR "usage: scriptdump [-d]\n";
+               exit 1;
+       }
+}
+
+open(IN, "setkey -D |") || die;
+foreach $_ (<IN>) {
+       if (/^[^\t]/) {
+               ($src, $dst) = split(/\s+/, $_);
+       } elsif (/^\t(esp|ah) mode=(\S+) spi=(\d+).*reqid=(\d+)/) {
+               ($proto, $ipsecmode, $spi, $reqid) = ($1, $2, $3, $4);
+       } elsif (/^\tE: (\S+) (.*)/) {
+               $ealgo = $1;
+               $ekey = $2;
+               $ekey =~ s/\s//g;
+               $ekey =~ s/^/0x/g;
+       } elsif (/^\tA: (\S+) (.*)/) {
+               $aalgo = $1;
+               $akey = $2;
+               $akey =~ s/\s//g;
+               $akey =~ s/^/0x/g;
+       } elsif (/^\tseq=(0x\d+) replay=(\d+) flags=(0x\d+) state=/) {
+               print "$mode $src $dst $proto $spi";
+               $replay = $2;
+               print " -u $reqid" if $reqid;
+               if ($mode eq 'add') {
+                       print " -m $ipsecmode -r $replay" if $replay;
+                       if ($proto eq 'esp') {
+                               print " -E $ealgo $ekey" if $ealgo;
+                               print " -A $aalgo $akey" if $aalgo;
+                       } elsif ($proto eq 'ah') {
+                               print " -A $aalgo $akey" if $aalgo;
+                       }
+               } 
+               print ";\n";
+
+               $src = $dst = $upper = $proxy = '';
+               $ealgo = $ekey = $aalgo = $akey = '';
+       }
+}
+close(IN);
+
+exit 0;
diff --git a/ipsec-tools/setkey/setkey.8 b/ipsec-tools/setkey/setkey.8
new file mode 100644 (file)
index 0000000..3a87ac1
--- /dev/null
@@ -0,0 +1,828 @@
+.\"    $NetBSD: setkey.8,v 1.17 2005/09/15 08:42:09 wiz Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+.\"
+.Dd March 19, 2004
+.Dt SETKEY 8
+.Os
+.\"
+.Sh NAME
+.Nm setkey
+.Nd manually manipulate the IPsec SA/SP database
+.\"
+.Sh SYNOPSIS
+.Nm setkey
+.Op Fl knrv
+.Ar file ...
+.Nm setkey
+.Op Fl knrv
+.Fl c
+.Nm setkey
+.Op Fl krv
+.Fl f Ar filename
+.Nm setkey
+.Op Fl aklPrv
+.Fl D
+.Nm setkey
+.Op Fl Pvp
+.Fl F
+.Nm setkey
+.Op Fl H
+.Fl x
+.Nm setkey
+.Op Fl ?V
+.\"
+.Sh DESCRIPTION
+.Nm
+adds, updates, dumps, or flushes
+Security Association Database (SAD) entries
+as well as Security Policy Database (SPD) entries in the kernel.
+.Pp
+.Nm
+takes a series of operations from standard input
+.Po
+if invoked with
+.Fl c
+.Pc
+or the file named
+.Ar filename
+.Po
+if invoked with
+.Fl f Ar filename
+.Pc .
+.Bl -tag -width Ds
+.It (no flag)
+Dump the SAD entries or SPD entries contained in the specified
+.Ar file .
+.It Fl ?
+Print short help.
+.It Fl a
+.Nm
+usually does not display dead SAD entries with
+.Fl D .
+If
+.Fl a
+is also specified, the dead SAD entries will be displayed as well.
+A dead SAD entry is one that has expired but remains in the
+system because it is referenced by some SPD entries.
+.It Fl D
+Dump the SAD entries.
+If
+.Fl P
+is also specified, the SPD entries are dumped.
+If
+.Fl p
+is specified, the ports are displayed.
+.It Fl F
+Flush the SAD entries.
+If
+.Fl P
+is also specified, the SPD entries are flushed.
+.It Fl H
+Add hexadecimal dump in
+.Fl x
+mode.
+.It Fl h
+On
+.Nx ,
+synonym for
+.Fl H .
+On other systems, synonym for
+.Fl ? .
+.It Fl k
+Use semantics used in kernel.
+Available only in Linux.
+See also
+.Fl r .
+.It Fl l
+Loop forever with short output on
+.Fl D .
+.It Fl n
+No action.
+The program will check validity of the input, but no changes to
+the SPD will be made.
+.It Fl r
+Use semantics described in IPsec RFCs.
+This mode is default.
+For details see section
+.Sx RFC vs Linux kernel semantics .
+Available only in Linux.
+See also
+.Fl k .
+.It Fl x
+Loop forever and dump all the messages transmitted to the
+.Dv PF_KEY
+socket.
+.Fl xx
+prints the unformatted timestamps.
+.It Fl V
+Print version string.
+.It Fl v
+Be verbose.
+The program will dump messages exchanged on the
+.Dv PF_KEY
+socket, including messages sent from other processes to the kernel.
+.El
+.Ss Configuration syntax
+With
+.Fl c
+or
+.Fl f
+on the command line,
+.Nm
+accepts the following configuration syntax.
+Lines starting with hash signs
+.Pq Sq #
+are treated as comment lines.
+.Bl -tag -width Ds
+.It Xo
+.Li add
+.Op Fl 46n
+.Ar src Ar dst Ar protocol Ar spi
+.Op Ar extensions
+.Ar algorithm ...
+.Li ;
+.Xc
+Add an SAD entry.
+.Li add
+can fail for multiple reasons, including when the key length does
+not match the specified algorithm.
+.\"
+.It Xo
+.Li get
+.Op Fl 46n
+.Ar src Ar dst Ar protocol Ar spi
+.Li ;
+.Xc
+Show an SAD entry.
+.\"
+.It Xo
+.Li delete
+.Op Fl 46n
+.Ar src Ar dst Ar protocol Ar spi
+.Li ;
+.Xc
+Remove an SAD entry.
+.\"
+.It Xo
+.Li deleteall
+.Op Fl 46n
+.Ar src Ar dst Ar protocol
+.Li ;
+.Xc
+Remove all SAD entries that match the specification.
+.\"
+.It Xo
+.Li flush
+.Op Ar protocol
+.Li ;
+.Xc
+Clear all SAD entries matched by the options.
+.Fl F
+on the command line achieves the same functionality.
+.\"
+.It Xo
+.Li dump
+.Op Ar protocol
+.Li ;
+.Xc
+Dumps all SAD entries matched by the options.
+.Fl D
+on the command line achieves the same functionality.
+.\"
+.It Xo
+.Li spdadd
+.Op Fl 46n
+.Ar src_range Ar dst_range Ar upperspec Ar policy
+.Li ;
+.Xc
+Add an SPD entry.
+.\"
+.It Xo
+.Li spdadd tagged
+.Ar tag Ar policy
+.Li ;
+.Xc
+Add an SPD entry based on a PF tag.
+.Ar tag
+must be a string surrounded by double quotes.
+.\"
+.It Xo
+.Li spddelete
+.Op Fl 46n
+.Ar src_range Ar dst_range Ar upperspec Fl P Ar direction
+.Li ;
+.Xc
+Delete an SPD entry.
+.\"
+.It Xo
+.Li spdflush
+.Li ;
+.Xc
+Clear all SPD entries.
+.Fl FP
+on the command line achieves the same functionality.
+.\"
+.It Xo
+.Li spddump
+.Li ;
+.Xc
+Dumps all SPD entries.
+.Fl DP
+on the command line achieves the same functionality.
+.El
+.\"
+.Pp
+Meta-arguments are as follows:
+.Pp
+.Bl -tag -compact -width Ds
+.It Ar src
+.It Ar dst
+Source/destination of the secure communication is specified as
+an IPv4/v6 address, and an optional port number between square
+brackets.
+.Nm
+can resolve a FQDN into numeric addresses.
+If the FQDN resolves into multiple addresses,
+.Nm
+will install multiple SAD/SPD entries into the kernel
+by trying all possible combinations.
+.Fl 4 ,
+.Fl 6 ,
+and
+.Fl n
+restrict the address resolution of FQDN in certain ways.
+.Fl 4
+and
+.Fl 6
+restrict results into IPv4/v6 addresses only, respectively.
+.Fl n
+avoids FQDN resolution and requires addresses to be numeric addresses.
+.\"
+.Pp
+.It Ar protocol
+.Ar protocol
+is one of following:
+.Bl -tag -width Fl -compact
+.It Li esp
+ESP based on rfc2406
+.It Li esp-old
+ESP based on rfc1827
+.It Li ah
+AH based on rfc2402
+.It Li ah-old
+AH based on rfc1826
+.It Li ipcomp
+IPComp
+.It Li tcp
+TCP-MD5 based on rfc2385
+.El
+.\"
+.Pp
+.It Ar spi
+Security Parameter Index
+.Pq SPI
+for the SAD and the SPD.
+.Ar spi
+must be a decimal number, or a hexadecimal number with a
+.Dq Li 0x
+prefix.
+SPI values between 0 and 255 are reserved for future use by IANA
+and cannot be used.
+TCP-MD5 associations must use 0x1000 and therefore only have per-host
+granularity at this time.
+.\"
+.Pp
+.It Ar extensions
+take some of the following:
+.Bl -tag -width Fl -compact
+.\"
+.It Fl m Ar mode
+Specify a security protocol mode for use.
+.Ar mode
+is one of following:
+.Li transport , tunnel ,
+or
+.Li any .
+The default value is
+.Li any .
+.\"
+.It Fl r Ar size
+Specify window size of bytes for replay prevention.
+.Ar size
+must be decimal number in 32-bit word.
+If
+.Ar size
+is zero or not specified, replay checks don't take place.
+.\"
+.It Fl u Ar id
+Specify the identifier of the policy entry in the SPD.
+See
+.Ar policy .
+.\"
+.It Fl f Ar pad_option
+defines the content of the ESP padding.
+.Ar pad_option
+is one of following:
+.Bl -tag -width random-pad -compact
+.It Li zero-pad
+All the paddings are zero.
+.It Li random-pad
+A series of randomized values are used.
+.It Li seq-pad
+A series of sequential increasing numbers started from 1 are used.
+.El
+.\"
+.It Fl f Li nocyclic-seq
+Don't allow cyclic sequence numbers.
+.\"
+.It Fl lh Ar time
+.It Fl ls Ar time
+Specify hard/soft life time duration of the SA measured in seconds.
+.\"
+.It Fl bh Ar bytes
+.It Fl bs Ar bytes
+Specify hard/soft life time duration of the SA measured in bytes transported.
+.El
+.\"
+.Pp
+.It Ar algorithm
+.Bl -tag -width Fl -compact
+.It Fl E Ar ealgo Ar key
+Specify an encryption algorithm
+.Ar ealgo
+for ESP.
+.It Xo
+.Fl E Ar ealgo Ar key
+.Fl A Ar aalgo Ar key
+.Xc
+Specify an encryption algorithm
+.Ar ealgo ,
+as well as a payload authentication algorithm
+.Ar aalgo ,
+for ESP.
+.It Fl A Ar aalgo Ar key
+Specify an authentication algorithm for AH.
+.It Fl C Ar calgo Op Fl R
+Specify a compression algorithm for IPComp.
+If
+.Fl R
+is specified, the
+.Ar spi
+field value will be used as the IPComp CPI
+.Pq compression parameter index
+on wire as-is.
+If
+.Fl R
+is not specified,
+the kernel will use well-known CPI on wire, and
+.Ar spi
+field will be used only as an index for kernel internal usage.
+.El
+.Pp
+.Ar key
+must be a double-quoted character string, or a series of hexadecimal
+digits preceded by
+.Dq Li 0x .
+.Pp
+Possible values for
+.Ar ealgo ,
+.Ar aalgo ,
+and
+.Ar calgo
+are specified in the
+.Sx Algorithms
+sections.
+.\"
+.Pp
+.It Ar src_range
+.It Ar dst_range
+These select the communications that should be secured by IPsec.
+They can be an IPv4/v6 address or an IPv4/v6 address range, and
+may be accompanied by a TCP/UDP port specification.
+This takes the following form:
+.Bd -literal -offset
+.Ar address
+.Ar address/prefixlen
+.Ar address[port]
+.Ar address/prefixlen[port]
+.Ed
+.Pp
+.Ar prefixlen
+and
+.Ar port
+must be decimal numbers.
+The square brackets around
+.Ar port
+are really necessary,
+they are not man page meta-characters.
+For FQDN resolution, the rules applicable to
+.Ar src
+and
+.Ar dst
+apply here as well.
+.\"
+.Pp
+.It Ar upperspec
+Upper-layer protocol to be used.
+You can use one of the words in
+.Pa /etc/protocols
+as
+.Ar upperspec ,
+or
+.Li icmp6 ,
+.Li ip4 ,
+or
+.Li any .
+.Li any
+stands for
+.Dq any protocol .
+You can also use the protocol number.
+You can specify a type and/or a code of ICMPv6 when the
+upper-layer protocol is ICMPv6.
+The specification can be placed after
+.Li icmp6 .
+A type is separated from a code by single comma.
+A code must always be specified.
+When a zero is specified, the kernel deals with it as a wildcard.
+Note that the kernel can not distinguish a wildcard from an ICPMv6
+type of zero.
+For example, the following means that the policy doesn't require IPsec
+for any inbound Neighbor Solicitation.
+.Dl spdadd ::/0 ::/0 icmp6 135,0 -P in none ;
+.Pp
+.Em Note :
+.Ar upperspec
+does not work against forwarding case at this moment,
+as it requires extra reassembly at the forwarding node
+.Pq not implemented at this moment .
+There are many protocols in
+.Pa /etc/protocols ,
+but all protocols except of TCP, UDP, and ICMP may not be suitable
+to use with IPsec.
+You have to consider carefully what to use.
+.\"
+.Pp
+.It Ar policy
+.Ar policy
+is in one of the following three formats:
+.Bd -literal -offset indent
+.It Fl P Ar direction [priority specification] Li discard
+.It Fl P Ar direction [priority specification] Li none
+.It Xo Fl P Ar direction [priority specification] Li ipsec
+.Ar protocol/mode/src-dst/level Op ...
+.Xc
+.Ed
+.Pp
+You must specify the direction of its policy as
+.Ar direction .
+Either
+.Ar out ,
+.Ar in ,
+or
+.Ar fwd
+can be used.
+.Pp
+.Ar priority specification
+is used to control the placement of the policy within the SPD.
+Policy position is determined by
+a signed integer where higher priorities indicate the policy is placed
+closer to the beginning of the list and lower priorities indicate the
+policy is placed closer to the end of the list.
+Policies with equal priorities are added at the end of groups
+of such policies.
+.Pp
+Priority can only
+be specified when setkey has been compiled against kernel headers that
+support policy priorities (Linux \*[Gt]= 2.6.6).
+If the kernel does not support priorities, a warning message will
+be printed the first time a priority specification is used.
+Policy priority takes one of the following formats:
+.Bl -tag  -width "discard"
+.It Xo
+.Ar {priority,prio} offset
+.Xc
+.Ar offset
+is an integer in the range from \-2147483647 to 214783648.
+.It Xo
+.Ar {priority,prio} base {+,\-} offset
+.Xc
+.Ar base
+is either
+.Li low (\-1073741824) ,
+.Li def (0) ,
+or
+.Li high (1073741824)
+.Pp
+.Ar offset
+is an unsigned integer.
+It can be up to 1073741824 for
+positive offsets, and up to 1073741823 for negative offsets.
+.El
+.Pp
+.Li discard
+means the packet matching indexes will be discarded.
+.Li none
+means that IPsec operation will not take place onto the packet.
+.Li ipsec
+means that IPsec operation will take place onto the packet.
+.Pp
+The
+.Ar protocol/mode/src-dst/level
+part specifies the rule how to process the packet.
+Either
+.Li ah ,
+.Li esp ,
+or
+.Li ipcomp
+must be used as
+.Ar protocol .
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel .
+If
+.Ar mode
+is
+.Li tunnel ,
+you must specify the end-point addresses of the SA as
+.Ar src
+and
+.Ar dst
+with
+.Sq -
+between these addresses, which is used to specify the SA to use.
+If
+.Ar mode
+is
+.Li transport ,
+both
+.Ar src
+and
+.Ar dst
+can be omitted.
+.Ar level
+is to be one of the following:
+.Li default , use , require ,
+or
+.Li unique .
+If the SA is not available in every level, the kernel will
+ask the key exchange daemon to establish a suitable SA.
+.Li default
+means the kernel consults the system wide default for the protocol
+you specified, e.g. the
+.Li esp_trans_deflev
+sysctl variable, when the kernel processes the packet.
+.Li use
+means that the kernel uses an SA if it's available,
+otherwise the kernel keeps normal operation.
+.Li require
+means SA is required whenever the kernel sends a packet matched
+with the policy.
+.Li unique
+is the same as
+.Li require ;
+in addition, it allows the policy to match the unique out-bound SA.
+You just specify the policy level
+.Li unique ,
+.Xr racoon 8
+will configure the SA for the policy.
+If you configure the SA by manual keying for that policy,
+you can put a decimal number as the policy identifier after
+.Li unique
+separated by a colon
+.Sq \&:
+like:
+.Li unique:number
+in order to bind this policy to the SA.
+.Li number
+must be between 1 and 32767.
+It corresponds to
+.Ar extensions Fl u
+of the manual SA configuration.
+When you want to use SA bundle, you can define multiple rules.
+For example, if an IP header was followed by an AH header followed
+by an ESP header followed by an upper layer protocol header, the
+rule would be:
+.Dl esp/transport//require ah/transport//require ;
+The rule order is very important.
+.Pp
+When NAT-T is enabled in the kernel, policy matching for ESP over
+UDP packets may be done on endpoint addresses and port
+(this depends on the system.
+System that do not perform the port check cannot support
+multiple endpoints behind the same NAT).
+When using ESP over UDP, you can specify port numbers in the endpoint
+addresses to get the correct matching.
+Here is an example:
+.Bd -literal -offset
+spdadd 10.0.11.0/24[any] 10.0.11.33/32[any] any -P out ipsec
+    esp/tunnel/192.168.0.1[4500]-192.168.1.2[30000]/require ;
+
+.Ed
+These ports must be left unspecified (which defaults to 0) for
+anything other than ESP over UDP.
+They can be displayed in SPD dump using
+.Nm
+.Fl DPp .
+.Pp
+Note that
+.Dq Li discard
+and
+.Dq Li none
+are not in the syntax described in
+.Xr ipsec_set_policy 3 .
+There are a few differences in the syntax.
+See
+.Xr ipsec_set_policy 3
+for detail.
+.El
+.\"
+.Ss Algorithms
+The following list shows the supported algorithms.
+.Sy protocol
+and
+.Sy algorithm
+are almost orthogonal.
+These authentication algorithms can be used as
+.Ar aalgo
+in
+.Fl A Ar aalgo
+of the
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm      keylen (bits)
+hmac-md5       128             ah: rfc2403
+               128             ah-old: rfc2085
+hmac-sha1      160             ah: rfc2404
+               160             ah-old: 128bit ICV (no document)
+keyed-md5      128             ah: 96bit ICV (no document)
+               128             ah-old: rfc1828
+keyed-sha1     160             ah: 96bit ICV (no document)
+               160             ah-old: 128bit ICV (no document)
+null           0 to 2048       for debugging
+hmac-sha256    256             ah: 96bit ICV
+                               (draft-ietf-ipsec-ciph-sha-256-00)
+               256             ah-old: 128bit ICV (no document)
+hmac-sha384    384             ah: 96bit ICV (no document)
+               384             ah-old: 128bit ICV (no document)
+hmac-sha512    512             ah: 96bit ICV (no document)
+               512             ah-old: 128bit ICV (no document)
+hmac-ripemd160 160             ah: 96bit ICV (RFC2857)
+                               ah-old: 128bit ICV (no document)
+aes-xcbc-mac   128             ah: 96bit ICV (RFC3566)
+               128             ah-old: 128bit ICV (no document)
+tcp-md5                8 to 640        tcp: rfc2385
+.Ed
+.Pp
+These encryption algorithms can be used as
+.Ar ealgo
+in
+.Fl E Ar ealgo
+of the
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm      keylen (bits)
+des-cbc                64              esp-old: rfc1829, esp: rfc2405
+3des-cbc       192             rfc2451
+null           0 to 2048       rfc2410
+blowfish-cbc   40 to 448       rfc2451
+cast128-cbc    40 to 128       rfc2451
+des-deriv      64              ipsec-ciph-des-derived-01
+3des-deriv     192             no document
+rijndael-cbc   128/192/256     rfc3602
+twofish-cbc    0 to 256        draft-ietf-ipsec-ciph-aes-cbc-01
+aes-ctr                160/224/288     draft-ietf-ipsec-ciph-aes-ctr-03
+.Ed
+.Pp
+Note that the first 128 bits of a key for
+.Li aes-ctr
+will be used as AES key, and the remaining 32 bits will be used as nonce.
+.Pp
+These compression algorithms can be used as
+.Ar calgo
+in
+.Fl C Ar calgo
+of the
+.Ar protocol
+parameter:
+.Pp
+.Bd -literal -offset indent
+algorithm
+deflate                rfc2394
+.Ed
+.\"
+.Ss RFC vs Linux kernel semantics
+The Linux kernel uses the
+.Ar fwd
+policy instead of the
+.Ar in
+policy for packets what are forwarded through that particular box.
+.Pp
+In
+.Ar kernel
+mode,
+.Nm
+manages and shows policies and SAs exactly as they are stored in the kernel.
+.Pp
+In
+.Ar RFC
+mode,
+.Nm
+.Bl -item
+.It
+creates
+.Ar fwd
+policies for every
+.Ar in
+policy inserted
+.It
+(not implemented yet) filters out all
+.Ar fwd
+policies
+.El
+.Sh RETURN VALUES
+The command exits with 0 on success, and non-zero on errors.
+.\"
+.Sh EXAMPLES
+.Bd -literal -offset
+add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457
+       -E des-cbc 0x3ffe05014819ffff ;
+
+add -6 myhost.example.com yourhost.example.com ah 123456
+       -A hmac-sha1 "AH SA configuration!" ;
+
+add 10.0.11.41 10.0.11.33 esp 0x10001
+       -E des-cbc 0x3ffe05014819ffff
+       -A hmac-md5 "authentication!!" ;
+
+get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ;
+
+flush ;
+
+dump esp ;
+
+spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any
+       -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ;
+
+add 10.1.10.34 10.1.10.36 tcp 0x1000 -A tcp-md5 "TCP-MD5 BGP secret" ;
+.Ed
+.\"
+.Sh SEE ALSO
+.Xr ipsec_set_policy 3 ,
+.Xr racoon 8 ,
+.Xr sysctl 8
+.Rs
+.%T "Changed manual key configuration for IPsec"
+.%O "http://www.kame.net/newsletter/19991007/"
+.%D "October 1999"
+.Re
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in the WIDE Hydrangea IPv6 protocol stack
+kit.
+The command was completely re-designed in June 1998.
+.\"
+.Sh BUGS
+.Nm
+should report and handle syntax errors better.
+.Pp
+For IPsec gateway configuration,
+.Ar src_range
+and
+.Ar dst_range
+with TCP/UDP port numbers does not work, as the gateway does not
+reassemble packets
+.Pq it cannot inspect upper-layer headers .
diff --git a/ipsec-tools/setkey/setkey.c b/ipsec-tools/setkey/setkey.c
new file mode 100644 (file)
index 0000000..1c9445f
--- /dev/null
@@ -0,0 +1,908 @@
+/*     $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <netinet/in.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <time.h>
+
+#ifdef HAVE_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include "config.h"
+#include "libpfkey.h"
+//#include "package_version.h"
+#define extern /* so that variables in extern.h are not extern... */
+#include "extern.h"
+
+#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
+
+void usage __P((/*int*/));
+int main __P((int, char **));
+int get_supported __P((void));
+void sendkeyshort __P((u_int));
+void promisc __P((void));
+int postproc __P((struct sadb_msg *, int));
+int verifypriority __P((struct sadb_msg *m));
+int fileproc __P((const char *));
+const char *numstr __P((int));
+void shortdump_hdr __P((void));
+void shortdump __P((struct sadb_msg *));
+static void printdate __P((void));
+static int32_t gmt2local __P((time_t));
+void stdin_loop __P((void));
+
+#define MODE_SCRIPT    1
+#define MODE_CMDDUMP   2
+#define MODE_CMDFLUSH  3
+#define MODE_PROMISC   4
+#define MODE_STDIN     5
+
+int so;
+
+int f_forever = 0;
+int f_all = 0;
+int f_verbose = 0;
+int f_mode = 0;
+int f_cmddump = 0;
+int f_policy = 0;
+int f_hexdump = 0;
+int f_tflag = 0;
+int f_notreally = 0;
+int f_withports = 0;
+#ifdef HAVE_POLICY_FWD
+int f_rfcmode = 1;
+#define RK_OPTS "rk"
+#else
+int f_rkwarn = 0;
+#define RK_OPTS ""
+static void rkwarn(void);
+static void
+rkwarn(void)
+{
+       if (!f_rkwarn) {
+               f_rkwarn = 1;
+               printf("warning: -r and -k options are not supported in this environment\n");
+       }
+}
+
+#endif
+static time_t thiszone;
+
+void
+usage(/*int only_version*/)
+{
+       //printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL); 
+       //if (! only_version) {
+               printf("usage: setkey [-v" RK_OPTS "] file ...\n");
+               printf("       setkey [-nv" RK_OPTS "] -c\n");
+               printf("       setkey [-nv" RK_OPTS "] -f filename\n");
+               printf("       setkey [-Palpv" RK_OPTS "] -D\n");
+               printf("       setkey [-Pv] -F\n");
+               printf("       setkey [-H] -x\n");
+               printf("       setkey [-V] [-h]\n");
+       //}
+       exit(1);
+}
+
+int
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       FILE *fp = stdin;
+       int c;
+
+       if (argc == 1) {
+               usage(0);
+               /* NOTREACHED */
+       }
+
+       thiszone = gmt2local(0);
+
+       while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) {
+               switch (c) {
+               case 'c':
+                       f_mode = MODE_STDIN;
+#ifdef HAVE_READLINE
+                       /* disable filename completion */
+                       rl_bind_key('\t', rl_insert);
+#endif
+                       break;
+               case 'f':
+                       f_mode = MODE_SCRIPT;
+                       if ((fp = fopen(optarg, "r")) == NULL) {
+                               err(1, "fopen");
+                               /*NOTREACHED*/
+                       }
+                       break;
+               case 'D':
+                       f_mode = MODE_CMDDUMP;
+                       break;
+               case 'F':
+                       f_mode = MODE_CMDFLUSH;
+                       break;
+               case 'a':
+                       f_all = 1;
+                       break;
+               case 'l':
+                       f_forever = 1;
+                       break;
+               case 'n':
+                       f_notreally = 1;
+                       break;
+#ifdef __NetBSD__
+               case 'h':
+#endif
+               case 'H':
+                       f_hexdump = 1;
+                       break;
+               case 'x':
+                       f_mode = MODE_PROMISC;
+                       f_tflag++;
+                       break;
+               case 'P':
+                       f_policy = 1;
+                       break;
+               case 'p':
+                       f_withports = 1;
+                       break;
+               case 'v':
+                       f_verbose = 1;
+                       break;
+               case 'r':
+#ifdef HAVE_POLICY_FWD
+                       f_rfcmode = 1;
+#else
+                       rkwarn();
+#endif
+                       break;
+               case 'k':
+#ifdef HAVE_POLICY_FWD
+                       f_rfcmode = 0;
+#else
+                       rkwarn();
+#endif
+                       break;
+               case 'V':
+                       usage(1);
+                       break;
+                       /*NOTREACHED*/
+#ifndef __NetBSD__
+               case 'h':
+#endif
+               case '?':
+               default:
+                       usage(0);
+                       /*NOTREACHED*/
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc > 0) {
+               while (argc--)
+                       if (fileproc(*argv++) < 0) {
+                               err(1, "%s", argv[-1]);
+                               /*NOTREACHED*/
+                       }
+               exit(0);
+       }
+
+       so = pfkey_open();
+       if (so < 0) {
+               perror("pfkey_open");
+               exit(1);
+       }
+
+       switch (f_mode) {
+       case MODE_CMDDUMP:
+               sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP);
+               break;
+       case MODE_CMDFLUSH:
+               sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
+               break;
+       case MODE_SCRIPT:
+               if (get_supported() < 0) {
+                       errx(1, "%s", ipsec_strerror());
+                       /*NOTREACHED*/
+               }
+               if (parse(&fp))
+                       exit (1);
+               break;
+       case MODE_STDIN:
+               if (get_supported() < 0) {
+                       errx(1, "%s", ipsec_strerror());
+                       /*NOTREACHED*/
+               }
+               stdin_loop();
+               break;
+       case MODE_PROMISC:
+               promisc();
+               /*NOTREACHED*/
+       default:
+               usage(0);
+               /*NOTREACHED*/
+       }
+
+       exit(0);
+}
+
+int
+get_supported()
+{
+
+       if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0)
+               return -1;
+
+       if (pfkey_recv_register(so) < 0)
+               return -1;
+
+       return (0);
+}
+
+void
+stdin_loop()
+{
+       char line[1024], *semicolon, *comment;
+       size_t linelen = 0;
+       
+       memset (line, 0, sizeof(line));
+
+       parse_init();
+       while (1) {
+#ifdef HAVE_READLINE
+               char *rbuf;
+               rbuf = readline ("");
+               if (! rbuf)
+                       break;
+#else
+               char rbuf[1024];
+               rbuf[0] = '\0';
+               fgets (rbuf, sizeof(rbuf), stdin);
+               if (!rbuf[0])
+                       break;
+               if (rbuf[strlen(rbuf)-1] == '\n')
+                       rbuf[strlen(rbuf)-1] = '\0';
+#endif
+               comment = strchr(rbuf, '#');
+               if (comment)
+                       *comment = '\0';
+
+               if (!rbuf[0])
+                       continue;
+
+               linelen += snprintf (&line[linelen], sizeof(line) - linelen,
+                                    "%s%s", linelen > 0 ? " " : "", rbuf);
+
+               semicolon = strchr(line, ';');
+               while (semicolon) {
+                       char saved_char = *++semicolon;
+                       *semicolon = '\0';
+#ifdef HAVE_READLINE
+                       add_history (line);
+#endif
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+                       last_msg_type = -1;  /* invalid message type */
+#endif
+
+                       parse_string (line);
+                       if (exit_now)
+                               return;
+                       if (saved_char) {
+                               *semicolon = saved_char;
+                               linelen = strlen (semicolon);
+                               memmove (line, semicolon, linelen + 1);
+                               semicolon = strchr(line, ';');
+                       }
+                       else {
+                               semicolon = NULL;
+                               linelen = 0;
+                       }
+               }
+       }
+}
+
+void
+sendkeyshort(type)
+        u_int type;
+{
+       struct sadb_msg msg;
+
+       msg.sadb_msg_version = PF_KEY_V2;
+       msg.sadb_msg_type = type;
+       msg.sadb_msg_errno = 0;
+       msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
+       msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
+       msg.sadb_msg_reserved = 0;
+       msg.sadb_msg_seq = 0;
+       msg.sadb_msg_pid = getpid();
+
+       sendkeymsg((char *)&msg, sizeof(msg));
+
+       return;
+}
+
+void
+promisc()
+{
+       struct sadb_msg msg;
+       u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+       ssize_t l;
+
+       msg.sadb_msg_version = PF_KEY_V2;
+       msg.sadb_msg_type = SADB_X_PROMISC;
+       msg.sadb_msg_errno = 0;
+       msg.sadb_msg_satype = 1;
+       msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
+       msg.sadb_msg_reserved = 0;
+       msg.sadb_msg_seq = 0;
+       msg.sadb_msg_pid = getpid();
+
+       if ((l = send(so, &msg, sizeof(msg), 0)) < 0) {
+               err(1, "send");
+               /*NOTREACHED*/
+       }
+
+       while (1) {
+               struct sadb_msg *base;
+
+               if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
+                       err(1, "recv");
+                       /*NOTREACHED*/
+               }
+
+               if (l != sizeof(*base))
+                       continue;
+
+               base = (struct sadb_msg *)rbuf;
+               if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
+                               0)) < 0) {
+                       err(1, "recv");
+                       /*NOTREACHED*/
+               }
+               printdate();
+               if (f_hexdump) {
+                       int i;
+                       for (i = 0; i < l; i++) {
+                               if (i % 16 == 0)
+                                       printf("%08x: ", i);
+                               printf("%02x ", rbuf[i] & 0xff);
+                               if (i % 16 == 15)
+                                       printf("\n");
+                       }
+                       if (l % 16)
+                               printf("\n");
+               }
+               /* adjust base pointer for promisc mode */
+               if (base->sadb_msg_type == SADB_X_PROMISC) {
+                       if ((ssize_t)sizeof(*base) < l)
+                               base++;
+                       else
+                               base = NULL;
+               }
+               if (base) {
+                       kdebug_sadb(base);
+                       printf("\n");
+                       fflush(stdout);
+               }
+       }
+}
+
+int
+sendkeymsg(buf, len)
+       char *buf;
+       size_t len;
+{
+       u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+       ssize_t l;
+       struct sadb_msg *msg;
+
+       if (f_notreally) {
+               goto end;
+       }
+
+    {
+       struct timeval tv;
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+       if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+               perror("setsockopt");
+               goto end;
+       }
+    }
+
+       if (f_forever)
+               shortdump_hdr();
+again:
+       if (f_verbose) {
+               kdebug_sadb((struct sadb_msg *)buf);
+               printf("\n");
+       }
+       if (f_hexdump) {
+               int i;
+               for (i = 0; i < len; i++) {
+                       if (i % 16 == 0)
+                               printf("%08x: ", i);
+                       printf("%02x ", buf[i] & 0xff);
+                       if (i % 16 == 15)
+                               printf("\n");
+               }
+               if (len % 16)
+                       printf("\n");
+       }
+
+       if ((l = send(so, buf, len, 0)) < 0) {
+               perror("send");
+               goto end;
+       }
+
+       msg = (struct sadb_msg *)rbuf;
+       do {
+               if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+                       perror("recv");
+                       goto end;
+               }
+
+               if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) {
+                       warnx("invalid keymsg length");
+                       break;
+               }
+
+               if (f_verbose) {
+                       kdebug_sadb((struct sadb_msg *)rbuf);
+                       printf("\n");
+               }
+               if (postproc(msg, l) < 0)
+                       break;
+       } while (msg->sadb_msg_errno || msg->sadb_msg_seq);
+
+       if (f_forever) {
+               fflush(stdout);
+               sleep(1);
+               goto again;
+       }
+
+end:
+       return (0);
+}
+
+int
+postproc(msg, len)
+       struct sadb_msg *msg;
+       int len;
+{
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       static int priority_support_check = 0;
+#endif
+
+       if (msg->sadb_msg_errno != 0) {
+               char inf[80];
+               const char *errmsg = NULL;
+
+               if (f_mode == MODE_SCRIPT)
+                       snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
+               else
+                       inf[0] = '\0';
+
+               switch (msg->sadb_msg_errno) {
+               case ENOENT:
+                       switch (msg->sadb_msg_type) {
+                       case SADB_DELETE:
+                       case SADB_GET:
+                       case SADB_X_SPDDELETE:
+                               errmsg = "No entry";
+                               break;
+                       case SADB_DUMP:
+                               errmsg = "No SAD entries";
+                               break;
+                       case SADB_X_SPDDUMP:
+                               errmsg = "No SPD entries";
+                               break;
+                       }
+                       break;
+               default:
+                       errmsg = strerror(msg->sadb_msg_errno);
+               }
+               printf("%s%s.\n", inf, errmsg);
+               return (-1);
+       }
+
+       switch (msg->sadb_msg_type) {
+       case SADB_GET:
+               if (f_withports)
+                       pfkey_sadump_withports(msg);
+               else
+                       pfkey_sadump(msg);
+               break;
+
+       case SADB_DUMP:
+               /* filter out DEAD SAs */
+               if (!f_all) {
+                       caddr_t mhp[SADB_EXT_MAX + 1];
+                       struct sadb_sa *sa;
+                       pfkey_align(msg, mhp);
+                       pfkey_check(mhp);
+                       if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+                               if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
+                                       break;
+                       }
+               }
+               if (f_forever) {
+                       /* TODO: f_withports */
+                       shortdump(msg);
+               } else {
+                       if (f_withports)
+                               pfkey_sadump_withports(msg);
+                       else
+                               pfkey_sadump(msg);
+               }
+               msg = (struct sadb_msg *)((caddr_t)msg +
+                                    PFKEY_UNUNIT64(msg->sadb_msg_len));
+               if (f_verbose) {
+                       kdebug_sadb((struct sadb_msg *)msg);
+                       printf("\n");
+               }
+               break;
+
+       case SADB_X_SPDGET:
+               if (f_withports) 
+                       pfkey_spdump_withports(msg);
+               else
+                       pfkey_spdump(msg);
+               break;
+
+       case SADB_X_SPDDUMP:
+               if (f_withports) 
+                       pfkey_spdump_withports(msg);
+               else
+                       pfkey_spdump(msg);
+               if (msg->sadb_msg_seq == 0) break;
+               msg = (struct sadb_msg *)((caddr_t)msg +
+                                    PFKEY_UNUNIT64(msg->sadb_msg_len));
+               if (f_verbose) {
+                       kdebug_sadb((struct sadb_msg *)msg);
+                       printf("\n");
+               }
+               break;
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+       case SADB_X_SPDADD:
+               if (last_msg_type == SADB_X_SPDADD && last_priority != 0 && 
+                   msg->sadb_msg_pid == getpid() && !priority_support_check) {
+                       priority_support_check = 1;     
+                       if (!verifypriority(msg))
+                               printf ("WARNING: Kernel does not support policy priorities\n");
+               }
+               break;
+#endif
+       }
+
+       return (0);
+}
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+int
+verifypriority(m)
+       struct sadb_msg *m;
+{
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       struct sadb_x_policy *xpl;
+
+       /* check pfkey message. */
+       if (pfkey_align(m, mhp)) {
+               printf("(%s\n", ipsec_strerror());
+               return 0;
+       }
+       if (pfkey_check(mhp)) {
+               printf("%s\n", ipsec_strerror());
+               return 0;
+       }
+
+       xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY];
+
+       if (xpl == NULL) {
+               printf("no X_POLICY extension.\n");
+               return 0;
+       }
+
+       /* now make sure they match */
+       if (last_priority != xpl->sadb_x_policy_priority)
+               return 0;
+
+       return 1; 
+}
+#endif
+
+int
+fileproc(filename)
+       const char *filename;
+{
+       int fd;
+       ssize_t len, l;
+       u_char *p, *ep;
+       struct sadb_msg *msg;
+       u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       l = 0;
+       while (1) {
+               len = read(fd, rbuf + l, sizeof(rbuf) - l);
+               if (len < 0) {
+                       close(fd);
+                       return -1;
+               } else if (len == 0)
+                       break;
+               l += len;
+       }
+
+       if (l < sizeof(struct sadb_msg)) {
+               close(fd);
+               errno = EINVAL;
+               return -1;
+       }
+       close(fd);
+
+       p = rbuf;
+       ep = rbuf + l;
+
+       while (p < ep) {
+               msg = (struct sadb_msg *)p;
+               len = PFKEY_UNUNIT64(msg->sadb_msg_len);
+               postproc(msg, len);
+               p += len;
+       }
+
+       return (0);
+}
+
+
+/*------------------------------------------------------------*/
+static const char *satype[] = {
+       NULL, NULL, "ah", "esp"
+};
+static const char *sastate[] = {
+       "L", "M", "D", "d"
+};
+static const char *ipproto[] = {
+/*0*/  "ip", "icmp", "igmp", "ggp", "ip4",
+       NULL, "tcp", NULL, "egp", NULL,
+/*10*/ NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, "udp", NULL, NULL,
+/*20*/ NULL, NULL, "idp", NULL, NULL,
+       NULL, NULL, NULL, NULL, "tp",
+/*30*/ NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL,
+/*40*/ NULL, "ip6", NULL, "rt6", "frag6",
+       NULL, "rsvp", "gre", NULL, NULL,
+/*50*/ "esp", "ah", NULL, NULL, NULL,
+       NULL, NULL, NULL, "icmp6", "none",
+/*60*/ "dst6",
+};
+
+#define STR_OR_ID(x, tab) \
+       (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
+
+const char *
+numstr(x)
+       int x;
+{
+       static char buf[20];
+       snprintf(buf, sizeof(buf), "#%d", x);
+       return buf;
+}
+
+void
+shortdump_hdr()
+{
+       printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
+               "time", "p", "s", "spi", "ltime", "src", "dst");
+}
+
+void
+shortdump(msg)
+       struct sadb_msg *msg;
+{
+       caddr_t mhp[SADB_EXT_MAX + 1];
+       char buf[NI_MAXHOST], pbuf[NI_MAXSERV];
+       struct sadb_sa *sa;
+       struct sadb_address *saddr;
+       struct sadb_lifetime *lts, *lth, *ltc;
+       struct sockaddr *s;
+       u_int t;
+       time_t cur = time(0);
+
+       pfkey_align(msg, mhp);
+       pfkey_check(mhp);
+
+       printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
+
+       printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
+
+       if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
+               printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
+               printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
+       } else
+               printf("%-1s %-8s", "?", "?");
+
+       lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+       lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+       ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+       if (lts && lth && ltc) {
+               if (ltc->sadb_lifetime_addtime == 0)
+                       t = (u_long)0;
+               else
+                       t = (u_long)(cur - ltc->sadb_lifetime_addtime);
+               if (t >= 1000)
+                       strlcpy(buf, " big/", sizeof(buf));
+               else
+                       snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
+               printf("%s", buf);
+
+               t = (u_long)lth->sadb_lifetime_addtime;
+               if (t >= 1000)
+                       strlcpy(buf, "big", sizeof(buf));
+               else
+                       snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
+               printf("%s", buf);
+       } else
+               printf(" ??\?/???");    /* backslash to avoid trigraph ??/ */
+
+       printf(" ");
+
+       if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
+               if (saddr->sadb_address_proto)
+                       printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+               s = (struct sockaddr *)(saddr + 1);
+               getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
+                       pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+               if (strcmp(pbuf, "0") != 0)
+                       printf("%s[%s]", buf, pbuf);
+               else
+                       printf("%s", buf);
+       } else
+               printf("?");
+
+       printf(" -> ");
+
+       if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
+               if (saddr->sadb_address_proto)
+                       printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
+
+               s = (struct sockaddr *)(saddr + 1);
+               getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
+                       pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
+               if (strcmp(pbuf, "0") != 0)
+                       printf("%s[%s]", buf, pbuf);
+               else
+                       printf("%s", buf);
+       } else
+               printf("?");
+
+       printf("\n");
+}
+
+/* From: tcpdump(1):gmt2local.c and util.c */
+/*
+ * Print the timestamp
+ */
+static void
+printdate()
+{
+       struct timeval tp;
+       int s;
+
+       if (gettimeofday(&tp, NULL) == -1) {
+               perror("gettimeofday");
+               return;
+       }
+
+       if (f_tflag == 1) {
+               /* Default */
+               s = (tp.tv_sec + thiszone ) % 86400;
+               (void)printf("%02d:%02d:%02d.%06u ",
+                   s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec);
+       } else if (f_tflag > 1) {
+               /* Unix timeval style */
+               (void)printf("%u.%06u ",
+                   (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec);
+       }
+
+       printf("\n");
+}
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ */
+int32_t
+gmt2local(time_t t)
+{
+       register int dt, dir;
+       register struct tm *gmt, *loc;
+       struct tm sgmt;
+
+       if (t == 0)
+               t = time(NULL);
+       gmt = &sgmt;
+       *gmt = *gmtime(&t);
+       loc = localtime(&t);
+       dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+           (loc->tm_min - gmt->tm_min) * 60;
+
+       /*
+        * If the year or julian day is different, we span 00:00 GMT
+        * and must add or subtract a day. Check the year first to
+        * avoid problems when the julian day wraps.
+        */
+       dir = loc->tm_year - gmt->tm_year;
+       if (dir == 0)
+               dir = loc->tm_yday - gmt->tm_yday;
+       dt += dir * 24 * 60 * 60;
+
+       return (dt);
+}
diff --git a/ipsec-tools/setkey/test-pfkey.c b/ipsec-tools/setkey/test-pfkey.c
new file mode 100644 (file)
index 0000000..fb80000
--- /dev/null
@@ -0,0 +1,571 @@
+/*     $KAME: test-pfkey.c,v 1.4 2000/06/07 00:29:14 itojun Exp $      */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#include <System/netkey/keydb.h>
+#include <System/netkey/key_var.h>
+#include <System/netkey/key_debug.h>
+#else
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netkey/key_var.h>
+#include <netkey/key_debug.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+
+u_char m_buf[BUFSIZ];
+u_int m_len;
+char *pname;
+
+void Usage __P((void));
+int sendkeymsg __P((void));
+void key_setsadbmsg __P((u_int));
+void key_setsadbsens __P((void));
+void key_setsadbprop __P((void));
+void key_setsadbid __P((u_int, caddr_t));
+void key_setsadblft __P((u_int, u_int));
+void key_setspirange __P((void));
+void key_setsadbkey __P((u_int, caddr_t));
+void key_setsadbsa __P((void));
+void key_setsadbaddr __P((u_int, u_int, caddr_t));
+void key_setsadbextbuf __P((caddr_t, int, caddr_t, int, caddr_t, int));
+
+void
+Usage()
+{
+       printf("Usage:\t%s number\n", pname);
+       exit(0);
+}
+
+int
+main(ac, av)
+       int ac;
+       char **av;
+{
+       pname = *av;
+
+       if (ac == 1) Usage();
+
+       key_setsadbmsg(atoi(*(av+1)));
+       sendkeymsg();
+
+       exit(0);
+}
+
+/* %%% */
+int
+sendkeymsg()
+{
+       u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
+       int so, len;
+
+       if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+               perror("socket(PF_KEY)");
+               goto end;
+       }
+#if 0
+    {
+#include <sys/time.h>
+       struct timeval tv;
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+       if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+               perror("setsockopt");
+               goto end;
+       }
+    }
+#endif
+
+       pfkey_sadump((struct sadb_msg *)m_buf);
+
+       if ((len = send(so, m_buf, m_len, 0)) < 0) {
+               perror("send");
+               goto end;
+       }
+
+       if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+               perror("recv");
+               goto end;
+       }
+
+       pfkey_sadump((struct sadb_msg *)rbuf);
+
+end:
+       (void)close(so);
+       return(0);
+}
+
+void
+key_setsadbmsg(type)
+       u_int type;
+{
+       struct sadb_msg m_msg;
+
+       memset(&m_msg, 0, sizeof(m_msg));
+       m_msg.sadb_msg_version = PF_KEY_V2;
+       m_msg.sadb_msg_type = type;
+       m_msg.sadb_msg_errno = 0;
+       m_msg.sadb_msg_satype = SADB_SATYPE_ESP;
+#if 0
+       m_msg.sadb_msg_reserved = 0;
+#endif
+       m_msg.sadb_msg_seq = 0;
+       m_msg.sadb_msg_pid = getpid();
+
+       m_len = sizeof(struct sadb_msg);
+       memcpy(m_buf, &m_msg, m_len);
+
+       switch (type) {
+       case SADB_GETSPI:
+               /*<base, address(SD), SPI range>*/
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "10.0.3.4");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "127.0.0.1");
+               key_setspirange();
+               /*<base, SA(*), address(SD)>*/
+               break;
+
+       case SADB_ADD:
+               /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+                  key(AE), (identity(SD),) (sensitivity)> */
+               key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+       case SADB_UPDATE:
+               key_setsadbsa();
+               key_setsadblft(SADB_EXT_LIFETIME_HARD, 10);
+               key_setsadblft(SADB_EXT_LIFETIME_SOFT, 5);
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+               /* XXX key_setsadbkey(SADB_EXT_KEY_AUTH, "abcde"); */
+               key_setsadbkey(SADB_EXT_KEY_AUTH, "1234567812345678");
+               key_setsadbkey(SADB_EXT_KEY_ENCRYPT, "12345678");
+               key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+               key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+               key_setsadbsens();
+               /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+                 (identity(SD),) (sensitivity)> */
+               break;
+
+       case SADB_DELETE:
+               /* <base, SA(*), address(SDP)> */
+               key_setsadbsa();
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+               key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+               /* <base, SA(*), address(SDP)> */
+               break;
+
+       case SADB_GET:
+               /* <base, SA(*), address(SDP)> */
+               key_setsadbsa();
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+               key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+               /* <base, SA, (lifetime(HSC),) address(SD), (address(P),)
+                  key(AE), (identity(SD),) (sensitivity)> */
+               break;
+
+       case SADB_ACQUIRE:
+               /* <base, address(SD), (address(P),) (identity(SD),)
+                  (sensitivity,) proposal> */
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+               key_setsadbaddr(SADB_EXT_ADDRESS_PROXY, AF_INET6, "3ffe::1");
+               key_setsadbid(SADB_EXT_IDENTITY_SRC, "hoge1234@hoge.com");
+               key_setsadbid(SADB_EXT_IDENTITY_DST, "hage5678@hage.net");
+               key_setsadbsens();
+               key_setsadbprop();
+               /* <base, address(SD), (address(P),) (identity(SD),)
+                  (sensitivity,) proposal> */
+               break;
+
+       case SADB_REGISTER:
+               /* <base> */
+               /* <base, supported> */
+               break;
+
+       case SADB_EXPIRE:
+       case SADB_FLUSH:
+               break;
+
+       case SADB_DUMP:
+               break;
+
+       case SADB_X_PROMISC:
+               /* <base> */
+               /* <base, base(, others)> */
+               break;
+
+       case SADB_X_PCHANGE:
+               break;
+
+       /* for SPD management */
+       case SADB_X_SPDFLUSH:
+       case SADB_X_SPDDUMP:
+               break;
+
+       case SADB_X_SPDADD:
+#if 0
+           {
+               struct sadb_x_policy m_policy;
+
+               m_policy.sadb_x_policy_len = PFKEY_UNIT64(sizeof(m_policy));
+               m_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+               m_policy.sadb_x_policy_type = SADB_X_PL_IPSEC;
+               m_policy.sadb_x_policy_esp_trans = 1;
+               m_policy.sadb_x_policy_ah_trans = 2;
+               m_policy.sadb_x_policy_esp_network = 3;
+               m_policy.sadb_x_policy_ah_network = 4;
+               m_policy.sadb_x_policy_reserved = 0;
+
+               memcpy(m_buf + m_len, &m_policy, sizeof(struct sadb_x_policy));
+               m_len += sizeof(struct sadb_x_policy);
+           }
+#endif
+
+       case SADB_X_SPDDELETE:
+               key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1");
+               key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4");
+               break;
+       }
+
+       ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len);
+
+       return;
+}
+
+void
+key_setsadbsens()
+{
+       struct sadb_sens m_sens;
+       u_char buf[64];
+       u_int s, i, slen, ilen, len;
+
+       /* make sens & integ */
+       s = htonl(0x01234567);
+       i = htonl(0x89abcdef);
+       slen = sizeof(s);
+       ilen = sizeof(i);
+       memcpy(buf, &s, slen);
+       memcpy(buf + slen, &i, ilen);
+
+       len = sizeof(m_sens) + PFKEY_ALIGN8(slen) + PFKEY_ALIGN8(ilen);
+       m_sens.sadb_sens_len = PFKEY_UNIT64(len);
+       m_sens.sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+       m_sens.sadb_sens_dpd = 1;
+       m_sens.sadb_sens_sens_level = 2;
+       m_sens.sadb_sens_sens_len = PFKEY_ALIGN8(slen);
+       m_sens.sadb_sens_integ_level = 3;
+       m_sens.sadb_sens_integ_len = PFKEY_ALIGN8(ilen);
+       m_sens.sadb_sens_reserved = 0;
+
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_sens, sizeof(struct sadb_sens),
+                       buf, slen + ilen);
+       m_len += len;
+
+       return;
+}
+
+void
+key_setsadbprop()
+{
+       struct sadb_prop m_prop;
+       struct sadb_comb *m_comb;
+       u_char buf[256];
+#if defined(SADB_X_EALG_AESCBC) && defined(SADB_X_AALG_SHA2_256)
+       u_int len = sizeof(m_prop) + sizeof(m_comb) * 3;
+#else
+       u_int len = sizeof(m_prop) + sizeof(m_comb) * 2;
+#endif
+
+       /* make prop & comb */
+       m_prop.sadb_prop_len = PFKEY_UNIT64(len);
+       m_prop.sadb_prop_exttype = SADB_EXT_PROPOSAL;
+       m_prop.sadb_prop_replay = 0;
+       m_prop.sadb_prop_reserved[0] = 0;
+       m_prop.sadb_prop_reserved[1] = 0;
+       m_prop.sadb_prop_reserved[2] = 0;
+
+       /* the 1st is ESP DES-CBC HMAC-MD5 */
+       m_comb = (struct sadb_comb *)buf;
+       m_comb->sadb_comb_auth = SADB_AALG_MD5HMAC;
+       m_comb->sadb_comb_encrypt = SADB_EALG_DESCBC;
+       m_comb->sadb_comb_flags = 0;
+       m_comb->sadb_comb_auth_minbits = 8;
+       m_comb->sadb_comb_auth_maxbits = 96;
+       m_comb->sadb_comb_encrypt_minbits = 64;
+       m_comb->sadb_comb_encrypt_maxbits = 64;
+       m_comb->sadb_comb_reserved = 0;
+       m_comb->sadb_comb_soft_allocations = 0;
+       m_comb->sadb_comb_hard_allocations = 0;
+       m_comb->sadb_comb_soft_bytes = 0;
+       m_comb->sadb_comb_hard_bytes = 0;
+       m_comb->sadb_comb_soft_addtime = 0;
+       m_comb->sadb_comb_hard_addtime = 0;
+       m_comb->sadb_comb_soft_usetime = 0;
+       m_comb->sadb_comb_hard_usetime = 0;
+
+       /* the 2st is ESP 3DES-CBC and AH HMAC-SHA1 */
+       m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb));
+       m_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC;
+       m_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC;
+       m_comb->sadb_comb_flags = 0;
+       m_comb->sadb_comb_auth_minbits = 8;
+       m_comb->sadb_comb_auth_maxbits = 96;
+       m_comb->sadb_comb_encrypt_minbits = 64;
+       m_comb->sadb_comb_encrypt_maxbits = 64;
+       m_comb->sadb_comb_reserved = 0;
+       m_comb->sadb_comb_soft_allocations = 0;
+       m_comb->sadb_comb_hard_allocations = 0;
+       m_comb->sadb_comb_soft_bytes = 0;
+       m_comb->sadb_comb_hard_bytes = 0;
+       m_comb->sadb_comb_soft_addtime = 0;
+       m_comb->sadb_comb_hard_addtime = 0;
+       m_comb->sadb_comb_soft_usetime = 0;
+       m_comb->sadb_comb_hard_usetime = 0;
+
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_prop, sizeof(struct sadb_prop),
+                       buf, sizeof(*m_comb) * 2);
+       m_len += len;
+
+ #if defined(SADB_X_EALG_AESCBC) && defined(SADB_X_AALG_SHA2_256)
+       /* the 3rd is ESP AES-CBC and AH HMAC-SHA256 */
+       m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb));
+       m_comb->sadb_comb_auth = SADB_X_AALG_SHA2_256;
+       m_comb->sadb_comb_encrypt = SADB_X_EALG_AESCBC;
+       m_comb->sadb_comb_flags = 0;
+       m_comb->sadb_comb_auth_minbits = 8;
+       m_comb->sadb_comb_auth_maxbits = 96;
+       m_comb->sadb_comb_encrypt_minbits = 128;
+       m_comb->sadb_comb_encrypt_maxbits = 128;
+       m_comb->sadb_comb_reserved = 0;
+       m_comb->sadb_comb_soft_allocations = 0;
+       m_comb->sadb_comb_hard_allocations = 0;
+       m_comb->sadb_comb_soft_bytes = 0;
+       m_comb->sadb_comb_hard_bytes = 0;
+       m_comb->sadb_comb_soft_addtime = 0;
+       m_comb->sadb_comb_hard_addtime = 0;
+       m_comb->sadb_comb_soft_usetime = 0;
+       m_comb->sadb_comb_hard_usetime = 0;
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_prop, sizeof(struct sadb_prop),
+                       buf, sizeof(*m_comb) * 3);
+       m_len += len;
+#else
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_prop, sizeof(struct sadb_prop),
+                       buf, sizeof(*m_comb) * 2);
+       m_len += len;
+#endif
+       return;
+}
+
+void
+key_setsadbid(ext, str)
+       u_int ext;
+       caddr_t str;
+{
+       struct sadb_ident m_id;
+       u_int idlen = strlen(str), len;
+
+       len = sizeof(m_id) + PFKEY_ALIGN8(idlen);
+       m_id.sadb_ident_len = PFKEY_UNIT64(len);
+       m_id.sadb_ident_exttype = ext;
+       m_id.sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
+       m_id.sadb_ident_reserved = 0;
+       m_id.sadb_ident_id = getpid();
+
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_id, sizeof(struct sadb_ident),
+                       str, idlen);
+       m_len += len;
+
+       return;
+}
+
+void
+key_setsadblft(ext, time)
+       u_int ext, time;
+{
+       struct sadb_lifetime m_lft;
+
+       m_lft.sadb_lifetime_len = PFKEY_UNIT64(sizeof(m_lft));
+       m_lft.sadb_lifetime_exttype = ext;
+       m_lft.sadb_lifetime_allocations = 0x2;
+       m_lft.sadb_lifetime_bytes = 0x1000;
+       m_lft.sadb_lifetime_addtime = time;
+       m_lft.sadb_lifetime_usetime = 0x0020;
+
+       memcpy(m_buf + m_len, &m_lft, sizeof(struct sadb_lifetime));
+       m_len += sizeof(struct sadb_lifetime);
+
+       return;
+}
+
+void
+key_setspirange()
+{
+       struct sadb_spirange m_spi;
+
+       m_spi.sadb_spirange_len = PFKEY_UNIT64(sizeof(m_spi));
+       m_spi.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+       m_spi.sadb_spirange_min = 0x00001000;
+       m_spi.sadb_spirange_max = 0x00002000;
+       m_spi.sadb_spirange_reserved = 0;
+
+       memcpy(m_buf + m_len, &m_spi, sizeof(struct sadb_spirange));
+       m_len += sizeof(struct sadb_spirange);
+
+       return;
+}
+
+void
+key_setsadbkey(ext, str)
+       u_int ext;
+       caddr_t str;
+{
+       struct sadb_key m_key;
+       u_int keylen = strlen(str);
+       u_int len;
+
+       len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+       m_key.sadb_key_len = PFKEY_UNIT64(len);
+       m_key.sadb_key_exttype = ext;
+       m_key.sadb_key_bits = keylen * 8;
+       m_key.sadb_key_reserved = 0;
+
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_key, sizeof(struct sadb_key),
+                       str, keylen);
+       m_len += len;
+
+       return;
+}
+
+void
+key_setsadbsa()
+{
+       struct sadb_sa m_sa;
+
+       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(0x12345678);
+       m_sa.sadb_sa_replay = 4;
+       m_sa.sadb_sa_state = 0;
+       m_sa.sadb_sa_auth = SADB_AALG_MD5HMAC;
+       m_sa.sadb_sa_encrypt = SADB_EALG_DESCBC;
+       m_sa.sadb_sa_flags = 0;
+
+       memcpy(m_buf + m_len, &m_sa, sizeof(struct sadb_sa));
+       m_len += sizeof(struct sadb_sa);
+
+       return;
+}
+
+void
+key_setsadbaddr(ext, af, str)
+       u_int ext, af;
+       caddr_t str;
+{
+       struct sadb_address m_addr;
+       u_int len;
+       struct addrinfo hints, *res;
+       const char *serv;
+       int plen;
+
+       switch (af) {
+       case AF_INET:
+               plen = sizeof(struct in_addr) << 3;
+               break;
+       case AF_INET6:
+               plen = sizeof(struct in6_addr) << 3;
+               break;
+       default:
+               /* XXX bark */
+               exit(1);
+       }
+
+       /* make sockaddr buffer */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = af;
+       hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+       hints.ai_flags = AI_NUMERICHOST;
+       serv = (ext == SADB_EXT_ADDRESS_PROXY ? "0" : "4660");  /*0x1234*/
+       if (getaddrinfo(str, serv, &hints, &res) != 0 || res->ai_next) {
+               /* XXX bark */
+               exit(1);
+       }
+       
+       len = sizeof(struct sadb_address) + PFKEY_ALIGN8(res->ai_addrlen);
+       m_addr.sadb_address_len = PFKEY_UNIT64(len);
+       m_addr.sadb_address_exttype = ext;
+       m_addr.sadb_address_proto =
+               (ext == SADB_EXT_ADDRESS_PROXY ? 0 : IPPROTO_TCP);
+       m_addr.sadb_address_prefixlen = plen;
+       m_addr.sadb_address_reserved = 0;
+
+       key_setsadbextbuf(m_buf, m_len,
+                       (caddr_t)&m_addr, sizeof(struct sadb_address),
+                       (caddr_t)res->ai_addr, res->ai_addrlen);
+       m_len += len;
+
+       freeaddrinfo(res);
+
+       return;
+}
+
+void
+key_setsadbextbuf(dst, off, ebuf, elen, vbuf, vlen)
+       caddr_t dst, ebuf, vbuf;
+       int off, elen, vlen;
+{
+       memset(dst + off, 0, elen + vlen);
+       memcpy(dst + off, (caddr_t)ebuf, elen);
+       memcpy(dst + off + elen, vbuf, vlen);
+
+       return;
+}
+
diff --git a/ipsec-tools/setkey/token.l b/ipsec-tools/setkey/token.l
new file mode 100644 (file)
index 0000000..a890d95
--- /dev/null
@@ -0,0 +1,353 @@
+/*     $KAME: token.l,v 1.44 2003/10/21 07:20:58 itojun Exp $  */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+%option noyywrap
+%{
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef __APPLE__
+#include <System/net/pfkeyv2.h>
+#else
+#include <net/pfkeyv2.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_NETINET6_IPSEC
+#  include <netinet6/ipsec.h>
+#else 
+#  include <netinet/ipsec.h>
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "vchar.h"
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__)
+#include "parse.h"
+#else
+#include "y.tab.h"
+#endif
+
+#include "extern.h"
+
+/* make the code compile on *BSD-current */
+#ifndef SADB_X_AALG_SHA2_256
+#define SADB_X_AALG_SHA2_256   (-1)
+#endif
+#ifndef SADB_X_AALG_SHA2_384
+#define SADB_X_AALG_SHA2_384   (-1)
+#endif
+#ifndef SADB_X_AALG_SHA2_512
+#define SADB_X_AALG_SHA2_512   (-1)
+#endif
+#ifndef SADB_X_AALG_RIPEMD160HMAC
+#define SADB_X_AALG_RIPEMD160HMAC      (-1)
+#endif
+#ifndef SADB_X_AALG_AES_XCBC_MAC
+#define SADB_X_AALG_AES_XCBC_MAC       (-1)
+#endif
+#ifndef SADB_X_EALG_TWOFISHCBC
+#define SADB_X_EALG_TWOFISHCBC (-1)
+#endif
+#ifndef SADB_X_EALG_AESCTR
+#define SADB_X_EALG_AESCTR     (-1)
+#endif
+%}
+
+/* common section */
+nl             \n
+ws             [ \t]+
+digit          [0-9]
+letter         [0-9A-Za-z]
+hexdigit       [0-9A-Fa-f]
+dot            \.
+hyphen         \-
+slash          \/
+blcl           \[
+elcl           \]
+semi           \;
+comment                \#.*
+quotedstring   \"[^"]*\"
+decstring      {digit}+
+hexstring      0[xX]{hexdigit}+
+ipaddress      [a-fA-F0-9:]([a-fA-F0-9:\.]*|[a-fA-F0-9:\.]*%[a-zA-Z0-9]*)
+ipaddrmask     {slash}{digit}{1,3}
+name           {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))*
+hostname       {name}(({dot}{name})+{dot}?)?
+
+%s S_PL S_AUTHALG S_ENCALG
+
+%%
+
+add            { return(ADD); }
+delete         { return(DELETE); }
+deleteall      { return(DELETEALL); }
+get            { return(GET); }
+flush          { return(FLUSH); }
+dump           { return(DUMP); }
+exit           { return(EXIT); }
+quit           { return(EXIT); }
+bye            { return(EXIT); }
+
+       /* for management SPD */
+spdadd         { return(SPDADD); }
+spddelete      { return(SPDDELETE); }
+spddump                { return(SPDDUMP); }
+spdflush       { return(SPDFLUSH); }
+tagged         { return(TAGGED); }
+{hyphen}P      { BEGIN S_PL; return(F_POLICY); }
+<S_PL>[a-zA-Z0-9:\.\-_/ \n\t][a-zA-Z0-9:\.%\-+_/ \n\t\]\[]* {
+                       yymore();
+
+                       /* count up for nl */
+                           {
+                               char *p;
+                               for (p = yytext; *p != '\0'; p++)
+                                       if (*p == '\n')
+                                               lineno++;
+                           }
+
+                       yylval.val.len = strlen(yytext);
+                       yylval.val.buf = strdup(yytext);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+
+                       return(PL_REQUESTS);
+               }
+<S_PL>{semi}   { BEGIN INITIAL; return(EOT); }
+
+       /* address resolution flags */
+{hyphen}[n46][n46]*    {
+                       yylval.val.len = strlen(yytext);
+                       yylval.val.buf = strdup(yytext);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+                       return(F_AIFLAGS);
+               }
+
+       /* security protocols */
+ah             { yylval.num = 0; return(PR_AH); }
+esp            { yylval.num = 0; return(PR_ESP); }
+ah-old         { yylval.num = 1; return(PR_AH); }
+esp-old                { yylval.num = 1; return(PR_ESP); }
+esp-udp                { yylval.num = 0; return(PR_ESPUDP); }
+ipcomp         { yylval.num = 0; return(PR_IPCOMP); }
+tcp            { 
+                       yylval.num = 0; return(PR_TCP); 
+               }
+
+       /* authentication alogorithm */
+{hyphen}A      { BEGIN S_AUTHALG; return(F_AUTH); }
+<S_AUTHALG>hmac-md5    { yylval.num = SADB_AALG_MD5HMAC; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha1   { yylval.num = SADB_AALG_SHA1HMAC; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>keyed-md5   { yylval.num = SADB_X_AALG_MD5; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>keyed-sha1  { yylval.num = SADB_X_AALG_SHA; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha2-256 { yylval.num = SADB_X_AALG_SHA2_256; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha256 { yylval.num = SADB_X_AALG_SHA2_256; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha2-384 { yylval.num = SADB_X_AALG_SHA2_384; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha384 { yylval.num = SADB_X_AALG_SHA2_384; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha2-512 { yylval.num = SADB_X_AALG_SHA2_512; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-sha512 { yylval.num = SADB_X_AALG_SHA2_512; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>hmac-ripemd160 { yylval.num = SADB_X_AALG_RIPEMD160HMAC; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>aes-xcbc-mac { yylval.num = SADB_X_AALG_AES_XCBC_MAC; BEGIN INITIAL; return(ALG_AUTH); }
+<S_AUTHALG>tcp-md5     { 
+#ifdef SADB_X_AALG_TCP_MD5
+                               yylval.num = SADB_X_AALG_TCP_MD5; 
+                               BEGIN INITIAL; 
+                               return(ALG_AUTH); 
+#endif
+                       }
+<S_AUTHALG>null { yylval.num = SADB_X_AALG_NULL; BEGIN INITIAL; return(ALG_AUTH_NOKEY); }
+
+       /* encryption alogorithm */
+{hyphen}E      { BEGIN S_ENCALG; return(F_ENC); }
+<S_ENCALG>des-cbc      { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>3des-cbc     { yylval.num = SADB_EALG_3DESCBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>null         { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_NOKEY); }
+<S_ENCALG>simple       { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_OLD); }
+<S_ENCALG>blowfish-cbc { yylval.num = SADB_X_EALG_BLOWFISHCBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>cast128-cbc  { yylval.num = SADB_X_EALG_CAST128CBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>des-deriv    { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DESDERIV); }
+<S_ENCALG>des-32iv     { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DES32IV); }
+<S_ENCALG>twofish-cbc  { yylval.num = SADB_X_EALG_TWOFISHCBC; BEGIN INITIAL; return(ALG_ENC); }
+<S_ENCALG>aes-cbc      { 
+#ifdef SADB_X_EALG_AESCBC
+       yylval.num = SADB_X_EALG_AESCBC; BEGIN INITIAL; return(ALG_ENC); 
+#endif
+}
+<S_ENCALG>rijndael-cbc { 
+#ifdef SADB_X_EALG_AESCBC
+       yylval.num = SADB_X_EALG_AESCBC; BEGIN INITIAL; return(ALG_ENC); 
+#endif
+}
+<S_ENCALG>aes-ctr      { yylval.num = SADB_X_EALG_AESCTR; BEGIN INITIAL; return(ALG_ENC); }
+
+       /* compression algorithms */
+{hyphen}C      { return(F_COMP); }
+oui            { yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); }
+deflate                { yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); }
+lzs            { yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); }
+{hyphen}R      { return(F_RAWCPI); }
+
+       /* extension */
+{hyphen}m      { return(F_MODE); }
+transport      { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel         { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
+{hyphen}u      { return(F_REQID); }
+{hyphen}f      { return(F_EXT); }
+random-pad     { yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); }
+seq-pad                { yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); }
+zero-pad       { yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); }
+nocyclic-seq   { return(NOCYCLICSEQ); }
+{hyphen}r      { return(F_REPLAY); }
+{hyphen}lh     { return(F_LIFETIME_HARD); }
+{hyphen}ls     { return(F_LIFETIME_SOFT); }
+{hyphen}bh     { return(F_LIFEBYTE_HARD); }
+{hyphen}bs     { return(F_LIFEBYTE_SOFT); }
+
+       /* ... */
+any            { return(ANY); }
+{ws}           { }
+{nl}           { lineno++; }
+{comment}
+{semi}         { return(EOT); }
+
+       /* for address parameters: /prefix, [port] */
+{slash}                { return SLASH; }
+{blcl}         { return BLCL; }
+{elcl}         { return ELCL; }
+
+       /* parameter */
+{decstring}    {
+                       char *bp;
+
+                       yylval.ulnum = strtoul(yytext, &bp, 10);
+                       return(DECSTRING);
+               }
+
+{hexstring}    {
+                       yylval.val.buf = strdup(yytext + 2);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+                       yylval.val.len = strlen(yylval.val.buf);
+
+                       return(HEXSTRING);
+               }
+
+{quotedstring} {
+                       char *p = yytext;
+                       while (*++p != '"') ;
+                       *p = '\0';
+                       yytext++;
+                       yylval.val.len = yyleng - 2;
+                       yylval.val.buf = strdup(yytext);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+
+                       return(QUOTEDSTRING);
+               }
+
+[A-Za-z0-9:][A-Za-z0-9:%\.-]* {
+                       yylval.val.len = yyleng;
+                       yylval.val.buf = strdup(yytext);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+                       return(STRING);
+               }
+
+[0-9,]+ {
+                       yylval.val.len = yyleng;
+                       yylval.val.buf = strdup(yytext);
+                       if (!yylval.val.buf)
+                               yyfatal("insufficient memory");
+                       return(STRING);
+               }
+
+.              {
+                       yyfatal("Syntax error");
+                       /*NOTREACHED*/
+               }
+
+%%
+
+void
+yyfatal(s)
+       const char *s;
+{
+       yyerror(s);
+       exit(1);
+}
+
+void
+yyerror(s)
+       const char *s;
+{
+       printf("line %d: %s at [%s]\n", lineno, s, yytext);
+}
+
+int
+parse(fp)
+       FILE **fp;
+{
+       yyin = *fp;
+
+       lineno = 1;
+       parse_init();
+
+       if (yyparse()) {
+               printf("parse failed, line %d.\n", lineno);
+               return(-1);
+       }
+
+       return(0);
+}
+
+int
+parse_string (char *src)
+{
+       int             result;
+       YY_BUFFER_STATE buf_state;
+
+       buf_state = yy_scan_string(src);
+       result = yyparse();
+       yy_delete_buffer(buf_state);
+       return result;
+}
+
diff --git a/ipsec-tools/setkey/vchar.h b/ipsec-tools/setkey/vchar.h
new file mode 100644 (file)
index 0000000..1031e42
--- /dev/null
@@ -0,0 +1,40 @@
+/* $Id: vchar.h,v 1.2 2004/06/07 09:18:47 ludvigm Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#ifndef _VCHAR_H
+#define _VCHAR_H
+
+typedef struct {
+       u_int len;
+       caddr_t buf;
+} vchar_t;
+
+#endif /* _VCHAR_H */
diff --git a/ipsec.xcodeproj/project.pbxproj b/ipsec.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..964f919
--- /dev/null
@@ -0,0 +1,2505 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 42;
+       objects = {
+
+/* Begin PBXAggregateTarget section */
+               23B20D2F0871D62A00A3B0FC /* IPSec (Aggregate) */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 25D3DAB8098952B20025F703 /* Build configuration list for PBXAggregateTarget "IPSec (Aggregate)" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               25D3DDE30989AFDE0025F703 /* PBXTargetDependency */,
+                               25D3DDE50989AFE50025F703 /* PBXTargetDependency */,
+                               25D3DDE70989AFE90025F703 /* PBXTargetDependency */,
+                               254347D109DCBAF8007943DE /* PBXTargetDependency */,
+                               25DE3DB609EC27B900147420 /* PBXTargetDependency */,
+                       );
+                       name = "IPSec (Aggregate)";
+                       productName = "IPSec (Aggregate)";
+               };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+               25078AE509D37570005F3F63 /* nattraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F00988657000D15623 /* nattraversal.c */; };
+               2537A1B109E4867100D0ECDA /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 25D9499F09A6AAD700CA0F24 /* config.h */; };
+               2537A1B509E4867700D0ECDA /* ipsec_dump_policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9520989B4EE00E5B678 /* ipsec_dump_policy.c */; };
+               2537A1B609E4867700D0ECDA /* ipsec_get_policylen.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9530989B4EE00E5B678 /* ipsec_get_policylen.c */; };
+               2537A1B709E4867800D0ECDA /* ipsec_strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9560989B4EE00E5B678 /* ipsec_strerror.c */; };
+               2537A1B809E4867900D0ECDA /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 252DF9570989B4EE00E5B678 /* ipsec_strerror.h */; };
+               2537A1B909E4867900D0ECDA /* policy_parse.y in Sources */ = {isa = PBXBuildFile; fileRef = 252DF95E0989B4EE00E5B678 /* policy_parse.y */; };
+               2537A1BA09E4867A00D0ECDA /* policy_token.l in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9600989B4EE00E5B678 /* policy_token.l */; };
+               2537A1C109E494B300D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               2537A1C709E49D0600D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               2537A1CB09E49D5600D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               2543473209DCAE27007943DE /* racoonctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2590C0988657000D15623 /* racoonctl.c */; };
+               2543474E09DCAEF8007943DE /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; };
+               2543475109DCB063007943DE /* kmpstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E80988657000D15623 /* kmpstat.c */; };
+               2543475509DCB0D9007943DE /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; };
+               2543475609DCB0DB007943DE /* sockmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591A0988657000D15623 /* sockmisc.c */; };
+               2543475709DCB0E6007943DE /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; };
+               2543476409DCB396007943DE /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; };
+               2543476709DCB400007943DE /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; };
+               2543476909DCB420007943DE /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               2543477109DCB492007943DE /* plainrsa-gen.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FC0988657000D15623 /* plainrsa-gen.c */; };
+               2543478A09DCB49C007943DE /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; };
+               2543478C09DCB4A6007943DE /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; };
+               254347A909DCB6C8007943DE /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; };
+               254347AB09DCB6D6007943DE /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; };
+               254347B809DCB84D007943DE /* test-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9610989B4EE00E5B678 /* test-policy.c */; };
+               254347C809DCBA1B007943DE /* test-pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 254347C709DCBA1B007943DE /* test-pfkey.c */; };
+               258CF2CB0A19197400166B38 /* setkey.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F258890988648C00D15623 /* setkey.8 */; };
+               258CF2CD0A1919A800166B38 /* ipsec_set_policy.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 252DF9540989B4EE00E5B678 /* ipsec_set_policy.3 */; };
+               258CF2CE0A1919AF00166B38 /* ipsec_strerror.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 252DF9550989B4EE00E5B678 /* ipsec_strerror.3 */; };
+               258CF2D20A191A0600166B38 /* racoonctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2590B0988657000D15623 /* racoonctl.8 */; };
+               258CF2D40A191A5000166B38 /* plainrsa-gen.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F258FB0988657000D15623 /* plainrsa-gen.8 */; };
+               258CF2E10A191A9200166B38 /* racoon.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F259090988657000D15623 /* racoon.8 */; };
+               258CF2E40A191AD500166B38 /* racoon.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2590A0988657000D15623 /* racoon.conf.5 */; };
+               258CF2E60A191B1800166B38 /* racoon.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2589A098864D700D15623 /* racoon.conf */; };
+               258CF2FB0A191B4F00166B38 /* anonymous.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F25898098864D700D15623 /* anonymous.conf */; };
+               258CF2FC0A191B5400166B38 /* psk.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F25899098864D700D15623 /* psk.txt */; };
+               25BC48740A0BC7B000A181A0 /* eaytest.c in Sources */ = {isa = PBXBuildFile; fileRef = 25BC48730A0BC7B000A181A0 /* eaytest.c */; };
+               25BE7E0109E5D3F4009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               25BE7E1209E5D550009B6B84 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; };
+               25BE7E1309E5D555009B6B84 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; };
+               25BE7E1B09E5D5D9009B6B84 /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; };
+               25BE7E2E09E5D709009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               25BE7E3809E5D80E009B6B84 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; };
+               25BE7E3E09E5D906009B6B84 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; };
+               25BE7E4009E5D92C009B6B84 /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; };
+               25BE7E5709E5DC4D009B6B84 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; };
+               25BE7E5A09E5DCBD009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               25BE7E5E09E5DCF5009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               25BE7E6009E5DD04009B6B84 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; };
+               25BE7E6309E5DD38009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               25BE7E7609E5DDBA009B6B84 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; };
+               25BE7E7709E5DDBE009B6B84 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; };
+               25BE7E7F09E5DE4C009B6B84 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; };
+               25BE7E8209E5DE8D009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; };
+               25BE7E8809E5E499009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               25BE7E8A09E5E4A6009B6B84 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; };
+               25BE7E8E09E5E5BE009B6B84 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; };
+               25BE7E9009E5E61F009B6B84 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; };
+               25BE7E9209E5E635009B6B84 /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; };
+               25DC9EC909DB0FBB00C89F86 /* rsalist.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259100988657000D15623 /* rsalist.c */; };
+               25DC9ED409DB16F300C89F86 /* isakmp_cfg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D50988657000D15623 /* isakmp_cfg.c */; };
+               25DC9ED509DB16F800C89F86 /* isakmp_unity.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E10988657000D15623 /* isakmp_unity.c */; };
+               25DC9ED609DB16FA00C89F86 /* isakmp_xauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E40988657000D15623 /* isakmp_xauth.c */; };
+               25DC9ED709DB170800C89F86 /* rsaparse.o in Frameworks */ = {isa = PBXBuildFile; fileRef = 25E08C9A09D9E64A001A11CF /* rsaparse.o */; };
+               25DE2DE90A8BD40E0010A46D /* vpn_control.c in Sources */ = {isa = PBXBuildFile; fileRef = 25DE2DE60A8BD40E0010A46D /* vpn_control.c */; };
+               25E08C9E09D9E681001A11CF /* prsa_par.y in Sources */ = {isa = PBXBuildFile; fileRef = 2589CBA809D8B727002DC960 /* prsa_par.y */; };
+               25E08C9F09D9E682001A11CF /* prsa_tok.l in Sources */ = {isa = PBXBuildFile; fileRef = 2589CBAA09D8B727002DC960 /* prsa_tok.l */; };
+               25EAE83209D875790042CC7F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE83109D875790042CC7F /* Security.framework */; };
+               25EAE83809D875BF0042CC7F /* DirectoryService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE83709D875BF0042CC7F /* DirectoryService.framework */; };
+               25EAE84809D879700042CC7F /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; };
+               25EAE84B09D879DE0042CC7F /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; };
+               25EAE87209D87A160042CC7F /* libgssapi_krb5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */; };
+               25EAE87409D87A390042CC7F /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87309D87A390042CC7F /* libpam.dylib */; };
+               25EAE87709D87A770042CC7F /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87609D87A770042CC7F /* libiconv.dylib */; };
+               25EAE8C109D87B080042CC7F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE8C009D87B080042CC7F /* CoreFoundation.framework */; };
+               25EAE8C609D87B990042CC7F /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               25ECCDA209AD479A00883CA3 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; };
+               25ECCDB509AD489200883CA3 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; };
+               25ECCDB709AD48A300883CA3 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; };
+               25F258900988648C00D15623 /* parse.y in Sources */ = {isa = PBXBuildFile; fileRef = 25F258870988648C00D15623 /* parse.y */; };
+               25F258910988648C00D15623 /* setkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2588A0988648C00D15623 /* setkey.c */; };
+               25F258940988648C00D15623 /* token.l in Sources */ = {isa = PBXBuildFile; fileRef = 25F2588D0988648C00D15623 /* token.l */; };
+               25F258A80988651000D15623 /* rijndael-alg-fst.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258A10988651000D15623 /* rijndael-alg-fst.c */; };
+               25F258A90988651000D15623 /* rijndael-api-fst.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258A30988651000D15623 /* rijndael-api-fst.c */; };
+               25F259280988657000D15623 /* admin.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258AC0988657000D15623 /* admin.c */; };
+               25F259290988657000D15623 /* algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258AE0988657000D15623 /* algorithm.c */; };
+               25F2592A0988657000D15623 /* backupsa.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B10988657000D15623 /* backupsa.c */; };
+               25F2592B0988657000D15623 /* cfparse.y in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B40988657000D15623 /* cfparse.y */; };
+               25F2592C0988657000D15623 /* cftoken.l in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B60988657000D15623 /* cftoken.l */; };
+               25F2592D0988657000D15623 /* crypto_cssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B70988657000D15623 /* crypto_cssm.c */; };
+               25F2592E0988657000D15623 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; };
+               25F2592F0988657000D15623 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258BE0988657000D15623 /* dnssec.c */; };
+               25F259310988657000D15623 /* evt.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C20988657000D15623 /* evt.c */; };
+               25F259320988657000D15623 /* genlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C50988657000D15623 /* genlist.c */; };
+               25F259330988657000D15623 /* getcertsbyname.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C70988657000D15623 /* getcertsbyname.c */; };
+               25F259340988657000D15623 /* grabmyaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C90988657000D15623 /* grabmyaddr.c */; };
+               25F259350988657000D15623 /* gssapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CB0988657000D15623 /* gssapi.c */; };
+               25F259360988657000D15623 /* handler.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CD0988657000D15623 /* handler.c */; };
+               25F259370988657000D15623 /* ipsec_doi.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CF0988657000D15623 /* ipsec_doi.c */; };
+               25F259380988657000D15623 /* isakmp_agg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D10988657000D15623 /* isakmp_agg.c */; };
+               25F259390988657000D15623 /* isakmp_base.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D30988657000D15623 /* isakmp_base.c */; };
+               25F2593C0988657000D15623 /* isakmp_ident.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D90988657000D15623 /* isakmp_ident.c */; };
+               25F2593D0988657000D15623 /* isakmp_inf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DB0988657000D15623 /* isakmp_inf.c */; };
+               25F2593E0988657000D15623 /* isakmp_newg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DD0988657000D15623 /* isakmp_newg.c */; };
+               25F2593F0988657000D15623 /* isakmp_quick.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DF0988657000D15623 /* isakmp_quick.c */; };
+               25F259420988657000D15623 /* isakmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E60988657000D15623 /* isakmp.c */; };
+               25F259440988657000D15623 /* localconf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E90988657000D15623 /* localconf.c */; };
+               25F259450988657000D15623 /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; };
+               25F259460988657000D15623 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258ED0988657000D15623 /* main.c */; };
+               25F259470988657000D15623 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; };
+               25F259490988657000D15623 /* oakley.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F30988657000D15623 /* oakley.c */; };
+               25F2594A0988657000D15623 /* open_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F50988657000D15623 /* open_dir.c */; };
+               25F2594C0988657000D15623 /* pfkey_racoon.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F80988657000D15623 /* pfkey_racoon.c */; };
+               25F2594F0988657000D15623 /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; };
+               25F259500988657000D15623 /* policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FF0988657000D15623 /* policy.c */; };
+               25F259510988657000D15623 /* privsep.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259010988657000D15623 /* privsep.c */; };
+               25F259520988657000D15623 /* proposal.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259030988657000D15623 /* proposal.c */; };
+               25F259580988657000D15623 /* remoteconf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2590E0988657000D15623 /* remoteconf.c */; };
+               25F2595A0988657000D15623 /* safefile.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259120988657000D15623 /* safefile.c */; };
+               25F2595B0988657000D15623 /* sainfo.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259140988657000D15623 /* sainfo.c */; };
+               25F2595C0988657000D15623 /* schedule.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259160988657000D15623 /* schedule.c */; };
+               25F2595D0988657000D15623 /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259180988657000D15623 /* session.c */; };
+               25F2595E0988657000D15623 /* sockmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591A0988657000D15623 /* sockmisc.c */; };
+               25F2595F0988657000D15623 /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; };
+               25F259600988657000D15623 /* strnames.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591F0988657000D15623 /* strnames.c */; };
+               25F259610988657000D15623 /* throttle.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259210988657000D15623 /* throttle.c */; };
+               25F259620988657000D15623 /* vendorid.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259240988657000D15623 /* vendorid.c */; };
+               25F259630988657000D15623 /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; };
+               81EDB0690B5D8D9600840BC7 /* ipsec_get_policylen.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 81EDB0680B5D8D8900840BC7 /* ipsec_get_policylen.3 */; };
+               81EDB06A0B5D8D9A00840BC7 /* ipsec_dump_policy.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 81EDB0670B5D8D7000840BC7 /* ipsec_dump_policy.3 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               2537A1C209E494D300D0ECDA /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               2537A1C809E49D1400D0ECDA /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               2537A1CC09E49D5C00D0ECDA /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               254347D009DCBAF8007943DE /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2543476E09DCB477007943DE;
+                       remoteInfo = "plainrsa-gen";
+               };
+               25BE7E0309E5D3FE009B6B84 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               25BE7E2F09E5D710009B6B84 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               25BE7E5B09E5DCC5009B6B84 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               25BE7E7B09E5DE28009B6B84 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               25D3DDE20989AFDE0025F703 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 25F258040987FBFA00D15623;
+                       remoteInfo = racoon;
+               };
+               25D3DDE40989AFE50025F703 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 25F258090987FC1500D15623;
+                       remoteInfo = setkey;
+               };
+               25D3DDE60989AFE90025F703 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 25F2580E0987FC3400D15623;
+                       remoteInfo = racoonctl;
+               };
+               25DE3DB509EC27B900147420 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 2537A1A709E4864800D0ECDA;
+                       remoteInfo = libipsec;
+               };
+               25E08CE909D9F0A2001A11CF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 23D2D790087071FC00C51098 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 25E08C9909D9E64A001A11CF;
+                       remoteInfo = rsaparse;
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               258CF2CF0A1919CD00166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man3;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2CD0A1919A800166B38 /* ipsec_set_policy.3 in CopyFiles */,
+                               258CF2CE0A1919AF00166B38 /* ipsec_strerror.3 in CopyFiles */,
+                               81EDB0690B5D8D9600840BC7 /* ipsec_get_policylen.3 in CopyFiles */,
+                               81EDB06A0B5D8D9A00840BC7 /* ipsec_dump_policy.3 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2D00A1919CD00166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2CB0A19197400166B38 /* setkey.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2D50A191A6E00166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2D20A191A0600166B38 /* racoonctl.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2D60A191A6E00166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2D40A191A5000166B38 /* plainrsa-gen.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2E20A191AB000166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2E10A191A9200166B38 /* racoon.8 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2F80A191B3900166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man5;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2E40A191AD500166B38 /* racoon.conf.5 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2F90A191B3900166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /private/etc/racoon;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2FC0A191B5400166B38 /* psk.txt in CopyFiles */,
+                               258CF2E60A191B1800166B38 /* racoon.conf in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               258CF2FA0A191B3900166B38 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /private/etc/racoon/remote;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               258CF2FB0A191B4F00166B38 /* anonymous.conf in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               252DF9520989B4EE00E5B678 /* ipsec_dump_policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipsec_dump_policy.c; path = libipsec/ipsec_dump_policy.c; sourceTree = "<group>"; };
+               252DF9530989B4EE00E5B678 /* ipsec_get_policylen.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipsec_get_policylen.c; path = libipsec/ipsec_get_policylen.c; sourceTree = "<group>"; };
+               252DF9540989B4EE00E5B678 /* ipsec_set_policy.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_set_policy.3; path = libipsec/ipsec_set_policy.3; sourceTree = "<group>"; };
+               252DF9550989B4EE00E5B678 /* ipsec_strerror.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_strerror.3; path = libipsec/ipsec_strerror.3; sourceTree = "<group>"; };
+               252DF9560989B4EE00E5B678 /* ipsec_strerror.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipsec_strerror.c; path = libipsec/ipsec_strerror.c; sourceTree = "<group>"; };
+               252DF9570989B4EE00E5B678 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ipsec_strerror.h; path = libipsec/ipsec_strerror.h; sourceTree = "<group>"; };
+               252DF95E0989B4EE00E5B678 /* policy_parse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; name = policy_parse.y; path = libipsec/policy_parse.y; sourceTree = "<group>"; };
+               252DF9600989B4EE00E5B678 /* policy_token.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; name = policy_token.l; path = libipsec/policy_token.l; sourceTree = "<group>"; };
+               252DF9610989B4EE00E5B678 /* test-policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = "test-policy.c"; path = "libipsec/test-policy.c"; sourceTree = "<group>"; };
+               2537A1A809E4864800D0ECDA /* libipsec.A.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libipsec.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+               2543476F09DCB477007943DE /* plainrsa-gen */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "plainrsa-gen"; sourceTree = BUILT_PRODUCTS_DIR; };
+               2543479309DCB57E007943DE /* eaytest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = eaytest; sourceTree = BUILT_PRODUCTS_DIR; };
+               254347B609DCB839007943DE /* test-policy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-policy"; sourceTree = BUILT_PRODUCTS_DIR; };
+               254347C509DCBA07007943DE /* test-pfkey */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-pfkey"; sourceTree = BUILT_PRODUCTS_DIR; };
+               254347C709DCBA1B007943DE /* test-pfkey.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "test-pfkey.c"; sourceTree = "<group>"; };
+               2589CBA809D8B727002DC960 /* prsa_par.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = prsa_par.y; sourceTree = "<group>"; };
+               2589CBAA09D8B727002DC960 /* prsa_tok.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = prsa_tok.l; sourceTree = "<group>"; };
+               25BC48730A0BC7B000A181A0 /* eaytest.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = eaytest.c; sourceTree = "<group>"; };
+               25D9499F09A6AAD700CA0F24 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = Common/config.h; sourceTree = "<group>"; };
+               25D949A109A6AAD700CA0F24 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = libpfkey.h; path = Common/libpfkey.h; sourceTree = "<group>"; };
+               25D949A209A6AAD700CA0F24 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pfkey.c; path = Common/pfkey.c; sourceTree = "<group>"; };
+               25DE2DE50A8BD40E0010A46D /* vpn_control_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vpn_control_var.h; sourceTree = "<group>"; };
+               25DE2DE60A8BD40E0010A46D /* vpn_control.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vpn_control.c; sourceTree = "<group>"; };
+               25DE2DE70A8BD40E0010A46D /* vpn_control.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vpn_control.h; sourceTree = "<group>"; };
+               25E08C9A09D9E64A001A11CF /* rsaparse.o */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = rsaparse.o; sourceTree = BUILT_PRODUCTS_DIR; };
+               25EAE83109D875790042CC7F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+               25EAE83709D875BF0042CC7F /* DirectoryService.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DirectoryService.framework; path = /System/Library/Frameworks/DirectoryService.framework; sourceTree = "<absolute>"; };
+               25EAE84709D879700042CC7F /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = /usr/lib/libssl.dylib; sourceTree = "<absolute>"; };
+               25EAE84A09D879DE0042CC7F /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = /usr/lib/libcrypto.dylib; sourceTree = "<absolute>"; };
+               25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgssapi_krb5.dylib; path = /usr/lib/libgssapi_krb5.dylib; sourceTree = "<absolute>"; };
+               25EAE87309D87A390042CC7F /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+               25EAE87609D87A770042CC7F /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = "<absolute>"; };
+               25EAE8C009D87B080042CC7F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+               25F258050987FBFA00D15623 /* racoon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = racoon; sourceTree = BUILT_PRODUCTS_DIR; };
+               25F2580A0987FC1500D15623 /* setkey */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = setkey; sourceTree = BUILT_PRODUCTS_DIR; };
+               25F2580F0987FC3400D15623 /* racoonctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = racoonctl; sourceTree = BUILT_PRODUCTS_DIR; };
+               25F258840988648C00D15623 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+               25F258870988648C00D15623 /* parse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = parse.y; sourceTree = "<group>"; };
+               25F258880988648C00D15623 /* scriptdump.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = scriptdump.pl; sourceTree = "<group>"; };
+               25F258890988648C00D15623 /* setkey.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = setkey.8; sourceTree = "<group>"; };
+               25F2588A0988648C00D15623 /* setkey.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = setkey.c; sourceTree = "<group>"; };
+               25F2588D0988648C00D15623 /* token.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = token.l; sourceTree = "<group>"; };
+               25F2588E0988648C00D15623 /* vchar.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vchar.h; sourceTree = "<group>"; };
+               25F25895098864AB00D15623 /* sample-policy01.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "sample-policy01.cf"; sourceTree = "<group>"; };
+               25F25896098864AB00D15623 /* sample-policy02.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "sample-policy02.cf"; sourceTree = "<group>"; };
+               25F25897098864AB00D15623 /* sample.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = sample.cf; sourceTree = "<group>"; };
+               25F25898098864D700D15623 /* anonymous.conf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = anonymous.conf; sourceTree = "<group>"; };
+               25F25899098864D700D15623 /* psk.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = psk.txt; sourceTree = "<group>"; };
+               25F2589A098864D700D15623 /* racoon.conf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.conf; sourceTree = "<group>"; };
+               25F2589B098864F500D15623 /* FAQ */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = FAQ; sourceTree = "<group>"; };
+               25F2589C098864F500D15623 /* README.certificate */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.certificate; sourceTree = "<group>"; };
+               25F2589D098864F500D15623 /* README.gssapi */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.gssapi; sourceTree = "<group>"; };
+               25F2589E098864F500D15623 /* TODO */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
+               25F2589F0988651000D15623 /* boxes-fst.dat */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "boxes-fst.dat"; sourceTree = "<group>"; };
+               25F258A00988651000D15623 /* rijndael_local.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rijndael_local.h; sourceTree = "<group>"; };
+               25F258A10988651000D15623 /* rijndael-alg-fst.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "rijndael-alg-fst.c"; sourceTree = "<group>"; };
+               25F258A20988651000D15623 /* rijndael-alg-fst.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "rijndael-alg-fst.h"; sourceTree = "<group>"; };
+               25F258A30988651000D15623 /* rijndael-api-fst.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "rijndael-api-fst.c"; sourceTree = "<group>"; };
+               25F258A40988651000D15623 /* rijndael-api-fst.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "rijndael-api-fst.h"; sourceTree = "<group>"; };
+               25F258A50988651000D15623 /* rijndael.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rijndael.h; sourceTree = "<group>"; };
+               25F258AB0988657000D15623 /* admin_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = admin_var.h; sourceTree = "<group>"; };
+               25F258AC0988657000D15623 /* admin.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = admin.c; sourceTree = "<group>"; };
+               25F258AD0988657000D15623 /* admin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = admin.h; sourceTree = "<group>"; };
+               25F258AE0988657000D15623 /* algorithm.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = algorithm.c; sourceTree = "<group>"; };
+               25F258AF0988657000D15623 /* algorithm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = algorithm.h; sourceTree = "<group>"; };
+               25F258B00988657000D15623 /* arc4random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = arc4random.h; sourceTree = "<group>"; };
+               25F258B10988657000D15623 /* backupsa.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = backupsa.c; sourceTree = "<group>"; };
+               25F258B20988657000D15623 /* backupsa.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = backupsa.h; sourceTree = "<group>"; };
+               25F258B30988657000D15623 /* cfparse_proto.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfparse_proto.h; sourceTree = "<group>"; };
+               25F258B40988657000D15623 /* cfparse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = cfparse.y; sourceTree = "<group>"; };
+               25F258B50988657000D15623 /* cftoken_proto.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cftoken_proto.h; sourceTree = "<group>"; };
+               25F258B60988657000D15623 /* cftoken.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = cftoken.l; sourceTree = "<group>"; };
+               25F258B70988657000D15623 /* crypto_cssm.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = crypto_cssm.c; sourceTree = "<group>"; };
+               25F258B80988657000D15623 /* crypto_cssm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crypto_cssm.h; sourceTree = "<group>"; };
+               25F258B90988657000D15623 /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = crypto_openssl.c; sourceTree = "<group>"; };
+               25F258BA0988657000D15623 /* crypto_openssl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crypto_openssl.h; sourceTree = "<group>"; };
+               25F258BB0988657000D15623 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
+               25F258BC0988657000D15623 /* debugrm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = debugrm.h; sourceTree = "<group>"; };
+               25F258BD0988657000D15623 /* dhgroup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dhgroup.h; sourceTree = "<group>"; };
+               25F258BE0988657000D15623 /* dnssec.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = dnssec.c; sourceTree = "<group>"; };
+               25F258BF0988657000D15623 /* dnssec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dnssec.h; sourceTree = "<group>"; };
+               25F258C00988657000D15623 /* dump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dump.h; sourceTree = "<group>"; };
+               25F258C20988657000D15623 /* evt.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = evt.c; sourceTree = "<group>"; };
+               25F258C30988657000D15623 /* evt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = evt.h; sourceTree = "<group>"; };
+               25F258C40988657000D15623 /* gcmalloc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gcmalloc.h; sourceTree = "<group>"; };
+               25F258C50988657000D15623 /* genlist.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = genlist.c; sourceTree = "<group>"; };
+               25F258C60988657000D15623 /* genlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = genlist.h; sourceTree = "<group>"; };
+               25F258C70988657000D15623 /* getcertsbyname.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = getcertsbyname.c; sourceTree = "<group>"; };
+               25F258C80988657000D15623 /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = "<group>"; };
+               25F258C90988657000D15623 /* grabmyaddr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = grabmyaddr.c; sourceTree = "<group>"; };
+               25F258CA0988657000D15623 /* grabmyaddr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = grabmyaddr.h; sourceTree = "<group>"; };
+               25F258CB0988657000D15623 /* gssapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gssapi.c; sourceTree = "<group>"; };
+               25F258CC0988657000D15623 /* gssapi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gssapi.h; sourceTree = "<group>"; };
+               25F258CD0988657000D15623 /* handler.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = handler.c; sourceTree = "<group>"; };
+               25F258CE0988657000D15623 /* handler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = handler.h; sourceTree = "<group>"; };
+               25F258CF0988657000D15623 /* ipsec_doi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ipsec_doi.c; sourceTree = "<group>"; };
+               25F258D00988657000D15623 /* ipsec_doi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ipsec_doi.h; sourceTree = "<group>"; };
+               25F258D10988657000D15623 /* isakmp_agg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_agg.c; sourceTree = "<group>"; };
+               25F258D20988657000D15623 /* isakmp_agg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_agg.h; sourceTree = "<group>"; };
+               25F258D30988657000D15623 /* isakmp_base.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_base.c; sourceTree = "<group>"; };
+               25F258D40988657000D15623 /* isakmp_base.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_base.h; sourceTree = "<group>"; };
+               25F258D50988657000D15623 /* isakmp_cfg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_cfg.c; sourceTree = "<group>"; };
+               25F258D60988657000D15623 /* isakmp_cfg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_cfg.h; sourceTree = "<group>"; };
+               25F258D70988657000D15623 /* isakmp_frag.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_frag.c; sourceTree = "<group>"; };
+               25F258D80988657000D15623 /* isakmp_frag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_frag.h; sourceTree = "<group>"; };
+               25F258D90988657000D15623 /* isakmp_ident.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_ident.c; sourceTree = "<group>"; };
+               25F258DA0988657000D15623 /* isakmp_ident.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_ident.h; sourceTree = "<group>"; };
+               25F258DB0988657000D15623 /* isakmp_inf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_inf.c; sourceTree = "<group>"; };
+               25F258DC0988657000D15623 /* isakmp_inf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_inf.h; sourceTree = "<group>"; };
+               25F258DD0988657000D15623 /* isakmp_newg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_newg.c; sourceTree = "<group>"; };
+               25F258DE0988657000D15623 /* isakmp_newg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_newg.h; sourceTree = "<group>"; };
+               25F258DF0988657000D15623 /* isakmp_quick.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_quick.c; sourceTree = "<group>"; };
+               25F258E00988657000D15623 /* isakmp_quick.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_quick.h; sourceTree = "<group>"; };
+               25F258E10988657000D15623 /* isakmp_unity.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_unity.c; sourceTree = "<group>"; };
+               25F258E20988657000D15623 /* isakmp_unity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_unity.h; sourceTree = "<group>"; };
+               25F258E30988657000D15623 /* isakmp_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_var.h; sourceTree = "<group>"; };
+               25F258E40988657000D15623 /* isakmp_xauth.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_xauth.c; sourceTree = "<group>"; };
+               25F258E50988657000D15623 /* isakmp_xauth.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_xauth.h; sourceTree = "<group>"; };
+               25F258E60988657000D15623 /* isakmp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp.c; sourceTree = "<group>"; };
+               25F258E70988657000D15623 /* isakmp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp.h; sourceTree = "<group>"; };
+               25F258E80988657000D15623 /* kmpstat.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kmpstat.c; sourceTree = "<group>"; };
+               25F258E90988657000D15623 /* localconf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = localconf.c; sourceTree = "<group>"; };
+               25F258EA0988657000D15623 /* localconf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = localconf.h; sourceTree = "<group>"; };
+               25F258EB0988657000D15623 /* logger.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = logger.c; sourceTree = "<group>"; };
+               25F258EC0988657000D15623 /* logger.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = logger.h; sourceTree = "<group>"; };
+               25F258ED0988657000D15623 /* main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+               25F258EE0988657000D15623 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+               25F258EF0988657000D15623 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = "<group>"; };
+               25F258F00988657000D15623 /* nattraversal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = nattraversal.c; sourceTree = "<group>"; };
+               25F258F10988657000D15623 /* nattraversal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = nattraversal.h; sourceTree = "<group>"; };
+               25F258F20988657000D15623 /* netdb_dnssec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = netdb_dnssec.h; sourceTree = "<group>"; };
+               25F258F30988657000D15623 /* oakley.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = oakley.c; sourceTree = "<group>"; };
+               25F258F40988657000D15623 /* oakley.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oakley.h; sourceTree = "<group>"; };
+               25F258F50988657000D15623 /* open_dir.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = open_dir.c; sourceTree = "<group>"; };
+               25F258F60988657000D15623 /* open_dir.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = open_dir.h; sourceTree = "<group>"; };
+               25F258F80988657000D15623 /* pfkey_racoon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = pfkey_racoon.c; sourceTree = "<group>"; };
+               25F258F90988657000D15623 /* pfkey.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pfkey.h; sourceTree = "<group>"; };
+               25F258FB0988657000D15623 /* plainrsa-gen.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "plainrsa-gen.8"; sourceTree = "<group>"; };
+               25F258FC0988657000D15623 /* plainrsa-gen.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "plainrsa-gen.c"; sourceTree = "<group>"; };
+               25F258FD0988657000D15623 /* plog.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = plog.c; sourceTree = "<group>"; };
+               25F258FE0988657000D15623 /* plog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = plog.h; sourceTree = "<group>"; };
+               25F258FF0988657000D15623 /* policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = policy.c; sourceTree = "<group>"; };
+               25F259000988657000D15623 /* policy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = policy.h; sourceTree = "<group>"; };
+               25F259010988657000D15623 /* privsep.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = privsep.c; sourceTree = "<group>"; };
+               25F259020988657000D15623 /* privsep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = privsep.h; sourceTree = "<group>"; };
+               25F259030988657000D15623 /* proposal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = proposal.c; sourceTree = "<group>"; };
+               25F259040988657000D15623 /* proposal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = proposal.h; sourceTree = "<group>"; };
+               25F259090988657000D15623 /* racoon.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.8; sourceTree = "<group>"; };
+               25F2590A0988657000D15623 /* racoon.conf.5 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.conf.5; sourceTree = "<group>"; };
+               25F2590B0988657000D15623 /* racoonctl.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoonctl.8; sourceTree = "<group>"; };
+               25F2590C0988657000D15623 /* racoonctl.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = racoonctl.c; sourceTree = "<group>"; };
+               25F2590D0988657000D15623 /* racoonctl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = racoonctl.h; sourceTree = "<group>"; };
+               25F2590E0988657000D15623 /* remoteconf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = remoteconf.c; sourceTree = "<group>"; };
+               25F2590F0988657000D15623 /* remoteconf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = remoteconf.h; sourceTree = "<group>"; };
+               25F259100988657000D15623 /* rsalist.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rsalist.c; sourceTree = "<group>"; };
+               25F259110988657000D15623 /* rsalist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rsalist.h; sourceTree = "<group>"; };
+               25F259120988657000D15623 /* safefile.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = safefile.c; sourceTree = "<group>"; };
+               25F259130988657000D15623 /* safefile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = safefile.h; sourceTree = "<group>"; };
+               25F259140988657000D15623 /* sainfo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = sainfo.c; sourceTree = "<group>"; };
+               25F259150988657000D15623 /* sainfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sainfo.h; sourceTree = "<group>"; };
+               25F259160988657000D15623 /* schedule.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = schedule.c; sourceTree = "<group>"; };
+               25F259170988657000D15623 /* schedule.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = schedule.h; sourceTree = "<group>"; };
+               25F259180988657000D15623 /* session.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = session.c; sourceTree = "<group>"; };
+               25F259190988657000D15623 /* session.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = "<group>"; };
+               25F2591A0988657000D15623 /* sockmisc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = sockmisc.c; sourceTree = "<group>"; };
+               25F2591B0988657000D15623 /* sockmisc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sockmisc.h; sourceTree = "<group>"; };
+               25F2591C0988657000D15623 /* stats.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = stats.pl; sourceTree = "<group>"; };
+               25F2591D0988657000D15623 /* str2val.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = str2val.c; sourceTree = "<group>"; };
+               25F2591E0988657000D15623 /* str2val.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = str2val.h; sourceTree = "<group>"; };
+               25F2591F0988657000D15623 /* strnames.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = strnames.c; sourceTree = "<group>"; };
+               25F259200988657000D15623 /* strnames.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = strnames.h; sourceTree = "<group>"; };
+               25F259210988657000D15623 /* throttle.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = throttle.c; sourceTree = "<group>"; };
+               25F259220988657000D15623 /* throttle.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = throttle.h; sourceTree = "<group>"; };
+               25F259230988657000D15623 /* var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = var.h; sourceTree = "<group>"; };
+               25F259240988657000D15623 /* vendorid.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vendorid.c; sourceTree = "<group>"; };
+               25F259250988657000D15623 /* vendorid.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vendorid.h; sourceTree = "<group>"; };
+               25F259260988657000D15623 /* vmbuf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vmbuf.c; sourceTree = "<group>"; };
+               25F259270988657000D15623 /* vmbuf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vmbuf.h; sourceTree = "<group>"; };
+               25F777B909ABE3E100C99783 /* key_debug.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = key_debug.c; path = Common/key_debug.c; sourceTree = "<group>"; };
+               25F777ED09ABE58400C99783 /* pfkey_dump.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pfkey_dump.c; path = Common/pfkey_dump.c; sourceTree = "<group>"; };
+               81EDB0670B5D8D7000840BC7 /* ipsec_dump_policy.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_dump_policy.3; path = libipsec/ipsec_dump_policy.3; sourceTree = "<group>"; };
+               81EDB0680B5D8D8900840BC7 /* ipsec_get_policylen.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_get_policylen.3; path = libipsec/ipsec_get_policylen.3; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               2537A1A609E4864800D0ECDA /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               2543476D09DCB477007943DE /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25BE7E8209E5DE8D009B6B84 /* libipsec.A.dylib in Frameworks */,
+                               25BE7E7609E5DDBA009B6B84 /* libssl.dylib in Frameworks */,
+                               25BE7E7709E5DDBE009B6B84 /* libcrypto.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               2543479109DCB57E007943DE /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25BE7E2E09E5D709009B6B84 /* libipsec.A.dylib in Frameworks */,
+                               25BE7E1209E5D550009B6B84 /* libssl.dylib in Frameworks */,
+                               25BE7E1309E5D555009B6B84 /* libcrypto.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               254347B409DCB839007943DE /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25BE7E0109E5D3F4009B6B84 /* libipsec.A.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               254347C309DCBA07007943DE /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25BE7E5A09E5DCBD009B6B84 /* libipsec.A.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25E08C9809D9E64A001A11CF /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F258030987FBFA00D15623 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2537A1C709E49D0600D0ECDA /* libipsec.A.dylib in Frameworks */,
+                               25EAE83209D875790042CC7F /* Security.framework in Frameworks */,
+                               25EAE83809D875BF0042CC7F /* DirectoryService.framework in Frameworks */,
+                               25EAE84809D879700042CC7F /* libssl.dylib in Frameworks */,
+                               25EAE84B09D879DE0042CC7F /* libcrypto.dylib in Frameworks */,
+                               25EAE87209D87A160042CC7F /* libgssapi_krb5.dylib in Frameworks */,
+                               25EAE87409D87A390042CC7F /* libpam.dylib in Frameworks */,
+                               25EAE87709D87A770042CC7F /* libiconv.dylib in Frameworks */,
+                               25EAE8C109D87B080042CC7F /* CoreFoundation.framework in Frameworks */,
+                               25DC9ED709DB170800C89F86 /* rsaparse.o in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F258080987FC1500D15623 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2537A1C109E494B300D0ECDA /* libipsec.A.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F2580D0987FC3400D15623 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2537A1CB09E49D5600D0ECDA /* libipsec.A.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               23D2D78C087071FC00C51098 = {
+                       isa = PBXGroup;
+                       children = (
+                               25E5E82D0981A61900F2834C /* ipsec-tools */,
+                               2589CB5409D8AE95002DC960 /* Libraries */,
+                               25D3DB4C098998230025F703 /* Frameworks */,
+                               23D2D79C087074CC00C51098 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               23D2D79C087074CC00C51098 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F258050987FBFA00D15623 /* racoon */,
+                               25F2580A0987FC1500D15623 /* setkey */,
+                               25F2580F0987FC3400D15623 /* racoonctl */,
+                               25E08C9A09D9E64A001A11CF /* rsaparse.o */,
+                               2543476F09DCB477007943DE /* plainrsa-gen */,
+                               2543479309DCB57E007943DE /* eaytest */,
+                               254347B609DCB839007943DE /* test-policy */,
+                               254347C509DCBA07007943DE /* test-pfkey */,
+                               2537A1A809E4864800D0ECDA /* libipsec.A.dylib */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               2589CB5409D8AE95002DC960 /* Libraries */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25EAE87609D87A770042CC7F /* libiconv.dylib */,
+                               25EAE87309D87A390042CC7F /* libpam.dylib */,
+                               25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */,
+                               25EAE84A09D879DE0042CC7F /* libcrypto.dylib */,
+                               25EAE84709D879700042CC7F /* libssl.dylib */,
+                       );
+                       name = Libraries;
+                       sourceTree = "<group>";
+               };
+               25D3DB1B098996310025F703 /* libipsec */ = {
+                       isa = PBXGroup;
+                       children = (
+                               81EDB0680B5D8D8900840BC7 /* ipsec_get_policylen.3 */,
+                               81EDB0670B5D8D7000840BC7 /* ipsec_dump_policy.3 */,
+                               252DF9520989B4EE00E5B678 /* ipsec_dump_policy.c */,
+                               252DF9530989B4EE00E5B678 /* ipsec_get_policylen.c */,
+                               252DF9540989B4EE00E5B678 /* ipsec_set_policy.3 */,
+                               252DF9550989B4EE00E5B678 /* ipsec_strerror.3 */,
+                               252DF9560989B4EE00E5B678 /* ipsec_strerror.c */,
+                               252DF9570989B4EE00E5B678 /* ipsec_strerror.h */,
+                               252DF95E0989B4EE00E5B678 /* policy_parse.y */,
+                               252DF9600989B4EE00E5B678 /* policy_token.l */,
+                               252DF9610989B4EE00E5B678 /* test-policy.c */,
+                       );
+                       name = libipsec;
+                       sourceTree = "<group>";
+               };
+               25D3DB4C098998230025F703 /* Frameworks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25EAE83109D875790042CC7F /* Security.framework */,
+                               25EAE83709D875BF0042CC7F /* DirectoryService.framework */,
+                               25EAE8C009D87B080042CC7F /* CoreFoundation.framework */,
+                       );
+                       name = Frameworks;
+                       sourceTree = "<group>";
+               };
+               25D9497C09A6AA7600CA0F24 /* Common */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F777ED09ABE58400C99783 /* pfkey_dump.c */,
+                               25F777B909ABE3E100C99783 /* key_debug.c */,
+                               25D9499F09A6AAD700CA0F24 /* config.h */,
+                               25D949A109A6AAD700CA0F24 /* libpfkey.h */,
+                               25D949A209A6AAD700CA0F24 /* pfkey.c */,
+                       );
+                       name = Common;
+                       sourceTree = "<group>";
+               };
+               25E5E82D0981A61900F2834C /* ipsec-tools */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25D9497C09A6AA7600CA0F24 /* Common */,
+                               25D3DB1B098996310025F703 /* libipsec */,
+                               25F258000987FB1600D15623 /* racoon */,
+                               25F257FF0987FB0E00D15623 /* setkey */,
+                       );
+                       path = "ipsec-tools";
+                       sourceTree = "<group>";
+               };
+               25F257FF0987FB0E00D15623 /* setkey */ = {
+                       isa = PBXGroup;
+                       children = (
+                               254347C709DCBA1B007943DE /* test-pfkey.c */,
+                               25F258840988648C00D15623 /* extern.h */,
+                               25F258870988648C00D15623 /* parse.y */,
+                               25F258880988648C00D15623 /* scriptdump.pl */,
+                               25F258890988648C00D15623 /* setkey.8 */,
+                               25F2588A0988648C00D15623 /* setkey.c */,
+                               25F2588D0988648C00D15623 /* token.l */,
+                               25F2588E0988648C00D15623 /* vchar.h */,
+                               25F2584B098861D900D15623 /* Sample */,
+                       );
+                       path = setkey;
+                       sourceTree = "<group>";
+               };
+               25F258000987FB1600D15623 /* racoon */ = {
+                       isa = PBXGroup;
+                       children = (
+                               2589CBA809D8B727002DC960 /* prsa_par.y */,
+                               2589CBAA09D8B727002DC960 /* prsa_tok.l */,
+                               25F258AB0988657000D15623 /* admin_var.h */,
+                               25F258AC0988657000D15623 /* admin.c */,
+                               25F258AD0988657000D15623 /* admin.h */,
+                               25F258AE0988657000D15623 /* algorithm.c */,
+                               25F258AF0988657000D15623 /* algorithm.h */,
+                               25F258B00988657000D15623 /* arc4random.h */,
+                               25F258B10988657000D15623 /* backupsa.c */,
+                               25F258B20988657000D15623 /* backupsa.h */,
+                               25F258B30988657000D15623 /* cfparse_proto.h */,
+                               25F258B40988657000D15623 /* cfparse.y */,
+                               25F258B50988657000D15623 /* cftoken_proto.h */,
+                               25F258B60988657000D15623 /* cftoken.l */,
+                               25F258B70988657000D15623 /* crypto_cssm.c */,
+                               25F258B80988657000D15623 /* crypto_cssm.h */,
+                               25F258B90988657000D15623 /* crypto_openssl.c */,
+                               25F258BA0988657000D15623 /* crypto_openssl.h */,
+                               25F258BB0988657000D15623 /* debug.h */,
+                               25F258BC0988657000D15623 /* debugrm.h */,
+                               25F258BD0988657000D15623 /* dhgroup.h */,
+                               25F258BE0988657000D15623 /* dnssec.c */,
+                               25F258BF0988657000D15623 /* dnssec.h */,
+                               25F258C00988657000D15623 /* dump.h */,
+                               25BC48730A0BC7B000A181A0 /* eaytest.c */,
+                               25F258C20988657000D15623 /* evt.c */,
+                               25F258C30988657000D15623 /* evt.h */,
+                               25F258C40988657000D15623 /* gcmalloc.h */,
+                               25F258C50988657000D15623 /* genlist.c */,
+                               25F258C60988657000D15623 /* genlist.h */,
+                               25F258C70988657000D15623 /* getcertsbyname.c */,
+                               25F258C80988657000D15623 /* gnuc.h */,
+                               25F258C90988657000D15623 /* grabmyaddr.c */,
+                               25F258CA0988657000D15623 /* grabmyaddr.h */,
+                               25F258CB0988657000D15623 /* gssapi.c */,
+                               25F258CC0988657000D15623 /* gssapi.h */,
+                               25F258CD0988657000D15623 /* handler.c */,
+                               25F258CE0988657000D15623 /* handler.h */,
+                               25F258CF0988657000D15623 /* ipsec_doi.c */,
+                               25F258D00988657000D15623 /* ipsec_doi.h */,
+                               25F258D10988657000D15623 /* isakmp_agg.c */,
+                               25F258D20988657000D15623 /* isakmp_agg.h */,
+                               25F258D30988657000D15623 /* isakmp_base.c */,
+                               25F258D40988657000D15623 /* isakmp_base.h */,
+                               25F258D50988657000D15623 /* isakmp_cfg.c */,
+                               25F258D60988657000D15623 /* isakmp_cfg.h */,
+                               25F258D70988657000D15623 /* isakmp_frag.c */,
+                               25F258D80988657000D15623 /* isakmp_frag.h */,
+                               25F258D90988657000D15623 /* isakmp_ident.c */,
+                               25F258DA0988657000D15623 /* isakmp_ident.h */,
+                               25F258DB0988657000D15623 /* isakmp_inf.c */,
+                               25F258DC0988657000D15623 /* isakmp_inf.h */,
+                               25F258DD0988657000D15623 /* isakmp_newg.c */,
+                               25F258DE0988657000D15623 /* isakmp_newg.h */,
+                               25F258DF0988657000D15623 /* isakmp_quick.c */,
+                               25F258E00988657000D15623 /* isakmp_quick.h */,
+                               25F258E10988657000D15623 /* isakmp_unity.c */,
+                               25F258E20988657000D15623 /* isakmp_unity.h */,
+                               25F258E30988657000D15623 /* isakmp_var.h */,
+                               25F258E40988657000D15623 /* isakmp_xauth.c */,
+                               25F258E50988657000D15623 /* isakmp_xauth.h */,
+                               25F258E60988657000D15623 /* isakmp.c */,
+                               25F258E70988657000D15623 /* isakmp.h */,
+                               25F258E80988657000D15623 /* kmpstat.c */,
+                               25F258E90988657000D15623 /* localconf.c */,
+                               25F258EA0988657000D15623 /* localconf.h */,
+                               25F258EB0988657000D15623 /* logger.c */,
+                               25F258EC0988657000D15623 /* logger.h */,
+                               25F258ED0988657000D15623 /* main.c */,
+                               25F258EE0988657000D15623 /* misc.c */,
+                               25F258EF0988657000D15623 /* misc.h */,
+                               25F258F00988657000D15623 /* nattraversal.c */,
+                               25F258F10988657000D15623 /* nattraversal.h */,
+                               25F258F20988657000D15623 /* netdb_dnssec.h */,
+                               25F258F30988657000D15623 /* oakley.c */,
+                               25F258F40988657000D15623 /* oakley.h */,
+                               25F258F50988657000D15623 /* open_dir.c */,
+                               25F258F60988657000D15623 /* open_dir.h */,
+                               25F258F80988657000D15623 /* pfkey_racoon.c */,
+                               25F258F90988657000D15623 /* pfkey.h */,
+                               25F258FB0988657000D15623 /* plainrsa-gen.8 */,
+                               25F258FC0988657000D15623 /* plainrsa-gen.c */,
+                               25F258FD0988657000D15623 /* plog.c */,
+                               25F258FE0988657000D15623 /* plog.h */,
+                               25F258FF0988657000D15623 /* policy.c */,
+                               25F259000988657000D15623 /* policy.h */,
+                               25F259010988657000D15623 /* privsep.c */,
+                               25F259020988657000D15623 /* privsep.h */,
+                               25F259030988657000D15623 /* proposal.c */,
+                               25F259040988657000D15623 /* proposal.h */,
+                               25F259090988657000D15623 /* racoon.8 */,
+                               25F2590A0988657000D15623 /* racoon.conf.5 */,
+                               25F2590B0988657000D15623 /* racoonctl.8 */,
+                               25F2590C0988657000D15623 /* racoonctl.c */,
+                               25F2590D0988657000D15623 /* racoonctl.h */,
+                               25F2590E0988657000D15623 /* remoteconf.c */,
+                               25F2590F0988657000D15623 /* remoteconf.h */,
+                               25F259100988657000D15623 /* rsalist.c */,
+                               25F259110988657000D15623 /* rsalist.h */,
+                               25F259120988657000D15623 /* safefile.c */,
+                               25F259130988657000D15623 /* safefile.h */,
+                               25F259140988657000D15623 /* sainfo.c */,
+                               25F259150988657000D15623 /* sainfo.h */,
+                               25F259160988657000D15623 /* schedule.c */,
+                               25F259170988657000D15623 /* schedule.h */,
+                               25F259180988657000D15623 /* session.c */,
+                               25F259190988657000D15623 /* session.h */,
+                               25F2591A0988657000D15623 /* sockmisc.c */,
+                               25F2591B0988657000D15623 /* sockmisc.h */,
+                               25F2591C0988657000D15623 /* stats.pl */,
+                               25F2591D0988657000D15623 /* str2val.c */,
+                               25F2591E0988657000D15623 /* str2val.h */,
+                               25F2591F0988657000D15623 /* strnames.c */,
+                               25F259200988657000D15623 /* strnames.h */,
+                               25F259210988657000D15623 /* throttle.c */,
+                               25F259220988657000D15623 /* throttle.h */,
+                               25F259230988657000D15623 /* var.h */,
+                               25F259240988657000D15623 /* vendorid.c */,
+                               25F259250988657000D15623 /* vendorid.h */,
+                               25F259260988657000D15623 /* vmbuf.c */,
+                               25F259270988657000D15623 /* vmbuf.h */,
+                               25DE2DE50A8BD40E0010A46D /* vpn_control_var.h */,
+                               25DE2DE60A8BD40E0010A46D /* vpn_control.c */,
+                               25DE2DE70A8BD40E0010A46D /* vpn_control.h */,
+                               25F2584E0988620300D15623 /* Sample */,
+                               25F2584D098861F500D15623 /* Documents */,
+                               25F2584C098861ED00D15623 /* Crypto */,
+                       );
+                       path = racoon;
+                       sourceTree = "<group>";
+               };
+               25F2584B098861D900D15623 /* Sample */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F25895098864AB00D15623 /* sample-policy01.cf */,
+                               25F25896098864AB00D15623 /* sample-policy02.cf */,
+                               25F25897098864AB00D15623 /* sample.cf */,
+                       );
+                       path = Sample;
+                       sourceTree = "<group>";
+               };
+               25F2584C098861ED00D15623 /* Crypto */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F2589F0988651000D15623 /* boxes-fst.dat */,
+                               25F258A00988651000D15623 /* rijndael_local.h */,
+                               25F258A10988651000D15623 /* rijndael-alg-fst.c */,
+                               25F258A20988651000D15623 /* rijndael-alg-fst.h */,
+                               25F258A30988651000D15623 /* rijndael-api-fst.c */,
+                               25F258A40988651000D15623 /* rijndael-api-fst.h */,
+                               25F258A50988651000D15623 /* rijndael.h */,
+                       );
+                       path = Crypto;
+                       sourceTree = "<group>";
+               };
+               25F2584D098861F500D15623 /* Documents */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F2589B098864F500D15623 /* FAQ */,
+                               25F2589C098864F500D15623 /* README.certificate */,
+                               25F2589D098864F500D15623 /* README.gssapi */,
+                               25F2589E098864F500D15623 /* TODO */,
+                       );
+                       path = Documents;
+                       sourceTree = "<group>";
+               };
+               25F2584E0988620300D15623 /* Sample */ = {
+                       isa = PBXGroup;
+                       children = (
+                               25F25898098864D700D15623 /* anonymous.conf */,
+                               25F25899098864D700D15623 /* psk.txt */,
+                               25F2589A098864D700D15623 /* racoon.conf */,
+                       );
+                       path = Sample;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+               2537A1A409E4864800D0ECDA /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2537A1B109E4867100D0ECDA /* config.h in Headers */,
+                               2537A1B809E4867900D0ECDA /* ipsec_strerror.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+               2537A1A709E4864800D0ECDA /* libipsec */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 2537A1A909E4866800D0ECDA /* Build configuration list for PBXNativeTarget "libipsec" */;
+                       buildPhases = (
+                               2537A1A409E4864800D0ECDA /* Headers */,
+                               2537A1A509E4864800D0ECDA /* Sources */,
+                               2537A1A609E4864800D0ECDA /* Frameworks */,
+                               258CF2CF0A1919CD00166B38 /* CopyFiles */,
+                               258CF3240A1943DE00166B38 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libipsec;
+                       productName = libipsec;
+                       productReference = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
+               };
+               2543476E09DCB477007943DE /* plainrsa-gen */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 2543478609DCB494007943DE /* Build configuration list for PBXNativeTarget "plainrsa-gen" */;
+                       buildPhases = (
+                               2543476C09DCB477007943DE /* Sources */,
+                               2543476D09DCB477007943DE /* Frameworks */,
+                               258CF2D60A191A6E00166B38 /* CopyFiles */,
+                               258CF3220A19439000166B38 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               25BE7E7C09E5DE28009B6B84 /* PBXTargetDependency */,
+                       );
+                       name = "plainrsa-gen";
+                       productName = "plainrsa-gen";
+                       productReference = 2543476F09DCB477007943DE /* plainrsa-gen */;
+                       productType = "com.apple.product-type.tool";
+               };
+               2543479209DCB57E007943DE /* eaytest */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 2543479909DCB596007943DE /* Build configuration list for PBXNativeTarget "eaytest" */;
+                       buildPhases = (
+                               2543479009DCB57E007943DE /* Sources */,
+                               2543479109DCB57E007943DE /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               25BE7E3009E5D710009B6B84 /* PBXTargetDependency */,
+                       );
+                       name = eaytest;
+                       productName = eaytest;
+                       productReference = 2543479309DCB57E007943DE /* eaytest */;
+                       productType = "com.apple.product-type.tool";
+               };
+               254347B509DCB839007943DE /* test-policy */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 254347BD09DCB851007943DE /* Build configuration list for PBXNativeTarget "test-policy" */;
+                       buildPhases = (
+                               254347B309DCB839007943DE /* Sources */,
+                               254347B409DCB839007943DE /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               25BE7E0409E5D3FE009B6B84 /* PBXTargetDependency */,
+                       );
+                       name = "test-policy";
+                       productName = "test-policy";
+                       productReference = 254347B609DCB839007943DE /* test-policy */;
+                       productType = "com.apple.product-type.tool";
+               };
+               254347C409DCBA07007943DE /* test-pfkey */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 254347C909DCBA1B007943DE /* Build configuration list for PBXNativeTarget "test-pfkey" */;
+                       buildPhases = (
+                               254347C209DCBA07007943DE /* Sources */,
+                               254347C309DCBA07007943DE /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               25BE7E5C09E5DCC5009B6B84 /* PBXTargetDependency */,
+                       );
+                       name = "test-pfkey";
+                       productName = "test-pfkey";
+                       productReference = 254347C509DCBA07007943DE /* test-pfkey */;
+                       productType = "com.apple.product-type.tool";
+               };
+               25E08C9909D9E64A001A11CF /* rsaparse */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 25E08CA209D9E6A4001A11CF /* Build configuration list for PBXNativeTarget "rsaparse" */;
+                       buildPhases = (
+                               25E08C9709D9E64A001A11CF /* Sources */,
+                               25E08C9809D9E64A001A11CF /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = rsaparse;
+                       productName = rsaparse;
+                       productReference = 25E08C9A09D9E64A001A11CF /* rsaparse.o */;
+                       productType = "com.apple.product-type.objfile";
+               };
+               25F258040987FBFA00D15623 /* racoon */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 25D3DABC098952B20025F703 /* Build configuration list for PBXNativeTarget "racoon" */;
+                       buildPhases = (
+                               25F258020987FBFA00D15623 /* Sources */,
+                               25F258030987FBFA00D15623 /* Frameworks */,
+                               258CF2E20A191AB000166B38 /* CopyFiles */,
+                               258CF2F80A191B3900166B38 /* CopyFiles */,
+                               258CF2F90A191B3900166B38 /* CopyFiles */,
+                               258CF2FA0A191B3900166B38 /* CopyFiles */,
+                               258CF31B0A1941A200166B38 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               25E08CEA09D9F0A2001A11CF /* PBXTargetDependency */,
+                               2537A1C909E49D1400D0ECDA /* PBXTargetDependency */,
+                       );
+                       name = racoon;
+                       productName = racoon;
+                       productReference = 25F258050987FBFA00D15623 /* racoon */;
+                       productType = "com.apple.product-type.tool";
+               };
+               25F258090987FC1500D15623 /* setkey */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 25D3DAC0098952B20025F703 /* Build configuration list for PBXNativeTarget "setkey" */;
+                       buildPhases = (
+                               25F258070987FC1500D15623 /* Sources */,
+                               25F258080987FC1500D15623 /* Frameworks */,
+                               258CF2D00A1919CD00166B38 /* CopyFiles */,
+                               258CF3200A19435B00166B38 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               2537A1C309E494D300D0ECDA /* PBXTargetDependency */,
+                       );
+                       name = setkey;
+                       productName = setkey;
+                       productReference = 25F2580A0987FC1500D15623 /* setkey */;
+                       productType = "com.apple.product-type.tool";
+               };
+               25F2580E0987FC3400D15623 /* racoonctl */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 25D3DAC4098952B20025F703 /* Build configuration list for PBXNativeTarget "racoonctl" */;
+                       buildPhases = (
+                               25F2580C0987FC3400D15623 /* Sources */,
+                               25F2580D0987FC3400D15623 /* Frameworks */,
+                               258CF2D50A191A6E00166B38 /* CopyFiles */,
+                               258CF31E0A19432A00166B38 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               2537A1CD09E49D5C00D0ECDA /* PBXTargetDependency */,
+                       );
+                       name = racoonctl;
+                       productName = racoonctl;
+                       productReference = 25F2580F0987FC3400D15623 /* racoonctl */;
+                       productType = "com.apple.product-type.tool";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               23D2D790087071FC00C51098 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = 25D3DACC098952B20025F703 /* Build configuration list for PBXProject "ipsec" */;
+                       compatibilityVersion = "Xcode 2.4";
+                       hasScannedForEncodings = 0;
+                       mainGroup = 23D2D78C087071FC00C51098;
+                       productRefGroup = 23D2D79C087074CC00C51098 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               23B20D2F0871D62A00A3B0FC /* IPSec (Aggregate) */,
+                               25F258040987FBFA00D15623 /* racoon */,
+                               25F2580E0987FC3400D15623 /* racoonctl */,
+                               25F258090987FC1500D15623 /* setkey */,
+                               25E08C9909D9E64A001A11CF /* rsaparse */,
+                               2543476E09DCB477007943DE /* plainrsa-gen */,
+                               2543479209DCB57E007943DE /* eaytest */,
+                               254347B509DCB839007943DE /* test-policy */,
+                               254347C409DCBA07007943DE /* test-pfkey */,
+                               2537A1A709E4864800D0ECDA /* libipsec */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               258CF31B0A1941A200166B38 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "/bin/chmod 600 $DSTROOT/private/etc/racoon/psk.txt\n/bin/chmod 644 $DSTROOT/private/etc/racoon/racoon.conf\n/bin/chmod 600 $DSTROOT/private/etc/racoon/remote/anonymous.conf\n/bin/chmod 444 $DSTROOT/usr/share/man/man5/racoon.conf.5\n/bin/chmod 444 $DSTROOT/usr/share/man/man8/racoon.8\n";
+               };
+               258CF31E0A19432A00166B38 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "/bin/chmod 444 $DSTROOT/usr/share/man/man8/racoonctl.8";
+               };
+               258CF3200A19435B00166B38 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "/bin/chmod 444 $DSTROOT/usr/share/man/man8/setkey.8";
+               };
+               258CF3220A19439000166B38 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "/bin/chmod 444 $DSTROOT/usr/share/man/man8/plainrsa-gen.8";
+               };
+               258CF3240A1943DE00166B38 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "/bin/chmod 444 $DSTROOT/usr/share/man/man3/ipsec_set_policy.3\n/bin/chmod 444 $DSTROOT/usr/share/man/man3/ipsec_strerror.3\n/bin/ln -s libipsec.A.dylib $DSTROOT/usr/lib/libipsec.dylib\n";
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               2537A1A509E4864800D0ECDA /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2537A1B509E4867700D0ECDA /* ipsec_dump_policy.c in Sources */,
+                               2537A1B609E4867700D0ECDA /* ipsec_get_policylen.c in Sources */,
+                               2537A1B709E4867800D0ECDA /* ipsec_strerror.c in Sources */,
+                               2537A1B909E4867900D0ECDA /* policy_parse.y in Sources */,
+                               2537A1BA09E4867A00D0ECDA /* policy_token.l in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               2543476C09DCB477007943DE /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2543477109DCB492007943DE /* plainrsa-gen.c in Sources */,
+                               2543478A09DCB49C007943DE /* plog.c in Sources */,
+                               2543478C09DCB4A6007943DE /* logger.c in Sources */,
+                               25BE7E7F09E5DE4C009B6B84 /* pfkey_dump.c in Sources */,
+                               25BE7E8809E5E499009B6B84 /* pfkey.c in Sources */,
+                               25BE7E8A09E5E4A6009B6B84 /* key_debug.c in Sources */,
+                               25BE7E8E09E5E5BE009B6B84 /* crypto_openssl.c in Sources */,
+                               25BE7E9009E5E61F009B6B84 /* misc.c in Sources */,
+                               25BE7E9209E5E635009B6B84 /* vmbuf.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               2543479009DCB57E007943DE /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               254347A909DCB6C8007943DE /* vmbuf.c in Sources */,
+                               254347AB09DCB6D6007943DE /* str2val.c in Sources */,
+                               25BE7E1B09E5D5D9009B6B84 /* plog.c in Sources */,
+                               25BE7E3809E5D80E009B6B84 /* crypto_openssl.c in Sources */,
+                               25BE7E3E09E5D906009B6B84 /* misc.c in Sources */,
+                               25BE7E4009E5D92C009B6B84 /* logger.c in Sources */,
+                               25BC48740A0BC7B000A181A0 /* eaytest.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               254347B309DCB839007943DE /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               254347B809DCB84D007943DE /* test-policy.c in Sources */,
+                               25BE7E6309E5DD38009B6B84 /* pfkey.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               254347C209DCBA07007943DE /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               254347C809DCBA1B007943DE /* test-pfkey.c in Sources */,
+                               25BE7E5709E5DC4D009B6B84 /* pfkey_dump.c in Sources */,
+                               25BE7E5E09E5DCF5009B6B84 /* pfkey.c in Sources */,
+                               25BE7E6009E5DD04009B6B84 /* key_debug.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25E08C9709D9E64A001A11CF /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25E08C9E09D9E681001A11CF /* prsa_par.y in Sources */,
+                               25E08C9F09D9E682001A11CF /* prsa_tok.l in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F258020987FBFA00D15623 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25F258A80988651000D15623 /* rijndael-alg-fst.c in Sources */,
+                               25F258A90988651000D15623 /* rijndael-api-fst.c in Sources */,
+                               25F259280988657000D15623 /* admin.c in Sources */,
+                               25F259290988657000D15623 /* algorithm.c in Sources */,
+                               25F2592A0988657000D15623 /* backupsa.c in Sources */,
+                               25F2592B0988657000D15623 /* cfparse.y in Sources */,
+                               25F2592C0988657000D15623 /* cftoken.l in Sources */,
+                               25F2592D0988657000D15623 /* crypto_cssm.c in Sources */,
+                               25F2592E0988657000D15623 /* crypto_openssl.c in Sources */,
+                               25F2592F0988657000D15623 /* dnssec.c in Sources */,
+                               25F259310988657000D15623 /* evt.c in Sources */,
+                               25F259320988657000D15623 /* genlist.c in Sources */,
+                               25F259330988657000D15623 /* getcertsbyname.c in Sources */,
+                               25F259340988657000D15623 /* grabmyaddr.c in Sources */,
+                               25F259350988657000D15623 /* gssapi.c in Sources */,
+                               25F259360988657000D15623 /* handler.c in Sources */,
+                               25F259370988657000D15623 /* ipsec_doi.c in Sources */,
+                               25F259380988657000D15623 /* isakmp_agg.c in Sources */,
+                               25F259390988657000D15623 /* isakmp_base.c in Sources */,
+                               25F2593C0988657000D15623 /* isakmp_ident.c in Sources */,
+                               25F2593D0988657000D15623 /* isakmp_inf.c in Sources */,
+                               25F2593E0988657000D15623 /* isakmp_newg.c in Sources */,
+                               25F2593F0988657000D15623 /* isakmp_quick.c in Sources */,
+                               25F259420988657000D15623 /* isakmp.c in Sources */,
+                               25F259440988657000D15623 /* localconf.c in Sources */,
+                               25F259450988657000D15623 /* logger.c in Sources */,
+                               25F259460988657000D15623 /* main.c in Sources */,
+                               25F259470988657000D15623 /* misc.c in Sources */,
+                               25F259490988657000D15623 /* oakley.c in Sources */,
+                               25F2594A0988657000D15623 /* open_dir.c in Sources */,
+                               25F2594C0988657000D15623 /* pfkey_racoon.c in Sources */,
+                               25F2594F0988657000D15623 /* plog.c in Sources */,
+                               25F259500988657000D15623 /* policy.c in Sources */,
+                               25F259510988657000D15623 /* privsep.c in Sources */,
+                               25F259520988657000D15623 /* proposal.c in Sources */,
+                               25F259580988657000D15623 /* remoteconf.c in Sources */,
+                               25F2595A0988657000D15623 /* safefile.c in Sources */,
+                               25F2595B0988657000D15623 /* sainfo.c in Sources */,
+                               25F2595C0988657000D15623 /* schedule.c in Sources */,
+                               25F2595D0988657000D15623 /* session.c in Sources */,
+                               25F2595E0988657000D15623 /* sockmisc.c in Sources */,
+                               25F2595F0988657000D15623 /* str2val.c in Sources */,
+                               25F259600988657000D15623 /* strnames.c in Sources */,
+                               25F259610988657000D15623 /* throttle.c in Sources */,
+                               25F259620988657000D15623 /* vendorid.c in Sources */,
+                               25F259630988657000D15623 /* vmbuf.c in Sources */,
+                               25078AE509D37570005F3F63 /* nattraversal.c in Sources */,
+                               25EAE8C609D87B990042CC7F /* pfkey.c in Sources */,
+                               25DC9EC909DB0FBB00C89F86 /* rsalist.c in Sources */,
+                               25DC9ED409DB16F300C89F86 /* isakmp_cfg.c in Sources */,
+                               25DC9ED509DB16F800C89F86 /* isakmp_unity.c in Sources */,
+                               25DC9ED609DB16FA00C89F86 /* isakmp_xauth.c in Sources */,
+                               25DE2DE90A8BD40E0010A46D /* vpn_control.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F258070987FC1500D15623 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               25F258900988648C00D15623 /* parse.y in Sources */,
+                               25ECCDB709AD48A300883CA3 /* pfkey_dump.c in Sources */,
+                               25ECCDB509AD489200883CA3 /* key_debug.c in Sources */,
+                               25ECCDA209AD479A00883CA3 /* pfkey.c in Sources */,
+                               25F258910988648C00D15623 /* setkey.c in Sources */,
+                               25F258940988648C00D15623 /* token.l in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               25F2580C0987FC3400D15623 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               2543473209DCAE27007943DE /* racoonctl.c in Sources */,
+                               2543474E09DCAEF8007943DE /* str2val.c in Sources */,
+                               2543475109DCB063007943DE /* kmpstat.c in Sources */,
+                               2543475509DCB0D9007943DE /* vmbuf.c in Sources */,
+                               2543475609DCB0DB007943DE /* sockmisc.c in Sources */,
+                               2543475709DCB0E6007943DE /* misc.c in Sources */,
+                               2543476409DCB396007943DE /* pfkey_dump.c in Sources */,
+                               2543476709DCB400007943DE /* key_debug.c in Sources */,
+                               2543476909DCB420007943DE /* pfkey.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               2537A1C309E494D300D0ECDA /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 2537A1C209E494D300D0ECDA /* PBXContainerItemProxy */;
+               };
+               2537A1C909E49D1400D0ECDA /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 2537A1C809E49D1400D0ECDA /* PBXContainerItemProxy */;
+               };
+               2537A1CD09E49D5C00D0ECDA /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 2537A1CC09E49D5C00D0ECDA /* PBXContainerItemProxy */;
+               };
+               254347D109DCBAF8007943DE /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2543476E09DCB477007943DE /* plainrsa-gen */;
+                       targetProxy = 254347D009DCBAF8007943DE /* PBXContainerItemProxy */;
+               };
+               25BE7E0409E5D3FE009B6B84 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 25BE7E0309E5D3FE009B6B84 /* PBXContainerItemProxy */;
+               };
+               25BE7E3009E5D710009B6B84 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 25BE7E2F09E5D710009B6B84 /* PBXContainerItemProxy */;
+               };
+               25BE7E5C09E5DCC5009B6B84 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 25BE7E5B09E5DCC5009B6B84 /* PBXContainerItemProxy */;
+               };
+               25BE7E7C09E5DE28009B6B84 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 25BE7E7B09E5DE28009B6B84 /* PBXContainerItemProxy */;
+               };
+               25D3DDE30989AFDE0025F703 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 25F258040987FBFA00D15623 /* racoon */;
+                       targetProxy = 25D3DDE20989AFDE0025F703 /* PBXContainerItemProxy */;
+               };
+               25D3DDE50989AFE50025F703 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 25F258090987FC1500D15623 /* setkey */;
+                       targetProxy = 25D3DDE40989AFE50025F703 /* PBXContainerItemProxy */;
+               };
+               25D3DDE70989AFE90025F703 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 25F2580E0987FC3400D15623 /* racoonctl */;
+                       targetProxy = 25D3DDE60989AFE90025F703 /* PBXContainerItemProxy */;
+               };
+               25DE3DB609EC27B900147420 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 2537A1A709E4864800D0ECDA /* libipsec */;
+                       targetProxy = 25DE3DB509EC27B900147420 /* PBXContainerItemProxy */;
+               };
+               25E08CEA09D9F0A2001A11CF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 25E08C9909D9E64A001A11CF /* rsaparse */;
+                       targetProxy = 25E08CE909D9F0A2001A11CF /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               2537A1AA09E4866800D0ECDA /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                                       ppc64,
+                                       x86_64,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
+                               DYLIB_CURRENT_VERSION = 300;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       "$(HEADER_SEARCH_PATHS)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/lib;
+                               LEXFLAGS = "$(LEXFLAGS) -P__libipsec";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ipsec.A;
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "ppc64 i386 x86_64 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -d -p__libipsec";
+                               ZERO_LINK = YES;
+                       };
+                       name = Development;
+               };
+               2537A1AB09E4866800D0ECDA /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                                       ppc64,
+                                       x86_64,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
+                               DYLIB_CURRENT_VERSION = 300;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       "$(HEADER_SEARCH_PATHS)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/lib;
+                               LEXFLAGS = "$(LEXFLAGS) -P__libipsec";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ipsec.A;
+                               VALID_ARCHS = "ppc64 i386 x86_64 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -d -p__libipsec";
+                               ZERO_LINK = YES;
+                       };
+                       name = Deployment;
+               };
+               2537A1AC09E4866800D0ECDA /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                                       ppc64,
+                                       x86_64,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
+                               DYLIB_CURRENT_VERSION = 300;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       "$(HEADER_SEARCH_PATHS)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/lib;
+                               LEXFLAGS = "$(LEXFLAGS) -P__libipsec";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ipsec.A;
+                               VALID_ARCHS = "ppc64 i386 x86_64 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -d -p__libipsec";
+                               ZERO_LINK = YES;
+                       };
+                       name = Default;
+               };
+               2543478709DCB494007943DE /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "plainrsa-gen";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               2543478809DCB494007943DE /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /use/sbin;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "plainrsa-gen";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               2543478909DCB494007943DE /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "plainrsa-gen";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Default;
+               };
+               2543479A09DCB596007943DE /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_GROUP = "$(inherited)";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = "$(inherited)";
+                               INSTALL_PATH = "";
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS)",
+                                       "-DEAYDEBUG",
+                                       "-DNOUSE_PLOG",
+                               );
+                               PREBINDING = NO;
+                               PRODUCT_NAME = eaytest;
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               2543479B09DCB596007943DE /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_GROUP = "$(inherited)";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = "$(inherited)";
+                               INSTALL_PATH = "";
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS)",
+                                       "-DEAYDEBUG",
+                                       "-DNOUSE_PLOG",
+                               );
+                               PREBINDING = NO;
+                               PRODUCT_NAME = eaytest;
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               2543479C09DCB596007943DE /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_GROUP = "$(inherited)";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = "$(inherited)";
+                               INSTALL_PATH = "";
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS)",
+                                       "-DEAYDEBUG",
+                                       "-DNOUSE_PLOG",
+                               );
+                               PREBINDING = NO;
+                               PRODUCT_NAME = eaytest;
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Default;
+               };
+               254347BE09DCB851007943DE /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-policy";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               254347BF09DCB851007943DE /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-policy";
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               254347C009DCB851007943DE /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(inherited)",
+                               );
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-policy";
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Default;
+               };
+               254347CA09DCBA1B007943DE /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-pfkey";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Development;
+               };
+               254347CB09DCBA1B007943DE /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-pfkey";
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               254347CC09DCBA1B007943DE /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1";
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = "test-pfkey";
+                               SKIP_INSTALL = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               ZERO_LINK = NO;
+                       };
+                       name = Default;
+               };
+               25D3DAB9098952B20025F703 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "IPSec (Aggregate)";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Development;
+               };
+               25D3DABA098952B20025F703 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "IPSec (Aggregate)";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Deployment;
+               };
+               25D3DABB098952B20025F703 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "IPSec (Aggregate)";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Default;
+               };
+               25D3DABD098952B20025F703 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       Crypto,
+                                       /tmp/ipsec.dst/usr/include,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               LEXFLAGS = "";
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS_QUOTED_1)",
+                                       "$(OTHER_CFLAGS_QUOTED_2)",
+                                       "$(OTHER_CFLAGS_QUOTED_3)",
+                               );
+                               OTHER_CFLAGS_QUOTED_1 = "-DSYSCONFDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_2 = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_3 = "-DPATHRACOON=\\\"/usr/sbin/racoon\\\"";
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoon;
+                               SECTORDER_FLAGS = "";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               YACCFLAGS = "$(YACCFLAGS) -d";
+                               YACC_GENERATE_DEBUGGING_DIRECTIVES = NO;
+                       };
+                       name = Development;
+               };
+               25D3DABE098952B20025F703 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               DSTROOT = "/tmp/$(PROJECT_NAME).dst";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       Crypto,
+                                       /tmp/ipsec.dst/usr/include,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS_QUOTED_1)",
+                                       "$(OTHER_CFLAGS_QUOTED_2)",
+                                       "$(OTHER_CFLAGS_QUOTED_3)",
+                               );
+                               OTHER_CFLAGS_QUOTED_1 = "-DSYSCONFDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_2 = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_3 = "-DPATHRACOON=\\\"/usr/sbin/racoon\\\"";
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoon;
+                               SECTORDER_FLAGS = "";
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               YACCFLAGS = "$(YACCFLAGS) -d";
+                       };
+                       name = Deployment;
+               };
+               25D3DABF098952B20025F703 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               DSTROOT = "/tmp/$(PROJECT_NAME).dst";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "";
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       ../Common,
+                                       Crypto,
+                                       /tmp/ipsec.dst/usr/include,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS_QUOTED_1)",
+                                       "$(OTHER_CFLAGS_QUOTED_2)",
+                                       "$(OTHER_CFLAGS_QUOTED_3)",
+                               );
+                               OTHER_CFLAGS_QUOTED_1 = "-DSYSCONFDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_2 = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_CFLAGS_QUOTED_3 = "-DPATHRACOON=\\\"/usr/sbin/racoon\\\"";
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoon;
+                               SECTORDER_FLAGS = "";
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               YACCFLAGS = "$(YACCFLAGS) -d";
+                       };
+                       name = Default;
+               };
+               25D3DAC1098952B20025F703 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1\nHAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       ../Common,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               LIBRARY_SEARCH_PATHS = "";
+                               MACH_O_TYPE = mh_execute;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRELINK_LIBS = "";
+                               PRODUCT_NAME = setkey;
+                               SECTORDER_FLAGS = "";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                               YACCFLAGS = "";
+                       };
+                       name = Development;
+               };
+               25D3DAC2098952B20025F703 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1\nHAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       ../Common,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               LIBRARY_SEARCH_PATHS = "";
+                               MACH_O_TYPE = mh_execute;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRELINK_LIBS = "";
+                               PRODUCT_NAME = setkey;
+                               SECTORDER_FLAGS = "";
+                               SKIP_INSTALL = NO;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Deployment;
+               };
+               25D3DAC3098952B20025F703 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1\nHAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       ../Common,
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               LIBRARY_SEARCH_PATHS = "";
+                               MACH_O_TYPE = mh_execute;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRELINK_LIBS = "";
+                               PRODUCT_NAME = setkey;
+                               SECTORDER_FLAGS = "";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Default;
+               };
+               25D3DAC5098952B20025F703 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               OTHER_CFLAGS = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoonctl;
+                               SECTORDER_FLAGS = "";
+                               SKIP_INSTALL = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Development;
+               };
+               25D3DAC6098952B20025F703 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               OTHER_CFLAGS = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoonctl;
+                               SECTORDER_FLAGS = "";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Deployment;
+               };
+               25D3DAC7098952B20025F703 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALTERNATE_GROUP = "$(inherited)";
+                               ALTERNATE_MODE = "$(inherited)";
+                               ALTERNATE_OWNER = "$(inherited)";
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "HAVE_CONFIG_H=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                               );
+                               HEADER_SEARCH_PATHS = (
+                                       "$(DSTROOT)/usr/include",
+                                       "$(inherited)",
+                               );
+                               INSTALL_GROUP = wheel;
+                               INSTALL_MODE_FLAG = 555;
+                               INSTALL_OWNER = root;
+                               INSTALL_PATH = /usr/sbin;
+                               OTHER_CFLAGS = "-DADMINPORTDIR=\\\"/etc/racoon\\\"";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = racoonctl;
+                               SECTORDER_FLAGS = "";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VALID_ARCHS = "i386 ppc";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Default;
+               };
+               25D3DACD098952B20025F703 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                               );
+                       };
+                       name = Development;
+               };
+               25D3DACE098952B20025F703 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                               );
+                       };
+                       name = Deployment;
+               };
+               25D3DACF098952B20025F703 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       i386,
+                                       ppc,
+                               );
+                       };
+                       name = Default;
+               };
+               25E08CA309D9E6A4001A11CF /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "";
+                               LEXFLAGS = "$(LEXFLAGS) -Pprsa";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rsaparse;
+                               VALID_ARCHS = "i386 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -pprsa";
+                       };
+                       name = Development;
+               };
+               25E08CA409D9E6A4001A11CF /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "";
+                               LEXFLAGS = "$(LEXFLAGS) -Pprsa";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rsaparse;
+                               VALID_ARCHS = "i386 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -pprsa";
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               25E08CA509D9E6A4001A11CF /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "";
+                               LEXFLAGS = "$(LEXFLAGS) -Pprsa";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rsaparse;
+                               VALID_ARCHS = "i386 ppc";
+                               YACCFLAGS = "$(YACCFLAGS) -pprsa";
+                       };
+                       name = Default;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               2537A1A909E4866800D0ECDA /* Build configuration list for PBXNativeTarget "libipsec" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               2537A1AA09E4866800D0ECDA /* Development */,
+                               2537A1AB09E4866800D0ECDA /* Deployment */,
+                               2537A1AC09E4866800D0ECDA /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               2543478609DCB494007943DE /* Build configuration list for PBXNativeTarget "plainrsa-gen" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               2543478709DCB494007943DE /* Development */,
+                               2543478809DCB494007943DE /* Deployment */,
+                               2543478909DCB494007943DE /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               2543479909DCB596007943DE /* Build configuration list for PBXNativeTarget "eaytest" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               2543479A09DCB596007943DE /* Development */,
+                               2543479B09DCB596007943DE /* Deployment */,
+                               2543479C09DCB596007943DE /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               254347BD09DCB851007943DE /* Build configuration list for PBXNativeTarget "test-policy" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               254347BE09DCB851007943DE /* Development */,
+                               254347BF09DCB851007943DE /* Deployment */,
+                               254347C009DCB851007943DE /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               254347C909DCBA1B007943DE /* Build configuration list for PBXNativeTarget "test-pfkey" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               254347CA09DCBA1B007943DE /* Development */,
+                               254347CB09DCBA1B007943DE /* Deployment */,
+                               254347CC09DCBA1B007943DE /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25D3DAB8098952B20025F703 /* Build configuration list for PBXAggregateTarget "IPSec (Aggregate)" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25D3DAB9098952B20025F703 /* Development */,
+                               25D3DABA098952B20025F703 /* Deployment */,
+                               25D3DABB098952B20025F703 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25D3DABC098952B20025F703 /* Build configuration list for PBXNativeTarget "racoon" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25D3DABD098952B20025F703 /* Development */,
+                               25D3DABE098952B20025F703 /* Deployment */,
+                               25D3DABF098952B20025F703 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25D3DAC0098952B20025F703 /* Build configuration list for PBXNativeTarget "setkey" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25D3DAC1098952B20025F703 /* Development */,
+                               25D3DAC2098952B20025F703 /* Deployment */,
+                               25D3DAC3098952B20025F703 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25D3DAC4098952B20025F703 /* Build configuration list for PBXNativeTarget "racoonctl" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25D3DAC5098952B20025F703 /* Development */,
+                               25D3DAC6098952B20025F703 /* Deployment */,
+                               25D3DAC7098952B20025F703 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25D3DACC098952B20025F703 /* Build configuration list for PBXProject "ipsec" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25D3DACD098952B20025F703 /* Development */,
+                               25D3DACE098952B20025F703 /* Deployment */,
+                               25D3DACF098952B20025F703 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+               25E08CA209D9E6A4001A11CF /* Build configuration list for PBXNativeTarget "rsaparse" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               25E08CA309D9E6A4001A11CF /* Development */,
+                               25E08CA409D9E6A4001A11CF /* Deployment */,
+                               25E08CA509D9E6A4001A11CF /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 23D2D790087071FC00C51098 /* Project object */;
+}