--- /dev/null
+
+
+/* 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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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);
+}
--- /dev/null
+.so man3/ipsec_set_policy.3
--- /dev/null
+/* $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;
+}
--- /dev/null
+.so man3/ipsec_set_policy.3
--- /dev/null
+/* $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;
+}
--- /dev/null
+.\" $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.
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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
+};
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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__ */
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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__ */
+
--- /dev/null
+/* $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__ */
+
--- /dev/null
+/* $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__ */
+
--- /dev/null
+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/
--- /dev/null
+See http://www.kame.net/newsletter/20001119b/
--- /dev/null
+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>
+
--- /dev/null
+$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.
+
--- /dev/null
+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 ;
+}
--- /dev/null
+# 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
--- /dev/null
+# $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 ;
+}
+
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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__ */
+
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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);
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+
+/*
+ * 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>";
+ }
+}
+
--- /dev/null
+
+/*
+ * 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__ */
+
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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);
+}
+
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 = ∅
+
+ 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
--- /dev/null
+/* $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__ */
+
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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);
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
+
+
--- /dev/null
+/* $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 *);
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
+ }
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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__ */
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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();
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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++; }
+\#.* ;
+%%
--- /dev/null
+.\" $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 .
--- /dev/null
+.\" $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 .
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
+
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+#!/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{$_};
+}
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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);
+ }
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+#
+# 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;
--- /dev/null
+#
+# 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";
--- /dev/null
+# 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.
--- /dev/null
+
+
+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
--- /dev/null
+/* $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;
+}
--- /dev/null
+#! @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;
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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 */
--- /dev/null
+// !$*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 */;
+}