From 52b7d2ce06d68d0a9160d16f6e7c08c21c149d0d Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 5 Oct 2007 21:23:48 +0000 Subject: [PATCH] ipsec-34.tar.gz --- ipsec-tools/Common/config.h | 256 + ipsec-tools/Common/key_debug.c | 819 ++++ ipsec-tools/Common/libpfkey.h | 191 + ipsec-tools/Common/pfkey.c | 2739 +++++++++++ ipsec-tools/Common/pfkey_dump.c | 784 +++ ipsec-tools/libipsec/ipsec_dump_policy.3 | 1 + ipsec-tools/libipsec/ipsec_dump_policy.c | 419 ++ ipsec-tools/libipsec/ipsec_get_policylen.3 | 1 + ipsec-tools/libipsec/ipsec_get_policylen.c | 60 + ipsec-tools/libipsec/ipsec_set_policy.3 | 334 ++ ipsec-tools/libipsec/ipsec_strerror.3 | 88 + ipsec-tools/libipsec/ipsec_strerror.c | 98 + ipsec-tools/libipsec/ipsec_strerror.h | 71 + ipsec-tools/libipsec/policy_parse.y | 653 +++ ipsec-tools/libipsec/policy_token.l | 198 + ipsec-tools/libipsec/test-policy.c | 334 ++ ipsec-tools/racoon/Crypto/boxes-fst.dat | 957 ++++ ipsec-tools/racoon/Crypto/rijndael-alg-fst.c | 492 ++ ipsec-tools/racoon/Crypto/rijndael-alg-fst.h | 34 + ipsec-tools/racoon/Crypto/rijndael-api-fst.c | 495 ++ ipsec-tools/racoon/Crypto/rijndael-api-fst.h | 104 + ipsec-tools/racoon/Crypto/rijndael.h | 10 + ipsec-tools/racoon/Crypto/rijndael_local.h | 17 + ipsec-tools/racoon/Documents/FAQ | 106 + .../racoon/Documents/README.certificate | 1 + ipsec-tools/racoon/Documents/README.gssapi | 106 + ipsec-tools/racoon/Documents/TODO | 131 + ipsec-tools/racoon/Sample/anonymous.conf | 34 + ipsec-tools/racoon/Sample/psk.txt | 10 + ipsec-tools/racoon/Sample/racoon.conf | 137 + ipsec-tools/racoon/admin.c | 640 +++ ipsec-tools/racoon/admin.h | 107 + ipsec-tools/racoon/admin_var.h | 39 + ipsec-tools/racoon/algorithm.c | 915 ++++ ipsec-tools/racoon/algorithm.h | 209 + ipsec-tools/racoon/arc4random.h | 39 + ipsec-tools/racoon/backupsa.c | 505 ++ ipsec-tools/racoon/backupsa.h | 42 + ipsec-tools/racoon/cfparse.y | 2158 ++++++++ ipsec-tools/racoon/cfparse_proto.h | 40 + ipsec-tools/racoon/cftoken.l | 854 ++++ ipsec-tools/racoon/cftoken_proto.h | 47 + ipsec-tools/racoon/crypto_cssm.c | 536 ++ ipsec-tools/racoon/crypto_cssm.h | 41 + ipsec-tools/racoon/crypto_openssl.c | 2908 +++++++++++ ipsec-tools/racoon/crypto_openssl.h | 229 + ipsec-tools/racoon/debug.h | 39 + ipsec-tools/racoon/debugrm.h | 92 + ipsec-tools/racoon/dhgroup.h | 203 + ipsec-tools/racoon/dnssec.c | 149 + ipsec-tools/racoon/dnssec.h | 37 + ipsec-tools/racoon/dump.h | 39 + ipsec-tools/racoon/eaytest.c | 1077 ++++ ipsec-tools/racoon/evt.c | 149 + ipsec-tools/racoon/evt.h | 84 + ipsec-tools/racoon/gcmalloc.h | 114 + ipsec-tools/racoon/genlist.c | 172 + ipsec-tools/racoon/genlist.h | 80 + ipsec-tools/racoon/getcertsbyname.c | 416 ++ ipsec-tools/racoon/gnuc.h | 44 + ipsec-tools/racoon/grabmyaddr.c | 824 ++++ ipsec-tools/racoon/grabmyaddr.h | 57 + ipsec-tools/racoon/gssapi.c | 745 +++ ipsec-tools/racoon/gssapi.h | 95 + ipsec-tools/racoon/handler.c | 1040 ++++ ipsec-tools/racoon/handler.h | 473 ++ ipsec-tools/racoon/ipsec_doi.c | 4348 +++++++++++++++++ ipsec-tools/racoon/ipsec_doi.h | 249 + ipsec-tools/racoon/isakmp.c | 3633 ++++++++++++++ ipsec-tools/racoon/isakmp.h | 447 ++ ipsec-tools/racoon/isakmp_agg.c | 1514 ++++++ ipsec-tools/racoon/isakmp_agg.h | 44 + ipsec-tools/racoon/isakmp_base.c | 1237 +++++ ipsec-tools/racoon/isakmp_base.h | 46 + ipsec-tools/racoon/isakmp_cfg.c | 1600 ++++++ ipsec-tools/racoon/isakmp_cfg.h | 176 + ipsec-tools/racoon/isakmp_frag.c | 353 ++ ipsec-tools/racoon/isakmp_frag.h | 49 + ipsec-tools/racoon/isakmp_ident.c | 1792 +++++++ ipsec-tools/racoon/isakmp_ident.h | 50 + ipsec-tools/racoon/isakmp_inf.c | 1799 +++++++ ipsec-tools/racoon/isakmp_inf.h | 55 + ipsec-tools/racoon/isakmp_newg.c | 230 + ipsec-tools/racoon/isakmp_newg.h | 37 + ipsec-tools/racoon/isakmp_quick.c | 2238 +++++++++ ipsec-tools/racoon/isakmp_quick.h | 48 + ipsec-tools/racoon/isakmp_unity.c | 172 + ipsec-tools/racoon/isakmp_unity.h | 45 + ipsec-tools/racoon/isakmp_var.h | 136 + ipsec-tools/racoon/isakmp_xauth.c | 995 ++++ ipsec-tools/racoon/isakmp_xauth.h | 96 + ipsec-tools/racoon/kmpstat.c | 230 + ipsec-tools/racoon/localconf.c | 479 ++ ipsec-tools/racoon/localconf.h | 167 + ipsec-tools/racoon/logger.c | 260 + ipsec-tools/racoon/logger.h | 51 + ipsec-tools/racoon/main.c | 469 ++ ipsec-tools/racoon/misc.c | 169 + ipsec-tools/racoon/misc.h | 61 + ipsec-tools/racoon/nattraversal.c | 652 +++ ipsec-tools/racoon/nattraversal.h | 104 + ipsec-tools/racoon/netdb_dnssec.h | 72 + ipsec-tools/racoon/oakley.c | 3626 ++++++++++++++ ipsec-tools/racoon/oakley.h | 218 + ipsec-tools/racoon/open_dir.c | 426 ++ ipsec-tools/racoon/open_dir.h | 30 + ipsec-tools/racoon/pfkey.h | 75 + ipsec-tools/racoon/pfkey_racoon.c | 3037 ++++++++++++ ipsec-tools/racoon/plainrsa-gen.8 | 137 + ipsec-tools/racoon/plainrsa-gen.c | 209 + ipsec-tools/racoon/plog.c | 270 + ipsec-tools/racoon/plog.h | 78 + ipsec-tools/racoon/policy.c | 481 ++ ipsec-tools/racoon/policy.h | 136 + ipsec-tools/racoon/privsep.c | 1210 +++++ ipsec-tools/racoon/privsep.h | 69 + ipsec-tools/racoon/proposal.c | 1189 +++++ ipsec-tools/racoon/proposal.h | 211 + ipsec-tools/racoon/prsa_par.y | 348 ++ ipsec-tools/racoon/prsa_tok.l | 91 + ipsec-tools/racoon/racoon.8 | 157 + ipsec-tools/racoon/racoon.conf.5 | 1158 +++++ ipsec-tools/racoon/racoonctl.8 | 190 + ipsec-tools/racoon/racoonctl.c | 1585 ++++++ ipsec-tools/racoon/racoonctl.h | 51 + ipsec-tools/racoon/remoteconf.c | 776 +++ ipsec-tools/racoon/remoteconf.h | 224 + ipsec-tools/racoon/rsalist.c | 214 + ipsec-tools/racoon/rsalist.h | 63 + ipsec-tools/racoon/safefile.c | 91 + ipsec-tools/racoon/safefile.h | 37 + ipsec-tools/racoon/sainfo.c | 250 + ipsec-tools/racoon/sainfo.h | 76 + ipsec-tools/racoon/schedule.c | 362 ++ ipsec-tools/racoon/schedule.h | 81 + ipsec-tools/racoon/session.c | 659 +++ ipsec-tools/racoon/session.h | 39 + ipsec-tools/racoon/sockmisc.c | 1105 +++++ ipsec-tools/racoon/sockmisc.h | 87 + ipsec-tools/racoon/stats.pl | 15 + ipsec-tools/racoon/str2val.c | 124 + ipsec-tools/racoon/str2val.h | 38 + ipsec-tools/racoon/strnames.c | 942 ++++ ipsec-tools/racoon/strnames.h | 74 + ipsec-tools/racoon/throttle.c | 154 + ipsec-tools/racoon/throttle.h | 49 + ipsec-tools/racoon/var.h | 105 + ipsec-tools/racoon/vendorid.c | 270 + ipsec-tools/racoon/vendorid.h | 104 + ipsec-tools/racoon/vmbuf.c | 129 + ipsec-tools/racoon/vmbuf.h | 68 + ipsec-tools/racoon/vpn_control.c | 516 ++ ipsec-tools/racoon/vpn_control.h | 172 + ipsec-tools/racoon/vpn_control_var.h | 65 + ipsec-tools/setkey/Sample/sample-policy01.cf | 20 + ipsec-tools/setkey/Sample/sample-policy02.cf | 43 + ipsec-tools/setkey/Sample/sample.cf | 217 + ipsec-tools/setkey/extern.h | 28 + ipsec-tools/setkey/parse.y | 1539 ++++++ ipsec-tools/setkey/scriptdump.pl | 55 + ipsec-tools/setkey/setkey.8 | 828 ++++ ipsec-tools/setkey/setkey.c | 908 ++++ ipsec-tools/setkey/test-pfkey.c | 571 +++ ipsec-tools/setkey/token.l | 353 ++ ipsec-tools/setkey/vchar.h | 40 + ipsec.xcodeproj/project.pbxproj | 2505 ++++++++++ 166 files changed, 77999 insertions(+) create mode 100644 ipsec-tools/Common/config.h create mode 100644 ipsec-tools/Common/key_debug.c create mode 100644 ipsec-tools/Common/libpfkey.h create mode 100644 ipsec-tools/Common/pfkey.c create mode 100644 ipsec-tools/Common/pfkey_dump.c create mode 100644 ipsec-tools/libipsec/ipsec_dump_policy.3 create mode 100644 ipsec-tools/libipsec/ipsec_dump_policy.c create mode 100644 ipsec-tools/libipsec/ipsec_get_policylen.3 create mode 100644 ipsec-tools/libipsec/ipsec_get_policylen.c create mode 100644 ipsec-tools/libipsec/ipsec_set_policy.3 create mode 100644 ipsec-tools/libipsec/ipsec_strerror.3 create mode 100644 ipsec-tools/libipsec/ipsec_strerror.c create mode 100644 ipsec-tools/libipsec/ipsec_strerror.h create mode 100644 ipsec-tools/libipsec/policy_parse.y create mode 100644 ipsec-tools/libipsec/policy_token.l create mode 100644 ipsec-tools/libipsec/test-policy.c create mode 100644 ipsec-tools/racoon/Crypto/boxes-fst.dat create mode 100644 ipsec-tools/racoon/Crypto/rijndael-alg-fst.c create mode 100644 ipsec-tools/racoon/Crypto/rijndael-alg-fst.h create mode 100644 ipsec-tools/racoon/Crypto/rijndael-api-fst.c create mode 100644 ipsec-tools/racoon/Crypto/rijndael-api-fst.h create mode 100644 ipsec-tools/racoon/Crypto/rijndael.h create mode 100644 ipsec-tools/racoon/Crypto/rijndael_local.h create mode 100644 ipsec-tools/racoon/Documents/FAQ create mode 100644 ipsec-tools/racoon/Documents/README.certificate create mode 100644 ipsec-tools/racoon/Documents/README.gssapi create mode 100644 ipsec-tools/racoon/Documents/TODO create mode 100644 ipsec-tools/racoon/Sample/anonymous.conf create mode 100644 ipsec-tools/racoon/Sample/psk.txt create mode 100644 ipsec-tools/racoon/Sample/racoon.conf create mode 100644 ipsec-tools/racoon/admin.c create mode 100644 ipsec-tools/racoon/admin.h create mode 100644 ipsec-tools/racoon/admin_var.h create mode 100644 ipsec-tools/racoon/algorithm.c create mode 100644 ipsec-tools/racoon/algorithm.h create mode 100644 ipsec-tools/racoon/arc4random.h create mode 100644 ipsec-tools/racoon/backupsa.c create mode 100644 ipsec-tools/racoon/backupsa.h create mode 100644 ipsec-tools/racoon/cfparse.y create mode 100644 ipsec-tools/racoon/cfparse_proto.h create mode 100644 ipsec-tools/racoon/cftoken.l create mode 100644 ipsec-tools/racoon/cftoken_proto.h create mode 100644 ipsec-tools/racoon/crypto_cssm.c create mode 100644 ipsec-tools/racoon/crypto_cssm.h create mode 100644 ipsec-tools/racoon/crypto_openssl.c create mode 100644 ipsec-tools/racoon/crypto_openssl.h create mode 100644 ipsec-tools/racoon/debug.h create mode 100644 ipsec-tools/racoon/debugrm.h create mode 100644 ipsec-tools/racoon/dhgroup.h create mode 100644 ipsec-tools/racoon/dnssec.c create mode 100644 ipsec-tools/racoon/dnssec.h create mode 100644 ipsec-tools/racoon/dump.h create mode 100644 ipsec-tools/racoon/eaytest.c create mode 100644 ipsec-tools/racoon/evt.c create mode 100644 ipsec-tools/racoon/evt.h create mode 100644 ipsec-tools/racoon/gcmalloc.h create mode 100644 ipsec-tools/racoon/genlist.c create mode 100644 ipsec-tools/racoon/genlist.h create mode 100644 ipsec-tools/racoon/getcertsbyname.c create mode 100644 ipsec-tools/racoon/gnuc.h create mode 100644 ipsec-tools/racoon/grabmyaddr.c create mode 100644 ipsec-tools/racoon/grabmyaddr.h create mode 100644 ipsec-tools/racoon/gssapi.c create mode 100644 ipsec-tools/racoon/gssapi.h create mode 100644 ipsec-tools/racoon/handler.c create mode 100644 ipsec-tools/racoon/handler.h create mode 100644 ipsec-tools/racoon/ipsec_doi.c create mode 100644 ipsec-tools/racoon/ipsec_doi.h create mode 100644 ipsec-tools/racoon/isakmp.c create mode 100644 ipsec-tools/racoon/isakmp.h create mode 100644 ipsec-tools/racoon/isakmp_agg.c create mode 100644 ipsec-tools/racoon/isakmp_agg.h create mode 100644 ipsec-tools/racoon/isakmp_base.c create mode 100644 ipsec-tools/racoon/isakmp_base.h create mode 100644 ipsec-tools/racoon/isakmp_cfg.c create mode 100644 ipsec-tools/racoon/isakmp_cfg.h create mode 100644 ipsec-tools/racoon/isakmp_frag.c create mode 100644 ipsec-tools/racoon/isakmp_frag.h create mode 100644 ipsec-tools/racoon/isakmp_ident.c create mode 100644 ipsec-tools/racoon/isakmp_ident.h create mode 100644 ipsec-tools/racoon/isakmp_inf.c create mode 100644 ipsec-tools/racoon/isakmp_inf.h create mode 100644 ipsec-tools/racoon/isakmp_newg.c create mode 100644 ipsec-tools/racoon/isakmp_newg.h create mode 100644 ipsec-tools/racoon/isakmp_quick.c create mode 100644 ipsec-tools/racoon/isakmp_quick.h create mode 100644 ipsec-tools/racoon/isakmp_unity.c create mode 100644 ipsec-tools/racoon/isakmp_unity.h create mode 100644 ipsec-tools/racoon/isakmp_var.h create mode 100644 ipsec-tools/racoon/isakmp_xauth.c create mode 100644 ipsec-tools/racoon/isakmp_xauth.h create mode 100644 ipsec-tools/racoon/kmpstat.c create mode 100644 ipsec-tools/racoon/localconf.c create mode 100644 ipsec-tools/racoon/localconf.h create mode 100644 ipsec-tools/racoon/logger.c create mode 100644 ipsec-tools/racoon/logger.h create mode 100644 ipsec-tools/racoon/main.c create mode 100644 ipsec-tools/racoon/misc.c create mode 100644 ipsec-tools/racoon/misc.h create mode 100644 ipsec-tools/racoon/nattraversal.c create mode 100644 ipsec-tools/racoon/nattraversal.h create mode 100644 ipsec-tools/racoon/netdb_dnssec.h create mode 100644 ipsec-tools/racoon/oakley.c create mode 100644 ipsec-tools/racoon/oakley.h create mode 100644 ipsec-tools/racoon/open_dir.c create mode 100644 ipsec-tools/racoon/open_dir.h create mode 100644 ipsec-tools/racoon/pfkey.h create mode 100644 ipsec-tools/racoon/pfkey_racoon.c create mode 100644 ipsec-tools/racoon/plainrsa-gen.8 create mode 100644 ipsec-tools/racoon/plainrsa-gen.c create mode 100644 ipsec-tools/racoon/plog.c create mode 100644 ipsec-tools/racoon/plog.h create mode 100644 ipsec-tools/racoon/policy.c create mode 100644 ipsec-tools/racoon/policy.h create mode 100644 ipsec-tools/racoon/privsep.c create mode 100644 ipsec-tools/racoon/privsep.h create mode 100644 ipsec-tools/racoon/proposal.c create mode 100644 ipsec-tools/racoon/proposal.h create mode 100644 ipsec-tools/racoon/prsa_par.y create mode 100644 ipsec-tools/racoon/prsa_tok.l create mode 100644 ipsec-tools/racoon/racoon.8 create mode 100644 ipsec-tools/racoon/racoon.conf.5 create mode 100644 ipsec-tools/racoon/racoonctl.8 create mode 100644 ipsec-tools/racoon/racoonctl.c create mode 100644 ipsec-tools/racoon/racoonctl.h create mode 100644 ipsec-tools/racoon/remoteconf.c create mode 100644 ipsec-tools/racoon/remoteconf.h create mode 100644 ipsec-tools/racoon/rsalist.c create mode 100644 ipsec-tools/racoon/rsalist.h create mode 100644 ipsec-tools/racoon/safefile.c create mode 100644 ipsec-tools/racoon/safefile.h create mode 100644 ipsec-tools/racoon/sainfo.c create mode 100644 ipsec-tools/racoon/sainfo.h create mode 100644 ipsec-tools/racoon/schedule.c create mode 100644 ipsec-tools/racoon/schedule.h create mode 100644 ipsec-tools/racoon/session.c create mode 100644 ipsec-tools/racoon/session.h create mode 100644 ipsec-tools/racoon/sockmisc.c create mode 100644 ipsec-tools/racoon/sockmisc.h create mode 100644 ipsec-tools/racoon/stats.pl create mode 100644 ipsec-tools/racoon/str2val.c create mode 100644 ipsec-tools/racoon/str2val.h create mode 100644 ipsec-tools/racoon/strnames.c create mode 100644 ipsec-tools/racoon/strnames.h create mode 100644 ipsec-tools/racoon/throttle.c create mode 100644 ipsec-tools/racoon/throttle.h create mode 100644 ipsec-tools/racoon/var.h create mode 100644 ipsec-tools/racoon/vendorid.c create mode 100644 ipsec-tools/racoon/vendorid.h create mode 100644 ipsec-tools/racoon/vmbuf.c create mode 100644 ipsec-tools/racoon/vmbuf.h create mode 100644 ipsec-tools/racoon/vpn_control.c create mode 100644 ipsec-tools/racoon/vpn_control.h create mode 100644 ipsec-tools/racoon/vpn_control_var.h create mode 100644 ipsec-tools/setkey/Sample/sample-policy01.cf create mode 100644 ipsec-tools/setkey/Sample/sample-policy02.cf create mode 100644 ipsec-tools/setkey/Sample/sample.cf create mode 100644 ipsec-tools/setkey/extern.h create mode 100644 ipsec-tools/setkey/parse.y create mode 100644 ipsec-tools/setkey/scriptdump.pl create mode 100644 ipsec-tools/setkey/setkey.8 create mode 100644 ipsec-tools/setkey/setkey.c create mode 100644 ipsec-tools/setkey/test-pfkey.c create mode 100644 ipsec-tools/setkey/token.l create mode 100644 ipsec-tools/setkey/vchar.h create mode 100644 ipsec.xcodeproj/project.pbxproj diff --git a/ipsec-tools/Common/config.h b/ipsec-tools/Common/config.h new file mode 100644 index 0000000..be2c9ed --- /dev/null +++ b/ipsec-tools/Common/config.h @@ -0,0 +1,256 @@ + + +/* If printf doesn't support %zu. */ +#undef BROKEN_PRINTF + +/* Enable admin port */ +#define ENABLE_ADMINPORT 1 + +/* Enable VPN control port */ +#define ENABLE_VPNCONTROL_PORT 1 + +/* Enable dead peer detection */ +#define ENABLE_DPD 1 + +/* IKE fragmentation support */ +#undef ENABLE_FRAG + +/* Hybrid authentication support */ +#define ENABLE_HYBRID 1 + +/* Enable NAT-Traversal */ +#define ENABLE_NATT 1 + +#ifndef __APPLE__ +/* our kernel does not have support for versions 00 or 01 */ +/* Enable NAT-Traversal draft 00 */ +#undef ENABLE_NATT_00 + +/* Enable NAT-Traversal draft 01 */ +#undef ENABLE_NATT_01 +#endif /* __APPLE__ */ + +/* Enable NAT-Traversal draft 02 */ +#define ENABLE_NATT_02 1 + +/* Enable NAT-Traversal draft 03 */ +#define ENABLE_NATT_03 1 + +/* Enable NAT-Traversal draft 04 */ +#define ENABLE_NATT_04 1 + +/* Enable NAT-Traversal draft 05 */ +#define ENABLE_NATT_05 1 + +/* Enable NAT-Traversal draft 06 */ +#define ENABLE_NATT_06 1 + +/* Enable NAT-Traversal draft 07 */ +#define ENABLE_NATT_07 1 + +/* Enable NAT-Traversal draft 08 */ +#define ENABLE_NATT_08 1 + +/* Enable NAT-Traversal APPLE version */ +#define ENABLE_NATT_APPLE 1 + +/* Enable NAT-Traversal RFC version */ +#define ENABLE_NATT_RFC 1 + +/* Enable samode-unspec */ +#undef ENABLE_SAMODE_UNSPECIFIED + +/* Enable statictics */ +//#define ENABLE_STATS 1 + +/* Define to 1 if you have the 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 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 header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Use */ +#define HAVE_NETINET6_IPSEC 1 + +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_AES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_ENGINE_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_IDEA_H + +/* Define to 1 if you have the 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 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 header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the 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 header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the 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 header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the 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 and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your 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 does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/ipsec-tools/Common/key_debug.c b/ipsec-tools/Common/key_debug.c new file mode 100644 index 0000000..06a9d4b --- /dev/null +++ b/ipsec-tools/Common/key_debug.c @@ -0,0 +1,819 @@ +/* $KAME: key_debug.c,v 1.29 2001/08/16 14:25:41 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _KERNEL +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif +#ifdef __NetBSD__ +#include "opt_inet.h" +#endif +#endif + +#include +#include +#ifdef _KERNEL +#include +#include +#include +#endif +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#ifndef _KERNEL +#include +#include +#include +#endif /* !_KERNEL */ + +#include "config.h" +#include "libpfkey.h" + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); +static void kdebug_sadb_x_sa2 __P((struct sadb_ext *)); +static void kdebug_sadb_x_policy __P((struct sadb_ext *ext)); +static void kdebug_sockaddr __P((struct sockaddr *addr)); + +#ifdef SADB_X_EXT_NAT_T_TYPE +static void kdebug_sadb_x_nat_t_type __P((struct sadb_ext *ext)); +static void kdebug_sadb_x_nat_t_port __P((struct sadb_ext *ext)); +#endif + +#ifdef _KERNEL +static void kdebug_secreplay __P((struct secreplay *)); +#endif + +#ifndef _KERNEL +#define panic(param) { printf(param); exit(1); } +#endif + +#include "libpfkey.h" +/* NOTE: host byte order */ + +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; +{ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u reserved=%u seq=%u pid=%u\n", + base->sadb_msg_len, base->sadb_msg_reserved, + base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (void *)((caddr_t)(void *)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + if (ext->sadb_ext_len > tlen) { + printf("kdebug_sadb: ext_len exceeds end of buffer.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + case SADB_X_EXT_SA2: + kdebug_sadb_x_sa2(ext); + break; +#ifdef SADB_X_EXT_NAT_T_TYPE + case SADB_X_EXT_NAT_T_TYPE: + kdebug_sadb_x_nat_t_type(ext); + break; + case SADB_X_EXT_NAT_T_SPORT: + case SADB_X_EXT_NAT_T_DPORT: + kdebug_sadb_x_nat_t_port(ext); + break; + case SADB_X_EXT_NAT_T_OA: + kdebug_sadb_address(ext); + break; +#endif + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (void *)((caddr_t)(void *)ext + extlen); + } + + return; +} + +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; +{ + struct sadb_prop *prop = (void *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (void *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; +{ + struct sadb_ident *id = (void *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + switch (id->sadb_ident_type) { + default: + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef _KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (void *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint((int)*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + break; + } + + printf(" }\n"); + + return; +} + +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; +{ + struct sadb_supported *sup = (void *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (void *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; +{ + struct sadb_lifetime *lft = (void *)ext; + + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); + + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); + + return; +} + +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; +{ + struct sadb_sa *sa = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); + + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); + + return; +} + +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; +{ + struct sadb_address *addr = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); + + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)(void *)&addr->sadb_address_reserved)[0], + ((u_char *)(void *)&addr->sadb_address_reserved)[1]); + + kdebug_sockaddr((void *)((caddr_t)(void *)ext + sizeof(*addr))); + + return; +} + +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; +{ + struct sadb_key *key = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if (((uint32_t)key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + (uint32_t)key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump(key + sizeof(struct sadb_key), + (int)((uint32_t)key->sadb_key_bits >> 3)); + printf(" }\n"); + return; +} + +static void +kdebug_sadb_x_sa2(ext) + struct sadb_ext *ext; +{ + struct sadb_x_sa2 *sa2 = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n"); + + printf("sadb_x_sa2{ mode=%u reqid=%u\n", + sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); + printf(" reserved1=%u reserved2=%u sequence=%u }\n", + sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved2, + sa2->sadb_x_sa2_sequence); + + return; +} + +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; +{ + struct sadb_x_policy *xpl = (void *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + printf("sadb_x_policy{ type=%u dir=%u id=%x priority=%u }\n", +#else + printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", +#endif + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, +#ifdef HAVE_PFKEY_POLICY_PRIORITY + xpl->sadb_x_policy_id, xpl->sadb_x_policy_priority); +#else + xpl->sadb_x_policy_id); +#endif + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (void *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level, + xisr->sadb_x_ipsecrequest_reqid); + + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + addr = (void *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (void *)((caddr_t)(void *)addr + + sysdep_sa_len(addr)); + kdebug_sockaddr(addr); + } + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len == 0) { + printf("kdebug_sadb_x_policy: wrong policy struct.\n"); + return; + } + /* prevent overflow */ + if (xisr->sadb_x_ipsecrequest_len > tlen) { + printf("invalid ipsec policy length\n"); + return; + } + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (void *)((caddr_t)(void *)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; +} + +#ifdef SADB_X_EXT_NAT_T_TYPE +static void +kdebug_sadb_x_nat_t_type(struct sadb_ext *ext) +{ + struct sadb_x_nat_t_type *ntt = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_nat_t_type: NULL pointer was passed.\n"); + + printf("sadb_x_nat_t_type{ type=%u }\n", ntt->sadb_x_nat_t_type_type); + + return; +} + +static void +kdebug_sadb_x_nat_t_port(struct sadb_ext *ext) +{ + struct sadb_x_nat_t_port *ntp = (void *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_nat_t_port: NULL pointer was passed.\n"); + + printf("sadb_x_nat_t_port{ port=%u }\n", ntohs(ntp->sadb_x_nat_t_port_port)); + + return; +} +#endif + +#ifdef _KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; +{ + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_GENERATE: + printf(" type=generate }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; +} + +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; +{ + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, + sysdep_sa_len((struct sockaddr *)&spidx->src)); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, + sysdep_sa_len((struct sockaddr *)&spidx->dst)); + printf("}\n"); + + return; +} + +void +kdebug_secasindex(saidx) + struct secasindex *saidx; +{ + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, + sysdep_sa_len((struct sockaddr *)&saidx->src)); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, + sysdep_sa_len((struct sockaddr *)&saidx->dst)); + printf("\n"); + + return; +} + +void +kdebug_secasv(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + +#if notyet + /* XXX: misc[123] ? */ +#endif + + return; +} + +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; +{ + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; +} + +void +kdebug_mbufhdr(m) + struct mbuf *m; +{ + /* sanity check */ + if (m == NULL) + return; + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + +#ifdef __FreeBSD__ + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } +#endif + + return; +} + +void +kdebug_mbuf(m0) + struct mbuf *m0; +{ + struct mbuf *m = m0; + int i, j; + + for (j = 0; m; m = m->m_next) { + kdebug_mbufhdr(m); + printf(" m_data:\n"); + for (i = 0; i < m->m_len; i++) { + if (i && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + printf("\n"); + } + + return; +} +#endif /* _KERNEL */ + +static void +kdebug_sockaddr(addr) + struct sockaddr *addr; +{ + struct sockaddr_in *sin4; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); + + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u", sysdep_sa_len(addr), addr->sa_family); + + switch (addr->sa_family) { + case AF_INET: + sin4 = (void *)addr; + printf(" port=%u\n", ntohs(sin4->sin_port)); + ipsec_hexdump(&sin4->sin_addr, sizeof(sin4->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + sin6 = (void *)addr; + printf(" port=%u\n", ntohs(sin6->sin6_port)); + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + sin6->sin6_flowinfo, sin6->sin6_scope_id); + ipsec_hexdump(&sin6->sin6_addr, sizeof(sin6->sin6_addr)); + break; +#endif + } + + printf(" }\n"); + + return; +} + +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; +} + + +void +ipsec_hexdump(buf, len) + const void *buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", ((const unsigned char *)buf)[i]); + } +#if 0 + if (i % 32 != 0) printf("\n"); +#endif + + return; +} diff --git a/ipsec-tools/Common/libpfkey.h b/ipsec-tools/Common/libpfkey.h new file mode 100644 index 0000000..628c835 --- /dev/null +++ b/ipsec-tools/Common/libpfkey.h @@ -0,0 +1,191 @@ +/* $Id: libpfkey.h,v 1.8.2.4 2005/12/04 20:41:47 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBPFKEY_H +#define _LIBPFKEY_H + +#ifndef KAME_LIBPFKEY_H +#define KAME_LIBPFKEY_H + +#include "config.h" + +#define PRIORITY_LOW 0xC0000000 +#define PRIORITY_DEFAULT 0x80000000 +#define PRIORITY_HIGH 0x40000000 + +#define PRIORITY_OFFSET_POSITIVE_MAX 0x3fffffff +#define PRIORITY_OFFSET_NEGATIVE_MAX 0x40000000 + +struct sadb_msg; +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_sadump_withports __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); +extern void pfkey_spdump_withports __P((struct sadb_msg *)); + +struct sockaddr; +struct sadb_alg; + +/* Accomodate different prototypes in */ +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#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 + +#ifndef IPPROTO_IPV4 +#define IPPROTO_IPV4 IPPROTO_IPIP +#endif + +#ifndef IPPROTO_IPCOMP +#define IPPROTO_IPCOMP IPPROTO_COMP +#endif + +static __inline u_int8_t +sysdep_sa_len (const struct sockaddr *sa) +{ +#ifdef __linux__ + switch (sa->sa_family) + { + case AF_INET: + return sizeof (struct sockaddr_in); + case AF_INET6: + return sizeof (struct sockaddr_in6); + } + // log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family); + return sizeof (struct sockaddr_in); +#else + return sa->sa_len; +#endif +} +#endif + +#endif /* KAME_LIBPFKEY_H */ + +#endif /* _LIBPFKEY_H */ diff --git a/ipsec-tools/Common/pfkey.c b/ipsec-tools/Common/pfkey.c new file mode 100644 index 0000000..0e566a4 --- /dev/null +++ b/ipsec-tools/Common/pfkey.c @@ -0,0 +1,2739 @@ +/* $KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); +#ifdef __APPLE__ +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, u_int16_t)); +#else +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, + u_int8_t, u_int16_t, u_int16_t, struct sockaddr *, u_int16_t)); +#endif +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +#ifdef __APPLE__ +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t, u_int16_t)); +#else +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +#endif +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +#ifdef SADB_X_EXT_NAT_T_TYPE +static caddr_t pfkey_set_natt_type __P((caddr_t, caddr_t, u_int, u_int8_t)); +static caddr_t pfkey_set_natt_port __P((caddr_t, caddr_t, u_int, u_int16_t)); +#endif +#ifdef SADB_X_EXT_NAT_T_FRAG +static caddr_t pfkey_set_natt_frag __P((caddr_t, caddr_t, u_int, u_int16_t)); +#endif + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, +#ifdef SADB_X_SATYPE_TCPSIGNATURE + NULL, +#endif +}; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +#ifdef SADB_X_SATYPE_TCPSIGNATURE + SADB_X_SATYPE_TCPSIGNATURE, +#endif +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap((int)satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (void *)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if (tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)(void *)p)->sadb_alg_id == alg_id) + return (void *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc((size_t)sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, (size_t)sup->sadb_supported_len); + + return 0; +} + +/* + * check key length against algorithm specified. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; +{ + u_int satype; + + /* validity check */ + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + return ipsec_check_keylen2(satype, alg_id, keylen); +} + +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + fprintf(stderr, "%d %d %d\n", keylen, alg->sadb_alg_minbits, + alg->sadb_alg_maxbits); + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; + + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + __ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return (u_int)~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + caddr_t ep; + int len; + int need_spirange = 0; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(dst)); + + if (min > 255 && max < (u_int)~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_GETSPI, + (u_int)len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* proccessing spi range */ + if (need_spirange) { + struct sadb_spirange spirange; + + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + + +#ifdef __APPLE__ +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, port) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; + u_int16_t port; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, port)) < 0) + return -1; + + return len; +} + + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, port) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; + u_int16_t port; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, port)) < 0) + return -1; + + return len; +} + + +#else /* __APPLE__ */ + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, 0, 0, 0, NULL, 0)) < 0) + return -1; + + return len; +} + +#ifdef SADB_X_EXT_NAT_T_TYPE +int +pfkey_send_update_nat(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, + l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa, + l_natt_frag) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; + u_int8_t l_natt_type; + u_int16_t l_natt_sport, l_natt_dport; + struct sockaddr *l_natt_oa; + u_int16_t l_natt_frag; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, l_natt_type, l_natt_sport, + l_natt_dport, l_natt_oa, l_natt_frag)) < 0) + return -1; + + return len; +} +#endif + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, 0, 0, 0, NULL, 0)) < 0) + return -1; + + return len; +} + +#ifdef SADB_X_EXT_NAT_T_TYPE +int +pfkey_send_add_nat(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, + l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa, + l_natt_frag) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; + u_int8_t l_natt_type; + u_int16_t l_natt_sport, l_natt_dport; + struct sockaddr *l_natt_oa; + u_int16_t l_natt_frag; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (u_int)l_bytes, (u_int)l_addtime, + (u_int)l_usetime, seq, l_natt_type, l_natt_sport, + l_natt_dport, l_natt_oa, l_natt_frag)) < 0) + return -1; + + return len; +} +#endif +#endif /* __APPLE__ */ + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +/*ARGSUSED*/ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(dst)); + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_DELETE, (u_int)len, + satype, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap((int)satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + int error = -1; + + /* receive message */ + for (;;) { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + if (newmsg->sadb_msg_type == SADB_REGISTER && + newmsg->sadb_msg_pid == pid) + break; + free(newmsg); + } + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (void *)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { + sup = (void *)p; + if (ep < p + sizeof(*sup) || + PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + + p += sup->sadb_supported_len; + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, + (u_int)(flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + (u_int64_t)0, (u_int64_t)0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + (u_int64_t)0, (u_int64_t)0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + (u_int64_t)0, (u_int64_t)0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + (u_int64_t)0, (u_int64_t)0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +#ifdef __APPLE__ +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, port) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; + u_int16_t port; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; +#ifdef SADB_X_AALG_TCP_MD5 + case SADB_X_SATYPE_TCPSIGNATURE: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_X_AALG_TCP_MD5) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + break; +#endif + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa_2) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(dst)) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags, port); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +#else /* __APPLE__ */ + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq, + l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa, + l_natt_frag) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst, *l_natt_oa; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; + u_int16_t l_natt_sport, l_natt_dport; + u_int8_t l_natt_type; + u_int16_t l_natt_frag; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; +#ifdef SADB_X_AALG_TCP_MD5 + case SADB_X_SATYPE_TCPSIGNATURE: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_X_AALG_TCP_MD5) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + break; +#endif + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(dst)) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + +#ifdef SADB_X_EXT_NAT_T_TYPE + /* add nat-t packets */ + if (l_natt_type) { + switch(satype) { + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + + len += sizeof(struct sadb_x_nat_t_type); + len += sizeof(struct sadb_x_nat_t_port); + len += sizeof(struct sadb_x_nat_t_port); + if (l_natt_oa) + len += sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(l_natt_oa)); +#ifdef SADB_X_EXT_NAT_T_FRAG + if (l_natt_frag) + len += sizeof(struct sadb_x_nat_t_frag); +#endif + } +#endif + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE && satype != SADB_X_SATYPE_IPCOMP) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + +#ifdef SADB_X_EXT_NAT_T_TYPE + /* Add nat-t messages */ + if (l_natt_type) { + p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE, l_natt_type); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT, + l_natt_sport); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT, + l_natt_dport); + if (!p) { + free(newmsg); + return -1; + } + + if (l_natt_oa) { + p = pfkey_setsadbaddr(p, ep, SADB_X_EXT_NAT_T_OA, + l_natt_oa, + (u_int)PFKEY_ALIGN8(sysdep_sa_len(l_natt_oa)), + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + } + + if (l_natt_frag) { +#ifdef SADB_X_EXT_NAT_T_FRAG + p = pfkey_set_natt_frag(p, ep, SADB_X_EXT_NAT_T_FRAG, + l_natt_frag); + if (!p) { + free(newmsg); + return -1; + } +#endif + } + } +#endif + + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} +#endif /* __APPLE__ */ + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +/*ARGSUSED*/ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(dst)); + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } +#ifdef __APPLE__ + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0, 0); +#else + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); +#endif + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + caddr_t ep; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: +#ifdef SADB_X_SATYPE_TCPSIGNATURE + case SADB_X_SATYPE_TCPSIGNATURE: +#endif + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > plen || prefd > plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sysdep_sa_len(src)) + + sizeof(struct sadb_lifetime) + + policylen; + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, (u_int)ltime, (u_int)vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } + memcpy(p, policy, (size_t)policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + caddr_t ep; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)(void *)newmsg) + len; + + p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + int bufsiz = 0; /* Max allowed by default */ + const unsigned long newbufk = 1536; + unsigned long oldmax; + size_t oldmaxsize = sizeof(oldmax); + unsigned long newmax = newbufk * (1024 + 128); + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + if (sysctlbyname("kern.ipc.maxsockbuf", &oldmax, &oldmaxsize, &newmax, sizeof(newmax)) != 0) + bufsiz = 233016; /* Max allowed by default */ + else + bufsiz = newbufk * 1024; + + setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + if (bufsiz == newbufk * 1024) + sysctlbyname("kern.ipc.maxsockbuf", NULL, NULL, &oldmax, oldmaxsize); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (void *)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (len < sizeof(buf)) { + recv(so, (void *)&buf, sizeof(buf), 0); + __ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC((size_t)reallen, struct sadb_msg *)) == 0) { + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (void *)newmsg, (socklen_t)reallen, 0)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (void *)msg, (socklen_t)len, 0)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: -1: invalid. + * 0: valid. + * + * XXX should be rewritten to obtain length explicitly + */ +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; +{ + struct sadb_ext *ext; + int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ + + /* validity check */ + if (msg == NULL || mhp == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (void *)msg; + + /* initialize */ + p = (void *) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (void *)p; + if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } + + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: +#ifdef SADB_X_EXT_NAT_T_TYPE + case SADB_X_EXT_NAT_T_TYPE: + case SADB_X_EXT_NAT_T_SPORT: + case SADB_X_EXT_NAT_T_DPORT: + case SADB_X_EXT_NAT_T_OA: +#endif +#ifdef SADB_X_EXT_TAG + case SADB_X_EXT_TAG: +#endif +#ifdef SADB_X_EXT_PACKET + case SADB_X_EXT_PACKET: +#endif + + mhp[ext->sadb_ext_type] = (void *)ext; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (void *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + __ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: +#ifdef SADB_X_NAT_T_NEW_MAPPING + case SADB_X_NAT_T_NEW_MAPPING: +#endif + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: +#ifdef SADB_X_SATYPE_TCPSIGNATURE + case SADB_X_SATYPE_TCPSIGNATURE: +#endif + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } +#ifdef SADB_X_NAT_T_NEW_MAPPING + if (msg->sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING && + msg->sadb_msg_satype != SADB_SATYPE_ESP) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } +#endif + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + + src0 = (void *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (void *)(mhp[SADB_EXT_ADDRESS_DST]); + + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; + return -1; + } + + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* + * prefixlen == 0 is valid because there must be the case + * all addresses are matched. + */ + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) + caddr_t buf; + caddr_t lim; + u_int type, satype; + u_int tlen; + u_int32_t seq; + pid_t pid; +{ + struct sadb_msg *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_msg); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_reserved = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +#ifdef __APPLE__ +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags, port) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; + u_int16_t port; +{ + struct sadb_sa_2 *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_sa_2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sa.sadb_sa_len = PFKEY_UNIT64(len); + p->sa.sadb_sa_exttype = SADB_EXT_SA; + p->sa.sadb_sa_spi = spi; + p->sa.sadb_sa_replay = wsize; + p->sa.sadb_sa_state = SADB_SASTATE_LARVAL; + p->sa.sadb_sa_auth = auth; + p->sa.sadb_sa_encrypt = enc; + p->sa.sadb_sa_flags = flags; + p->sadb_sa_natt_port = port; + + return(buf + len); +} +#else + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_sa); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + p->sadb_sa_natt_port = port; + + return(buf + len); +} +#endif + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + caddr_t lim; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(sysdep_sa_len(saddr)); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, (size_t)sysdep_sa_len(saddr)); + + return(buf + len); +} + +/* + * set sadb_key structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; + u_int type, keylen; +{ + struct sadb_key *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; + + memcpy(p + 1, key, keylen); + + return buf + len; +} + +/* + * set sadb_lifetime structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + caddr_t lim; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +{ + struct sadb_lifetime *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_lifetime); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; + + switch (type) { + case SADB_EXT_LIFETIME_SOFT: + p->sadb_lifetime_allocations + = (l_alloc * soft_lifetime_allocations_rate) /100; + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime + = (l_addtime * soft_lifetime_addtime_rate) /100; + p->sadb_lifetime_usetime + = (l_usetime * soft_lifetime_usetime_rate) /100; + break; + case SADB_EXT_LIFETIME_HARD: + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; + break; + } + + return buf + len; +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, lim, mode0, reqid) + caddr_t buf; + caddr_t lim; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_x_sa2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} + +#ifdef SADB_X_EXT_NAT_T_TYPE +static caddr_t +pfkey_set_natt_type(buf, lim, type, l_natt_type) + caddr_t buf; + caddr_t lim; + u_int type; + u_int8_t l_natt_type; +{ + struct sadb_x_nat_t_type *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_x_nat_t_type); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len); + p->sadb_x_nat_t_type_exttype = type; + p->sadb_x_nat_t_type_type = l_natt_type; + + return(buf + len); +} + +static caddr_t +pfkey_set_natt_port(buf, lim, type, l_natt_port) + caddr_t buf; + caddr_t lim; + u_int type; + u_int16_t l_natt_port; +{ + struct sadb_x_nat_t_port *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_x_nat_t_port); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len); + p->sadb_x_nat_t_port_exttype = type; + p->sadb_x_nat_t_port_port = htons(l_natt_port); + + return(buf + len); +} +#endif + +#ifdef SADB_X_EXT_NAT_T_FRAG +static caddr_t +pfkey_set_natt_frag(buf, lim, type, l_natt_frag) + caddr_t buf; + caddr_t lim; + u_int type; + u_int16_t l_natt_frag; +{ + struct sadb_x_nat_t_frag *p; + u_int len; + + p = (void *)buf; + len = sizeof(struct sadb_x_nat_t_frag); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_nat_t_frag_len = PFKEY_UNIT64(len); + p->sadb_x_nat_t_frag_exttype = type; + p->sadb_x_nat_t_frag_fraglen = l_natt_frag; + + return(buf + len); +} +#endif diff --git a/ipsec-tools/Common/pfkey_dump.c b/ipsec-tools/Common/pfkey_dump.c new file mode 100644 index 0000000..5c8cd26 --- /dev/null +++ b/ipsec-tools/Common/pfkey_dump.c @@ -0,0 +1,784 @@ +/* $KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +#define GETMSGSTR(str, num) \ +do { \ + /*CONSTCOND*/ \ + if (sizeof((str)[0]) == 0 \ + || num >= sizeof(str)/sizeof((str)[0])) \ + printf("%u ", (num)); \ + else if (strlen((str)[(num)]) == 0) \ + printf("%u ", (num)); \ + else \ + printf("%s ", (str)[(num)]); \ +} while (/*CONSTCOND*/0) + +#define GETMSGV2S(v2s, num) \ +do { \ + struct val2str *p; \ + for (p = (v2s); p && p->str; p++) { \ + if (p->val == (num)) \ + break; \ + } \ + if (p && p->str) \ + printf("%s ", p->str); \ + else \ + printf("%u ", (num)); \ +} while (/*CONSTCOND*/0) + +static char *str_ipaddr __P((struct sockaddr *)); +static char *str_ipport __P((struct sockaddr *)); +static char *str_prefport __P((u_int, u_int, u_int, u_int)); +static void str_upperspec __P((u_int, u_int, u_int)); +static char *str_time __P((time_t)); +static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); +static void pfkey_sadump1(struct sadb_msg *, int); +static void pfkey_spdump1(struct sadb_msg *, int); + +struct val2str { + int val; + const char *str; +}; + +/* + * Must to be re-written about following strings. + */ +static char *str_satype[] = { + "unspec", + "unknown", + "ah", + "esp", + "unknown", + "rsvp", + "ospfv2", + "ripv2", + "mip", + "ipcomp", + "policy", + "tcp", +}; + +static char *str_mode[] = { + "any", + "transport", + "tunnel", +}; + +static char *str_state[] = { + "larval", + "mature", + "dying", + "dead", +}; + +static struct val2str str_alg_auth[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_TCP_MD5 + { SADB_X_AALG_TCP_MD5, "tcp-md5", }, +#endif +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha512", }, +#endif +#ifdef SADB_X_AALG_RIPEMD160HMAC + { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", }, +#endif +#ifdef SADB_X_AALG_AES_XCBC_MAC + { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_enc[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_AESCBC + { SADB_X_EALG_AESCBC, "aes-cbc", }, +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, +#endif +#ifdef SADB_X_EALG_AESCTR + { SADB_X_EALG_AESCTR, "aes-ctr", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_comp[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL, }, +}; + +/* + * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). + */ + +void +pfkey_sadump(m) + struct sadb_msg *m; +{ + pfkey_sadump1(m, 0); +} + +void +pfkey_sadump_withports(m) + struct sadb_msg *m; +{ + pfkey_sadump1(m, 1); +} + +void +pfkey_sadump1(m, withports) + struct sadb_msg *m; + int withports; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *m_sa; + struct sadb_x_sa2 *m_sa2; + struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; + struct sadb_address *m_saddr, *m_daddr; +#ifdef notdef + struct sadb_address *m_paddr; +#endif + struct sadb_key *m_auth, *m_enc; +#ifdef notdef + struct sadb_ident *m_sid, *m_did; + struct sadb_sens *m_sens; +#endif +#ifdef SADB_X_EXT_NAT_T_TYPE + struct sadb_x_nat_t_type *natt_type; + struct sadb_x_nat_t_port *natt_sport, *natt_dport; + struct sadb_address *natt_oa; + + int use_natt = 0; +#endif + struct sockaddr *sa; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_sa = (void *)mhp[SADB_EXT_SA]; + m_sa2 = (void *)mhp[SADB_X_EXT_SA2]; + m_lftc = (void *)mhp[SADB_EXT_LIFETIME_CURRENT]; + m_lfth = (void *)mhp[SADB_EXT_LIFETIME_HARD]; + m_lfts = (void *)mhp[SADB_EXT_LIFETIME_SOFT]; + m_saddr = (void *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (void *)mhp[SADB_EXT_ADDRESS_DST]; +#ifdef notdef + m_paddr = (void *)mhp[SADB_EXT_ADDRESS_PROXY]; +#endif + m_auth = (void *)mhp[SADB_EXT_KEY_AUTH]; + m_enc = (void *)mhp[SADB_EXT_KEY_ENCRYPT]; +#ifdef notdef + m_sid = (void *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (void *)mhp[SADB_EXT_IDENTITY_DST]; + m_sens = (void *)mhp[SADB_EXT_SENSITIVITY]; +#endif +#ifdef SADB_X_EXT_NAT_T_TYPE + natt_type = (void *)mhp[SADB_X_EXT_NAT_T_TYPE]; + natt_sport = (void *)mhp[SADB_X_EXT_NAT_T_SPORT]; + natt_dport = (void *)mhp[SADB_X_EXT_NAT_T_DPORT]; + natt_oa = (void *)mhp[SADB_X_EXT_NAT_T_OA]; + + if (natt_type && natt_type->sadb_x_nat_t_type_type) + use_natt = 1; +#endif + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + sa = (void *)(m_saddr + 1); + if (withports) + printf("%s[%s]", str_ipaddr(sa), str_ipport(sa)); + else + printf("%s", str_ipaddr(sa)); +#ifdef SADB_X_EXT_NAT_T_TYPE + if (use_natt && natt_sport) + printf("[%u]", ntohs(natt_sport->sadb_x_nat_t_port_port)); +#endif + printf(" "); + + /* destination address */ + if (m_daddr == NULL) { + printf(" no ADDRESS_DST extension.\n"); + return; + } + sa = (void *)(m_daddr + 1); + if (withports) + printf("%s[%s]", str_ipaddr(sa), str_ipport(sa)); + else + printf("%s", str_ipaddr(sa)); +#ifdef SADB_X_EXT_NAT_T_TYPE + if (use_natt && natt_dport) + printf("[%u]", ntohs(natt_dport->sadb_x_nat_t_port_port)); +#endif + printf(" "); + + /* SA type */ + if (m_sa == NULL) { + printf("no SA extension.\n"); + return; + } + if (m_sa2 == NULL) { + printf("no SA2 extension.\n"); + return; + } + printf("\n\t"); + +#ifdef SADB_X_EXT_NAT_T_TYPE + if (use_natt && m->sadb_msg_satype == SADB_SATYPE_ESP) + printf("esp-udp "); + else if (use_natt) + printf("natt+"); + + if (!use_natt || m->sadb_msg_satype != SADB_SATYPE_ESP) +#endif + GETMSGSTR(str_satype, m->sadb_msg_satype); + + printf("mode="); + GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); + + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)m_sa2->sadb_x_sa2_reqid, + (u_int32_t)m_sa2->sadb_x_sa2_reqid); + +#ifdef SADB_X_EXT_NAT_T_TYPE + /* other NAT-T information */ + if (use_natt && natt_oa) + printf("\tNAT OA=%s\n", + str_ipaddr((void *)(natt_oa + 1))); +#endif + + /* encryption key */ + if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { + printf("\tC: "); + GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); + } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { + if (m_enc != NULL) { + printf("\tE: "); + GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); + ipsec_hexdump((caddr_t)(void *)m_enc + sizeof(*m_enc), + m_enc->sadb_key_bits / 8); + printf("\n"); + } + } + + /* authentication key */ + if (m_auth != NULL) { + printf("\tA: "); + GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); + ipsec_hexdump((caddr_t)(void *)m_auth + sizeof(*m_auth), + m_auth->sadb_key_bits / 8); + printf("\n"); + } + + /* replay windoe size & flags */ + printf("\tseq=0x%08x replay=%u flags=0x%08x ", + m_sa2->sadb_x_sa2_sequence, + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + + /* state */ + printf("state="); + GETMSGSTR(str_state, m_sa->sadb_sa_state); + printf("\n"); + + /* lifetime */ + if (m_lftc != NULL) { + time_t tmp_time = time(0); + + printf("\tcreated: %s", + str_time((long)m_lftc->sadb_lifetime_addtime)); + printf("\tcurrent: %s\n", str_time(tmp_time)); + printf("\tdiff: %lu(s)", + (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? + 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); + + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_addtime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_addtime)); + + printf("\tlast: %s", + str_time((long)m_lftc->sadb_lifetime_usetime)); + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_usetime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_usetime)); + + str_lifetime_byte(m_lftc, "current"); + str_lifetime_byte(m_lfth, "hard"); + str_lifetime_byte(m_lfts, "soft"); + printf("\n"); + + printf("\tallocated: %lu", + (unsigned long)m_lftc->sadb_lifetime_allocations); + printf("\thard: %lu", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_allocations)); + printf("\tsoft: %lu\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_allocations)); + } + + printf("\tsadb_seq=%lu pid=%lu ", + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* XXX DEBUG */ + printf("refcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +void +pfkey_spdump(m) + struct sadb_msg *m; +{ + pfkey_spdump1(m, 0); +} + +void +pfkey_spdump_withports(m) + struct sadb_msg *m; +{ + pfkey_spdump1(m, 1); +} + +static void +pfkey_spdump1(m, withports) + struct sadb_msg *m; + int withports; +{ + char pbuf[NI_MAXSERV]; + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_address *m_saddr, *m_daddr; +#ifdef SADB_X_EXT_TAG + struct sadb_x_tag *m_tag; +#endif + struct sadb_x_policy *m_xpl; + struct sadb_lifetime *m_lftc = NULL, *m_lfth = NULL; + struct sockaddr *sa; + u_int16_t sport = 0, dport = 0; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_saddr = (void *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (void *)mhp[SADB_EXT_ADDRESS_DST]; +#ifdef SADB_X_EXT_TAG + m_tag = (void *)mhp[SADB_X_EXT_TAG]; +#endif + m_xpl = (void *)mhp[SADB_X_EXT_POLICY]; + m_lftc = (void *)mhp[SADB_EXT_LIFETIME_CURRENT]; + m_lfth = (void *)mhp[SADB_EXT_LIFETIME_HARD]; + +#ifdef __linux__ + /* *bsd indicates per-socket policies by omiting src and dst + * extensions. Linux always includes them, but we can catch it + * by checkin for policy id. + */ + if (m_xpl->sadb_x_policy_id % 8 >= 3) { + printf("(per-socket policy) "); + } else +#endif + if (m_saddr && m_daddr) { + /* source address */ + sa = (void *)(m_saddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL, + 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) + sport = 0; /*XXX*/ + else + sport = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport((u_int)sa->sa_family, + (u_int)m_saddr->sadb_address_prefixlen, + (u_int)sport, + (u_int)m_saddr->sadb_address_proto)); + break; + default: + printf("unknown-af "); + break; + } + + /* destination address */ + sa = (void *)(m_daddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL, + 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) + dport = 0; /*XXX*/ + else + dport = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport((u_int)sa->sa_family, + (u_int)m_daddr->sadb_address_prefixlen, + (u_int)dport, + (u_int)m_saddr->sadb_address_proto)); + break; + default: + printf("unknown-af "); + break; + } + + /* upper layer protocol */ + if (m_saddr->sadb_address_proto != + m_daddr->sadb_address_proto) { + printf("upper layer protocol mismatched.\n"); + return; + } + str_upperspec((u_int)m_saddr->sadb_address_proto, (u_int)sport, + (u_int)dport); + } +#ifdef SADB_X_EXT_TAG + else if (m_tag) + printf("tagged \"%s\" ", m_tag->sadb_x_tag_name); +#endif + else + printf("(no selector, probably per-socket policy) "); + + /* policy */ + { + char *d_xpl; + + if (m_xpl == NULL) { + printf("no X_POLICY extension.\n"); + return; + } + if (withports) + d_xpl = ipsec_dump_policy_withports(m_xpl, "\n\t"); + else + d_xpl = ipsec_dump_policy((ipsec_policy_t)m_xpl, "\n\t"); + + if (!d_xpl) + printf("\n\tPolicy:[%s]\n", ipsec_strerror()); + else { + /* dump SPD */ + printf("\n\t%s\n", d_xpl); + free(d_xpl); + } + } + + /* lifetime */ + if (m_lftc) { + printf("\tcreated: %s ", + str_time((long)m_lftc->sadb_lifetime_addtime)); + printf("lastused: %s\n", + str_time((long)m_lftc->sadb_lifetime_usetime)); + } + if (m_lfth) { + printf("\tlifetime: %lu(s) ", + (u_long)m_lfth->sadb_lifetime_addtime); + printf("validtime: %lu(s)\n", + (u_long)m_lfth->sadb_lifetime_usetime); + } + + + printf("\tspid=%ld seq=%ld pid=%ld\n", + (u_long)m_xpl->sadb_x_policy_id, + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* XXX TEST */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +/* + * set "ipaddress" to buffer. + */ +static char * +str_ipaddr(sa) + struct sockaddr *sa; +{ + static char buf[NI_MAXHOST]; + const int niflag = NI_NUMERICHOST; + + if (sa == NULL) + return ""; + + if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), buf, sizeof(buf), + NULL, 0, niflag) == 0) + return buf; + return NULL; +} + +/* + * set "port" to buffer. + */ +static char * +str_ipport(sa) + struct sockaddr *sa; +{ + static char buf[NI_MAXHOST]; + const int niflag = NI_NUMERICSERV; + + if (sa == NULL) + return ""; + + if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), NULL, 0, + buf, sizeof(buf), niflag) == 0) + return buf; + return NULL; +} + + +/* + * set "/prefix[port number]" to buffer. + */ +static char * +str_prefport(family, pref, port, ulp) + u_int family, pref, port, ulp; +{ + static char buf[128]; + char prefbuf[128]; + char portbuf[128]; + int plen; + + switch (family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + return "?"; + } + + if (pref == plen) + prefbuf[0] = '\0'; + else + snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); + + if (ulp == IPPROTO_ICMPV6) + memset(portbuf, 0, sizeof(portbuf)); + else { + if (port == IPSEC_PORT_ANY) + snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + else + snprintf(portbuf, sizeof(portbuf), "[%u]", port); + } + + snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); + + return buf; +} + +static void +str_upperspec(ulp, p1, p2) + u_int ulp, p1, p2; +{ + if (ulp == IPSEC_ULPROTO_ANY) + printf("any"); + else if (ulp == IPPROTO_ICMPV6) { + printf("icmp6"); + if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY)) + printf(" %u,%u", p1, p2); + } else { + struct protoent *ent; + + switch (ulp) { + case IPPROTO_IPV4: + printf("ip4"); + break; + default: + ent = getprotobynumber((int)ulp); + if (ent) + printf("%s", ent->p_name); + else + printf("%u", ulp); + + endprotoent(); + break; + } + } +} + +/* + * set "Mon Day Time Year" to buffer + */ +static char * +str_time(t) + time_t t; +{ + static char buf[128]; + + if (t == 0) { + int i = 0; + for (;i < 20;) buf[i++] = ' '; + } else { + char *t0; + t0 = ctime(&t); + memcpy(buf, t0 + 4, 20); + } + + buf[20] = '\0'; + + return(buf); +} + +static void +str_lifetime_byte(x, str) + struct sadb_lifetime *x; + char *str; +{ + double y; + char *unit; + int w; + + if (x == NULL) { + printf("\t%s: 0(bytes)", str); + return; + } + +#if 0 + if ((x->sadb_lifetime_bytes) / 1024 / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; + unit = "M"; + w = 1; + } else if ((x->sadb_lifetime_bytes) / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024; + unit = "K"; + w = 1; + } else { + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; + } +#else + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; +#endif + printf("\t%s: %.*f(%sbytes)", str, w, y, unit); +} diff --git a/ipsec-tools/libipsec/ipsec_dump_policy.3 b/ipsec-tools/libipsec/ipsec_dump_policy.3 new file mode 100644 index 0000000..fe6f5ad --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_dump_policy.3 @@ -0,0 +1 @@ +.so man3/ipsec_set_policy.3 diff --git a/ipsec-tools/libipsec/ipsec_dump_policy.c b/ipsec-tools/libipsec/ipsec_dump_policy.c new file mode 100644 index 0000000..d69776b --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_dump_policy.c @@ -0,0 +1,419 @@ +/* $Id: ipsec_dump_policy.c,v 1.7.4.2 2005/06/29 13:01:27 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include + +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +static const char *ipsp_dir_strs[] = { + "any", "in", "out", "fwd" +}; + +static const char *ipsp_policy_strs[] = { + "discard", "none", "ipsec", "entrust", "bypass", "generate", +}; + +static char *ipsec_dump_ipsecrequest __P((char *, size_t, + struct sadb_x_ipsecrequest *, size_t, int)); +static char *ipsec_dump_policy1 __P((void *, const char *, int)); +static int set_addresses __P((char *, size_t, struct sockaddr *, + struct sockaddr *, int)); +static char *set_address __P((char *, size_t, struct sockaddr *, int)); + +/* + * policy is sadb_x_policy buffer. + * Must call free() later. + * When delimiter == NULL, alternatively ' '(space) is applied. + */ +char * +ipsec_dump_policy(policy, delimiter) + ipsec_policy_t policy; + __ipsec_const char *delimiter; +{ + return ipsec_dump_policy1(policy, delimiter, 0); +} + +char * +ipsec_dump_policy_withports(policy, delimiter) + void *policy; + const char *delimiter; +{ + return ipsec_dump_policy1(policy, delimiter, 1); +} + +static char * +ipsec_dump_policy1(policy, delimiter, withports) + void *policy; + const char *delimiter; + int withports; +{ + struct sadb_x_policy *xpl = policy; + struct sadb_x_ipsecrequest *xisr; + size_t off, buflen; + char *buf; + char isrbuf[1024]; + char *newbuf; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + int32_t priority_offset; + char *priority_str; + char operator; +#endif + + /* sanity check */ + if (policy == NULL) + return NULL; + if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return NULL; + } + + /* set delimiter */ + if (delimiter == NULL) + delimiter = " "; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + if (xpl->sadb_x_policy_priority == 0) + { + priority_offset = 0; + priority_str = ""; + } + /* find which constant the priority is closest to */ + else if (xpl->sadb_x_policy_priority < + (u_int32_t) (PRIORITY_DEFAULT / 4) * 3) + { + priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH; + priority_str = "prio high"; + } + else if (xpl->sadb_x_policy_priority >= + (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 && + xpl->sadb_x_policy_priority < + (u_int32_t) (PRIORITY_DEFAULT / 4) * 5) + { + priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT; + priority_str = "prio def"; + } + else + { + priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW; + priority_str = "prio low"; + } + + /* fix sign to match the way it is input */ + priority_offset *= -1; + if (priority_offset < 0) + { + operator = '-'; + priority_offset *= -1; + } + else + { + operator = '+'; + } +#endif + + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_ANY: + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: +#ifdef HAVE_POLICY_FWD + case IPSEC_DIR_FWD: +#endif + break; + default: + __ipsec_errcode = EIPSEC_INVAL_DIR; + return NULL; + } + + switch (xpl->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_GENERATE: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_IPSEC: + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_ENTRUST: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_POLICY; + return NULL; + } + + buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) + + 1 /* space */ +#ifdef HAVE_PFKEY_POLICY_PRIORITY + + strlen(priority_str) + + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */ + + ((strlen(priority_str) != 0) ? 1 : 0) /* space */ +#endif + + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) + + 1; /* NUL */ + + if ((buf = malloc(buflen)) == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return NULL; + } +#ifdef HAVE_PFKEY_POLICY_PRIORITY + if (priority_offset != 0) + { + snprintf(buf, buflen, "%s %s %c %u %s", + ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, + priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]); + } + else if (strlen (priority_str) != 0) + { + snprintf(buf, buflen, "%s %s %s", + ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, + ipsp_policy_strs[xpl->sadb_x_policy_type]); + } + else + { + snprintf(buf, buflen, "%s %s", + ipsp_dir_strs[xpl->sadb_x_policy_dir], + ipsp_policy_strs[xpl->sadb_x_policy_type]); + } +#else + snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], + ipsp_policy_strs[xpl->sadb_x_policy_type]); +#endif + + if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + __ipsec_errcode = EIPSEC_NO_ERROR; + return buf; + } + + /* count length of buffer for use */ + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + xisr = (void *)((caddr_t)(void *)xpl + off); + off += xisr->sadb_x_ipsecrequest_len; + } + + /* validity check */ + if (off != PFKEY_EXTLEN(xpl)) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + free(buf); + return NULL; + } + + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + int offset; + xisr = (void *)((caddr_t)(void *)xpl + off); + + if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, + PFKEY_EXTLEN(xpl) - off, withports) == NULL) { + free(buf); + return NULL; + } + + offset = strlen(buf); + buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1; + newbuf = (char *)realloc(buf, buflen); + if (newbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + free(buf); + return NULL; + } + buf = newbuf; + snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf); + + off += xisr->sadb_x_ipsecrequest_len; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return buf; +} + +static char * +ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports) + char *buf; + size_t len; + struct sadb_x_ipsecrequest *xisr; + size_t bound; /* boundary */ + int withports; +{ + const char *proto, *mode, *level; + char abuf[NI_MAXHOST * 2 + 2]; + + if (xisr->sadb_x_ipsecrequest_len > bound) { + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + proto = "esp"; + break; + case IPPROTO_AH: + proto = "ah"; + break; + case IPPROTO_IPCOMP: + proto = "ipcomp"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_ANY: + mode = "any"; + break; + case IPSEC_MODE_TRANSPORT: + mode = "transport"; + break; + case IPSEC_MODE_TUNNEL: + mode = "tunnel"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_MODE; + return NULL; + } + + abuf[0] = '\0'; + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *sa1, *sa2; + caddr_t p; + + p = (void *)(xisr + 1); + sa1 = (void *)p; + sa2 = (void *)(p + sysdep_sa_len(sa1)); + if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) != + xisr->sadb_x_ipsecrequest_len) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return NULL; + } + if (set_addresses(abuf, sizeof(abuf), + sa1, sa2, withports) != 0) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return NULL; + } + } + + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + level = "default"; + break; + case IPSEC_LEVEL_USE: + level = "use"; + break; + case IPSEC_LEVEL_REQUIRE: + level = "require"; + break; + case IPSEC_LEVEL_UNIQUE: + level = "unique"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_LEVEL; + return NULL; + } + + if (xisr->sadb_x_ipsecrequest_reqid == 0) + snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); + else { + int ch; + + if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) + ch = '#'; + else + ch = ':'; + snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level, + ch, xisr->sadb_x_ipsecrequest_reqid); + } + + return buf; +} + +static int +set_addresses(buf, len, sa1, sa2, withports) + char *buf; + size_t len; + struct sockaddr *sa1; + struct sockaddr *sa2; + int withports; +{ + char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; + + if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL || + set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL) + return -1; + if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) + return -1; + snprintf(buf, len, "%s-%s", tmp1, tmp2); + return 0; +} + +static char * +set_address(buf, len, sa, withports) + char *buf; + size_t len; + struct sockaddr *sa; + int withports; +{ + const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + + if (len < 1) + return NULL; + buf[0] = '\0'; + if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host), + serv, sizeof(serv), niflags) != 0) + return NULL; + + if (withports) + snprintf(buf, len, "%s[%s]", host, serv); + else + snprintf(buf, len, "%s", host); + + return buf; +} diff --git a/ipsec-tools/libipsec/ipsec_get_policylen.3 b/ipsec-tools/libipsec/ipsec_get_policylen.3 new file mode 100644 index 0000000..fe6f5ad --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_get_policylen.3 @@ -0,0 +1 @@ +.so man3/ipsec_set_policy.3 diff --git a/ipsec-tools/libipsec/ipsec_get_policylen.c b/ipsec-tools/libipsec/ipsec_get_policylen.c new file mode 100644 index 0000000..1dca6d2 --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_get_policylen.c @@ -0,0 +1,60 @@ +/* $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#ifdef __APPPLE__ +#include +#else +#include +#endif + +#include "libpfkey.h" +#include "ipsec_strerror.h" + +int +ipsec_get_policylen(policy) + ipsec_policy_t policy; +{ + return policy ? PFKEY_EXTLEN(policy) : -1; +} diff --git a/ipsec-tools/libipsec/ipsec_set_policy.3 b/ipsec-tools/libipsec/ipsec_set_policy.3 new file mode 100644 index 0000000..6b278f9 --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_set_policy.3 @@ -0,0 +1,334 @@ +.\" $KAME: ipsec_set_policy.3,v 1.16 2003/01/06 21:59:03 sumikawa Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 5, 1998 +.Dt IPSEC_SET_POLICY 3 +.Os +.Sh NAME +.Nm ipsec_dump_policy , +.Nm ipsec_get_policylen , +.Nm ipsec_set_policy +.Nd manipulate IPsec policy specification structure from human-readable policy string +.\" +.Sh LIBRARY +.Lb libipsec +.Sh SYNOPSIS +.In netinet6/ipsec.h +.Ft "char *" +.Fo ipsec_dump_policy +.Fa "caddr_t buf" +.Fa "char *delim" +.Fc +.Ft int +.Fo ipsec_get_policylen +.Fa "caddr_t buf" +.Fc +.Ft "char *" +.Fo ipsec_set_policy +.Fa "char *policy" +.Fa "int len" +.Fc +.Sh DESCRIPTION +.Fn ipsec_set_policy +generates an IPsec policy specification structure, namely +.Li struct sadb_x_policy +and/or +.Li struct sadb_x_ipsecrequest +from a human-readable policy specification. +The policy specification must be given as a C string +.Fa policy +and its length +.Fa len . +.Fn ipsec_set_policy +will return a buffer with the corresponding IPsec policy specification structure. +The buffer is dynamically allocated, and must be +.Xr free 3 Ap d +by the caller. +.Pp +You can get the length of the generated buffer with +.Fn ipsec_get_policylen +(i.e. for calling +.Xr setsockopt 2 ) . +.Pp +.Fn ipsec_dump_policy +converts an IPsec policy structure into human-readable form. +Therefore, +.Fn ipsec_dump_policy +can be regarded as the inverse function to +.Fn ipsec_set_policy . +.Fa buf +points to an IPsec policy structure, +.Li struct sadb_x_policy . +.Fa delim +is a delimiter string, which is usually a blank character. +If you set +.Fa delim +to +.Dv NULL , +a single whitespace is assumed. +.Fn ipsec_dump_policy +returns a pointer to a dynamically allocated string. +It is the caller's responsibility to +.Xr free 3 +it. +.Pp +.Fa policy +is formatted as either of the following: +.Bl -tag -width "discard" +.It Ar direction [priority specification] Li discard +.Ar direction +must be +.Li in , +.Li out , +or +.Li fwd . +.Ar direction +specifies in which direction the policy needs to be applied. +The non-standard direction +.Li fwd +is substituted with +.Li in +on platforms which do not support forward policies. +.Pp +.Ar priority specification +is used to control the placement of the policy within the SPD. +The policy position is determined by +a signed integer where higher priorities indicate the policy is placed +closer to the beginning of the list and lower priorities indicate the +policy is placed closer to the end of the list. +Policies with equal +priorities are added at the end of the group of such policies. +.Pp +Priority can only +be specified when libipsec has been compiled against kernel headers that +support policy priorities (Linux \*[Gt]= 2.6.6). +It takes one of the following formats: +.Bl -tag -width "discard" +.It Xo +.Ar {priority,prio} offset +.Xc +.Ar offset +is an integer in the range -2147483647..214783648. +.It Xo +.Ar {priority,prio} base {+,-} offset +.Xc +.Ar base +is either +.Li low (-1073741824) , +.Li def (0) , +or +.Li high (1073741824) . +.Pp +.Ar offset +is an unsigned integer. +It can be up to 1073741824 for +positive offsets, and up to 1073741823 for negative offsets. +.El +.Pp +The interpretation of policy priority in these functions and the +kernel DOES differ. +The relationship between the two can be described as +p(kernel) = 0x80000000 - p(func) +.Pp +With +.Li discard +policy, packets will be dropped if they match the policy. +.It Ar direction [priority specification] Li entrust +.Li entrust +means to consult the SPD defined by +.Xr setkey 8 . +.It Ar direction [priority specification] Li bypass +.Li bypass +means to bypass the IPsec processing. +.Pq the packet will be transmitted in clear . +This is for privileged sockets. +.It Xo +.Ar direction +.Bq Ar priority specification +.Li ipsec +.Ar request ... +.Xc +.Li ipsec +means that the matching packets are subject to IPsec processing. +.Li ipsec +can be followed by one or more +.Ar request +strings, which are formatted as below: +.Bl -tag -width "discard" +.It Xo +.Ar protocol +.Li / +.Ar mode +.Li / +.Ar src +.Li - +.Ar dst +.Op Ar /level +.Xc +.Ar protocol +is either +.Li ah , +.Li esp , +or +.Li ipcomp . +.Pp +.Ar mode +is either +.Li transport +or +.Li tunnel . +.Pp +.Ar src +and +.Ar dst +specifies the IPsec endpoint. +.Ar src +always means the +.Dq sending node +and +.Ar dst +always means the +.Dq receiving node . +Therefore, when +.Ar direction +is +.Li in , +.Ar dst +is this node +and +.Ar src +is the other node +.Pq peer . +If +.Ar mode +is +.Li transport , +Both +.Ar src +and +.Ar dst +can be omitted. +.Pp +.Ar level +must be set to one of the following: +.Li default , use , require , +or +.Li unique . +.Li default +means that the kernel should consult the system default policy +defined by +.Xr sysctl 8 , +such as +.Li net.inet.ipsec.esp_trans_deflev . +See +.Xr ipsec 4 +regarding the system default. +.Li use +means that a relevant SA can be used when available, +since the kernel may perform IPsec operation against packets when possible. +In this case, packets can be transmitted in clear +.Pq when SA is not available , +or encrypted +.Pq when SA is available . +.Li require +means that a relevant SA is required, +since the kernel must perform IPsec operation against packets. +.Li unique +is the same as +.Li require , +but adds the restriction that the SA for outbound traffic is used +only for this policy. +You may need the identifier in order to relate the policy and the SA +when you define the SA by manual keying. +You can put the decimal number as the identifier after +.Li unique +like +.Li unique : number . +.Li number +must be between 1 and 32767 . +If the +.Ar request +string is kept unambiguous, +.Ar level +and slash prior to +.Ar level +can be omitted. +However, it is encouraged to specify them explicitly +to avoid unintended behavior. +If +.Ar level +is omitted, it will be interpreted as +.Li default . +.El +.Pp +Note that there are slight differences to the specification of +.Xr setkey 8 . +In the specification of +.Xr setkey 8 , +both +.Li entrust +and +.Li bypass +are not used. +Refer to +.Xr setkey 8 +for details. +.Pp +Here are several examples +.Pq long lines are wrapped for readability : +.Bd -literal -offset indent +in discard +out ipsec esp/transport//require +in ipsec ah/transport//require +out ipsec esp/tunnel/10.1.1.2-10.1.1.1/use +in ipsec ipcomp/transport//use + esp/transport//use +.Ed +.El +.Sh RETURN VALUES +.Fn ipsec_set_policy +returns a pointer to the allocated buffer with the policy specification +if successful; otherwise a +.Dv NULL +pointer is returned. +.Fn ipsec_get_policylen +returns a positive value +.Pq meaning the buffer size +on success, and a negative value on errors. +.Fn ipsec_dump_policy +returns a pointer to a dynamically allocated region on success, +and +.Dv NULL +on errors. +.Sh SEE ALSO +.Xr ipsec_strerror 3 , +.Xr ipsec 4 , +.Xr setkey 8 +.Sh HISTORY +The functions first appeared in the WIDE/KAME IPv6 protocol stack kit. diff --git a/ipsec-tools/libipsec/ipsec_strerror.3 b/ipsec-tools/libipsec/ipsec_strerror.3 new file mode 100644 index 0000000..718eb50 --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_strerror.3 @@ -0,0 +1,88 @@ +.\" $KAME: ipsec_strerror.3,v 1.9 2001/08/17 07:21:36 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 6, 1998 +.Dt IPSEC_STRERROR 3 +.Os +.\" +.Sh NAME +.Nm ipsec_strerror +.Nd error messages for the IPsec policy manipulation library +.\" +.Sh LIBRARY +.Lb libipsec +.Sh SYNOPSIS +.In netinet6/ipsec.h +.Ft "const char *" +.Fo ipsec_strerror +.Fa void +.Fc +.\" +.Sh DESCRIPTION +.Pa netinet6/ipsec.h +declares +.Pp +.Dl extern int ipsec_errcode ; +.Pp +which is used to pass an error code from the IPsec policy manipulation +library to a program. +.Fn ipsec_strerror +can be used to obtain the error message string for the error code. +.Pp +The array pointed to is not to be modified by the calling program. +Since +.Fn ipsec_strerror +uses +.Xr strerror 3 +as underlying function, calling +.Xr strerror 3 +after +.Fn ipsec_strerror +will make the return value from +.Fn ipsec_strerror +invalid or overwritten. +.\" +.Sh RETURN VALUES +.Fn ipsec_strerror +always returns a pointer to a C string. +The C string must not be overwritten by the calling program. +.\" +.Sh SEE ALSO +.Xr ipsec_set_policy 3 +.\" +.Sh HISTORY +.Fn ipsec_strerror +first appeared in the WIDE/KAME IPv6 protocol stack kit. +.\" +.Sh BUGS +.Fn ipsec_strerror +will return its result which may be overwritten by subsequent calls. +.Pp +.Va ipsec_errcode +is not thread safe. diff --git a/ipsec-tools/libipsec/ipsec_strerror.c b/ipsec-tools/libipsec/ipsec_strerror.c new file mode 100644 index 0000000..e9fda58 --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_strerror.c @@ -0,0 +1,98 @@ +/* $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include "ipsec_strerror.h" + +int __ipsec_errcode; + +static const char *ipsec_errlist[] = { +"Success", /*EIPSEC_NO_ERROR*/ +"Not supported", /*EIPSEC_NOT_SUPPORTED*/ +"Invalid argument", /*EIPSEC_INVAL_ARGUMENT*/ +"Invalid sadb message", /*EIPSEC_INVAL_SADBMSG*/ +"Invalid version", /*EIPSEC_INVAL_VERSION*/ +"Invalid security policy", /*EIPSEC_INVAL_POLICY*/ +"Invalid address specification", /*EIPSEC_INVAL_ADDRESS*/ +"Invalid ipsec protocol", /*EIPSEC_INVAL_PROTO*/ +"Invalid ipsec mode", /*EIPSEC_INVAL_MODE*/ +"Invalid ipsec level", /*EIPSEC_INVAL_LEVEL*/ +"Invalid SA type", /*EIPSEC_INVAL_SATYPE*/ +"Invalid message type", /*EIPSEC_INVAL_MSGTYPE*/ +"Invalid extension type", /*EIPSEC_INVAL_EXTTYPE*/ +"Invalid algorithm type", /*EIPSEC_INVAL_ALGS*/ +"Invalid key length", /*EIPSEC_INVAL_KEYLEN*/ +"Invalid address family", /*EIPSEC_INVAL_FAMILY*/ +"Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/ +"Invalid direciton", /*EIPSEC_INVAL_DIR*/ +"SPI range violation", /*EIPSEC_INVAL_SPI*/ +"No protocol specified", /*EIPSEC_NO_PROTO*/ +"No algorithm specified", /*EIPSEC_NO_ALGS*/ +"No buffers available", /*EIPSEC_NO_BUFS*/ +"Must get supported algorithms list first", /*EIPSEC_DO_GET_SUPP_LIST*/ +"Protocol mismatch", /*EIPSEC_PROTO_MISMATCH*/ +"Family mismatch", /*EIPSEC_FAMILY_MISMATCH*/ +"Too few arguments", /*EIPSEC_FEW_ARGUMENTS*/ +NULL, /*EIPSEC_SYSTEM_ERROR*/ +"Priority offset not in valid range [-2147483647, 2147483648]", /*EIPSEC_INVAL_PRIORITY_OFFSET*/ +"Priority offset from base not in valid range [0, 1073741823] for negative offsets and [0, 1073741824] for positive offsets", /* EIPSEC_INVAL_PRIORITY_OFFSET */ +"Policy priority not compiled in", /*EIPSEC_PRIORITY_NOT_COMPILED*/ +"Unknown error", /*EIPSEC_MAX*/ +}; + +const char *ipsec_strerror(void) +{ + if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX) + __ipsec_errcode = EIPSEC_MAX; + + return ipsec_errlist[__ipsec_errcode]; +} + +void __ipsec_set_strerror(const char *str) +{ + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str; + + return; +} diff --git a/ipsec-tools/libipsec/ipsec_strerror.h b/ipsec-tools/libipsec/ipsec_strerror.h new file mode 100644 index 0000000..7c8c6dd --- /dev/null +++ b/ipsec-tools/libipsec/ipsec_strerror.h @@ -0,0 +1,71 @@ +/* $Id: ipsec_strerror.h,v 1.4 2004/06/07 09:18:46 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _IPSEC_STRERROR_H +#define _IPSEC_STRERROR_H + +extern int __ipsec_errcode; +extern void __ipsec_set_strerror __P((const char *)); + +#define EIPSEC_NO_ERROR 0 /*success*/ +#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ +#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ +#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ +#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ +#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_INVAL_PRIORITY_OFFSET 27 /*priority offset out of range*/ +#define EIPSEC_INVAL_PRIORITY_BASE_OFFSET 28 /* priority base offset too + large */ +#define EIPSEC_PRIORITY_NOT_COMPILED 29 /*no priority support in libipsec*/ +#define EIPSEC_MAX 30 /*unknown error*/ + +#endif /* _IPSEC_STRERROR_H */ diff --git a/ipsec-tools/libipsec/policy_parse.y b/ipsec-tools/libipsec/policy_parse.y new file mode 100644 index 0000000..51fb115 --- /dev/null +++ b/ipsec-tools/libipsec/policy_parse.y @@ -0,0 +1,653 @@ +/* $KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * IN/OUT bound policy configuration take place such below: + * in + * out + * + * is one of the following: + * priority 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} {+,-} where low and high are + * constants which are closer + * to the end of the list and + * beginning of the list, + * respectively + * + * is one of following: + * "discard", "none", "ipsec ", "entrust", "bypass", + * + * The following requests are accepted as : + * + * 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 +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include + +#include + +#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 PRIO_BASE +%token PRIO_OFFSET +%token ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY IPADDRESS PORT +%token ME ANY +%token SLASH HYPHEN +%type DIR PRIORITY ACTION PROTOCOL MODE LEVEL +%type IPADDRESS LEVEL_SPECIFY PORT + +%% +policy_spec + : DIR ACTION + { + p_dir = $1; + p_type = $2; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + p_priority = PRIORITY_DEFAULT; +#else + p_priority = 0; +#endif + + if (init_x_policy()) + return -1; + } + rules + | DIR PRIORITY PRIO_OFFSET ACTION + { + char *offset_buf; + + p_dir = $1; + p_type = $4; + + /* buffer big enough to hold a prepended negative sign */ + offset_buf = malloc($3.len + 2); + if (offset_buf == NULL) + { + __ipsec_errcode = EIPSEC_NO_BUFS; + return -1; + } + + /* positive input value means higher priority, therefore lower + actual value so that is closer to the beginning of the list */ + snprintf (offset_buf, $3.len + 2, "-%s", $3.buf); + + errno = 0; + p_priority_offset = atol(offset_buf); + + free(offset_buf); + + if (errno != 0 || p_priority_offset < INT32_MIN) + { + __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET; + return -1; + } + + p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset; + + if (init_x_policy()) + return -1; + } + rules + | DIR PRIORITY HYPHEN PRIO_OFFSET ACTION + { + p_dir = $1; + p_type = $5; + + errno = 0; + p_priority_offset = atol($4.buf); + + if (errno != 0 || p_priority_offset > INT32_MAX) + { + __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET; + return -1; + } + + /* negative input value means lower priority, therefore higher + actual value so that is closer to the end of the list */ + p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset; + + if (init_x_policy()) + return -1; + } + rules + | DIR PRIORITY PRIO_BASE ACTION + { + p_dir = $1; + p_type = $4; + + p_priority = $3; + + if (init_x_policy()) + return -1; + } + rules + | DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION + { + p_dir = $1; + p_type = $6; + + errno = 0; + p_priority_offset = atol($5.buf); + + if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX) + { + __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET; + return -1; + } + + /* adding value means higher priority, therefore lower + actual value so that is closer to the beginning of the list */ + p_priority = $3 - (u_int32_t) p_priority_offset; + + if (init_x_policy()) + return -1; + } + rules + | DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION + { + p_dir = $1; + p_type = $6; + + errno = 0; + p_priority_offset = atol($5.buf); + + if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX) + { + __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET; + return -1; + } + + /* subtracting value means lower priority, therefore higher + actual value so that is closer to the end of the list */ + p_priority = $3 + (u_int32_t) p_priority_offset; + + if (init_x_policy()) + return -1; + } + rules + | DIR + { + p_dir = $1; + p_type = 0; /* ignored it by kernel */ + + p_priority = 0; + + if (init_x_policy()) + return -1; + } + ; + +rules + : /*NOTHING*/ + | rules rule { + if (rule_check() < 0) + return -1; + + if (set_x_request(p_src, p_dst) < 0) + return -1; + + policy_parse_request_init(); + } + ; + +rule + : protocol SLASH mode SLASH addresses SLASH level + | protocol SLASH mode SLASH addresses SLASH + | protocol SLASH mode SLASH addresses + | protocol SLASH mode SLASH + | protocol SLASH mode SLASH SLASH level + | protocol SLASH mode + | protocol SLASH { + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + return -1; + } + | protocol { + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + return -1; + } + ; + +protocol + : PROTOCOL { p_protocol = $1; } + ; + +mode + : MODE { p_mode = $1; } + ; + +level + : LEVEL { + p_level = $1; + p_reqid = 0; + } + | LEVEL_SPECIFY { + p_level = IPSEC_LEVEL_UNIQUE; + p_reqid = atol($1.buf); /* atol() is good. */ + } + ; + +addresses + : IPADDRESS { + p_src = parse_sockaddr(&$1, NULL); + if (p_src == NULL) + return -1; + } + HYPHEN + IPADDRESS { + p_dst = parse_sockaddr(&$4, NULL); + if (p_dst == NULL) + return -1; + } + | IPADDRESS PORT { + p_src = parse_sockaddr(&$1, &$2); + if (p_src == NULL) + return -1; + } + HYPHEN + IPADDRESS PORT { + p_dst = parse_sockaddr(&$5, &$6); + if (p_dst == NULL) + return -1; + } + | ME HYPHEN ANY { + if (p_dir != IPSEC_DIR_OUTBOUND) { + __ipsec_errcode = EIPSEC_INVAL_DIR; + return -1; + } + } + | ANY HYPHEN ME { + if (p_dir != IPSEC_DIR_INBOUND) { + __ipsec_errcode = EIPSEC_INVAL_DIR; + return -1; + } + } + /* + | ME HYPHEN ME + */ + ; + +%% + +void +yyerror(msg) + char *msg; +{ + fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", + msg, __libipsectext); + + return; +} + +static struct sockaddr * +parse_sockaddr(addrbuf, portbuf) + struct _val *addrbuf; + struct _val *portbuf; +{ + struct addrinfo hints, *res; + char *addr; + char *serv = NULL; + int error; + struct sockaddr *newaddr = NULL; + + if ((addr = malloc(addrbuf->len + 1)) == NULL) { + yyerror("malloc failed"); + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (portbuf && ((serv = malloc(portbuf->len + 1)) == NULL)) { + free(addr); + yyerror("malloc failed"); + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + strncpy(addr, addrbuf->buf, addrbuf->len); + addr[addrbuf->len] = '\0'; + + if (portbuf) { + strncpy(serv, portbuf->buf, portbuf->len); + serv[portbuf->len] = '\0'; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(addr, serv, &hints, &res); + free(addr); + if (serv != NULL) + free(serv); + if (error != 0) { + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); + return NULL; + } + + if (res->ai_addr == NULL) { + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); + return NULL; + } + + newaddr = malloc(res->ai_addrlen); + if (newaddr == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + freeaddrinfo(res); + return NULL; + } + memcpy(newaddr, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newaddr; +} + +static int +rule_check() +{ + if (p_type == IPSEC_POLICY_IPSEC) { + if (p_protocol == IPPROTO_IP) { + __ipsec_errcode = EIPSEC_NO_PROTO; + return -1; + } + + if (p_mode != IPSEC_MODE_TRANSPORT + && p_mode != IPSEC_MODE_TUNNEL) { + __ipsec_errcode = EIPSEC_INVAL_MODE; + return -1; + } + + if (p_src == NULL && p_dst == NULL) { + if (p_mode != IPSEC_MODE_TRANSPORT) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return -1; + } + } + else if (p_src->sa_family != p_dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +init_x_policy() +{ + struct sadb_x_policy *p; + + if (pbuf) { + free(pbuf); + tlen = 0; + } + pbuf = malloc(sizeof(struct sadb_x_policy)); + if (pbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return -1; + } + tlen = sizeof(struct sadb_x_policy); + + memset(pbuf, 0, tlen); + p = (struct sadb_x_policy *)pbuf; + p->sadb_x_policy_len = 0; /* must update later */ + p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + p->sadb_x_policy_type = p_type; + p->sadb_x_policy_dir = p_dir; + p->sadb_x_policy_id = 0; +#ifdef HAVE_PFKEY_POLICY_PRIORITY + p->sadb_x_policy_priority = p_priority; +#else + /* fail if given a priority and libipsec was not compiled with + priority support */ + if (p_priority != 0) + { + __ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED; + return -1; + } +#endif + + offset = tlen; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +set_x_request(src, dst) + struct sockaddr *src, *dst; +{ + struct sadb_x_ipsecrequest *p; + int reqlen; + u_int8_t *n; + + reqlen = sizeof(*p) + + (src ? sysdep_sa_len(src) : 0) + + (dst ? sysdep_sa_len(dst) : 0); + tlen += reqlen; /* increment to total length */ + + n = realloc(pbuf, tlen); + if (n == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return -1; + } + pbuf = n; + + p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; + p->sadb_x_ipsecrequest_len = reqlen; + p->sadb_x_ipsecrequest_proto = p_protocol; + p->sadb_x_ipsecrequest_mode = p_mode; + p->sadb_x_ipsecrequest_level = p_level; + p->sadb_x_ipsecrequest_reqid = p_reqid; + offset += sizeof(*p); + + if (set_sockaddr(src) || set_sockaddr(dst)) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +set_sockaddr(addr) + struct sockaddr *addr; +{ + if (addr == NULL) { + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; + } + + /* tlen has already incremented */ + + memcpy(&pbuf[offset], addr, sysdep_sa_len(addr)); + + offset += sysdep_sa_len(addr); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static void +policy_parse_request_init() +{ + p_protocol = IPPROTO_IP; + p_mode = IPSEC_MODE_ANY; + p_level = IPSEC_LEVEL_DEFAULT; + p_reqid = 0; + if (p_src != NULL) { + free(p_src); + p_src = NULL; + } + if (p_dst != NULL) { + free(p_dst); + p_dst = NULL; + } + + return; +} + +static void * +policy_parse(msg, msglen) + const char *msg; + int msglen; +{ + int error; + + pbuf = NULL; + tlen = 0; + + /* initialize */ + p_dir = IPSEC_DIR_INVALID; + p_type = IPSEC_POLICY_DISCARD; + policy_parse_request_init(); + __policy__strbuffer__init__(msg); + + error = yyparse(); /* it must be set errcode. */ + __policy__strbuffer__free__(); + + if (error) { + if (pbuf != NULL) + free(pbuf); + return NULL; + } + + /* update total length */ + ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return pbuf; +} + +ipsec_policy_t +ipsec_set_policy(msg, msglen) + __ipsec_const char *msg; + int msglen; +{ + caddr_t policy; + + policy = policy_parse(msg, msglen); + if (policy == NULL) { + if (__ipsec_errcode == EIPSEC_NO_ERROR) + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return policy; +} diff --git a/ipsec-tools/libipsec/policy_token.l b/ipsec-tools/libipsec/policy_token.l new file mode 100644 index 0000000..3351855 --- /dev/null +++ b/ipsec-tools/libipsec/policy_token.l @@ -0,0 +1,198 @@ +/* $Id: policy_token.l,v 1.10.4.1 2005/05/07 14:30:38 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +%{ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include +#include + +#include "libpfkey.h" + +#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__linux__) +#include "y.tab.h" +#else +#include "policy_parse.h" +#endif +#define yylval __libipseclval /* XXX */ + +int yylex __P((void)); +%} + +%option noyywrap +%option nounput + +/* common section */ +nl \n +ws [ \t]+ +digit [0-9] +hexdigit [0-9A-Fa-f] +special [()+\|\?\*,] +dot \. +comma \, +hyphen \- +colon \: +slash \/ +bcl \{ +ecl \} +blcl \[ +elcl \] +percent \% +semi \; +plus \+ +usec {dot}{digit}{1,6} +comment \#.* +ccomment "/*" +bracketstring \<[^>]*\> +quotedstring \"[^"]*\" +decstring {digit}+ +hexpair {hexdigit}{hexdigit} +hexstring 0[xX]{hexdigit}+ +octetstring {octet}({dot}{octet})+ +ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%[a-zA-Z0-9]+)? + +%% + +in { yylval.num = IPSEC_DIR_INBOUND; return(DIR); } +out { yylval.num = IPSEC_DIR_OUTBOUND; return(DIR); } +fwd { +#ifdef HAVE_POLICY_FWD + yylval.num = IPSEC_DIR_FWD; return(DIR); +#else + yylval.num = IPSEC_DIR_INBOUND; return(DIR); +#endif + } + +priority { return(PRIORITY); } +prio { return(PRIORITY); } +low { yylval.num32 = PRIORITY_LOW; return(PRIO_BASE); } +def { yylval.num32 = PRIORITY_DEFAULT; return(PRIO_BASE); } +high { yylval.num32 = PRIORITY_HIGH; return(PRIO_BASE); } +{plus} { return(PLUS); } +{decstring} { + yylval.val.len = strlen(yytext); + yylval.val.buf = yytext; + return(PRIO_OFFSET); +} + +discard { yylval.num = IPSEC_POLICY_DISCARD; return(ACTION); } +generate { yylval.num = IPSEC_POLICY_GENERATE; return(ACTION); } +none { yylval.num = IPSEC_POLICY_NONE; return(ACTION); } +ipsec { yylval.num = IPSEC_POLICY_IPSEC; return(ACTION); } +bypass { yylval.num = IPSEC_POLICY_BYPASS; return(ACTION); } +entrust { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); } + +esp { yylval.num = IPPROTO_ESP; return(PROTOCOL); } +ah { yylval.num = IPPROTO_AH; return(PROTOCOL); } +ipcomp { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); } + +transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); } +tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } + +me { return(ME); } +any { return(ANY); } + +default { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); } +use { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); } +require { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); } +unique{colon}{decstring} { + yylval.val.len = strlen(yytext + 7); + yylval.val.buf = yytext + 7; + return(LEVEL_SPECIFY); + } +unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); } +{slash} { return(SLASH); } + +{ipaddress} { + yylval.val.len = strlen(yytext); + yylval.val.buf = yytext; + return(IPADDRESS); + } + +{hyphen} { return(HYPHEN); } + +{blcl}{decstring}{elcl} { + /* Remove leading '[' and trailing ']' */ + yylval.val.buf = yytext + 1; + yylval.val.len = strlen(yytext) - 2; + + return(PORT); + } + +{ws} { ; } +{nl} { ; } + +%% + +void __policy__strbuffer__init__ __P((char *)); +void __policy__strbuffer__free__ __P((void)); + +static YY_BUFFER_STATE strbuffer; + +void +__policy__strbuffer__init__(msg) + char *msg; +{ + if (YY_CURRENT_BUFFER) + yy_delete_buffer(YY_CURRENT_BUFFER); + strbuffer = (YY_BUFFER_STATE)yy_scan_string(msg); + yy_switch_to_buffer(strbuffer); + + return; +} + +void +__policy__strbuffer__free__() +{ + yy_delete_buffer(strbuffer); + + return; +} diff --git a/ipsec-tools/libipsec/test-policy.c b/ipsec-tools/libipsec/test-policy.c new file mode 100644 index 0000000..c6bf4f2 --- /dev/null +++ b/ipsec-tools/libipsec/test-policy.c @@ -0,0 +1,334 @@ +/* $KAME: test-policy.c,v 1.16 2003/08/26 03:24:08 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include + +#include +#include +#include +#include +#include +#include + +#include "libpfkey.h" + +struct req_t { + int result; /* expected result; 0:ok 1:ng */ + char *str; +} reqs[] = { +{ 0, "out ipsec" }, +{ 1, "must_error" }, +{ 1, "in ipsec must_error" }, +{ 1, "out ipsec esp/must_error" }, +{ 1, "out discard" }, +{ 1, "out none" }, +{ 0, "in entrust" }, +{ 0, "out entrust" }, +{ 1, "out ipsec esp" }, +{ 0, "in ipsec ah/transport" }, +{ 1, "in ipsec ah/tunnel" }, +{ 0, "out ipsec ah/transport/" }, +{ 1, "out ipsec ah/tunnel/" }, +{ 0, "in ipsec esp / transport / 10.0.0.1-10.0.0.2" }, +{ 0, "in ipsec esp/tunnel/::1-::2" }, +{ 1, "in ipsec esp/tunnel/10.0.0.1-::2" }, +{ 0, "in ipsec esp/tunnel/::1-::2/require" }, +{ 0, "out ipsec ah/transport//use" }, +{ 1, "out ipsec ah/transport esp/use" }, +{ 1, "in ipsec ah/transport esp/tunnel" }, +{ 0, "in ipsec ah/transport esp/tunnel/::1-::1" }, +{ 0, "in ipsec ah / transport esp / tunnel / ::1-::2" }, +{ 0, "out ipsec \ + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \ + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \ + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require \ + " }, +{ 0, "out ipsec esp/transport/fec0::10-fec0::11/use" }, +}; + +int test1 __P((void)); +int test1sub1 __P((struct req_t *)); +int test1sub2 __P((char *, int)); +int test2 __P((void)); +int test2sub __P((int)); + +int +main(ac, av) + int ac; + char **av; +{ + test1(); + test2(); + + exit(0); +} + +int +test1() +{ + int i; + int result; + + printf("TEST1\n"); + for (i = 0; i < sizeof(reqs)/sizeof(reqs[0]); i++) { + printf("#%d [%s]\n", i + 1, reqs[i].str); + + result = test1sub1(&reqs[i]); + if (result == 0 && reqs[i].result == 1) { + warnx("ERROR: expecting failure."); + } else if (result == 1 && reqs[i].result == 0) { + warnx("ERROR: expecting success."); + } + } + + return 0; +} + +int +test1sub1(req) + struct req_t *req; +{ + char *buf; + + buf = ipsec_set_policy(req->str, strlen(req->str)); + if (buf == NULL) { + printf("ipsec_set_policy: %s\n", ipsec_strerror()); + return 1; + } + + if (test1sub2(buf, PF_INET) != 0 + || test1sub2(buf, PF_INET6) != 0) { + free(buf); + return 1; + } +#if 0 + kdebug_sadb_x_policy((struct sadb_ext *)buf); +#endif + + free(buf); + return 0; +} + +int +test1sub2(policy, family) + char *policy; + int family; +{ + int so; + int proto = 0, optname = 0; + int len; + char getbuf[1024]; + + switch (family) { + case PF_INET: + proto = IPPROTO_IP; + optname = IP_IPSEC_POLICY; + break; + case PF_INET6: + proto = IPPROTO_IPV6; + optname = IPV6_IPSEC_POLICY; + break; + } + + if ((so = socket(family, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + len = ipsec_get_policylen(policy); +#if 0 + printf("\tsetlen:%d\n", len); +#endif + + if (setsockopt(so, proto, optname, policy, len) < 0) { + printf("fail to set sockopt; %s\n", strerror(errno)); + close(so); + return 1; + } + + memset(getbuf, 0, sizeof(getbuf)); + memcpy(getbuf, policy, sizeof(struct sadb_x_policy)); + if (getsockopt(so, proto, optname, getbuf, &len) < 0) { + printf("fail to get sockopt; %s\n", strerror(errno)); + close(so); + return 1; + } + + { + char *buf = NULL; + +#if 0 + printf("\tgetlen:%d\n", len); +#endif + + if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) { + printf("%s\n", ipsec_strerror()); + close(so); + return 1; + } +#if 0 + printf("\t[%s]\n", buf); +#endif + free(buf); + } + + close (so); + return 0; +} + +char addr[] = { + 28, 28, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, +}; + +int +test2() +{ + int so; + char *pol1 = "out ipsec"; + char *pol2 = "out ipsec ah/transport//use"; + char *sp1, *sp2; + int splen1, splen2; + int spid; + struct sadb_msg *m; + + printf("TEST2\n"); + if (getuid() != 0) + errx(1, "root privilege required."); + + sp1 = ipsec_set_policy(pol1, strlen(pol1)); + splen1 = ipsec_get_policylen(sp1); + sp2 = ipsec_set_policy(pol2, strlen(pol2)); + splen2 = ipsec_get_policylen(sp2); + + if ((so = pfkey_open()) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + + printf("spdflush()\n"); + if (pfkey_send_spdflush(so) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdsetidx()\n"); + if (pfkey_send_spdsetidx(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp1, splen1, 0) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdupdate()\n"); + if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("sleep(4)\n"); + sleep(4); + + printf("spddelete()\n"); + if (pfkey_send_spddelete(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp1, splen1, 0) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdadd()\n"); + if (pfkey_send_spdadd(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + spid = test2sub(so); + + printf("spdget(%u)\n", spid); + if (pfkey_send_spdget(so, spid) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("sleep(4)\n"); + sleep(4); + + printf("spddelete2()\n"); + if (pfkey_send_spddelete2(so, spid) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdadd() with lifetime's 10(s)\n"); + if (pfkey_send_spdadd2(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, 0, 10, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s", ipsec_strerror()); + spid = test2sub(so); + + /* expecting failure */ + printf("spdupdate()\n"); + if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) == 0) { + warnx("ERROR: expecting failure."); + } + + return 0; +} + +int +test2sub(so) + int so; +{ + struct sadb_msg *msg; + caddr_t mhp[SADB_EXT_MAX + 1]; + + if ((msg = pfkey_recv(so)) == NULL) + errx(1, "ERROR: pfkey_recv failure."); + if (pfkey_align(msg, mhp) < 0) + errx(1, "ERROR: pfkey_align failure."); + + return ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id; +} + diff --git a/ipsec-tools/racoon/Crypto/boxes-fst.dat b/ipsec-tools/racoon/Crypto/boxes-fst.dat new file mode 100644 index 0000000..50e6cb3 --- /dev/null +++ b/ipsec-tools/racoon/Crypto/boxes-fst.dat @@ -0,0 +1,957 @@ +/* $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $ */ + +const word8 S[256] = { + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, +202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, +183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, +208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, +205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, +224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, +231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, +186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, +112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, +225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, +140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 +}; + +#ifdef INTERMEDIATE_VALUE_KAT +static const word8 Si[256] = { + 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, +124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, +114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, +108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, +144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, +208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, +150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, +252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, +160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 +}; +#endif /* INTERMEDIATE_VALUE_KAT */ + +union xtab { + word32 xt32[256]; + word8 xt8[256][4]; +}; + +static const union xtab xT1 = { + .xt8 = { +{0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d}, +{0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54}, +{0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d}, +{0xe7,0xfe,0xfe,0x19}, {0xb5,0xd7,0xd7,0x62}, {0x4d,0xab,0xab,0xe6}, {0xec,0x76,0x76,0x9a}, +{0x8f,0xca,0xca,0x45}, {0x1f,0x82,0x82,0x9d}, {0x89,0xc9,0xc9,0x40}, {0xfa,0x7d,0x7d,0x87}, +{0xef,0xfa,0xfa,0x15}, {0xb2,0x59,0x59,0xeb}, {0x8e,0x47,0x47,0xc9}, {0xfb,0xf0,0xf0,0x0b}, +{0x41,0xad,0xad,0xec}, {0xb3,0xd4,0xd4,0x67}, {0x5f,0xa2,0xa2,0xfd}, {0x45,0xaf,0xaf,0xea}, +{0x23,0x9c,0x9c,0xbf}, {0x53,0xa4,0xa4,0xf7}, {0xe4,0x72,0x72,0x96}, {0x9b,0xc0,0xc0,0x5b}, +{0x75,0xb7,0xb7,0xc2}, {0xe1,0xfd,0xfd,0x1c}, {0x3d,0x93,0x93,0xae}, {0x4c,0x26,0x26,0x6a}, +{0x6c,0x36,0x36,0x5a}, {0x7e,0x3f,0x3f,0x41}, {0xf5,0xf7,0xf7,0x02}, {0x83,0xcc,0xcc,0x4f}, +{0x68,0x34,0x34,0x5c}, {0x51,0xa5,0xa5,0xf4}, {0xd1,0xe5,0xe5,0x34}, {0xf9,0xf1,0xf1,0x08}, +{0xe2,0x71,0x71,0x93}, {0xab,0xd8,0xd8,0x73}, {0x62,0x31,0x31,0x53}, {0x2a,0x15,0x15,0x3f}, +{0x08,0x04,0x04,0x0c}, {0x95,0xc7,0xc7,0x52}, {0x46,0x23,0x23,0x65}, {0x9d,0xc3,0xc3,0x5e}, +{0x30,0x18,0x18,0x28}, {0x37,0x96,0x96,0xa1}, {0x0a,0x05,0x05,0x0f}, {0x2f,0x9a,0x9a,0xb5}, +{0x0e,0x07,0x07,0x09}, {0x24,0x12,0x12,0x36}, {0x1b,0x80,0x80,0x9b}, {0xdf,0xe2,0xe2,0x3d}, +{0xcd,0xeb,0xeb,0x26}, {0x4e,0x27,0x27,0x69}, {0x7f,0xb2,0xb2,0xcd}, {0xea,0x75,0x75,0x9f}, +{0x12,0x09,0x09,0x1b}, {0x1d,0x83,0x83,0x9e}, {0x58,0x2c,0x2c,0x74}, {0x34,0x1a,0x1a,0x2e}, +{0x36,0x1b,0x1b,0x2d}, {0xdc,0x6e,0x6e,0xb2}, {0xb4,0x5a,0x5a,0xee}, {0x5b,0xa0,0xa0,0xfb}, +{0xa4,0x52,0x52,0xf6}, {0x76,0x3b,0x3b,0x4d}, {0xb7,0xd6,0xd6,0x61}, {0x7d,0xb3,0xb3,0xce}, +{0x52,0x29,0x29,0x7b}, {0xdd,0xe3,0xe3,0x3e}, {0x5e,0x2f,0x2f,0x71}, {0x13,0x84,0x84,0x97}, +{0xa6,0x53,0x53,0xf5}, {0xb9,0xd1,0xd1,0x68}, {0x00,0x00,0x00,0x00}, {0xc1,0xed,0xed,0x2c}, +{0x40,0x20,0x20,0x60}, {0xe3,0xfc,0xfc,0x1f}, {0x79,0xb1,0xb1,0xc8}, {0xb6,0x5b,0x5b,0xed}, +{0xd4,0x6a,0x6a,0xbe}, {0x8d,0xcb,0xcb,0x46}, {0x67,0xbe,0xbe,0xd9}, {0x72,0x39,0x39,0x4b}, +{0x94,0x4a,0x4a,0xde}, {0x98,0x4c,0x4c,0xd4}, {0xb0,0x58,0x58,0xe8}, {0x85,0xcf,0xcf,0x4a}, +{0xbb,0xd0,0xd0,0x6b}, {0xc5,0xef,0xef,0x2a}, {0x4f,0xaa,0xaa,0xe5}, {0xed,0xfb,0xfb,0x16}, +{0x86,0x43,0x43,0xc5}, {0x9a,0x4d,0x4d,0xd7}, {0x66,0x33,0x33,0x55}, {0x11,0x85,0x85,0x94}, +{0x8a,0x45,0x45,0xcf}, {0xe9,0xf9,0xf9,0x10}, {0x04,0x02,0x02,0x06}, {0xfe,0x7f,0x7f,0x81}, +{0xa0,0x50,0x50,0xf0}, {0x78,0x3c,0x3c,0x44}, {0x25,0x9f,0x9f,0xba}, {0x4b,0xa8,0xa8,0xe3}, +{0xa2,0x51,0x51,0xf3}, {0x5d,0xa3,0xa3,0xfe}, {0x80,0x40,0x40,0xc0}, {0x05,0x8f,0x8f,0x8a}, +{0x3f,0x92,0x92,0xad}, {0x21,0x9d,0x9d,0xbc}, {0x70,0x38,0x38,0x48}, {0xf1,0xf5,0xf5,0x04}, +{0x63,0xbc,0xbc,0xdf}, {0x77,0xb6,0xb6,0xc1}, {0xaf,0xda,0xda,0x75}, {0x42,0x21,0x21,0x63}, +{0x20,0x10,0x10,0x30}, {0xe5,0xff,0xff,0x1a}, {0xfd,0xf3,0xf3,0x0e}, {0xbf,0xd2,0xd2,0x6d}, +{0x81,0xcd,0xcd,0x4c}, {0x18,0x0c,0x0c,0x14}, {0x26,0x13,0x13,0x35}, {0xc3,0xec,0xec,0x2f}, +{0xbe,0x5f,0x5f,0xe1}, {0x35,0x97,0x97,0xa2}, {0x88,0x44,0x44,0xcc}, {0x2e,0x17,0x17,0x39}, +{0x93,0xc4,0xc4,0x57}, {0x55,0xa7,0xa7,0xf2}, {0xfc,0x7e,0x7e,0x82}, {0x7a,0x3d,0x3d,0x47}, +{0xc8,0x64,0x64,0xac}, {0xba,0x5d,0x5d,0xe7}, {0x32,0x19,0x19,0x2b}, {0xe6,0x73,0x73,0x95}, +{0xc0,0x60,0x60,0xa0}, {0x19,0x81,0x81,0x98}, {0x9e,0x4f,0x4f,0xd1}, {0xa3,0xdc,0xdc,0x7f}, +{0x44,0x22,0x22,0x66}, {0x54,0x2a,0x2a,0x7e}, {0x3b,0x90,0x90,0xab}, {0x0b,0x88,0x88,0x83}, +{0x8c,0x46,0x46,0xca}, {0xc7,0xee,0xee,0x29}, {0x6b,0xb8,0xb8,0xd3}, {0x28,0x14,0x14,0x3c}, +{0xa7,0xde,0xde,0x79}, {0xbc,0x5e,0x5e,0xe2}, {0x16,0x0b,0x0b,0x1d}, {0xad,0xdb,0xdb,0x76}, +{0xdb,0xe0,0xe0,0x3b}, {0x64,0x32,0x32,0x56}, {0x74,0x3a,0x3a,0x4e}, {0x14,0x0a,0x0a,0x1e}, +{0x92,0x49,0x49,0xdb}, {0x0c,0x06,0x06,0x0a}, {0x48,0x24,0x24,0x6c}, {0xb8,0x5c,0x5c,0xe4}, +{0x9f,0xc2,0xc2,0x5d}, {0xbd,0xd3,0xd3,0x6e}, {0x43,0xac,0xac,0xef}, {0xc4,0x62,0x62,0xa6}, +{0x39,0x91,0x91,0xa8}, {0x31,0x95,0x95,0xa4}, {0xd3,0xe4,0xe4,0x37}, {0xf2,0x79,0x79,0x8b}, +{0xd5,0xe7,0xe7,0x32}, {0x8b,0xc8,0xc8,0x43}, {0x6e,0x37,0x37,0x59}, {0xda,0x6d,0x6d,0xb7}, +{0x01,0x8d,0x8d,0x8c}, {0xb1,0xd5,0xd5,0x64}, {0x9c,0x4e,0x4e,0xd2}, {0x49,0xa9,0xa9,0xe0}, +{0xd8,0x6c,0x6c,0xb4}, {0xac,0x56,0x56,0xfa}, {0xf3,0xf4,0xf4,0x07}, {0xcf,0xea,0xea,0x25}, +{0xca,0x65,0x65,0xaf}, {0xf4,0x7a,0x7a,0x8e}, {0x47,0xae,0xae,0xe9}, {0x10,0x08,0x08,0x18}, +{0x6f,0xba,0xba,0xd5}, {0xf0,0x78,0x78,0x88}, {0x4a,0x25,0x25,0x6f}, {0x5c,0x2e,0x2e,0x72}, +{0x38,0x1c,0x1c,0x24}, {0x57,0xa6,0xa6,0xf1}, {0x73,0xb4,0xb4,0xc7}, {0x97,0xc6,0xc6,0x51}, +{0xcb,0xe8,0xe8,0x23}, {0xa1,0xdd,0xdd,0x7c}, {0xe8,0x74,0x74,0x9c}, {0x3e,0x1f,0x1f,0x21}, +{0x96,0x4b,0x4b,0xdd}, {0x61,0xbd,0xbd,0xdc}, {0x0d,0x8b,0x8b,0x86}, {0x0f,0x8a,0x8a,0x85}, +{0xe0,0x70,0x70,0x90}, {0x7c,0x3e,0x3e,0x42}, {0x71,0xb5,0xb5,0xc4}, {0xcc,0x66,0x66,0xaa}, +{0x90,0x48,0x48,0xd8}, {0x06,0x03,0x03,0x05}, {0xf7,0xf6,0xf6,0x01}, {0x1c,0x0e,0x0e,0x12}, +{0xc2,0x61,0x61,0xa3}, {0x6a,0x35,0x35,0x5f}, {0xae,0x57,0x57,0xf9}, {0x69,0xb9,0xb9,0xd0}, +{0x17,0x86,0x86,0x91}, {0x99,0xc1,0xc1,0x58}, {0x3a,0x1d,0x1d,0x27}, {0x27,0x9e,0x9e,0xb9}, +{0xd9,0xe1,0xe1,0x38}, {0xeb,0xf8,0xf8,0x13}, {0x2b,0x98,0x98,0xb3}, {0x22,0x11,0x11,0x33}, +{0xd2,0x69,0x69,0xbb}, {0xa9,0xd9,0xd9,0x70}, {0x07,0x8e,0x8e,0x89}, {0x33,0x94,0x94,0xa7}, +{0x2d,0x9b,0x9b,0xb6}, {0x3c,0x1e,0x1e,0x22}, {0x15,0x87,0x87,0x92}, {0xc9,0xe9,0xe9,0x20}, +{0x87,0xce,0xce,0x49}, {0xaa,0x55,0x55,0xff}, {0x50,0x28,0x28,0x78}, {0xa5,0xdf,0xdf,0x7a}, +{0x03,0x8c,0x8c,0x8f}, {0x59,0xa1,0xa1,0xf8}, {0x09,0x89,0x89,0x80}, {0x1a,0x0d,0x0d,0x17}, +{0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8}, +{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11}, +{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a} + } +}; +#define T1 xT1.xt8 + +static const union xtab xT2 = { + .xt8 = { +{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b}, +{0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5}, +{0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b}, +{0x19,0xe7,0xfe,0xfe}, {0x62,0xb5,0xd7,0xd7}, {0xe6,0x4d,0xab,0xab}, {0x9a,0xec,0x76,0x76}, +{0x45,0x8f,0xca,0xca}, {0x9d,0x1f,0x82,0x82}, {0x40,0x89,0xc9,0xc9}, {0x87,0xfa,0x7d,0x7d}, +{0x15,0xef,0xfa,0xfa}, {0xeb,0xb2,0x59,0x59}, {0xc9,0x8e,0x47,0x47}, {0x0b,0xfb,0xf0,0xf0}, +{0xec,0x41,0xad,0xad}, {0x67,0xb3,0xd4,0xd4}, {0xfd,0x5f,0xa2,0xa2}, {0xea,0x45,0xaf,0xaf}, +{0xbf,0x23,0x9c,0x9c}, {0xf7,0x53,0xa4,0xa4}, {0x96,0xe4,0x72,0x72}, {0x5b,0x9b,0xc0,0xc0}, +{0xc2,0x75,0xb7,0xb7}, {0x1c,0xe1,0xfd,0xfd}, {0xae,0x3d,0x93,0x93}, {0x6a,0x4c,0x26,0x26}, +{0x5a,0x6c,0x36,0x36}, {0x41,0x7e,0x3f,0x3f}, {0x02,0xf5,0xf7,0xf7}, {0x4f,0x83,0xcc,0xcc}, +{0x5c,0x68,0x34,0x34}, {0xf4,0x51,0xa5,0xa5}, {0x34,0xd1,0xe5,0xe5}, {0x08,0xf9,0xf1,0xf1}, +{0x93,0xe2,0x71,0x71}, {0x73,0xab,0xd8,0xd8}, {0x53,0x62,0x31,0x31}, {0x3f,0x2a,0x15,0x15}, +{0x0c,0x08,0x04,0x04}, {0x52,0x95,0xc7,0xc7}, {0x65,0x46,0x23,0x23}, {0x5e,0x9d,0xc3,0xc3}, +{0x28,0x30,0x18,0x18}, {0xa1,0x37,0x96,0x96}, {0x0f,0x0a,0x05,0x05}, {0xb5,0x2f,0x9a,0x9a}, +{0x09,0x0e,0x07,0x07}, {0x36,0x24,0x12,0x12}, {0x9b,0x1b,0x80,0x80}, {0x3d,0xdf,0xe2,0xe2}, +{0x26,0xcd,0xeb,0xeb}, {0x69,0x4e,0x27,0x27}, {0xcd,0x7f,0xb2,0xb2}, {0x9f,0xea,0x75,0x75}, +{0x1b,0x12,0x09,0x09}, {0x9e,0x1d,0x83,0x83}, {0x74,0x58,0x2c,0x2c}, {0x2e,0x34,0x1a,0x1a}, +{0x2d,0x36,0x1b,0x1b}, {0xb2,0xdc,0x6e,0x6e}, {0xee,0xb4,0x5a,0x5a}, {0xfb,0x5b,0xa0,0xa0}, +{0xf6,0xa4,0x52,0x52}, {0x4d,0x76,0x3b,0x3b}, {0x61,0xb7,0xd6,0xd6}, {0xce,0x7d,0xb3,0xb3}, +{0x7b,0x52,0x29,0x29}, {0x3e,0xdd,0xe3,0xe3}, {0x71,0x5e,0x2f,0x2f}, {0x97,0x13,0x84,0x84}, +{0xf5,0xa6,0x53,0x53}, {0x68,0xb9,0xd1,0xd1}, {0x00,0x00,0x00,0x00}, {0x2c,0xc1,0xed,0xed}, +{0x60,0x40,0x20,0x20}, {0x1f,0xe3,0xfc,0xfc}, {0xc8,0x79,0xb1,0xb1}, {0xed,0xb6,0x5b,0x5b}, +{0xbe,0xd4,0x6a,0x6a}, {0x46,0x8d,0xcb,0xcb}, {0xd9,0x67,0xbe,0xbe}, {0x4b,0x72,0x39,0x39}, +{0xde,0x94,0x4a,0x4a}, {0xd4,0x98,0x4c,0x4c}, {0xe8,0xb0,0x58,0x58}, {0x4a,0x85,0xcf,0xcf}, +{0x6b,0xbb,0xd0,0xd0}, {0x2a,0xc5,0xef,0xef}, {0xe5,0x4f,0xaa,0xaa}, {0x16,0xed,0xfb,0xfb}, +{0xc5,0x86,0x43,0x43}, {0xd7,0x9a,0x4d,0x4d}, {0x55,0x66,0x33,0x33}, {0x94,0x11,0x85,0x85}, +{0xcf,0x8a,0x45,0x45}, {0x10,0xe9,0xf9,0xf9}, {0x06,0x04,0x02,0x02}, {0x81,0xfe,0x7f,0x7f}, +{0xf0,0xa0,0x50,0x50}, {0x44,0x78,0x3c,0x3c}, {0xba,0x25,0x9f,0x9f}, {0xe3,0x4b,0xa8,0xa8}, +{0xf3,0xa2,0x51,0x51}, {0xfe,0x5d,0xa3,0xa3}, {0xc0,0x80,0x40,0x40}, {0x8a,0x05,0x8f,0x8f}, +{0xad,0x3f,0x92,0x92}, {0xbc,0x21,0x9d,0x9d}, {0x48,0x70,0x38,0x38}, {0x04,0xf1,0xf5,0xf5}, +{0xdf,0x63,0xbc,0xbc}, {0xc1,0x77,0xb6,0xb6}, {0x75,0xaf,0xda,0xda}, {0x63,0x42,0x21,0x21}, +{0x30,0x20,0x10,0x10}, {0x1a,0xe5,0xff,0xff}, {0x0e,0xfd,0xf3,0xf3}, {0x6d,0xbf,0xd2,0xd2}, +{0x4c,0x81,0xcd,0xcd}, {0x14,0x18,0x0c,0x0c}, {0x35,0x26,0x13,0x13}, {0x2f,0xc3,0xec,0xec}, +{0xe1,0xbe,0x5f,0x5f}, {0xa2,0x35,0x97,0x97}, {0xcc,0x88,0x44,0x44}, {0x39,0x2e,0x17,0x17}, +{0x57,0x93,0xc4,0xc4}, {0xf2,0x55,0xa7,0xa7}, {0x82,0xfc,0x7e,0x7e}, {0x47,0x7a,0x3d,0x3d}, +{0xac,0xc8,0x64,0x64}, {0xe7,0xba,0x5d,0x5d}, {0x2b,0x32,0x19,0x19}, {0x95,0xe6,0x73,0x73}, +{0xa0,0xc0,0x60,0x60}, {0x98,0x19,0x81,0x81}, {0xd1,0x9e,0x4f,0x4f}, {0x7f,0xa3,0xdc,0xdc}, +{0x66,0x44,0x22,0x22}, {0x7e,0x54,0x2a,0x2a}, {0xab,0x3b,0x90,0x90}, {0x83,0x0b,0x88,0x88}, +{0xca,0x8c,0x46,0x46}, {0x29,0xc7,0xee,0xee}, {0xd3,0x6b,0xb8,0xb8}, {0x3c,0x28,0x14,0x14}, +{0x79,0xa7,0xde,0xde}, {0xe2,0xbc,0x5e,0x5e}, {0x1d,0x16,0x0b,0x0b}, {0x76,0xad,0xdb,0xdb}, +{0x3b,0xdb,0xe0,0xe0}, {0x56,0x64,0x32,0x32}, {0x4e,0x74,0x3a,0x3a}, {0x1e,0x14,0x0a,0x0a}, +{0xdb,0x92,0x49,0x49}, {0x0a,0x0c,0x06,0x06}, {0x6c,0x48,0x24,0x24}, {0xe4,0xb8,0x5c,0x5c}, +{0x5d,0x9f,0xc2,0xc2}, {0x6e,0xbd,0xd3,0xd3}, {0xef,0x43,0xac,0xac}, {0xa6,0xc4,0x62,0x62}, +{0xa8,0x39,0x91,0x91}, {0xa4,0x31,0x95,0x95}, {0x37,0xd3,0xe4,0xe4}, {0x8b,0xf2,0x79,0x79}, +{0x32,0xd5,0xe7,0xe7}, {0x43,0x8b,0xc8,0xc8}, {0x59,0x6e,0x37,0x37}, {0xb7,0xda,0x6d,0x6d}, +{0x8c,0x01,0x8d,0x8d}, {0x64,0xb1,0xd5,0xd5}, {0xd2,0x9c,0x4e,0x4e}, {0xe0,0x49,0xa9,0xa9}, +{0xb4,0xd8,0x6c,0x6c}, {0xfa,0xac,0x56,0x56}, {0x07,0xf3,0xf4,0xf4}, {0x25,0xcf,0xea,0xea}, +{0xaf,0xca,0x65,0x65}, {0x8e,0xf4,0x7a,0x7a}, {0xe9,0x47,0xae,0xae}, {0x18,0x10,0x08,0x08}, +{0xd5,0x6f,0xba,0xba}, {0x88,0xf0,0x78,0x78}, {0x6f,0x4a,0x25,0x25}, {0x72,0x5c,0x2e,0x2e}, +{0x24,0x38,0x1c,0x1c}, {0xf1,0x57,0xa6,0xa6}, {0xc7,0x73,0xb4,0xb4}, {0x51,0x97,0xc6,0xc6}, +{0x23,0xcb,0xe8,0xe8}, {0x7c,0xa1,0xdd,0xdd}, {0x9c,0xe8,0x74,0x74}, {0x21,0x3e,0x1f,0x1f}, +{0xdd,0x96,0x4b,0x4b}, {0xdc,0x61,0xbd,0xbd}, {0x86,0x0d,0x8b,0x8b}, {0x85,0x0f,0x8a,0x8a}, +{0x90,0xe0,0x70,0x70}, {0x42,0x7c,0x3e,0x3e}, {0xc4,0x71,0xb5,0xb5}, {0xaa,0xcc,0x66,0x66}, +{0xd8,0x90,0x48,0x48}, {0x05,0x06,0x03,0x03}, {0x01,0xf7,0xf6,0xf6}, {0x12,0x1c,0x0e,0x0e}, +{0xa3,0xc2,0x61,0x61}, {0x5f,0x6a,0x35,0x35}, {0xf9,0xae,0x57,0x57}, {0xd0,0x69,0xb9,0xb9}, +{0x91,0x17,0x86,0x86}, {0x58,0x99,0xc1,0xc1}, {0x27,0x3a,0x1d,0x1d}, {0xb9,0x27,0x9e,0x9e}, +{0x38,0xd9,0xe1,0xe1}, {0x13,0xeb,0xf8,0xf8}, {0xb3,0x2b,0x98,0x98}, {0x33,0x22,0x11,0x11}, +{0xbb,0xd2,0x69,0x69}, {0x70,0xa9,0xd9,0xd9}, {0x89,0x07,0x8e,0x8e}, {0xa7,0x33,0x94,0x94}, +{0xb6,0x2d,0x9b,0x9b}, {0x22,0x3c,0x1e,0x1e}, {0x92,0x15,0x87,0x87}, {0x20,0xc9,0xe9,0xe9}, +{0x49,0x87,0xce,0xce}, {0xff,0xaa,0x55,0x55}, {0x78,0x50,0x28,0x28}, {0x7a,0xa5,0xdf,0xdf}, +{0x8f,0x03,0x8c,0x8c}, {0xf8,0x59,0xa1,0xa1}, {0x80,0x09,0x89,0x89}, {0x17,0x1a,0x0d,0x0d}, +{0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68}, +{0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f}, +{0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16} + } +}; +#define T2 xT2.xt8 + +static const union xtab xT3 = { + .xt8 = { +{0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b}, +{0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5}, +{0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b}, +{0xfe,0x19,0xe7,0xfe}, {0xd7,0x62,0xb5,0xd7}, {0xab,0xe6,0x4d,0xab}, {0x76,0x9a,0xec,0x76}, +{0xca,0x45,0x8f,0xca}, {0x82,0x9d,0x1f,0x82}, {0xc9,0x40,0x89,0xc9}, {0x7d,0x87,0xfa,0x7d}, +{0xfa,0x15,0xef,0xfa}, {0x59,0xeb,0xb2,0x59}, {0x47,0xc9,0x8e,0x47}, {0xf0,0x0b,0xfb,0xf0}, +{0xad,0xec,0x41,0xad}, {0xd4,0x67,0xb3,0xd4}, {0xa2,0xfd,0x5f,0xa2}, {0xaf,0xea,0x45,0xaf}, +{0x9c,0xbf,0x23,0x9c}, {0xa4,0xf7,0x53,0xa4}, {0x72,0x96,0xe4,0x72}, {0xc0,0x5b,0x9b,0xc0}, +{0xb7,0xc2,0x75,0xb7}, {0xfd,0x1c,0xe1,0xfd}, {0x93,0xae,0x3d,0x93}, {0x26,0x6a,0x4c,0x26}, +{0x36,0x5a,0x6c,0x36}, {0x3f,0x41,0x7e,0x3f}, {0xf7,0x02,0xf5,0xf7}, {0xcc,0x4f,0x83,0xcc}, +{0x34,0x5c,0x68,0x34}, {0xa5,0xf4,0x51,0xa5}, {0xe5,0x34,0xd1,0xe5}, {0xf1,0x08,0xf9,0xf1}, +{0x71,0x93,0xe2,0x71}, {0xd8,0x73,0xab,0xd8}, {0x31,0x53,0x62,0x31}, {0x15,0x3f,0x2a,0x15}, +{0x04,0x0c,0x08,0x04}, {0xc7,0x52,0x95,0xc7}, {0x23,0x65,0x46,0x23}, {0xc3,0x5e,0x9d,0xc3}, +{0x18,0x28,0x30,0x18}, {0x96,0xa1,0x37,0x96}, {0x05,0x0f,0x0a,0x05}, {0x9a,0xb5,0x2f,0x9a}, +{0x07,0x09,0x0e,0x07}, {0x12,0x36,0x24,0x12}, {0x80,0x9b,0x1b,0x80}, {0xe2,0x3d,0xdf,0xe2}, +{0xeb,0x26,0xcd,0xeb}, {0x27,0x69,0x4e,0x27}, {0xb2,0xcd,0x7f,0xb2}, {0x75,0x9f,0xea,0x75}, +{0x09,0x1b,0x12,0x09}, {0x83,0x9e,0x1d,0x83}, {0x2c,0x74,0x58,0x2c}, {0x1a,0x2e,0x34,0x1a}, +{0x1b,0x2d,0x36,0x1b}, {0x6e,0xb2,0xdc,0x6e}, {0x5a,0xee,0xb4,0x5a}, {0xa0,0xfb,0x5b,0xa0}, +{0x52,0xf6,0xa4,0x52}, {0x3b,0x4d,0x76,0x3b}, {0xd6,0x61,0xb7,0xd6}, {0xb3,0xce,0x7d,0xb3}, +{0x29,0x7b,0x52,0x29}, {0xe3,0x3e,0xdd,0xe3}, {0x2f,0x71,0x5e,0x2f}, {0x84,0x97,0x13,0x84}, +{0x53,0xf5,0xa6,0x53}, {0xd1,0x68,0xb9,0xd1}, {0x00,0x00,0x00,0x00}, {0xed,0x2c,0xc1,0xed}, +{0x20,0x60,0x40,0x20}, {0xfc,0x1f,0xe3,0xfc}, {0xb1,0xc8,0x79,0xb1}, {0x5b,0xed,0xb6,0x5b}, +{0x6a,0xbe,0xd4,0x6a}, {0xcb,0x46,0x8d,0xcb}, {0xbe,0xd9,0x67,0xbe}, {0x39,0x4b,0x72,0x39}, +{0x4a,0xde,0x94,0x4a}, {0x4c,0xd4,0x98,0x4c}, {0x58,0xe8,0xb0,0x58}, {0xcf,0x4a,0x85,0xcf}, +{0xd0,0x6b,0xbb,0xd0}, {0xef,0x2a,0xc5,0xef}, {0xaa,0xe5,0x4f,0xaa}, {0xfb,0x16,0xed,0xfb}, +{0x43,0xc5,0x86,0x43}, {0x4d,0xd7,0x9a,0x4d}, {0x33,0x55,0x66,0x33}, {0x85,0x94,0x11,0x85}, +{0x45,0xcf,0x8a,0x45}, {0xf9,0x10,0xe9,0xf9}, {0x02,0x06,0x04,0x02}, {0x7f,0x81,0xfe,0x7f}, +{0x50,0xf0,0xa0,0x50}, {0x3c,0x44,0x78,0x3c}, {0x9f,0xba,0x25,0x9f}, {0xa8,0xe3,0x4b,0xa8}, +{0x51,0xf3,0xa2,0x51}, {0xa3,0xfe,0x5d,0xa3}, {0x40,0xc0,0x80,0x40}, {0x8f,0x8a,0x05,0x8f}, +{0x92,0xad,0x3f,0x92}, {0x9d,0xbc,0x21,0x9d}, {0x38,0x48,0x70,0x38}, {0xf5,0x04,0xf1,0xf5}, +{0xbc,0xdf,0x63,0xbc}, {0xb6,0xc1,0x77,0xb6}, {0xda,0x75,0xaf,0xda}, {0x21,0x63,0x42,0x21}, +{0x10,0x30,0x20,0x10}, {0xff,0x1a,0xe5,0xff}, {0xf3,0x0e,0xfd,0xf3}, {0xd2,0x6d,0xbf,0xd2}, +{0xcd,0x4c,0x81,0xcd}, {0x0c,0x14,0x18,0x0c}, {0x13,0x35,0x26,0x13}, {0xec,0x2f,0xc3,0xec}, +{0x5f,0xe1,0xbe,0x5f}, {0x97,0xa2,0x35,0x97}, {0x44,0xcc,0x88,0x44}, {0x17,0x39,0x2e,0x17}, +{0xc4,0x57,0x93,0xc4}, {0xa7,0xf2,0x55,0xa7}, {0x7e,0x82,0xfc,0x7e}, {0x3d,0x47,0x7a,0x3d}, +{0x64,0xac,0xc8,0x64}, {0x5d,0xe7,0xba,0x5d}, {0x19,0x2b,0x32,0x19}, {0x73,0x95,0xe6,0x73}, +{0x60,0xa0,0xc0,0x60}, {0x81,0x98,0x19,0x81}, {0x4f,0xd1,0x9e,0x4f}, {0xdc,0x7f,0xa3,0xdc}, +{0x22,0x66,0x44,0x22}, {0x2a,0x7e,0x54,0x2a}, {0x90,0xab,0x3b,0x90}, {0x88,0x83,0x0b,0x88}, +{0x46,0xca,0x8c,0x46}, {0xee,0x29,0xc7,0xee}, {0xb8,0xd3,0x6b,0xb8}, {0x14,0x3c,0x28,0x14}, +{0xde,0x79,0xa7,0xde}, {0x5e,0xe2,0xbc,0x5e}, {0x0b,0x1d,0x16,0x0b}, {0xdb,0x76,0xad,0xdb}, +{0xe0,0x3b,0xdb,0xe0}, {0x32,0x56,0x64,0x32}, {0x3a,0x4e,0x74,0x3a}, {0x0a,0x1e,0x14,0x0a}, +{0x49,0xdb,0x92,0x49}, {0x06,0x0a,0x0c,0x06}, {0x24,0x6c,0x48,0x24}, {0x5c,0xe4,0xb8,0x5c}, +{0xc2,0x5d,0x9f,0xc2}, {0xd3,0x6e,0xbd,0xd3}, {0xac,0xef,0x43,0xac}, {0x62,0xa6,0xc4,0x62}, +{0x91,0xa8,0x39,0x91}, {0x95,0xa4,0x31,0x95}, {0xe4,0x37,0xd3,0xe4}, {0x79,0x8b,0xf2,0x79}, +{0xe7,0x32,0xd5,0xe7}, {0xc8,0x43,0x8b,0xc8}, {0x37,0x59,0x6e,0x37}, {0x6d,0xb7,0xda,0x6d}, +{0x8d,0x8c,0x01,0x8d}, {0xd5,0x64,0xb1,0xd5}, {0x4e,0xd2,0x9c,0x4e}, {0xa9,0xe0,0x49,0xa9}, +{0x6c,0xb4,0xd8,0x6c}, {0x56,0xfa,0xac,0x56}, {0xf4,0x07,0xf3,0xf4}, {0xea,0x25,0xcf,0xea}, +{0x65,0xaf,0xca,0x65}, {0x7a,0x8e,0xf4,0x7a}, {0xae,0xe9,0x47,0xae}, {0x08,0x18,0x10,0x08}, +{0xba,0xd5,0x6f,0xba}, {0x78,0x88,0xf0,0x78}, {0x25,0x6f,0x4a,0x25}, {0x2e,0x72,0x5c,0x2e}, +{0x1c,0x24,0x38,0x1c}, {0xa6,0xf1,0x57,0xa6}, {0xb4,0xc7,0x73,0xb4}, {0xc6,0x51,0x97,0xc6}, +{0xe8,0x23,0xcb,0xe8}, {0xdd,0x7c,0xa1,0xdd}, {0x74,0x9c,0xe8,0x74}, {0x1f,0x21,0x3e,0x1f}, +{0x4b,0xdd,0x96,0x4b}, {0xbd,0xdc,0x61,0xbd}, {0x8b,0x86,0x0d,0x8b}, {0x8a,0x85,0x0f,0x8a}, +{0x70,0x90,0xe0,0x70}, {0x3e,0x42,0x7c,0x3e}, {0xb5,0xc4,0x71,0xb5}, {0x66,0xaa,0xcc,0x66}, +{0x48,0xd8,0x90,0x48}, {0x03,0x05,0x06,0x03}, {0xf6,0x01,0xf7,0xf6}, {0x0e,0x12,0x1c,0x0e}, +{0x61,0xa3,0xc2,0x61}, {0x35,0x5f,0x6a,0x35}, {0x57,0xf9,0xae,0x57}, {0xb9,0xd0,0x69,0xb9}, +{0x86,0x91,0x17,0x86}, {0xc1,0x58,0x99,0xc1}, {0x1d,0x27,0x3a,0x1d}, {0x9e,0xb9,0x27,0x9e}, +{0xe1,0x38,0xd9,0xe1}, {0xf8,0x13,0xeb,0xf8}, {0x98,0xb3,0x2b,0x98}, {0x11,0x33,0x22,0x11}, +{0x69,0xbb,0xd2,0x69}, {0xd9,0x70,0xa9,0xd9}, {0x8e,0x89,0x07,0x8e}, {0x94,0xa7,0x33,0x94}, +{0x9b,0xb6,0x2d,0x9b}, {0x1e,0x22,0x3c,0x1e}, {0x87,0x92,0x15,0x87}, {0xe9,0x20,0xc9,0xe9}, +{0xce,0x49,0x87,0xce}, {0x55,0xff,0xaa,0x55}, {0x28,0x78,0x50,0x28}, {0xdf,0x7a,0xa5,0xdf}, +{0x8c,0x8f,0x03,0x8c}, {0xa1,0xf8,0x59,0xa1}, {0x89,0x80,0x09,0x89}, {0x0d,0x17,0x1a,0x0d}, +{0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68}, +{0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f}, +{0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16} + } +}; +#define T3 xT3.xt8 + +static const union xtab xT4 = { + .xt8 = { +{0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6}, +{0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91}, +{0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56}, +{0xfe,0xfe,0x19,0xe7}, {0xd7,0xd7,0x62,0xb5}, {0xab,0xab,0xe6,0x4d}, {0x76,0x76,0x9a,0xec}, +{0xca,0xca,0x45,0x8f}, {0x82,0x82,0x9d,0x1f}, {0xc9,0xc9,0x40,0x89}, {0x7d,0x7d,0x87,0xfa}, +{0xfa,0xfa,0x15,0xef}, {0x59,0x59,0xeb,0xb2}, {0x47,0x47,0xc9,0x8e}, {0xf0,0xf0,0x0b,0xfb}, +{0xad,0xad,0xec,0x41}, {0xd4,0xd4,0x67,0xb3}, {0xa2,0xa2,0xfd,0x5f}, {0xaf,0xaf,0xea,0x45}, +{0x9c,0x9c,0xbf,0x23}, {0xa4,0xa4,0xf7,0x53}, {0x72,0x72,0x96,0xe4}, {0xc0,0xc0,0x5b,0x9b}, +{0xb7,0xb7,0xc2,0x75}, {0xfd,0xfd,0x1c,0xe1}, {0x93,0x93,0xae,0x3d}, {0x26,0x26,0x6a,0x4c}, +{0x36,0x36,0x5a,0x6c}, {0x3f,0x3f,0x41,0x7e}, {0xf7,0xf7,0x02,0xf5}, {0xcc,0xcc,0x4f,0x83}, +{0x34,0x34,0x5c,0x68}, {0xa5,0xa5,0xf4,0x51}, {0xe5,0xe5,0x34,0xd1}, {0xf1,0xf1,0x08,0xf9}, +{0x71,0x71,0x93,0xe2}, {0xd8,0xd8,0x73,0xab}, {0x31,0x31,0x53,0x62}, {0x15,0x15,0x3f,0x2a}, +{0x04,0x04,0x0c,0x08}, {0xc7,0xc7,0x52,0x95}, {0x23,0x23,0x65,0x46}, {0xc3,0xc3,0x5e,0x9d}, +{0x18,0x18,0x28,0x30}, {0x96,0x96,0xa1,0x37}, {0x05,0x05,0x0f,0x0a}, {0x9a,0x9a,0xb5,0x2f}, +{0x07,0x07,0x09,0x0e}, {0x12,0x12,0x36,0x24}, {0x80,0x80,0x9b,0x1b}, {0xe2,0xe2,0x3d,0xdf}, +{0xeb,0xeb,0x26,0xcd}, {0x27,0x27,0x69,0x4e}, {0xb2,0xb2,0xcd,0x7f}, {0x75,0x75,0x9f,0xea}, +{0x09,0x09,0x1b,0x12}, {0x83,0x83,0x9e,0x1d}, {0x2c,0x2c,0x74,0x58}, {0x1a,0x1a,0x2e,0x34}, +{0x1b,0x1b,0x2d,0x36}, {0x6e,0x6e,0xb2,0xdc}, {0x5a,0x5a,0xee,0xb4}, {0xa0,0xa0,0xfb,0x5b}, +{0x52,0x52,0xf6,0xa4}, {0x3b,0x3b,0x4d,0x76}, {0xd6,0xd6,0x61,0xb7}, {0xb3,0xb3,0xce,0x7d}, +{0x29,0x29,0x7b,0x52}, {0xe3,0xe3,0x3e,0xdd}, {0x2f,0x2f,0x71,0x5e}, {0x84,0x84,0x97,0x13}, +{0x53,0x53,0xf5,0xa6}, {0xd1,0xd1,0x68,0xb9}, {0x00,0x00,0x00,0x00}, {0xed,0xed,0x2c,0xc1}, +{0x20,0x20,0x60,0x40}, {0xfc,0xfc,0x1f,0xe3}, {0xb1,0xb1,0xc8,0x79}, {0x5b,0x5b,0xed,0xb6}, +{0x6a,0x6a,0xbe,0xd4}, {0xcb,0xcb,0x46,0x8d}, {0xbe,0xbe,0xd9,0x67}, {0x39,0x39,0x4b,0x72}, +{0x4a,0x4a,0xde,0x94}, {0x4c,0x4c,0xd4,0x98}, {0x58,0x58,0xe8,0xb0}, {0xcf,0xcf,0x4a,0x85}, +{0xd0,0xd0,0x6b,0xbb}, {0xef,0xef,0x2a,0xc5}, {0xaa,0xaa,0xe5,0x4f}, {0xfb,0xfb,0x16,0xed}, +{0x43,0x43,0xc5,0x86}, {0x4d,0x4d,0xd7,0x9a}, {0x33,0x33,0x55,0x66}, {0x85,0x85,0x94,0x11}, +{0x45,0x45,0xcf,0x8a}, {0xf9,0xf9,0x10,0xe9}, {0x02,0x02,0x06,0x04}, {0x7f,0x7f,0x81,0xfe}, +{0x50,0x50,0xf0,0xa0}, {0x3c,0x3c,0x44,0x78}, {0x9f,0x9f,0xba,0x25}, {0xa8,0xa8,0xe3,0x4b}, +{0x51,0x51,0xf3,0xa2}, {0xa3,0xa3,0xfe,0x5d}, {0x40,0x40,0xc0,0x80}, {0x8f,0x8f,0x8a,0x05}, +{0x92,0x92,0xad,0x3f}, {0x9d,0x9d,0xbc,0x21}, {0x38,0x38,0x48,0x70}, {0xf5,0xf5,0x04,0xf1}, +{0xbc,0xbc,0xdf,0x63}, {0xb6,0xb6,0xc1,0x77}, {0xda,0xda,0x75,0xaf}, {0x21,0x21,0x63,0x42}, +{0x10,0x10,0x30,0x20}, {0xff,0xff,0x1a,0xe5}, {0xf3,0xf3,0x0e,0xfd}, {0xd2,0xd2,0x6d,0xbf}, +{0xcd,0xcd,0x4c,0x81}, {0x0c,0x0c,0x14,0x18}, {0x13,0x13,0x35,0x26}, {0xec,0xec,0x2f,0xc3}, +{0x5f,0x5f,0xe1,0xbe}, {0x97,0x97,0xa2,0x35}, {0x44,0x44,0xcc,0x88}, {0x17,0x17,0x39,0x2e}, +{0xc4,0xc4,0x57,0x93}, {0xa7,0xa7,0xf2,0x55}, {0x7e,0x7e,0x82,0xfc}, {0x3d,0x3d,0x47,0x7a}, +{0x64,0x64,0xac,0xc8}, {0x5d,0x5d,0xe7,0xba}, {0x19,0x19,0x2b,0x32}, {0x73,0x73,0x95,0xe6}, +{0x60,0x60,0xa0,0xc0}, {0x81,0x81,0x98,0x19}, {0x4f,0x4f,0xd1,0x9e}, {0xdc,0xdc,0x7f,0xa3}, +{0x22,0x22,0x66,0x44}, {0x2a,0x2a,0x7e,0x54}, {0x90,0x90,0xab,0x3b}, {0x88,0x88,0x83,0x0b}, +{0x46,0x46,0xca,0x8c}, {0xee,0xee,0x29,0xc7}, {0xb8,0xb8,0xd3,0x6b}, {0x14,0x14,0x3c,0x28}, +{0xde,0xde,0x79,0xa7}, {0x5e,0x5e,0xe2,0xbc}, {0x0b,0x0b,0x1d,0x16}, {0xdb,0xdb,0x76,0xad}, +{0xe0,0xe0,0x3b,0xdb}, {0x32,0x32,0x56,0x64}, {0x3a,0x3a,0x4e,0x74}, {0x0a,0x0a,0x1e,0x14}, +{0x49,0x49,0xdb,0x92}, {0x06,0x06,0x0a,0x0c}, {0x24,0x24,0x6c,0x48}, {0x5c,0x5c,0xe4,0xb8}, +{0xc2,0xc2,0x5d,0x9f}, {0xd3,0xd3,0x6e,0xbd}, {0xac,0xac,0xef,0x43}, {0x62,0x62,0xa6,0xc4}, +{0x91,0x91,0xa8,0x39}, {0x95,0x95,0xa4,0x31}, {0xe4,0xe4,0x37,0xd3}, {0x79,0x79,0x8b,0xf2}, +{0xe7,0xe7,0x32,0xd5}, {0xc8,0xc8,0x43,0x8b}, {0x37,0x37,0x59,0x6e}, {0x6d,0x6d,0xb7,0xda}, +{0x8d,0x8d,0x8c,0x01}, {0xd5,0xd5,0x64,0xb1}, {0x4e,0x4e,0xd2,0x9c}, {0xa9,0xa9,0xe0,0x49}, +{0x6c,0x6c,0xb4,0xd8}, {0x56,0x56,0xfa,0xac}, {0xf4,0xf4,0x07,0xf3}, {0xea,0xea,0x25,0xcf}, +{0x65,0x65,0xaf,0xca}, {0x7a,0x7a,0x8e,0xf4}, {0xae,0xae,0xe9,0x47}, {0x08,0x08,0x18,0x10}, +{0xba,0xba,0xd5,0x6f}, {0x78,0x78,0x88,0xf0}, {0x25,0x25,0x6f,0x4a}, {0x2e,0x2e,0x72,0x5c}, +{0x1c,0x1c,0x24,0x38}, {0xa6,0xa6,0xf1,0x57}, {0xb4,0xb4,0xc7,0x73}, {0xc6,0xc6,0x51,0x97}, +{0xe8,0xe8,0x23,0xcb}, {0xdd,0xdd,0x7c,0xa1}, {0x74,0x74,0x9c,0xe8}, {0x1f,0x1f,0x21,0x3e}, +{0x4b,0x4b,0xdd,0x96}, {0xbd,0xbd,0xdc,0x61}, {0x8b,0x8b,0x86,0x0d}, {0x8a,0x8a,0x85,0x0f}, +{0x70,0x70,0x90,0xe0}, {0x3e,0x3e,0x42,0x7c}, {0xb5,0xb5,0xc4,0x71}, {0x66,0x66,0xaa,0xcc}, +{0x48,0x48,0xd8,0x90}, {0x03,0x03,0x05,0x06}, {0xf6,0xf6,0x01,0xf7}, {0x0e,0x0e,0x12,0x1c}, +{0x61,0x61,0xa3,0xc2}, {0x35,0x35,0x5f,0x6a}, {0x57,0x57,0xf9,0xae}, {0xb9,0xb9,0xd0,0x69}, +{0x86,0x86,0x91,0x17}, {0xc1,0xc1,0x58,0x99}, {0x1d,0x1d,0x27,0x3a}, {0x9e,0x9e,0xb9,0x27}, +{0xe1,0xe1,0x38,0xd9}, {0xf8,0xf8,0x13,0xeb}, {0x98,0x98,0xb3,0x2b}, {0x11,0x11,0x33,0x22}, +{0x69,0x69,0xbb,0xd2}, {0xd9,0xd9,0x70,0xa9}, {0x8e,0x8e,0x89,0x07}, {0x94,0x94,0xa7,0x33}, +{0x9b,0x9b,0xb6,0x2d}, {0x1e,0x1e,0x22,0x3c}, {0x87,0x87,0x92,0x15}, {0xe9,0xe9,0x20,0xc9}, +{0xce,0xce,0x49,0x87}, {0x55,0x55,0xff,0xaa}, {0x28,0x28,0x78,0x50}, {0xdf,0xdf,0x7a,0xa5}, +{0x8c,0x8c,0x8f,0x03}, {0xa1,0xa1,0xf8,0x59}, {0x89,0x89,0x80,0x09}, {0x0d,0x0d,0x17,0x1a}, +{0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0}, +{0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e}, +{0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c} + } +}; +#define T4 xT4.xt8 + +static const union xtab xT5 = { + .xt8 = { +{0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96}, +{0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93}, +{0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25}, +{0x4f,0xe5,0xd7,0xfc}, {0xc5,0x2a,0xcb,0xd7}, {0x26,0x35,0x44,0x80}, {0xb5,0x62,0xa3,0x8f}, +{0xde,0xb1,0x5a,0x49}, {0x25,0xba,0x1b,0x67}, {0x45,0xea,0x0e,0x98}, {0x5d,0xfe,0xc0,0xe1}, +{0xc3,0x2f,0x75,0x02}, {0x81,0x4c,0xf0,0x12}, {0x8d,0x46,0x97,0xa3}, {0x6b,0xd3,0xf9,0xc6}, +{0x03,0x8f,0x5f,0xe7}, {0x15,0x92,0x9c,0x95}, {0xbf,0x6d,0x7a,0xeb}, {0x95,0x52,0x59,0xda}, +{0xd4,0xbe,0x83,0x2d}, {0x58,0x74,0x21,0xd3}, {0x49,0xe0,0x69,0x29}, {0x8e,0xc9,0xc8,0x44}, +{0x75,0xc2,0x89,0x6a}, {0xf4,0x8e,0x79,0x78}, {0x99,0x58,0x3e,0x6b}, {0x27,0xb9,0x71,0xdd}, +{0xbe,0xe1,0x4f,0xb6}, {0xf0,0x88,0xad,0x17}, {0xc9,0x20,0xac,0x66}, {0x7d,0xce,0x3a,0xb4}, +{0x63,0xdf,0x4a,0x18}, {0xe5,0x1a,0x31,0x82}, {0x97,0x51,0x33,0x60}, {0x62,0x53,0x7f,0x45}, +{0xb1,0x64,0x77,0xe0}, {0xbb,0x6b,0xae,0x84}, {0xfe,0x81,0xa0,0x1c}, {0xf9,0x08,0x2b,0x94}, +{0x70,0x48,0x68,0x58}, {0x8f,0x45,0xfd,0x19}, {0x94,0xde,0x6c,0x87}, {0x52,0x7b,0xf8,0xb7}, +{0xab,0x73,0xd3,0x23}, {0x72,0x4b,0x02,0xe2}, {0xe3,0x1f,0x8f,0x57}, {0x66,0x55,0xab,0x2a}, +{0xb2,0xeb,0x28,0x07}, {0x2f,0xb5,0xc2,0x03}, {0x86,0xc5,0x7b,0x9a}, {0xd3,0x37,0x08,0xa5}, +{0x30,0x28,0x87,0xf2}, {0x23,0xbf,0xa5,0xb2}, {0x02,0x03,0x6a,0xba}, {0xed,0x16,0x82,0x5c}, +{0x8a,0xcf,0x1c,0x2b}, {0xa7,0x79,0xb4,0x92}, {0xf3,0x07,0xf2,0xf0}, {0x4e,0x69,0xe2,0xa1}, +{0x65,0xda,0xf4,0xcd}, {0x06,0x05,0xbe,0xd5}, {0xd1,0x34,0x62,0x1f}, {0xc4,0xa6,0xfe,0x8a}, +{0x34,0x2e,0x53,0x9d}, {0xa2,0xf3,0x55,0xa0}, {0x05,0x8a,0xe1,0x32}, {0xa4,0xf6,0xeb,0x75}, +{0x0b,0x83,0xec,0x39}, {0x40,0x60,0xef,0xaa}, {0x5e,0x71,0x9f,0x06}, {0xbd,0x6e,0x10,0x51}, +{0x3e,0x21,0x8a,0xf9}, {0x96,0xdd,0x06,0x3d}, {0xdd,0x3e,0x05,0xae}, {0x4d,0xe6,0xbd,0x46}, +{0x91,0x54,0x8d,0xb5}, {0x71,0xc4,0x5d,0x05}, {0x04,0x06,0xd4,0x6f}, {0x60,0x50,0x15,0xff}, +{0x19,0x98,0xfb,0x24}, {0xd6,0xbd,0xe9,0x97}, {0x89,0x40,0x43,0xcc}, {0x67,0xd9,0x9e,0x77}, +{0xb0,0xe8,0x42,0xbd}, {0x07,0x89,0x8b,0x88}, {0xe7,0x19,0x5b,0x38}, {0x79,0xc8,0xee,0xdb}, +{0xa1,0x7c,0x0a,0x47}, {0x7c,0x42,0x0f,0xe9}, {0xf8,0x84,0x1e,0xc9}, {0x00,0x00,0x00,0x00}, +{0x09,0x80,0x86,0x83}, {0x32,0x2b,0xed,0x48}, {0x1e,0x11,0x70,0xac}, {0x6c,0x5a,0x72,0x4e}, +{0xfd,0x0e,0xff,0xfb}, {0x0f,0x85,0x38,0x56}, {0x3d,0xae,0xd5,0x1e}, {0x36,0x2d,0x39,0x27}, +{0x0a,0x0f,0xd9,0x64}, {0x68,0x5c,0xa6,0x21}, {0x9b,0x5b,0x54,0xd1}, {0x24,0x36,0x2e,0x3a}, +{0x0c,0x0a,0x67,0xb1}, {0x93,0x57,0xe7,0x0f}, {0xb4,0xee,0x96,0xd2}, {0x1b,0x9b,0x91,0x9e}, +{0x80,0xc0,0xc5,0x4f}, {0x61,0xdc,0x20,0xa2}, {0x5a,0x77,0x4b,0x69}, {0x1c,0x12,0x1a,0x16}, +{0xe2,0x93,0xba,0x0a}, {0xc0,0xa0,0x2a,0xe5}, {0x3c,0x22,0xe0,0x43}, {0x12,0x1b,0x17,0x1d}, +{0x0e,0x09,0x0d,0x0b}, {0xf2,0x8b,0xc7,0xad}, {0x2d,0xb6,0xa8,0xb9}, {0x14,0x1e,0xa9,0xc8}, +{0x57,0xf1,0x19,0x85}, {0xaf,0x75,0x07,0x4c}, {0xee,0x99,0xdd,0xbb}, {0xa3,0x7f,0x60,0xfd}, +{0xf7,0x01,0x26,0x9f}, {0x5c,0x72,0xf5,0xbc}, {0x44,0x66,0x3b,0xc5}, {0x5b,0xfb,0x7e,0x34}, +{0x8b,0x43,0x29,0x76}, {0xcb,0x23,0xc6,0xdc}, {0xb6,0xed,0xfc,0x68}, {0xb8,0xe4,0xf1,0x63}, +{0xd7,0x31,0xdc,0xca}, {0x42,0x63,0x85,0x10}, {0x13,0x97,0x22,0x40}, {0x84,0xc6,0x11,0x20}, +{0x85,0x4a,0x24,0x7d}, {0xd2,0xbb,0x3d,0xf8}, {0xae,0xf9,0x32,0x11}, {0xc7,0x29,0xa1,0x6d}, +{0x1d,0x9e,0x2f,0x4b}, {0xdc,0xb2,0x30,0xf3}, {0x0d,0x86,0x52,0xec}, {0x77,0xc1,0xe3,0xd0}, +{0x2b,0xb3,0x16,0x6c}, {0xa9,0x70,0xb9,0x99}, {0x11,0x94,0x48,0xfa}, {0x47,0xe9,0x64,0x22}, +{0xa8,0xfc,0x8c,0xc4}, {0xa0,0xf0,0x3f,0x1a}, {0x56,0x7d,0x2c,0xd8}, {0x22,0x33,0x90,0xef}, +{0x87,0x49,0x4e,0xc7}, {0xd9,0x38,0xd1,0xc1}, {0x8c,0xca,0xa2,0xfe}, {0x98,0xd4,0x0b,0x36}, +{0xa6,0xf5,0x81,0xcf}, {0xa5,0x7a,0xde,0x28}, {0xda,0xb7,0x8e,0x26}, {0x3f,0xad,0xbf,0xa4}, +{0x2c,0x3a,0x9d,0xe4}, {0x50,0x78,0x92,0x0d}, {0x6a,0x5f,0xcc,0x9b}, {0x54,0x7e,0x46,0x62}, +{0xf6,0x8d,0x13,0xc2}, {0x90,0xd8,0xb8,0xe8}, {0x2e,0x39,0xf7,0x5e}, {0x82,0xc3,0xaf,0xf5}, +{0x9f,0x5d,0x80,0xbe}, {0x69,0xd0,0x93,0x7c}, {0x6f,0xd5,0x2d,0xa9}, {0xcf,0x25,0x12,0xb3}, +{0xc8,0xac,0x99,0x3b}, {0x10,0x18,0x7d,0xa7}, {0xe8,0x9c,0x63,0x6e}, {0xdb,0x3b,0xbb,0x7b}, +{0xcd,0x26,0x78,0x09}, {0x6e,0x59,0x18,0xf4}, {0xec,0x9a,0xb7,0x01}, {0x83,0x4f,0x9a,0xa8}, +{0xe6,0x95,0x6e,0x65}, {0xaa,0xff,0xe6,0x7e}, {0x21,0xbc,0xcf,0x08}, {0xef,0x15,0xe8,0xe6}, +{0xba,0xe7,0x9b,0xd9}, {0x4a,0x6f,0x36,0xce}, {0xea,0x9f,0x09,0xd4}, {0x29,0xb0,0x7c,0xd6}, +{0x31,0xa4,0xb2,0xaf}, {0x2a,0x3f,0x23,0x31}, {0xc6,0xa5,0x94,0x30}, {0x35,0xa2,0x66,0xc0}, +{0x74,0x4e,0xbc,0x37}, {0xfc,0x82,0xca,0xa6}, {0xe0,0x90,0xd0,0xb0}, {0x33,0xa7,0xd8,0x15}, +{0xf1,0x04,0x98,0x4a}, {0x41,0xec,0xda,0xf7}, {0x7f,0xcd,0x50,0x0e}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x43,0xef,0xb0,0x4d}, {0xcc,0xaa,0x4d,0x54}, {0xe4,0x96,0x04,0xdf}, +{0x9e,0xd1,0xb5,0xe3}, {0x4c,0x6a,0x88,0x1b}, {0xc1,0x2c,0x1f,0xb8}, {0x46,0x65,0x51,0x7f}, +{0x9d,0x5e,0xea,0x04}, {0x01,0x8c,0x35,0x5d}, {0xfa,0x87,0x74,0x73}, {0xfb,0x0b,0x41,0x2e}, +{0xb3,0x67,0x1d,0x5a}, {0x92,0xdb,0xd2,0x52}, {0xe9,0x10,0x56,0x33}, {0x6d,0xd6,0x47,0x13}, +{0x9a,0xd7,0x61,0x8c}, {0x37,0xa1,0x0c,0x7a}, {0x59,0xf8,0x14,0x8e}, {0xeb,0x13,0x3c,0x89}, +{0xce,0xa9,0x27,0xee}, {0xb7,0x61,0xc9,0x35}, {0xe1,0x1c,0xe5,0xed}, {0x7a,0x47,0xb1,0x3c}, +{0x9c,0xd2,0xdf,0x59}, {0x55,0xf2,0x73,0x3f}, {0x18,0x14,0xce,0x79}, {0x73,0xc7,0x37,0xbf}, +{0x53,0xf7,0xcd,0xea}, {0x5f,0xfd,0xaa,0x5b}, {0xdf,0x3d,0x6f,0x14}, {0x78,0x44,0xdb,0x86}, +{0xca,0xaf,0xf3,0x81}, {0xb9,0x68,0xc4,0x3e}, {0x38,0x24,0x34,0x2c}, {0xc2,0xa3,0x40,0x5f}, +{0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41}, +{0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90}, +{0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42} + } +}; +#define T5 xT5.xt8 + +static const union xtab xT6 = { + .xt8 = { +{0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e}, +{0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03}, +{0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c}, +{0xfc,0x4f,0xe5,0xd7}, {0xd7,0xc5,0x2a,0xcb}, {0x80,0x26,0x35,0x44}, {0x8f,0xb5,0x62,0xa3}, +{0x49,0xde,0xb1,0x5a}, {0x67,0x25,0xba,0x1b}, {0x98,0x45,0xea,0x0e}, {0xe1,0x5d,0xfe,0xc0}, +{0x02,0xc3,0x2f,0x75}, {0x12,0x81,0x4c,0xf0}, {0xa3,0x8d,0x46,0x97}, {0xc6,0x6b,0xd3,0xf9}, +{0xe7,0x03,0x8f,0x5f}, {0x95,0x15,0x92,0x9c}, {0xeb,0xbf,0x6d,0x7a}, {0xda,0x95,0x52,0x59}, +{0x2d,0xd4,0xbe,0x83}, {0xd3,0x58,0x74,0x21}, {0x29,0x49,0xe0,0x69}, {0x44,0x8e,0xc9,0xc8}, +{0x6a,0x75,0xc2,0x89}, {0x78,0xf4,0x8e,0x79}, {0x6b,0x99,0x58,0x3e}, {0xdd,0x27,0xb9,0x71}, +{0xb6,0xbe,0xe1,0x4f}, {0x17,0xf0,0x88,0xad}, {0x66,0xc9,0x20,0xac}, {0xb4,0x7d,0xce,0x3a}, +{0x18,0x63,0xdf,0x4a}, {0x82,0xe5,0x1a,0x31}, {0x60,0x97,0x51,0x33}, {0x45,0x62,0x53,0x7f}, +{0xe0,0xb1,0x64,0x77}, {0x84,0xbb,0x6b,0xae}, {0x1c,0xfe,0x81,0xa0}, {0x94,0xf9,0x08,0x2b}, +{0x58,0x70,0x48,0x68}, {0x19,0x8f,0x45,0xfd}, {0x87,0x94,0xde,0x6c}, {0xb7,0x52,0x7b,0xf8}, +{0x23,0xab,0x73,0xd3}, {0xe2,0x72,0x4b,0x02}, {0x57,0xe3,0x1f,0x8f}, {0x2a,0x66,0x55,0xab}, +{0x07,0xb2,0xeb,0x28}, {0x03,0x2f,0xb5,0xc2}, {0x9a,0x86,0xc5,0x7b}, {0xa5,0xd3,0x37,0x08}, +{0xf2,0x30,0x28,0x87}, {0xb2,0x23,0xbf,0xa5}, {0xba,0x02,0x03,0x6a}, {0x5c,0xed,0x16,0x82}, +{0x2b,0x8a,0xcf,0x1c}, {0x92,0xa7,0x79,0xb4}, {0xf0,0xf3,0x07,0xf2}, {0xa1,0x4e,0x69,0xe2}, +{0xcd,0x65,0xda,0xf4}, {0xd5,0x06,0x05,0xbe}, {0x1f,0xd1,0x34,0x62}, {0x8a,0xc4,0xa6,0xfe}, +{0x9d,0x34,0x2e,0x53}, {0xa0,0xa2,0xf3,0x55}, {0x32,0x05,0x8a,0xe1}, {0x75,0xa4,0xf6,0xeb}, +{0x39,0x0b,0x83,0xec}, {0xaa,0x40,0x60,0xef}, {0x06,0x5e,0x71,0x9f}, {0x51,0xbd,0x6e,0x10}, +{0xf9,0x3e,0x21,0x8a}, {0x3d,0x96,0xdd,0x06}, {0xae,0xdd,0x3e,0x05}, {0x46,0x4d,0xe6,0xbd}, +{0xb5,0x91,0x54,0x8d}, {0x05,0x71,0xc4,0x5d}, {0x6f,0x04,0x06,0xd4}, {0xff,0x60,0x50,0x15}, +{0x24,0x19,0x98,0xfb}, {0x97,0xd6,0xbd,0xe9}, {0xcc,0x89,0x40,0x43}, {0x77,0x67,0xd9,0x9e}, +{0xbd,0xb0,0xe8,0x42}, {0x88,0x07,0x89,0x8b}, {0x38,0xe7,0x19,0x5b}, {0xdb,0x79,0xc8,0xee}, +{0x47,0xa1,0x7c,0x0a}, {0xe9,0x7c,0x42,0x0f}, {0xc9,0xf8,0x84,0x1e}, {0x00,0x00,0x00,0x00}, +{0x83,0x09,0x80,0x86}, {0x48,0x32,0x2b,0xed}, {0xac,0x1e,0x11,0x70}, {0x4e,0x6c,0x5a,0x72}, +{0xfb,0xfd,0x0e,0xff}, {0x56,0x0f,0x85,0x38}, {0x1e,0x3d,0xae,0xd5}, {0x27,0x36,0x2d,0x39}, +{0x64,0x0a,0x0f,0xd9}, {0x21,0x68,0x5c,0xa6}, {0xd1,0x9b,0x5b,0x54}, {0x3a,0x24,0x36,0x2e}, +{0xb1,0x0c,0x0a,0x67}, {0x0f,0x93,0x57,0xe7}, {0xd2,0xb4,0xee,0x96}, {0x9e,0x1b,0x9b,0x91}, +{0x4f,0x80,0xc0,0xc5}, {0xa2,0x61,0xdc,0x20}, {0x69,0x5a,0x77,0x4b}, {0x16,0x1c,0x12,0x1a}, +{0x0a,0xe2,0x93,0xba}, {0xe5,0xc0,0xa0,0x2a}, {0x43,0x3c,0x22,0xe0}, {0x1d,0x12,0x1b,0x17}, +{0x0b,0x0e,0x09,0x0d}, {0xad,0xf2,0x8b,0xc7}, {0xb9,0x2d,0xb6,0xa8}, {0xc8,0x14,0x1e,0xa9}, +{0x85,0x57,0xf1,0x19}, {0x4c,0xaf,0x75,0x07}, {0xbb,0xee,0x99,0xdd}, {0xfd,0xa3,0x7f,0x60}, +{0x9f,0xf7,0x01,0x26}, {0xbc,0x5c,0x72,0xf5}, {0xc5,0x44,0x66,0x3b}, {0x34,0x5b,0xfb,0x7e}, +{0x76,0x8b,0x43,0x29}, {0xdc,0xcb,0x23,0xc6}, {0x68,0xb6,0xed,0xfc}, {0x63,0xb8,0xe4,0xf1}, +{0xca,0xd7,0x31,0xdc}, {0x10,0x42,0x63,0x85}, {0x40,0x13,0x97,0x22}, {0x20,0x84,0xc6,0x11}, +{0x7d,0x85,0x4a,0x24}, {0xf8,0xd2,0xbb,0x3d}, {0x11,0xae,0xf9,0x32}, {0x6d,0xc7,0x29,0xa1}, +{0x4b,0x1d,0x9e,0x2f}, {0xf3,0xdc,0xb2,0x30}, {0xec,0x0d,0x86,0x52}, {0xd0,0x77,0xc1,0xe3}, +{0x6c,0x2b,0xb3,0x16}, {0x99,0xa9,0x70,0xb9}, {0xfa,0x11,0x94,0x48}, {0x22,0x47,0xe9,0x64}, +{0xc4,0xa8,0xfc,0x8c}, {0x1a,0xa0,0xf0,0x3f}, {0xd8,0x56,0x7d,0x2c}, {0xef,0x22,0x33,0x90}, +{0xc7,0x87,0x49,0x4e}, {0xc1,0xd9,0x38,0xd1}, {0xfe,0x8c,0xca,0xa2}, {0x36,0x98,0xd4,0x0b}, +{0xcf,0xa6,0xf5,0x81}, {0x28,0xa5,0x7a,0xde}, {0x26,0xda,0xb7,0x8e}, {0xa4,0x3f,0xad,0xbf}, +{0xe4,0x2c,0x3a,0x9d}, {0x0d,0x50,0x78,0x92}, {0x9b,0x6a,0x5f,0xcc}, {0x62,0x54,0x7e,0x46}, +{0xc2,0xf6,0x8d,0x13}, {0xe8,0x90,0xd8,0xb8}, {0x5e,0x2e,0x39,0xf7}, {0xf5,0x82,0xc3,0xaf}, +{0xbe,0x9f,0x5d,0x80}, {0x7c,0x69,0xd0,0x93}, {0xa9,0x6f,0xd5,0x2d}, {0xb3,0xcf,0x25,0x12}, +{0x3b,0xc8,0xac,0x99}, {0xa7,0x10,0x18,0x7d}, {0x6e,0xe8,0x9c,0x63}, {0x7b,0xdb,0x3b,0xbb}, +{0x09,0xcd,0x26,0x78}, {0xf4,0x6e,0x59,0x18}, {0x01,0xec,0x9a,0xb7}, {0xa8,0x83,0x4f,0x9a}, +{0x65,0xe6,0x95,0x6e}, {0x7e,0xaa,0xff,0xe6}, {0x08,0x21,0xbc,0xcf}, {0xe6,0xef,0x15,0xe8}, +{0xd9,0xba,0xe7,0x9b}, {0xce,0x4a,0x6f,0x36}, {0xd4,0xea,0x9f,0x09}, {0xd6,0x29,0xb0,0x7c}, +{0xaf,0x31,0xa4,0xb2}, {0x31,0x2a,0x3f,0x23}, {0x30,0xc6,0xa5,0x94}, {0xc0,0x35,0xa2,0x66}, +{0x37,0x74,0x4e,0xbc}, {0xa6,0xfc,0x82,0xca}, {0xb0,0xe0,0x90,0xd0}, {0x15,0x33,0xa7,0xd8}, +{0x4a,0xf1,0x04,0x98}, {0xf7,0x41,0xec,0xda}, {0x0e,0x7f,0xcd,0x50}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x4d,0x43,0xef,0xb0}, {0x54,0xcc,0xaa,0x4d}, {0xdf,0xe4,0x96,0x04}, +{0xe3,0x9e,0xd1,0xb5}, {0x1b,0x4c,0x6a,0x88}, {0xb8,0xc1,0x2c,0x1f}, {0x7f,0x46,0x65,0x51}, +{0x04,0x9d,0x5e,0xea}, {0x5d,0x01,0x8c,0x35}, {0x73,0xfa,0x87,0x74}, {0x2e,0xfb,0x0b,0x41}, +{0x5a,0xb3,0x67,0x1d}, {0x52,0x92,0xdb,0xd2}, {0x33,0xe9,0x10,0x56}, {0x13,0x6d,0xd6,0x47}, +{0x8c,0x9a,0xd7,0x61}, {0x7a,0x37,0xa1,0x0c}, {0x8e,0x59,0xf8,0x14}, {0x89,0xeb,0x13,0x3c}, +{0xee,0xce,0xa9,0x27}, {0x35,0xb7,0x61,0xc9}, {0xed,0xe1,0x1c,0xe5}, {0x3c,0x7a,0x47,0xb1}, +{0x59,0x9c,0xd2,0xdf}, {0x3f,0x55,0xf2,0x73}, {0x79,0x18,0x14,0xce}, {0xbf,0x73,0xc7,0x37}, +{0xea,0x53,0xf7,0xcd}, {0x5b,0x5f,0xfd,0xaa}, {0x14,0xdf,0x3d,0x6f}, {0x86,0x78,0x44,0xdb}, +{0x81,0xca,0xaf,0xf3}, {0x3e,0xb9,0x68,0xc4}, {0x2c,0x38,0x24,0x34}, {0x5f,0xc2,0xa3,0x40}, +{0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95}, +{0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1}, +{0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57} + } +}; +#define T6 xT6.xt8 + +static const union xtab xT7 = { + .xt8 = { +{0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27}, +{0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3}, +{0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02}, +{0xd7,0xfc,0x4f,0xe5}, {0xcb,0xd7,0xc5,0x2a}, {0x44,0x80,0x26,0x35}, {0xa3,0x8f,0xb5,0x62}, +{0x5a,0x49,0xde,0xb1}, {0x1b,0x67,0x25,0xba}, {0x0e,0x98,0x45,0xea}, {0xc0,0xe1,0x5d,0xfe}, +{0x75,0x02,0xc3,0x2f}, {0xf0,0x12,0x81,0x4c}, {0x97,0xa3,0x8d,0x46}, {0xf9,0xc6,0x6b,0xd3}, +{0x5f,0xe7,0x03,0x8f}, {0x9c,0x95,0x15,0x92}, {0x7a,0xeb,0xbf,0x6d}, {0x59,0xda,0x95,0x52}, +{0x83,0x2d,0xd4,0xbe}, {0x21,0xd3,0x58,0x74}, {0x69,0x29,0x49,0xe0}, {0xc8,0x44,0x8e,0xc9}, +{0x89,0x6a,0x75,0xc2}, {0x79,0x78,0xf4,0x8e}, {0x3e,0x6b,0x99,0x58}, {0x71,0xdd,0x27,0xb9}, +{0x4f,0xb6,0xbe,0xe1}, {0xad,0x17,0xf0,0x88}, {0xac,0x66,0xc9,0x20}, {0x3a,0xb4,0x7d,0xce}, +{0x4a,0x18,0x63,0xdf}, {0x31,0x82,0xe5,0x1a}, {0x33,0x60,0x97,0x51}, {0x7f,0x45,0x62,0x53}, +{0x77,0xe0,0xb1,0x64}, {0xae,0x84,0xbb,0x6b}, {0xa0,0x1c,0xfe,0x81}, {0x2b,0x94,0xf9,0x08}, +{0x68,0x58,0x70,0x48}, {0xfd,0x19,0x8f,0x45}, {0x6c,0x87,0x94,0xde}, {0xf8,0xb7,0x52,0x7b}, +{0xd3,0x23,0xab,0x73}, {0x02,0xe2,0x72,0x4b}, {0x8f,0x57,0xe3,0x1f}, {0xab,0x2a,0x66,0x55}, +{0x28,0x07,0xb2,0xeb}, {0xc2,0x03,0x2f,0xb5}, {0x7b,0x9a,0x86,0xc5}, {0x08,0xa5,0xd3,0x37}, +{0x87,0xf2,0x30,0x28}, {0xa5,0xb2,0x23,0xbf}, {0x6a,0xba,0x02,0x03}, {0x82,0x5c,0xed,0x16}, +{0x1c,0x2b,0x8a,0xcf}, {0xb4,0x92,0xa7,0x79}, {0xf2,0xf0,0xf3,0x07}, {0xe2,0xa1,0x4e,0x69}, +{0xf4,0xcd,0x65,0xda}, {0xbe,0xd5,0x06,0x05}, {0x62,0x1f,0xd1,0x34}, {0xfe,0x8a,0xc4,0xa6}, +{0x53,0x9d,0x34,0x2e}, {0x55,0xa0,0xa2,0xf3}, {0xe1,0x32,0x05,0x8a}, {0xeb,0x75,0xa4,0xf6}, +{0xec,0x39,0x0b,0x83}, {0xef,0xaa,0x40,0x60}, {0x9f,0x06,0x5e,0x71}, {0x10,0x51,0xbd,0x6e}, +{0x8a,0xf9,0x3e,0x21}, {0x06,0x3d,0x96,0xdd}, {0x05,0xae,0xdd,0x3e}, {0xbd,0x46,0x4d,0xe6}, +{0x8d,0xb5,0x91,0x54}, {0x5d,0x05,0x71,0xc4}, {0xd4,0x6f,0x04,0x06}, {0x15,0xff,0x60,0x50}, +{0xfb,0x24,0x19,0x98}, {0xe9,0x97,0xd6,0xbd}, {0x43,0xcc,0x89,0x40}, {0x9e,0x77,0x67,0xd9}, +{0x42,0xbd,0xb0,0xe8}, {0x8b,0x88,0x07,0x89}, {0x5b,0x38,0xe7,0x19}, {0xee,0xdb,0x79,0xc8}, +{0x0a,0x47,0xa1,0x7c}, {0x0f,0xe9,0x7c,0x42}, {0x1e,0xc9,0xf8,0x84}, {0x00,0x00,0x00,0x00}, +{0x86,0x83,0x09,0x80}, {0xed,0x48,0x32,0x2b}, {0x70,0xac,0x1e,0x11}, {0x72,0x4e,0x6c,0x5a}, +{0xff,0xfb,0xfd,0x0e}, {0x38,0x56,0x0f,0x85}, {0xd5,0x1e,0x3d,0xae}, {0x39,0x27,0x36,0x2d}, +{0xd9,0x64,0x0a,0x0f}, {0xa6,0x21,0x68,0x5c}, {0x54,0xd1,0x9b,0x5b}, {0x2e,0x3a,0x24,0x36}, +{0x67,0xb1,0x0c,0x0a}, {0xe7,0x0f,0x93,0x57}, {0x96,0xd2,0xb4,0xee}, {0x91,0x9e,0x1b,0x9b}, +{0xc5,0x4f,0x80,0xc0}, {0x20,0xa2,0x61,0xdc}, {0x4b,0x69,0x5a,0x77}, {0x1a,0x16,0x1c,0x12}, +{0xba,0x0a,0xe2,0x93}, {0x2a,0xe5,0xc0,0xa0}, {0xe0,0x43,0x3c,0x22}, {0x17,0x1d,0x12,0x1b}, +{0x0d,0x0b,0x0e,0x09}, {0xc7,0xad,0xf2,0x8b}, {0xa8,0xb9,0x2d,0xb6}, {0xa9,0xc8,0x14,0x1e}, +{0x19,0x85,0x57,0xf1}, {0x07,0x4c,0xaf,0x75}, {0xdd,0xbb,0xee,0x99}, {0x60,0xfd,0xa3,0x7f}, +{0x26,0x9f,0xf7,0x01}, {0xf5,0xbc,0x5c,0x72}, {0x3b,0xc5,0x44,0x66}, {0x7e,0x34,0x5b,0xfb}, +{0x29,0x76,0x8b,0x43}, {0xc6,0xdc,0xcb,0x23}, {0xfc,0x68,0xb6,0xed}, {0xf1,0x63,0xb8,0xe4}, +{0xdc,0xca,0xd7,0x31}, {0x85,0x10,0x42,0x63}, {0x22,0x40,0x13,0x97}, {0x11,0x20,0x84,0xc6}, +{0x24,0x7d,0x85,0x4a}, {0x3d,0xf8,0xd2,0xbb}, {0x32,0x11,0xae,0xf9}, {0xa1,0x6d,0xc7,0x29}, +{0x2f,0x4b,0x1d,0x9e}, {0x30,0xf3,0xdc,0xb2}, {0x52,0xec,0x0d,0x86}, {0xe3,0xd0,0x77,0xc1}, +{0x16,0x6c,0x2b,0xb3}, {0xb9,0x99,0xa9,0x70}, {0x48,0xfa,0x11,0x94}, {0x64,0x22,0x47,0xe9}, +{0x8c,0xc4,0xa8,0xfc}, {0x3f,0x1a,0xa0,0xf0}, {0x2c,0xd8,0x56,0x7d}, {0x90,0xef,0x22,0x33}, +{0x4e,0xc7,0x87,0x49}, {0xd1,0xc1,0xd9,0x38}, {0xa2,0xfe,0x8c,0xca}, {0x0b,0x36,0x98,0xd4}, +{0x81,0xcf,0xa6,0xf5}, {0xde,0x28,0xa5,0x7a}, {0x8e,0x26,0xda,0xb7}, {0xbf,0xa4,0x3f,0xad}, +{0x9d,0xe4,0x2c,0x3a}, {0x92,0x0d,0x50,0x78}, {0xcc,0x9b,0x6a,0x5f}, {0x46,0x62,0x54,0x7e}, +{0x13,0xc2,0xf6,0x8d}, {0xb8,0xe8,0x90,0xd8}, {0xf7,0x5e,0x2e,0x39}, {0xaf,0xf5,0x82,0xc3}, +{0x80,0xbe,0x9f,0x5d}, {0x93,0x7c,0x69,0xd0}, {0x2d,0xa9,0x6f,0xd5}, {0x12,0xb3,0xcf,0x25}, +{0x99,0x3b,0xc8,0xac}, {0x7d,0xa7,0x10,0x18}, {0x63,0x6e,0xe8,0x9c}, {0xbb,0x7b,0xdb,0x3b}, +{0x78,0x09,0xcd,0x26}, {0x18,0xf4,0x6e,0x59}, {0xb7,0x01,0xec,0x9a}, {0x9a,0xa8,0x83,0x4f}, +{0x6e,0x65,0xe6,0x95}, {0xe6,0x7e,0xaa,0xff}, {0xcf,0x08,0x21,0xbc}, {0xe8,0xe6,0xef,0x15}, +{0x9b,0xd9,0xba,0xe7}, {0x36,0xce,0x4a,0x6f}, {0x09,0xd4,0xea,0x9f}, {0x7c,0xd6,0x29,0xb0}, +{0xb2,0xaf,0x31,0xa4}, {0x23,0x31,0x2a,0x3f}, {0x94,0x30,0xc6,0xa5}, {0x66,0xc0,0x35,0xa2}, +{0xbc,0x37,0x74,0x4e}, {0xca,0xa6,0xfc,0x82}, {0xd0,0xb0,0xe0,0x90}, {0xd8,0x15,0x33,0xa7}, +{0x98,0x4a,0xf1,0x04}, {0xda,0xf7,0x41,0xec}, {0x50,0x0e,0x7f,0xcd}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xb0,0x4d,0x43,0xef}, {0x4d,0x54,0xcc,0xaa}, {0x04,0xdf,0xe4,0x96}, +{0xb5,0xe3,0x9e,0xd1}, {0x88,0x1b,0x4c,0x6a}, {0x1f,0xb8,0xc1,0x2c}, {0x51,0x7f,0x46,0x65}, +{0xea,0x04,0x9d,0x5e}, {0x35,0x5d,0x01,0x8c}, {0x74,0x73,0xfa,0x87}, {0x41,0x2e,0xfb,0x0b}, +{0x1d,0x5a,0xb3,0x67}, {0xd2,0x52,0x92,0xdb}, {0x56,0x33,0xe9,0x10}, {0x47,0x13,0x6d,0xd6}, +{0x61,0x8c,0x9a,0xd7}, {0x0c,0x7a,0x37,0xa1}, {0x14,0x8e,0x59,0xf8}, {0x3c,0x89,0xeb,0x13}, +{0x27,0xee,0xce,0xa9}, {0xc9,0x35,0xb7,0x61}, {0xe5,0xed,0xe1,0x1c}, {0xb1,0x3c,0x7a,0x47}, +{0xdf,0x59,0x9c,0xd2}, {0x73,0x3f,0x55,0xf2}, {0xce,0x79,0x18,0x14}, {0x37,0xbf,0x73,0xc7}, +{0xcd,0xea,0x53,0xf7}, {0xaa,0x5b,0x5f,0xfd}, {0x6f,0x14,0xdf,0x3d}, {0xdb,0x86,0x78,0x44}, +{0xf3,0x81,0xca,0xaf}, {0xc4,0x3e,0xb9,0x68}, {0x34,0x2c,0x38,0x24}, {0x40,0x5f,0xc2,0xa3}, +{0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d}, +{0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56}, +{0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8} + } +}; +#define T7 xT7.xt8 + +static const union xtab xT8 = { + .xt8 = { +{0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a}, +{0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b}, +{0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5}, +{0xe5,0xd7,0xfc,0x4f}, {0x2a,0xcb,0xd7,0xc5}, {0x35,0x44,0x80,0x26}, {0x62,0xa3,0x8f,0xb5}, +{0xb1,0x5a,0x49,0xde}, {0xba,0x1b,0x67,0x25}, {0xea,0x0e,0x98,0x45}, {0xfe,0xc0,0xe1,0x5d}, +{0x2f,0x75,0x02,0xc3}, {0x4c,0xf0,0x12,0x81}, {0x46,0x97,0xa3,0x8d}, {0xd3,0xf9,0xc6,0x6b}, +{0x8f,0x5f,0xe7,0x03}, {0x92,0x9c,0x95,0x15}, {0x6d,0x7a,0xeb,0xbf}, {0x52,0x59,0xda,0x95}, +{0xbe,0x83,0x2d,0xd4}, {0x74,0x21,0xd3,0x58}, {0xe0,0x69,0x29,0x49}, {0xc9,0xc8,0x44,0x8e}, +{0xc2,0x89,0x6a,0x75}, {0x8e,0x79,0x78,0xf4}, {0x58,0x3e,0x6b,0x99}, {0xb9,0x71,0xdd,0x27}, +{0xe1,0x4f,0xb6,0xbe}, {0x88,0xad,0x17,0xf0}, {0x20,0xac,0x66,0xc9}, {0xce,0x3a,0xb4,0x7d}, +{0xdf,0x4a,0x18,0x63}, {0x1a,0x31,0x82,0xe5}, {0x51,0x33,0x60,0x97}, {0x53,0x7f,0x45,0x62}, +{0x64,0x77,0xe0,0xb1}, {0x6b,0xae,0x84,0xbb}, {0x81,0xa0,0x1c,0xfe}, {0x08,0x2b,0x94,0xf9}, +{0x48,0x68,0x58,0x70}, {0x45,0xfd,0x19,0x8f}, {0xde,0x6c,0x87,0x94}, {0x7b,0xf8,0xb7,0x52}, +{0x73,0xd3,0x23,0xab}, {0x4b,0x02,0xe2,0x72}, {0x1f,0x8f,0x57,0xe3}, {0x55,0xab,0x2a,0x66}, +{0xeb,0x28,0x07,0xb2}, {0xb5,0xc2,0x03,0x2f}, {0xc5,0x7b,0x9a,0x86}, {0x37,0x08,0xa5,0xd3}, +{0x28,0x87,0xf2,0x30}, {0xbf,0xa5,0xb2,0x23}, {0x03,0x6a,0xba,0x02}, {0x16,0x82,0x5c,0xed}, +{0xcf,0x1c,0x2b,0x8a}, {0x79,0xb4,0x92,0xa7}, {0x07,0xf2,0xf0,0xf3}, {0x69,0xe2,0xa1,0x4e}, +{0xda,0xf4,0xcd,0x65}, {0x05,0xbe,0xd5,0x06}, {0x34,0x62,0x1f,0xd1}, {0xa6,0xfe,0x8a,0xc4}, +{0x2e,0x53,0x9d,0x34}, {0xf3,0x55,0xa0,0xa2}, {0x8a,0xe1,0x32,0x05}, {0xf6,0xeb,0x75,0xa4}, +{0x83,0xec,0x39,0x0b}, {0x60,0xef,0xaa,0x40}, {0x71,0x9f,0x06,0x5e}, {0x6e,0x10,0x51,0xbd}, +{0x21,0x8a,0xf9,0x3e}, {0xdd,0x06,0x3d,0x96}, {0x3e,0x05,0xae,0xdd}, {0xe6,0xbd,0x46,0x4d}, +{0x54,0x8d,0xb5,0x91}, {0xc4,0x5d,0x05,0x71}, {0x06,0xd4,0x6f,0x04}, {0x50,0x15,0xff,0x60}, +{0x98,0xfb,0x24,0x19}, {0xbd,0xe9,0x97,0xd6}, {0x40,0x43,0xcc,0x89}, {0xd9,0x9e,0x77,0x67}, +{0xe8,0x42,0xbd,0xb0}, {0x89,0x8b,0x88,0x07}, {0x19,0x5b,0x38,0xe7}, {0xc8,0xee,0xdb,0x79}, +{0x7c,0x0a,0x47,0xa1}, {0x42,0x0f,0xe9,0x7c}, {0x84,0x1e,0xc9,0xf8}, {0x00,0x00,0x00,0x00}, +{0x80,0x86,0x83,0x09}, {0x2b,0xed,0x48,0x32}, {0x11,0x70,0xac,0x1e}, {0x5a,0x72,0x4e,0x6c}, +{0x0e,0xff,0xfb,0xfd}, {0x85,0x38,0x56,0x0f}, {0xae,0xd5,0x1e,0x3d}, {0x2d,0x39,0x27,0x36}, +{0x0f,0xd9,0x64,0x0a}, {0x5c,0xa6,0x21,0x68}, {0x5b,0x54,0xd1,0x9b}, {0x36,0x2e,0x3a,0x24}, +{0x0a,0x67,0xb1,0x0c}, {0x57,0xe7,0x0f,0x93}, {0xee,0x96,0xd2,0xb4}, {0x9b,0x91,0x9e,0x1b}, +{0xc0,0xc5,0x4f,0x80}, {0xdc,0x20,0xa2,0x61}, {0x77,0x4b,0x69,0x5a}, {0x12,0x1a,0x16,0x1c}, +{0x93,0xba,0x0a,0xe2}, {0xa0,0x2a,0xe5,0xc0}, {0x22,0xe0,0x43,0x3c}, {0x1b,0x17,0x1d,0x12}, +{0x09,0x0d,0x0b,0x0e}, {0x8b,0xc7,0xad,0xf2}, {0xb6,0xa8,0xb9,0x2d}, {0x1e,0xa9,0xc8,0x14}, +{0xf1,0x19,0x85,0x57}, {0x75,0x07,0x4c,0xaf}, {0x99,0xdd,0xbb,0xee}, {0x7f,0x60,0xfd,0xa3}, +{0x01,0x26,0x9f,0xf7}, {0x72,0xf5,0xbc,0x5c}, {0x66,0x3b,0xc5,0x44}, {0xfb,0x7e,0x34,0x5b}, +{0x43,0x29,0x76,0x8b}, {0x23,0xc6,0xdc,0xcb}, {0xed,0xfc,0x68,0xb6}, {0xe4,0xf1,0x63,0xb8}, +{0x31,0xdc,0xca,0xd7}, {0x63,0x85,0x10,0x42}, {0x97,0x22,0x40,0x13}, {0xc6,0x11,0x20,0x84}, +{0x4a,0x24,0x7d,0x85}, {0xbb,0x3d,0xf8,0xd2}, {0xf9,0x32,0x11,0xae}, {0x29,0xa1,0x6d,0xc7}, +{0x9e,0x2f,0x4b,0x1d}, {0xb2,0x30,0xf3,0xdc}, {0x86,0x52,0xec,0x0d}, {0xc1,0xe3,0xd0,0x77}, +{0xb3,0x16,0x6c,0x2b}, {0x70,0xb9,0x99,0xa9}, {0x94,0x48,0xfa,0x11}, {0xe9,0x64,0x22,0x47}, +{0xfc,0x8c,0xc4,0xa8}, {0xf0,0x3f,0x1a,0xa0}, {0x7d,0x2c,0xd8,0x56}, {0x33,0x90,0xef,0x22}, +{0x49,0x4e,0xc7,0x87}, {0x38,0xd1,0xc1,0xd9}, {0xca,0xa2,0xfe,0x8c}, {0xd4,0x0b,0x36,0x98}, +{0xf5,0x81,0xcf,0xa6}, {0x7a,0xde,0x28,0xa5}, {0xb7,0x8e,0x26,0xda}, {0xad,0xbf,0xa4,0x3f}, +{0x3a,0x9d,0xe4,0x2c}, {0x78,0x92,0x0d,0x50}, {0x5f,0xcc,0x9b,0x6a}, {0x7e,0x46,0x62,0x54}, +{0x8d,0x13,0xc2,0xf6}, {0xd8,0xb8,0xe8,0x90}, {0x39,0xf7,0x5e,0x2e}, {0xc3,0xaf,0xf5,0x82}, +{0x5d,0x80,0xbe,0x9f}, {0xd0,0x93,0x7c,0x69}, {0xd5,0x2d,0xa9,0x6f}, {0x25,0x12,0xb3,0xcf}, +{0xac,0x99,0x3b,0xc8}, {0x18,0x7d,0xa7,0x10}, {0x9c,0x63,0x6e,0xe8}, {0x3b,0xbb,0x7b,0xdb}, +{0x26,0x78,0x09,0xcd}, {0x59,0x18,0xf4,0x6e}, {0x9a,0xb7,0x01,0xec}, {0x4f,0x9a,0xa8,0x83}, +{0x95,0x6e,0x65,0xe6}, {0xff,0xe6,0x7e,0xaa}, {0xbc,0xcf,0x08,0x21}, {0x15,0xe8,0xe6,0xef}, +{0xe7,0x9b,0xd9,0xba}, {0x6f,0x36,0xce,0x4a}, {0x9f,0x09,0xd4,0xea}, {0xb0,0x7c,0xd6,0x29}, +{0xa4,0xb2,0xaf,0x31}, {0x3f,0x23,0x31,0x2a}, {0xa5,0x94,0x30,0xc6}, {0xa2,0x66,0xc0,0x35}, +{0x4e,0xbc,0x37,0x74}, {0x82,0xca,0xa6,0xfc}, {0x90,0xd0,0xb0,0xe0}, {0xa7,0xd8,0x15,0x33}, +{0x04,0x98,0x4a,0xf1}, {0xec,0xda,0xf7,0x41}, {0xcd,0x50,0x0e,0x7f}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0xef,0xb0,0x4d,0x43}, {0xaa,0x4d,0x54,0xcc}, {0x96,0x04,0xdf,0xe4}, +{0xd1,0xb5,0xe3,0x9e}, {0x6a,0x88,0x1b,0x4c}, {0x2c,0x1f,0xb8,0xc1}, {0x65,0x51,0x7f,0x46}, +{0x5e,0xea,0x04,0x9d}, {0x8c,0x35,0x5d,0x01}, {0x87,0x74,0x73,0xfa}, {0x0b,0x41,0x2e,0xfb}, +{0x67,0x1d,0x5a,0xb3}, {0xdb,0xd2,0x52,0x92}, {0x10,0x56,0x33,0xe9}, {0xd6,0x47,0x13,0x6d}, +{0xd7,0x61,0x8c,0x9a}, {0xa1,0x0c,0x7a,0x37}, {0xf8,0x14,0x8e,0x59}, {0x13,0x3c,0x89,0xeb}, +{0xa9,0x27,0xee,0xce}, {0x61,0xc9,0x35,0xb7}, {0x1c,0xe5,0xed,0xe1}, {0x47,0xb1,0x3c,0x7a}, +{0xd2,0xdf,0x59,0x9c}, {0xf2,0x73,0x3f,0x55}, {0x14,0xce,0x79,0x18}, {0xc7,0x37,0xbf,0x73}, +{0xf7,0xcd,0xea,0x53}, {0xfd,0xaa,0x5b,0x5f}, {0x3d,0x6f,0x14,0xdf}, {0x44,0xdb,0x86,0x78}, +{0xaf,0xf3,0x81,0xca}, {0x68,0xc4,0x3e,0xb9}, {0x24,0x34,0x2c,0x38}, {0xa3,0x40,0x5f,0xc2}, +{0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff}, +{0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64}, +{0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0} + } +}; +#define T8 xT8.xt8 + +static const word8 S5[256] = { +0x52,0x09,0x6a,0xd5, +0x30,0x36,0xa5,0x38, +0xbf,0x40,0xa3,0x9e, +0x81,0xf3,0xd7,0xfb, +0x7c,0xe3,0x39,0x82, +0x9b,0x2f,0xff,0x87, +0x34,0x8e,0x43,0x44, +0xc4,0xde,0xe9,0xcb, +0x54,0x7b,0x94,0x32, +0xa6,0xc2,0x23,0x3d, +0xee,0x4c,0x95,0x0b, +0x42,0xfa,0xc3,0x4e, +0x08,0x2e,0xa1,0x66, +0x28,0xd9,0x24,0xb2, +0x76,0x5b,0xa2,0x49, +0x6d,0x8b,0xd1,0x25, +0x72,0xf8,0xf6,0x64, +0x86,0x68,0x98,0x16, +0xd4,0xa4,0x5c,0xcc, +0x5d,0x65,0xb6,0x92, +0x6c,0x70,0x48,0x50, +0xfd,0xed,0xb9,0xda, +0x5e,0x15,0x46,0x57, +0xa7,0x8d,0x9d,0x84, +0x90,0xd8,0xab,0x00, +0x8c,0xbc,0xd3,0x0a, +0xf7,0xe4,0x58,0x05, +0xb8,0xb3,0x45,0x06, +0xd0,0x2c,0x1e,0x8f, +0xca,0x3f,0x0f,0x02, +0xc1,0xaf,0xbd,0x03, +0x01,0x13,0x8a,0x6b, +0x3a,0x91,0x11,0x41, +0x4f,0x67,0xdc,0xea, +0x97,0xf2,0xcf,0xce, +0xf0,0xb4,0xe6,0x73, +0x96,0xac,0x74,0x22, +0xe7,0xad,0x35,0x85, +0xe2,0xf9,0x37,0xe8, +0x1c,0x75,0xdf,0x6e, +0x47,0xf1,0x1a,0x71, +0x1d,0x29,0xc5,0x89, +0x6f,0xb7,0x62,0x0e, +0xaa,0x18,0xbe,0x1b, +0xfc,0x56,0x3e,0x4b, +0xc6,0xd2,0x79,0x20, +0x9a,0xdb,0xc0,0xfe, +0x78,0xcd,0x5a,0xf4, +0x1f,0xdd,0xa8,0x33, +0x88,0x07,0xc7,0x31, +0xb1,0x12,0x10,0x59, +0x27,0x80,0xec,0x5f, +0x60,0x51,0x7f,0xa9, +0x19,0xb5,0x4a,0x0d, +0x2d,0xe5,0x7a,0x9f, +0x93,0xc9,0x9c,0xef, +0xa0,0xe0,0x3b,0x4d, +0xae,0x2a,0xf5,0xb0, +0xc8,0xeb,0xbb,0x3c, +0x83,0x53,0x99,0x61, +0x17,0x2b,0x04,0x7e, +0xba,0x77,0xd6,0x26, +0xe1,0x69,0x14,0x63, +0x55,0x21,0x0c,0x7d +}; + +static const union xtab xU1 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d}, +{0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31}, +{0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45}, +{0x48,0x6c,0x5c,0x74}, {0x46,0x65,0x51,0x7f}, {0x54,0x7e,0x46,0x62}, {0x5a,0x77,0x4b,0x69}, +{0xe0,0x90,0xd0,0xb0}, {0xee,0x99,0xdd,0xbb}, {0xfc,0x82,0xca,0xa6}, {0xf2,0x8b,0xc7,0xad}, +{0xd8,0xb4,0xe4,0x9c}, {0xd6,0xbd,0xe9,0x97}, {0xc4,0xa6,0xfe,0x8a}, {0xca,0xaf,0xf3,0x81}, +{0x90,0xd8,0xb8,0xe8}, {0x9e,0xd1,0xb5,0xe3}, {0x8c,0xca,0xa2,0xfe}, {0x82,0xc3,0xaf,0xf5}, +{0xa8,0xfc,0x8c,0xc4}, {0xa6,0xf5,0x81,0xcf}, {0xb4,0xee,0x96,0xd2}, {0xba,0xe7,0x9b,0xd9}, +{0xdb,0x3b,0xbb,0x7b}, {0xd5,0x32,0xb6,0x70}, {0xc7,0x29,0xa1,0x6d}, {0xc9,0x20,0xac,0x66}, +{0xe3,0x1f,0x8f,0x57}, {0xed,0x16,0x82,0x5c}, {0xff,0x0d,0x95,0x41}, {0xf1,0x04,0x98,0x4a}, +{0xab,0x73,0xd3,0x23}, {0xa5,0x7a,0xde,0x28}, {0xb7,0x61,0xc9,0x35}, {0xb9,0x68,0xc4,0x3e}, +{0x93,0x57,0xe7,0x0f}, {0x9d,0x5e,0xea,0x04}, {0x8f,0x45,0xfd,0x19}, {0x81,0x4c,0xf0,0x12}, +{0x3b,0xab,0x6b,0xcb}, {0x35,0xa2,0x66,0xc0}, {0x27,0xb9,0x71,0xdd}, {0x29,0xb0,0x7c,0xd6}, +{0x03,0x8f,0x5f,0xe7}, {0x0d,0x86,0x52,0xec}, {0x1f,0x9d,0x45,0xf1}, {0x11,0x94,0x48,0xfa}, +{0x4b,0xe3,0x03,0x93}, {0x45,0xea,0x0e,0x98}, {0x57,0xf1,0x19,0x85}, {0x59,0xf8,0x14,0x8e}, +{0x73,0xc7,0x37,0xbf}, {0x7d,0xce,0x3a,0xb4}, {0x6f,0xd5,0x2d,0xa9}, {0x61,0xdc,0x20,0xa2}, +{0xad,0x76,0x6d,0xf6}, {0xa3,0x7f,0x60,0xfd}, {0xb1,0x64,0x77,0xe0}, {0xbf,0x6d,0x7a,0xeb}, +{0x95,0x52,0x59,0xda}, {0x9b,0x5b,0x54,0xd1}, {0x89,0x40,0x43,0xcc}, {0x87,0x49,0x4e,0xc7}, +{0xdd,0x3e,0x05,0xae}, {0xd3,0x37,0x08,0xa5}, {0xc1,0x2c,0x1f,0xb8}, {0xcf,0x25,0x12,0xb3}, +{0xe5,0x1a,0x31,0x82}, {0xeb,0x13,0x3c,0x89}, {0xf9,0x08,0x2b,0x94}, {0xf7,0x01,0x26,0x9f}, +{0x4d,0xe6,0xbd,0x46}, {0x43,0xef,0xb0,0x4d}, {0x51,0xf4,0xa7,0x50}, {0x5f,0xfd,0xaa,0x5b}, +{0x75,0xc2,0x89,0x6a}, {0x7b,0xcb,0x84,0x61}, {0x69,0xd0,0x93,0x7c}, {0x67,0xd9,0x9e,0x77}, +{0x3d,0xae,0xd5,0x1e}, {0x33,0xa7,0xd8,0x15}, {0x21,0xbc,0xcf,0x08}, {0x2f,0xb5,0xc2,0x03}, +{0x05,0x8a,0xe1,0x32}, {0x0b,0x83,0xec,0x39}, {0x19,0x98,0xfb,0x24}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x78,0x44,0xdb,0x86}, {0x6a,0x5f,0xcc,0x9b}, {0x64,0x56,0xc1,0x90}, +{0x4e,0x69,0xe2,0xa1}, {0x40,0x60,0xef,0xaa}, {0x52,0x7b,0xf8,0xb7}, {0x5c,0x72,0xf5,0xbc}, +{0x06,0x05,0xbe,0xd5}, {0x08,0x0c,0xb3,0xde}, {0x1a,0x17,0xa4,0xc3}, {0x14,0x1e,0xa9,0xc8}, +{0x3e,0x21,0x8a,0xf9}, {0x30,0x28,0x87,0xf2}, {0x22,0x33,0x90,0xef}, {0x2c,0x3a,0x9d,0xe4}, +{0x96,0xdd,0x06,0x3d}, {0x98,0xd4,0x0b,0x36}, {0x8a,0xcf,0x1c,0x2b}, {0x84,0xc6,0x11,0x20}, +{0xae,0xf9,0x32,0x11}, {0xa0,0xf0,0x3f,0x1a}, {0xb2,0xeb,0x28,0x07}, {0xbc,0xe2,0x25,0x0c}, +{0xe6,0x95,0x6e,0x65}, {0xe8,0x9c,0x63,0x6e}, {0xfa,0x87,0x74,0x73}, {0xf4,0x8e,0x79,0x78}, +{0xde,0xb1,0x5a,0x49}, {0xd0,0xb8,0x57,0x42}, {0xc2,0xa3,0x40,0x5f}, {0xcc,0xaa,0x4d,0x54}, +{0x41,0xec,0xda,0xf7}, {0x4f,0xe5,0xd7,0xfc}, {0x5d,0xfe,0xc0,0xe1}, {0x53,0xf7,0xcd,0xea}, +{0x79,0xc8,0xee,0xdb}, {0x77,0xc1,0xe3,0xd0}, {0x65,0xda,0xf4,0xcd}, {0x6b,0xd3,0xf9,0xc6}, +{0x31,0xa4,0xb2,0xaf}, {0x3f,0xad,0xbf,0xa4}, {0x2d,0xb6,0xa8,0xb9}, {0x23,0xbf,0xa5,0xb2}, +{0x09,0x80,0x86,0x83}, {0x07,0x89,0x8b,0x88}, {0x15,0x92,0x9c,0x95}, {0x1b,0x9b,0x91,0x9e}, +{0xa1,0x7c,0x0a,0x47}, {0xaf,0x75,0x07,0x4c}, {0xbd,0x6e,0x10,0x51}, {0xb3,0x67,0x1d,0x5a}, +{0x99,0x58,0x3e,0x6b}, {0x97,0x51,0x33,0x60}, {0x85,0x4a,0x24,0x7d}, {0x8b,0x43,0x29,0x76}, +{0xd1,0x34,0x62,0x1f}, {0xdf,0x3d,0x6f,0x14}, {0xcd,0x26,0x78,0x09}, {0xc3,0x2f,0x75,0x02}, +{0xe9,0x10,0x56,0x33}, {0xe7,0x19,0x5b,0x38}, {0xf5,0x02,0x4c,0x25}, {0xfb,0x0b,0x41,0x2e}, +{0x9a,0xd7,0x61,0x8c}, {0x94,0xde,0x6c,0x87}, {0x86,0xc5,0x7b,0x9a}, {0x88,0xcc,0x76,0x91}, +{0xa2,0xf3,0x55,0xa0}, {0xac,0xfa,0x58,0xab}, {0xbe,0xe1,0x4f,0xb6}, {0xb0,0xe8,0x42,0xbd}, +{0xea,0x9f,0x09,0xd4}, {0xe4,0x96,0x04,0xdf}, {0xf6,0x8d,0x13,0xc2}, {0xf8,0x84,0x1e,0xc9}, +{0xd2,0xbb,0x3d,0xf8}, {0xdc,0xb2,0x30,0xf3}, {0xce,0xa9,0x27,0xee}, {0xc0,0xa0,0x2a,0xe5}, +{0x7a,0x47,0xb1,0x3c}, {0x74,0x4e,0xbc,0x37}, {0x66,0x55,0xab,0x2a}, {0x68,0x5c,0xa6,0x21}, +{0x42,0x63,0x85,0x10}, {0x4c,0x6a,0x88,0x1b}, {0x5e,0x71,0x9f,0x06}, {0x50,0x78,0x92,0x0d}, +{0x0a,0x0f,0xd9,0x64}, {0x04,0x06,0xd4,0x6f}, {0x16,0x1d,0xc3,0x72}, {0x18,0x14,0xce,0x79}, +{0x32,0x2b,0xed,0x48}, {0x3c,0x22,0xe0,0x43}, {0x2e,0x39,0xf7,0x5e}, {0x20,0x30,0xfa,0x55}, +{0xec,0x9a,0xb7,0x01}, {0xe2,0x93,0xba,0x0a}, {0xf0,0x88,0xad,0x17}, {0xfe,0x81,0xa0,0x1c}, +{0xd4,0xbe,0x83,0x2d}, {0xda,0xb7,0x8e,0x26}, {0xc8,0xac,0x99,0x3b}, {0xc6,0xa5,0x94,0x30}, +{0x9c,0xd2,0xdf,0x59}, {0x92,0xdb,0xd2,0x52}, {0x80,0xc0,0xc5,0x4f}, {0x8e,0xc9,0xc8,0x44}, +{0xa4,0xf6,0xeb,0x75}, {0xaa,0xff,0xe6,0x7e}, {0xb8,0xe4,0xf1,0x63}, {0xb6,0xed,0xfc,0x68}, +{0x0c,0x0a,0x67,0xb1}, {0x02,0x03,0x6a,0xba}, {0x10,0x18,0x7d,0xa7}, {0x1e,0x11,0x70,0xac}, +{0x34,0x2e,0x53,0x9d}, {0x3a,0x27,0x5e,0x96}, {0x28,0x3c,0x49,0x8b}, {0x26,0x35,0x44,0x80}, +{0x7c,0x42,0x0f,0xe9}, {0x72,0x4b,0x02,0xe2}, {0x60,0x50,0x15,0xff}, {0x6e,0x59,0x18,0xf4}, +{0x44,0x66,0x3b,0xc5}, {0x4a,0x6f,0x36,0xce}, {0x58,0x74,0x21,0xd3}, {0x56,0x7d,0x2c,0xd8}, +{0x37,0xa1,0x0c,0x7a}, {0x39,0xa8,0x01,0x71}, {0x2b,0xb3,0x16,0x6c}, {0x25,0xba,0x1b,0x67}, +{0x0f,0x85,0x38,0x56}, {0x01,0x8c,0x35,0x5d}, {0x13,0x97,0x22,0x40}, {0x1d,0x9e,0x2f,0x4b}, +{0x47,0xe9,0x64,0x22}, {0x49,0xe0,0x69,0x29}, {0x5b,0xfb,0x7e,0x34}, {0x55,0xf2,0x73,0x3f}, +{0x7f,0xcd,0x50,0x0e}, {0x71,0xc4,0x5d,0x05}, {0x63,0xdf,0x4a,0x18}, {0x6d,0xd6,0x47,0x13}, +{0xd7,0x31,0xdc,0xca}, {0xd9,0x38,0xd1,0xc1}, {0xcb,0x23,0xc6,0xdc}, {0xc5,0x2a,0xcb,0xd7}, +{0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb}, +{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f}, +{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3} + } +}; +#define U1 xU1.xt8 + +static const union xtab xU2 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17}, +{0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23}, +{0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f}, +{0x74,0x48,0x6c,0x5c}, {0x7f,0x46,0x65,0x51}, {0x62,0x54,0x7e,0x46}, {0x69,0x5a,0x77,0x4b}, +{0xb0,0xe0,0x90,0xd0}, {0xbb,0xee,0x99,0xdd}, {0xa6,0xfc,0x82,0xca}, {0xad,0xf2,0x8b,0xc7}, +{0x9c,0xd8,0xb4,0xe4}, {0x97,0xd6,0xbd,0xe9}, {0x8a,0xc4,0xa6,0xfe}, {0x81,0xca,0xaf,0xf3}, +{0xe8,0x90,0xd8,0xb8}, {0xe3,0x9e,0xd1,0xb5}, {0xfe,0x8c,0xca,0xa2}, {0xf5,0x82,0xc3,0xaf}, +{0xc4,0xa8,0xfc,0x8c}, {0xcf,0xa6,0xf5,0x81}, {0xd2,0xb4,0xee,0x96}, {0xd9,0xba,0xe7,0x9b}, +{0x7b,0xdb,0x3b,0xbb}, {0x70,0xd5,0x32,0xb6}, {0x6d,0xc7,0x29,0xa1}, {0x66,0xc9,0x20,0xac}, +{0x57,0xe3,0x1f,0x8f}, {0x5c,0xed,0x16,0x82}, {0x41,0xff,0x0d,0x95}, {0x4a,0xf1,0x04,0x98}, +{0x23,0xab,0x73,0xd3}, {0x28,0xa5,0x7a,0xde}, {0x35,0xb7,0x61,0xc9}, {0x3e,0xb9,0x68,0xc4}, +{0x0f,0x93,0x57,0xe7}, {0x04,0x9d,0x5e,0xea}, {0x19,0x8f,0x45,0xfd}, {0x12,0x81,0x4c,0xf0}, +{0xcb,0x3b,0xab,0x6b}, {0xc0,0x35,0xa2,0x66}, {0xdd,0x27,0xb9,0x71}, {0xd6,0x29,0xb0,0x7c}, +{0xe7,0x03,0x8f,0x5f}, {0xec,0x0d,0x86,0x52}, {0xf1,0x1f,0x9d,0x45}, {0xfa,0x11,0x94,0x48}, +{0x93,0x4b,0xe3,0x03}, {0x98,0x45,0xea,0x0e}, {0x85,0x57,0xf1,0x19}, {0x8e,0x59,0xf8,0x14}, +{0xbf,0x73,0xc7,0x37}, {0xb4,0x7d,0xce,0x3a}, {0xa9,0x6f,0xd5,0x2d}, {0xa2,0x61,0xdc,0x20}, +{0xf6,0xad,0x76,0x6d}, {0xfd,0xa3,0x7f,0x60}, {0xe0,0xb1,0x64,0x77}, {0xeb,0xbf,0x6d,0x7a}, +{0xda,0x95,0x52,0x59}, {0xd1,0x9b,0x5b,0x54}, {0xcc,0x89,0x40,0x43}, {0xc7,0x87,0x49,0x4e}, +{0xae,0xdd,0x3e,0x05}, {0xa5,0xd3,0x37,0x08}, {0xb8,0xc1,0x2c,0x1f}, {0xb3,0xcf,0x25,0x12}, +{0x82,0xe5,0x1a,0x31}, {0x89,0xeb,0x13,0x3c}, {0x94,0xf9,0x08,0x2b}, {0x9f,0xf7,0x01,0x26}, +{0x46,0x4d,0xe6,0xbd}, {0x4d,0x43,0xef,0xb0}, {0x50,0x51,0xf4,0xa7}, {0x5b,0x5f,0xfd,0xaa}, +{0x6a,0x75,0xc2,0x89}, {0x61,0x7b,0xcb,0x84}, {0x7c,0x69,0xd0,0x93}, {0x77,0x67,0xd9,0x9e}, +{0x1e,0x3d,0xae,0xd5}, {0x15,0x33,0xa7,0xd8}, {0x08,0x21,0xbc,0xcf}, {0x03,0x2f,0xb5,0xc2}, +{0x32,0x05,0x8a,0xe1}, {0x39,0x0b,0x83,0xec}, {0x24,0x19,0x98,0xfb}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x86,0x78,0x44,0xdb}, {0x9b,0x6a,0x5f,0xcc}, {0x90,0x64,0x56,0xc1}, +{0xa1,0x4e,0x69,0xe2}, {0xaa,0x40,0x60,0xef}, {0xb7,0x52,0x7b,0xf8}, {0xbc,0x5c,0x72,0xf5}, +{0xd5,0x06,0x05,0xbe}, {0xde,0x08,0x0c,0xb3}, {0xc3,0x1a,0x17,0xa4}, {0xc8,0x14,0x1e,0xa9}, +{0xf9,0x3e,0x21,0x8a}, {0xf2,0x30,0x28,0x87}, {0xef,0x22,0x33,0x90}, {0xe4,0x2c,0x3a,0x9d}, +{0x3d,0x96,0xdd,0x06}, {0x36,0x98,0xd4,0x0b}, {0x2b,0x8a,0xcf,0x1c}, {0x20,0x84,0xc6,0x11}, +{0x11,0xae,0xf9,0x32}, {0x1a,0xa0,0xf0,0x3f}, {0x07,0xb2,0xeb,0x28}, {0x0c,0xbc,0xe2,0x25}, +{0x65,0xe6,0x95,0x6e}, {0x6e,0xe8,0x9c,0x63}, {0x73,0xfa,0x87,0x74}, {0x78,0xf4,0x8e,0x79}, +{0x49,0xde,0xb1,0x5a}, {0x42,0xd0,0xb8,0x57}, {0x5f,0xc2,0xa3,0x40}, {0x54,0xcc,0xaa,0x4d}, +{0xf7,0x41,0xec,0xda}, {0xfc,0x4f,0xe5,0xd7}, {0xe1,0x5d,0xfe,0xc0}, {0xea,0x53,0xf7,0xcd}, +{0xdb,0x79,0xc8,0xee}, {0xd0,0x77,0xc1,0xe3}, {0xcd,0x65,0xda,0xf4}, {0xc6,0x6b,0xd3,0xf9}, +{0xaf,0x31,0xa4,0xb2}, {0xa4,0x3f,0xad,0xbf}, {0xb9,0x2d,0xb6,0xa8}, {0xb2,0x23,0xbf,0xa5}, +{0x83,0x09,0x80,0x86}, {0x88,0x07,0x89,0x8b}, {0x95,0x15,0x92,0x9c}, {0x9e,0x1b,0x9b,0x91}, +{0x47,0xa1,0x7c,0x0a}, {0x4c,0xaf,0x75,0x07}, {0x51,0xbd,0x6e,0x10}, {0x5a,0xb3,0x67,0x1d}, +{0x6b,0x99,0x58,0x3e}, {0x60,0x97,0x51,0x33}, {0x7d,0x85,0x4a,0x24}, {0x76,0x8b,0x43,0x29}, +{0x1f,0xd1,0x34,0x62}, {0x14,0xdf,0x3d,0x6f}, {0x09,0xcd,0x26,0x78}, {0x02,0xc3,0x2f,0x75}, +{0x33,0xe9,0x10,0x56}, {0x38,0xe7,0x19,0x5b}, {0x25,0xf5,0x02,0x4c}, {0x2e,0xfb,0x0b,0x41}, +{0x8c,0x9a,0xd7,0x61}, {0x87,0x94,0xde,0x6c}, {0x9a,0x86,0xc5,0x7b}, {0x91,0x88,0xcc,0x76}, +{0xa0,0xa2,0xf3,0x55}, {0xab,0xac,0xfa,0x58}, {0xb6,0xbe,0xe1,0x4f}, {0xbd,0xb0,0xe8,0x42}, +{0xd4,0xea,0x9f,0x09}, {0xdf,0xe4,0x96,0x04}, {0xc2,0xf6,0x8d,0x13}, {0xc9,0xf8,0x84,0x1e}, +{0xf8,0xd2,0xbb,0x3d}, {0xf3,0xdc,0xb2,0x30}, {0xee,0xce,0xa9,0x27}, {0xe5,0xc0,0xa0,0x2a}, +{0x3c,0x7a,0x47,0xb1}, {0x37,0x74,0x4e,0xbc}, {0x2a,0x66,0x55,0xab}, {0x21,0x68,0x5c,0xa6}, +{0x10,0x42,0x63,0x85}, {0x1b,0x4c,0x6a,0x88}, {0x06,0x5e,0x71,0x9f}, {0x0d,0x50,0x78,0x92}, +{0x64,0x0a,0x0f,0xd9}, {0x6f,0x04,0x06,0xd4}, {0x72,0x16,0x1d,0xc3}, {0x79,0x18,0x14,0xce}, +{0x48,0x32,0x2b,0xed}, {0x43,0x3c,0x22,0xe0}, {0x5e,0x2e,0x39,0xf7}, {0x55,0x20,0x30,0xfa}, +{0x01,0xec,0x9a,0xb7}, {0x0a,0xe2,0x93,0xba}, {0x17,0xf0,0x88,0xad}, {0x1c,0xfe,0x81,0xa0}, +{0x2d,0xd4,0xbe,0x83}, {0x26,0xda,0xb7,0x8e}, {0x3b,0xc8,0xac,0x99}, {0x30,0xc6,0xa5,0x94}, +{0x59,0x9c,0xd2,0xdf}, {0x52,0x92,0xdb,0xd2}, {0x4f,0x80,0xc0,0xc5}, {0x44,0x8e,0xc9,0xc8}, +{0x75,0xa4,0xf6,0xeb}, {0x7e,0xaa,0xff,0xe6}, {0x63,0xb8,0xe4,0xf1}, {0x68,0xb6,0xed,0xfc}, +{0xb1,0x0c,0x0a,0x67}, {0xba,0x02,0x03,0x6a}, {0xa7,0x10,0x18,0x7d}, {0xac,0x1e,0x11,0x70}, +{0x9d,0x34,0x2e,0x53}, {0x96,0x3a,0x27,0x5e}, {0x8b,0x28,0x3c,0x49}, {0x80,0x26,0x35,0x44}, +{0xe9,0x7c,0x42,0x0f}, {0xe2,0x72,0x4b,0x02}, {0xff,0x60,0x50,0x15}, {0xf4,0x6e,0x59,0x18}, +{0xc5,0x44,0x66,0x3b}, {0xce,0x4a,0x6f,0x36}, {0xd3,0x58,0x74,0x21}, {0xd8,0x56,0x7d,0x2c}, +{0x7a,0x37,0xa1,0x0c}, {0x71,0x39,0xa8,0x01}, {0x6c,0x2b,0xb3,0x16}, {0x67,0x25,0xba,0x1b}, +{0x56,0x0f,0x85,0x38}, {0x5d,0x01,0x8c,0x35}, {0x40,0x13,0x97,0x22}, {0x4b,0x1d,0x9e,0x2f}, +{0x22,0x47,0xe9,0x64}, {0x29,0x49,0xe0,0x69}, {0x34,0x5b,0xfb,0x7e}, {0x3f,0x55,0xf2,0x73}, +{0x0e,0x7f,0xcd,0x50}, {0x05,0x71,0xc4,0x5d}, {0x18,0x63,0xdf,0x4a}, {0x13,0x6d,0xd6,0x47}, +{0xca,0xd7,0x31,0xdc}, {0xc1,0xd9,0x38,0xd1}, {0xdc,0xcb,0x23,0xc6}, {0xd7,0xc5,0x2a,0xcb}, +{0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff}, +{0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3}, +{0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97} + } +}; +#define U2 xU2.xt8 + +static const union xtab xU3 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b}, +{0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f}, +{0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53}, +{0x5c,0x74,0x48,0x6c}, {0x51,0x7f,0x46,0x65}, {0x46,0x62,0x54,0x7e}, {0x4b,0x69,0x5a,0x77}, +{0xd0,0xb0,0xe0,0x90}, {0xdd,0xbb,0xee,0x99}, {0xca,0xa6,0xfc,0x82}, {0xc7,0xad,0xf2,0x8b}, +{0xe4,0x9c,0xd8,0xb4}, {0xe9,0x97,0xd6,0xbd}, {0xfe,0x8a,0xc4,0xa6}, {0xf3,0x81,0xca,0xaf}, +{0xb8,0xe8,0x90,0xd8}, {0xb5,0xe3,0x9e,0xd1}, {0xa2,0xfe,0x8c,0xca}, {0xaf,0xf5,0x82,0xc3}, +{0x8c,0xc4,0xa8,0xfc}, {0x81,0xcf,0xa6,0xf5}, {0x96,0xd2,0xb4,0xee}, {0x9b,0xd9,0xba,0xe7}, +{0xbb,0x7b,0xdb,0x3b}, {0xb6,0x70,0xd5,0x32}, {0xa1,0x6d,0xc7,0x29}, {0xac,0x66,0xc9,0x20}, +{0x8f,0x57,0xe3,0x1f}, {0x82,0x5c,0xed,0x16}, {0x95,0x41,0xff,0x0d}, {0x98,0x4a,0xf1,0x04}, +{0xd3,0x23,0xab,0x73}, {0xde,0x28,0xa5,0x7a}, {0xc9,0x35,0xb7,0x61}, {0xc4,0x3e,0xb9,0x68}, +{0xe7,0x0f,0x93,0x57}, {0xea,0x04,0x9d,0x5e}, {0xfd,0x19,0x8f,0x45}, {0xf0,0x12,0x81,0x4c}, +{0x6b,0xcb,0x3b,0xab}, {0x66,0xc0,0x35,0xa2}, {0x71,0xdd,0x27,0xb9}, {0x7c,0xd6,0x29,0xb0}, +{0x5f,0xe7,0x03,0x8f}, {0x52,0xec,0x0d,0x86}, {0x45,0xf1,0x1f,0x9d}, {0x48,0xfa,0x11,0x94}, +{0x03,0x93,0x4b,0xe3}, {0x0e,0x98,0x45,0xea}, {0x19,0x85,0x57,0xf1}, {0x14,0x8e,0x59,0xf8}, +{0x37,0xbf,0x73,0xc7}, {0x3a,0xb4,0x7d,0xce}, {0x2d,0xa9,0x6f,0xd5}, {0x20,0xa2,0x61,0xdc}, +{0x6d,0xf6,0xad,0x76}, {0x60,0xfd,0xa3,0x7f}, {0x77,0xe0,0xb1,0x64}, {0x7a,0xeb,0xbf,0x6d}, +{0x59,0xda,0x95,0x52}, {0x54,0xd1,0x9b,0x5b}, {0x43,0xcc,0x89,0x40}, {0x4e,0xc7,0x87,0x49}, +{0x05,0xae,0xdd,0x3e}, {0x08,0xa5,0xd3,0x37}, {0x1f,0xb8,0xc1,0x2c}, {0x12,0xb3,0xcf,0x25}, +{0x31,0x82,0xe5,0x1a}, {0x3c,0x89,0xeb,0x13}, {0x2b,0x94,0xf9,0x08}, {0x26,0x9f,0xf7,0x01}, +{0xbd,0x46,0x4d,0xe6}, {0xb0,0x4d,0x43,0xef}, {0xa7,0x50,0x51,0xf4}, {0xaa,0x5b,0x5f,0xfd}, +{0x89,0x6a,0x75,0xc2}, {0x84,0x61,0x7b,0xcb}, {0x93,0x7c,0x69,0xd0}, {0x9e,0x77,0x67,0xd9}, +{0xd5,0x1e,0x3d,0xae}, {0xd8,0x15,0x33,0xa7}, {0xcf,0x08,0x21,0xbc}, {0xc2,0x03,0x2f,0xb5}, +{0xe1,0x32,0x05,0x8a}, {0xec,0x39,0x0b,0x83}, {0xfb,0x24,0x19,0x98}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xdb,0x86,0x78,0x44}, {0xcc,0x9b,0x6a,0x5f}, {0xc1,0x90,0x64,0x56}, +{0xe2,0xa1,0x4e,0x69}, {0xef,0xaa,0x40,0x60}, {0xf8,0xb7,0x52,0x7b}, {0xf5,0xbc,0x5c,0x72}, +{0xbe,0xd5,0x06,0x05}, {0xb3,0xde,0x08,0x0c}, {0xa4,0xc3,0x1a,0x17}, {0xa9,0xc8,0x14,0x1e}, +{0x8a,0xf9,0x3e,0x21}, {0x87,0xf2,0x30,0x28}, {0x90,0xef,0x22,0x33}, {0x9d,0xe4,0x2c,0x3a}, +{0x06,0x3d,0x96,0xdd}, {0x0b,0x36,0x98,0xd4}, {0x1c,0x2b,0x8a,0xcf}, {0x11,0x20,0x84,0xc6}, +{0x32,0x11,0xae,0xf9}, {0x3f,0x1a,0xa0,0xf0}, {0x28,0x07,0xb2,0xeb}, {0x25,0x0c,0xbc,0xe2}, +{0x6e,0x65,0xe6,0x95}, {0x63,0x6e,0xe8,0x9c}, {0x74,0x73,0xfa,0x87}, {0x79,0x78,0xf4,0x8e}, +{0x5a,0x49,0xde,0xb1}, {0x57,0x42,0xd0,0xb8}, {0x40,0x5f,0xc2,0xa3}, {0x4d,0x54,0xcc,0xaa}, +{0xda,0xf7,0x41,0xec}, {0xd7,0xfc,0x4f,0xe5}, {0xc0,0xe1,0x5d,0xfe}, {0xcd,0xea,0x53,0xf7}, +{0xee,0xdb,0x79,0xc8}, {0xe3,0xd0,0x77,0xc1}, {0xf4,0xcd,0x65,0xda}, {0xf9,0xc6,0x6b,0xd3}, +{0xb2,0xaf,0x31,0xa4}, {0xbf,0xa4,0x3f,0xad}, {0xa8,0xb9,0x2d,0xb6}, {0xa5,0xb2,0x23,0xbf}, +{0x86,0x83,0x09,0x80}, {0x8b,0x88,0x07,0x89}, {0x9c,0x95,0x15,0x92}, {0x91,0x9e,0x1b,0x9b}, +{0x0a,0x47,0xa1,0x7c}, {0x07,0x4c,0xaf,0x75}, {0x10,0x51,0xbd,0x6e}, {0x1d,0x5a,0xb3,0x67}, +{0x3e,0x6b,0x99,0x58}, {0x33,0x60,0x97,0x51}, {0x24,0x7d,0x85,0x4a}, {0x29,0x76,0x8b,0x43}, +{0x62,0x1f,0xd1,0x34}, {0x6f,0x14,0xdf,0x3d}, {0x78,0x09,0xcd,0x26}, {0x75,0x02,0xc3,0x2f}, +{0x56,0x33,0xe9,0x10}, {0x5b,0x38,0xe7,0x19}, {0x4c,0x25,0xf5,0x02}, {0x41,0x2e,0xfb,0x0b}, +{0x61,0x8c,0x9a,0xd7}, {0x6c,0x87,0x94,0xde}, {0x7b,0x9a,0x86,0xc5}, {0x76,0x91,0x88,0xcc}, +{0x55,0xa0,0xa2,0xf3}, {0x58,0xab,0xac,0xfa}, {0x4f,0xb6,0xbe,0xe1}, {0x42,0xbd,0xb0,0xe8}, +{0x09,0xd4,0xea,0x9f}, {0x04,0xdf,0xe4,0x96}, {0x13,0xc2,0xf6,0x8d}, {0x1e,0xc9,0xf8,0x84}, +{0x3d,0xf8,0xd2,0xbb}, {0x30,0xf3,0xdc,0xb2}, {0x27,0xee,0xce,0xa9}, {0x2a,0xe5,0xc0,0xa0}, +{0xb1,0x3c,0x7a,0x47}, {0xbc,0x37,0x74,0x4e}, {0xab,0x2a,0x66,0x55}, {0xa6,0x21,0x68,0x5c}, +{0x85,0x10,0x42,0x63}, {0x88,0x1b,0x4c,0x6a}, {0x9f,0x06,0x5e,0x71}, {0x92,0x0d,0x50,0x78}, +{0xd9,0x64,0x0a,0x0f}, {0xd4,0x6f,0x04,0x06}, {0xc3,0x72,0x16,0x1d}, {0xce,0x79,0x18,0x14}, +{0xed,0x48,0x32,0x2b}, {0xe0,0x43,0x3c,0x22}, {0xf7,0x5e,0x2e,0x39}, {0xfa,0x55,0x20,0x30}, +{0xb7,0x01,0xec,0x9a}, {0xba,0x0a,0xe2,0x93}, {0xad,0x17,0xf0,0x88}, {0xa0,0x1c,0xfe,0x81}, +{0x83,0x2d,0xd4,0xbe}, {0x8e,0x26,0xda,0xb7}, {0x99,0x3b,0xc8,0xac}, {0x94,0x30,0xc6,0xa5}, +{0xdf,0x59,0x9c,0xd2}, {0xd2,0x52,0x92,0xdb}, {0xc5,0x4f,0x80,0xc0}, {0xc8,0x44,0x8e,0xc9}, +{0xeb,0x75,0xa4,0xf6}, {0xe6,0x7e,0xaa,0xff}, {0xf1,0x63,0xb8,0xe4}, {0xfc,0x68,0xb6,0xed}, +{0x67,0xb1,0x0c,0x0a}, {0x6a,0xba,0x02,0x03}, {0x7d,0xa7,0x10,0x18}, {0x70,0xac,0x1e,0x11}, +{0x53,0x9d,0x34,0x2e}, {0x5e,0x96,0x3a,0x27}, {0x49,0x8b,0x28,0x3c}, {0x44,0x80,0x26,0x35}, +{0x0f,0xe9,0x7c,0x42}, {0x02,0xe2,0x72,0x4b}, {0x15,0xff,0x60,0x50}, {0x18,0xf4,0x6e,0x59}, +{0x3b,0xc5,0x44,0x66}, {0x36,0xce,0x4a,0x6f}, {0x21,0xd3,0x58,0x74}, {0x2c,0xd8,0x56,0x7d}, +{0x0c,0x7a,0x37,0xa1}, {0x01,0x71,0x39,0xa8}, {0x16,0x6c,0x2b,0xb3}, {0x1b,0x67,0x25,0xba}, +{0x38,0x56,0x0f,0x85}, {0x35,0x5d,0x01,0x8c}, {0x22,0x40,0x13,0x97}, {0x2f,0x4b,0x1d,0x9e}, +{0x64,0x22,0x47,0xe9}, {0x69,0x29,0x49,0xe0}, {0x7e,0x34,0x5b,0xfb}, {0x73,0x3f,0x55,0xf2}, +{0x50,0x0e,0x7f,0xcd}, {0x5d,0x05,0x71,0xc4}, {0x4a,0x18,0x63,0xdf}, {0x47,0x13,0x6d,0xd6}, +{0xdc,0xca,0xd7,0x31}, {0xd1,0xc1,0xd9,0x38}, {0xc6,0xdc,0xcb,0x23}, {0xcb,0xd7,0xc5,0x2a}, +{0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e}, +{0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62}, +{0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46} + } +}; +#define U3 xU3.xt8 + +static const union xtab xU4 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12}, +{0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a}, +{0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62}, +{0x6c,0x5c,0x74,0x48}, {0x65,0x51,0x7f,0x46}, {0x7e,0x46,0x62,0x54}, {0x77,0x4b,0x69,0x5a}, +{0x90,0xd0,0xb0,0xe0}, {0x99,0xdd,0xbb,0xee}, {0x82,0xca,0xa6,0xfc}, {0x8b,0xc7,0xad,0xf2}, +{0xb4,0xe4,0x9c,0xd8}, {0xbd,0xe9,0x97,0xd6}, {0xa6,0xfe,0x8a,0xc4}, {0xaf,0xf3,0x81,0xca}, +{0xd8,0xb8,0xe8,0x90}, {0xd1,0xb5,0xe3,0x9e}, {0xca,0xa2,0xfe,0x8c}, {0xc3,0xaf,0xf5,0x82}, +{0xfc,0x8c,0xc4,0xa8}, {0xf5,0x81,0xcf,0xa6}, {0xee,0x96,0xd2,0xb4}, {0xe7,0x9b,0xd9,0xba}, +{0x3b,0xbb,0x7b,0xdb}, {0x32,0xb6,0x70,0xd5}, {0x29,0xa1,0x6d,0xc7}, {0x20,0xac,0x66,0xc9}, +{0x1f,0x8f,0x57,0xe3}, {0x16,0x82,0x5c,0xed}, {0x0d,0x95,0x41,0xff}, {0x04,0x98,0x4a,0xf1}, +{0x73,0xd3,0x23,0xab}, {0x7a,0xde,0x28,0xa5}, {0x61,0xc9,0x35,0xb7}, {0x68,0xc4,0x3e,0xb9}, +{0x57,0xe7,0x0f,0x93}, {0x5e,0xea,0x04,0x9d}, {0x45,0xfd,0x19,0x8f}, {0x4c,0xf0,0x12,0x81}, +{0xab,0x6b,0xcb,0x3b}, {0xa2,0x66,0xc0,0x35}, {0xb9,0x71,0xdd,0x27}, {0xb0,0x7c,0xd6,0x29}, +{0x8f,0x5f,0xe7,0x03}, {0x86,0x52,0xec,0x0d}, {0x9d,0x45,0xf1,0x1f}, {0x94,0x48,0xfa,0x11}, +{0xe3,0x03,0x93,0x4b}, {0xea,0x0e,0x98,0x45}, {0xf1,0x19,0x85,0x57}, {0xf8,0x14,0x8e,0x59}, +{0xc7,0x37,0xbf,0x73}, {0xce,0x3a,0xb4,0x7d}, {0xd5,0x2d,0xa9,0x6f}, {0xdc,0x20,0xa2,0x61}, +{0x76,0x6d,0xf6,0xad}, {0x7f,0x60,0xfd,0xa3}, {0x64,0x77,0xe0,0xb1}, {0x6d,0x7a,0xeb,0xbf}, +{0x52,0x59,0xda,0x95}, {0x5b,0x54,0xd1,0x9b}, {0x40,0x43,0xcc,0x89}, {0x49,0x4e,0xc7,0x87}, +{0x3e,0x05,0xae,0xdd}, {0x37,0x08,0xa5,0xd3}, {0x2c,0x1f,0xb8,0xc1}, {0x25,0x12,0xb3,0xcf}, +{0x1a,0x31,0x82,0xe5}, {0x13,0x3c,0x89,0xeb}, {0x08,0x2b,0x94,0xf9}, {0x01,0x26,0x9f,0xf7}, +{0xe6,0xbd,0x46,0x4d}, {0xef,0xb0,0x4d,0x43}, {0xf4,0xa7,0x50,0x51}, {0xfd,0xaa,0x5b,0x5f}, +{0xc2,0x89,0x6a,0x75}, {0xcb,0x84,0x61,0x7b}, {0xd0,0x93,0x7c,0x69}, {0xd9,0x9e,0x77,0x67}, +{0xae,0xd5,0x1e,0x3d}, {0xa7,0xd8,0x15,0x33}, {0xbc,0xcf,0x08,0x21}, {0xb5,0xc2,0x03,0x2f}, +{0x8a,0xe1,0x32,0x05}, {0x83,0xec,0x39,0x0b}, {0x98,0xfb,0x24,0x19}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0x44,0xdb,0x86,0x78}, {0x5f,0xcc,0x9b,0x6a}, {0x56,0xc1,0x90,0x64}, +{0x69,0xe2,0xa1,0x4e}, {0x60,0xef,0xaa,0x40}, {0x7b,0xf8,0xb7,0x52}, {0x72,0xf5,0xbc,0x5c}, +{0x05,0xbe,0xd5,0x06}, {0x0c,0xb3,0xde,0x08}, {0x17,0xa4,0xc3,0x1a}, {0x1e,0xa9,0xc8,0x14}, +{0x21,0x8a,0xf9,0x3e}, {0x28,0x87,0xf2,0x30}, {0x33,0x90,0xef,0x22}, {0x3a,0x9d,0xe4,0x2c}, +{0xdd,0x06,0x3d,0x96}, {0xd4,0x0b,0x36,0x98}, {0xcf,0x1c,0x2b,0x8a}, {0xc6,0x11,0x20,0x84}, +{0xf9,0x32,0x11,0xae}, {0xf0,0x3f,0x1a,0xa0}, {0xeb,0x28,0x07,0xb2}, {0xe2,0x25,0x0c,0xbc}, +{0x95,0x6e,0x65,0xe6}, {0x9c,0x63,0x6e,0xe8}, {0x87,0x74,0x73,0xfa}, {0x8e,0x79,0x78,0xf4}, +{0xb1,0x5a,0x49,0xde}, {0xb8,0x57,0x42,0xd0}, {0xa3,0x40,0x5f,0xc2}, {0xaa,0x4d,0x54,0xcc}, +{0xec,0xda,0xf7,0x41}, {0xe5,0xd7,0xfc,0x4f}, {0xfe,0xc0,0xe1,0x5d}, {0xf7,0xcd,0xea,0x53}, +{0xc8,0xee,0xdb,0x79}, {0xc1,0xe3,0xd0,0x77}, {0xda,0xf4,0xcd,0x65}, {0xd3,0xf9,0xc6,0x6b}, +{0xa4,0xb2,0xaf,0x31}, {0xad,0xbf,0xa4,0x3f}, {0xb6,0xa8,0xb9,0x2d}, {0xbf,0xa5,0xb2,0x23}, +{0x80,0x86,0x83,0x09}, {0x89,0x8b,0x88,0x07}, {0x92,0x9c,0x95,0x15}, {0x9b,0x91,0x9e,0x1b}, +{0x7c,0x0a,0x47,0xa1}, {0x75,0x07,0x4c,0xaf}, {0x6e,0x10,0x51,0xbd}, {0x67,0x1d,0x5a,0xb3}, +{0x58,0x3e,0x6b,0x99}, {0x51,0x33,0x60,0x97}, {0x4a,0x24,0x7d,0x85}, {0x43,0x29,0x76,0x8b}, +{0x34,0x62,0x1f,0xd1}, {0x3d,0x6f,0x14,0xdf}, {0x26,0x78,0x09,0xcd}, {0x2f,0x75,0x02,0xc3}, +{0x10,0x56,0x33,0xe9}, {0x19,0x5b,0x38,0xe7}, {0x02,0x4c,0x25,0xf5}, {0x0b,0x41,0x2e,0xfb}, +{0xd7,0x61,0x8c,0x9a}, {0xde,0x6c,0x87,0x94}, {0xc5,0x7b,0x9a,0x86}, {0xcc,0x76,0x91,0x88}, +{0xf3,0x55,0xa0,0xa2}, {0xfa,0x58,0xab,0xac}, {0xe1,0x4f,0xb6,0xbe}, {0xe8,0x42,0xbd,0xb0}, +{0x9f,0x09,0xd4,0xea}, {0x96,0x04,0xdf,0xe4}, {0x8d,0x13,0xc2,0xf6}, {0x84,0x1e,0xc9,0xf8}, +{0xbb,0x3d,0xf8,0xd2}, {0xb2,0x30,0xf3,0xdc}, {0xa9,0x27,0xee,0xce}, {0xa0,0x2a,0xe5,0xc0}, +{0x47,0xb1,0x3c,0x7a}, {0x4e,0xbc,0x37,0x74}, {0x55,0xab,0x2a,0x66}, {0x5c,0xa6,0x21,0x68}, +{0x63,0x85,0x10,0x42}, {0x6a,0x88,0x1b,0x4c}, {0x71,0x9f,0x06,0x5e}, {0x78,0x92,0x0d,0x50}, +{0x0f,0xd9,0x64,0x0a}, {0x06,0xd4,0x6f,0x04}, {0x1d,0xc3,0x72,0x16}, {0x14,0xce,0x79,0x18}, +{0x2b,0xed,0x48,0x32}, {0x22,0xe0,0x43,0x3c}, {0x39,0xf7,0x5e,0x2e}, {0x30,0xfa,0x55,0x20}, +{0x9a,0xb7,0x01,0xec}, {0x93,0xba,0x0a,0xe2}, {0x88,0xad,0x17,0xf0}, {0x81,0xa0,0x1c,0xfe}, +{0xbe,0x83,0x2d,0xd4}, {0xb7,0x8e,0x26,0xda}, {0xac,0x99,0x3b,0xc8}, {0xa5,0x94,0x30,0xc6}, +{0xd2,0xdf,0x59,0x9c}, {0xdb,0xd2,0x52,0x92}, {0xc0,0xc5,0x4f,0x80}, {0xc9,0xc8,0x44,0x8e}, +{0xf6,0xeb,0x75,0xa4}, {0xff,0xe6,0x7e,0xaa}, {0xe4,0xf1,0x63,0xb8}, {0xed,0xfc,0x68,0xb6}, +{0x0a,0x67,0xb1,0x0c}, {0x03,0x6a,0xba,0x02}, {0x18,0x7d,0xa7,0x10}, {0x11,0x70,0xac,0x1e}, +{0x2e,0x53,0x9d,0x34}, {0x27,0x5e,0x96,0x3a}, {0x3c,0x49,0x8b,0x28}, {0x35,0x44,0x80,0x26}, +{0x42,0x0f,0xe9,0x7c}, {0x4b,0x02,0xe2,0x72}, {0x50,0x15,0xff,0x60}, {0x59,0x18,0xf4,0x6e}, +{0x66,0x3b,0xc5,0x44}, {0x6f,0x36,0xce,0x4a}, {0x74,0x21,0xd3,0x58}, {0x7d,0x2c,0xd8,0x56}, +{0xa1,0x0c,0x7a,0x37}, {0xa8,0x01,0x71,0x39}, {0xb3,0x16,0x6c,0x2b}, {0xba,0x1b,0x67,0x25}, +{0x85,0x38,0x56,0x0f}, {0x8c,0x35,0x5d,0x01}, {0x97,0x22,0x40,0x13}, {0x9e,0x2f,0x4b,0x1d}, +{0xe9,0x64,0x22,0x47}, {0xe0,0x69,0x29,0x49}, {0xfb,0x7e,0x34,0x5b}, {0xf2,0x73,0x3f,0x55}, +{0xcd,0x50,0x0e,0x7f}, {0xc4,0x5d,0x05,0x71}, {0xdf,0x4a,0x18,0x63}, {0xd6,0x47,0x13,0x6d}, +{0x31,0xdc,0xca,0xd7}, {0x38,0xd1,0xc1,0xd9}, {0x23,0xc6,0xdc,0xcb}, {0x2a,0xcb,0xd7,0xc5}, +{0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd}, +{0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5}, +{0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d} + } +}; +#define U4 xU4.xt8 + +static const word32 rcon[30] = { + 0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +}; diff --git a/ipsec-tools/racoon/Crypto/rijndael-alg-fst.c b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.c new file mode 100644 index 0000000..8ccf9e1 --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.c @@ -0,0 +1,492 @@ +/* $KAME: rijndael-alg-fst.c,v 1.9 2001/06/19 15:21:05 itojun Exp $ */ + +/* + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#else +#include +#endif +#include +#include + +#include "boxes-fst.dat" + +#include +#define bcopy(a, b, c) memcpy((b), (a), (c)) +#define bzero(a, b) memset((a), 0, (b)) +#define panic(a) err(1, (a)) + +int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + /* Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + int j, r, t, rconpointer = 0; + union { + word8 x8[MAXKC][4]; + word32 x32[MAXKC]; + } xtk; +#define tk xtk.x8 + int KC = ROUNDS - 6; + + for (j = KC-1; j >= 0; j--) { + *((word32*)tk[j]) = *((word32*)k[j]); + } + r = 0; + t = 0; + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) { /* while not enough round key material calculated */ + /* calculate new values */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) { + for (j = 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } else { + for (j = 1; j < KC/2; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + } + return 0; +#undef tk +} + +int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + word8 *w; + + for (r = 1; r < ROUNDS; r++) { + w = W[r][0]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][1]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][2]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][3]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + } + return 0; +} + +/** + * Encrypt a single block. + */ +int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]); + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + for (r = 1; r < ROUNDS-1; r++) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[ROUNDS-1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]); + b[ 0] = T1[temp[0][0]][1]; + b[ 1] = T1[temp[1][1]][1]; + b[ 2] = T1[temp[2][2]][1]; + b[ 3] = T1[temp[3][3]][1]; + b[ 4] = T1[temp[1][0]][1]; + b[ 5] = T1[temp[2][1]][1]; + b[ 6] = T1[temp[3][2]][1]; + b[ 7] = T1[temp[0][3]][1]; + b[ 8] = T1[temp[2][0]][1]; + b[ 9] = T1[temp[3][1]][1]; + b[10] = T1[temp[0][2]][1]; + b[11] = T1[temp[1][3]][1]; + b[12] = T1[temp[3][0]][1]; + b[13] = T1[temp[0][1]][1]; + b[14] = T1[temp[1][2]][1]; + b[15] = T1[temp[2][3]][1]; + *((word32*)(b )) ^= *((word32*)rk[ROUNDS][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]); + *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Encrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + */ +int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r; + word8 temp[4][4]; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + + *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]); + *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]); + *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]); + *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]); + + for (r = 1; (r <= rounds) && (r < ROUNDS); r++) { + *((word32*)temp[0]) = *((const word32*)T1[a[0][0]]) + ^ *((const word32*)T2[a[1][1]]) + ^ *((const word32*)T3[a[2][2]]) + ^ *((const word32*)T4[a[3][3]]); + *((word32*)temp[1]) = *((const word32*)T1[a[1][0]]) + ^ *((const word32*)T2[a[2][1]]) + ^ *((const word32*)T3[a[3][2]]) + ^ *((const word32*)T4[a[0][3]]); + *((word32*)temp[2]) = *((const word32*)T1[a[2][0]]) + ^ *((const word32*)T2[a[3][1]]) + ^ *((const word32*)T3[a[0][2]]) + ^ *((const word32*)T4[a[1][3]]); + *((word32*)temp[3]) = *((const word32*)T1[a[3][0]]) + ^ *((const word32*)T2[a[0][1]]) + ^ *((const word32*)T3[a[1][2]]) + ^ *((const word32*)T4[a[2][3]]); + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]); + } + if (rounds == ROUNDS) { + /* last round is special */ + temp[0][0] = T1[a[0][0]][1]; + temp[0][1] = T1[a[1][1]][1]; + temp[0][2] = T1[a[2][2]][1]; + temp[0][3] = T1[a[3][3]][1]; + temp[1][0] = T1[a[1][0]][1]; + temp[1][1] = T1[a[2][1]][1]; + temp[1][2] = T1[a[3][2]][1]; + temp[1][3] = T1[a[0][3]][1]; + temp[2][0] = T1[a[2][0]][1]; + temp[2][1] = T1[a[3][1]][1]; + temp[2][2] = T1[a[0][2]][1]; + temp[2][3] = T1[a[1][3]][1]; + temp[3][0] = T1[a[3][0]][1]; + temp[3][1] = T1[a[0][1]][1]; + temp[3][2] = T1[a[1][2]][1]; + temp[3][3] = T1[a[2][3]][1]; + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]); + } + + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ + +/** + * Decrypt a single block. + */ +int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]); + + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + for (r = ROUNDS-1; r > 1; r--) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + *((word32*)(b )) ^= *((word32*)rk[0][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]); + *((word32*)(b+12)) ^= *((word32*)rk[0][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Decrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * Operations rearranged such that the intermediate values + * of decryption correspond with the intermediate values + * of encryption. + */ +int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r, i; + word8 temp[4], shift; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + /* first round is special: */ + *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0]; + *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1]; + *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2]; + *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3]; + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + /* ROUNDS-1 ordinary rounds */ + for (r = ROUNDS-1; r > rounds; r--) { + *(word32 *)a[0] ^= *(word32 *)rk[r][0]; + *(word32 *)a[1] ^= *(word32 *)rk[r][1]; + *(word32 *)a[2] ^= *(word32 *)rk[r][2]; + *(word32 *)a[3] ^= *(word32 *)rk[r][3]; + + *((word32*)a[0]) = + *((const word32*)U1[a[0][0]]) + ^ *((const word32*)U2[a[0][1]]) + ^ *((const word32*)U3[a[0][2]]) + ^ *((const word32*)U4[a[0][3]]); + + *((word32*)a[1]) = + *((const word32*)U1[a[1][0]]) + ^ *((const word32*)U2[a[1][1]]) + ^ *((const word32*)U3[a[1][2]]) + ^ *((const word32*)U4[a[1][3]]); + + *((word32*)a[2]) = + *((const word32*)U1[a[2][0]]) + ^ *((const word32*)U2[a[2][1]]) + ^ *((const word32*)U3[a[2][2]]) + ^ *((const word32*)U4[a[2][3]]); + + *((word32*)a[3]) = + *((const word32*)U1[a[3][0]]) + ^ *((const word32*)U2[a[3][1]]) + ^ *((const word32*)U3[a[3][2]]) + ^ *((const word32*)U4[a[3][3]]); + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + } + if (rounds == 0) { + /* End with the extra key addition */ + *(word32 *)a[0] ^= *(word32 *)rk[0][0]; + *(word32 *)a[1] ^= *(word32 *)rk[0][1]; + *(word32 *)a[2] ^= *(word32 *)rk[0][2]; + *(word32 *)a[3] ^= *(word32 *)rk[0][3]; + } + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/ipsec-tools/racoon/Crypto/rijndael-alg-fst.h b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.h new file mode 100644 index 0000000..7a725ae --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael-alg-fst.h @@ -0,0 +1,34 @@ +/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */ + +/* + * rijndael-alg-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_ALG_FST_H__ +#define __RIJNDAEL_ALG_FST_H__ + +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXROUNDS 14 + +int rijndaelKeySched(u_int8_t k[RIJNDAEL_MAXKC][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelKeyEncToDec(u_int8_t W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelEncrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelEncryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +int rijndaelDecrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelDecryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_ALG_FST_H__ */ + diff --git a/ipsec-tools/racoon/Crypto/rijndael-api-fst.c b/ipsec-tools/racoon/Crypto/rijndael-api-fst.c new file mode 100644 index 0000000..a3104c2 --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael-api-fst.c @@ -0,0 +1,495 @@ +/* $KAME: rijndael-api-fst.c,v 1.1.1.1 2001/08/08 09:56:23 sakane Exp $ */ + +/* + * rijndael-api-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.1: Vincent Rijmen + * v2.2: Vincent Rijmen + * v2.3: Paulo Barreto + * v2.4: Vincent Rijmen + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#include +#else +#include +#endif +#include +#include +#include + +#include +#define bcopy(a, b, c) memcpy(b, a, c) +#define bzero(a, b) memset(a, 0, b) +#define panic(a) err(1, (a)) + +int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) { + word8 k[MAXKC][4]; + int i; + char *keyMat; + + if (key == NULL) { + return BAD_KEY_INSTANCE; + } + + if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) { + key->direction = direction; + } else { + return BAD_KEY_DIR; + } + + if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { + key->keyLen = keyLen; + } else { + return BAD_KEY_MAT; + } + + if (keyMaterial != NULL) { + bcopy(keyMaterial, key->keyMaterial, keyLen/8); + } + + key->ROUNDS = keyLen/32 + 6; + + /* initialize key schedule: */ + keyMat = key->keyMaterial; + for (i = 0; i < key->keyLen/8; i++) { + k[i >> 2][i & 3] = (word8)keyMat[i]; + } + rijndaelKeySched(k, key->keySched, key->ROUNDS); + if (direction == DIR_DECRYPT) { + rijndaelKeyEncToDec(key->keySched, key->ROUNDS); + } + + return TRUE; +} + +int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { + if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) { + cipher->mode = mode; + } else { + return BAD_CIPHER_MODE; + } + if (IV != NULL) { + bcopy(IV, cipher->IV, MAX_IV_SIZE); + } else { + bzero(cipher->IV, MAX_IV_SIZE); + } + return TRUE; +} + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, block, 16); + bcopy(input, iv, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3]; +#endif + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + for (i = numBlocks - 1; i > 0; i--) { +#if 0 /*STRICT_ALIGN*/ + bcopy(outBuffer, block, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3]; +#endif + outBuffer += 16; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, iv, 16); +#else /* !STRICT_ALIGN */ + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif /* ?STRICT_ALIGN */ + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +/** + * Encrypt data partitioned in octets, using RFC 2040-like padding. + * + * @param input data to be encrypted (octet sequence) + * @param inputOctets input length in octets (not bits) + * @param outBuffer encrypted output data + * + * @return length in octets (not bits) of the encrypted output buffer. + */ +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16], *iv, *cp; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + padLen = 16 - (inputOctets - 16*numBlocks); + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(ECB)"); + bcopy(input, block, 16 - padLen); + for (cp = block + 16 - padLen; cp < block + 16; cp++) + *cp = padLen; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + case MODE_CBC: + iv = cipher->IV; + for (i = numBlocks; i > 0; i--) { + ((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0]; + ((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1]; + ((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2]; + ((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3]; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + iv = outBuffer; + input += 16; + outBuffer += 16; + } +#if 0 /*XXX i'm not sure that is correct. sakane@kame.net */ + padLen = 16 - (inputOctets - 16*numBlocks); +#else + padLen = 16 - inputOctets % 16; + if (padLen == 16) + padLen = 0; +#endif + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(CBC)"); + for (i = 0; i < 16 - padLen; i++) { + block[i] = input[i] ^ iv[i]; + } + for (i = 16 - padLen; i < 16; i++) { + block[i] = (BYTE)padLen ^ iv[i]; + } + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*(numBlocks + 1); +} + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= *((word32*)iv[0]); + ((word32*)block)[1] ^= *((word32*)iv[1]); + ((word32*)block)[2] ^= *((word32*)iv[2]); + ((word32*)block)[3] ^= *((word32*)iv[3]); +#if 0 /*STRICT_ALIGN*/ + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); +#else + *((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0]; + *((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1]; + *((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2]; + *((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3]; +#endif + input += 16; + outBuffer += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV)); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16]; + word32 iv[4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_ENCRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + if (inputOctets % 16 != 0) { + return BAD_DATA; + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + padLen = block[15]; + if (padLen >= 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + case MODE_CBC: + bcopy(cipher->IV, iv, 16); + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + padLen = block[15]; + if (padLen <= 0 || padLen > 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*numBlocks - padLen; +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * cipherUpdateRounds: + * + * Encrypts/Decrypts exactly one full block a specified number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * + * Returns: + * TRUE - on success + * BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized) + */ +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer, int rounds) { + int j; + word8 block[4][4]; + + if (cipher == NULL || key == NULL) { + return BAD_CIPHER_STATE; + } + + for (j = 3; j >= 0; j--) { + /* parse input stream into rectangular array */ + *((word32*)block[j]) = *((word32*)(input+4*j)); + } + + switch (key->direction) { + case DIR_ENCRYPT: + rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + case DIR_DECRYPT: + rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + default: + return BAD_KEY_DIR; + } + + for (j = 3; j >= 0; j--) { + /* parse rectangular array into output ciphertext bytes */ + *((word32*)(outBuffer+4*j)) = *((word32*)block[j]); + } + + return TRUE; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/ipsec-tools/racoon/Crypto/rijndael-api-fst.h b/ipsec-tools/racoon/Crypto/rijndael-api-fst.h new file mode 100644 index 0000000..9e0ed3a --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael-api-fst.h @@ -0,0 +1,104 @@ +/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ + +/* + * rijndael-api-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_API_FST_H__ +#define __RIJNDAEL_API_FST_H__ + +#include + +/* Defines: + Add any additional defines you need +*/ + +#define DIR_ENCRYPT 0 /* Are we encrpyting? */ +#define DIR_DECRYPT 1 /* Are we decrpyting? */ +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ +#define TRUE 1 +#define FALSE 0 +#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ + +/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ +#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ +#define BAD_KEY_MAT -2 /* Key material not of correct length */ +#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ +#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ +#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ +#define BAD_BLOCK_LENGTH -6 +#define BAD_CIPHER_INSTANCE -7 +#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */ +#define BAD_OTHER -9 /* Unknown error */ + +/* CHANGE POSSIBLE: inclusion of algorithm specific defines */ +#define MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */ +#define MAX_IV_SIZE 16 /* # bytes needed to represent an IV */ + +/* Typedefs: + + Typedef'ed data storage elements. Add any algorithm specific +parameters at the bottom of the structs as appropriate. +*/ + +/* The structure for key information */ +typedef struct { + u_int8_t direction; /* Key used for encrypting or decrypting? */ + int keyLen; /* Length of the key */ + char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ + /* The following parameters are algorithm dependent, replace or add as necessary */ + int ROUNDS; /* key-length-dependent number of rounds */ + int blockLen; /* block length */ + union { + u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */ + } xKeySched; +#define keySched xKeySched.xkS8 +} keyInstance; + +/* The structure for cipher information */ +typedef struct { /* changed order of the components */ + u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ + u_int8_t IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ + /* Add any algorithm specific parameters needed here */ + int blockLen; /* Sample: Handles non-128 bit block sizes (if available) */ +} cipherInstance; + +/* Function prototypes */ +/* CHANGED: nothing + TODO: implement the following extensions to setup 192-bit and 256-bit block lengths: + makeKeyEx(): parameter blockLen added + -- this parameter is absolutely necessary if you want to + setup the round keys in a variable block length setting + cipherInitEx(): parameter blockLen added (for obvious reasons) + */ + +int rijndael_makeKey(keyInstance *key, u_int8_t direction, int keyLen, char *keyMaterial); + +int rijndael_cipherInit(cipherInstance *cipher, u_int8_t mode, char *IV); + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer, int Rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_API_FST_H__ */ + diff --git a/ipsec-tools/racoon/Crypto/rijndael.h b/ipsec-tools/racoon/Crypto/rijndael.h new file mode 100644 index 0000000..6af4aa0 --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael.h @@ -0,0 +1,10 @@ +/* $KAME: rijndael.h,v 1.2 2000/10/02 17:14:27 itojun Exp $ */ + +#ifndef __RIJNDAEL_H__ +#define __RIJNDAEL_H__ + +#include + + +#endif /* __RIJNDAEL_H__ */ + diff --git a/ipsec-tools/racoon/Crypto/rijndael_local.h b/ipsec-tools/racoon/Crypto/rijndael_local.h new file mode 100644 index 0000000..652b328 --- /dev/null +++ b/ipsec-tools/racoon/Crypto/rijndael_local.h @@ -0,0 +1,17 @@ +/* $KAME: rijndael_local.h,v 1.3 2000/10/02 17:14:27 itojun Exp $ */ + +#ifndef __RIJNDAEL_LOCAL_H__ +#define __RIJNDAEL_LOCAL_H__ + +/* the file should not be used from outside */ +typedef u_int8_t BYTE; +typedef u_int8_t word8; +typedef u_int16_t word16; +typedef u_int32_t word32; + +#define MAXKC RIJNDAEL_MAXKC +#define MAXROUNDS RIJNDAEL_MAXROUNDS + + +#endif /* __RIJNDAEL_LOCAL_H__ */ + diff --git a/ipsec-tools/racoon/Documents/FAQ b/ipsec-tools/racoon/Documents/FAQ new file mode 100644 index 0000000..924c73f --- /dev/null +++ b/ipsec-tools/racoon/Documents/FAQ @@ -0,0 +1,106 @@ +This document is derived from the KAME racoon FAQ. Some answers do not +apply to ipsec-tools (they are obsolete or not up to date). They are +tagged [KAME] + +Q: With what other IKE/IPsec implementation racoon is known to be interoperable? + +A: [KAME] + See "IMPLEMENTATION" document supplied with KAME kit, or: + http://www.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION + As we have tested/got test reports in the past, and our end and + the other end may have changed their implemenations, we are not sure + if we can interoperate with them today (we hope them to interoperate, + but we are not sure). + Also note that, IKE interoperability highly depends on configuration + on both ends. You must configure both ends exactly the same. + +Q: How can I make racoon interoperate with ? + +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: + + + If your question is confidential, send your questions to: + + +Q: Other documents to look at? + +A: + http://www.netbsd.org/Documentation/network/ipsec/ + http://www.kame.net/ + http://www.kame.net/newsletter/ diff --git a/ipsec-tools/racoon/Documents/README.certificate b/ipsec-tools/racoon/Documents/README.certificate new file mode 100644 index 0000000..a8bbfa2 --- /dev/null +++ b/ipsec-tools/racoon/Documents/README.certificate @@ -0,0 +1 @@ +See http://www.kame.net/newsletter/20001119b/ diff --git a/ipsec-tools/racoon/Documents/README.gssapi b/ipsec-tools/racoon/Documents/README.gssapi new file mode 100644 index 0000000..9cb3fbb --- /dev/null +++ b/ipsec-tools/racoon/Documents/README.gssapi @@ -0,0 +1,106 @@ +The gss-api authentication mechanism implementation for racoon was +based on the ietf draft draft-ietf-ipsec-isakmp-gss-auth-06.txt. + +The implementation uses the Heimdal gss-api library, i.e. gss-api +on top of Kerberos 5. The Heimdal gss-api library had to be modified +to meet the requirements of using gss-api in a daemon. More specifically, +the gss_acquire_cred() call did not work for other cases than +GSS_C_NO_CREDENTIAL ("use default creds"). Daemons are often started +as root, and have no Kerberos 5 credentials, so racoon explicitly +needs to acquire its credentials. The usual method (already used +by login authentication daemons) in these situations is to add +a set of special credentials to be used. For example, authentication +by daemons concerned with login credentials, uses 'host/fqdn' as +its credential, where fqdn is the hostname on the interface that +is being used. These special credentials need to be extracted into +a local keytab from the kdc. The default value used in racoon +is 'ike/fqdn', but it can be overridden in the racoon config file. + +The modification to the Heimdal gss-api library implements the +mechanism above. If a credential other than GSS_C_NO_CREDENTIAL +is specified to gss_acquire_cred(), it first looks in the default +credential cache if it its principal matches the desired credential. +If not, it extracts it from the default keytab file, and stores +it in a memory-based credential cache, part of the gss credential +structure. + + + +The modifcations to racoon itself are as follows: + + * The racoon.conf config file accepts a new keyword, "gssapi_id", + to be used inside a proposal specification. It specifies + a string (a Kerberos 5 principal in this case), specifying the + credential that racoon will try to acquire. The default value + is 'ike/fqdn', where fqdn is the hostname for the interface + being used for the exchange. If the id is not specified, no + GSS endpoint attribute will be specified in the first SA sent. + However, if the initiator does specify a GSS endpoint attribute, + racoon will always respond with its own GSS endpoint name + in the SA (the default one if not specified by this option). + + * The racoon.conf file accepts "gssapi_krb" as authentication + method inside a proposal specification. The number used + for this method is 65001, which is a temporary number as + specified in the draft. + + * The cftoken.l and cfparse.y source files were modified to + pick up the configuration options. The original sources + stored algorithms in bitmask, which unfortunately meant + that the maximum value was 32, clearly not enough for 65001. + After consulting with the author (sakane@kame.net), it turned + out that method was a leftover, and no longer needed. I replaced + it with plain integers. + + * The gss-api specific code was concentrated as much as possible + in gssapi.c and gssapi.h. The code to call functions defined + in these files is conditional on HAVE_GSSAPI, except for the + config scan code. Specifying this flag on the compiler commandline + is conditional on the --enable-gssapi option to the configure + script. + + * Racoon seems to want to send accepted SA proposals back to + the initiator in a verbatim fashion, leaving no room to + insert the (variable-length) GSS endpoint name attribute. + I worked around this by re-assembling the extracted SA + into a new SA if the gssapi_krb method is used, and the + initiator sent the name attribute. This scheme should + possibly be re-examined by the racoon maintainers, storing + the SAs (the transformations, to be more precise) in a different + fashion to allow for variable-length attributes to be + re-inserted would be a good change, but I considered it to be + beyond the scope of this project. + + * The various state functions for aggressive and main mode + (in isakmp_agg.c and isakmp_ident.c respectively) were + changed to conditionally change their behavior if the + gssapi_krb method is specified. + + +This implementation tried to follow the specification in the ietf draft +as close as possible. However, it has not been tested against other +IKE daemon implementations. The only other one I know of is Windows 2000, +and it has some caveats. I attempted to be Windows 2000 compatible. +Should racoon be tried against Windows 2000, the gssapi_id option in +the config file must be used, as Windows 2000 expects the GSS endpoint +name to be sent at all times. I have my doubts as to the W2K compatibility, +because the spec describes the GSS endpoint name sent by W2K as +an unicode string 'xxx@domain', which doesn't seem to match the +required standard for gss-api + kerberos 5 (i.e. I am fairly certain +that such a string will be rejected by the Heimdal gss-api library, as it +is not a valid Kerberos 5 principal). + +With the Heimdal gss-api implementation, the gssapi_krb authentication +method will only work in main mode. Aggressive mode does not allow +for the extra round-trips needed by gss_init_sec_context and +gss_accept_sec_context when mutual authentication is requested. +The draft specifies that the a fallback should be done to main mode, +through the return of INVALID-EXCHANGE-TYPE if it turns out that +the gss-api mechanisms needs more roundtrips. This is implemented. +Unfortunately, racoon does not seem to properly fall back to +its next mode, and this is not specific to the gssapi_krb method. +So, to avoid problems, only specify main mode in the config file. + + + -- Frank van der Linden + diff --git a/ipsec-tools/racoon/Documents/TODO b/ipsec-tools/racoon/Documents/TODO new file mode 100644 index 0000000..1507167 --- /dev/null +++ b/ipsec-tools/racoon/Documents/TODO @@ -0,0 +1,131 @@ +$KAME: TODO,v 1.36 2001/09/19 09:41:39 sakane Exp $ + +Please send any questions or bug reports to snap-users@kame.net. + +TODO list + +URGENT +o The documents for users convenience. +o split log file based on client. printf-like config directive, i.e. + "logfile racoon.%s.log", should be useful here. + -> beware of possible security issue, don't use sprintf() directly! + make validation before giving a string to sprintf(). +o save decrypted IKE packet in tcpdump format +o IPComp SA with wellknown CPI in CPI field. how to handle it? +o better rekey + +MUST +o multiple certificate payload handling. +o To consider the use with certificate infrastructure. PXIX ??? +o kmstat should be improved. +o Informational Exchange processing properly. +o require less configuration. phase 2 is easier (as kernel presents racoon + some hints), phase 1 is harder. for example, + - grab phase 2 lifetime and algorith configuration from sadb_comb payloads in + ACQUIRE message. + - give reasonable default behavior when no configuration file is present. + - difficult items: + how to guess a reasonable phase 1 SA lifetime + (hardcoded default? guess from phase 2 lifetime?) + guess what kind of ID payload to use + guess what kind of authentication to be used + guess phase 1 DH group (for aggressive mode, we cannot negotiate it) + guess if we need phase 2 PFS or not (we cannot negotiate it. so + we may need to pick from "no PFS" or "same as phase 1 DH group") + guess how we should negotiate lifetime + (is "strict" a reasonable default?) + guess which mode to use for phase 1 negotiation (is main mode useful? + is base mode popular enough?) +o more acceptable check. + +SHOULD +o psk.txt should be a database? (psk.db?) psk_mkdb? +o Dynamically retry to exchange and resend the packet per nodes. +o To make the list of supported algorithm by sadb_supported payload + in the SADB_REGISTER message which happens asynchronously. +o fix the structure of ph2handle. + We can handle the below case. + + node A node B + +--------------SA1----------------+ + +--------------SA2----------------+ + + at node A: + kernel + acquire(A-B) ------> ph2handle(A=B) -----> ph1handle + | + policy + A=B + A=B + + But we can not handle the below case because there is no x?handle. + + node A node B node C + +--------------SA1----------------+ + +------------------------------------------------SA2---------------+ + + at node A: + kernel + acquire(A-C) ---+---> x?handle ---+---> ph2handle(A=B) -------> ph1handle + | | | + acquire(A-B) ---+ policy +---> ph2handle(A=C) -------> ph1handle + A=B + A=C + +o consistency of function name. +o deep copy configuration entry to hander. It's easy to reload configuration. +o don't keep to hold keymat values, do it ? +o local address's field in isakmpsa handler must be kicked out to rmconf. +o responder policy and initiator policy should be separated. +o for lifetime and key length, something like this should be useful. + - propose N + - accept between X and Y +o wildcard "accept any proposal" policy should be allowed. +o replay prevention + - limited total number of session + - limited session per peer + - number of proposal +o full support for variable length SPI. quickhack support for IPComp is done. + +MAY +o Effective code. +o interaction between IKE/IPsec and socket layer. + at this moment, IKE/IPsec failure is modeled as total packet loss to other + part of network subsystem, including socket layer. this presents the + following behaviors: + - annoyingly long timeouts on tcp connection attempt, and IKE failure; + need to wait till tcp socket timeouts. + - blackhole if there's mismatching SAs. + we may be able to give socket layer some feedback from IKE/IPsec layer. + still not sure if those make sense or not. + for example: + - send PRU_HOSTDEAD to sockets if IKE negotiation failed + (sys/netkey/key.c:key_acquire2) + to do this, we need to remember which ACQUIRE was caused by which socket, + possibly into larval SAs. + - PRU_QUENCH on "no SA found on output" + - kick tcp retransmission timer on first SA establishment +o IKE daemon should handle situations where peer does not run IKE daemon + (UDP port unreach for port 500) better. + should use connected UDP sockets for sending IKE datagrams. +o rate-limit log messages from kernel IPsec errors, like "no SA found". + +TO BE TESTED. +o IKE retransmit behavior + see, draft-*-ipsec-rekeying*.txt +o Reboot recovery (peer reboot losing it's security associations) + see, draft-*-ipsec-rekeying*.txt +o Scenarios + - End-to-End transport long lived security associations + (over night, data transfer >1Gb) with frequent dynamic rekey + - End-to-GW tunnel long lived security associations + (over night, data transfer >1Gb) with frequent dynamic rekey + - Policy change events while under SA load + - End-to-End SA through IPsec tunnels, initiation both ways + - Client End-to-End through client-to-GW tunnel SA, initiate from + client for tunnel, then initiation both ways for end-to-end + - Client-to-GW transport SA for secure management +o behavior to receive multiple auth method proposals and AND proposal + +and to be written many many. + diff --git a/ipsec-tools/racoon/Sample/anonymous.conf b/ipsec-tools/racoon/Sample/anonymous.conf new file mode 100644 index 0000000..70b0ed4 --- /dev/null +++ b/ipsec-tools/racoon/Sample/anonymous.conf @@ -0,0 +1,34 @@ +remote anonymous +{ + #exchange_mode main,aggressive; + exchange_mode aggressive,main; + doi ipsec_doi; + situation identity_only; + + #my_identifier address; + my_identifier user_fqdn "macuser@localhost"; + peers_identifier user_fqdn "macuser@localhost"; + #certificate_type x509 "mycert" "mypriv"; + + nonce_size 16; + lifetime time 1 min; # sec,min,hour + initial_contact on; + support_mip6 on; + proposal_check obey; # obey, strict or claim + + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key ; + dh_group 2 ; + } +} + +sainfo anonymous +{ + pfs_group 1; + lifetime time 30 sec; + encryption_algorithm aes, 3des ; + authentication_algorithm hmac_sha1; + compression_algorithm deflate ; +} diff --git a/ipsec-tools/racoon/Sample/psk.txt b/ipsec-tools/racoon/Sample/psk.txt new file mode 100644 index 0000000..d7de289 --- /dev/null +++ b/ipsec-tools/racoon/Sample/psk.txt @@ -0,0 +1,10 @@ +# IPv4/v6 addresses +# 10.160.94.3 asecretkeygoeshere +# 172.16.1.133 asecretkeygoeshere +# 3ffe:501:410:ffff:200:86ff:fe05:80fa asecretkeygoeshere +# 3ffe:501:410:ffff:210:4bff:fea2:8baa asecretkeygoeshere + +# USER_FQDN +# macuser@localhost somethingsecret +# FQDN +# kame hoge diff --git a/ipsec-tools/racoon/Sample/racoon.conf b/ipsec-tools/racoon/Sample/racoon.conf new file mode 100644 index 0000000..2a6112b --- /dev/null +++ b/ipsec-tools/racoon/Sample/racoon.conf @@ -0,0 +1,137 @@ +# $KAME: racoon.conf.in,v 1.17 2001/08/14 12:10:22 sakane Exp $ + +# "path" must be placed before it should be used. +# You can overwrite which you defined, but it should not use due to confusing. +path include "/etc/racoon" ; + +# Allow third parties the ability to specify remote and sainfo entries +# by including all files matching /etc/racoon/remote/*.conf +include "/etc/racoon/remote/*.conf" ; + +# search this file for pre_shared_key with various ID key. +path pre_shared_key "/etc/racoon/psk.txt" ; + +# racoon will look for certificate file in the directory, +# if the certificate/certificate request payload is received. +path certificate "/etc/cert" ; + +# "log" specifies logging level. It is followed by either "notify", "debug" +# or "debug2". +#log debug; + +# "padding" defines some parameter of padding. You should not touch these. +padding +{ + maximum_length 20; # maximum padding length. + randomize off; # enable randomize length. + strict_check off; # enable strict check. + exclusive_tail off; # extract last one octet. +} + +# if no listen directive is specified, racoon will listen to all +# available interface addresses. +listen +{ + #isakmp ::1 [7000]; + #isakmp 202.249.11.124 [500]; + #admin [7002]; # administrative's port by kmpstat. + #strict_address; # required all addresses must be bound. +} + +# Specification of default various timer. +timer +{ + # These value can be changed per remote node. + counter 10; # maximum trying count to send. + interval 3 sec; # interval to resend (retransmit) + persend 1; # the number of packets per a send. + + # timer for waiting to complete each phase. + phase1 30 sec; + phase2 30 sec; + + # Auto exit delay timer - for use when controlled by VPN socket + auto_exit_delay 3 sec; +} + +# +# anonymous entry is defined in /etc/racoon/remote/anonymous.conf +# +#remote anonymous +#{ +# #exchange_mode main,aggressive; +# exchange_mode aggressive,main; +# doi ipsec_doi; +# situation identity_only; +# +# #my_identifier address; +# my_identifier user_fqdn "macuser@localhost"; +# peers_identifier user_fqdn "macuser@localhost"; +# #certificate_type x509 "mycert" "mypriv"; +# +# nonce_size 16; +# lifetime time 1 min; # sec,min,hour +# initial_contact on; +# support_mip6 on; +# proposal_check obey; # obey, strict or claim +# +# proposal { +# encryption_algorithm 3des; +# hash_algorithm sha1; +# authentication_method pre_shared_key ; +# dh_group 2 ; +# } +#} + +remote ::1 [8000] +{ + #exchange_mode main,aggressive; + exchange_mode aggressive,main; + doi ipsec_doi; + situation identity_only; + + my_identifier user_fqdn "macuser@localhost"; + peers_identifier user_fqdn "macuser@localhost"; + #certificate_type x509 "mycert" "mypriv"; + + nonce_size 16; + lifetime time 1 min; # sec,min,hour + + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key ; + dh_group 2 ; + } +} + +# +# anonymous entry is defined in /etc/racoon/remote/anonymous.conf +# +#sainfo anonymous +#{ +# pfs_group 1; +# lifetime time 30 sec; +# encryption_algorithm aes, 3des ; +# authentication_algorithm hmac_sha1; +# compression_algorithm deflate ; +#} + +# sainfo address 203.178.141.209 any address 203.178.141.218 any +# { +# pfs_group 1; +# lifetime time 30 sec; +# encryption_algorithm des ; +# authentication_algorithm hmac_md5; +# compression_algorithm deflate ; +# } + +sainfo address ::1 icmp6 address ::1 icmp6 +{ + pfs_group 1; + lifetime time 60 sec; + encryption_algorithm 3des, cast128, blowfish 448, des ; + authentication_algorithm hmac_sha1, hmac_md5 ; + compression_algorithm deflate ; +} + diff --git a/ipsec-tools/racoon/admin.c b/ipsec-tools/racoon/admin.c new file mode 100644 index 0000000..344e2f4 --- /dev/null +++ b/ipsec-tools/racoon/admin.c @@ -0,0 +1,640 @@ +/* $Id: admin.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "localconf.h" +#include "remoteconf.h" +#include "grabmyaddr.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "evt.h" +#include "pfkey.h" +#include "ipsec_doi.h" +#include "admin.h" +#include "admin_var.h" +#include "isakmp_inf.h" +#include "session.h" +#include "gcmalloc.h" + +#ifdef ENABLE_ADMINPORT +char *adminsock_path = ADMINSOCK_PATH; +uid_t adminsock_owner = 0; +gid_t adminsock_group = 0; +mode_t adminsock_mode = 0600; + +static struct sockaddr_un sunaddr; +static int admin_process __P((int, char *)); +static int admin_reply __P((int, struct admin_com *, vchar_t *)); + +int +admin_handler() +{ + int so2; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + struct admin_com com; + char *combuf = NULL; + pid_t pid = -1; + int len, error = -1; + + so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); + if (so2 < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to accept admin command: %s\n", + strerror(errno)); + return -1; + } + + /* get buffer length */ + while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv admin command: %s\n", + strerror(errno)); + goto end; + } + + /* sanity check */ + if (len < sizeof(com)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid header length of admin command\n"); + goto end; + } + + /* get buffer to receive */ + if ((combuf = racoon_malloc(com.ac_len)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to alloc buffer for admin command\n"); + goto end; + } + + /* get real data */ + while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv admin command: %s\n", + strerror(errno)); + goto end; + } + + if (com.ac_cmd == ADMIN_RELOAD_CONF) { + /* reload does not work at all! */ + signal_handler(SIGHUP); + goto end; + } + + error = admin_process(so2, combuf); + + end: + (void)close(so2); + if (combuf) + racoon_free(combuf); + + /* exit if child's process. */ + if (pid == 0 && !f_foreground) + exit(error); + + return error; +} + +/* + * main child's process. + */ +static int +admin_process(so2, combuf) + int so2; + char *combuf; +{ + struct admin_com *com = (struct admin_com *)combuf; + vchar_t *buf = NULL; + vchar_t *id = NULL; + vchar_t *key = NULL; + int idtype = 0; + int error = 0; + + com->ac_errno = 0; + + switch (com->ac_cmd) { + case ADMIN_RELOAD_CONF: + /* don't entered because of proccessing it in other place. */ + plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n"); + goto bad; + + case ADMIN_SHOW_SCHED: + { + caddr_t p; + int len; + if (sched_dump(&p, &len) == -1) + com->ac_errno = -1; + buf = vmalloc(len); + if (buf == NULL) + com->ac_errno = -1; + else + memcpy(buf->v, p, len); + } + break; + + case ADMIN_SHOW_EVT: + /* It's not really an error, don't force racoonctl to quit */ + if ((buf = evt_dump()) == NULL) + com->ac_errno = 0; + break; + + case ADMIN_SHOW_SA: + case ADMIN_FLUSH_SA: + { + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + buf = dumpph1(); + if (buf == NULL) + com->ac_errno = -1; + break; + case ADMIN_FLUSH_SA: + flushph1(); + break; + } + break; + case ADMIN_PROTO_IPSEC: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + { + u_int p; + p = admin2pfkey_proto(com->ac_proto); + if (p == -1) + goto bad; + buf = pfkey_dump_sadb(p); + if (buf == NULL) + com->ac_errno = -1; + } + break; + case ADMIN_FLUSH_SA: + pfkey_flush_sadb(com->ac_proto); + break; + } + break; + + case ADMIN_PROTO_INTERNAL: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + buf = NULL; /*XXX dumpph2(&error);*/ + if (buf == NULL) + com->ac_errno = error; + break; + case ADMIN_FLUSH_SA: + /*XXX flushph2();*/ + com->ac_errno = 0; + break; + } + break; + + default: + /* ignore */ + com->ac_errno = -1; + } + } + break; + + case ADMIN_DELETE_SA: { + struct ph1handle *iph1; + struct sockaddr *dst; + struct sockaddr *src; + char *loc, *rem; + + src = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->src; + dst = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->dst; + + if ((loc = strdup(saddrwop2str(src))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory\n"); + break; + } + if ((rem = strdup(saddrwop2str(dst))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory\n"); + break; + } + + if ((iph1 = getph1byaddrwop(src, dst)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "phase 1 for %s -> %s not found\n", loc, rem); + } else { + if (iph1->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(iph1); + purge_remote(iph1); + } + + racoon_free(loc); + racoon_free(rem); + + break; + } + + case ADMIN_DELETE_ALL_SA_DST: { + struct ph1handle *iph1; + struct sockaddr *dst; + char *loc, *rem; + + dst = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->dst; + + if ((rem = strdup(saddrwop2str(dst))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory\n"); + break; + } + + plog(LLV_INFO, LOCATION, NULL, + "Flushing all SAs for peer %s\n", rem); + + while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { + if ((loc = strdup(saddrwop2str(iph1->local))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory\n"); + break; + } + + if (iph1->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(iph1); + purge_remote(iph1); + + racoon_free(loc); + } + + racoon_free(rem); + + break; + } + + case ADMIN_ESTABLISH_SA_PSK: { + struct admin_com_psk *acp; + char *data; + + com->ac_cmd = ADMIN_ESTABLISH_SA; + + acp = (struct admin_com_psk *) + ((char *)com + sizeof(*com) + + sizeof(struct admin_com_indexes)); + + idtype = acp->id_type; + + if ((id = vmalloc(acp->id_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory: %s\n", + strerror(errno)); + break; + } + data = (char *)(acp + 1); + memcpy(id->v, data, id->l); + + if ((key = vmalloc(acp->key_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory: %s\n", + strerror(errno)); + vfree(id); + break; + } + data = (char *)(data + acp->id_len); + memcpy(key->v, data, key->l); + } + /* FALLTHROUGH */ + case ADMIN_ESTABLISH_SA: + { + struct sockaddr *dst; + struct sockaddr *src; + src = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->src; + dst = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->dst; + + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + { + struct remoteconf *rmconf; + struct sockaddr *remote; + struct sockaddr *local; + + /* search appropreate configuration */ + rmconf = getrmconf(dst); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no configuration found " + "for %s\n", saddrwop2str(dst)); + com->ac_errno = -1; + break; + } + + /* get remote IP address and port number. */ + remote = dupsaddr(dst); + if (remote == NULL) { + com->ac_errno = -1; + break; + } + switch (remote->sa_family) { + case AF_INET: + ((struct sockaddr_in *)remote)->sin_port = + ((struct sockaddr_in *)rmconf->remote)->sin_port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)remote)->sin6_port = + ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + remote->sa_family); + com->ac_errno = -1; + break; + } + + /* get local address */ + local = dupsaddr(src); + if (local == NULL) { + com->ac_errno = -1; + break; + } + switch (local->sa_family) { + case AF_INET: + ((struct sockaddr_in *)local)->sin_port = + getmyaddrsport(local); + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)local)->sin6_port = + getmyaddrsport(local); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + local->sa_family); + com->ac_errno = -1; + break; + } + + /* Set the id and key */ + if (id && key) { + if (rmconf->idv != NULL) { + vfree(rmconf->idv); + rmconf->idv = NULL; + } + if (rmconf->key != NULL) { + vfree(rmconf->key); + rmconf->key = NULL; + } + + rmconf->idvtype = idtype; + rmconf->idv = id; + rmconf->key = key; + } + + plog(LLV_INFO, LOCATION, NULL, + "accept a request to establish IKE-SA: " + "%s\n", saddrwop2str(remote)); + + /* begin ident mode */ + if (isakmp_ph1begin_i(rmconf, remote, local) < 0) { + com->ac_errno = -1; + break; + } + } + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + break; + default: + /* ignore */ + com->ac_errno = -1; + } + } + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid command: %d\n", com->ac_cmd); + com->ac_errno = -1; + } + + if (admin_reply(so2, com, buf) < 0) + goto bad; + + if (buf != NULL) + vfree(buf); + + return 0; + + bad: + if (buf != NULL) + vfree(buf); + return -1; +} + +static int +admin_reply(so, combuf, buf) + int so; + struct admin_com *combuf; + vchar_t *buf; +{ + int tlen; + char *retbuf = NULL; + + if (buf != NULL) + tlen = sizeof(*combuf) + buf->l; + else + tlen = sizeof(*combuf); + + retbuf = racoon_calloc(1, tlen); + if (retbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate admin buffer\n"); + return -1; + } + + memcpy(retbuf, combuf, sizeof(*combuf)); + ((struct admin_com *)retbuf)->ac_len = tlen; + + if (buf != NULL) + memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); + + tlen = send(so, retbuf, tlen, 0); + racoon_free(retbuf); + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to send admin command: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +/* ADMIN_PROTO -> SADB_SATYPE */ +int +admin2pfkey_proto(proto) + u_int proto; +{ + switch (proto) { + case ADMIN_PROTO_IPSEC: + return SADB_SATYPE_UNSPEC; + case ADMIN_PROTO_AH: + return SADB_SATYPE_AH; + case ADMIN_PROTO_ESP: + return SADB_SATYPE_ESP; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported proto for admin: %d\n", proto); + return -1; + } + /*NOTREACHED*/ +} + +int +admin_init() +{ + if (adminsock_path == NULL) { + lcconf->sock_admin = -1; + return 0; + } + + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), + "%s", adminsock_path); + + lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); + if (lcconf->sock_admin == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "socket: %s\n", strerror(errno)); + return -1; + } + + unlink(sunaddr.sun_path); + if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + + if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "chown(%s, %d, %d): %s\n", + sunaddr.sun_path, adminsock_owner, + adminsock_group, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + + if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "chmod(%s, 0%03o): %s\n", + sunaddr.sun_path, adminsock_mode, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + + if (listen(lcconf->sock_admin, 5) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "listen(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "open %s as racoon management.\n", sunaddr.sun_path); + + return 0; +} + +int +admin_close() +{ + close(lcconf->sock_admin); + return 0; +} +#endif diff --git a/ipsec-tools/racoon/admin.h b/ipsec-tools/racoon/admin.h new file mode 100644 index 0000000..e07616d --- /dev/null +++ b/ipsec-tools/racoon/admin.h @@ -0,0 +1,107 @@ +/* $Id: admin.h,v 1.10 2004/12/30 13:45:49 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ADMIN_H +#define _ADMIN_H + +#define ADMINSOCK_PATH ADMINPORTDIR "/racoon.sock" + +extern char *adminsock_path; +extern uid_t adminsock_owner; +extern gid_t adminsock_group; +extern mode_t adminsock_mode; + +/* command for administration. */ +/* NOTE: host byte order. */ +struct admin_com { + u_int16_t ac_len; /* total packet length including data */ + u_int16_t ac_cmd; + int16_t ac_errno; + u_int16_t ac_proto; +}; + +/* + * No data follows as the data. + * These don't use proto field. + */ +#define ADMIN_RELOAD_CONF 0x0001 +#define ADMIN_SHOW_SCHED 0x0002 +#define ADMIN_SHOW_EVT 0x0003 + +/* + * No data follows as the data. + * These use proto field. + */ +#define ADMIN_SHOW_SA 0x0101 +#define ADMIN_FLUSH_SA 0x0102 + +/* + * The admin_com_indexes follows, see below. + */ +#define ADMIN_DELETE_SA 0x0201 +#define ADMIN_ESTABLISH_SA 0x0202 +#define ADMIN_DELETE_ALL_SA_DST 0x0204 /* All SA for a given peer */ + +/* + * The admin_com_indexes and admin_com_psk follow, see below. + */ +#define ADMIN_ESTABLISH_SA_PSK 0x0203 + +/* + * Range 0x08xx is reserved for privilege separation, see privsep.h + */ + +/* the value of proto */ +#define ADMIN_PROTO_ISAKMP 0x01ff +#define ADMIN_PROTO_IPSEC 0x02ff +#define ADMIN_PROTO_AH 0x0201 +#define ADMIN_PROTO_ESP 0x0202 +#define ADMIN_PROTO_INTERNAL 0x0301 + +struct admin_com_indexes { + u_int8_t prefs; + u_int8_t prefd; + u_int8_t ul_proto; + u_int8_t reserved; + struct sockaddr_storage src; + struct sockaddr_storage dst; +}; + +struct admin_com_psk { + int id_type; + size_t id_len; + size_t key_len; + /* Followed by id and key */ +}; + +extern int admin2pfkey_proto __P((u_int)); + +#endif /* _ADMIN_H */ diff --git a/ipsec-tools/racoon/admin_var.h b/ipsec-tools/racoon/admin_var.h new file mode 100644 index 0000000..4054695 --- /dev/null +++ b/ipsec-tools/racoon/admin_var.h @@ -0,0 +1,39 @@ +/* $Id: admin_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ADMIN_VAR_H +#define _ADMIN_VAR_H + +extern int admin_handler __P((void)); +extern int admin_init __P((void)); +extern int admin_close __P((void)); + +#endif /* _ADMIN_VAR_H */ diff --git a/ipsec-tools/racoon/algorithm.c b/ipsec-tools/racoon/algorithm.c new file mode 100644 index 0000000..1af0150 --- /dev/null +++ b/ipsec-tools/racoon/algorithm.c @@ -0,0 +1,915 @@ +/* $Id: algorithm.c,v 1.11.4.1 2005/06/28 22:38:02 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "crypto_openssl.h" +#include "dhgroup.h" +#include "algorithm.h" +#include "oakley.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "gcmalloc.h" + +static struct hash_algorithm oakley_hashdef[] = { +{ "md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5, + eay_md5_init, eay_md5_update, + eay_md5_final, eay_md5_hashlen, + eay_md5_one, }, +{ "sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA, + eay_sha1_init, eay_sha1_update, + eay_sha1_final, eay_sha1_hashlen, + eay_sha1_one, }, +#ifdef WITH_SHA2 +{ "sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256, + eay_sha2_256_init, eay_sha2_256_update, + eay_sha2_256_final, eay_sha2_256_hashlen, + eay_sha2_256_one, }, +{ "sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384, + eay_sha2_384_init, eay_sha2_384_update, + eay_sha2_384_final, eay_sha2_384_hashlen, + eay_sha2_384_one, }, +{ "sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512, + eay_sha2_512_init, eay_sha2_512_update, + eay_sha2_512_final, eay_sha2_512_hashlen, + eay_sha2_512_one, }, +#endif +}; + +static struct hmac_algorithm oakley_hmacdef[] = { +{ "hmac_md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5, + eay_hmacmd5_init, eay_hmacmd5_update, + eay_hmacmd5_final, NULL, + eay_hmacmd5_one, }, +{ "hmac_sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA, + eay_hmacsha1_init, eay_hmacsha1_update, + eay_hmacsha1_final, NULL, + eay_hmacsha1_one, }, +#ifdef WITH_SHA2 +{ "hmac_sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256, + eay_hmacsha2_256_init, eay_hmacsha2_256_update, + eay_hmacsha2_256_final, NULL, + eay_hmacsha2_256_one, }, +{ "hmac_sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384, + eay_hmacsha2_384_init, eay_hmacsha2_384_update, + eay_hmacsha2_384_final, NULL, + eay_hmacsha2_384_one, }, +{ "hmac_sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512, + eay_hmacsha2_512_init, eay_hmacsha2_512_update, + eay_hmacsha2_512_final, NULL, + eay_hmacsha2_512_one, }, +#endif +}; + +static struct enc_algorithm oakley_encdef[] = { +{ "des", algtype_des, OAKLEY_ATTR_ENC_ALG_DES, 8, + eay_des_encrypt, eay_des_decrypt, + eay_des_weakkey, eay_des_keylen, }, +#ifdef HAVE_OPENSSL_IDEA_H +{ "idea", algtype_idea, OAKLEY_ATTR_ENC_ALG_IDEA, 8, + eay_idea_encrypt, eay_idea_decrypt, + eay_idea_weakkey, eay_idea_keylen, }, +#endif +{ "blowfish", algtype_blowfish, OAKLEY_ATTR_ENC_ALG_BLOWFISH, 8, + eay_bf_encrypt, eay_bf_decrypt, + eay_bf_weakkey, eay_bf_keylen, }, +#ifdef HAVE_OPENSSL_RC5_H +{ "rc5", algtype_rc5, OAKLEY_ATTR_ENC_ALG_RC5, 8, + eay_rc5_encrypt, eay_rc5_decrypt, + eay_rc5_weakkey, eay_rc5_keylen, }, +#endif +{ "3des", algtype_3des, OAKLEY_ATTR_ENC_ALG_3DES, 8, + eay_3des_encrypt, eay_3des_decrypt, + eay_3des_weakkey, eay_3des_keylen, }, +{ "cast", algtype_cast128, OAKLEY_ATTR_ENC_ALG_CAST, 8, + eay_cast_encrypt, eay_cast_decrypt, + eay_cast_weakkey, eay_cast_keylen, }, +{ "aes", algtype_aes, OAKLEY_ATTR_ENC_ALG_AES, 16, + eay_aes_encrypt, eay_aes_decrypt, + eay_aes_weakkey, eay_aes_keylen, }, +}; + +static struct enc_algorithm ipsec_encdef[] = { +{ "des-iv64", algtype_des_iv64, IPSECDOI_ESP_DES_IV64, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "des", algtype_des, IPSECDOI_ESP_DES, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "3des", algtype_3des, IPSECDOI_ESP_3DES, 8, + NULL, NULL, + NULL, eay_3des_keylen, }, +#ifdef HAVE_OPENSSL_RC5_H +{ "rc5", algtype_rc5, IPSECDOI_ESP_RC5, 8, + NULL, NULL, + NULL, eay_rc5_keylen, }, +#endif +{ "cast", algtype_cast128, IPSECDOI_ESP_CAST, 8, + NULL, NULL, + NULL, eay_cast_keylen, }, +{ "blowfish", algtype_blowfish, IPSECDOI_ESP_BLOWFISH, 8, + NULL, NULL, + NULL, eay_bf_keylen, }, +{ "des-iv32", algtype_des_iv32, IPSECDOI_ESP_DES_IV32, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "null", algtype_null_enc, IPSECDOI_ESP_NULL, 8, + NULL, NULL, + NULL, eay_null_keylen, }, +{ "aes", algtype_aes, IPSECDOI_ESP_AES, 16, + NULL, NULL, + NULL, eay_aes_keylen, }, +{ "twofish", algtype_twofish, IPSECDOI_ESP_TWOFISH, 16, + NULL, NULL, + NULL, eay_twofish_keylen, }, +#ifdef HAVE_OPENSSL_IDEA_H +{ "3idea", algtype_3idea, IPSECDOI_ESP_3IDEA, 8, + NULL, NULL, + NULL, NULL, }, +{ "idea", algtype_idea, IPSECDOI_ESP_IDEA, 8, + NULL, NULL, + NULL, NULL, }, +#endif +{ "rc4", algtype_rc4, IPSECDOI_ESP_RC4, 8, + NULL, NULL, + NULL, NULL, }, +}; + +static struct hmac_algorithm ipsec_hmacdef[] = { +{ "md5", algtype_hmac_md5, IPSECDOI_ATTR_AUTH_HMAC_MD5, + NULL, NULL, + NULL, eay_md5_hashlen, + NULL, }, +{ "sha1", algtype_hmac_sha1, IPSECDOI_ATTR_AUTH_HMAC_SHA1, + NULL, NULL, + NULL, eay_sha1_hashlen, + NULL, }, +{ "kpdk", algtype_kpdk, IPSECDOI_ATTR_AUTH_KPDK, + NULL, NULL, + NULL, eay_kpdk_hashlen, + NULL, }, +{ "null", algtype_non_auth, IPSECDOI_ATTR_AUTH_NONE, + NULL, NULL, + NULL, eay_null_hashlen, + NULL, }, +#ifdef WITH_SHA2 +{ "hmac_sha2_256", algtype_hmac_sha2_256,IPSECDOI_ATTR_AUTH_HMAC_SHA2_256, + NULL, NULL, + NULL, eay_sha2_256_hashlen, + NULL, }, +{ "hmac_sha2_384", algtype_hmac_sha2_384,IPSECDOI_ATTR_AUTH_HMAC_SHA2_384, + NULL, NULL, + NULL, eay_sha2_384_hashlen, + NULL, }, +{ "hmac_sha2_512", algtype_hmac_sha2_512,IPSECDOI_ATTR_AUTH_HMAC_SHA2_512, + NULL, NULL, + NULL, eay_sha2_512_hashlen, + NULL, }, +#endif +}; + +static struct misc_algorithm ipsec_compdef[] = { +{ "oui", algtype_oui, IPSECDOI_IPCOMP_OUI, }, +{ "deflate", algtype_deflate, IPSECDOI_IPCOMP_DEFLATE, }, +{ "lzs", algtype_lzs, IPSECDOI_IPCOMP_LZS, }, +}; + +static struct misc_algorithm oakley_authdef[] = { +{ "pre_shared_key", algtype_psk, OAKLEY_ATTR_AUTH_METHOD_PSKEY, }, +{ "dsssig", algtype_dsssig, OAKLEY_ATTR_AUTH_METHOD_DSSSIG, }, +{ "rsasig", algtype_rsasig, OAKLEY_ATTR_AUTH_METHOD_RSASIG, }, +{ "rsaenc", algtype_rsaenc, OAKLEY_ATTR_AUTH_METHOD_RSAENC, }, +{ "rsarev", algtype_rsarev, OAKLEY_ATTR_AUTH_METHOD_RSAREV, }, +{ "gssapi_krb", algtype_gssapikrb, OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, }, +#ifdef ENABLE_HYBRID +{ "hybrid_rsa_server", algtype_hybrid_rsa_s, + OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I, }, +{ "hybrid_dss_server", algtype_hybrid_dss_s, + OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I, }, +{ "hybrid_rsa_client", algtype_hybrid_rsa_c, + OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R, }, +{ "hybrid_dss_client", algtype_hybrid_dss_c, + OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R, }, +#endif +}; + +static struct dh_algorithm oakley_dhdef[] = { +{ "modp768", algtype_modp768, OAKLEY_ATTR_GRP_DESC_MODP768, + &dh_modp768, }, +{ "modp1024", algtype_modp1024, OAKLEY_ATTR_GRP_DESC_MODP1024, + &dh_modp1024, }, +{ "modp1536", algtype_modp1536, OAKLEY_ATTR_GRP_DESC_MODP1536, + &dh_modp1536, }, +{ "modp2048", algtype_modp2048, OAKLEY_ATTR_GRP_DESC_MODP2048, + &dh_modp2048, }, +{ "modp3072", algtype_modp3072, OAKLEY_ATTR_GRP_DESC_MODP3072, + &dh_modp3072, }, +{ "modp4096", algtype_modp4096, OAKLEY_ATTR_GRP_DESC_MODP4096, + &dh_modp4096, }, +{ "modp6144", algtype_modp6144, OAKLEY_ATTR_GRP_DESC_MODP6144, + &dh_modp6144, }, +{ "modp8192", algtype_modp8192, OAKLEY_ATTR_GRP_DESC_MODP8192, + &dh_modp8192, }, +}; + +static struct hash_algorithm *alg_oakley_hashdef __P((int)); +static struct hmac_algorithm *alg_oakley_hmacdef __P((int)); +static struct enc_algorithm *alg_oakley_encdef __P((int)); +static struct enc_algorithm *alg_ipsec_encdef __P((int)); +static struct hmac_algorithm *alg_ipsec_hmacdef __P((int)); +static struct dh_algorithm *alg_oakley_dhdef __P((int)); + +/* oakley hash algorithm */ +static struct hash_algorithm * +alg_oakley_hashdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_hashdef); i++) + if (doi == oakley_hashdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hash(%s)\n", + oakley_hashdef[i].name); + return &oakley_hashdef[i]; + } + return NULL; +} + +int +alg_oakley_hashdef_ok(doi) + int doi; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_hashdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_hashdef); i++) + if (type == oakley_hashdef[i].type) { + res = oakley_hashdef[i].doi; + break; + } + return res; +} + +int +alg_oakley_hashdef_hashlen(doi) + int doi; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL || f->hashlen == NULL) + return 0; + + return (f->hashlen)(); +} + +const char * +alg_oakley_hashdef_name (doi) + int doi; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL) + return "*UNKNOWN*"; + + return f->name; +} + +vchar_t * +alg_oakley_hashdef_one(doi, buf) + int doi; + vchar_t *buf; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL || f->hashlen == NULL) + return NULL; + + return (f->one)(buf); +} + +/* oakley hmac algorithm */ +static struct hmac_algorithm * +alg_oakley_hmacdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++) + if (doi == oakley_hmacdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_hmacdef[i].name); + return &oakley_hmacdef[i]; + } + return NULL; +} + +int +alg_oakley_hmacdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++) + if (type == oakley_hmacdef[i].type) { + res = oakley_hmacdef[i].doi; + break; + } + return res; +} + +vchar_t * +alg_oakley_hmacdef_one(doi, key, buf) + int doi; + vchar_t *key, *buf; +{ + struct hmac_algorithm *f; + vchar_t *res; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_hmacdef(doi); + if (f == NULL || f->one == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->one)(key, buf); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s size=%d): %8.6f", __func__, + f->name, buf->l, timedelta(&start, &end)); +#endif + + return res; +} + +/* oakley encryption algorithm */ +static struct enc_algorithm * +alg_oakley_encdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_encdef); i++) + if (doi == oakley_encdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n", + oakley_encdef[i].name); + return &oakley_encdef[i]; + } + return NULL; +} + +int +alg_oakley_encdef_ok(doi) + int doi; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_encdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_encdef); i++) + if (type == oakley_encdef[i].type) { + res = oakley_encdef[i].doi; + break; + } + return res; +} + +int +alg_oakley_encdef_keylen(doi, len) + int doi, len; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL || f->keylen == NULL) + return -1; + + return (f->keylen)(len); +} + +int +alg_oakley_encdef_blocklen(doi) + int doi; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL) + return -1; + + return f->blocklen; +} + +const char * +alg_oakley_encdef_name (doi) + int doi; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL) + return "*UNKNOWN*"; + + return f->name; +} + +vchar_t * +alg_oakley_encdef_decrypt(doi, buf, key, iv) + int doi; + vchar_t *buf, *key, *iv; +{ + vchar_t *res; + struct enc_algorithm *f; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_encdef(doi); + if (f == NULL || f->decrypt == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->decrypt)(buf, key, iv); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __func__, + f->name, key->l << 3, buf->l, timedelta(&start, &end)); +#endif + return res; +} + +vchar_t * +alg_oakley_encdef_encrypt(doi, buf, key, iv) + int doi; + vchar_t *buf, *key, *iv; +{ + vchar_t *res; + struct enc_algorithm *f; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_encdef(doi); + if (f == NULL || f->encrypt == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->encrypt)(buf, key, iv); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __func__, + f->name, key->l << 3, buf->l, timedelta(&start, &end)); +#endif + return res; +} + +/* ipsec encryption algorithm */ +static struct enc_algorithm * +alg_ipsec_encdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(ipsec_encdef); i++) + if (doi == ipsec_encdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n", + ipsec_encdef[i].name); + return &ipsec_encdef[i]; + } + return NULL; +} + +int +alg_ipsec_encdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_encdef); i++) + if (type == ipsec_encdef[i].type) { + res = ipsec_encdef[i].doi; + break; + } + return res; +} + +int +alg_ipsec_encdef_keylen(doi, len) + int doi, len; +{ + struct enc_algorithm *f; + + f = alg_ipsec_encdef(doi); + if (f == NULL || f->keylen == NULL) + return -1; + + return (f->keylen)(len); +} + +/* ipsec hmac algorithm */ +static struct hmac_algorithm * +alg_ipsec_hmacdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++) + if (doi == ipsec_hmacdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_hmacdef[i].name); + return &ipsec_hmacdef[i]; + } + return NULL; +} + +int +alg_ipsec_hmacdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++) + if (type == ipsec_hmacdef[i].type) { + res = ipsec_hmacdef[i].doi; + break; + } + return res; +} + +int +alg_ipsec_hmacdef_hashlen(doi) + int doi; +{ + struct hmac_algorithm *f; + + f = alg_ipsec_hmacdef(doi); + if (f == NULL || f->hashlen == NULL) + return -1; + + return (f->hashlen)(); +} + +/* ip compression */ +int +alg_ipsec_compdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_compdef); i++) + if (type == ipsec_compdef[i].type) { + res = ipsec_compdef[i].doi; + break; + } + return res; +} + +/* dh algorithm */ +static struct dh_algorithm * +alg_oakley_dhdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_dhdef); i++) + if (doi == oakley_dhdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_dhdef[i].name); + return &oakley_dhdef[i]; + } + return NULL; +} + +int +alg_oakley_dhdef_ok(doi) + int doi; +{ + struct dh_algorithm *f; + + f = alg_oakley_dhdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_dhdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_dhdef); i++) + if (type == oakley_dhdef[i].type) { + res = oakley_dhdef[i].doi; + break; + } + return res; +} + +struct dhgroup * +alg_oakley_dhdef_group(doi) + int doi; +{ + struct dh_algorithm *f; + + f = alg_oakley_dhdef(doi); + if (f == NULL || f->dhgroup == NULL) + return NULL; + + return f->dhgroup; +} + +const char * +alg_oakley_dhdef_name (doi) + int doi; +{ + struct dh_algorithm *f; + + f = alg_oakley_dhdef(doi); + if (f == NULL) + return "*UNKNOWN*"; + return f->name; +} + +/* authentication method */ +int +alg_oakley_authdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_authdef); i++) + if (type == oakley_authdef[i].type) { + res = oakley_authdef[i].doi; + break; + } + return res; +} + +const char * +alg_oakley_authdef_name (doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_authdef); i++) + if (doi == oakley_authdef[i].doi) { + return oakley_authdef[i].name; + } + return "*UNKNOWN*"; +} + +/* + * give the default key length + * OUT: -1: NG + * 0: fixed key cipher, key length not allowed + * positive: default key length + */ +int +default_keylen(class, type) + int class, type; +{ + + switch (class) { + case algclass_isakmp_enc: + case algclass_ipsec_enc: + break; + default: + return 0; + } + + switch (type) { + case algtype_blowfish: + case algtype_rc5: + case algtype_cast128: + case algtype_aes: + case algtype_twofish: + return 128; + default: + return 0; + } +} + +/* + * check key length + * OUT: -1: NG + * 0: OK + */ +int +check_keylen(class, type, len) + int class, type, len; +{ + int badrange; + + switch (class) { + case algclass_isakmp_enc: + case algclass_ipsec_enc: + break; + default: + /* unknown class, punt */ + plog(LLV_ERROR, LOCATION, NULL, + "unknown algclass %d\n", class); + return -1; + } + + /* key length must be multiple of 8 bytes - RFC2451 2.2 */ + switch (type) { + case algtype_blowfish: + case algtype_rc5: + case algtype_cast128: + case algtype_aes: + case algtype_twofish: + if (len % 8 != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "key length %d is not multiple of 8\n", len); + return -1; + } + break; + } + + /* key length range */ + badrange = 0; + switch (type) { + case algtype_blowfish: + if (len < 40 || 448 < len) + badrange++; + break; + case algtype_rc5: + if (len < 40 || 2040 < len) + badrange++; + break; + case algtype_cast128: + if (len < 40 || 128 < len) + badrange++; + break; + case algtype_aes: + if (!(len == 128 || len == 192 || len == 256)) + badrange++; + break; + case algtype_twofish: + if (len < 40 || 256 < len) + badrange++; + break; + default: + if (len) { + plog(LLV_ERROR, LOCATION, NULL, + "key length is not allowed"); + return -1; + } + break; + } + if (badrange) { + plog(LLV_ERROR, LOCATION, NULL, + "key length out of range\n"); + return -1; + } + + return 0; +} + +/* + * convert algorithm type to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +algtype2doi(class, type) + int class, type; +{ + int res = -1; + + switch (class) { + case algclass_ipsec_enc: + res = alg_ipsec_encdef_doi(type); + break; + case algclass_ipsec_auth: + res = alg_ipsec_hmacdef_doi(type); + break; + case algclass_ipsec_comp: + res = alg_ipsec_compdef_doi(type); + break; + case algclass_isakmp_enc: + res = alg_oakley_encdef_doi(type); + break; + case algclass_isakmp_hash: + res = alg_oakley_hashdef_doi(type); + break; + case algclass_isakmp_dh: + res = alg_oakley_dhdef_doi(type); + break; + case algclass_isakmp_ameth: + res = alg_oakley_authdef_doi(type); + break; + } + return res; +} + +/* + * convert algorithm class to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +algclass2doi(class) + int class; +{ + switch (class) { + case algclass_ipsec_enc: + return IPSECDOI_PROTO_IPSEC_ESP; + case algclass_ipsec_auth: + return IPSECDOI_ATTR_AUTH; + case algclass_ipsec_comp: + return IPSECDOI_PROTO_IPCOMP; + case algclass_isakmp_enc: + return OAKLEY_ATTR_ENC_ALG; + case algclass_isakmp_hash: + return OAKLEY_ATTR_HASH_ALG; + case algclass_isakmp_dh: + return OAKLEY_ATTR_GRP_DESC; + case algclass_isakmp_ameth: + return OAKLEY_ATTR_AUTH_METHOD; + default: + return -1; + } + /*NOTREACHED*/ + return -1; +} diff --git a/ipsec-tools/racoon/algorithm.h b/ipsec-tools/racoon/algorithm.h new file mode 100644 index 0000000..e4fc1fe --- /dev/null +++ b/ipsec-tools/racoon/algorithm.h @@ -0,0 +1,209 @@ +/* $Id: algorithm.h,v 1.8 2004/11/18 15:14:44 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ALGORITHM_H +#define _ALGORITHM_H + +#include + +/* algorithm class */ +enum { + algclass_ipsec_enc, + algclass_ipsec_auth, + algclass_ipsec_comp, + algclass_isakmp_enc, + algclass_isakmp_hash, + algclass_isakmp_dh, + algclass_isakmp_ameth, /* authentication method. */ +#define MAXALGCLASS 7 +}; + +#define ALG_DEFAULT_KEYLEN 64 + +#define ALGTYPE_NOTHING 0 + +/* algorithm type */ +enum algtype { + algtype_nothing = 0, + + /* enc */ + algtype_des_iv64, + algtype_des, + algtype_3des, + algtype_rc5, + algtype_idea, + algtype_cast128, + algtype_blowfish, + algtype_3idea, + algtype_des_iv32, + algtype_rc4, + algtype_null_enc, + algtype_aes, + algtype_twofish, + + /* ipsec auth */ + algtype_hmac_md5, + algtype_hmac_sha1, + algtype_des_mac, + algtype_kpdk, + algtype_non_auth, + algtype_hmac_sha2_256, + algtype_hmac_sha2_384, + algtype_hmac_sha2_512, + + /* ipcomp */ + algtype_oui, + algtype_deflate, + algtype_lzs, + + /* hash */ + algtype_md5, + algtype_sha1, + algtype_tiger, + algtype_sha2_256, + algtype_sha2_384, + algtype_sha2_512, + + /* dh_group */ + algtype_modp768, + algtype_modp1024, + algtype_ec2n155, + algtype_ec2n185, + algtype_modp1536, + algtype_modp2048, + algtype_modp3072, + algtype_modp4096, + algtype_modp6144, + algtype_modp8192, + + /* authentication method. */ + algtype_psk, + algtype_dsssig, + algtype_rsasig, + algtype_rsaenc, + algtype_rsarev, + algtype_gssapikrb, +#ifdef ENABLE_HYBRID + algtype_hybrid_rsa_s, + algtype_hybrid_dss_s, + algtype_hybrid_rsa_c, + algtype_hybrid_dss_c, +#endif +}; + +struct hmac_algorithm { + char *name; + int type; + int doi; + caddr_t (*init) __P((vchar_t *)); + void (*update) __P((caddr_t, vchar_t *)); + vchar_t *(*final) __P((caddr_t)); + int (*hashlen) __P((void)); + vchar_t *(*one) __P((vchar_t *, vchar_t *)); +}; + +struct hash_algorithm { + char *name; + int type; + int doi; + caddr_t (*init) __P((void)); + void (*update) __P((caddr_t, vchar_t *)); + vchar_t *(*final) __P((caddr_t)); + int (*hashlen) __P((void)); + vchar_t *(*one) __P((vchar_t *)); +}; + +struct enc_algorithm { + char *name; + int type; + int doi; + int blocklen; + vchar_t *(*encrypt) __P((vchar_t *, vchar_t *, vchar_t *)); + vchar_t *(*decrypt) __P((vchar_t *, vchar_t *, vchar_t *)); + int (*weakkey) __P((vchar_t *)); + int (*keylen) __P((int)); +}; + +/* dh group */ +struct dh_algorithm { + char *name; + int type; + int doi; + struct dhgroup *dhgroup; +}; + +/* ipcomp, auth meth, dh group */ +struct misc_algorithm { + char *name; + int type; + int doi; +}; + +extern int alg_oakley_hashdef_ok __P((int)); +extern int alg_oakley_hashdef_doi __P((int)); +extern int alg_oakley_hashdef_hashlen __P((int)); +extern vchar_t *alg_oakley_hashdef_one __P((int, vchar_t *)); + +extern int alg_oakley_hmacdef_doi __P((int)); +extern vchar_t *alg_oakley_hmacdef_one __P((int, vchar_t *, vchar_t *)); + +extern int alg_oakley_encdef_ok __P((int)); +extern int alg_oakley_encdef_doi __P((int)); +extern int alg_oakley_encdef_keylen __P((int, int)); +extern int alg_oakley_encdef_blocklen __P((int)); +extern vchar_t *alg_oakley_encdef_decrypt __P((int, vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *alg_oakley_encdef_encrypt __P((int, vchar_t *, vchar_t *, vchar_t *)); + +extern int alg_ipsec_encdef_doi __P((int)); +extern int alg_ipsec_encdef_keylen __P((int, int)); + +extern int alg_ipsec_hmacdef_doi __P((int)); +extern int alg_ipsec_hmacdef_hashlen __P((int)); + +extern int alg_ipsec_compdef_doi __P((int)); + +extern int alg_oakley_dhdef_doi __P((int)); +extern int alg_oakley_dhdef_ok __P((int)); +extern struct dhgroup *alg_oakley_dhdef_group __P((int)); + +extern int alg_oakley_authdef_doi __P((int)); + +extern int default_keylen __P((int, int)); +extern int check_keylen __P((int, int, int)); +extern int algtype2doi __P((int, int)); +extern int algclass2doi __P((int)); + +extern const char *alg_oakley_encdef_name __P((int)); +extern const char *alg_oakley_hashdef_name __P((int)); +extern const char *alg_oakley_dhdef_name __P((int)); +extern const char *alg_oakley_authdef_name __P((int)); + +#endif /* _ALGORITHM_H */ diff --git a/ipsec-tools/racoon/arc4random.h b/ipsec-tools/racoon/arc4random.h new file mode 100644 index 0000000..1957945 --- /dev/null +++ b/ipsec-tools/racoon/arc4random.h @@ -0,0 +1,39 @@ +/* $KAME: arc4random.h,v 1.1 2002/06/04 05:23:26 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __ARC4RANDOM_H__ +#define __ARC4RANDOM_H__ + +extern u_int32_t arc4random __P((void)); + + +#endif /* __ARC4RANDOM_H__ */ + diff --git a/ipsec-tools/racoon/backupsa.c b/ipsec-tools/racoon/backupsa.c new file mode 100644 index 0000000..1b9f1f8 --- /dev/null +++ b/ipsec-tools/racoon/backupsa.c @@ -0,0 +1,505 @@ +/* $KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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 +int +main() +{ + struct tm tm; + time_t t; + char *buf = "Nov 24 18:22:48 1986 "; + char *p; + + memset(&tm, 0, sizeof(tm)); + p = str2tmx(buf, &tm); + printf("[%x]\n", *p); + t = mktime(&tm); + if (t == -1) + printf("mktime failed."); + p = ctime(&t); + printf("[%s]\n", p); + + exit(0); +} +#endif diff --git a/ipsec-tools/racoon/backupsa.h b/ipsec-tools/racoon/backupsa.h new file mode 100644 index 0000000..67cb67c --- /dev/null +++ b/ipsec-tools/racoon/backupsa.h @@ -0,0 +1,42 @@ +/* $Id: backupsa.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BACKUPSA_H +#define _BACKUPSA_H + +extern int backupsa_to_file __P((u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, + u_int32_t, u_int64_t, u_int64_t, u_int64_t, u_int32_t)); +extern int backupsa_from_file __P((void)); +extern int backupsa_clean __P((void)); + +#endif /* _BACKUPSA_H */ diff --git a/ipsec-tools/racoon/cfparse.y b/ipsec-tools/racoon/cfparse.y new file mode 100644 index 0000000..d9ac8a4 --- /dev/null +++ b/ipsec-tools/racoon/cfparse.y @@ -0,0 +1,2158 @@ +/* $Id: cfparse.y,v 1.37.2.7 2006/02/02 14:37:17 vanhu Exp $ */ + +%{ +/* + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 and 2003 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#ifdef ENABLE_HYBRID +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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 NUMBER BOOLEAN SWITCH keylength +%type PATHTYPE IDENTIFIERTYPE LOGLEV GSS_ID_ENCTYPE +%type SECRETTYPE +%type ALGORITHM_CLASS dh_group_num +%type ALGORITHMTYPE STRENGTHTYPE +%type PREFIX prefix PORT port ike_port +%type ul_proto UL_PROTO +%type EXCHANGETYPE DOITYPE SITUATIONTYPE +%type CERTTYPE CERT_X509 CERT_PLAINRSA PROPOSAL_CHECK_LEVEL NAT_TRAVERSAL_LEVEL +%type VERIFICATION_MODULE VERIFICATION_OPTION +%type unittype_time unittype_byte +%type QUOTEDSTRING HEXSTRING ADDRSTRING sainfo_id +%type identifierstring +%type remote_index ike_addrinfo_port +%type algorithm + +%% + +statements + : /* nothing */ + | statements statement + ; +statement + : privsep_statement + | path_statement + | include_statement + | gssenc_statement + | identifier_statement + | logging_statement + | padding_statement + | listen_statement + | modecfg_statement + | timer_statement + | sainfo_statement + | remote_statement + | special_statement + ; + + /* privsep */ +privsep_statement + : PRIVSEP BOC privsep_stmts EOC + ; +privsep_stmts + : /* nothing */ + | privsep_stmts privsep_stmt + ; +privsep_stmt + : USER QUOTEDSTRING + { + struct passwd *pw; + + if ((pw = getpwnam($2->v)) == NULL) { + yyerror("unkown user \"%s\"", $2->v); + return -1; + } + lcconf->uid = pw->pw_uid; + } + EOS + | USER NUMBER { lcconf->uid = $2; } EOS + | GROUP QUOTEDSTRING + { + struct group *gr; + + if ((gr = getgrnam($2->v)) == NULL) { + yyerror("unkown group \"%s\"", $2->v); + return -1; + } + lcconf->gid = gr->gr_gid; + } + EOS + | GROUP NUMBER { lcconf->gid = $2; } EOS + | CHROOT QUOTEDSTRING { lcconf->chroot = $2->v; } EOS + ; + + /* path */ +path_statement + : PATH PATHTYPE QUOTEDSTRING + { + if ($2 >= LC_PATHTYPE_MAX) { + yyerror("invalid path type %d", $2); + return -1; + } + + /* free old pathinfo */ + if (lcconf->pathinfo[$2]) + racoon_free(lcconf->pathinfo[$2]); + + /* set new pathinfo */ + lcconf->pathinfo[$2] = strdup($3->v); + vfree($3); + } + EOS + ; + + /* special */ +special_statement + : COMPLEX_BUNDLE SWITCH { lcconf->complex_bundle = $2; } EOS + ; + + /* include */ +include_statement + : INCLUDE QUOTEDSTRING EOS + { + char path[MAXPATHLEN]; + + getpathname(path, sizeof(path), + LC_PATHTYPE_INCLUDE, $2->v); + vfree($2); + if (yycf_switch_buffer(path) != 0) + return -1; + } + ; + + /* gss_id_enc */ +gssenc_statement + : GSS_ID_ENC GSS_ID_ENCTYPE EOS + { + if ($2 >= LC_GSSENC_MAX) { + yyerror("invalid GSS ID encoding %d", $2); + return -1; + } + lcconf->gss_id_enc = $2; + } + ; + + /* self infomation */ +identifier_statement + : IDENTIFIER identifier_stmt + ; +identifier_stmt + : VENDORID + { + /*XXX to be deleted */ + } + QUOTEDSTRING EOS + | IDENTIFIERTYPE QUOTEDSTRING + { + /*XXX to be deleted */ + $2->l--; /* nuke '\0' */ + lcconf->ident[$1] = $2; + if (lcconf->ident[$1] == NULL) { + yyerror("failed to set my ident: %s", + strerror(errno)); + return -1; + } + } + EOS + ; + + /* logging */ +logging_statement + : LOGGING log_level EOS + ; +log_level + : HEXSTRING + { + /* + * XXX ignore it because this specification + * will be obsoleted. + */ + yywarn("see racoon.conf(5), such a log specification will be obsoleted."); + vfree($1); + } + | LOGLEV + { + /* + * set the loglevel by configuration file only when + * the command line did not specify any loglevel. + */ + if (loglevel <= LLV_BASE) + loglevel += $1; + } + ; + + /* padding */ +padding_statement + : PADDING BOC padding_stmts EOC + ; +padding_stmts + : /* nothing */ + | padding_stmts padding_stmt + ; +padding_stmt + : PAD_RANDOMIZE SWITCH { lcconf->pad_random = $2; } EOS + | PAD_RANDOMIZELEN SWITCH { lcconf->pad_randomlen = $2; } EOS + | PAD_MAXLEN NUMBER { lcconf->pad_maxsize = $2; } EOS + | PAD_STRICT SWITCH { lcconf->pad_strict = $2; } EOS + | PAD_EXCLTAIL SWITCH { lcconf->pad_excltail = $2; } EOS + ; + + /* listen */ +listen_statement + : LISTEN BOC listen_stmts EOC + ; +listen_stmts + : /* nothing */ + | listen_stmts listen_stmt + ; +listen_stmt + : X_ISAKMP ike_addrinfo_port + { + listen_addr ($2, 0); + } + EOS + | X_ISAKMP_NATT ike_addrinfo_port + { +#ifdef ENABLE_NATT + listen_addr ($2, 1); +#else + yyerror("NAT-T support not compiled in."); +#endif + } + EOS + | X_ADMIN + { + yyerror("admin directive is obsoleted."); + } + PORT EOS + | ADMINSOCK QUOTEDSTRING QUOTEDSTRING QUOTEDSTRING NUMBER + { +#ifdef ENABLE_ADMINPORT + adminsock_conf($2, $3, $4, $5); +#else + yywarn("admin port support not compiled in"); +#endif + } + EOS + | ADMINSOCK QUOTEDSTRING + { +#ifdef ENABLE_ADMINPORT + adminsock_conf($2, NULL, NULL, -1); +#else + yywarn("admin port support not compiled in"); +#endif + } + EOS + | ADMINSOCK DISABLED + { +#ifdef ENABLE_ADMINPORT + adminsock_path = NULL; +#else + yywarn("admin port support not compiled in"); +#endif + } + EOS + | STRICT_ADDRESS { lcconf->strict_address = TRUE; } EOS + ; +ike_addrinfo_port + : ADDRSTRING ike_port + { + char portbuf[10]; + + snprintf(portbuf, sizeof(portbuf), "%ld", $2); + $$ = str2saddr($1->v, portbuf); + vfree($1); + if (!$$) + return -1; + } + ; +ike_port + : /* nothing */ { $$ = PORT_ISAKMP; } + | PORT { $$ = $1; } + ; + /* modecfg */ +modecfg_statement + : MODECFG BOC modecfg_stmts EOC + ; +modecfg_stmts + : /* nothing */ + | modecfg_stmts modecfg_stmt + ; +modecfg_stmt + : CFG_NET4 ADDRSTRING + { +#ifdef ENABLE_HYBRID + if (inet_pton(AF_INET, $2->v, + &isakmp_cfg_config.network4) != 1) + yyerror("bad IPv4 network address."); +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_MASK4 ADDRSTRING + { +#ifdef ENABLE_HYBRID + if (inet_pton(AF_INET, $2->v, + &isakmp_cfg_config.netmask4) != 1) + yyerror("bad IPv4 netmask address."); +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_DNS4 ADDRSTRING + { +#ifdef ENABLE_HYBRID + if (inet_pton(AF_INET, $2->v, + &isakmp_cfg_config.dns4) != 1) + yyerror("bad IPv4 DNS address."); +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_NBNS4 ADDRSTRING + { +#ifdef ENABLE_HYBRID + if (inet_pton(AF_INET, $2->v, + &isakmp_cfg_config.nbns4) != 1) + yyerror("bad IPv4 WINS address."); +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_AUTH_SOURCE CFG_SYSTEM + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_SYSTEM; +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_AUTH_SOURCE CFG_RADIUS + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_RADIUS; +#else /* HAVE_LIBRADIUS */ + yyerror("racoon not configured with --with-libradius"); +#endif /* HAVE_LIBRADIUS */ +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_AUTH_SOURCE CFG_PAM + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBPAM + isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_PAM; +#else /* HAVE_LIBPAM */ + yyerror("racoon not configured with --with-libpam"); +#endif /* HAVE_LIBPAM */ +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_ACCOUNTING CFG_NONE + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_NONE; +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | CFG_ACCOUNTING CFG_RADIUS + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_RADIUS; +#else /* HAVE_LIBRADIUS */ + yyerror("racoon not configured with --with-libradius"); +#endif /* HAVE_LIBRADIUS */ +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_ACCOUNTING CFG_PAM + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBPAM + isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_PAM; +#else /* HAVE_LIBPAM */ + yyerror("racoon not configured with --with-libpam"); +#endif /* HAVE_LIBPAM */ +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_POOL_SIZE NUMBER + { +#ifdef ENABLE_HYBRID + size_t len; + + isakmp_cfg_config.pool_size = $2; + + len = $2 * sizeof(*isakmp_cfg_config.port_pool); + isakmp_cfg_config.port_pool = racoon_malloc(len); + if (isakmp_cfg_config.port_pool == NULL) + yyerror("cannot allocate memory for pool"); + bzero(isakmp_cfg_config.port_pool, len); +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_PFS_GROUP NUMBER + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.pfs_group = $2; +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_SAVE_PASSWD SWITCH + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.save_passwd = $2; +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_AUTH_THROTTLE NUMBER + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.auth_throttle = $2; +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_CONF_SOURCE CFG_LOCAL + { +#ifdef ENABLE_HYBRID + isakmp_cfg_config.confsource = ISAKMP_CFG_CONF_LOCAL; +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_CONF_SOURCE CFG_RADIUS + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + isakmp_cfg_config.confsource = ISAKMP_CFG_CONF_RADIUS; +#else /* HAVE_LIBRADIUS */ + yyerror("racoon not configured with --with-libradius"); +#endif /* HAVE_LIBRADIUS */ +#else /* ENABLE_HYBRID */ + yyerror("racoon not configured with --enable-hybrid"); +#endif /* ENABLE_HYBRID */ + } + EOS + | CFG_MOTD QUOTEDSTRING + { +#ifdef ENABLE_HYBRID + strncpy(&isakmp_cfg_config.motd[0], $2->v, MAXPATHLEN); + isakmp_cfg_config.motd[MAXPATHLEN] = '\0'; + vfree($2); +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + ; + + /* timer */ +timer_statement + : RETRY BOC timer_stmts EOC + ; +timer_stmts + : /* nothing */ + | timer_stmts timer_stmt + ; +timer_stmt + : RETRY_COUNTER NUMBER + { + lcconf->retry_counter = $2; + } + EOS + | RETRY_INTERVAL NUMBER unittype_time + { + lcconf->retry_interval = $2 * $3; + } + EOS + | RETRY_PERSEND NUMBER + { + lcconf->count_persend = $2; + } + EOS + | RETRY_PHASE1 NUMBER unittype_time + { + lcconf->retry_checkph1 = $2 * $3; + } + EOS + | RETRY_PHASE2 NUMBER unittype_time + { + lcconf->wait_ph2complete = $2 * $3; + } + EOS + | AUTO_EXIT_DELAY NUMBER unittype_time + { + lcconf->auto_exit_delay = $2 * $3; + lcconf->auto_exit_state |= LC_AUTOEXITSTATE_SET; + } + EOS + + | NATT_KA NUMBER unittype_time + { +#ifdef ENABLE_NATT + lcconf->natt_ka_interval = $2 * $3; +#else + yyerror("NAT-T support not compiled in."); +#endif + } + EOS + ; + + /* sainfo */ +sainfo_statement + : SAINFO + { + cur_sainfo = newsainfo(); + if (cur_sainfo == NULL) { + yyerror("failed to allocate sainfo"); + return -1; + } + } + sainfo_name sainfo_peer BOC sainfo_specs + { + struct sainfo *check; + + /* default */ + if (cur_sainfo->algs[algclass_ipsec_enc] == 0) { + yyerror("no encryption algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + if (cur_sainfo->algs[algclass_ipsec_auth] == 0) { + yyerror("no authentication algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + if (cur_sainfo->algs[algclass_ipsec_comp] == 0) { + yyerror("no compression algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + + /* duplicate check */ + check = getsainfo(cur_sainfo->idsrc, + cur_sainfo->iddst, + cur_sainfo->id_i); + if (check && (!check->idsrc && !cur_sainfo->idsrc)) { + yyerror("duplicated sainfo: %s", + sainfo2str(cur_sainfo)); + return -1; + } + inssainfo(cur_sainfo); + } + EOC + ; +sainfo_name + : ANONYMOUS + { + cur_sainfo->idsrc = NULL; + cur_sainfo->iddst = NULL; + } + | sainfo_id sainfo_id + { + cur_sainfo->idsrc = $1; + cur_sainfo->iddst = $2; + } + ; +sainfo_id + : IDENTIFIERTYPE ADDRSTRING prefix port ul_proto + { + char portbuf[10]; + struct sockaddr *saddr; + + if (($5 == IPPROTO_ICMP || $5 == IPPROTO_ICMPV6) + && ($4 != IPSEC_PORT_ANY || $4 != IPSEC_PORT_ANY)) { + yyerror("port number must be \"any\"."); + return -1; + } + + snprintf(portbuf, sizeof(portbuf), "%lu", $4); + saddr = str2saddr($2->v, portbuf); + vfree($2); + if (saddr == NULL) + return -1; + + switch (saddr->sa_family) { + case AF_INET: + if ($5 == IPPROTO_ICMPV6) { + yyerror("upper layer protocol mismatched.\n"); + racoon_free(saddr); + return -1; + } + $$ = ipsecdoi_sockaddr2id(saddr, +#if 0 + $3 == (sizeof(struct in_addr) << 3) && + $1 == IDTYPE_ADDRESS + ? ~0 : $3, +#else + $3 == ~0 ? (sizeof(struct in_addr) << 3): $3, +#endif + $5); + break; +#ifdef INET6 + case AF_INET6: + if ($5 == IPPROTO_ICMP) { + yyerror("upper layer protocol mismatched.\n"); + racoon_free(saddr); + return -1; + } + $$ = ipsecdoi_sockaddr2id(saddr, +#if 0 + $3 == (sizeof(struct in6_addr) << 3) && + $1 == IDTYPE_ADDRESS + ? ~0 : $3, +#else + $3 == ~0 ? (sizeof(struct in6_addr) << 3): $3, +#endif + $5); + break; +#endif + default: + yyerror("invalid family: %d", saddr->sa_family); + $$ = NULL; + break; + } + racoon_free(saddr); + if ($$ == NULL) + return -1; + } + | IDENTIFIERTYPE QUOTEDSTRING + { + struct ipsecdoi_id_b *id_b; + + if ($1 == IDTYPE_ASN1DN) { + yyerror("id type forbidden: %d", $1); + $$ = NULL; + return -1; + } + + $2->l--; + + $$ = vmalloc(sizeof(*id_b) + $2->l); + if ($$ == NULL) { + yyerror("failed to allocate identifier"); + return -1; + } + + id_b = (struct ipsecdoi_id_b *)$$->v; + id_b->type = idtype2doi($1); + + id_b->proto_id = 0; + id_b->port = 0; + + memcpy($$->v + sizeof(*id_b), $2->v, $2->l); + } + ; +sainfo_peer + : /* nothing */ + { + cur_sainfo->id_i = NULL; + } + + | FROM IDENTIFIERTYPE identifierstring + { + struct ipsecdoi_id_b *id_b; + vchar_t *idv; + + if (set_identifier(&idv, $2, $3) != 0) { + yyerror("failed to set identifer.\n"); + return -1; + } + cur_sainfo->id_i = vmalloc(sizeof(*id_b) + idv->l); + if (cur_sainfo->id_i == NULL) { + yyerror("failed to allocate identifier"); + return -1; + } + + id_b = (struct ipsecdoi_id_b *)cur_sainfo->id_i->v; + id_b->type = idtype2doi($2); + + id_b->proto_id = 0; + id_b->port = 0; + + memcpy(cur_sainfo->id_i->v + sizeof(*id_b), + idv->v, idv->l); + vfree(idv); + } + ; +sainfo_specs + : /* nothing */ + | sainfo_specs sainfo_spec + ; +sainfo_spec + : PFS_GROUP dh_group_num + { + cur_sainfo->pfs_group = $2; + } + EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + cur_sainfo->lifetime = $3 * $4; + } + EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated"); + return -1; +#else + cur_sainfo->lifebyte = fix_lifebyte($3 * $4); + if (cur_sainfo->lifebyte == 0) + return -1; +#endif + } + EOS + | ALGORITHM_CLASS { + cur_algclass = $1; + } + algorithms EOS + | IDENTIFIER IDENTIFIERTYPE + { + yyerror("it's deprecated to specify a identifier in phase 2"); + } + EOS + | MY_IDENTIFIER IDENTIFIERTYPE QUOTEDSTRING + { + yyerror("it's deprecated to specify a identifier in phase 2"); + } + EOS + ; + +algorithms + : algorithm + { + inssainfoalg(&cur_sainfo->algs[cur_algclass], $1); + } + | algorithm + { + inssainfoalg(&cur_sainfo->algs[cur_algclass], $1); + } + COMMA algorithms + ; +algorithm + : ALGORITHMTYPE keylength + { + int defklen; + + $$ = newsainfoalg(); + if ($$ == NULL) { + yyerror("failed to get algorithm allocation"); + return -1; + } + + $$->alg = algtype2doi(cur_algclass, $1); + if ($$->alg == -1) { + yyerror("algorithm mismatched"); + racoon_free($$); + $$ = NULL; + return -1; + } + + defklen = default_keylen(cur_algclass, $1); + if (defklen == 0) { + if ($2) { + yyerror("keylen not allowed"); + racoon_free($$); + $$ = NULL; + return -1; + } + } else { + if ($2 && check_keylen(cur_algclass, $1, $2) < 0) { + yyerror("invalid keylen %d", $2); + racoon_free($$); + $$ = NULL; + return -1; + } + } + + if ($2) + $$->encklen = $2; + else + $$->encklen = defklen; + + /* check if it's supported algorithm by kernel */ + if (!(cur_algclass == algclass_ipsec_auth && $1 == algtype_non_auth) + && pk_checkalg(cur_algclass, $1, $$->encklen)) { + int a = algclass2doi(cur_algclass); + int b = algtype2doi(cur_algclass, $1); + if (a == IPSECDOI_ATTR_AUTH) + a = IPSECDOI_PROTO_IPSEC_AH; + yyerror("algorithm %s not supported by the kernel (missing module?)", + s_ipsecdoi_trns(a, b)); + racoon_free($$); + $$ = NULL; + return -1; + } + } + ; +prefix + : /* nothing */ { $$ = ~0; } + | PREFIX { $$ = $1; } + ; +port + : /* nothing */ { $$ = IPSEC_PORT_ANY; } + | PORT { $$ = $1; } + | PORTANY { $$ = IPSEC_PORT_ANY; } + ; +ul_proto + : NUMBER { $$ = $1; } + | UL_PROTO { $$ = $1; } + | ANY { $$ = IPSEC_ULPROTO_ANY; } + ; +keylength + : /* nothing */ { $$ = 0; } + | NUMBER { $$ = $1; } + ; + + /* remote */ +remote_statement + : REMOTE remote_index INHERIT remote_index + { + struct remoteconf *new; + struct proposalspec *prspec; + + new = copyrmconf($4); + if (new == NULL) { + yyerror("failed to get remoteconf for %s.", saddr2str ($4)); + return -1; + } + + new->remote = $2; + new->inherited_from = getrmconf_strict($4, 1); + new->proposal = NULL; + new->prhead = NULL; + cur_rmconf = new; + + prspec = newprspec(); + if (prspec == NULL || !cur_rmconf->inherited_from + || !cur_rmconf->inherited_from->proposal) + return -1; + prspec->lifetime = cur_rmconf->inherited_from->proposal->lifetime; + prspec->lifebyte = cur_rmconf->inherited_from->proposal->lifebyte; + insprspec(prspec, &cur_rmconf->prhead); + } + remote_specs_block + | REMOTE remote_index + { + struct remoteconf *new; + struct proposalspec *prspec; + + new = newrmconf(); + if (new == NULL) { + yyerror("failed to get new remoteconf."); + return -1; + } + + new->remote = $2; + cur_rmconf = new; + + prspec = newprspec(); + if (prspec == NULL) + return -1; + prspec->lifetime = oakley_get_defaultlifetime(); + insprspec(prspec, &cur_rmconf->prhead); + } + remote_specs_block + ; + +remote_specs_block + : BOC remote_specs EOC + { + /* check a exchange mode */ + if (cur_rmconf->etypes == NULL) { + yyerror("no exchange mode specified.\n"); + return -1; + } + + if (cur_rmconf->idvtype == IDTYPE_UNDEFINED) + cur_rmconf->idvtype = IDTYPE_ADDRESS; + + + if (cur_rmconf->idvtype == IDTYPE_ASN1DN) { + if (cur_rmconf->mycertfile +#ifdef __APPLE__ + || cur_rmconf->identity_in_keychain) +#endif + { + if (cur_rmconf->idv) + yywarn("Both CERT and ASN1 ID " + "are set. Hope this is OK.\n"); + /* TODO: Preparse the DN here */ + } else if (cur_rmconf->idv) { + /* OK, using asn1dn without X.509. */ + } else { + yyerror("ASN1 ID not specified " + "and no CERT defined!\n"); + return -1; + } + } + +#ifdef __APPLE__ + if (cur_rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER) { + struct genlist_entry *gpb; + if (genlist_next(cur_rmconf->idvl_p, &gpb) == NULL) { + yyerror("peers_identifier required for specified certificate " + "verification option.\n"); + return -1; + } + } +#endif + + if (cur_rmconf->prhead->spspec == NULL + && cur_rmconf->inherited_from + && cur_rmconf->inherited_from->prhead) { + cur_rmconf->prhead->spspec = cur_rmconf->inherited_from->prhead->spspec; + } + if (set_isakmp_proposal(cur_rmconf, cur_rmconf->prhead) != 0) + return -1; + + /* DH group settting if aggressive mode is there. */ + if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) { + struct isakmpsa *p; + int b = 0; + + /* DH group */ + for (p = cur_rmconf->proposal; p; p = p->next) { + if (b == 0 || (b && b == p->dh_group)) { + b = p->dh_group; + continue; + } + yyerror("DH group must be equal " + "in all proposals " + "when aggressive mode is " + "used.\n"); + return -1; + } + cur_rmconf->dh_group = b; + + if (cur_rmconf->dh_group == 0) { + yyerror("DH group must be set in the proposal.\n"); + return -1; + } + + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(cur_rmconf->dh_group, + &cur_rmconf->dhgrp) < 0) { + yyerror("failed to set DH value.\n"); + return -1; + } + } + + insrmconf(cur_rmconf); + } + ; +remote_index + : ANONYMOUS ike_port + { + $$ = newsaddr(sizeof(struct sockaddr)); + $$->sa_family = AF_UNSPEC; + ((struct sockaddr_in *)$$)->sin_port = htons($2); + } + | ike_addrinfo_port + { + $$ = $1; + if ($$ == NULL) { + yyerror("failed to allocate sockaddr"); + return -1; + } + } + ; +remote_specs + : /* nothing */ + | remote_specs remote_spec + ; +remote_spec + : EXCHANGE_MODE + { + cur_rmconf->etypes = NULL; + } + exchange_types EOS + | DOI DOITYPE { cur_rmconf->doitype = $2; } EOS + | SITUATION SITUATIONTYPE { cur_rmconf->sittype = $2; } EOS + | CERTIFICATE_TYPE cert_spec + | PEERS_CERTFILE QUOTEDSTRING + { + yywarn("This directive without certtype will be removed!\n"); + yywarn("Please use 'peers_certfile x509 \"%s\";' instead\n", $2->v); + cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; + cur_rmconf->peerscertfile = strdup($2->v); + vfree($2); + } + EOS + | CA_TYPE CERT_X509 QUOTEDSTRING + { + cur_rmconf->cacerttype = $2; + cur_rmconf->getcacert_method = ISAKMP_GETCERT_LOCALFILE; + cur_rmconf->cacertfile = strdup($3->v); + vfree($3); + } + EOS + | PEERS_CERTFILE CERT_X509 QUOTEDSTRING + { + cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; + cur_rmconf->peerscertfile = strdup($3->v); + vfree($3); + } + EOS + | PEERS_CERTFILE CERT_PLAINRSA QUOTEDSTRING + { + char path[MAXPATHLEN]; + int ret = 0; + + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, $3->v); + vfree($3); + + if (cur_rmconf->getcert_method == ISAKMP_GETCERT_DNS) { + yyerror("Different peers_certfile method " + "already defined: %d!\n", + cur_rmconf->getcert_method); + return -1; + } + cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; + if (rsa_parse_file(cur_rmconf->rsa_public, path, RSA_TYPE_PUBLIC)) { + yyerror("Couldn't parse keyfile.\n", path); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, "Public PlainRSA keyfile parsed: %s\n", path); + } + EOS + | PEERS_CERTFILE DNSSEC + { + if (cur_rmconf->getcert_method) { + yyerror("Different peers_certfile method already defined!\n"); + return -1; + } + cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS; + cur_rmconf->peerscertfile = NULL; + } + EOS + | VERIFY_CERT SWITCH { cur_rmconf->verify_cert = $2; } EOS + | SEND_CERT SWITCH { cur_rmconf->send_cert = $2; } EOS + | SEND_CR SWITCH { cur_rmconf->send_cr = $2; } EOS + | CERTIFICATE_VERIFICATION VERIFICATION_MODULE + { +#ifdef __APPLE__ + cur_rmconf->cert_verification = $2; +#else + yyerror("Apple specific features not compiled in."); + return -1; +#endif + } EOS + | CERTIFICATE_VERIFICATION VERIFICATION_MODULE VERIFICATION_OPTION + { +#ifdef __APPLE__ + cur_rmconf->cert_verification = $2; + cur_rmconf->cert_verification_option = $3; +#else + yyerror("Apple specific features not compiled in."); + return -1; +#endif + } + EOS + | OPEN_DIR_AUTH_GROUP QUOTEDSTRING + { +#ifdef __APPLE__ + cur_rmconf->open_dir_auth_group = $2; +#else + yyerror("Apple specific features not compiled in."); + return -1; +#endif + } EOS + | MY_IDENTIFIER IDENTIFIERTYPE identifierstring + { + if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) { + yyerror("failed to set identifer.\n"); + vfree($3); //%%% BUG FIX - memory leak + return -1; + } + vfree($3); //%%% BUG FIX - memory leak + cur_rmconf->idvtype = $2; + } + EOS + | XAUTH_LOGIN identifierstring + { +#ifdef ENABLE_HYBRID + /* formerly identifier type login */ + cur_rmconf->idvtype = IDTYPE_LOGIN; + if (set_identifier(&cur_rmconf->idv, IDTYPE_LOGIN, $2) != 0) { + yyerror("failed to set identifer.\n"); + return -1; + } + /* cur_rmconf->use_xauth = 1; */ +#else + yyerror("racoon not configured with --enable-hybrid"); +#endif + } + EOS + | PEERS_IDENTIFIER IDENTIFIERTYPE identifierstring + { + struct idspec *id; + id = newidspec(); + if (id == NULL) { + yyerror("failed to allocate idspec"); + return -1; + } + if (set_identifier(&id->id, $2, $3) != 0) { + yyerror("failed to set identifer.\n"); + racoon_free(id); + vfree($3); //%%% BUG FIX - memory leak + return -1; + } + vfree($3); //%%% BUG FIX - memory leak + id->idtype = $2; + genlist_append (cur_rmconf->idvl_p, id); + } + EOS + | VERIFY_IDENTIFIER SWITCH { cur_rmconf->verify_identifier = $2; } EOS + | SHARED_SECRET SECRETTYPE QUOTEDSTRING + { +#ifdef __APPLE__ + cur_rmconf->secrettype = $2; + cur_rmconf->shared_secret = $3; +#else + yyerror("Apple specific features not compiled in."); + return -1; +#endif + } EOS + | SHARED_SECRET SECRETTYPE + { +#ifdef __APPLE__ + if ($2 != SECRETTYPE_KEYCHAIN_BY_ID) { + yyerror("shared secret value missing.\n"); + return -1; + } + cur_rmconf->secrettype = $2; +#else + yyerror("Apple specific features not compiled in."); + return -1; +#endif + + } EOS + | NONCE_SIZE NUMBER { cur_rmconf->nonce_size = $2; } EOS + | DH_GROUP + { + yyerror("dh_group cannot be defined here."); + return -1; + } + dh_group_num EOS + | PASSIVE SWITCH { cur_rmconf->passive = $2; } EOS + | IKE_FRAG SWITCH { cur_rmconf->ike_frag = $2; } EOS + | ESP_FRAG NUMBER { +#ifdef SADB_X_EXT_NAT_T_FRAG + cur_rmconf->esp_frag = $2; +#else + yywarn("Your kernel does not support esp_frag"); +#endif + } EOS + | SCRIPT QUOTEDSTRING PHASE1_UP { + cur_rmconf->script[SCRIPT_PHASE1_UP] = + script_path_add(vdup($2)); + } EOS + | SCRIPT QUOTEDSTRING PHASE1_DOWN { + cur_rmconf->script[SCRIPT_PHASE1_DOWN] = + script_path_add(vdup($2)); + } EOS + | MODE_CFG SWITCH { cur_rmconf->mode_cfg = $2; } EOS + | GENERATE_POLICY SWITCH { cur_rmconf->gen_policy = $2; } EOS + | SUPPORT_PROXY SWITCH { cur_rmconf->support_proxy = $2; } EOS + | INITIAL_CONTACT SWITCH { cur_rmconf->ini_contact = $2; } EOS + | NAT_TRAVERSAL SWITCH + { +#ifdef ENABLE_NATT + cur_rmconf->nat_traversal = $2; +#else + yyerror("NAT-T support not compiled in."); +#endif + } EOS + | NAT_TRAVERSAL NAT_TRAVERSAL_LEVEL + { +#ifdef ENABLE_NATT + cur_rmconf->nat_traversal = $2; +#else + yyerror("NAT-T support not compiled in."); +#endif + } EOS + | NAT_TRAVERSAL_MULTI_USER SWITCH + { +#ifdef ENABLE_NATT +#ifdef __APPLE__ + cur_rmconf->natt_multiple_user = $2; +#else + yyerror("Apple specific features not compiled in."); +#endif +#else + yyerror("NAT-T support not compiled in."); +#endif + } EOS + | DPD SWITCH + { +#ifdef ENABLE_DPD + cur_rmconf->dpd = $2; +#else + yyerror("DPD support not compiled in."); +#endif + } EOS + | DPD_DELAY NUMBER + { +#ifdef ENABLE_DPD + cur_rmconf->dpd_interval = $2; +#else + yyerror("DPD support not compiled in."); +#endif + } + EOS + | DPD_RETRY NUMBER + { +#ifdef ENABLE_DPD + cur_rmconf->dpd_retry = $2; +#else + yyerror("DPD support not compiled in."); +#endif + } + EOS + | DPD_MAXFAIL NUMBER + { +#ifdef ENABLE_DPD + cur_rmconf->dpd_maxfails = $2; +#else + yyerror("DPD support not compiled in."); +#endif + } + EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + cur_rmconf->prhead->lifetime = $3 * $4; + } + EOS + | PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated in Phase1"); + return -1; +#else + yywarn("the lifetime of bytes in phase 1 " + "will be ignored at the moment."); + cur_rmconf->prhead->lifebyte = fix_lifebyte($3 * $4); + if (cur_rmconf->prhead->lifebyte == 0) + return -1; +#endif + } + EOS + | PROPOSAL + { + struct secprotospec *spspec; + + spspec = newspspec(); + if (spspec == NULL) + return -1; + insspspec(spspec, &cur_rmconf->prhead); + } + BOC isakmpproposal_specs EOC + ; +exchange_types + : /* nothing */ + | exchange_types EXCHANGETYPE + { + struct etypes *new; + new = racoon_malloc(sizeof(struct etypes)); + if (new == NULL) { + yyerror("filed to allocate etypes"); + return -1; + } + new->type = $2; + new->next = NULL; + if (cur_rmconf->etypes == NULL) + cur_rmconf->etypes = new; + else { + struct etypes *p; + for (p = cur_rmconf->etypes; + p->next != NULL; + p = p->next) + ; + p->next = new; + } + } + ; +cert_spec + : CERT_X509 QUOTEDSTRING QUOTEDSTRING + { + cur_rmconf->certtype = $1; + cur_rmconf->mycertfile = strdup($2->v); + vfree($2); + cur_rmconf->myprivfile = strdup($3->v); + vfree($3); + } + EOS + | CERT_X509 IN_KEYCHAIN + { +#ifdef __APPLE__ + cur_rmconf->certtype = $1; + cur_rmconf->identity_in_keychain = 1; + cur_rmconf->keychainCertRef = NULL; +#endif + } + EOS + ; + | CERT_X509 IN_KEYCHAIN QUOTEDSTRING + { +#ifdef __APPLE__ + + cur_rmconf->certtype = $1; + cur_rmconf->identity_in_keychain = 1; + cur_rmconf->keychainCertRef = $3; +#endif + } + EOS + ; + | CERT_PLAINRSA QUOTEDSTRING + { + char path[MAXPATHLEN]; + int ret = 0; + + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, $2->v); + vfree($2); + + cur_rmconf->certtype = $1; + cur_rmconf->send_cr = FALSE; + cur_rmconf->send_cert = FALSE; + cur_rmconf->verify_cert = FALSE; + if (rsa_parse_file(cur_rmconf->rsa_private, path, RSA_TYPE_PRIVATE)) { + yyerror("Couldn't parse keyfile.\n", path); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, "Private PlainRSA keyfile parsed: %s\n", path); + } + EOS + ; +dh_group_num + : ALGORITHMTYPE + { + $$ = algtype2doi(algclass_isakmp_dh, $1); + if ($$ == -1) { + yyerror("must be DH group"); + return -1; + } + } + | NUMBER + { + if (ARRAYLEN(num2dhgroup) > $1 && num2dhgroup[$1] != 0) { + $$ = num2dhgroup[$1]; + } else { + yyerror("must be DH group"); + $$ = 0; + return -1; + } + } + ; +identifierstring + : /* nothing */ { $$ = NULL; } + | ADDRSTRING { $$ = $1; } + | QUOTEDSTRING { $$ = $1; } + ; +isakmpproposal_specs + : /* nothing */ + | isakmpproposal_specs isakmpproposal_spec + ; +isakmpproposal_spec + : STRENGTH + { + yyerror("strength directive is obsoleted."); + } STRENGTHTYPE EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + cur_rmconf->prhead->spspec->lifetime = $3 * $4; + } + EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated"); + return -1; +#else + cur_rmconf->prhead->spspec->lifebyte = fix_lifebyte($3 * $4); + if (cur_rmconf->prhead->spspec->lifebyte == 0) + return -1; +#endif + } + EOS + | DH_GROUP dh_group_num + { + cur_rmconf->prhead->spspec->algclass[algclass_isakmp_dh] = $2; + } + EOS + | GSS_ID QUOTEDSTRING + { + if (cur_rmconf->prhead->spspec->vendorid != VENDORID_GSSAPI) { + yyerror("wrong Vendor ID for gssapi_id"); + return -1; + } + cur_rmconf->prhead->spspec->gssid = strdup($2->v); + } + EOS + | ALGORITHM_CLASS ALGORITHMTYPE keylength + { + int doi; + int defklen; + + doi = algtype2doi($1, $2); + if (doi == -1) { + yyerror("algorithm mismatched 1"); + return -1; + } + + switch ($1) { + case algclass_isakmp_enc: + /* reject suppressed algorithms */ +#ifndef HAVE_OPENSSL_RC5_H + if ($2 == algtype_rc5) { + yyerror("algorithm %s not supported", + s_attr_isakmp_enc(doi)); + return -1; + } +#endif +#ifndef HAVE_OPENSSL_IDEA_H + if ($2 == algtype_idea) { + yyerror("algorithm %s not supported", + s_attr_isakmp_enc(doi)); + return -1; + } +#endif + + cur_rmconf->prhead->spspec->algclass[algclass_isakmp_enc] = doi; + defklen = default_keylen($1, $2); + if (defklen == 0) { + if ($3) { + yyerror("keylen not allowed"); + return -1; + } + } else { + if ($3 && check_keylen($1, $2, $3) < 0) { + yyerror("invalid keylen %d", $3); + return -1; + } + } + if ($3) + cur_rmconf->prhead->spspec->encklen = $3; + else + cur_rmconf->prhead->spspec->encklen = defklen; + break; + case algclass_isakmp_hash: + cur_rmconf->prhead->spspec->algclass[algclass_isakmp_hash] = doi; + break; + case algclass_isakmp_ameth: + cur_rmconf->prhead->spspec->algclass[algclass_isakmp_ameth] = doi; + /* + * We may have to set the Vendor ID for the + * authentication method we're using. + */ + switch ($2) { + case algtype_gssapikrb: + if (cur_rmconf->prhead->spspec->vendorid != + VENDORID_UNKNOWN) { + yyerror("Vendor ID mismatch " + "for auth method"); + return -1; + } + /* + * For interoperability with Win2k, + * we set the Vendor ID to "GSSAPI". + */ + cur_rmconf->prhead->spspec->vendorid = + VENDORID_GSSAPI; + break; + case algtype_rsasig: + if (cur_rmconf->certtype == ISAKMP_CERT_PLAINRSA) { + if (rsa_list_count(cur_rmconf->rsa_private) == 0) { + yyerror ("Private PlainRSA key not set. " + "Use directive 'certificate_type plainrsa ...'\n"); + return -1; + } + if (rsa_list_count(cur_rmconf->rsa_public) == 0) { + yyerror ("Public PlainRSA keys not set. " + "Use directive 'peers_certfile plainrsa ...'\n"); + return -1; + } + } + break; + default: + break; + } + break; + default: + yyerror("algorithm mismatched 2"); + return -1; + } + } + EOS + ; + +unittype_time + : UNITTYPE_SEC { $$ = 1; } + | UNITTYPE_MIN { $$ = 60; } + | UNITTYPE_HOUR { $$ = (60 * 60); } + ; +unittype_byte + : UNITTYPE_BYTE { $$ = 1; } + | UNITTYPE_KBYTES { $$ = 1024; } + | UNITTYPE_MBYTES { $$ = (1024 * 1024); } + | UNITTYPE_TBYTES { $$ = (1024 * 1024 * 1024); } + ; +%% + +static struct proposalspec * +newprspec() +{ + struct proposalspec *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + yyerror("failed to allocate proposal"); + + return new; +} + +/* + * insert into head of list. + */ +static void +insprspec(prspec, head) + struct proposalspec *prspec; + struct proposalspec **head; +{ + if (*head != NULL) + (*head)->prev = prspec; + prspec->next = *head; + *head = prspec; +} + +static struct secprotospec * +newspspec() +{ + struct secprotospec *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + yyerror("failed to allocate spproto"); + return NULL; + } + + new->encklen = 0; /*XXX*/ + + /* + * Default to "uknown" vendor -- we will override this + * as necessary. When we send a Vendor ID payload, an + * "unknown" will be translated to a KAME/racoon ID. + */ + new->vendorid = VENDORID_UNKNOWN; + + return new; +} + +/* + * insert into head of list. + */ +static void +insspspec(spspec, head) + struct secprotospec *spspec; + struct proposalspec **head; +{ + spspec->back = *head; + + if ((*head)->spspec != NULL) + (*head)->spspec->prev = spspec; + spspec->next = (*head)->spspec; + (*head)->spspec = spspec; +} + +/* set final acceptable proposal */ +static int +set_isakmp_proposal(rmconf, prspec) + struct remoteconf *rmconf; + struct proposalspec *prspec; +{ + struct proposalspec *p; + struct secprotospec *s; + int prop_no = 1; + int trns_no = 1; + int32_t types[MAXALGCLASS]; + + p = prspec; + if (p->next != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple proposal definition.\n"); + return -1; + } + + /* mandatory check */ + if (p->spspec == NULL) { + yyerror("no remote specification found: %s.\n", + saddr2str(rmconf->remote)); + return -1; + } + for (s = p->spspec; s != NULL; s = s->next) { + /* XXX need more to check */ + if (s->algclass[algclass_isakmp_enc] == 0) { + yyerror("encryption algorithm required."); + return -1; + } + if (s->algclass[algclass_isakmp_hash] == 0) { + yyerror("hash algorithm required."); + return -1; + } + if (s->algclass[algclass_isakmp_dh] == 0) { + yyerror("DH group required."); + return -1; + } + if (s->algclass[algclass_isakmp_ameth] == 0) { + yyerror("authentication method required."); + return -1; + } + } + + /* skip to last part */ + for (s = p->spspec; s->next != NULL; s = s->next) + ; + + while (s != NULL) { + plog(LLV_DEBUG2, LOCATION, NULL, + "lifetime = %ld\n", (long) + (s->lifetime ? s->lifetime : p->lifetime)); + plog(LLV_DEBUG2, LOCATION, NULL, + "lifebyte = %d\n", + s->lifebyte ? s->lifebyte : p->lifebyte); + plog(LLV_DEBUG2, LOCATION, NULL, + "encklen=%d\n", s->encklen); + + memset(types, 0, ARRAYLEN(types)); + types[algclass_isakmp_enc] = s->algclass[algclass_isakmp_enc]; + types[algclass_isakmp_hash] = s->algclass[algclass_isakmp_hash]; + types[algclass_isakmp_dh] = s->algclass[algclass_isakmp_dh]; + types[algclass_isakmp_ameth] = + s->algclass[algclass_isakmp_ameth]; + + /* expanding spspec */ + clean_tmpalgtype(); + trns_no = expand_isakmpspec(prop_no, trns_no, types, + algclass_isakmp_enc, algclass_isakmp_ameth + 1, + s->lifetime ? s->lifetime : p->lifetime, + s->lifebyte ? s->lifebyte : p->lifebyte, + s->encklen, s->vendorid, s->gssid, + rmconf); + if (trns_no == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to expand isakmp proposal.\n"); + return -1; + } + + s = s->prev; + } + + if (rmconf->proposal == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no proposal found.\n"); + return -1; + } + + return 0; +} + +static void +clean_tmpalgtype() +{ + int i; + for (i = 0; i < MAXALGCLASS; i++) + tmpalgtype[i] = 0; /* means algorithm undefined. */ +} + +static int +expand_isakmpspec(prop_no, trns_no, types, + class, last, lifetime, lifebyte, encklen, vendorid, gssid, + rmconf) + int prop_no, trns_no; + int *types, class, last; + time_t lifetime; + int lifebyte; + int encklen; + int vendorid; + char *gssid; + struct remoteconf *rmconf; +{ + struct isakmpsa *new; + + /* debugging */ + { + int j; + char tb[10]; + plog(LLV_DEBUG2, LOCATION, NULL, + "p:%d t:%d\n", prop_no, trns_no); + for (j = class; j < MAXALGCLASS; j++) { + snprintf(tb, sizeof(tb), "%d", types[j]); + plog(LLV_DEBUG2, LOCATION, NULL, + "%s%s%s%s\n", + s_algtype(j, types[j]), + types[j] ? "(" : "", + tb[0] == '0' ? "" : tb, + types[j] ? ")" : ""); + } + plog(LLV_DEBUG2, LOCATION, NULL, "\n"); + } + +#define TMPALGTYPE2STR(n) \ + s_algtype(algclass_isakmp_##n, types[algclass_isakmp_##n]) + /* check mandatory values */ + if (types[algclass_isakmp_enc] == 0 + || types[algclass_isakmp_ameth] == 0 + || types[algclass_isakmp_hash] == 0 + || types[algclass_isakmp_dh] == 0) { + yyerror("few definition of algorithm " + "enc=%s ameth=%s hash=%s dhgroup=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(ameth), + TMPALGTYPE2STR(hash), + TMPALGTYPE2STR(dh)); + return -1; + } +#undef TMPALGTYPE2STR + + /* set new sa */ + new = newisakmpsa(); + if (new == NULL) { + yyerror("failed to allocate isakmp sa"); + return -1; + } + new->prop_no = prop_no; + new->trns_no = trns_no++; + new->lifetime = lifetime; + new->lifebyte = lifebyte; + new->enctype = types[algclass_isakmp_enc]; + new->encklen = encklen; + new->authmethod = types[algclass_isakmp_ameth]; + new->hashtype = types[algclass_isakmp_hash]; + new->dh_group = types[algclass_isakmp_dh]; + new->vendorid = vendorid; +#ifdef HAVE_GSSAPI + if (new->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (gssid != NULL) { + new->gssid = vmalloc(strlen(gssid)); + memcpy(new->gssid->v, gssid, new->gssid->l); + racoon_free(gssid); + } else { + /* + * Allocate the default ID so that it gets put + * into a GSS ID attribute during the Phase 1 + * exchange. + */ + new->gssid = gssapi_get_default_gss_id(); + } + } +#endif + insisakmpsa(new, rmconf); + + return trns_no; +} + +static int +listen_addr (struct sockaddr *addr, int udp_encap) +{ + struct myaddrs *p; + + p = newmyaddr(); + if (p == NULL) { + yyerror("failed to allocate myaddrs"); + return -1; + } + p->addr = addr; + if (p->addr == NULL) { + yyerror("failed to copy sockaddr "); + delmyaddr(p); + return -1; + } + p->udp_encap = udp_encap; +#ifdef __APPLE__ + /* These need to be initialized for Apple modifications + * to open code for isakmp sockets + */ + p->sock = -1; + p->in_use = 1; +#endif + + insmyaddr(p, &lcconf->myaddrs); + + lcconf->autograbaddr = 0; + return 0; +} + +#if 0 +/* + * fix lifebyte. + * Must be more than 1024B because its unit is kilobytes. + * That is defined RFC2407. + */ +static int +fix_lifebyte(t) + unsigned long t; +{ + if (t < 1024) { + yyerror("byte size should be more than 1024B."); + return 0; + } + + return(t / 1024); +} +#endif + +int +cfparse() +{ + int error; + + plog(LLV_DEBUG, LOCATION, NULL, "===== parse config\n"); + + yycf_init_buffer(); + + if (yycf_switch_buffer(lcconf->racoon_conf) != 0) + return -1; + + error = yyparse(); + if (error != 0) { + if (yyerrorcount) { + plog(LLV_ERROR, LOCATION, NULL, + "fatal parse failure (%d errors)\n", + yyerrorcount); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "fatal parse failure.\n"); + } + return -1; + } + + if (error == 0 && yyerrorcount) { + plog(LLV_ERROR, LOCATION, NULL, + "parse error is nothing, but yyerrorcount is %d.\n", + yyerrorcount); + exit(1); + } + + yycf_clean_buffer(); + + plog(LLV_DEBUG2, LOCATION, NULL, "parse successed.\n"); + + return 0; +} + +int +cfreparse() +{ + plog(LLV_DEBUG, LOCATION, NULL, "==== Got HUP signal - re-parsing.\n"); + flushph2(); + flushph1(); + flushrmconf(); + flushsainfo(); + flushlcconf(); + check_auto_exit(); /* check/change state of auto exit */ + clean_tmpalgtype(); + + return(cfparse()); +} + + +#ifdef ENABLE_ADMINPORT +static void +adminsock_conf(path, owner, group, mode_dec) + vchar_t *path; + vchar_t *owner; + vchar_t *group; + int mode_dec; +{ + struct passwd *pw = NULL; + struct group *gr = NULL; + mode_t mode = 0; + uid_t uid; + gid_t gid; + int isnum; + + adminsock_path = path->v; + + if (owner == NULL) + return; + + errno = 0; + uid = atoi(owner->v); + isnum = !errno; + if (((pw = getpwnam(owner->v)) == NULL) && !isnum) + yyerror("User \"%s\" does not exist", owner->v); + + if (pw) + adminsock_owner = pw->pw_uid; + else + adminsock_owner = uid; + + if (group == NULL) + return; + + errno = 0; + gid = atoi(group->v); + isnum = !errno; + if (((gr = getgrnam(group->v)) == NULL) && !isnum) + yyerror("Group \"%s\" does not exist", group->v); + + if (gr) + adminsock_group = gr->gr_gid; + else + adminsock_group = gid; + + if (mode_dec == -1) + return; + + if (mode_dec > 777) + yyerror("Mode 0%03o is invalid", mode_dec); + if (mode_dec >= 400) { mode += 0400; mode_dec -= 400; } + if (mode_dec >= 200) { mode += 0200; mode_dec -= 200; } + if (mode_dec >= 100) { mode += 0200; mode_dec -= 100; } + + if (mode_dec > 77) + yyerror("Mode 0%03o is invalid", mode_dec); + if (mode_dec >= 40) { mode += 040; mode_dec -= 40; } + if (mode_dec >= 20) { mode += 020; mode_dec -= 20; } + if (mode_dec >= 10) { mode += 020; mode_dec -= 10; } + + if (mode_dec > 7) + yyerror("Mode 0%03o is invalid", mode_dec); + if (mode_dec >= 4) { mode += 04; mode_dec -= 4; } + if (mode_dec >= 2) { mode += 02; mode_dec -= 2; } + if (mode_dec >= 1) { mode += 02; mode_dec -= 1; } + + adminsock_mode = mode; + + return; +} +#endif diff --git a/ipsec-tools/racoon/cfparse_proto.h b/ipsec-tools/racoon/cfparse_proto.h new file mode 100644 index 0000000..73c824e --- /dev/null +++ b/ipsec-tools/racoon/cfparse_proto.h @@ -0,0 +1,40 @@ +/* $Id: cfparse_proto.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CFPARSE_PROTO_H +#define _CFPARSE_PROTO_H + +/* cfparse.y */ +extern int yyparse __P((void)); +extern int cfparse __P((void)); +extern int cfreparse __P((void)); + +#endif /* _CFPARSE_PROTO_H */ diff --git a/ipsec-tools/racoon/cftoken.l b/ipsec-tools/racoon/cftoken.l new file mode 100644 index 0000000..861e836 --- /dev/null +++ b/ipsec-tools/racoon/cftoken.l @@ -0,0 +1,854 @@ +/* $Id: cftoken.l,v 1.31.2.7 2005/11/06 17:18:26 monas Exp $ */ +%option noyywrap +%{ +/* + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 and 2003 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif + +//%%% BUG FIX - 2 missing include files when not using +// the bison files +#include +#include + +#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 */ +privsep { BEGIN S_PRIV; YYDB; return(PRIVSEP); } +{bcl} { return(BOC); } +user { YYD; return(USER); } +group { YYD; return(GROUP); } +chroot { YYD; return(CHROOT); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* path */ +path { BEGIN S_PTH; YYDB; return(PATH); } +include { YYD; yylval.num = LC_PATHTYPE_INCLUDE; + return(PATHTYPE); } +pre_shared_key { YYD; yylval.num = LC_PATHTYPE_PSK; + return(PATHTYPE); } +certificate { YYD; yylval.num = LC_PATHTYPE_CERT; + return(PATHTYPE); } +script { YYD; yylval.num = LC_PATHTYPE_SCRIPT; + return(PATHTYPE); } +backupsa { YYD; yylval.num = LC_PATHTYPE_BACKUPSA; + return(PATHTYPE); } +pidfile { YYD; yylval.num = LC_PATHTYPE_PIDFILE; + return(PATHTYPE); } +logfile { YYD; yylval.num = LC_PATHTYPE_LOGFILE; + return(PATHTYPE); } +{semi} { BEGIN S_INI; YYDB; return(EOS); } + + /* include */ +include { YYDB; return(INCLUDE); } + + /* self information */ +identifier { BEGIN S_INF; YYDB; yywarn("it is obsoleted. use \"my_identifier\" in each remote directives."); return(IDENTIFIER); } +{semi} { BEGIN S_INI; return(EOS); } + + /* special */ +complex_bundle { YYDB; return(COMPLEX_BUNDLE); } + + /* logging */ +log { BEGIN S_LOG; YYDB; return(LOGGING); } +info { YYD; yywarn("it is obsoleted. use \"notify\""); yylval.num = 0; return(LOGLEV); } +notify { YYD; yylval.num = 0; return(LOGLEV); } +debug { YYD; yylval.num = 1; return(LOGLEV); } +debug2 { YYD; yylval.num = 2; return(LOGLEV); } +debug3 { YYD; yywarn("it is osboleted. use \"debug2\""); yylval.num = 2; return(LOGLEV); } +debug4 { YYD; yywarn("it is obsoleted. use \"debug2\""); yylval.num = 2; return(LOGLEV); } +{semi} { BEGIN S_INI; return(EOS); } + + /* padding */ +padding { BEGIN S_PAD; YYDB; return(PADDING); } +{bcl} { return(BOC); } +randomize { YYD; return(PAD_RANDOMIZE); } +randomize_length { YYD; return(PAD_RANDOMIZELEN); } +maximum_length { YYD; return(PAD_MAXLEN); } +strict_check { YYD; return(PAD_STRICT); } +exclusive_tail { YYD; return(PAD_EXCLTAIL); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* listen */ +listen { BEGIN S_LST; YYDB; return(LISTEN); } +{bcl} { return(BOC); } +isakmp { YYD; return(X_ISAKMP); } +isakmp_natt { YYD; return(X_ISAKMP_NATT); } +admin { YYD; return(X_ADMIN); } +adminsock { YYD; return(ADMINSOCK); } +disabled { YYD; return(DISABLED); } +strict_address { YYD; return(STRICT_ADDRESS); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* mode_cfg */ +mode_cfg { BEGIN S_CFG; YYDB; return(MODECFG); } +{bcl} { return(BOC); } +network4 { YYD; return(CFG_NET4); } +netmask4 { YYD; return(CFG_MASK4); } +dns4 { YYD; return(CFG_DNS4); } +wins4 { YYD; return(CFG_NBNS4); } +auth_source { YYD; return(CFG_AUTH_SOURCE); } +conf_source { YYD; return(CFG_CONF_SOURCE); } +accounting { YYD; return(CFG_ACCOUNTING); } +system { YYD; return(CFG_SYSTEM); } +local { YYD; return(CFG_LOCAL); } +none { YYD; return(CFG_NONE); } +radius { YYD; return(CFG_RADIUS); } +pam { YYD; return(CFG_PAM); } +pool_size { YYD; return(CFG_POOL_SIZE); } +banner { YYD; return(CFG_MOTD); } +auth_throttle { YYD; return(CFG_AUTH_THROTTLE); } +pfs_group { YYD; return(CFG_PFS_GROUP); } +save_passwd { YYD; return(CFG_SAVE_PASSWD); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* timer */ +timer { BEGIN S_RTRY; YYDB; return(RETRY); } +{bcl} { return(BOC); } +counter { YYD; return(RETRY_COUNTER); } +interval { YYD; return(RETRY_INTERVAL); } +persend { YYD; return(RETRY_PERSEND); } +phase1 { YYD; return(RETRY_PHASE1); } +phase2 { YYD; return(RETRY_PHASE2); } +natt_keepalive { YYD; return(NATT_KA); } +auto_exit_delay { YYD; return(AUTO_EXIT_DELAY); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* sainfo */ +sainfo { BEGIN S_SAINF; YYDB; return(SAINFO); } +anonymous { YYD; return(ANONYMOUS); } +{blcl}any{elcl} { YYD; return(PORTANY); } +any { YYD; return(ANY); } +from { YYD; return(FROM); } + /* sainfo spec */ +{bcl} { BEGIN S_SAINFS; return(BOC); } +{semi} { BEGIN S_INI; return(EOS); } +{ecl} { BEGIN S_INI; return(EOC); } +pfs_group { YYD; return(PFS_GROUP); } +identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } +my_identifier { YYD; return(MY_IDENTIFIER); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } +encryption_algorithm { YYD; yylval.num = algclass_ipsec_enc; return(ALGORITHM_CLASS); } +authentication_algorithm { YYD; yylval.num = algclass_ipsec_auth; return(ALGORITHM_CLASS); } +compression_algorithm { YYD; yylval.num = algclass_ipsec_comp; return(ALGORITHM_CLASS); } +{comma} { YYD; return(COMMA); } + + /* remote */ +remote { BEGIN S_RMT; YYDB; return(REMOTE); } +anonymous { YYD; return(ANONYMOUS); } +inherit { YYD; return(INHERIT); } + /* remote spec */ +{bcl} { BEGIN S_RMTS; return(BOC); } +{ecl} { BEGIN S_INI; return(EOC); } +exchange_mode { YYD; return(EXCHANGE_MODE); } +{comma} { YYD; /* XXX ignored, but to be handled. */ ; } +base { YYD; yylval.num = ISAKMP_ETYPE_BASE; return(EXCHANGETYPE); } +main { YYD; yylval.num = ISAKMP_ETYPE_IDENT; return(EXCHANGETYPE); } +aggressive { YYD; yylval.num = ISAKMP_ETYPE_AGG; return(EXCHANGETYPE); } +doi { YYD; return(DOI); } +ipsec_doi { YYD; yylval.num = IPSEC_DOI; return(DOITYPE); } +situation { YYD; return(SITUATION); } +identity_only { YYD; yylval.num = IPSECDOI_SIT_IDENTITY_ONLY; return(SITUATIONTYPE); } +secrecy { YYD; yylval.num = IPSECDOI_SIT_SECRECY; return(SITUATIONTYPE); } +integrity { YYD; yylval.num = IPSECDOI_SIT_INTEGRITY; return(SITUATIONTYPE); } +identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } +my_identifier { YYD; return(MY_IDENTIFIER); } +xauth_login { YYD; return(XAUTH_LOGIN); /* formerly identifier type login */ } +peers_identifier { YYD; return(PEERS_IDENTIFIER); } +verify_identifier { YYD; return(VERIFY_IDENTIFIER); } +certificate_type { YYD; return(CERTIFICATE_TYPE); } +ca_type { YYD; return(CA_TYPE); } +x509 { YYD; yylval.num = ISAKMP_CERT_X509SIGN; return(CERT_X509); } +plain_rsa { YYD; yylval.num = ISAKMP_CERT_PLAINRSA; return(CERT_PLAINRSA); } +open_dir_auth_group { +#ifdef __APPLE__ + YYD; + return(OPEN_DIR_AUTH_GROUP); +#else + yyerror("Apple specific features not compiled in."); +#endif +} +shared_secret { +#ifdef __APPLE__ + YYD; + return(SHARED_SECRET); +#else + yyerror("Apple specific features not compiled in."); +#endif +} +in_keychain { +#ifdef __APPLE__ + YYD; + return(IN_KEYCHAIN); +#else + yyerror("Apple specific features not compiled in."); +#endif +} +certificate_verification { +#ifdef __APPLE__ + YYD; + return(CERTIFICATE_VERIFICATION); +#else + yyerror("Apple specific features not compiled in."); +#endif +} +peers_certfile { YYD; return(PEERS_CERTFILE); } +dnssec { YYD; return(DNSSEC); } +verify_cert { YYD; return(VERIFY_CERT); } +send_cert { YYD; return(SEND_CERT); } +send_cr { YYD; return(SEND_CR); } +dh_group { YYD; return(DH_GROUP); } +nonce_size { YYD; return(NONCE_SIZE); } +generate_policy { YYD; return(GENERATE_POLICY); } +support_mip6 { YYD; yywarn("it is obsoleted. use \"support_proxy\"."); return(SUPPORT_PROXY); } +support_proxy { YYD; return(SUPPORT_PROXY); } +initial_contact { YYD; return(INITIAL_CONTACT); } +nat_traversal { YYD; return(NAT_TRAVERSAL); } +force { YYD; yylval.num = NATT_FORCE; return(NAT_TRAVERSAL_LEVEL); } +nat_traversal_multi_user { +#ifdef __APPLE__ + YYD; + return(NAT_TRAVERSAL_MULTI_USER); +#else + yyerror("Apple specific features not compiled in."); +#endif +} +proposal_check { YYD; return(PROPOSAL_CHECK); } +obey { YYD; yylval.num = PROP_CHECK_OBEY; return(PROPOSAL_CHECK_LEVEL); } +strict { YYD; yylval.num = PROP_CHECK_STRICT; return(PROPOSAL_CHECK_LEVEL); } +exact { YYD; yylval.num = PROP_CHECK_EXACT; return(PROPOSAL_CHECK_LEVEL); } +claim { YYD; yylval.num = PROP_CHECK_CLAIM; return(PROPOSAL_CHECK_LEVEL); } +keepalive { YYD; return(KEEPALIVE); } +passive { YYD; return(PASSIVE); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } +dpd { YYD; return(DPD); } +dpd_delay { YYD; return(DPD_DELAY); } +dpd_retry { YYD; return(DPD_RETRY); } +dpd_maxfail { YYD; return(DPD_MAXFAIL); } +ike_frag { YYD; return(IKE_FRAG); } +esp_frag { YYD; return(ESP_FRAG); } +script { YYD; return(SCRIPT); } +phase1_up { YYD; return(PHASE1_UP); } +phase1_down { YYD; return(PHASE1_DOWN); } +mode_cfg { YYD; return(MODE_CFG); } + /* remote proposal */ +proposal { BEGIN S_RMTP; YYDB; return(PROPOSAL); } +{bcl} { return(BOC); } +{ecl} { BEGIN S_RMTS; return(EOC); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } +encryption_algorithm { YYD; yylval.num = algclass_isakmp_enc; return(ALGORITHM_CLASS); } +authentication_method { YYD; yylval.num = algclass_isakmp_ameth; return(ALGORITHM_CLASS); } +hash_algorithm { YYD; yylval.num = algclass_isakmp_hash; return(ALGORITHM_CLASS); } +dh_group { YYD; return(DH_GROUP); } +gss_id { YYD; return(GSS_ID); } +gssapi_id { YYD; return(GSS_ID); } /* for back compatibility */ + + /* GSS ID encoding type (global) */ +gss_id_enc { BEGIN S_GSSENC; YYDB; return(GSS_ID_ENC); } +latin1 { YYD; yylval.num = LC_GSSENC_LATIN1; + return(GSS_ID_ENCTYPE); } +utf-16le { YYD; yylval.num = LC_GSSENC_UTF16LE; + return(GSS_ID_ENCTYPE); } +{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); + } + +<> { + yy_delete_buffer(YY_CURRENT_BUFFER); + yycf_free_buffer(incstackp); + incstackp--; + nextfile: + if (incstack[incstackp].matchon < + incstack[incstackp].matches.gl_pathc) { + char* filepath = incstack[incstackp].matches.gl_pathv[incstack[incstackp].matchon]; + incstack[incstackp].matchon++; + incstackp++; + if (yycf_set_buffer(filepath) != 0) { + incstackp--; + goto nextfile; + } + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + BEGIN(S_INI); + } else { + globfree(&incstack[incstackp].matches); + if (incstackp == 0) + yyterminate(); + else + yy_switch_to_buffer(incstack[incstackp].prevstate); + } + } + + /* ... */ +{ws} { ; } +{nl} { incstack[incstackp].lineno++; } +{comment} { YYD; } +{semi} { return(EOS); } +. { yymore(); } + +%% + +void +yyerror(char *s, ...) +{ + char fmt[512]; + + va_list ap; +#ifdef HAVE_STDARG_H + va_start(ap, s); +#else + va_start(ap); +#endif + snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n", + incstack[incstackp].path, incstack[incstackp].lineno, + yytext, s); + plogv(LLV_ERROR, LOCATION, NULL, fmt, ap); + va_end(ap); + + yyerrorcount++; +} + +void +yywarn(char *s, ...) +{ + char fmt[512]; + + va_list ap; +#ifdef HAVE_STDARG_H + va_start(ap, s); +#else + va_start(ap); +#endif + snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n", + incstack[incstackp].path, incstack[incstackp].lineno, + yytext, s); + plogv(LLV_WARNING, LOCATION, NULL, fmt, ap); + va_end(ap); +} + +int +yycf_switch_buffer(path) + char *path; +{ + char *filepath = NULL; + + /* got the include file name */ + if (incstackp >= MAX_INCLUDE_DEPTH) { + plog(LLV_ERROR, LOCATION, NULL, + "Includes nested too deeply"); + return -1; + } + + if (glob(path, GLOB_TILDE, NULL, &incstack[incstackp].matches) != 0 || + incstack[incstackp].matches.gl_pathc == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "glob found no matches for path"); + return -1; + } + incstack[incstackp].matchon = 0; + incstack[incstackp].prevstate = YY_CURRENT_BUFFER; + + nextmatch: + if (incstack[incstackp].matchon >= incstack[incstackp].matches.gl_pathc) + return -1; + filepath = + incstack[incstackp].matches.gl_pathv[incstack[incstackp].matchon]; + incstack[incstackp].matchon++; + incstackp++; + + if (yycf_set_buffer(filepath) != 0) { + incstackp--; + goto nextmatch; + } + + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + + BEGIN(S_INI); + + return 0; +} + +int +yycf_set_buffer(path) + char *path; +{ + yyin = fopen(path, "r"); + if (yyin == NULL) { + fprintf(stderr, "failed to open file %s (%s)\n", + path, strerror(errno)); + plog(LLV_ERROR, LOCATION, NULL, + "failed to open file %s (%s)\n", + path, strerror(errno)); + return -1; + } + + /* initialize */ + incstack[incstackp].fp = yyin; + incstack[incstackp].path = strdup(path); + incstack[incstackp].lineno = 1; + plog(LLV_DEBUG, LOCATION, NULL, + "reading config file %s\n", path); + + return 0; +} + +void +yycf_init_buffer() +{ + int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) + memset(&incstack[i], 0, sizeof(incstack[i])); + incstackp = 0; +} + +void +yycf_free_buffer(index) + int index; +{ + fclose(incstack[index].fp); + racoon_free(incstack[index].path); + incstack[index].path = NULL; +} + +void +yycf_clean_buffer() +{ + int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) + if (incstack[i].path != NULL) + yycf_free_buffer(i); +} + diff --git a/ipsec-tools/racoon/cftoken_proto.h b/ipsec-tools/racoon/cftoken_proto.h new file mode 100644 index 0000000..76156a6 --- /dev/null +++ b/ipsec-tools/racoon/cftoken_proto.h @@ -0,0 +1,47 @@ +/* $Id: cftoken_proto.h,v 1.3 2004/06/11 16:00:15 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CFTOKEN_PROTO_H +#define _CFTOKEN_PROTO_H + +extern int yyerrorcount; + +extern int yylex __P((void)); +extern void yyerror __P((char *, ...)); +extern void yywarn __P((char *, ...)); + +extern int yycf_switch_buffer __P((char *)); +extern int yycf_set_buffer __P((char *)); +extern void yycf_init_buffer __P((void)); +extern void yycf_clean_buffer __P((void)); +extern void yycf_free_buffer __P((int)); + +#endif /* _CFTOKEN_PROTO_H */ diff --git a/ipsec-tools/racoon/crypto_cssm.c b/ipsec-tools/racoon/crypto_cssm.c new file mode 100644 index 0000000..9b0e349 --- /dev/null +++ b/ipsec-tools/racoon/crypto_cssm.c @@ -0,0 +1,536 @@ + +/* + * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +/* + * Racoon module for verifying and signing certificates through Security + * Framework and CSSM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 ""; + } +} + diff --git a/ipsec-tools/racoon/crypto_cssm.h b/ipsec-tools/racoon/crypto_cssm.h new file mode 100644 index 0000000..6152770 --- /dev/null +++ b/ipsec-tools/racoon/crypto_cssm.h @@ -0,0 +1,41 @@ + +/* + * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __CRYPTO_CSSM_H__ +#define __CRYPTO_CSSM_H__ + +/* + * Racoon module for verifying and signing certificates through Security + * Framework and CSSM + */ + +#include "vmbuf.h" + + +extern int crypto_cssm_check_x509cert(vchar_t *cert); +extern vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash); +extern vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef); + + +#endif /* __CRYPTO_CSSM_H__ */ + diff --git a/ipsec-tools/racoon/crypto_openssl.c b/ipsec-tools/racoon/crypto_openssl.c new file mode 100644 index 0000000..39e96b7 --- /dev/null +++ b/ipsec-tools/racoon/crypto_openssl.c @@ -0,0 +1,2908 @@ +/* $Id: crypto_openssl.c,v 1.40.4.5 2005/07/12 11:50:15 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#ifdef __APPLE__ +#define COMMON_DIGEST_FOR_OPENSSL 1 +#endif + +#include +#include + +#include +#include +#include +#include + +/* get openssl/ssleay version number */ +#include + +#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090602fL) +#error OpenSSL version 0.9.6 or later required. +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#include +#else +#include +#include +#include +#endif +#include +#include +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif +#include +#include +#include +#ifdef HAVE_OPENSSL_RC5_H +#include +#endif +#ifdef HAVE_OPENSSL_IDEA_H +#include +#endif +#if defined(HAVE_OPENSSL_AES_H) +#include +#elif defined(HAVE_OPENSSL_RIJNDAEL_H) +#include +#else +#include "crypto/rijndael/rijndael-api-fst.h" +#endif +#ifdef WITH_SHA2 +#ifndef __APPLE__ +#ifdef HAVE_OPENSSL_SHA2_H +#include +#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 +/* 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; ilength; i++) + { + int ca, cb; + + ca = tolower(a->data[i]); + cb = tolower(b->data[i]); + + if (ca != cb) + return(ca-cb); + } + return 0; +} + +/* Case insensitive string comparision with space normalization + * Space normalization - ignore leading, trailing spaces, + * multiple spaces between characters are replaced by single space + */ +static int nocase_spacenorm_cmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + unsigned char *pa = NULL, *pb = NULL; + int la, lb; + + la = a->length; + lb = b->length; + pa = a->data; + pb = b->data; + + /* skip leading spaces */ + while (la > 0 && isspace(*pa)) + { + la--; + pa++; + } + while (lb > 0 && isspace(*pb)) + { + lb--; + pb++; + } + + /* skip trailing spaces */ + while (la > 0 && isspace(pa[la-1])) + la--; + while (lb > 0 && isspace(pb[lb-1])) + lb--; + + /* compare strings with space normalization */ + while (la > 0 && lb > 0) + { + int ca, cb; + + /* compare character */ + ca = tolower(*pa); + cb = tolower(*pb); + if (ca != cb) + return (ca - cb); + + pa++; pb++; + la--; lb--; + + if (la <= 0 || lb <= 0) + break; + + /* is white space next character ? */ + if (isspace(*pa) && isspace(*pb)) + { + /* skip remaining white spaces */ + while (la > 0 && isspace(*pa)) + { + la--; + pa++; + } + while (lb > 0 && isspace(*pb)) + { + lb--; + pb++; + } + } + } + if (la > 0 || lb > 0) + return la - lb; + + return 0; +} + +static int X509_NAME_wildcmp(const X509_NAME *a, const X509_NAME *b) +{ + int i,j; + X509_NAME_ENTRY *na,*nb; + + if (sk_X509_NAME_ENTRY_num(a->entries) + != sk_X509_NAME_ENTRY_num(b->entries)) + return sk_X509_NAME_ENTRY_num(a->entries) + -sk_X509_NAME_ENTRY_num(b->entries); + for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--) + { + na=sk_X509_NAME_ENTRY_value(a->entries,i); + nb=sk_X509_NAME_ENTRY_value(b->entries,i); + j=OBJ_cmp(na->object,nb->object); + if (j) return(j); + if ((na->value->length == 1 && na->value->data[0] == '*') + || (nb->value->length == 1 && nb->value->data[0] == '*')) + continue; + j=na->value->type-nb->value->type; + if (j) return(j); + if (na->value->type == V_ASN1_PRINTABLESTRING) + j=nocase_spacenorm_cmp(na->value, nb->value); + else if (na->value->type == V_ASN1_IA5STRING + && OBJ_obj2nid(na->object) == NID_pkcs9_emailAddress) + j=nocase_cmp(na->value, nb->value); + else + { + j=na->value->length-nb->value->length; + if (j) return(j); + j=memcmp(na->value->data,nb->value->data, + na->value->length); + } + if (j) return(j); + j=na->set-nb->set; + if (j) return(j); + } + + return(0); +} + +/* + * compare two subjectNames. + * OUT: 0: equal + * positive: + * -1: other error. + */ +int +eay_cmp_asn1dn(n1, n2) + vchar_t *n1, *n2; +{ + X509_NAME *a = NULL, *b = NULL; + caddr_t p; + int i = -1; + + p = n1->v; + if (!d2i_X509_NAME(&a, (void *)&p, n1->l)) + goto end; + p = n2->v; + if (!d2i_X509_NAME(&b, (void *)&p, n2->l)) + goto end; + + i = X509_NAME_wildcmp(a, b); + + end: + if (a) + X509_NAME_free(a); + if (b) + X509_NAME_free(b); + return i; +} + +/* + * this functions is derived from apps/verify.c in OpenSSL0.9.5 + */ +int +eay_check_x509cert(cert, CApath, CAfile, local) + vchar_t *cert; + char *CApath; + char *CAfile; + int local; +{ + X509_STORE *cert_ctx = NULL; + X509_LOOKUP *lookup = NULL; + X509 *x509 = NULL; + X509_STORE_CTX *csc; + int error = -1; + + cert_ctx = X509_STORE_new(); + if (cert_ctx == NULL) + goto end; + + if (local) + X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert_local); + else + X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert_remote); + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + + X509_LOOKUP_load_file(lookup, CAfile, + (CAfile == NULL) ? X509_FILETYPE_DEFAULT : X509_FILETYPE_PEM); + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + goto end; + error = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); + if(!error) { + error = -1; + goto end; + } + error = -1; /* initialized */ + + /* read the certificate to be verified */ + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + csc = X509_STORE_CTX_new(); + if (csc == NULL) + goto end; + X509_STORE_CTX_init(csc, cert_ctx, x509, NULL); +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + X509_STORE_CTX_set_flags (csc, X509_V_FLAG_CRL_CHECK); + X509_STORE_CTX_set_flags (csc, X509_V_FLAG_CRL_CHECK_ALL); +#endif + error = X509_verify_cert(csc); + X509_STORE_CTX_cleanup(csc); + + /* + * if x509_verify_cert() is successful then the value of error is + * set non-zero. + */ + error = error ? 0 : -1; + +end: + if (error) + printf("%s\n", eay_strerror()); + if (cert_ctx != NULL) + X509_STORE_free(cert_ctx); + if (x509 != NULL) + X509_free(x509); + + return(error); +} + +/* + * callback function for verifing certificate. + * this function is derived from cb() in openssl/apps/s_server.c + */ +static int +cb_check_cert_local(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + char buf[256]; + int log_tag; + + if (!ok) { + X509_NAME_oneline( + X509_get_subject_name(ctx->current_cert), + buf, + 256); + /* + * since we are just checking the certificates, it is + * ok if they are self signed. But we should still warn + * the user. + */ + switch (ctx->error) { + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_INVALID_CA: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_PURPOSE: + case X509_V_ERR_UNABLE_TO_GET_CRL: + ok = 1; + log_tag = LLV_WARNING; + break; + default: + log_tag = LLV_ERROR; + } + plog(log_tag, LOCATION, NULL, + "%s(%d) at depth:%d SubjectName:%s\n", + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); + } + ERR_clear_error(); + + return ok; +} + +/* + * callback function for verifing remote certificates. + * this function is derived from cb() in openssl/apps/s_server.c + */ +static int +cb_check_cert_remote(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + char buf[256]; + int log_tag; + + if (!ok) { + X509_NAME_oneline( + X509_get_subject_name(ctx->current_cert), + buf, + 256); + switch (ctx->error) { + case X509_V_ERR_UNABLE_TO_GET_CRL: + ok = 1; + log_tag = LLV_WARNING; + break; + default: + log_tag = LLV_ERROR; + } + plog(log_tag, LOCATION, NULL, + "%s(%d) at depth:%d SubjectName:%s\n", + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); + } + ERR_clear_error(); + + return ok; +} + +/* + * get a subjectAltName from X509 certificate. + */ +vchar_t * +eay_get_x509asn1subjectname(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + u_char *bp; + vchar_t *name = NULL; + int len; + int error = -1; + + bp = (unsigned char *) cert->v; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + /* get the length of the name */ + len = i2d_X509_NAME(x509->cert_info->subject, NULL); + name = vmalloc(len); + if (!name) + goto end; + /* get the name */ + bp = (unsigned char *) name->v; + len = i2d_X509_NAME(x509->cert_info->subject, &bp); + + error = 0; + + end: + if (error) { + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + if (name) { + vfree(name); + name = NULL; + } + } + if (x509) + X509_free(x509); + + return name; +} + +#ifdef __APPLE__ + +/* + * Get the common name from a cert + */ +#define EAY_MAX_CN_LEN 256 +vchar_t * +eay_get_x509_common_name(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + X509_NAME *name; + vchar_t *commonName = NULL; + + commonName = vmalloc(EAY_MAX_CN_LEN); + if (commonName == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no memory\n"); + return NULL; + } + + x509 = mem2x509(cert); + if (x509 == NULL) { + vfree(commonName); + return NULL; + } + + name = X509_get_subject_name(x509); + X509_NAME_get_text_by_NID(name, NID_commonName, commonName->v, EAY_MAX_CN_LEN); + + commonName->l = strlen(commonName->v); + + if (x509) + X509_free(x509); + return commonName; +} + +/* + * get the subjectAltName from X509 certificate. + * the name must be terminated by '\0'. + */ +int +eay_get_x509subjectaltname(cert, altname, type, pos, len) + vchar_t *cert; + char **altname; + int *type; + int pos; + int *len; +{ + X509 *x509 = NULL; + int i; + GENERAL_NAMES *gens; + GENERAL_NAME *gen; + int error = -1; + + *altname = NULL; + *type = GENT_OTHERNAME; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); + if (gens == NULL) + goto end; + + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + if (i + 1 != pos) + continue; + break; + } + + /* there is no data at "pos" */ + if (i == sk_GENERAL_NAME_num(gens)) + goto end; + + gen = sk_GENERAL_NAME_value(gens, i); + + /* make sure the data is terminated by '\0'. */ + if (gen->d.ia5->data[gen->d.ia5->length] != '\0') { + plog(LLV_ERROR, LOCATION, NULL, + "data is not terminated by 0."); + hexdump(gen->d.ia5->data, gen->d.ia5->length + 1); + goto end; + } + + /* read DNSName / Email */ + if (gen->type == GEN_DNS || + gen->type == GEN_EMAIL || + gen->type == GEN_URI) { + + *len = gen->d.ia5->length + 1; + *altname = racoon_malloc(*len); + if (!*altname) + goto end; + + strlcpy(*altname, (const char *)gen->d.ia5->data, *len); + *type = gen->type; + + error = 0; + } else if (gen->type == GEN_IPADD) { + + *len = gen->d.ia5->length + 1; + *altname = racoon_malloc(*len); + if (!*altname) + goto end; + + memcpy(*altname, (const char *)gen->d.ia5->data, *len); + *type = gen->type; + + error = 0; + } + + end: + if (error) { + if (*altname) { + racoon_free(*altname); + *altname = NULL; + } +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + } + if (x509) + X509_free(x509); + + return error; +} + +#else /* __APPLE__ */ + +/* + * get the subjectAltName from X509 certificate. + * the name must be terminated by '\0'. + */ +int +eay_get_x509subjectaltname(cert, altname, type, pos) + vchar_t *cert; + char **altname; + int *type; + int pos; +{ + X509 *x509 = NULL; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen; + int len; + int error = -1; + + *altname = NULL; + *type = GENT_OTHERNAME; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); + if (gens == NULL) + goto end; + + /* there is no data at "pos" */ + if (pos > sk_GENERAL_NAME_num(gens)) + goto end; + + gen = sk_GENERAL_NAME_value(gens, pos - 1); + + /* read DNSName / Email */ + if (gen->type == GEN_DNS || + gen->type == GEN_EMAIL || + gen->type == GEN_URI ) + { + /* make sure if the data is terminated by '\0'. */ + if (gen->d.ia5->data[gen->d.ia5->length] != '\0') + { + plog(LLV_ERROR, LOCATION, NULL, + "data is not terminated by NUL."); + hexdump(gen->d.ia5->data, gen->d.ia5->length + 1); + goto end; + } + + len = gen->d.ia5->length + 1; + *altname = racoon_malloc(len); + if (!*altname) + goto end; + + strlcpy(*altname, (char *) gen->d.ia5->data, len); + *type = gen->type; + error = 0; + } + /* read IP address */ + else if (gen->type == GEN_IPADD) + { + unsigned char p[5], *ip; + const int maxaltnamelen = 20; + ip = p; + + /* only support IPv4 */ + if (gen->d.ip->length != 4) + goto end; + + /* convert Octet String to String + * XXX ??????? + */ + /*i2d_ASN1_OCTET_STRING(gen->d.ip,&ip);*/ + ip = gen->d.ip->data; + + /* XXX Magic, enough for an IPv4 address + */ + *altname = racoon_malloc(maxaltnamelen); + if (!*altname) + goto end; + + snprintf(*altname, maxaltnamelen, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + *type = gen->type; + error = 0; + } + /* XXX other possible types ? + * For now, error will be -1 if unsupported type + */ + +end: + if (error) { + if (*altname) { + racoon_free(*altname); + *altname = NULL; + } + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + } + if (x509) + X509_free(x509); + if (gens) + /* free the whole stack. */ + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + + return error; +} + +#endif + +/* + * decode a X509 certificate and make a readable text terminated '\n'. + * return the buffer allocated, so must free it later. + */ +char * +eay_get_x509text(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + BIO *bio = NULL; + char *text = NULL; + u_char *bp = NULL; + int len = 0; + int error = -1; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto end; + + error = X509_print(bio, x509); + if (error != 1) { + error = -1; + goto end; + } + + len = BIO_get_mem_data(bio, &bp); + text = racoon_malloc(len + 1); + if (text == NULL) + goto end; + memcpy(text, bp, len); + text[len] = '\0'; + + error = 0; + + end: + if (error) { + if (text) { + racoon_free(text); + text = NULL; + } + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + } + if (bio) + BIO_free(bio); + if (x509) + X509_free(x509); + + return text; +} + +/* get X509 structure from buffer. */ +static X509 * +mem2x509(cert) + vchar_t *cert; +{ + X509 *x509; + +#ifndef EAYDEBUG + { + u_char *bp; + + bp = (unsigned char *) cert->v; + + x509 = d2i_X509(NULL, (void *)&bp, cert->l); + } +#else + { + BIO *bio; + int len; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + return NULL; + len = BIO_write(bio, cert->v, cert->l); + if (len == -1) + return NULL; + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + } +#endif + return x509; +} + +/* + * get a X509 certificate from local file. + * a certificate must be PEM format. + * Input: + * path to a certificate. + * Output: + * NULL if error occured + * other is the cert. + */ +vchar_t * +eay_get_x509cert(path) + char *path; +{ + FILE *fp; + X509 *x509; + vchar_t *cert; + u_char *bp; + int len; + int error; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + x509 = PEM_read_X509(fp, NULL, NULL, NULL); + fclose (fp); + + if (x509 == NULL) + return NULL; + + len = i2d_X509(x509, NULL); + cert = vmalloc(len); + if (cert == NULL) { + X509_free(x509); + return NULL; + } + bp = (unsigned char *) cert->v; + error = i2d_X509(x509, &bp); + X509_free(x509); + + if (error == 0) { + vfree(cert); + return NULL; + } + + return cert; +} + +/* + * check a X509 signature + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + * OUT: return -1 when error. + * 0 + */ +int +eay_check_x509sign(source, sig, cert) + vchar_t *source; + vchar_t *sig; + vchar_t *cert; +{ + X509 *x509; + u_char *bp; + EVP_PKEY *evp; + int res; + + bp = (unsigned char *) cert->v; + + x509 = d2i_X509(NULL, (void *)&bp, cert->l); + if (x509 == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "d2i_X509(): %s\n", eay_strerror()); + return -1; + } + + evp = X509_get_pubkey(x509); + if (! evp) { + plog(LLV_ERROR, LOCATION, NULL, "X509_get_pubkey(): %s\n", eay_strerror()); + return -1; + } + + res = eay_rsa_verify(source, sig, evp->pkey.rsa); + + EVP_PKEY_free(evp); + + return res; +} + +/* + * check RSA signature + * OUT: return -1 when error. + * 0 on success + */ +int +eay_check_rsasign(source, sig, rsa) + vchar_t *source; + vchar_t *sig; + RSA *rsa; +{ + return eay_rsa_verify(source, sig, rsa); +} + +/* + * get PKCS#1 Private Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1privkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + + evp = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + + fclose (fp); + + if (evp == NULL) + return NULL; + + pkeylen = i2d_PrivateKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = (unsigned char *) pkey->v; + pkeylen = i2d_PrivateKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; + +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} + +/* + * get PKCS#1 Public Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1pubkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + X509 *x509 = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + + x509 = PEM_read_X509(fp, NULL, NULL, NULL); + + fclose (fp); + + if (x509 == NULL) + return NULL; + + /* Get public key - eay */ + evp = X509_get_pubkey(x509); + if (evp == NULL) + return NULL; + + pkeylen = i2d_PublicKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = (unsigned char *) pkey->v; + pkeylen = i2d_PublicKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} + +vchar_t * +eay_get_x509sign(src, privkey) + vchar_t *src, *privkey; +{ + EVP_PKEY *evp; + u_char *bp = (unsigned char *) privkey->v; + vchar_t *sig = NULL; + int len; + int pad = RSA_PKCS1_PADDING; + + /* XXX to be handled EVP_PKEY_DSA */ + evp = d2i_PrivateKey(EVP_PKEY_RSA, NULL, (void *)&bp, privkey->l); + if (evp == NULL) + return NULL; + + sig = eay_rsa_sign(src, evp->pkey.rsa); + + EVP_PKEY_free(evp); + + return sig; +} + +vchar_t * +eay_get_rsasign(src, rsa) + vchar_t *src; + RSA *rsa; +{ + return eay_rsa_sign(src, rsa); +} + +vchar_t * +eay_rsa_sign(vchar_t *src, RSA *rsa) +{ + int len; + vchar_t *sig = NULL; + int pad = RSA_PKCS1_PADDING; + + len = RSA_size(rsa); + + sig = vmalloc(len); + if (sig == NULL) + return NULL; + + len = RSA_private_encrypt(src->l, (unsigned char *) src->v, + (unsigned char *) sig->v, rsa, pad); + + if (len == 0 || len != sig->l) { + vfree(sig); + sig = NULL; + } + + return sig; +} + +int +eay_rsa_verify(src, sig, rsa) + vchar_t *src, *sig; + RSA *rsa; +{ + vchar_t *xbuf = NULL; + int pad = RSA_PKCS1_PADDING; + int len = 0; + int error; + + len = RSA_size(rsa); + xbuf = vmalloc(len); + if (xbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + return -1; + } + + len = RSA_public_decrypt(sig->l, (unsigned char *) sig->v, + (unsigned char *) xbuf->v, rsa, pad); + if (len == 0 || len != src->l) { + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + vfree(xbuf); + return -1; + } + + error = memcmp(src->v, xbuf->v, src->l); + vfree(xbuf); + if (error != 0) + return -1; + + return 0; +} + +/* + * get error string + * MUST load ERR_load_crypto_strings() first. + */ +char * +eay_strerror() +{ + static char ebuf[512]; + int len = 0, n; + unsigned long l; + char buf[200]; + const char *file, *data; + int line, flags; + unsigned long es; + + es = CRYPTO_thread_id(); + + while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0){ + n = snprintf(ebuf + len, sizeof(ebuf) - len, + "%lu:%s:%s:%d:%s ", + es, ERR_error_string(l, buf), file, line, + (flags & ERR_TXT_STRING) ? data : ""); + if (n < 0 || n >= sizeof(ebuf) - len) + break; + len += n; + if (sizeof(ebuf) < len) + break; + } + + return ebuf; +} + +vchar_t * +evp_crypt(vchar_t *data, vchar_t *key, vchar_t *iv, const EVP_CIPHER *e, int enc) +{ + vchar_t *res; + EVP_CIPHER_CTX ctx; + + if (!e) + return NULL; + + if (data->l % EVP_CIPHER_block_size(e)) + return NULL; + + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + EVP_CIPHER_CTX_init(&ctx); + + switch(EVP_CIPHER_nid(e)){ + case NID_bf_cbc: + case NID_bf_ecb: + case NID_bf_cfb64: + case NID_bf_ofb64: + case NID_cast5_cbc: + case NID_cast5_ecb: + case NID_cast5_cfb64: + case NID_cast5_ofb64: + /* XXX: can we do that also for algos with a fixed key size ? + */ + /* init context without key/iv + */ + if (!EVP_CipherInit(&ctx, e, NULL, NULL, enc)) + { + OpenSSL_BUG(); + vfree(res); + return NULL; + } + + /* update key size + */ + if (!EVP_CIPHER_CTX_set_key_length(&ctx, key->l)) + { + OpenSSL_BUG(); + vfree(res); + return NULL; + } + + /* finalize context init with desired key size + */ + if (!EVP_CipherInit(&ctx, NULL, (u_char *) key->v, + (u_char *) iv->v, enc)) + { + OpenSSL_BUG(); + vfree(res); + return NULL; + } + break; + default: + if (!EVP_CipherInit(&ctx, e, (u_char *) key->v, + (u_char *) iv->v, enc)) { + OpenSSL_BUG(); + vfree(res); + return NULL; + } + } + + /* disable openssl padding */ + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + if (!EVP_Cipher(&ctx, (u_char *) res->v, (u_char *) data->v, data->l)) { + OpenSSL_BUG(); + vfree(res); + return NULL; + } + + EVP_CIPHER_CTX_cleanup(&ctx); + + return res; +} + +int +evp_weakkey(vchar_t *key, const EVP_CIPHER *e) +{ + return 0; +} + +int +evp_keylen(int len, const EVP_CIPHER *e) +{ + if (!e) + return -1; + /* EVP functions return lengths in bytes, ipsec-tools + * uses lengths in bits, therefore conversion is required. --AK + */ + if (len != 0 && len != (EVP_CIPHER_key_length(e) << 3)) + return -1; + + return EVP_CIPHER_key_length(e) << 3; +} + +/* + * DES-CBC + */ +vchar_t * +eay_des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_des_cbc(), 1); +} + +vchar_t * +eay_des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_des_cbc(), 0); +} + +int +eay_des_weakkey(key) + vchar_t *key; +{ +#ifdef USE_NEW_DES_API + return DES_is_weak_key((void *)key->v); +#else + return des_is_weak_key((void *)key->v); +#endif +} + +int +eay_des_keylen(len) + int len; +{ + return evp_keylen(len, EVP_des_cbc()); +} + +#ifdef HAVE_OPENSSL_IDEA_H +/* + * IDEA-CBC + */ +vchar_t * +eay_idea_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks; + + idea_set_encrypt_key(key->v, &ks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, IDEA_ENCRYPT); + + return res; +} + +vchar_t * +eay_idea_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks, dks; + + idea_set_encrypt_key(key->v, &ks); + idea_set_decrypt_key(&ks, &dks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &dks, iv->v, IDEA_DECRYPT); + + return res; +} + +int +eay_idea_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX */ +} + +int +eay_idea_keylen(len) + int len; +{ + if (len != 0 && len != 128) + return -1; + return 128; +} +#endif + +/* + * BLOWFISH-CBC + */ +vchar_t * +eay_bf_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_bf_cbc(), 1); +} + +vchar_t * +eay_bf_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_bf_cbc(), 0); +} + +int +eay_bf_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX to be done. refer to RFC 2451 */ +} + +int +eay_bf_keylen(len) + int len; +{ + if (len == 0) + return 448; + if (len < 40 || len > 448) + return -1; + return len; +} + +#ifdef HAVE_OPENSSL_RC5_H +/* + * RC5-CBC + */ +vchar_t * +eay_rc5_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_ENCRYPT); + + return res; +} + +vchar_t * +eay_rc5_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_DECRYPT); + + return res; +} + +int +eay_rc5_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys when used with 16 rounds. */ + +} + +int +eay_rc5_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 2040) + return -1; + return len; +} +#endif + +/* + * 3DES-CBC + */ +vchar_t * +eay_3des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_des_ede3_cbc(), 1); +} + +vchar_t * +eay_3des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_des_ede3_cbc(), 0); +} + +int +eay_3des_weakkey(key) + vchar_t *key; +{ +#ifdef USE_NEW_DES_API + return (DES_is_weak_key((void *)key->v) || + DES_is_weak_key((void *)(key->v + 8)) || + DES_is_weak_key((void *)(key->v + 16))); +#else + if (key->l < 24) + return 0; + + return (des_is_weak_key((void *)key->v) || + des_is_weak_key((void *)(key->v + 8)) || + des_is_weak_key((void *)(key->v + 16))); +#endif +} + +int +eay_3des_keylen(len) + int len; +{ + if (len != 0 && len != 192) + return -1; + return 192; +} + +/* + * CAST-CBC + */ +vchar_t * +eay_cast_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_cast5_cbc(), 1); +} + +vchar_t * +eay_cast_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, EVP_cast5_cbc(), 0); +} + +int +eay_cast_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys. */ +} + +int +eay_cast_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 128) + return -1; + return len; +} + +/* + * AES(RIJNDAEL)-CBC + */ +#ifndef HAVE_OPENSSL_AES_H +vchar_t * +eay_aes_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_ENCRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* encryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0){ + vfree(res); + return NULL; + } + if (rijndael_blockEncrypt(&c, &k, data->v, data->l << 3, res->v) < 0){ + vfree(res); + return NULL; + } + + return res; +} + +vchar_t * +eay_aes_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_DECRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0){ + vfree(res); + return NULL; + } + if (rijndael_blockDecrypt(&c, &k, data->v, data->l << 3, res->v) < 0){ + vfree(res); + return NULL; + } + + return res; +} +#else +static inline const EVP_CIPHER * +aes_evp_by_keylen(int keylen) +{ + switch(keylen) { + case 16: + case 128: + return EVP_aes_128_cbc(); + case 24: + case 192: + return EVP_aes_192_cbc(); + case 32: + case 256: + return EVP_aes_256_cbc(); + default: + return NULL; + } +} + +vchar_t * +eay_aes_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, aes_evp_by_keylen(key->l), 1); +} + +vchar_t * +eay_aes_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + return evp_crypt(data, key, iv, aes_evp_by_keylen(key->l), 0); +} +#endif + +int +eay_aes_weakkey(key) + vchar_t *key; +{ + return 0; +} + +int +eay_aes_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len != 128 && len != 192 && len != 256) + return -1; + return len; +} + +/* for ipsec part */ +int +eay_null_hashlen() +{ + return 0; +} + +int +eay_kpdk_hashlen() +{ + return 0; +} + +int +eay_twofish_keylen(len) + int len; +{ + if (len < 0 || len > 256) + return -1; + return len; +} + +int +eay_null_keylen(len) + int len; +{ + return 0; +} + +/* + * HMAC functions + */ + +#ifdef __APPLE__ +static caddr_t +eay_hmac_init(key, algorithm) + vchar_t *key; + CCHmacAlgorithm algorithm; +{ + CCHmacContext *c = racoon_malloc(sizeof(*c)); + + CCHmacInit(c, algorithm, key->v, key->l); + + return (caddr_t)c; +} +#else +static caddr_t +eay_hmac_init(key, md) + vchar_t *key; + const EVP_MD *md; +{ + HMAC_CTX *c = racoon_malloc(sizeof(*c)); + + HMAC_Init(c, key->v, key->l, md); + + return (caddr_t)c; +} +#endif /* __APPLE__ */ + +#ifdef WITH_SHA2 +/* + * HMAC SHA2-512 + */ +vchar_t * +eay_hmacsha2_512_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_512_init(key); + eay_hmacsha2_512_update(ctx, data); + res = eay_hmacsha2_512_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_512_init(key) + vchar_t *key; +{ +#ifdef __APPLE__ + return eay_hmac_init(key, kCCHmacAlgSHA512); +#else + return eay_hmac_init(key, EVP_sha2_512()); +#endif +} + +void +eay_hmacsha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ +#ifdef __APPLE__ + CCHmacUpdate((CCHmacContext *)c, data->v, data->l); +#else + HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l); +#endif +} + +#ifdef __APPLE__ +vchar_t * +eay_hmacsha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(CC_SHA512_DIGEST_LENGTH)) == 0) + return NULL; + + CCHmacFinal((CCHmacContext *)c, res->v); + res->l = CC_SHA512_DIGEST_LENGTH; + + (void)racoon_free(c); + return(res); +} +#else +vchar_t * +eay_hmacsha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l); + res->l = l; + HMAC_cleanup((HMAC_CTX *)c); + + (void)racoon_free(c); + + if (SHA512_DIGEST_LENGTH != res->l) { + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_512 length mismatch %zd.\n", res->l); + vfree(res); + return NULL; + } + + return(res); +} +#endif /* __APPLE__ */ + +/* + * HMAC SHA2-384 + */ +vchar_t * +eay_hmacsha2_384_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_384_init(key); + eay_hmacsha2_384_update(ctx, data); + res = eay_hmacsha2_384_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_384_init(key) + vchar_t *key; +{ +#ifdef __APPLE__ + return eay_hmac_init(key, kCCHmacAlgSHA384); +#else + return eay_hmac_init(key, EVP_sha2_384()); +#endif +} + +void +eay_hmacsha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ +#ifdef __APPLE__ + CCHmacUpdate((CCHmacContext *)c, data->v, data->l); +#else + HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l); +#endif +} + +#ifdef __APPLE__ +vchar_t * +eay_hmacsha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(CC_SHA384_DIGEST_LENGTH)) == 0) + return NULL; + + CCHmacFinal((CCHmacContext *)c, res->v); + res->l = CC_SHA384_DIGEST_LENGTH; + + (void)racoon_free(c); + return(res); +} +#else +vchar_t * +eay_hmacsha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l); + res->l = l; + HMAC_cleanup((HMAC_CTX *)c); + + (void)racoon_free(c); + + if (SHA384_DIGEST_LENGTH != res->l) { + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_384 length mismatch %zd.\n", res->l); + vfree(res); + return NULL; + } + + return(res); +} +#endif /* __APPLE__ */ + +/* + * HMAC SHA2-256 + */ +vchar_t * +eay_hmacsha2_256_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_256_init(key); + eay_hmacsha2_256_update(ctx, data); + res = eay_hmacsha2_256_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_256_init(key) + vchar_t *key; +{ +#ifdef __APPLE__ + return eay_hmac_init(key, kCCHmacAlgSHA256); +#else + return eay_hmac_init(key, EVP_sha2_256()); +#endif +} + +void +eay_hmacsha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ +#ifdef __APPLE__ + CCHmacUpdate((CCHmacContext *)c, data->v, data->l); +#else + HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l); +#endif +} + +#ifdef __APPLE__ +vchar_t * +eay_hmacsha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(CC_SHA256_DIGEST_LENGTH)) == 0) + return NULL; + + CCHmacFinal((CCHmacContext *)c, res->v); + res->l = CC_SHA256_DIGEST_LENGTH; + + (void)racoon_free(c); + return(res); +} +#else +vchar_t * +eay_hmacsha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l); + res->l = l; + HMAC_cleanup((HMAC_CTX *)c); + + (void)racoon_free(c); + + if (SHA256_DIGEST_LENGTH != res->l) { + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_256 length mismatch %zd.\n", res->l); + vfree(res); + return NULL; + } + + return(res); +} +#endif /* __APPLE__ */ +#endif /* WITH_SHA2 */ + +/* + * HMAC SHA1 + */ +vchar_t * +eay_hmacsha1_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha1_init(key); + eay_hmacsha1_update(ctx, data); + res = eay_hmacsha1_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha1_init(key) + vchar_t *key; +{ +#ifdef __APPLE__ + return eay_hmac_init(key, kCCHmacAlgSHA1); +#else + return eay_hmac_init(key, EVP_sha1()); +#endif +} + +void +eay_hmacsha1_update(c, data) + caddr_t c; + vchar_t *data; +{ +#ifdef __APPLE__ + CCHmacUpdate((CCHmacContext *)c, data->v, data->l); +#else + HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l); +#endif +} + +#ifdef __APPLE__ +vchar_t * +eay_hmacsha1_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(CC_SHA1_DIGEST_LENGTH)) == 0) + return NULL; + + CCHmacFinal((CCHmacContext *)c, res->v); + res->l = CC_SHA1_DIGEST_LENGTH; + + (void)racoon_free(c); + return(res); +} +#else +vchar_t * +eay_hmacsha1_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l); + res->l = l; + HMAC_cleanup((HMAC_CTX *)c); + + (void)racoon_free(c); + + if (SHA_DIGEST_LENGTH != res->l) { + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha1 length mismatch %zd.\n", res->l); + vfree(res); + return NULL; + } + + return(res); +} +#endif /* __APPLE__ */ + +/* + * HMAC MD5 + */ +vchar_t * +eay_hmacmd5_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacmd5_init(key); + eay_hmacmd5_update(ctx, data); + res = eay_hmacmd5_final(ctx); + + return(res); +} + +caddr_t +eay_hmacmd5_init(key) + vchar_t *key; +{ +#ifdef __APPLE__ + return eay_hmac_init(key, kCCHmacAlgMD5); +#else + return eay_hmac_init(key, EVP_md5()); +#endif +} + +void +eay_hmacmd5_update(c, data) + caddr_t c; + vchar_t *data; +{ +#ifdef __APPLE__ + CCHmacUpdate((CCHmacContext *)c, data->v, data->l); +#else + HMAC_Update((HMAC_CTX *)c, (unsigned char *) data->v, data->l); +#endif +} + +#ifdef __APPLE__ +vchar_t * +eay_hmacmd5_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(CC_MD5_DIGEST_LENGTH)) == 0) + return NULL; + + CCHmacFinal((CCHmacContext *)c, res->v); + res->l = CC_MD5_DIGEST_LENGTH; + (void)racoon_free(c); + + return(res); +} +#else +vchar_t * +eay_hmacmd5_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, (unsigned char *) res->v, &l); + res->l = l; + HMAC_cleanup((HMAC_CTX *)c); + + (void)racoon_free(c); + + if (MD5_DIGEST_LENGTH != res->l) { + plog(LLV_ERROR, LOCATION, NULL, + "hmac md5 length mismatch %zd.\n", res->l); + vfree(res); + return NULL; + } + + return(res); +} +#endif /* __APPLE__ */ + +#ifdef WITH_SHA2 +/* + * SHA2-512 functions + */ +caddr_t +eay_sha2_512_init() +{ + SHA512_CTX *c = racoon_malloc(sizeof(*c)); + + SHA512_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA512_Update((SHA512_CTX *)c, (unsigned char *) data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return(0); + + SHA512_Final((unsigned char *) res->v, (SHA512_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_512_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_512_init(); + eay_sha2_512_update(ctx, data); + res = eay_sha2_512_final(ctx); + + return(res); +} + +int +eay_sha2_512_hashlen() +{ + return SHA512_DIGEST_LENGTH << 3; +} +#endif + +#ifdef WITH_SHA2 +/* + * SHA2-384 functions + */ + +#ifdef __APPLE__ +typedef SHA512_CTX SHA384_CTX; +#endif + +caddr_t +eay_sha2_384_init() +{ + SHA384_CTX *c = racoon_malloc(sizeof(*c)); + + SHA384_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA384_Update((SHA384_CTX *)c, (unsigned char *) data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return(0); + + SHA384_Final((unsigned char *) res->v, (SHA384_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_384_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_384_init(); + eay_sha2_384_update(ctx, data); + res = eay_sha2_384_final(ctx); + + return(res); +} + +int +eay_sha2_384_hashlen() +{ + return SHA384_DIGEST_LENGTH << 3; +} +#endif + +#ifdef WITH_SHA2 +/* + * SHA2-256 functions + */ +caddr_t +eay_sha2_256_init() +{ + SHA256_CTX *c = racoon_malloc(sizeof(*c)); + + SHA256_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA256_Update((SHA256_CTX *)c, (unsigned char *) data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return(0); + + SHA256_Final((unsigned char *) res->v, (SHA256_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_256_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_256_init(); + eay_sha2_256_update(ctx, data); + res = eay_sha2_256_final(ctx); + + return(res); +} + +int +eay_sha2_256_hashlen() +{ + return SHA256_DIGEST_LENGTH << 3; +} +#endif + +/* + * SHA functions + */ +caddr_t +eay_sha1_init() +{ + SHA_CTX *c = racoon_malloc(sizeof(*c)); + + SHA1_Init(c); + + return((caddr_t)c); +} + +void +eay_sha1_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA1_Update((SHA_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha1_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return(0); + + SHA1_Final((unsigned char *) res->v, (SHA_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha1_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha1_init(); + eay_sha1_update(ctx, data); + res = eay_sha1_final(ctx); + + return(res); +} + +int +eay_sha1_hashlen() +{ + return SHA_DIGEST_LENGTH << 3; +} + +/* + * MD5 functions + */ +caddr_t +eay_md5_init() +{ + MD5_CTX *c = racoon_malloc(sizeof(*c)); + + MD5_Init(c); + + return((caddr_t)c); +} + +void +eay_md5_update(c, data) + caddr_t c; + vchar_t *data; +{ + MD5_Update((MD5_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_md5_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return(0); + + MD5_Final((unsigned char *) res->v, (MD5_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_md5_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_md5_init(); + eay_md5_update(ctx, data); + res = eay_md5_final(ctx); + + return(res); +} + +int +eay_md5_hashlen() +{ + return MD5_DIGEST_LENGTH << 3; +} + +/* + * eay_set_random + * size: number of bytes. + */ +vchar_t * +eay_set_random(size) + u_int32_t size; +{ + BIGNUM *r = NULL; + vchar_t *res = 0; + + if ((r = BN_new()) == NULL) + goto end; + BN_rand(r, size * 8, 0, 0); + eay_bn2v(&res, r); + +end: + if (r) + BN_free(r); + return(res); +} + +/* DH */ +int +eay_dh_generate(prime, g, publen, pub, priv) + vchar_t *prime, **pub, **priv; + u_int publen; + u_int32_t g; +{ + BIGNUM *p = NULL; + DH *dh = NULL; + int error = -1; + + /* initialize */ + /* pre-process to generate number */ + if (eay_v2bn(&p, prime) < 0) + goto end; + + if ((dh = DH_new()) == NULL) + goto end; + dh->p = p; + p = NULL; /* p is now part of dh structure */ + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if (publen != 0) + dh->length = publen; + + /* generate public and private number */ + if (!DH_generate_key(dh)) + goto end; + + /* copy results to buffers */ + if (eay_bn2v(pub, dh->pub_key) < 0) + goto end; + if (eay_bn2v(priv, dh->priv_key) < 0) { + vfree(*pub); + goto end; + } + + error = 0; + +end: + if (dh != NULL) + DH_free(dh); + if (p != 0) + BN_free(p); + return(error); +} + +int +eay_dh_compute(prime, g, pub, priv, pub2, key) + vchar_t *prime, *pub, *priv, *pub2, **key; + u_int32_t g; +{ + BIGNUM *dh_pub = NULL; + DH *dh = NULL; + int l; + unsigned char *v = NULL; + int error = -1; + + /* make public number to compute */ + if (eay_v2bn(&dh_pub, pub2) < 0) + goto end; + + /* make DH structure */ + if ((dh = DH_new()) == NULL) + goto end; + if (eay_v2bn(&dh->p, prime) < 0) + goto end; + if (eay_v2bn(&dh->pub_key, pub) < 0) + goto end; + if (eay_v2bn(&dh->priv_key, priv) < 0) + goto end; + dh->length = pub2->l * 8; + + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if ((v = racoon_calloc(prime->l, sizeof(u_char))) == NULL) + goto end; + if ((l = DH_compute_key(v, dh_pub, dh)) == -1) + goto end; + memcpy((*key)->v + (prime->l - l), v, l); + + error = 0; + +end: + if (dh_pub != NULL) + BN_free(dh_pub); + if (dh != NULL) + DH_free(dh); + if (v != NULL) + racoon_free(v); + return(error); +} + +/* + * convert vchar_t <-> BIGNUM. + * + * vchar_t: unit is u_char, network endian, most significant byte first. + * BIGNUM: unit is BN_ULONG, each of BN_ULONG is in host endian, + * least significant BN_ULONG must come first. + * + * hex value of "0x3ffe050104" is represented as follows: + * vchar_t: 3f fe 05 01 04 + * BIGNUM (BN_ULONG = u_int8_t): 04 01 05 fe 3f + * BIGNUM (BN_ULONG = u_int16_t): 0x0104 0xfe05 0x003f + * BIGNUM (BN_ULONG = u_int32_t_t): 0xfe050104 0x0000003f + */ +int +eay_v2bn(bn, var) + BIGNUM **bn; + vchar_t *var; +{ + if ((*bn = BN_bin2bn((unsigned char *) var->v, var->l, NULL)) == NULL) + return -1; + + return 0; +} + +int +eay_bn2v(var, bn) + vchar_t **var; + BIGNUM *bn; +{ + *var = vmalloc(bn->top * BN_BYTES); + if (*var == NULL) + return(-1); + + (*var)->l = BN_bn2bin(bn, (unsigned char *) (*var)->v); + + return 0; +} + +void +eay_init() +{ + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); +#ifdef HAVE_OPENSSL_ENGINE_H + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); +#endif +} + +vchar_t * +base64_decode(char *in, long inlen) +{ + BIO *bio=NULL, *b64=NULL; + vchar_t *res = NULL; + char out[inlen*2]; + long outlen; + + bio = BIO_new_mem_buf(in, inlen); + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_push(b64, bio); + + outlen = BIO_read(bio, out, inlen * 2); + if (outlen <= 0) { + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + goto out; + } + + res = vmalloc(outlen); + if (!res) + goto out; + + memcpy(res->v, out, outlen); + +out: + if (bio) + BIO_free_all(bio); + + return res; +} + +vchar_t * +base64_encode(char *in, long inlen) +{ + BIO *bio=NULL, *b64=NULL; + char *ptr; + long plen = -1; + vchar_t *res = NULL; + + bio = BIO_new(BIO_s_mem()); + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_push(b64, bio); + + BIO_write(bio, in, inlen); + BIO_flush(bio); + + plen = BIO_get_mem_data(bio, &ptr); + res = vmalloc(plen+1); + if (!res) + goto out; + + memcpy (res->v, ptr, plen); + res->v[plen] = '\0'; + +out: + if (bio) + BIO_free_all(bio); + + return res; +} + +static RSA * +binbuf_pubkey2rsa(vchar_t *binbuf) +{ + BIGNUM *exp, *mod; + RSA *rsa_pub = NULL; + + if (binbuf->v[0] > binbuf->l - 1) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: decoded string doesn't make sense.\n"); + goto out; + } + + exp = BN_bin2bn((unsigned char *) (binbuf->v + 1), binbuf->v[0], NULL); + mod = BN_bin2bn((unsigned char *) (binbuf->v + binbuf->v[0] + 1), + binbuf->l - binbuf->v[0] - 1, NULL); + rsa_pub = RSA_new(); + + if (!exp || !mod || !rsa_pub) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey parsing error: %s\n", eay_strerror()); + if (exp) + BN_free(exp); + if (mod) + BN_free(exp); + if (rsa_pub) + RSA_free(rsa_pub); + rsa_pub = NULL; + goto out; + } + + rsa_pub->n = mod; + rsa_pub->e = exp; + +out: + return rsa_pub; +} + +RSA * +base64_pubkey2rsa(char *in) +{ + BIGNUM *exp, *mod; + RSA *rsa_pub = NULL; + vchar_t *binbuf; + + if (strncmp(in, "0s", 2) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: doesn't start with '0s'\n"); + return NULL; + } + + binbuf = base64_decode(in + 2, strlen(in + 2)); + if (!binbuf) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: Base64 decoding failed.\n"); + return NULL; + } + + if (binbuf->v[0] > binbuf->l - 1) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey format error: decoded string doesn't make sense.\n"); + goto out; + } + + rsa_pub = binbuf_pubkey2rsa(binbuf); + +out: + if (binbuf) + vfree(binbuf); + + return rsa_pub; +} + +RSA * +bignum_pubkey2rsa(BIGNUM *in) +{ + RSA *rsa_pub = NULL; + vchar_t *binbuf; + + binbuf = vmalloc(BN_num_bytes(in)); + if (!binbuf) { + plog(LLV_ERROR, LOCATION, NULL, "Plain RSA pubkey conversion: memory allocation failed..\n"); + return NULL; + } + + BN_bn2bin(in, (unsigned char *) binbuf->v); + + rsa_pub = binbuf_pubkey2rsa(binbuf); + +out: + if (binbuf) + vfree(binbuf); + + return rsa_pub; +} + +u_int32_t +eay_random() +{ + u_int32_t result; + vchar_t *vrand; + + vrand = eay_set_random(sizeof(result)); + memcpy(&result, vrand->v, sizeof(result)); + vfree(vrand); + + return result; +} + +const char * +eay_version() +{ + return SSLeay_version(SSLEAY_VERSION); +} diff --git a/ipsec-tools/racoon/crypto_openssl.h b/ipsec-tools/racoon/crypto_openssl.h new file mode 100644 index 0000000..8b71a7d --- /dev/null +++ b/ipsec-tools/racoon/crypto_openssl.h @@ -0,0 +1,229 @@ +/* $Id: crypto_openssl.h,v 1.11 2004/11/13 11:28:01 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CRYPTO_OPENSSL_H +#define _CRYPTO_OPENSSL_H + +#include "crypto_openssl.h" + +#include +#include + +#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 +extern int eay_v2bn __P((BIGNUM **, vchar_t *)); +extern int eay_bn2v __P((vchar_t **, BIGNUM *)); + +extern const char *eay_version __P((void)); + +#define CBC_BLOCKLEN 8 +#define IPSEC_ENCRYPTKEYLEN 8 + +#endif /* _CRYPTO_OPENSSL_H */ diff --git a/ipsec-tools/racoon/debug.h b/ipsec-tools/racoon/debug.h new file mode 100644 index 0000000..7fd45f2 --- /dev/null +++ b/ipsec-tools/racoon/debug.h @@ -0,0 +1,39 @@ +/* $Id: debug.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +/* define by main.c */ +extern int f_local; +extern int vflag; + +#endif /* _DEBUG_H */ diff --git a/ipsec-tools/racoon/debugrm.h b/ipsec-tools/racoon/debugrm.h new file mode 100644 index 0000000..3dec6cd --- /dev/null +++ b/ipsec-tools/racoon/debugrm.h @@ -0,0 +1,92 @@ +/* $Id: debugrm.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEBUGRM_H +#define _DEBUGRM_H + +#define DRMDUMPFILE "/var/tmp/debugrm.dump" + +#ifdef NONEED_DRM +#ifndef racoon_malloc +#define racoon_malloc(sz) malloc((sz)) +#endif +#ifndef racoon_calloc +#define racoon_calloc(cnt, sz) calloc((cnt), (sz)) +#endif +#ifndef racoon_realloc +#define racoon_realloc(old, sz) realloc((old), (sz)) +#endif +#ifndef racoon_free +#define racoon_free(p) free((p)) +#endif +#else /*!NONEED_DRM*/ +#ifndef racoon_malloc +#define racoon_malloc(sz) \ + DRM_malloc(__FILE__, __LINE__, __func__, (sz)) +#endif +#ifndef racoon_calloc +#define racoon_calloc(cnt, sz) \ + DRM_calloc(__FILE__, __LINE__, __func__, (cnt), (sz)) +#endif +#ifndef racoon_realloc +#define racoon_realloc(old, sz) \ + DRM_realloc(__FILE__, __LINE__, __func__, (old), (sz)) +#endif +#ifndef racoon_free +#define racoon_free(p) \ + DRM_free(__FILE__, __LINE__, __func__, (p)) +#endif +#endif /*NONEED_DRM*/ + +extern void DRM_init __P((void)); +extern void DRM_dump __P((void)); +extern void *DRM_malloc __P((char *, int, char *, size_t)); +extern void *DRM_calloc __P((char *, int, char *, size_t, size_t)); +extern void *DRM_realloc __P((char *, int, char *, void *, size_t)); +extern void DRM_free __P((char *, int, char *, void *)); + +#ifndef NONEED_DRM +#define vmalloc(sz) \ + DRM_vmalloc(__FILE__, __LINE__, __func__, (sz)) +#define vdup(old) \ + DRM_vdup(__FILE__, __LINE__, __func__, (old)) +#define vrealloc(old, sz) \ + DRM_vrealloc(__FILE__, __LINE__, __func__, (old), (sz)) +#define vfree(p) \ + DRM_vfree(__FILE__, __LINE__, __func__, (p)) +#endif + +extern void *DRM_vmalloc __P((char *, int, char *, size_t)); +extern void *DRM_vrealloc __P((char *, int, char *, void *, size_t)); +extern void DRM_vfree __P((char *, int, char *, void *)); +extern void *DRM_vdup __P((char *, int, char *, void *)); + +#endif /* _DEBUGRM_H */ diff --git a/ipsec-tools/racoon/dhgroup.h b/ipsec-tools/racoon/dhgroup.h new file mode 100644 index 0000000..8f65583 --- /dev/null +++ b/ipsec-tools/racoon/dhgroup.h @@ -0,0 +1,203 @@ +/* $Id: dhgroup.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DHGROUP_H +#define _DHGROUP_H + +#define OAKLEY_PRIME_MODP768 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP1024 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" \ + "FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP1536 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF" + +/* RFC 3526 */ +#define OAKLEY_PRIME_MODP2048 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP3072 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP4096 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \ + "FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP6144 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ + "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \ + "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \ + "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \ + "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \ + "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \ + "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \ + "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ + "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \ + "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \ + "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \ + "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP8192 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ + "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \ + "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \ + "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \ + "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \ + "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \ + "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \ + "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ + "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \ + "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \ + "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \ + "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \ + "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \ + "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \ + "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \ + "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \ + "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \ + "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \ + "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \ + "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \ + "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \ + "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \ + "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF" + +extern struct dhgroup dh_modp768; +extern struct dhgroup dh_modp1024; +extern struct dhgroup dh_modp1536; +extern struct dhgroup dh_modp2048; +extern struct dhgroup dh_modp3072; +extern struct dhgroup dh_modp4096; +extern struct dhgroup dh_modp6144; +extern struct dhgroup dh_modp8192; + +#endif /* _DHGROUP_H */ diff --git a/ipsec-tools/racoon/dnssec.c b/ipsec-tools/racoon/dnssec.c new file mode 100644 index 0000000..2f1dc25 --- /dev/null +++ b/ipsec-tools/racoon/dnssec.c @@ -0,0 +1,149 @@ +/* $KAME: dnssec.c,v 1.2 2001/08/05 18:46:07 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "var.h" +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "netdb_dnssec.h" +#include "strnames.h" +#include "dnssec.h" +#include "gcmalloc.h" + +extern int h_errno; + +cert_t * +dnssec_getcert(id) + vchar_t *id; +{ + cert_t *cert = NULL; + struct certinfo *res = NULL; + struct ipsecdoi_id_b *id_b; + int type; + char *name = NULL; + int namelen; + int error; + + id_b = (struct ipsecdoi_id_b *)id->v; + + namelen = id->l - sizeof(*id_b); + name = racoon_malloc(namelen + 1); + if (!name) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return NULL; + } + memcpy(name, id_b + 1, namelen); + name[namelen] = '\0'; + + switch (id_b->type) { + case IPSECDOI_ID_FQDN: + error = getcertsbyname(name, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getcertsbyname(\"%s\") failed.\n", name); + goto err; + } + break; + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + /* XXX should be processed to query PTR ? */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "impropper ID type passed %s " + "though getcert method is dnssec.\n", + s_ipsecdoi_ident(id_b->type)); + return NULL; + } + + /* check response */ + if (res->ci_next != NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "not supported multiple CERT RR.\n"); + } + switch (res->ci_type) { + case DNSSEC_TYPE_PKIX: + /* XXX is it enough condition to set this type ? */ + type = ISAKMP_CERT_X509SIGN; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported CERT RR type %d.\n", res->ci_type); + goto err; + } + + /* create cert holder */ + cert = oakley_newcert(); + if (cert == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto err; + } + cert->pl = vmalloc(res->ci_certlen + 1); + if (cert->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto err; + } + memcpy(cert->pl->v + 1, res->ci_cert, res->ci_certlen); + cert->pl->v[0] = type; + cert->cert.v = cert->pl->v + 1; + cert->cert.l = cert->pl->l - 1; + + plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n"); + plogdump(LLV_DEBUG, cert->pl->v, cert->pl->l); + +end: + if (res) + freecertinfo(res); + + return cert; + +err: + if (name) + racoon_free(name); + if (cert) + oakley_delcert(cert); + goto end; +} diff --git a/ipsec-tools/racoon/dnssec.h b/ipsec-tools/racoon/dnssec.h new file mode 100644 index 0000000..e43ed81 --- /dev/null +++ b/ipsec-tools/racoon/dnssec.h @@ -0,0 +1,37 @@ +/* $Id: dnssec.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DNSSEC_H +#define _DNSSEC_H + +extern cert_t *dnssec_getcert __P((vchar_t *)); + +#endif /* _DNSSEC_H */ diff --git a/ipsec-tools/racoon/dump.h b/ipsec-tools/racoon/dump.h new file mode 100644 index 0000000..7473bbc --- /dev/null +++ b/ipsec-tools/racoon/dump.h @@ -0,0 +1,39 @@ +/* $Id: dump.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DUMP_H +#define _DUMP_H + +extern int isakmp_dump_open __P((char *)); +extern int isakmp_dump_close __P((void)); +extern int isakmp_dump __P((vchar_t *, struct sockaddr *, struct sockaddr *)); + +#endif /* _DUMP_H */ diff --git a/ipsec-tools/racoon/eaytest.c b/ipsec-tools/racoon/eaytest.c new file mode 100644 index 0000000..3265546 --- /dev/null +++ b/ipsec-tools/racoon/eaytest.c @@ -0,0 +1,1077 @@ +/* $Id: eaytest.c,v 1.20.4.2 2005/06/28 22:38:02 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include "vmbuf.h" +#include "plog.h" +#include "misc.h" +#include "gcmalloc.h" +#include "evt.h" + + +struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); +int evtlist_len = 0; + +void +evt_push(src, dst, type, optdata) + struct sockaddr *src; + struct sockaddr *dst; + int type; + vchar_t *optdata; +{ + struct evtdump *evtdump; + struct evt *evt; + size_t len; + + /* If we are above the limit, don't record anything */ + if (evtlist_len > EVTLIST_MAX) { + plog(LLV_DEBUG, LOCATION, NULL, + "Cannot record event: event queue overflowed\n"); + return; + } + + /* If we hit the limit, record an overflow event instead */ + if (evtlist_len == EVTLIST_MAX) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot record event: event queue overflow\n"); + src = NULL; + dst = NULL; + type = EVTT_OVERFLOW; + optdata = NULL; + } + + len = sizeof(*evtdump); + if (optdata) + len += optdata->l; + + if ((evtdump = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", + strerror(errno)); + return; + } + + if ((evt = racoon_malloc(sizeof(*evt))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", + strerror(errno)); + racoon_free(evtdump); + return; + } + + if (src) + memcpy(&evtdump->src, src, sysdep_sa_len(src)); + if (dst) + memcpy(&evtdump->dst, dst, sysdep_sa_len(dst)); + evtdump->len = len; + evtdump->type = type; + time(&evtdump->timestamp); + + if (optdata) + memcpy(evtdump + 1, optdata->v, optdata->l); + + evt->dump = evtdump; + TAILQ_INSERT_TAIL(&evtlist, evt, next); + + evtlist_len++; + + return; +} + +struct evtdump * +evt_pop(void) { + struct evtdump *evtdump; + struct evt *evt; + + if ((evt = TAILQ_FIRST(&evtlist)) == NULL) + return NULL; + + evtdump = evt->dump; + TAILQ_REMOVE(&evtlist, evt, next); + racoon_free(evt); + evtlist_len--; + + return evtdump; +} + +vchar_t * +evt_dump(void) { + struct evtdump *evtdump; + vchar_t *buf = NULL; + + if ((evtdump = evt_pop()) != NULL) { + if ((buf = vmalloc(evtdump->len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "evt_dump failed: %s\n", strerror(errno)); + return NULL; + } + memcpy(buf->v, evtdump, evtdump->len); + racoon_free(evtdump); + } + + return buf; +} diff --git a/ipsec-tools/racoon/evt.h b/ipsec-tools/racoon/evt.h new file mode 100644 index 0000000..209c854 --- /dev/null +++ b/ipsec-tools/racoon/evt.h @@ -0,0 +1,84 @@ +/* $Id: evt.h,v 1.3 2004/11/29 23:30:39 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _EVT_H +#define _EVT_H + +struct evtdump { + size_t len; + struct sockaddr_storage src; + struct sockaddr_storage dst; + time_t timestamp; + int type; + /* + * Optionnal list of struct isakmp_data + * for type EVTT_ISAKMP_CFG_DONE + */ +}; + +/* type */ +#define EVTT_UNSEPC 0 +#define EVTT_PHASE1_UP 1 +#define EVTT_PHASE1_DOWN 2 +#define EVTT_XAUTH_SUCCESS 3 +#define EVTT_ISAKMP_CFG_DONE 4 +#define EVTT_PHASE2_UP 5 +#define EVTT_PHASE2_DOWN 6 +#define EVTT_DPD_TIMEOUT 7 +#define EVTT_PEER_NO_RESPONSE 8 +#define EVTT_PEER_DELETE 9 +#define EVTT_RACOON_QUIT 10 +#define EVTT_XAUTH_FAILED 11 +#define EVTT_OVERFLOW 12 /* Event queue overflowed */ +#define EVTT_PEERPH1AUTH_FAILED 13 + +struct evt { + struct evtdump *dump; + TAILQ_ENTRY(evt) next; +}; + +TAILQ_HEAD(evtlist, evt); + +#define EVTLIST_MAX 32 + +#ifdef ENABLE_ADMINPORT +struct evtdump *evt_pop(void); +vchar_t *evt_dump(void); +void evt_push(struct sockaddr *, struct sockaddr *, int, vchar_t *); +#endif + +#ifdef ENABLE_ADMINPORT +#define EVT_PUSH(src, dst, type, optdata) evt_push(src, dst, type, optdata); +#else +#define EVT_PUSH(src, dst, type, optdata) ; +#endif + +#endif /* _EVT_H */ diff --git a/ipsec-tools/racoon/gcmalloc.h b/ipsec-tools/racoon/gcmalloc.h new file mode 100644 index 0000000..ca08528 --- /dev/null +++ b/ipsec-tools/racoon/gcmalloc.h @@ -0,0 +1,114 @@ +/* $KAME: gcmalloc.h,v 1.4 2001/11/16 04:34:57 sakane Exp $ */ + +/* + * Copyright (C) 2000, 2001 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Debugging malloc glue for Racoon. + */ + +#ifndef _GCMALLOC_H_DEFINED +#define _GCMALLOC_H_DEFINED + +/* ElectricFence needs no special handling. */ + +/* + * Boehm-GC provides GC_malloc(), GC_realloc(), GC_free() functions, + * but not the traditional entry points. So what we do is provide + * malloc(), calloc(), realloc(), and free() entry points in the main + * program and letting the linker do the rest. + */ +#ifdef GC +#define GC_DEBUG +#include + +#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 +#endif /* DMALLOC */ + +#ifdef DEBUG_RECORD_MALLOCATION +#include +#else +#ifndef racoon_malloc +#define racoon_malloc(sz) malloc((sz)) +#endif +#ifndef racoon_calloc +#define racoon_calloc(cnt, sz) calloc((cnt), (sz)) +#endif +#ifndef racoon_realloc +#define racoon_realloc(old, sz) realloc((old), (sz)) +#endif +#ifndef racoon_free +#define racoon_free(p) free((p)) +#endif +#endif /* DEBUG_RECORD_MALLOCATION */ + +#endif /* _GCMALLOC_H_DEFINED */ diff --git a/ipsec-tools/racoon/genlist.c b/ipsec-tools/racoon/genlist.c new file mode 100644 index 0000000..0f9b195 --- /dev/null +++ b/ipsec-tools/racoon/genlist.c @@ -0,0 +1,172 @@ +/* $Id: genlist.c,v 1.2 2004/07/12 20:43:50 ludvigm Exp $ */ + +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include +#include + +#include "genlist.h" + +struct genlist * +genlist_init (void) +{ + struct genlist *new = calloc(sizeof(struct genlist), 1); + TAILQ_INIT(new); + return new; +} + +struct genlist_entry * +genlist_insert (struct genlist *head, void *data) +{ + struct genlist_entry *entry = calloc(sizeof(struct genlist_entry), 1); + entry->data = data; + TAILQ_INSERT_HEAD(head, entry, chain); + return entry; +} + +struct genlist_entry * +genlist_append (struct genlist *head, void *data) +{ + struct genlist_entry *entry = calloc(sizeof(struct genlist_entry), 1); + entry->data = data; + TAILQ_INSERT_TAIL(head, entry, chain); + return entry; +} + +void * +genlist_foreach (struct genlist *head, genlist_func_t func, void *arg) +{ + struct genlist_entry *p; + void *ret = NULL; + TAILQ_FOREACH(p, head, chain) { + ret = (*func)(p->data, arg); + if (ret) + break; + } + + return ret; +} + +void * +genlist_next (struct genlist *head, struct genlist_entry **buf) +{ + struct genlist_entry *p; + + if (head) + p = TAILQ_FIRST(head); + else + p = (buf && *buf) ? TAILQ_NEXT(*buf, chain) : NULL; + if (buf) + *buf = p; + return (p ? p->data : NULL); +} + +void +genlist_free (struct genlist *head, genlist_freedata_t func) +{ + struct genlist_entry *p; + + while ((p = TAILQ_LAST(head, genlist)) != NULL) { + TAILQ_REMOVE(head, p, chain); + if (func) + func(p->data); + free(p); + } + free(head); +} + + +#if 0 +/* Here comes the example... */ +struct conf { + struct genlist *l1, *l2; +}; + +void * +print_entry(void *entry, void *arg) +{ + if (!entry) + return NULL; + printf("%s\n", (char *)entry); + return NULL; +} + +void +dump_list(struct genlist *head) +{ + genlist_foreach(head, print_entry, NULL); +} + +void +free_data(void *data) +{ + printf ("removing %s\n", (char *)data); +} + +int main() +{ + struct conf *cf; + char *cp; + struct genlist_entry *gpb; + + cf = calloc(sizeof(struct conf), 1); + cf->l1 = genlist_init(); + cf->l2 = genlist_init(); + + genlist_insert(cf->l1, "Ahoj"); + genlist_insert(cf->l1, "Cau"); + genlist_insert(cf->l1, "Nazdar"); + genlist_insert(cf->l1, "Te buch"); + + genlist_append(cf->l2, "Curak"); + genlist_append(cf->l2, "Kozy"); + genlist_append(cf->l2, "Pica"); + genlist_append(cf->l2, "Prdel"); + + printf("List 2\n"); + dump_list(cf->l2); + printf("\nList 1\n"); + dump_list(cf->l1); + + printf("\nList 2 - using genlist_next()\n"); + for (cp = genlist_next (cf->l2, &gpb); cp; cp = genlist_next (0, &gpb)) + printf("%s\n", cp); + + printf("\nFreeing List 1\n"); + /* the data here isn't actually alloc'd so we would really call + * genlist_free (cf->l1, 0); but to illustrate the idea */ + genlist_free (cf->l1, free_data); + cf->l1 = 0; + + return 0; +} +#endif diff --git a/ipsec-tools/racoon/genlist.h b/ipsec-tools/racoon/genlist.h new file mode 100644 index 0000000..089e624 --- /dev/null +++ b/ipsec-tools/racoon/genlist.h @@ -0,0 +1,80 @@ +/* $Id: genlist.h,v 1.2 2004/07/12 20:43:50 ludvigm Exp $ */ + +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 + +/* See the bottom of genlist.c for example use. */ + +/* This declares 'struct genlist' */ +TAILQ_HEAD(genlist, genlist_entry); + +/* This is where the data are actually stored. */ +struct genlist_entry { + void *data; + TAILQ_ENTRY(genlist_entry) chain; +}; + +/* This function returns an initialized list head. */ +struct genlist *genlist_init (void); + +/* Insert an entry at the beginning/end og the list. */ +struct genlist_entry *genlist_insert (struct genlist *head, void *data); +struct genlist_entry *genlist_append (struct genlist *head, void *data); + +/* Create a function with this prototype for use with genlist_foreach(). + * See genlist_foreach() description below for details. */ +typedef void *(genlist_func_t)(void *entry, void *arg); + +/* Traverse the list and call 'func' for each entry. As long as func() returns + * NULL the list traversal continues, once it returns non-NULL (usually the + * 'entry' arg), the list traversal exits and the return value is returned + * further from genlist_foreach(). Optional 'arg' may be passed to func(), e.g. + * for some lookup purposes, etc. */ +void *genlist_foreach (struct genlist *head, genlist_func_t func, void *arg); + +/* Get first entry in list if head is not NULL, otherwise get next + * entry based on saved position in list from previous call as stored in buf. + * If buf is NULL no position is saved */ +void *genlist_next (struct genlist *head, struct genlist_entry **buf); + +/* Create a function with this prototype for use with genlist_free() + * to free any storage associated with genlist_entry.data */ +typedef void (genlist_freedata_t)(void *entry); + +/* Free all storage associated with list at head using func to free any + * alloc()d data in data field of genlist_entry */ +void genlist_free (struct genlist *head, genlist_freedata_t func); + +#endif /* _GENLIST_H */ diff --git a/ipsec-tools/racoon/getcertsbyname.c b/ipsec-tools/racoon/getcertsbyname.c new file mode 100644 index 0000000..890f067 --- /dev/null +++ b/ipsec-tools/racoon/getcertsbyname.c @@ -0,0 +1,416 @@ +/* $KAME: getcertsbyname.c,v 1.7 2001/11/16 04:12:59 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//%%%HWR Do we need this? +#define BIND_8_COMPAT + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_LWRES_GETRRSETBYNAME +#include +#include +#else +#include +#endif +#include +#include +#include + +#ifdef DNSSEC_DEBUG +#include +#include +#endif + +#include "netdb_dnssec.h" + +/* XXX should it use ci_errno to hold errno instead of h_errno ? */ +extern int h_errno; + +static struct certinfo *getnewci __P((int, int, int, int, int, + unsigned char *)); + +static struct certinfo * +getnewci(qtype, keytag, algorithm, flags, certlen, cert) + int qtype, keytag, algorithm, flags, certlen; + unsigned char *cert; +{ + struct certinfo *res; + + res = malloc(sizeof(*res)); + if (!res) + return NULL; + + memset(res, 0, sizeof(*res)); + res->ci_type = qtype; + res->ci_keytag = keytag; + res->ci_algorithm = algorithm; + res->ci_flags = flags; + res->ci_certlen = certlen; + res->ci_cert = malloc(certlen); + if (!res->ci_cert) { + free(res); + return NULL; + } + memcpy(res->ci_cert, cert, certlen); + + return res; +} + +void +freecertinfo(ci) + struct certinfo *ci; +{ + struct certinfo *next; + + do { + next = ci->ci_next; + if (ci->ci_cert) + free(ci->ci_cert); + free(ci); + ci = next; + } while (ci); +} + +/* + * get CERT RR by FQDN and create certinfo structure chain. + */ +#ifdef HAVE_LWRES_GETRRSETBYNAME +#define getrrsetbyname lwres_getrrsetbyname +#define freerrset lwres_freerrset +#define hstrerror lwres_hstrerror +#endif +#if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(HAVE_GETRRSETBYNAME) //%%% BUG FIX - HAVE misspelled +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + int rdlength; + char *cp; + int type, keytag, algorithm; + struct certinfo head, *cur; + struct rrsetinfo *rr = NULL; + int i; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr); + if (error) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s\n", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + + if (rr->rri_rdclass != C_IN + || rr->rri_rdtype != T_CERT + || rr->rri_nrdatas == 0) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + if (!(rr->rri_flags & LWRDATA_VALIDATED)) + printf("rr is not valid"); +#endif + + for (i = 0; i < rr->rri_nrdatas; i++) { + rdlength = rr->rri_rdatas[i].rdi_length; + cp = rr->rri_rdatas[i].rdi_data; + + GETSHORT(type, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + type, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(type, keytag, algorithm, + rr->rri_flags, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + } + + *res = head.ci_next; + error = 0; + +end: + if (rr) + freerrset(rr); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#else /*!HAVE_LWRES_GETRRSETBYNAME*/ +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + unsigned char *answer = NULL, *p; + int buflen, anslen, len; + HEADER *hp; + int qdcount, ancount, rdlength; + unsigned char *cp, *eom; + char hostbuf[1024]; /* XXX */ + int qtype, qclass, keytag, algorithm; + struct certinfo head, *cur; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + /* get CERT RR */ + buflen = 512; + do { + + buflen *= 2; + p = realloc(answer, buflen); + if (!p) { +#ifdef DNSSEC_DEBUG + printf("realloc: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + answer = p; + + anslen = res_query(name, C_IN, T_CERT, answer, buflen); + if (anslen == -1) + goto end; + + } while (buflen < anslen); + +#ifdef DNSSEC_DEBUG + printf("get a DNS packet len=%d\n", anslen); +#endif + + /* parse CERT RR */ + eom = answer + anslen; + + hp = (HEADER *)answer; + qdcount = ntohs(hp->qdcount); + ancount = ntohs(hp->ancount); + + /* question section */ + if (qdcount != 1) { +#ifdef DNSSEC_DEBUG + printf("query count is not 1.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cp = (unsigned char *)(hp + 1); + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* QTYPE */ + GETSHORT(qclass, cp); /* QCLASS */ + + /* answer section */ + while (ancount-- && cp < eom) { + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* TYPE */ + GETSHORT(qclass, cp); /* CLASS */ + cp += INT32SZ; /* TTL */ + GETSHORT(rdlength, cp); /* RDLENGTH */ + + /* CERT RR */ + if (qtype != T_CERT) { +#ifdef DNSSEC_DEBUG + printf("not T_CERT\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + GETSHORT(qtype, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + if (cp + rdlength > eom) { +#ifdef DNSSEC_DEBUG + printf("rdlength is too long.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + qtype, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(qtype, keytag, algorithm, + 0, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + + cp += rdlength; + } + + *res = head.ci_next; + error = 0; + +end: + if (answer) + free(answer); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#endif + +#ifdef DNSSEC_DEBUG +int +b64encode(p, len) + char *p; + int len; +{ + static const char b64t[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + + while (len > 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]); + printf("%c", b64t[p[2] & 0x3f]); + len -= 3; + p += 3; + } + + if (len == 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c)]); + printf("%c", '='); + } else if (len == 1) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)]); + printf("%c", '='); + printf("%c", '='); + } + + return 0; +} + +int +main(ac, av) + int ac; + char **av; +{ + struct certinfo *res, *p; + int i; + + if (ac < 2) { + printf("Usage: a.out (FQDN)\n"); + exit(1); + } + + i = getcertsbyname(*(av + 1), &res); + if (i != 0) { + herror("getcertsbyname"); + exit(1); + } + printf("getcertsbyname succeeded.\n"); + + i = 0; + for (p = res; p; p = p->ci_next) { + printf("certinfo[%d]:\n", i); + printf("\tci_type=%d\n", p->ci_type); + printf("\tci_keytag=%d\n", p->ci_keytag); + printf("\tci_algorithm=%d\n", p->ci_algorithm); + printf("\tci_flags=%d\n", p->ci_flags); + printf("\tci_certlen=%d\n", p->ci_certlen); + printf("\tci_cert: "); + b64encode(p->ci_cert, p->ci_certlen); + printf("\n"); + i++; + } + + freecertinfo(res); + + exit(0); +} +#endif diff --git a/ipsec-tools/racoon/gnuc.h b/ipsec-tools/racoon/gnuc.h new file mode 100644 index 0000000..a923f77 --- /dev/null +++ b/ipsec-tools/racoon/gnuc.h @@ -0,0 +1,44 @@ +/* $Id: gnuc.h,v 1.4 2004/11/18 15:14:44 ludvigm Exp $ */ + +/* Define __P() macro, if necessary */ +#undef __P +#ifndef __P +#if __STDC__ +#define __P(protos) protos +#else +#define __P(protos) () +#endif +#endif + +/* inline foo */ +#ifdef __GNUC__ +#define inline __inline +#else +#define inline +#endif + +/* + * Handle new and old "dead" routine prototypes + * + * For example: + * + * __dead void foo(void) __attribute__((volatile)); + * + */ +#ifdef __GNUC__ +#ifndef __dead +#define __dead volatile +#endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +#ifndef __attribute__ +#define __attribute__(args) +#endif +#endif +#else +#ifndef __dead +#define __dead +#endif +#ifndef __attribute__ +#define __attribute__(args) +#endif +#endif diff --git a/ipsec-tools/racoon/grabmyaddr.c b/ipsec-tools/racoon/grabmyaddr.c new file mode 100644 index 0000000..98f2d4c --- /dev/null +++ b/ipsec-tools/racoon/grabmyaddr.c @@ -0,0 +1,824 @@ +/* $Id: grabmyaddr.c,v 1.23.4.2 2005/07/16 04:41:01 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) +#include +#include +#endif +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_GETIFADDRS +#include +#include +#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 +#include +#ifndef HAVE_GETIFADDRS +#define HAVE_GETIFADDRS +#define NEED_LINUX_GETIFADDRS +#endif +#endif + +#ifndef HAVE_GETIFADDRS +static unsigned int if_maxindex __P((void)); +#endif +#ifdef __APPLE__ +static struct myaddrs *find_myaddr __P((struct myaddrs *, struct sockaddr *, int)); +#else +static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *)); +#endif +static int suitable_ifaddr __P((const char *, const struct sockaddr *)); +#ifdef INET6 +static int suitable_ifaddr6 __P((const char *, const struct sockaddr *)); +#endif + +#ifdef NEED_LINUX_GETIFADDRS + +/* We could do this _much_ better. kame racoon in its current form + * will esentially die at frequent changes of address configuration. + */ + +struct ifaddrs +{ + struct ifaddrs *ifa_next; + char ifa_name[16]; + int ifa_ifindex; + struct sockaddr *ifa_addr; + struct sockaddr_storage ifa_addrbuf; +}; + +static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta,len); + } + return 0; +} + +static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq) +{ + char buf[8192]; + struct sockaddr_nl nladdr; + struct iovec iov = { buf, sizeof(buf) }; + struct ifaddrmsg *m; + struct rtattr * rta_tb[IFA_MAX+1]; + struct ifaddrs *I; + + while (1) { + int status; + struct nlmsghdr *h; + + struct msghdr msg = { + (void*)&nladdr, sizeof(nladdr), + &iov, 1, + NULL, 0, + 0 + }; + + status = recvmsg(fd, &msg, 0); + + if (status < 0) + continue; + + if (status == 0) + return; + + if (nladdr.nl_pid) /* Message not from kernel */ + continue; + + h = (struct nlmsghdr*)buf; + while (NLMSG_OK(h, status)) { + if (h->nlmsg_seq != seq) + goto skip_it; + + if (h->nlmsg_type == NLMSG_DONE) + return; + + if (h->nlmsg_type == NLMSG_ERROR) + return; + + if (h->nlmsg_type != RTM_NEWADDR) + goto skip_it; + + m = NLMSG_DATA(h); + + if (m->ifa_family != AF_INET && + m->ifa_family != AF_INET6) + goto skip_it; + + if (m->ifa_flags&IFA_F_TENTATIVE) + goto skip_it; + + memset(rta_tb, 0, sizeof(rta_tb)); + parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m))); + + if (rta_tb[IFA_LOCAL] == NULL) + rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; + if (rta_tb[IFA_LOCAL] == NULL) + goto skip_it; + + I = malloc(sizeof(struct ifaddrs)); + if (!I) + return; + memset(I, 0, sizeof(*I)); + + I->ifa_ifindex = m->ifa_index; + I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf; + I->ifa_addr->sa_family = m->ifa_family; + if (m->ifa_family == AF_INET) { + struct sockaddr_in *sin = (void*)I->ifa_addr; + memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4); + } else { + struct sockaddr_in6 *sin = (void*)I->ifa_addr; + memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16); + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) + sin->sin6_scope_id = I->ifa_ifindex; + } + I->ifa_next = *ifa; + *ifa = I; + +skip_it: + h = NLMSG_NEXT(h, status); + } + if (msg.msg_flags & MSG_TRUNC) + continue; + } + return; +} + +static int getifaddrs(struct ifaddrs **ifa0) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct sockaddr_nl nladdr; + static __u32 seq; + struct ifaddrs *i; + int fd; + + fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) + return -1; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = RTM_GETADDR; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = ++seq; + req.g.rtgen_family = AF_UNSPEC; + + if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) { + close(fd); + return -1; + } + + *ifa0 = NULL; + + recvaddrs(fd, ifa0, seq); + + close(fd); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + for (i=*ifa0; i; i = i->ifa_next) { + struct ifreq ifr; + ifr.ifr_ifindex = i->ifa_ifindex; + ioctl(fd, SIOCGIFNAME, (void*)&ifr); + memcpy(i->ifa_name, ifr.ifr_name, 16); + } + close(fd); + + return 0; +} + +static void freeifaddrs(struct ifaddrs *ifa0) +{ + struct ifaddrs *i; + + while (ifa0) { + i = ifa0; + ifa0 = i->ifa_next; + free(i); + } +} + +#endif + +#ifndef HAVE_GETIFADDRS +static unsigned int +if_maxindex() +{ + struct if_nameindex *p, *p0; + unsigned int max = 0; + + p0 = if_nameindex(); + for (p = p0; p && p->if_index && p->if_name; p++) { + if (max < p->if_index) + max = p->if_index; + } + if_freenameindex(p0); + return max; +} +#endif + + +void +clear_myaddr() +{ + struct myaddrs *p, *next; + + for (p = lcconf->myaddrs; p; p = next) { + next = p->next; + + if (p->addr) + racoon_free(p->addr); + racoon_free(p); + } + + lcconf->myaddrs = NULL; + +} + + +static struct myaddrs * +find_myaddr(db, addr, udp_encap) + struct myaddrs *db; + struct sockaddr *addr; + int udp_encap; +{ + struct myaddrs *q; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + + if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0, + NI_NUMERICHOST | niflags) != 0) + return NULL; + + for (q = db; q; q = q->next) { + if (!q->addr) + continue; + if (q->udp_encap && !udp_encap + || !q->udp_encap && udp_encap) + continue; + if (addr->sa_family != q->addr->sa_family) + continue; + if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2), + NULL, 0, NI_NUMERICHOST | niflags) != 0) + return NULL; + if (strcmp(h1, h2) == 0) + return q; + } + + return NULL; +} + + +// modified to avoid closing and opening sockets for +// all interfaces each time an interface change occurs. +// on return: addrcount = zero indicates address no longer used +// sock = -1 indicates a new address - no socket opened yet. +void +grab_myaddrs() +{ +#ifdef HAVE_GETIFADDRS + struct myaddrs *p, *q; + struct ifaddrs *ifa0, *ifap; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + char addr1[NI_MAXHOST]; + + if (getifaddrs(&ifa0)) { + plog(LLV_ERROR2, LOCATION, NULL, + "getifaddrs failed: %s\n", strerror(errno)); + exit(1); + /*NOTREACHED*/ + } + + // clear the in_use flag for each address in the list + for (p = lcconf->myaddrs; p; p = p->next) + p->in_use = 0; + + for (ifap = ifa0; ifap; ifap = ifap->ifa_next) { + + if (ifap->ifa_addr->sa_family != AF_INET +#ifdef INET6 + && ifap->ifa_addr->sa_family != AF_INET6 +#endif + ) + continue; + + if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "unsuitable address: %s %s\n", + ifap->ifa_name, + saddrwop2str(ifap->ifa_addr)); + continue; + } + + p = find_myaddr(lcconf->myaddrs, ifap->ifa_addr, 0); + if (p) { + p->in_use = 1; +#ifdef ENABLE_NATT + q = find_myaddr(lcconf->myaddrs, ifap->ifa_addr, 1); + if (q) + q->in_use = 1; +#endif + } else { + p = newmyaddr(); + if (p == NULL) { + plog(LLV_ERROR2, LOCATION, NULL, + "unable to allocate space for addr.\n"); + exit(1); + /*NOTREACHED*/ + } + p->addr = dupsaddr(ifap->ifa_addr); + if (p->addr == NULL) { + plog(LLV_ERROR2, LOCATION, NULL, + "unable to duplicate addr.\n"); + exit(1); + /*NOTREACHED*/ + } + p->sock = -1; + p->in_use = 1; + + if (getnameinfo(p->addr, p->addr->sa_len, + addr1, sizeof(addr1), + NULL, 0, + NI_NUMERICHOST | niflags)) + strlcpy(addr1, "(invalid)", sizeof(addr1)); + plog(LLV_DEBUG, LOCATION, NULL, + "my interface: %s (%s)\n", + addr1, ifap->ifa_name); + + p->next = lcconf->myaddrs; + lcconf->myaddrs = p; + +#ifdef ENABLE_NATT + if (natt_enabled_in_rmconf ()) { + q = dupmyaddr(p); + if (q == NULL) { + plog(LLV_ERROR2, LOCATION, NULL, + "unable to allocate space for natt addr.\n"); + exit(1); + } + q->udp_encap = 1; + } +#endif + + } + } + + freeifaddrs(ifa0); + + +#else /*!HAVE_GETIFADDRS*/ +#error "NOT SUPPORTED" +#endif /*HAVE_GETIFADDRS*/ +} + + +/* + * check the interface is suitable or not + */ +static int +suitable_ifaddr(ifname, ifaddr) + const char *ifname; + const struct sockaddr *ifaddr; +{ +#ifdef ENABLE_HYBRID + /* Exclude any address we got through ISAKMP mode config */ + if (exclude_cfg_addr(ifaddr) == 0) + return 0; +#endif + switch(ifaddr->sa_family) { + case AF_INET: + return 1; +#ifdef INET6 + case AF_INET6: + return suitable_ifaddr6(ifname, ifaddr); +#endif + default: + return 0; + } + /*NOTREACHED*/ +} + +#ifdef INET6 +static int +suitable_ifaddr6(ifname, ifaddr) + const char *ifname; + const struct sockaddr *ifaddr; +{ +#ifndef __linux__ + struct in6_ifreq ifr6; + int s; +#endif + + if (ifaddr->sa_family != AF_INET6) + return 0; + +#ifndef __linux__ + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(SOCK_DGRAM) failed:%s\n", strerror(errno)); + return 0; + } + + memset(&ifr6, 0, sizeof(ifr6)); + strncpy(ifr6.ifr_name, ifname, strlen(ifname)); + + ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr; + + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno)); + close(s); + return 0; + } + + close(s); + + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED + || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED + || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) + return 0; +#endif + + /* suitable */ + return 1; +} +#endif + +int +update_myaddrs() +{ +#ifdef __linux__ + char msg[BUFSIZ]; + int len; + struct nlmsghdr *h = (void*)msg; + len = read(lcconf->rtsock, msg, sizeof(msg)); + if (len < 0) + return errno == ENOBUFS; + if (len < sizeof(*h)) + return 0; + if (h->nlmsg_pid) /* not from kernel! */ + return 0; + if (h->nlmsg_type == RTM_NEWLINK) + return 0; + plog(LLV_DEBUG, LOCATION, NULL, + "netlink signals update interface address list\n"); + return 1; +#else + char msg[BUFSIZ]; + int len; + struct rt_msghdr *rtm; + + len = read(lcconf->rtsock, msg, sizeof(msg)); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "read(PF_ROUTE) failed: %s\n", + strerror(errno)); + return 0; + } + rtm = (struct rt_msghdr *)msg; + if (len < rtm->rtm_msglen) { + plog(LLV_ERROR, LOCATION, NULL, + "read(PF_ROUTE) short read\n"); + return 0; + } + if (rtm->rtm_version != RTM_VERSION) { + plog(LLV_ERROR, LOCATION, NULL, + "routing socket version mismatch\n"); + close(lcconf->rtsock); + lcconf->rtsock = -1; + return 0; + } + switch (rtm->rtm_type) { + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_DELETE: + case RTM_IFINFO: + break; + case RTM_MISS: + /* ignore this message silently */ + return 0; + default: + plog(LLV_DEBUG, LOCATION, NULL, + "msg %d not interesting\n", rtm->rtm_type); + return 0; + } + /* XXX more filters here? */ + + plog(LLV_DEBUG, LOCATION, NULL, + "caught rtm:%d, need update interface address list\n", + rtm->rtm_type); + + return 1; +#endif /* __linux__ */ +} + +/* + * initialize default port for ISAKMP to send, if no "listen" + * directive is specified in config file. + * + * DO NOT listen to wildcard addresses. if you receive packets to + * wildcard address, you'll be in trouble (DoS attack possible by + * broadcast storm). + */ +int +autoconf_myaddrsport() +{ + struct myaddrs *p; + int n; + + plog(LLV_DEBUG, LOCATION, NULL, + "configuring default isakmp port.\n"); + + for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) { + set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp); + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d addrs are configured successfully\n", n); + + return 0; +} + +/* + * get a port number to which racoon binded. + * NOTE: network byte order returned. + */ +u_short +getmyaddrsport(local) + struct sockaddr *local; +{ + struct myaddrs *p, *bestmatch = NULL; + u_short bestmatch_port = PORT_ISAKMP; + + /* get a relative port */ + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + if (!cmpsaddrwop(local, p->addr)) { + if (! bestmatch) { + bestmatch = p; + continue; + } + + switch (p->addr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) { + bestmatch = p; + bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port; + break; + } + break; +#ifdef INET6 + case AF_INET6: + if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) { + bestmatch = p; + bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port; + break; + } + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported AF %d\n", p->addr->sa_family); + continue; + } + } + } + + return htons(bestmatch_port); +} + +struct myaddrs * +newmyaddr() +{ + struct myaddrs *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer for myaddrs.\n"); + return NULL; + } + + new->next = NULL; + new->addr = NULL; + + return new; +} + +struct myaddrs * +dupmyaddr(struct myaddrs *old) +{ + struct myaddrs *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer for myaddrs.\n"); + return NULL; + } + + /* Copy the whole structure and set the differences. */ + memcpy (new, old, sizeof (*new)); + new->addr = dupsaddr (old->addr); + if (new->addr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer for duplicate addr.\n"); + racoon_free(new); + return NULL; + } + new->next = old->next; + old->next = new; + + return new; +} + +void +insmyaddr(new, head) + struct myaddrs *new; + struct myaddrs **head; +{ + new->next = *head; + *head = new; +} + +void +delmyaddr(myaddr) + struct myaddrs *myaddr; +{ + if (myaddr->addr) + racoon_free(myaddr->addr); + racoon_free(myaddr); +} + +int +initmyaddr() +{ + /* initialize routing socket */ + lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); + if (lcconf->rtsock < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(PF_ROUTE) failed: %s", + strerror(errno)); + return -1; + } + +#ifdef __linux__ + { + struct sockaddr_nl nl; + u_int addr_len; + + memset(&nl, 0, sizeof(nl)); + nl.nl_family = AF_NETLINK; + nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK; + + if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind(PF_NETLINK) failed: %s\n", + strerror(errno)); + return -1; + } + addr_len = sizeof(nl); + if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname(PF_NETLINK) failed: %s\n", + strerror(errno)); + return -1; + } + } +#endif + + if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) { + grab_myaddrs(); + + if (autoconf_myaddrsport() < 0) + return -1; + } + + return 0; +} + +/* select the socket to be sent */ +/* should implement other method. */ +int +getsockmyaddr(my) + struct sockaddr *my; +{ + struct myaddrs *p, *lastresort = NULL; +#if defined(INET6) && defined(__linux__) + struct myaddrs *match_wo_scope_id = NULL; + int check_wo_scope_id = (my->sa_family == AF_INET6) && + IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr); +#endif + + for (p = lcconf->myaddrs; p; p = p->next) { + if (p->addr == NULL) + continue; + if (my->sa_family == p->addr->sa_family) { + lastresort = p; + } else continue; + if (sysdep_sa_len(my) == sysdep_sa_len(p->addr) + && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) { + break; + } +#if defined(INET6) && defined(__linux__) + if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) && + /* XXX: this depends on sin6_scope_id to be last + * item in struct sockaddr_in6 */ + memcmp(my, p->addr, + sysdep_sa_len(my) - sizeof(uint32_t)) == 0) { + match_wo_scope_id = p; + } +#endif + } +#if defined(INET6) && defined(__linux__) + if (!p) + p = match_wo_scope_id; +#endif + if (!p) + p = lastresort; + if (!p) { + plog(LLV_ERROR, LOCATION, NULL, + "no socket matches address family %d\n", + my->sa_family); + return -1; + } + + return p->sock; +} diff --git a/ipsec-tools/racoon/grabmyaddr.h b/ipsec-tools/racoon/grabmyaddr.h new file mode 100644 index 0000000..a237cb5 --- /dev/null +++ b/ipsec-tools/racoon/grabmyaddr.h @@ -0,0 +1,57 @@ +/* $Id: grabmyaddr.h,v 1.5 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GRABMYADDR_H +#define _GRABMYADDR_H + +struct myaddrs { + struct myaddrs *next; + struct sockaddr *addr; + int sock; + int udp_encap; +#ifdef __APPLE__ + int in_use; +#endif +}; + +extern void clear_myaddr __P((void)); +extern void grab_myaddrs __P((void)); +extern int update_myaddrs __P((void)); +extern int autoconf_myaddrsport __P((void)); +extern u_short getmyaddrsport __P((struct sockaddr *)); +extern struct myaddrs *newmyaddr __P((void)); +extern struct myaddrs *dupmyaddr __P((struct myaddrs *)); +extern void insmyaddr __P((struct myaddrs *, struct myaddrs **)); +extern void delmyaddr __P((struct myaddrs *)); +extern int initmyaddr __P((void)); +extern int getsockmyaddr __P((struct sockaddr *)); + +#endif /* _GRABMYADDR_H */ diff --git a/ipsec-tools/racoon/gssapi.c b/ipsec-tools/racoon/gssapi.c new file mode 100644 index 0000000..0a11f83 --- /dev/null +++ b/ipsec-tools/racoon/gssapi.c @@ -0,0 +1,745 @@ +/* $KAME: gssapi.c,v 1.19 2001/04/03 15:51:55 thorpej Exp $ */ + +/* + * Copyright 2000 Wasabi Systems, Inc. + * All rights reserved. + * + * This software was written by Frank van der Linden of Wasabi Systems + * for Zembu Labs, Inc. http://www.zembu.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#ifdef HAVE_GSSAPI + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 diff --git a/ipsec-tools/racoon/gssapi.h b/ipsec-tools/racoon/gssapi.h new file mode 100644 index 0000000..8994281 --- /dev/null +++ b/ipsec-tools/racoon/gssapi.h @@ -0,0 +1,95 @@ +/* $Id: gssapi.h,v 1.5 2005/02/11 06:59:01 manubsd Exp $ */ + +/* + * Copyright 2000 Wasabi Systems, Inc. + * All rights reserved. + * + * This software was written by Frank van der Linden of Wasabi Systems + * for Zembu Labs, Inc. http://www.zembu.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GSSAPI_H__ +#define __GSSAPI_H__ + +#ifdef __FreeBSD__ +#include "/usr/include/gssapi.h" +#else +#include +#endif + +#define GSSAPI_DEF_NAME "host" + +struct ph1handle; +struct isakmpsa; + +struct gssapi_ph1_state { + int gsscnt; /* # of token we're working on */ + int gsscnt_p; /* # of token we're working on */ + + gss_buffer_desc gss[3]; /* gss-api tokens. */ + /* NOTE: XXX this restricts the max # */ + /* to 3. More should never happen */ + + gss_buffer_desc gss_p[3]; + + gss_ctx_id_t gss_context; /* context for gss_init_sec_context */ + + OM_uint32 gss_status; /* retval from gss_init_sec_context */ + gss_cred_id_t gss_cred; /* acquired credentials */ + + int gss_flags; +#define GSSFLAG_ID_SENT 0x0001 +#define GSSFLAG_ID_RCVD 0x0001 +}; + +#define gssapi_get_state(ph) \ + ((struct gssapi_ph1_state *)((ph)->gssapi_state)) + +#define gssapi_set_state(ph, st) \ + (ph)->gssapi_state = (st) + +#define gssapi_more_tokens(ph) \ + ((gssapi_get_state(ph)->gss_status & GSS_S_CONTINUE_NEEDED) != 0) + +int gssapi_get_itoken __P((struct ph1handle *, int *)); +int gssapi_get_rtoken __P((struct ph1handle *, int *)); +int gssapi_save_received_token __P((struct ph1handle *, vchar_t *)); +int gssapi_get_token_to_send __P((struct ph1handle *, vchar_t **)); +int gssapi_get_itokens __P((struct ph1handle *, vchar_t **)); +int gssapi_get_rtokens __P((struct ph1handle *, vchar_t **)); +vchar_t *gssapi_wraphash __P((struct ph1handle *)); +vchar_t *gssapi_unwraphash __P((struct ph1handle *)); +void gssapi_set_id_sent __P((struct ph1handle *)); +int gssapi_id_sent __P((struct ph1handle *)); +void gssapi_set_id_rcvd __P((struct ph1handle *)); +int gssapi_id_rcvd __P((struct ph1handle *)); +void gssapi_free_state __P((struct ph1handle *)); +vchar_t *gssapi_get_id __P((struct ph1handle *)); +vchar_t *gssapi_get_default_gss_id __P((void)); + +#endif /* __GSSAPI_H__ */ + diff --git a/ipsec-tools/racoon/handler.c b/ipsec-tools/racoon/handler.c new file mode 100644 index 0000000..4082bb5 --- /dev/null +++ b/ipsec-tools/racoon/handler.c @@ -0,0 +1,1040 @@ +/* $Id: handler.c,v 1.13.4.4 2005/07/14 12:00:36 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "grabmyaddr.h" +#include "algorithm.h" +#include "crypto_openssl.h" +#include "policy.h" +#include "proposal.h" +#include "isakmp_var.h" +#include "evt.h" +#include "isakmp.h" +#ifdef ENABLE_HYBRID +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" +#endif +#include "isakmp_inf.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "handler.h" +#include "gcmalloc.h" +#include "nattraversal.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +static LIST_HEAD(_ph1tree_, ph1handle) ph1tree; +static LIST_HEAD(_ph2tree_, ph2handle) ph2tree; +static LIST_HEAD(_ctdtree_, contacted) ctdtree; +static LIST_HEAD(_rcptree_, recvdpkt) rcptree; + +static void del_recvdpkt __P((struct recvdpkt *)); +static void rem_recvdpkt __P((struct recvdpkt *)); +static void sweep_recvdpkt __P((void *)); + +/* + * functions about management of the isakmp status table + */ +/* %%% management phase 1 handler */ +/* + * search for isakmpsa handler with isakmp index. + */ + +extern caddr_t val2str(const char *, size_t); + +struct ph1handle * +getph1byindex(index) + isakmp_index *index; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (memcmp(&p->index, index, sizeof(*index)) == 0) + return p; + } + + return NULL; +} + +/* + * search for isakmp handler by i_ck in index. + */ +struct ph1handle * +getph1byindex0(index) + isakmp_index *index; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (memcmp(&p->index, index, sizeof(cookie_t)) == 0) + return p; + } + + return NULL; +} + +/* + * search for isakmpsa handler by source and remote address. + * don't use port number to search because this function search + * with phase 2's destinaion. + */ +struct ph1handle * +getph1byaddr(local, remote) + struct sockaddr *local, *remote; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (CMPSADDR(local, p->local) == 0 + && CMPSADDR(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +struct ph1handle * +getph1byaddrwop(local, remote) + struct sockaddr *local, *remote; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (cmpsaddrwop(local, p->local) == 0 + && cmpsaddrwop(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +/* + * search for isakmpsa handler by remote address. + * don't use port number to search because this function search + * with phase 2's destinaion. + */ +struct ph1handle * +getph1bydstaddrwop(remote) + struct sockaddr *remote; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (cmpsaddrwop(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +/* + * dump isakmp-sa + */ +vchar_t * +dumpph1() +{ + struct ph1handle *iph1; + struct ph1dump *pd; + int cnt = 0; + vchar_t *buf; + + /* get length of buffer */ + LIST_FOREACH(iph1, &ph1tree, chain) + cnt++; + + buf = vmalloc(cnt * sizeof(struct ph1dump)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer\n"); + return NULL; + } + pd = (struct ph1dump *)buf->v; + + LIST_FOREACH(iph1, &ph1tree, chain) { + memcpy(&pd->index, &iph1->index, sizeof(iph1->index)); + pd->status = iph1->status; + pd->side = iph1->side; + memcpy(&pd->remote, iph1->remote, sysdep_sa_len(iph1->remote)); + memcpy(&pd->local, iph1->local, sysdep_sa_len(iph1->local)); + pd->version = iph1->version; + pd->etype = iph1->etype; + pd->created = iph1->created; + pd->ph2cnt = iph1->ph2cnt; + pd++; + } + + return buf; +} + +/* + * create new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +struct ph1handle * +newph1() +{ + struct ph1handle *iph1; + + /* create new iph1 */ + iph1 = racoon_calloc(1, sizeof(*iph1)); + if (iph1 == NULL) + return NULL; + + iph1->status = PHASE1ST_SPAWN; + +#ifdef ENABLE_DPD + iph1->dpd_support = 0; + iph1->dpd_lastack = 0; + iph1->dpd_seq = 0; + iph1->dpd_fails = 0; + iph1->dpd_r_u = NULL; +#endif + + return iph1; +} + +/* + * delete new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +void +delph1(iph1) + struct ph1handle *iph1; +{ + /* SA down shell script hook */ + if (iph1 != NULL) + script_hook(iph1, SCRIPT_PHASE1_DOWN); + + EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL); + +#ifdef ENABLE_NATT +#ifndef __APPLE__ + if (iph1->natt_flags & NAT_KA_QUEUED) + natt_keepalive_remove (iph1->local, iph1->remote); +#endif /* __APPLE__ */ + if (iph1->natt_options) { + racoon_free(iph1->natt_options); + iph1->natt_options = NULL; + } +#endif + +#ifdef ENABLE_DPD + if (iph1->dpd_r_u != NULL) + SCHED_KILL(iph1->dpd_r_u); +#endif + + if (iph1->remote) { + racoon_free(iph1->remote); + iph1->remote = NULL; + } + if (iph1->local) { + racoon_free(iph1->local); + iph1->local = NULL; + } + + if (iph1->approval) { + delisakmpsa(iph1->approval); + iph1->approval = NULL; + } + +#ifdef ENABLE_HYBRID + if (iph1->mode_cfg) + isakmp_cfg_rmstate(iph1); +#endif + + VPTRINIT(iph1->authstr); + + sched_scrub_param(iph1); + iph1->sce = NULL; + iph1->scr = NULL; + + VPTRINIT(iph1->sendbuf); + + VPTRINIT(iph1->dhpriv); + VPTRINIT(iph1->dhpub); + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->dhgxy); + VPTRINIT(iph1->nonce); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->skeyid); + VPTRINIT(iph1->skeyid_d); + VPTRINIT(iph1->skeyid_a); + VPTRINIT(iph1->skeyid_e); + VPTRINIT(iph1->key); + VPTRINIT(iph1->hash); + VPTRINIT(iph1->sig); + VPTRINIT(iph1->sig_p); + oakley_delcert(iph1->cert); + iph1->cert = NULL; + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + VPTRINIT(iph1->id); + VPTRINIT(iph1->id_p); + + if (iph1->ivm) { + oakley_delivm(iph1->ivm); + iph1->ivm = NULL; + } + + VPTRINIT(iph1->sa); + VPTRINIT(iph1->sa_ret); + +#ifdef HAVE_GSSAPI + VPTRINIT(iph1->gi_i); + VPTRINIT(iph1->gi_r); + + gssapi_free_state(iph1); +#endif + + racoon_free(iph1); +} + +/* + * create new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +int +insph1(iph1) + struct ph1handle *iph1; +{ + /* validity check */ + if (iph1->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid isakmp SA handler. no remote address.\n"); + return -1; + } + LIST_INSERT_HEAD(&ph1tree, iph1, chain); + + return 0; +} + +void +remph1(iph1) + struct ph1handle *iph1; +{ + LIST_REMOVE(iph1, chain); +} + +/* + * flush isakmp-sa + */ +void +flushph1() +{ + struct ph1handle *p, *next; + + for (p = LIST_FIRST(&ph1tree); p; p = next) { + next = LIST_NEXT(p, chain); + + /* send delete information */ + if (p->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(p); + + remph1(p); + delph1(p); + } +} + +void +initph1tree() +{ + LIST_INIT(&ph1tree); +} + +/* %%% management phase 2 handler */ +/* + * search ph2handle with policy id. + */ +struct ph2handle * +getph2byspid(spid) + u_int32_t spid; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + /* + * there are ph2handle independent on policy + * such like informational exchange. + */ + if (p->spid == spid) + return p; + } + + return NULL; +} + +/* + * search ph2handle with sequence number. + */ +struct ph2handle * +getph2byseq(seq) + u_int32_t seq; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (p->seq == seq) + return p; + } + + return NULL; +} + +/* + * search ph2handle with message id. + */ +struct ph2handle * +getph2bymsgid(iph1, msgid) + struct ph1handle *iph1; + u_int32_t msgid; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (p->msgid == msgid) + return p; + } + + return NULL; +} + +struct ph2handle * +getph2byid(src, dst, spid) + struct sockaddr *src, *dst; + u_int32_t spid; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (spid == p->spid && + CMPSADDR(src, p->src) == 0 && + CMPSADDR(dst, p->dst) == 0) + return p; + } + + return NULL; +} + +struct ph2handle * +getph2bysaddr(src, dst) + struct sockaddr *src, *dst; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (cmpsaddrstrict(src, p->src) == 0 && + cmpsaddrstrict(dst, p->dst) == 0) + return p; + } + + return NULL; +} + +/* + * call by pk_recvexpire(). + */ +struct ph2handle * +getph2bysaidx(src, dst, proto_id, spi) + struct sockaddr *src, *dst; + u_int proto_id; + u_int32_t spi; +{ + struct ph2handle *iph2; + struct saproto *pr; + + LIST_FOREACH(iph2, &ph2tree, chain) { + if (iph2->proposal == NULL && iph2->approval == NULL) + continue; + if (iph2->approval != NULL) { + for (pr = iph2->approval->head; pr != NULL; + pr = pr->next) { + if (proto_id != pr->proto_id) + break; + if (spi == pr->spi || spi == pr->spi_p) + return iph2; + } + } else if (iph2->proposal != NULL) { + for (pr = iph2->proposal->head; pr != NULL; + pr = pr->next) { + if (proto_id != pr->proto_id) + break; + if (spi == pr->spi) + return iph2; + } + } + } + + return NULL; +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +struct ph2handle * +newph2() +{ + struct ph2handle *iph2 = NULL; + + /* create new iph2 */ + iph2 = racoon_calloc(1, sizeof(*iph2)); + if (iph2 == NULL) + return NULL; + + iph2->status = PHASE1ST_SPAWN; + + return iph2; +} + +/* + * initialize ph2handle + * NOTE: don't initialize src/dst. + * SPI in the proposal is cleared. + */ +void +initph2(iph2) + struct ph2handle *iph2; +{ + sched_scrub_param(iph2); + iph2->sce = NULL; + iph2->scr = NULL; + + VPTRINIT(iph2->sendbuf); + VPTRINIT(iph2->msg1); + + /* clear spi, keep variables in the proposal */ + if (iph2->proposal) { + struct saproto *pr; + for (pr = iph2->proposal->head; pr != NULL; pr = pr->next) + pr->spi = 0; + } + + /* clear approval */ + if (iph2->approval) { + flushsaprop(iph2->approval); + iph2->approval = NULL; + } + + /* clear the generated policy */ + if (iph2->spidx_gen) { + delsp_bothdir((struct policyindex *)iph2->spidx_gen); + racoon_free(iph2->spidx_gen); + iph2->spidx_gen = NULL; + } + + if (iph2->pfsgrp) { + oakley_dhgrp_free(iph2->pfsgrp); + iph2->pfsgrp = NULL; + } + + VPTRINIT(iph2->dhpriv); + VPTRINIT(iph2->dhpub); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->dhgxy); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + VPTRINIT(iph2->nonce); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->sa); + VPTRINIT(iph2->sa_ret); + + if (iph2->ivm) { + oakley_delivm(iph2->ivm); + iph2->ivm = NULL; + } +} + +/* + * delete new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +void +delph2(iph2) + struct ph2handle *iph2; +{ + initph2(iph2); + + if (iph2->src) { + racoon_free(iph2->src); + iph2->src = NULL; + } + if (iph2->dst) { + racoon_free(iph2->dst); + iph2->dst = NULL; + } + if (iph2->src_id) { + racoon_free(iph2->src_id); + iph2->src_id = NULL; + } + if (iph2->dst_id) { + racoon_free(iph2->dst_id); + iph2->dst_id = NULL; + } + + if (iph2->proposal) { + flushsaprop(iph2->proposal); + iph2->proposal = NULL; + } + + racoon_free(iph2); +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +int +insph2(iph2) + struct ph2handle *iph2; +{ + LIST_INSERT_HEAD(&ph2tree, iph2, chain); + + return 0; +} + +void +remph2(iph2) + struct ph2handle *iph2; +{ + LIST_REMOVE(iph2, chain); +} + +void +initph2tree() +{ + LIST_INIT(&ph2tree); +} + +void +flushph2() +{ + struct ph2handle *p, *next; + + for (p = LIST_FIRST(&ph2tree); p; p = next) { + next = LIST_NEXT(p, chain); + + /* send delete information */ + if (p->status == PHASE2ST_ESTABLISHED) + isakmp_info_send_d2(p); + + delete_spd(p); + unbindph12(p); + remph2(p); + delph2(p); + } +} + +/* + * Delete all Phase 2 handlers for this src/dst/proto. This + * is used during INITIAL-CONTACT processing (so no need to + * send a message to the peer). + */ +void +deleteallph2(src, dst, proto_id) + struct sockaddr *src, *dst; + u_int proto_id; +{ + struct ph2handle *iph2, *next; + struct saproto *pr; + + for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) { + next = LIST_NEXT(iph2, chain); + if (iph2->proposal == NULL && iph2->approval == NULL) + continue; + if (iph2->approval != NULL) { + for (pr = iph2->approval->head; pr != NULL; + pr = pr->next) { + if (proto_id == pr->proto_id) + goto zap_it; + } + } else if (iph2->proposal != NULL) { + for (pr = iph2->proposal->head; pr != NULL; + pr = pr->next) { + if (proto_id == pr->proto_id) + goto zap_it; + } + } + continue; + zap_it: + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } +} + +/* %%% */ +void +bindph12(iph1, iph2) + struct ph1handle *iph1; + struct ph2handle *iph2; +{ + iph2->ph1 = iph1; + LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind); +} + +void +unbindph12(iph2) + struct ph2handle *iph2; +{ + if (iph2->ph1 != NULL) { + iph2->ph1 = NULL; + LIST_REMOVE(iph2, ph1bind); + } +} + +/* %%% management contacted list */ +/* + * search contacted list. + */ +struct contacted * +getcontacted(remote) + struct sockaddr *remote; +{ + struct contacted *p; + + LIST_FOREACH(p, &ctdtree, chain) { + if (cmpsaddrstrict(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +int +inscontacted(remote) + struct sockaddr *remote; +{ + struct contacted *new; + + /* create new iph2 */ + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return -1; + + new->remote = dupsaddr(remote); + + LIST_INSERT_HEAD(&ctdtree, new, chain); + + return 0; +} + + +void +clear_contacted() +{ + struct contacted *c, *next; + + for (c = LIST_FIRST(&ctdtree); c; c = next) { + next = LIST_NEXT(c, chain); + LIST_REMOVE(c, chain); + racoon_free(c->remote); + racoon_free(c); + } +} + +void +initctdtree() +{ + LIST_INIT(&ctdtree); +} + +/* + * check the response has been sent to the peer. when not, simply reply + * the buffered packet to the peer. + * OUT: + * 0: the packet is received at the first time. + * 1: the packet was processed before. + * 2: the packet was processed before, but the address mismatches. + * -1: error happened. + */ +int +check_recvdpkt(remote, local, rbuf) + struct sockaddr *remote, *local; + vchar_t *rbuf; +{ + vchar_t *hash; + struct recvdpkt *r; + time_t t; + int len, s; + + /* set current time */ + t = time(NULL); + + hash = eay_md5_one(rbuf); + if (!hash) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + return -1; + } + + LIST_FOREACH(r, &rcptree, chain) { + if (memcmp(hash->v, r->hash->v, r->hash->l) == 0) + break; + } + vfree(hash); + + /* this is the first time to receive the packet */ + if (r == NULL) + return 0; + + /* + * the packet was processed before, but the remote address mismatches. + */ + if (cmpsaddrstrict(remote, r->remote) != 0) + return 2; + + /* + * it should not check the local address because the packet + * may arrive at other interface. + */ + + /* check the previous time to send */ + if (t - r->time_send < 1) { + plog(LLV_WARNING, LOCATION, NULL, + "the packet retransmitted in a short time from %s\n", + saddr2str(remote)); + /*XXX should it be error ? */ + } + + /* select the socket to be sent */ + s = getsockmyaddr(r->local); + if (s == -1) + return -1; + + /* resend the packet if needed */ + len = sendfromto(s, r->sendbuf->v, r->sendbuf->l, + r->local, r->remote, lcconf->count_persend); + if (len == -1) { + plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); + return -1; + } + + /* check the retry counter */ + r->retry_counter--; + if (r->retry_counter <= 0) { + rem_recvdpkt(r); + del_recvdpkt(r); + plog(LLV_DEBUG, LOCATION, NULL, + "deleted the retransmission packet to %s.\n", + saddr2str(remote)); + } else + r->time_send = t; + + return 1; +} + +/* + * adding a hash of received packet into the received list. + */ +int +add_recvdpkt(remote, local, sbuf, rbuf) + struct sockaddr *remote, *local; + vchar_t *sbuf, *rbuf; +{ + struct recvdpkt *new = NULL; + + if (lcconf->retry_counter == 0) { + /* no need to add it */ + return 0; + } + + new = racoon_calloc(1, sizeof(*new)); + if (!new) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + return -1; + } + + new->hash = eay_md5_one(rbuf); + if (!new->hash) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->remote = dupsaddr(remote); + if (new->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->local = dupsaddr(local); + if (new->local == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->sendbuf = vdup(sbuf); + if (new->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + + new->retry_counter = lcconf->retry_counter; + new->time_send = 0; + new->created = time(NULL); + + LIST_INSERT_HEAD(&rcptree, new, chain); + + return 0; +} + +void +del_recvdpkt(r) + struct recvdpkt *r; +{ + if (r->remote) + racoon_free(r->remote); + if (r->local) + racoon_free(r->local); + if (r->hash) + vfree(r->hash); + if (r->sendbuf) + vfree(r->sendbuf); + racoon_free(r); +} + +void +rem_recvdpkt(r) + struct recvdpkt *r; +{ + LIST_REMOVE(r, chain); +} + +void +sweep_recvdpkt(dummy) + void *dummy; +{ + struct recvdpkt *r, *next; + time_t t, lt; + + /* set current time */ + t = time(NULL); + + /* set the lifetime of the retransmission */ + lt = lcconf->retry_counter * lcconf->retry_interval; + + for (r = LIST_FIRST(&rcptree); r; r = next) { + next = LIST_NEXT(r, chain); + + if (t - r->created > lt) { + rem_recvdpkt(r); + del_recvdpkt(r); + } + } + + sched_new(lt, sweep_recvdpkt, NULL); +} + +void +clear_recvdpkt() +{ + struct recvdpkt *r, *next; + + for (r = LIST_FIRST(&rcptree); r; r = next) { + next = LIST_NEXT(r, chain); + rem_recvdpkt(r); + del_recvdpkt(r); + } +} + +void +init_recvdpkt() +{ + time_t lt = lcconf->retry_counter * lcconf->retry_interval; + + LIST_INIT(&rcptree); + + sched_new(lt, sweep_recvdpkt, NULL); +} + +#ifdef ENABLE_HYBRID +/* + * Returns 0 if the address was obtained by ISAKMP mode config, 1 otherwise + * This should be in isakmp_cfg.c but ph1tree being private, it must be there + */ +int +exclude_cfg_addr(addr) + const struct sockaddr *addr; +{ + struct ph1handle *p; + struct sockaddr_in *sin; + + LIST_FOREACH(p, &ph1tree, chain) { + if ((p->mode_cfg != NULL) && + (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) && + (addr->sa_family == AF_INET)) { + sin = (struct sockaddr_in *)addr; + if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr) + return 0; + } + } + + return 1; +} +#endif diff --git a/ipsec-tools/racoon/handler.h b/ipsec-tools/racoon/handler.h new file mode 100644 index 0000000..2d5bfb4 --- /dev/null +++ b/ipsec-tools/racoon/handler.h @@ -0,0 +1,473 @@ +/* $Id: handler.h,v 1.11.4.3 2005/05/07 17:26:05 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _HANDLER_H +#define _HANDLER_H + +#include +#include + +#include + +#include "isakmp_var.h" +#include "oakley.h" + +/* Phase 1 handler */ +/* + * main mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 2nd msg sent 2nd msg sent + * 6 2nd valid msg received 3rd valid msg received + * 7 3rd msg sent 3rd msg sent + * 8 3rd valid msg received (---) + * 9 SA established SA established + * + * aggressive mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 (---) (---) + * 6 (---) (---) + * 7 (---) (---) + * 8 (---) (---) + * 9 SA established SA established + * + * base mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 2nd msg sent (---) + * 6 (---) (---) + * 7 (---) (---) + * 8 (---) (---) + * 9 SA established SA established + */ +#define PHASE1ST_SPAWN 0 +#define PHASE1ST_START 1 +#define PHASE1ST_MSG1RECEIVED 2 +#define PHASE1ST_MSG1SENT 3 +#define PHASE1ST_MSG2RECEIVED 4 +#define PHASE1ST_MSG2SENT 5 +#define PHASE1ST_MSG3RECEIVED 6 +#define PHASE1ST_MSG3SENT 7 +#define PHASE1ST_MSG4RECEIVED 8 +#define PHASE1ST_ESTABLISHED 9 +#define PHASE1ST_EXPIRED 10 +#define PHASE1ST_MAX 11 + +/* About address semantics in each case. + * initiator(addr=I) responder(addr=R) + * src dst src dst + * (local) (remote) (local) (remote) + * phase 1 handler I R R I + * phase 2 handler I R R I + * getspi msg R I I R + * acquire msg I R + * ID payload I R I R + */ +#ifdef ENABLE_HYBRID +struct isakmp_cfg_state; +#endif +struct ph1handle { + isakmp_index index; + + int status; /* status of this SA */ + int side; /* INITIATOR or RESPONDER */ + + struct sockaddr *remote; /* remote address to negosiate ph1 */ + struct sockaddr *local; /* local address to negosiate ph1 */ + /* XXX copy from rmconf due to anonymous configuration. + * If anonymous will be forbidden, we do delete them. */ + + struct remoteconf *rmconf; /* pointer to remote configuration */ + + struct isakmpsa *approval; /* pointer to SA(s) approved. */ + vchar_t *authstr; /* place holder of string for auth. */ + /* for example pre-shared key */ + + u_int8_t version; /* ISAKMP version */ + u_int8_t etype; /* Exchange type actually for use */ + u_int8_t flags; /* Flags */ + u_int32_t msgid; /* message id */ + + struct ph1natt_options *natt_options; /* Selected NAT-T IKE version */ + u_int32_t natt_flags; /* NAT-T related flags */ +#ifdef ENABLE_FRAG + int frag; /* IKE phase 1 fragmentation */ + struct isakmp_frag_item *frag_chain; /* Received fragments */ +#endif + + struct sched *sce; /* schedule for expire */ + + struct sched *scr; /* schedule for resend */ + int retry_counter; /* for resend. */ + vchar_t *sendbuf; /* buffer for re-sending */ + + vchar_t *dhpriv; /* DH; private value */ + vchar_t *dhpub; /* DH; public value */ + vchar_t *dhpub_p; /* DH; partner's public value */ + vchar_t *dhgxy; /* DH; shared secret */ + vchar_t *nonce; /* nonce value */ + vchar_t *nonce_p; /* partner's nonce value */ + vchar_t *skeyid; /* SKEYID */ + vchar_t *skeyid_d; /* SKEYID_d */ + vchar_t *skeyid_a; /* SKEYID_a, i.e. hash */ + vchar_t *skeyid_e; /* SKEYID_e, i.e. encryption */ + vchar_t *key; /* cipher key */ + vchar_t *hash; /* HASH minus general header */ + vchar_t *sig; /* SIG minus general header */ + vchar_t *sig_p; /* peer's SIG minus general header */ + cert_t *cert; /* CERT minus general header */ + cert_t *cert_p; /* peer's CERT minus general header */ + cert_t *crl_p; /* peer's CRL minus general header */ + cert_t *cr_p; /* peer's CR not including general */ + RSA *rsa; /* my RSA key */ + RSA *rsa_p; /* peer's RSA key */ + struct genlist *rsa_candidates; /* possible candidates for peer's RSA key */ + vchar_t *id; /* ID minus gen header */ + vchar_t *id_p; /* partner's ID minus general header */ + /* i.e. strut ipsecdoi_id_b*. */ + struct isakmp_ivm *ivm; /* IVs */ + + vchar_t *sa; /* whole SA payload to send/to be sent*/ + /* to calculate HASH */ + /* NOT INCLUDING general header. */ + + vchar_t *sa_ret; /* SA payload to reply/to be replyed */ + /* NOT INCLUDING general header. */ + /* NOTE: Should be release after use. */ + +#ifdef HAVE_GSSAPI + void *gssapi_state; /* GSS-API specific state. */ + /* Allocated when needed */ + vchar_t *gi_i; /* optional initiator GSS id */ + vchar_t *gi_r; /* optional responder GSS id */ +#endif + + struct isakmp_pl_hash *pl_hash; /* pointer to hash payload */ + + time_t created; /* timestamp for establish */ +#ifdef ENABLE_STATS + struct timeval start; + struct timeval end; +#endif + + int dpd_support; /* Does remote supports DPD ? */ + time_t dpd_lastack; /* Last ack received */ + u_int16_t dpd_seq; /* DPD seq number to receive */ + u_int8_t dpd_fails; /* number of failures */ + struct sched *dpd_r_u; + + u_int32_t msgid2; /* msgid counter for Phase 2 */ + int ph2cnt; /* the number which is negotiated by this phase 1 */ + LIST_HEAD(_ph2ofph1_, ph2handle) ph2tree; + + LIST_ENTRY(ph1handle) chain; +#ifdef ENABLE_HYBRID + struct isakmp_cfg_state *mode_cfg; /* ISAKMP mode config state */ +#endif + +}; + +/* Phase 2 handler */ +/* allocated per a SA or SA bundles of a pair of peer's IP addresses. */ +/* + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 acquire msg get 1st valid msg received + * 3 getspi request sent getspi request sent + * 4 getspi done getspi done + * 5 1st msg sent 1st msg sent + * 6 1st valid msg received 2nd valid msg received + * 7 (commit bit) (commit bit) + * 8 SAs added SAs added + * 9 SAs established SAs established + * 10 SAs expired SAs expired + */ +#define PHASE2ST_SPAWN 0 +#define PHASE2ST_START 1 +#define PHASE2ST_STATUS2 2 +#define PHASE2ST_GETSPISENT 3 +#define PHASE2ST_GETSPIDONE 4 +#define PHASE2ST_MSG1SENT 5 +#define PHASE2ST_STATUS6 6 +#define PHASE2ST_COMMIT 7 +#define PHASE2ST_ADDSA 8 +#define PHASE2ST_ESTABLISHED 9 +#define PHASE2ST_EXPIRED 10 +#define PHASE2ST_MAX 11 + +struct ph2handle { + struct sockaddr *src; /* my address of SA. */ + struct sockaddr *dst; /* peer's address of SA. */ + + /* + * copy ip address from ID payloads when ID type is ip address. + * In other case, they must be null. + */ + struct sockaddr *src_id; + struct sockaddr *dst_id; + + u_int32_t spid; /* policy id by kernel */ + + int status; /* ipsec sa status */ + u_int8_t side; /* INITIATOR or RESPONDER */ + + struct sched *sce; /* schedule for expire */ + struct sched *scr; /* schedule for resend */ + int retry_counter; /* for resend. */ + vchar_t *sendbuf; /* buffer for re-sending */ + vchar_t *msg1; /* buffer for re-sending */ + /* used for responder's first message */ + + int retry_checkph1; /* counter to wait phase 1 finished. */ + /* NOTE: actually it's timer. */ + + u_int32_t seq; /* sequence number used by PF_KEY */ + /* + * NOTE: In responder side, we can't identify each SAs + * with same destination address for example, when + * socket based SA is required. So we set a identifier + * number to "seq", and sent kernel by pfkey. + */ + u_int8_t satype; /* satype in PF_KEY */ + /* + * saved satype in the original PF_KEY request from + * the kernel in order to reply a error. + */ + + u_int8_t flags; /* Flags for phase 2 */ + u_int32_t msgid; /* msgid for phase 2 */ + + struct sainfo *sainfo; /* place holder of sainfo */ + struct saprop *proposal; /* SA(s) proposal. */ + struct saprop *approval; /* SA(s) approved. */ + caddr_t spidx_gen; /* policy from peer's proposal */ + + struct dhgroup *pfsgrp; /* DH; prime number */ + vchar_t *dhpriv; /* DH; private value */ + vchar_t *dhpub; /* DH; public value */ + vchar_t *dhpub_p; /* DH; partner's public value */ + vchar_t *dhgxy; /* DH; shared secret */ + vchar_t *id; /* ID minus gen header */ + vchar_t *id_p; /* peer's ID minus general header */ + vchar_t *nonce; /* nonce value in phase 2 */ + vchar_t *nonce_p; /* partner's nonce value in phase 2 */ + + vchar_t *sa; /* whole SA payload to send/to be sent*/ + /* to calculate HASH */ + /* NOT INCLUDING general header. */ + + vchar_t *sa_ret; /* SA payload to reply/to be replyed */ + /* NOT INCLUDING general header. */ + /* NOTE: Should be release after use. */ + + struct isakmp_ivm *ivm; /* IVs */ + + int generated_spidx; /* mark handlers whith generated policy */ + +#ifdef ENABLE_STATS + struct timeval start; + struct timeval end; +#endif + struct ph1handle *ph1; /* back pointer to isakmp status */ + + LIST_ENTRY(ph2handle) chain; + LIST_ENTRY(ph2handle) ph1bind; /* chain to ph1handle */ +}; + +/* + * for handling initial contact. + */ +struct contacted { + struct sockaddr *remote; /* remote address to negotiate ph1 */ + LIST_ENTRY(contacted) chain; +}; + +/* + * for checking if a packet is retransmited. + */ +struct recvdpkt { + struct sockaddr *remote; /* the remote address */ + struct sockaddr *local; /* the local address */ + vchar_t *hash; /* hash of the received packet */ + vchar_t *sendbuf; /* buffer for the response */ + int retry_counter; /* how many times to send */ + time_t time_send; /* timestamp to send a packet */ + time_t created; /* timestamp to create a queue */ + + struct sched *scr; /* schedule for resend, may not used */ + + LIST_ENTRY(recvdpkt) chain; +}; + +/* for parsing ISAKMP header. */ +struct isakmp_parse_t { + u_char type; /* payload type of mine */ + int len; /* ntohs(ptr->len) */ + struct isakmp_gen *ptr; +}; + +/* + * for IV management. + * + * - normal case + * initiator responder + * ------------------------- -------------------------- + * initialize iv(A), ive(A). initialize iv(A), ive(A). + * encode by ive(A). + * save to iv(B). ---[packet(B)]--> save to ive(B). + * decode by iv(A). + * packet consistency. + * sync iv(B) with ive(B). + * check auth, integrity. + * encode by ive(B). + * save to ive(C). <--[packet(C)]--- save to iv(C). + * decoded by iv(B). + * : + * + * - In the case that a error is found while cipher processing, + * initiator responder + * ------------------------- -------------------------- + * initialize iv(A), ive(A). initialize iv(A), ive(A). + * encode by ive(A). + * save to iv(B). ---[packet(B)]--> save to ive(B). + * decode by iv(A). + * packet consistency. + * sync iv(B) with ive(B). + * check auth, integrity. + * error found. + * create notify. + * get ive2(X) from iv(B). + * encode by ive2(X). + * get iv2(X) from iv(B). <--[packet(Y)]--- save to iv2(Y). + * save to ive2(Y). + * decoded by iv2(X). + * : + * + * The reason why the responder synchronizes iv with ive after checking the + * packet consistency is that it is required to leave the IV for decoding + * packet. Because there is a potential of error while checking the packet + * consistency. Also the reason why that is before authentication and + * integirty check is that the IV for informational exchange has to be made + * by the IV which is after packet decoded and checking the packet consistency. + * Otherwise IV mismatched happens between the intitiator and the responder. + */ +struct isakmp_ivm { + vchar_t *iv; /* for decoding packet */ + /* if phase 1, it's for computing phase2 iv */ + vchar_t *ive; /* for encoding packet */ +}; + +/* for dumping */ +struct ph1dump { + isakmp_index index; + int status; + int side; + struct sockaddr_storage remote; + struct sockaddr_storage local; + u_int8_t version; + u_int8_t etype; + time_t created; + int ph2cnt; +}; + +struct sockaddr; +struct ph1handle; +struct ph2handle; +struct policyindex; + +extern struct ph1handle *getph1byindex __P((isakmp_index *)); +extern struct ph1handle *getph1byindex0 __P((isakmp_index *)); +extern struct ph1handle *getph1byaddr __P((struct sockaddr *, + struct sockaddr *)); +extern struct ph1handle *getph1byaddrwop __P((struct sockaddr *, + struct sockaddr *)); +extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *)); +extern vchar_t *dumpph1 __P((void)); +extern struct ph1handle *newph1 __P((void)); +extern void delph1 __P((struct ph1handle *)); +extern int insph1 __P((struct ph1handle *)); +extern void remph1 __P((struct ph1handle *)); +extern void flushph1 __P((void)); +extern void initph1tree __P((void)); + +extern struct ph2handle *getph2byspidx __P((struct policyindex *)); +extern struct ph2handle *getph2byspid __P((u_int32_t)); +extern struct ph2handle *getph2byseq __P((u_int32_t)); +extern struct ph2handle *getph2bysaddr __P((struct sockaddr *, + struct sockaddr *)); +extern struct ph2handle *getph2bymsgid __P((struct ph1handle *, u_int32_t)); +extern struct ph2handle *getph2byid __P((struct sockaddr *, + struct sockaddr *, u_int32_t)); +extern struct ph2handle *getph2bysaidx __P((struct sockaddr *, + struct sockaddr *, u_int, u_int32_t)); +extern struct ph2handle *newph2 __P((void)); +extern void initph2 __P((struct ph2handle *)); +extern void delph2 __P((struct ph2handle *)); +extern int insph2 __P((struct ph2handle *)); +extern void remph2 __P((struct ph2handle *)); +extern void flushph2 __P((void)); +extern void deleteallph2 __P((struct sockaddr *, struct sockaddr *, u_int)); +extern void initph2tree __P((void)); + +extern void bindph12 __P((struct ph1handle *, struct ph2handle *)); +extern void unbindph12 __P((struct ph2handle *)); + +extern struct contacted *getcontacted __P((struct sockaddr *)); +extern int inscontacted __P((struct sockaddr *)); +extern void clear_contacted __P((void)); +extern void initctdtree __P((void)); + +extern int check_recvdpkt __P((struct sockaddr *, + struct sockaddr *, vchar_t *)); +extern int add_recvdpkt __P((struct sockaddr *, struct sockaddr *, + vchar_t *, vchar_t *)); +extern void clear_recvdpkt __P((void)); +extern void init_recvdpkt __P((void)); + +#ifdef ENABLE_HYBRID +extern int exclude_cfg_addr __P((const struct sockaddr *)); +#endif + +#endif /* _HANDLER_H */ diff --git a/ipsec-tools/racoon/ipsec_doi.c b/ipsec-tools/racoon/ipsec_doi.c new file mode 100644 index 0000000..1854964 --- /dev/null +++ b/ipsec-tools/racoon/ipsec_doi.c @@ -0,0 +1,4348 @@ +/* $Id: ipsec_doi.c,v 1.26.2.16 2006/02/02 14:37:17 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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 +#include "gssapi.h" +#ifdef HAVE_ICONV_2ND_CONST +#define __iconv_const const +#else +#define __iconv_const +#endif +#endif + +int verbose_proposal_check = 1; + +static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **)); +static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *, + struct isakmpsa *, struct isakmpsa *, int)); +static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *)); +static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *)); +static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *)); +static struct prop_pair *get_ph2approval __P((struct ph2handle *, + struct prop_pair **)); +static struct prop_pair *get_ph2approvalx __P((struct ph2handle *, + struct prop_pair *)); +static void free_proppair0 __P((struct prop_pair *)); + +static int get_transform + __P((struct isakmp_pl_p *, struct prop_pair **, int *)); +static u_int32_t ipsecdoi_set_ld __P((vchar_t *)); + +static int check_doi __P((u_int32_t)); +static int check_situation __P((u_int32_t)); + +static int check_prot_main __P((int)); +static int check_prot_quick __P((int)); +static int (*check_protocol[]) __P((int)) = { + check_prot_main, /* IPSECDOI_TYPE_PH1 */ + check_prot_quick, /* IPSECDOI_TYPE_PH2 */ +}; + +static int check_spi_size __P((int, int)); + +static int check_trns_isakmp __P((int)); +static int check_trns_ah __P((int)); +static int check_trns_esp __P((int)); +static int check_trns_ipcomp __P((int)); +static int (*check_transform[]) __P((int)) = { + 0, + check_trns_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_trns_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_trns_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_trns_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int check_attr_isakmp __P((struct isakmp_pl_t *)); +static int check_attr_ah __P((struct isakmp_pl_t *)); +static int check_attr_esp __P((struct isakmp_pl_t *)); +static int check_attr_ipsec __P((int, struct isakmp_pl_t *)); +static int check_attr_ipcomp __P((struct isakmp_pl_t *)); +static int (*check_attributes[]) __P((struct isakmp_pl_t *)) = { + 0, + check_attr_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_attr_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_attr_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_attr_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int setph1prop __P((struct isakmpsa *, caddr_t)); +static int setph1trns __P((struct isakmpsa *, caddr_t)); +static int setph1attr __P((struct isakmpsa *, caddr_t)); +static vchar_t *setph2proposal0 __P((const struct ph2handle *, + const struct saprop *, const struct saproto *)); + +static vchar_t *getidval __P((int, vchar_t *)); + +#ifdef HAVE_GSSAPI +static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *, + struct isakmpsa *)); +#endif + +/*%%%*/ +/* + * check phase 1 SA payload. + * make new SA payload to be replyed not including general header. + * the pointer to one of isakmpsa in proposal is set into iph1->approval. + * OUT: + * positive: the pointer to new buffer of SA payload. + * network byte order. + * NULL : error occurd. + */ +int +ipsecdoi_checkph1proposal(sa, iph1) + vchar_t *sa; + struct ph1handle *iph1; +{ + vchar_t *newsa; /* new SA payload approved. */ + struct prop_pair **pair; + + /* get proposal pair */ + pair = get_proppair(sa, IPSECDOI_TYPE_PH1); + if (pair == NULL) + return -1; + + /* check and get one SA for use */ + newsa = get_ph1approval(iph1, pair); + + free_proppair(pair); + + if (newsa == NULL) + return -1; + + iph1->sa_ret = newsa; + + return 0; +} + +/* + * acceptable check for remote configuration. + * return a new SA payload to be reply to peer. + */ +static vchar_t * +get_ph1approval(iph1, pair) + struct ph1handle *iph1; + struct prop_pair **pair; +{ + vchar_t *newsa; + struct isakmpsa *sa, tsa; + struct prop_pair *s, *p; + int prophlen; + int i; + + if (iph1->approval) { + delisakmpsa(iph1->approval); + iph1->approval = NULL; + } + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = + sizeof(struct isakmp_pl_p) + s->prop->spi_size; + + /* compare proposal and select one */ + for (p = s; p; p = p->tnext) { + if ((sa = get_ph1approvalx(p, + iph1->rmconf->proposal, &tsa, + iph1->rmconf->pcheck_level)) != NULL) + goto found; + } + } + } + + /* + * if there is no suitable proposal, racoon complains about all of + * mismatched items in those proposal. + */ + if (verbose_proposal_check) { + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = sizeof(struct isakmp_pl_p) + + s->prop->spi_size; + for (p = s; p; p = p->tnext) { + print_ph1mismatched(p, + iph1->rmconf->proposal); + } + } + } + } + plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n"); + + return NULL; + +found: + plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n"); + + /* check DH group settings */ + if (sa->dhgrp) { + if (sa->dhgrp->prime && sa->dhgrp->gen1) { + /* it's ok */ + goto saok; + } + plog(LLV_WARNING, LOCATION, NULL, + "invalid DH parameter found, use default.\n"); + oakley_dhgrp_free(sa->dhgrp); + } + + if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) { + sa->dhgrp = NULL; + return NULL; + } + +saok: +#ifdef HAVE_GSSAPI + if (sa->gssid != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n", + sa->gssid->l, sa->gssid->v); + if (iph1-> side == INITIATOR) { + if (iph1->rmconf->proposal->gssid != NULL) + iph1->gi_i = vdup(iph1->rmconf->proposal->gssid); + if (tsa.gssid != NULL) + iph1->gi_r = vdup(tsa.gssid); + iph1->approval = fixup_initiator_sa(sa, &tsa); + } else { + if (tsa.gssid != NULL) { + iph1->gi_r = vdup(tsa.gssid); + iph1->gi_i = gssapi_get_id(iph1); + if (sa->gssid == NULL && iph1->gi_i != NULL) + sa->gssid = vdup(iph1->gi_i); + } + iph1->approval = sa; + } + if (iph1->gi_i != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "GIi is %.*s\n", + iph1->gi_i->l, iph1->gi_i->v); + if (iph1->gi_r != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n", + iph1->gi_r->l, iph1->gi_r->v); +#else + iph1->approval = sa; +#endif + + newsa = get_sabyproppair(p, iph1); + if (newsa == NULL) { + delisakmpsa(iph1->approval); + iph1->approval = NULL; + } + + return newsa; +} + +/* + * compare peer's single proposal and all of my proposal. + * and select one if suiatable. + * p : one of peer's proposal. + * proposal: my proposals. + */ +static struct isakmpsa * +get_ph1approvalx(p, proposal, sap, check_level) + struct prop_pair *p; + struct isakmpsa *proposal, *sap; + int check_level; +{ + struct isakmp_pl_p *prop = p->prop; + struct isakmp_pl_t *trns = p->trns; + struct isakmpsa sa, *s, *tsap; + int authmethod; + + plog(LLV_DEBUG, LOCATION, NULL, + "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n", + prop->p_no, s_ipsecdoi_proto(prop->proto_id), + prop->spi_size, prop->num_t); + + plog(LLV_DEBUG, LOCATION, NULL, + "trns#=%d, trns-id=%s\n", + trns->t_no, + s_ipsecdoi_trns(prop->proto_id, trns->t_id)); + + tsap = sap != NULL ? sap : &sa; + + memset(tsap, 0, sizeof(*tsap)); + if (t2isakmpsa(trns, tsap) < 0) + return NULL; + for (s = proposal; s != NULL; s = s->next) { +#ifdef ENABLE_HYBRID + authmethod = switch_authmethod(s->authmethod); +#else + authmethod = s->authmethod; +#endif + plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n"); + plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n", + (long)s->lifetime, (long)tsap->lifetime); + plog(LLV_DEBUG, LOCATION, NULL, "(lifebyte = %zu:%zu)\n", + s->lifebyte, tsap->lifebyte); + plog(LLV_DEBUG, LOCATION, NULL, "enctype = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + s->enctype), + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + tsap->enctype)); + plog(LLV_DEBUG, LOCATION, NULL, "(encklen = %d:%d)\n", + s->encklen, tsap->encklen); + plog(LLV_DEBUG, LOCATION, NULL, "hashtype = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + s->hashtype), + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + tsap->hashtype)); + plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + authmethod), + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + tsap->authmethod)); + plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + s->dh_group), + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + tsap->dh_group)); +#if 0 + /* XXX to be considered ? */ + if (tsap->lifebyte > s->lifebyte) ; +#endif + /* + * if responder side and peer's key length in proposal + * is bigger than mine, it might be accepted. + */ + if(tsap->enctype == s->enctype && + tsap->authmethod == authmethod && + tsap->hashtype == s->hashtype && + tsap->dh_group == s->dh_group && + tsap->encklen == s->encklen) { + switch(check_level) { + case PROP_CHECK_OBEY: + goto found; + break; + + case PROP_CHECK_STRICT: + if ((tsap->lifetime > s->lifetime) || + (tsap->lifebyte > s->lifebyte)) + continue; + goto found; + break; + + case PROP_CHECK_CLAIM: + if (tsap->lifetime < s->lifetime) + s->lifetime = tsap->lifetime; + if (tsap->lifebyte < s->lifebyte) + s->lifebyte = tsap->lifebyte; + goto found; + break; + + case PROP_CHECK_EXACT: + if ((tsap->lifetime != s->lifetime) || + (tsap->lifebyte != s->lifebyte)) + continue; + goto found; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected proposal_check value\n"); + continue; + break; + } + } + } + +found: + if (tsap->dhgrp != NULL) + oakley_dhgrp_free(tsap->dhgrp); + + if ((s = dupisakmpsa(s)) != NULL) { + switch(check_level) { + case PROP_CHECK_OBEY: + s->lifetime = tsap->lifetime; + s->lifebyte = tsap->lifebyte; + break; + + case PROP_CHECK_STRICT: + s->lifetime = tsap->lifetime; + s->lifebyte = tsap->lifebyte; + break; + + case PROP_CHECK_CLAIM: + if (tsap->lifetime < s->lifetime) + s->lifetime = tsap->lifetime; + if (tsap->lifebyte < s->lifebyte) + s->lifebyte = tsap->lifebyte; + break; + + default: + break; + } + } + + return s; +} + +/* + * print all of items in peer's proposal which are mismatched to my proposal. + * p : one of peer's proposal. + * proposal: my proposals. + */ +static void +print_ph1mismatched(p, proposal) + struct prop_pair *p; + struct isakmpsa *proposal; +{ + struct isakmpsa sa, *s; + + memset(&sa, 0, sizeof(sa)); + if (t2isakmpsa(p->trns, &sa) < 0) + return; + for (s = proposal; s ; s = s->next) { + if (sa.enctype != s->enctype) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected enctype: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + s->enctype), + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + sa.enctype)); + } + if (sa.authmethod != s->authmethod) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected authmethod: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + s->authmethod), + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + sa.authmethod)); + } + if (sa.hashtype != s->hashtype) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected hashtype: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + s->hashtype), + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + sa.hashtype)); + } + if (sa.dh_group != s->dh_group) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected dh_group: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + s->dh_group), + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + sa.dh_group)); + } + } + + if (sa.dhgrp != NULL) + oakley_dhgrp_free(sa.dhgrp); +} + +/* + * get ISAKMP data attributes + */ +static int +t2isakmpsa(trns, sa) + struct isakmp_pl_t *trns; + struct isakmpsa *sa; +{ + struct isakmp_data *d, *prev; + int flag, type; + int error = -1; + int life_t; + int keylen = 0; + vchar_t *val = NULL; + int len, tlen; + u_char *p; + + tlen = ntohs(trns->h.len) - sizeof(*trns); + prev = (struct isakmp_data *)NULL; + d = (struct isakmp_data *)(trns + 1); + + /* default */ + life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT; + sa->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT; + sa->lifebyte = 0; + sa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); + if (!sa->dhgrp) + goto err; + + while (tlen > 0) { + + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_oakley_attr(type), flag, + s_oakley_attr_v(type, ntohs(d->lorv))); + + /* get variable-sized item */ + switch (type) { + case OAKLEY_ATTR_GRP_PI: + case OAKLEY_ATTR_GRP_GEN_ONE: + case OAKLEY_ATTR_GRP_GEN_TWO: + case OAKLEY_ATTR_GRP_CURVE_A: + case OAKLEY_ATTR_GRP_CURVE_B: + case OAKLEY_ATTR_SA_LD: + case OAKLEY_ATTR_GRP_ORDER: + if (flag) { /*TV*/ + len = 2; + p = (u_char *)&d->lorv; + } else { /*TLV*/ + len = ntohs(d->lorv); + p = (u_char *)(d + 1); + } + val = vmalloc(len); + if (!val) + return -1; + memcpy(val->v, p, len); + break; + + default: + break; + } + + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + sa->enctype = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_HASH_ALG: + sa->hashtype = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_AUTH_METHOD: + sa->authmethod = ntohs(d->lorv); + break; + + case OAKLEY_ATTR_GRP_DESC: + sa->dh_group = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_GRP_TYPE: + { + int type = (int)ntohs(d->lorv); + if (type == OAKLEY_ATTR_GRP_TYPE_MODP) + sa->dhgrp->type = type; + else + return -1; + break; + } + case OAKLEY_ATTR_GRP_PI: + sa->dhgrp->prime = val; + break; + + case OAKLEY_ATTR_GRP_GEN_ONE: + vfree(val); + if (!flag) + sa->dhgrp->gen1 = ntohs(d->lorv); + else { + int len = ntohs(d->lorv); + sa->dhgrp->gen1 = 0; + if (len > 4) + return -1; + memcpy(&sa->dhgrp->gen1, d + 1, len); + sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1); + } + break; + + case OAKLEY_ATTR_GRP_GEN_TWO: + vfree(val); + if (!flag) + sa->dhgrp->gen2 = ntohs(d->lorv); + else { + int len = ntohs(d->lorv); + sa->dhgrp->gen2 = 0; + if (len > 4) + return -1; + memcpy(&sa->dhgrp->gen2, d + 1, len); + sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2); + } + break; + + case OAKLEY_ATTR_GRP_CURVE_A: + sa->dhgrp->curve_a = val; + break; + + case OAKLEY_ATTR_GRP_CURVE_B: + sa->dhgrp->curve_b = val; + break; + + case OAKLEY_ATTR_SA_LD_TYPE: + { + int type = (int)ntohs(d->lorv); + switch (type) { + case OAKLEY_ATTR_SA_LD_TYPE_SEC: + case OAKLEY_ATTR_SA_LD_TYPE_KB: + life_t = type; + break; + default: + life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT; + break; + } + break; + } + case OAKLEY_ATTR_SA_LD: + if (!prev + || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) != + OAKLEY_ATTR_SA_LD_TYPE) { + plog(LLV_ERROR, LOCATION, NULL, + "life duration must follow ltype\n"); + break; + } + + switch (life_t) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + sa->lifetime = ipsecdoi_set_ld(val); + vfree(val); + if (sa->lifetime == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto err; + } + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + sa->lifebyte = ipsecdoi_set_ld(val); + vfree(val); + if (sa->lifebyte == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto err; + } + break; + default: + vfree(val); + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type: %d\n", life_t); + goto err; + } + break; + + case OAKLEY_ATTR_KEY_LEN: + { + int len = ntohs(d->lorv); + if (len % 8 != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "keylen %d: not multiple of 8\n", + len); + goto err; + } + sa->encklen = (u_int16_t)len; + keylen++; + break; + } + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_FIELD_SIZE: + /* unsupported */ + break; + + case OAKLEY_ATTR_GRP_ORDER: + sa->dhgrp->order = val; + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_GSS_ID: + { + iconv_t cd; + size_t srcleft, dstleft, rv; + __iconv_const char *src; + char *dst; + int len = ntohs(d->lorv); + + /* + * Older verions of racoon just placed the + * ISO-Latin-1 string on the wire directly. + * Check to see if we are configured to be + * compatible with this behavior. + */ + if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) { + sa->gssid = vmalloc(len); + memcpy(sa->gssid->v, d + 1, len); + plog(LLV_DEBUG, LOCATION, NULL, + "received old-style gss id '%.*s' (len %d)\n", + sa->gssid->l, sa->gssid->v, sa->gssid->l); + break; + } + + /* + * For Windows 2000 compatibility, we expect + * the GSS ID attribute on the wire to be + * encoded in UTF-16LE. Internally, we work + * in ISO-Latin-1. Therefore, we should need + * 1/2 the specified length, which should always + * be a multiple of 2 octets. + */ + cd = iconv_open("latin1", "utf-16le"); + if (cd == (iconv_t) -1) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to initialize utf-16le -> latin1 " + "conversion descriptor: %s\n", + strerror(errno)); + break; + } + + sa->gssid = vmalloc(len / 2); + + src = (__iconv_const char *)(d + 1); + srcleft = len; + + dst = sa->gssid->v; + dstleft = len / 2; + + rv = iconv(cd, (__iconv_const char **)&src, &srcleft, + &dst, &dstleft); + if (rv != 0) { + if (rv == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to convert GSS ID from " + "utf-16le -> latin1: %s\n", + strerror(errno)); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "%zd character%s in GSS ID cannot " + "be represented in latin1\n", + rv, rv == 1 ? "" : "s"); + } + (void) iconv_close(cd); + vfree(sa->gssid); + sa->gssid = NULL; + break; + } + (void) iconv_close(cd); + + /* XXX dstleft should always be 0; assert it? */ + sa->gssid->l = (len / 2) - dstleft; + + plog(LLV_DEBUG, LOCATION, NULL, + "received gss id '%.*s' (len %d)\n", + sa->gssid->l, sa->gssid->v, sa->gssid->l); + break; + } +#endif /* HAVE_GSSAPI */ + + default: + break; + } + + prev = d; + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + ntohs(d->lorv)); + d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv)); + } + } + + /* key length must not be specified on some algorithms */ + if (keylen) { + if (sa->enctype == OAKLEY_ATTR_ENC_ALG_DES +#ifdef HAVE_OPENSSL_IDEA_H + || sa->enctype == OAKLEY_ATTR_ENC_ALG_IDEA +#endif + || sa->enctype == OAKLEY_ATTR_ENC_ALG_3DES) { + plog(LLV_ERROR, LOCATION, NULL, + "keylen must not be specified " + "for encryption algorithm %d\n", + sa->enctype); + return -1; + } + } + + return 0; +err: + return error; +} + +/*%%%*/ +/* + * check phase 2 SA payload and select single proposal. + * make new SA payload to be replyed not including general header. + * This function is called by responder only. + * OUT: + * 0: succeed. + * -1: error occured. + */ +int +ipsecdoi_selectph2proposal(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **pair; + struct prop_pair *ret; + + /* get proposal pair */ + pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return -1; + + /* check and select a proposal. */ + ret = get_ph2approval(iph2, pair); + free_proppair(pair); + if (ret == NULL) + return -1; + + /* make a SA to be replayed. */ + /* SPI must be updated later. */ + iph2->sa_ret = get_sabyproppair(ret, iph2->ph1); + free_proppair0(ret); + if (iph2->sa_ret == NULL) + return -1; + + return 0; +} + +/* + * check phase 2 SA payload returned from responder. + * This function is called by initiator only. + * OUT: + * 0: valid. + * -1: invalid. + */ +int +ipsecdoi_checkph2proposal(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **rpair = NULL, **spair = NULL; + struct prop_pair *p; + int i, n, num; + int error = -1; + vchar_t *sa_ret = NULL; + + /* get proposal pair of SA sent. */ + spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (spair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get prop pair.\n"); + goto end; + } + + /* XXX should check the number of transform */ + + /* get proposal pair of SA replayed */ + rpair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2); + if (rpair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get prop pair.\n"); + goto end; + } + + /* check proposal is only one ? */ + n = 0; + num = 0; + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (rpair[i]) { + n = i; + num++; + } + } + if (num == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no proposal received.\n"); + goto end; + } + if (num != 1) { + plog(LLV_ERROR, LOCATION, NULL, + "some proposals received.\n"); + goto end; + } + + if (spair[n] == NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "invalid proposal number:%d received.\n", i); + } + + + if (rpair[n]->tnext != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "multi transforms replyed.\n"); + goto end; + } + + if (cmp_aproppair_i(rpair[n], spair[n])) { + plog(LLV_ERROR, LOCATION, NULL, + "proposal mismathed.\n"); + goto end; + } + + /* + * check and select a proposal. + * ensure that there is no modification of the proposal by + * cmp_aproppair_i() + */ + p = get_ph2approval(iph2, rpair); + if (p == NULL) + goto end; + + /* make a SA to be replayed. */ + sa_ret = iph2->sa_ret; + iph2->sa_ret = get_sabyproppair(p, iph2->ph1); + free_proppair0(p); + if (iph2->sa_ret == NULL) + goto end; + + error = 0; + +end: + if (rpair) + free_proppair(rpair); + if (spair) + free_proppair(spair); + if (sa_ret) + vfree(sa_ret); + + return error; +} + +/* + * compare two prop_pair which is assumed to have same proposal number. + * the case of bundle or single SA, NOT multi transforms. + * a: a proposal that is multi protocols and single transform, usually replyed. + * b: a proposal that is multi protocols and multi transform, usually sent. + * NOTE: this function is for initiator. + * OUT + * 0: equal + * 1: not equal + * XXX cannot understand the comment! + */ +static int +cmp_aproppair_i(a, b) + struct prop_pair *a, *b; +{ + struct prop_pair *p, *q, *r; + int len; + + for (p = a, q = b; p && q; p = p->next, q = q->next) { + for (r = q; r; r = r->tnext) { + /* compare trns */ + if (p->trns->t_no == r->trns->t_no) + break; + } + if (!r) { + /* no suitable transform found */ + plog(LLV_ERROR, LOCATION, NULL, + "no suitable transform found.\n"); + return -1; + } + + /* compare prop */ + if (p->prop->p_no != r->prop->p_no) { + plog(LLV_WARNING, LOCATION, NULL, + "proposal #%d mismatched, " + "expected #%d.\n", + r->prop->p_no, p->prop->p_no); + /*FALLTHROUGH*/ + } + + if (p->prop->proto_id != r->prop->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "proto_id mismathed: my:%d peer:%d\n", + r->prop->proto_id, p->prop->proto_id); + return -1; + } + + if (p->prop->proto_id != r->prop->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid spi size: %d.\n", + p->prop->proto_id); + return -1; + } + + /* check #of transforms */ + if (p->prop->num_t != 1) { + plog(LLV_WARNING, LOCATION, NULL, + "#of transform is %d, " + "but expected 1.\n", p->prop->num_t); + /*FALLTHROUGH*/ + } + + if (p->trns->t_id != r->trns->t_id) { + plog(LLV_WARNING, LOCATION, NULL, + "transform number has been modified.\n"); + /*FALLTHROUGH*/ + } + if (p->trns->reserved != r->trns->reserved) { + plog(LLV_WARNING, LOCATION, NULL, + "reserved field should be zero.\n"); + /*FALLTHROUGH*/ + } + + /* compare attribute */ + len = ntohs(r->trns->h.len) - sizeof(*p->trns); + if (memcmp(p->trns + 1, r->trns + 1, len) != 0) { + plog(LLV_WARNING, LOCATION, NULL, + "attribute has been modified.\n"); + /*FALLTHROUGH*/ + } + } + if ((p && !q) || (!p && q)) { + /* # of protocols mismatched */ + plog(LLV_ERROR, LOCATION, NULL, + "#of protocols mismatched.\n"); + return -1; + } + + return 0; +} + +/* + * acceptable check for policy configuration. + * return a new SA payload to be reply to peer. + */ +static struct prop_pair * +get_ph2approval(iph2, pair) + struct ph2handle *iph2; + struct prop_pair **pair; +{ + struct prop_pair *ret; + int i; + + iph2->approval = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, + "begin compare proposals.\n"); + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + plog(LLV_DEBUG, LOCATION, NULL, + "pair[%d]: %p\n", i, pair[i]); + print_proppair(LLV_DEBUG, pair[i]);; + + /* compare proposal and select one */ + ret = get_ph2approvalx(iph2, pair[i]); + if (ret != NULL) { + /* found */ + return ret; + } + } + + plog(LLV_ERROR, LOCATION, NULL, "no suitable policy found.\n"); + + return NULL; +} + +/* + * compare my proposal and peers just one proposal. + * set a approval. + */ +static struct prop_pair * +get_ph2approvalx(iph2, pp) + struct ph2handle *iph2; + struct prop_pair *pp; +{ + struct prop_pair *ret = NULL; + struct saprop *pr0, *pr = NULL; + struct saprop *q1, *q2; + + pr0 = aproppair2saprop(pp); + if (pr0 == NULL) + return NULL; + + for (q1 = pr0; q1; q1 = q1->next) { + for (q2 = iph2->proposal; q2; q2 = q2->next) { + plog(LLV_DEBUG, LOCATION, NULL, + "peer's single bundle:\n"); + printsaprop0(LLV_DEBUG, q1); + plog(LLV_DEBUG, LOCATION, NULL, + "my single bundle:\n"); + printsaprop0(LLV_DEBUG, q2); + + pr = cmpsaprop_alloc(iph2->ph1, q1, q2, iph2->side); + if (pr != NULL) + goto found; + + plog(LLV_ERROR, LOCATION, NULL, + "not matched\n"); + } + } + /* no proposal matching */ +err: + flushsaprop(pr0); + return NULL; + +found: + flushsaprop(pr0); + plog(LLV_DEBUG, LOCATION, NULL, "matched\n"); + iph2->approval = pr; + + { + struct saproto *sp; + struct prop_pair *p, *n, *x; + + ret = NULL; + + for (p = pp; p; p = p->next) { + /* + * find a proposal with matching proto_id. + * we have analyzed validity already, in cmpsaprop_alloc(). + */ + for (sp = pr->head; sp; sp = sp->next) { + if (sp->proto_id == p->prop->proto_id) + break; + } + if (!sp) + goto err; + if (sp->head->next) + goto err; /* XXX */ + + for (x = p; x; x = x->tnext) + if (sp->head->trns_no == x->trns->t_no) + break; + if (!x) + goto err; /* XXX */ + + n = racoon_calloc(1, sizeof(struct prop_pair)); + if (!n) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + goto err; + } + + n->prop = x->prop; + n->trns = x->trns; + + /* need to preserve the order */ + for (x = ret; x && x->next; x = x->next) + ; + if (x && x->prop == n->prop) { + for (/*nothing*/; x && x->tnext; x = x->tnext) + ; + x->tnext = n; + } else { + if (x) + x->next = n; + else { + ret = n; + } + } + + /* #of transforms should be updated ? */ + } + } + + return ret; +} + +void +free_proppair(pair) + struct prop_pair **pair; +{ + int i; + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + free_proppair0(pair[i]); + pair[i] = NULL; + } + racoon_free(pair); +} + +static void +free_proppair0(pair) + struct prop_pair *pair; +{ + struct prop_pair *p, *q, *r, *s; + + p = pair; + while (p) { + q = p->next; + r = p; + while (r) { + s = r->tnext; + racoon_free(r); + r = s; + } + p = q; + } +} + +/* + * get proposal pairs from SA payload. + * tiny check for proposal payload. + */ +struct prop_pair ** +get_proppair(sa, mode) + vchar_t *sa; + int mode; +{ + struct prop_pair **pair; + int num_p = 0; /* number of proposal for use */ + int tlen; + caddr_t bp; + int i; + struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v; + + plog(LLV_DEBUG, LOCATION, NULL, "total SA len=%zu\n", sa->l); + plogdump(LLV_DEBUG, sa->v, sa->l); + + /* check SA payload size */ + if (sa->l < sizeof(*sab)) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid SA length = %zu.\n", sa->l); + return NULL; + } + + /* check DOI */ + if (check_doi(ntohl(sab->doi)) < 0) + return NULL; + + /* check SITUATION */ + if (check_situation(ntohl(sab->sit)) < 0) + return NULL; + + pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair)); + if (pair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return NULL; + } + memset(pair, 0, sizeof(pair)); + + bp = (caddr_t)(sab + 1); + tlen = sa->l - sizeof(*sab); + + { + struct isakmp_pl_p *prop; + int proplen; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + + pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen); + if (pbuf == NULL) + return NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + /* check the value of next payload */ + if (pa->type != ISAKMP_NPTYPE_P) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid payload type=%u\n", pa->type); + vfree(pbuf); + return NULL; + } + + prop = (struct isakmp_pl_p *)pa->ptr; + proplen = pa->len; + + plog(LLV_DEBUG, LOCATION, NULL, + "proposal #%u len=%d\n", prop->p_no, proplen); + + if (proplen == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proposal with length %d\n", proplen); + vfree(pbuf); + return NULL; + } + + /* check Protocol ID */ + if (!check_protocol[mode]) { + plog(LLV_ERROR, LOCATION, NULL, + "unsupported mode %d\n", mode); + continue; + } + + if (check_protocol[mode](prop->proto_id) < 0) + continue; + + /* check SPI length when IKE. */ + if (check_spi_size(prop->proto_id, prop->spi_size) < 0) + continue; + + /* get transform */ + if (get_transform(prop, pair, &num_p) < 0) { + vfree(pbuf); + return NULL; + } + } + vfree(pbuf); + pbuf = NULL; + } + + { + int notrans, nprop; + struct prop_pair *p, *q; + + /* check for proposals with no transforms */ + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (!pair[i]) + continue; + + plog(LLV_DEBUG, LOCATION, NULL, "pair %d:\n", i); + print_proppair(LLV_DEBUG, pair[i]); + + notrans = nprop = 0; + for (p = pair[i]; p; p = p->next) { + if (p->trns == NULL) { + notrans++; + break; + } + for (q = p; q; q = q->tnext) + nprop++; + } + +#if 0 + /* + * XXX at this moment, we cannot accept proposal group + * with multiple proposals. this should be fixed. + */ + if (pair[i]->next) { + plog(LLV_WARNING, LOCATION, NULL, + "proposal #%u ignored " + "(multiple proposal not supported)\n", + pair[i]->prop->p_no); + notrans++; + } +#endif + + if (notrans) { + for (p = pair[i]; p; p = q) { + q = p->next; + racoon_free(p); + } + pair[i] = NULL; + num_p--; + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "proposal #%u: %d transform\n", + pair[i]->prop->p_no, nprop); + } + } + } + + /* bark if no proposal is found. */ + if (num_p <= 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no Proposal found.\n"); + return NULL; + } + + return pair; +} + +/* + * check transform payload. + * OUT: + * positive: return the pointer to the payload of valid transform. + * 0 : No valid transform found. + */ +static int +get_transform(prop, pair, num_p) + struct isakmp_pl_p *prop; + struct prop_pair **pair; + int *num_p; +{ + int tlen; /* total length of all transform in a proposal */ + caddr_t bp; + struct isakmp_pl_t *trns; + int trnslen; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + struct prop_pair *p = NULL, *q; + int num_t; + + bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size; + tlen = ntohs(prop->h.len) + - (sizeof(struct isakmp_pl_p) + prop->spi_size); + pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, tlen); + if (pbuf == NULL) + return -1; + + /* check and get transform for use */ + num_t = 0; + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + num_t++; + + /* check the value of next payload */ + if (pa->type != ISAKMP_NPTYPE_T) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid payload type=%u\n", pa->type); + break; + } + + trns = (struct isakmp_pl_t *)pa->ptr; + trnslen = pa->len; + + plog(LLV_DEBUG, LOCATION, NULL, + "transform #%u len=%u\n", trns->t_no, trnslen); + + /* check transform ID */ + if (prop->proto_id >= ARRAYLEN(check_transform)) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + if (prop->proto_id >= ARRAYLEN(check_attributes)) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + + if (!check_transform[prop->proto_id] + || !check_attributes[prop->proto_id]) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + if (check_transform[prop->proto_id](trns->t_id) < 0) + continue; + + /* check data attributes */ + if (check_attributes[prop->proto_id](trns) != 0) + continue; + + p = racoon_calloc(1, sizeof(*p)); + if (p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + vfree(pbuf); + return -1; + } + p->prop = prop; + p->trns = trns; + + /* need to preserve the order */ + for (q = pair[prop->p_no]; q && q->next; q = q->next) + ; + if (q && q->prop == p->prop) { + for (/*nothing*/; q && q->tnext; q = q->tnext) + ; + q->tnext = p; + } else { + if (q) + q->next = p; + else { + pair[prop->p_no] = p; + (*num_p)++; + } + } + } + + vfree(pbuf); + + return 0; +} + +/* + * make a new SA payload from prop_pair. + * NOTE: this function make spi value clear. + */ +vchar_t * +get_sabyproppair(pair, iph1) + struct prop_pair *pair; + struct ph1handle *iph1; +{ + vchar_t *newsa; + int newtlen; + u_int8_t *np_p = NULL; + struct prop_pair *p; + int prophlen, trnslen; + caddr_t bp; + + newtlen = sizeof(struct ipsecdoi_sa_b); + for (p = pair; p; p = p->next) { + newtlen += sizeof(struct isakmp_pl_p); + newtlen += p->prop->spi_size; + newtlen += ntohs(p->trns->h.len); + } + + newsa = vmalloc(newtlen); + if (newsa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); + return NULL; + } + bp = newsa->v; + + ((struct isakmp_gen *)bp)->len = htons(newtlen); + + /* update some of values in SA header */ + ((struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype); + ((struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype); + bp += sizeof(struct ipsecdoi_sa_b); + + /* create proposal payloads */ + for (p = pair; p; p = p->next) { + prophlen = sizeof(struct isakmp_pl_p) + + p->prop->spi_size; + trnslen = ntohs(p->trns->h.len); + + if (np_p) + *np_p = ISAKMP_NPTYPE_P; + + /* create proposal */ + + memcpy(bp, p->prop, prophlen); + ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen); + ((struct isakmp_pl_p *)bp)->num_t = 1; + np_p = &((struct isakmp_pl_p *)bp)->h.np; + memset(bp + sizeof(struct isakmp_pl_p), 0, p->prop->spi_size); + bp += prophlen; + + /* create transform */ + memcpy(bp, p->trns, trnslen); + ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen); + bp += trnslen; + } + + return newsa; +} + +/* + * update responder's spi + */ +int +ipsecdoi_updatespi(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **pair, *p; + struct saprop *pp; + struct saproto *pr; + int i; + int error = -1; + u_int8_t *spi; + + pair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return -1; + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i]) + break; + } + if (i == MAXPROPPAIRLEN || pair[i]->tnext) { + /* multiple transform must be filtered by selectph2proposal.*/ + goto end; + } + + pp = iph2->approval; + + /* create proposal payloads */ + for (p = pair[i]; p; p = p->next) { + /* + * find a proposal/transform with matching proto_id/t_id. + * we have analyzed validity already, in cmpsaprop_alloc(). + */ + for (pr = pp->head; pr; pr = pr->next) { + if (p->prop->proto_id == pr->proto_id && + p->trns->t_id == pr->head->trns_id) { + break; + } + } + if (!pr) + goto end; + + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + spi = (u_int8_t *)&pr->spi; + spi += sizeof(pr->spi); + spi -= pr->spisize; + memcpy((caddr_t)p->prop + sizeof(*p->prop), spi, pr->spisize); + } + + error = 0; +end: + free_proppair(pair); + return error; +} + +/* + * make a new SA payload from prop_pair. + */ +vchar_t * +get_sabysaprop(pp0, sa0) + struct saprop *pp0; + vchar_t *sa0; +{ + struct prop_pair **pair; + vchar_t *newsa; + int newtlen; + u_int8_t *np_p = NULL; + struct prop_pair *p = NULL; + struct saprop *pp; + struct saproto *pr; + struct satrns *tr; + int prophlen, trnslen; + caddr_t bp; + + /* get proposal pair */ + pair = get_proppair(sa0, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return NULL; + + newtlen = sizeof(struct ipsecdoi_sa_b); + for (pp = pp0; pp; pp = pp->next) { + + if (pair[pp->prop_no] == NULL) + return NULL; + + for (pr = pp->head; pr; pr = pr->next) { + newtlen += (sizeof(struct isakmp_pl_p) + + pr->spisize); + + for (tr = pr->head; tr; tr = tr->next) { + for (p = pair[pp->prop_no]; p; p = p->tnext) { + if (tr->trns_no == p->trns->t_no) + break; + } + if (p == NULL) + return NULL; + + newtlen += ntohs(p->trns->h.len); + } + } + } + + newsa = vmalloc(newtlen); + if (newsa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); + return NULL; + } + bp = newsa->v; + + /* some of values of SA must be updated in the out of this function */ + ((struct isakmp_gen *)bp)->len = htons(newtlen); + bp += sizeof(struct ipsecdoi_sa_b); + + /* create proposal payloads */ + for (pp = pp0; pp; pp = pp->next) { + + for (pr = pp->head; pr; pr = pr->next) { + prophlen = sizeof(struct isakmp_pl_p) + + p->prop->spi_size; + + for (tr = pr->head; tr; tr = tr->next) { + for (p = pair[pp->prop_no]; p; p = p->tnext) { + if (tr->trns_no == p->trns->t_no) + break; + } + if (p == NULL) + return NULL; + + trnslen = ntohs(p->trns->h.len); + + if (np_p) + *np_p = ISAKMP_NPTYPE_P; + + /* create proposal */ + + memcpy(bp, p->prop, prophlen); + ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen); + ((struct isakmp_pl_p *)bp)->num_t = 1; + np_p = &((struct isakmp_pl_p *)bp)->h.np; + bp += prophlen; + + /* create transform */ + memcpy(bp, p->trns, trnslen); + ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen); + bp += trnslen; + } + } + } + + return newsa; +} + +/* + * If some error happens then return 0. Although 0 means that lifetime is zero, + * such a value should not be accepted. + * Also 0 of lifebyte should not be included in a packet although 0 means not + * to care of it. + */ +static u_int32_t +ipsecdoi_set_ld(buf) + vchar_t *buf; +{ + u_int32_t ld; + + if (buf == 0) + return 0; + + switch (buf->l) { + case 2: + ld = ntohs(*(u_int16_t *)buf->v); + break; + case 4: + ld = ntohl(*(u_int32_t *)buf->v); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "length %zu of life duration " + "isn't supported.\n", buf->l); + return 0; + } + + return ld; +} + +/*%%%*/ +/* + * check DOI + */ +static int +check_doi(doi) + u_int32_t doi; +{ + switch (doi) { + case IPSEC_DOI: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid value of DOI 0x%08x.\n", doi); + return -1; + } + /* NOT REACHED */ +} + +/* + * check situation + */ +static int +check_situation(sit) + u_int32_t sit; +{ + switch (sit) { + case IPSECDOI_SIT_IDENTITY_ONLY: + return 0; + + case IPSECDOI_SIT_SECRECY: + case IPSECDOI_SIT_INTEGRITY: + plog(LLV_ERROR, LOCATION, NULL, + "situation 0x%08x unsupported yet.\n", sit); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid situation 0x%08x.\n", sit); + return -1; + } + /* NOT REACHED */ +} + +/* + * check protocol id in main mode + */ +static int +check_prot_main(proto_id) + int proto_id; +{ + switch (proto_id) { + case IPSECDOI_PROTO_ISAKMP: + return 0; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Illegal protocol id=%u.\n", proto_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check protocol id in quick mode + */ +static int +check_prot_quick(proto_id) + int proto_id; +{ + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + return 0; + + case IPSECDOI_PROTO_IPCOMP: + return 0; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid protocol id %d.\n", proto_id); + return -1; + } + /* NOT REACHED */ +} + +static int +check_spi_size(proto_id, size) + int proto_id, size; +{ + switch (proto_id) { + case IPSECDOI_PROTO_ISAKMP: + if (size != 0) { + /* WARNING */ + plog(LLV_WARNING, LOCATION, NULL, + "SPI size isn't zero, but IKE proposal.\n"); + } + return 0; + + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + if (size != 4) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid SPI size=%d for IPSEC proposal.\n", + size); + return -1; + } + return 0; + + case IPSECDOI_PROTO_IPCOMP: + if (size != 2 && size != 4) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid SPI size=%d for IPCOMP proposal.\n", + size); + return -1; + } + return 0; + + default: + /* ??? */ + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in ISAKMP. + */ +static int +check_trns_isakmp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_KEY_IKE: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in proto_id=%u.\n", + t_id, IPSECDOI_KEY_IKE); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in AH. + */ +static int +check_trns_ah(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_AH_MD5: + case IPSECDOI_AH_SHA: + case IPSECDOI_AH_SHA256: + case IPSECDOI_AH_SHA384: + case IPSECDOI_AH_SHA512: + return 0; + case IPSECDOI_AH_DES: + plog(LLV_ERROR, LOCATION, NULL, + "not support transform-id=%u in AH.\n", t_id); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in AH.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in ESP. + */ +static int +check_trns_esp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_ESP_DES: + case IPSECDOI_ESP_3DES: + case IPSECDOI_ESP_NULL: + case IPSECDOI_ESP_RC5: + case IPSECDOI_ESP_CAST: + case IPSECDOI_ESP_BLOWFISH: + case IPSECDOI_ESP_AES: + case IPSECDOI_ESP_TWOFISH: + return 0; + case IPSECDOI_ESP_DES_IV32: + case IPSECDOI_ESP_DES_IV64: + case IPSECDOI_ESP_IDEA: + case IPSECDOI_ESP_3IDEA: + case IPSECDOI_ESP_RC4: + plog(LLV_ERROR, LOCATION, NULL, + "not support transform-id=%u in ESP.\n", t_id); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in ESP.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in IPCOMP. + */ +static int +check_trns_ipcomp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_IPCOMP_OUI: + case IPSECDOI_IPCOMP_DEFLATE: + case IPSECDOI_IPCOMP_LZS: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in IPCOMP.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check data attributes in IKE. + */ +static int +check_attr_isakmp(trns) + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type; + u_int16_t lorv; + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_oakley_attr(type), flag, + s_oakley_attr_v(type, lorv)); + + /* + * some of the attributes must be encoded in TV. + * see RFC2409 Appendix A "Attribute Classes". + */ + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + case OAKLEY_ATTR_HASH_ALG: + case OAKLEY_ATTR_AUTH_METHOD: + case OAKLEY_ATTR_GRP_DESC: + case OAKLEY_ATTR_GRP_TYPE: + case OAKLEY_ATTR_SA_LD_TYPE: + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_KEY_LEN: + case OAKLEY_ATTR_FIELD_SIZE: + if (!flag) { /* TLV*/ + plog(LLV_ERROR, LOCATION, NULL, + "oakley attribute %d must be TV.\n", + type); + return -1; + } + break; + } + + /* sanity check for TLV. length must be specified. */ + if (!flag && lorv == 0) { /*TLV*/ + plog(LLV_ERROR, LOCATION, NULL, + "invalid length %d for TLV attribute %d.\n", + lorv, type); + return -1; + } + + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + if (!alg_oakley_encdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalied encryption algorithm=%d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_HASH_ALG: + if (!alg_oakley_hashdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalied hash algorithm=%d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_AUTH_METHOD: + switch (lorv) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: +#endif + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_ERROR, LOCATION, NULL, + "auth method %d isn't supported.\n", + lorv); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid auth method %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_DESC: + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid DH group %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_TYPE: + switch (lorv) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported DH group type %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_PI: + case OAKLEY_ATTR_GRP_GEN_ONE: + /* sanity checks? */ + break; + + case OAKLEY_ATTR_GRP_GEN_TWO: + case OAKLEY_ATTR_GRP_CURVE_A: + case OAKLEY_ATTR_GRP_CURVE_B: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + case OAKLEY_ATTR_SA_LD_TYPE: + switch (lorv) { + case OAKLEY_ATTR_SA_LD_TYPE_SEC: + case OAKLEY_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case OAKLEY_ATTR_SA_LD: + /* should check the value */ + break; + + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_KEY_LEN: + break; + + case OAKLEY_ATTR_FIELD_SIZE: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + case OAKLEY_ATTR_GRP_ORDER: + break; + + case OAKLEY_ATTR_GSS_ID: + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((char *)d + + sizeof(*d) + lorv); + } + } + + return 0; +} + +/* + * check data attributes in IPSEC AH/ESP. + */ +static int +check_attr_ah(trns) + struct isakmp_pl_t *trns; +{ + return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_AH, trns); +} + +static int +check_attr_esp(trns) + struct isakmp_pl_t *trns; +{ + return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns); +} + +static int +check_attr_ipsec(proto_id, trns) + int proto_id; + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type = 0; + u_int16_t lorv; + int attrseen[16]; /* XXX magic number */ + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + memset(attrseen, 0, sizeof(attrseen)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_ipsecdoi_attr(type), flag, + s_ipsecdoi_attr_v(type, lorv)); + + if (type < sizeof(attrseen)/sizeof(attrseen[0])) + attrseen[type]++; + + switch (type) { + case IPSECDOI_ATTR_ENC_MODE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when ENC_MODE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: + case IPSECDOI_ATTR_ENC_MODE_TRNS: + break; +#ifdef ENABLE_NATT + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT: + plog(LLV_DEBUG, LOCATION, NULL, + "UDP encapsulation requested\n"); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption mode=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_AUTH: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when AUTH.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH && + trns->t_id != IPSECDOI_AH_MD5) { +ahmismatch: + plog(LLV_ERROR, LOCATION, NULL, + "auth algorithm %u conflicts " + "with transform %u.\n", + lorv, trns->t_id); + return -1; + } + break; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH) { + if (trns->t_id != IPSECDOI_AH_SHA) + goto ahmismatch; + } + break; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH) { + if (trns->t_id != IPSECDOI_AH_SHA256) + goto ahmismatch; + } + break; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH) { + if (trns->t_id != IPSECDOI_AH_SHA384) + goto ahmismatch; + } + break; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH) { + if (trns->t_id != IPSECDOI_AH_SHA512) + goto ahmismatch; + } + break; + case IPSECDOI_ATTR_AUTH_DES_MAC: + case IPSECDOI_ATTR_AUTH_KPDK: + plog(LLV_ERROR, LOCATION, NULL, + "auth algorithm %u isn't supported.\n", + lorv); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid auth algorithm=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD: + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + plog(LLV_DEBUG, LOCATION, NULL, + "life duration was in TLV.\n"); + } else { + /* i.e. ISAKMP_GEN_TLV */ + if (lorv == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid length of LD\n"); + return -1; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when GRP_DESC.\n"); + return -1; + } + + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid group description=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_KEY_LENGTH: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when KEY_LENGTH.\n"); + return -1; + } + break; + + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((caddr_t)d + + sizeof(*d) + lorv); + } + } + + if (proto_id == IPSECDOI_PROTO_IPSEC_AH && + !attrseen[IPSECDOI_ATTR_AUTH]) { + plog(LLV_ERROR, LOCATION, NULL, + "attr AUTH must be present for AH.\n"); + return -1; + } + + if (proto_id == IPSECDOI_PROTO_IPSEC_ESP && + trns->t_id == IPSECDOI_ESP_NULL && + !attrseen[IPSECDOI_ATTR_AUTH]) { + plog(LLV_ERROR, LOCATION, NULL, + "attr AUTH must be present for ESP NULL encryption.\n"); + return -1; + } + + return 0; +} + +static int +check_attr_ipcomp(trns) + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type = 0; + u_int16_t lorv; + int attrseen[16]; /* XXX magic number */ + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + memset(attrseen, 0, sizeof(attrseen)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%d, flag=0x%04x, lorv=0x%04x\n", + type, flag, lorv); + + if (type < sizeof(attrseen)/sizeof(attrseen[0])) + attrseen[type]++; + + switch (type) { + case IPSECDOI_ATTR_ENC_MODE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when ENC_MODE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: + case IPSECDOI_ATTR_ENC_MODE_TRNS: + break; +#ifdef ENABLE_NATT + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT: + plog(LLV_DEBUG, LOCATION, NULL, + "UDP encapsulation requested\n"); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption mode=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD: + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + plog(LLV_DEBUG, LOCATION, NULL, + "life duration was in TLV.\n"); + } else { + /* i.e. ISAKMP_GEN_TLV */ + if (lorv == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid length of LD\n"); + return -1; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when GRP_DESC.\n"); + return -1; + } + + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid group description=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_AUTH: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attr type=%u.\n", type); + return -1; + + case IPSECDOI_ATTR_KEY_LENGTH: + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((caddr_t)d + + sizeof(*d) + lorv); + } + } + +#if 0 + if (proto_id == IPSECDOI_PROTO_IPCOMP && + !attrseen[IPSECDOI_ATTR_AUTH]) { + plog(LLV_ERROR, LOCATION, NULL, + "attr AUTH must be present for AH.\n", type); + return -1; + } +#endif + + return 0; +} + +/* %%% */ +/* + * create phase1 proposal from remote configuration. + * NOT INCLUDING isakmp general header of SA payload + */ +vchar_t * +ipsecdoi_setph1proposal(props) + struct isakmpsa *props; +{ + vchar_t *mysa; + int sablen; + + /* count total size of SA minus isakmp general header */ + /* not including isakmp general header of SA payload */ + sablen = sizeof(struct ipsecdoi_sa_b); + sablen += setph1prop(props, NULL); + + mysa = vmalloc(sablen); + if (mysa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + return NULL; + } + + /* create SA payload */ + /* not including isakmp general header */ + ((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(props->rmconf->doitype); + ((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype); + + (void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b)); + + return mysa; +} + +static int +setph1prop(props, buf) + struct isakmpsa *props; + caddr_t buf; +{ + struct isakmp_pl_p *prop = NULL; + struct isakmpsa *s = NULL; + int proplen, trnslen; + u_int8_t *np_t; /* pointer next trns type in previous header */ + int trns_num; + caddr_t p = buf; + + proplen = sizeof(*prop); + if (buf) { + /* create proposal */ + prop = (struct isakmp_pl_p *)p; + prop->h.np = ISAKMP_NPTYPE_NONE; + prop->p_no = props->prop_no; + prop->proto_id = IPSECDOI_PROTO_ISAKMP; + prop->spi_size = 0; + p += sizeof(*prop); + } + + np_t = NULL; + trns_num = 0; + + for (s = props; s != NULL; s = s->next) { + if (np_t) + *np_t = ISAKMP_NPTYPE_T; + + trnslen = setph1trns(s, p); + proplen += trnslen; + if (buf) { + /* save buffer to pre-next payload */ + np_t = &((struct isakmp_pl_t *)p)->h.np; + p += trnslen; + + /* count up transform length */ + trns_num++; + } + } + + /* update proposal length */ + if (buf) { + prop->h.len = htons(proplen); + prop->num_t = trns_num; + } + + return proplen; +} + +static int +setph1trns(sa, buf) + struct isakmpsa *sa; + caddr_t buf; +{ + struct isakmp_pl_t *trns = NULL; + int trnslen, attrlen; + caddr_t p = buf; + + trnslen = sizeof(*trns); + if (buf) { + /* create transform */ + trns = (struct isakmp_pl_t *)p; + trns->h.np = ISAKMP_NPTYPE_NONE; + trns->t_no = sa->trns_no; + trns->t_id = IPSECDOI_KEY_IKE; + p += sizeof(*trns); + } + + attrlen = setph1attr(sa, p); + trnslen += attrlen; + if (buf) + p += attrlen; + + if (buf) + trns->h.len = htons(trnslen); + + return trnslen; +} + +static int +setph1attr(sa, buf) + struct isakmpsa *sa; + caddr_t buf; +{ + caddr_t p = buf; + int attrlen = 0; + + if (sa->lifetime) { + u_int32_t lifetime = htonl((u_int32_t)sa->lifetime); + + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (sa->lifetime > 0xffff) + attrlen += sizeof(lifetime); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE, + OAKLEY_ATTR_SA_LD_TYPE_SEC); + if (sa->lifetime > 0xffff) { + p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD, + (caddr_t)&lifetime, + sizeof(lifetime)); + } else { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD, + sa->lifetime); + } + } + } + + if (sa->lifebyte) { + u_int32_t lifebyte = htonl((u_int32_t)sa->lifebyte); + + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (sa->lifebyte > 0xffff) + attrlen += sizeof(lifebyte); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE, + OAKLEY_ATTR_SA_LD_TYPE_KB); + if (sa->lifebyte > 0xffff) { + p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD, + (caddr_t)&lifebyte, + sizeof(lifebyte)); + } else { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD, + sa->lifebyte); + } + } + } + + if (sa->enctype) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_ENC_ALG, sa->enctype); + } + if (sa->encklen) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_KEY_LEN, sa->encklen); + } + if (sa->authmethod) { + int authmethod; + +#ifdef ENABLE_HYBRID + authmethod = switch_authmethod(sa->authmethod); +#else + authmethod = sa->authmethod; +#endif + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod); + } + if (sa->hashtype) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_HASH_ALG, sa->hashtype); + } + switch (sa->dh_group) { + case OAKLEY_ATTR_GRP_DESC_MODP768: + case OAKLEY_ATTR_GRP_DESC_MODP1024: + case OAKLEY_ATTR_GRP_DESC_MODP1536: + case OAKLEY_ATTR_GRP_DESC_MODP2048: + case OAKLEY_ATTR_GRP_DESC_MODP3072: + case OAKLEY_ATTR_GRP_DESC_MODP4096: + case OAKLEY_ATTR_GRP_DESC_MODP6144: + case OAKLEY_ATTR_GRP_DESC_MODP8192: + /* don't attach group type for known groups */ + attrlen += sizeof(struct isakmp_data); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_DESC, + sa->dh_group); + } + break; + case OAKLEY_ATTR_GRP_DESC_EC2N155: + case OAKLEY_ATTR_GRP_DESC_EC2N185: + /* don't attach group type for known groups */ + attrlen += sizeof(struct isakmp_data); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_TYPE, + OAKLEY_ATTR_GRP_TYPE_EC2N); + } + break; + case 0: + default: + break; + } + +#ifdef HAVE_GSSAPI + if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + sa->gssid != NULL) { + attrlen += sizeof(struct isakmp_data); + /* + * Older versions of racoon just placed the ISO-Latin-1 + * string on the wire directly. Check to see if we are + * configured to be compatible with this behavior. Otherwise, + * we encode the GSS ID as UTF-16LE for Windows 2000 + * compatibility, which requires twice the number of octets. + */ + if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) + attrlen += sa->gssid->l; + else + attrlen += sa->gssid->l * 2; + if (buf) { + plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %d, " + "val '%.*s'\n", sa->gssid->l, sa->gssid->l, + sa->gssid->v); + if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) { + p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID, + (caddr_t)sa->gssid->v, + sa->gssid->l); + } else { + size_t dstleft = sa->gssid->l * 2; + size_t srcleft = sa->gssid->l; + const char *src = (const char *)sa->gssid->v; + char *odst, *dst = racoon_malloc(dstleft); + iconv_t cd; + size_t rv; + + cd = iconv_open("utf-16le", "latin1"); + if (cd == (iconv_t) -1) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to initialize " + "latin1 -> utf-16le " + "converstion descriptor: %s\n", + strerror(errno)); + attrlen -= sa->gssid->l * 2; + goto gssid_done; + } + odst = dst; + rv = iconv(cd, (__iconv_const char **)&src, + &srcleft, &dst, &dstleft); + if (rv != 0) { + if (rv == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to convert GSS ID " + "from latin1 -> utf-16le: " + "%s\n", strerror(errno)); + } else { + /* should never happen */ + plog(LLV_ERROR, LOCATION, NULL, + "%zd character%s in GSS ID " + "cannot be represented " + "in utf-16le\n", + rv, rv == 1 ? "" : "s"); + } + (void) iconv_close(cd); + attrlen -= sa->gssid->l * 2; + goto gssid_done; + } + (void) iconv_close(cd); + + /* XXX Check srcleft and dstleft? */ + + p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID, + odst, sa->gssid->l * 2); + + racoon_free(odst); + } + } + } + gssid_done: +#endif /* HAVE_GSSAPI */ + + return attrlen; +} + +static vchar_t * +setph2proposal0(iph2, pp, pr) + const struct ph2handle *iph2; + const struct saprop *pp; + const struct saproto *pr; +{ + vchar_t *p; + struct isakmp_pl_p *prop; + struct isakmp_pl_t *trns; + struct satrns *tr; + int attrlen; + size_t trnsoff; + caddr_t x0, x; + u_int8_t *np_t; /* pointer next trns type in previous header */ + const u_int8_t *spi; + + p = vmalloc(sizeof(*prop) + sizeof(pr->spi)); + if (p == NULL) + return NULL; + + /* create proposal */ + prop = (struct isakmp_pl_p *)p->v; + prop->h.np = ISAKMP_NPTYPE_NONE; + prop->p_no = pp->prop_no; + prop->proto_id = pr->proto_id; + prop->num_t = 1; + + spi = (const u_int8_t *)&pr->spi; + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPCOMP: + /* + * draft-shacham-ippcp-rfc2393bis-05.txt: + * construct 16bit SPI (CPI). + * XXX we may need to provide a configuration option to + * generate 32bit SPI. otherwise we cannot interoeprate + * with nodes that uses 32bit SPI, in case we are initiator. + */ + prop->spi_size = sizeof(u_int16_t); + spi += sizeof(pr->spi) - sizeof(u_int16_t); + p->l -= sizeof(pr->spi); + p->l += sizeof(u_int16_t); + break; + default: + prop->spi_size = sizeof(pr->spi); + break; + } + memcpy(prop + 1, spi, prop->spi_size); + + /* create transform */ + trnsoff = sizeof(*prop) + prop->spi_size; + np_t = NULL; + + for (tr = pr->head; tr; tr = tr->next) { + + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + /* + * don't build a null encryption + * with no authentication transform. + */ + if (tr->trns_id == IPSECDOI_ESP_NULL && + tr->authtype == IPSECDOI_ATTR_AUTH_NONE) + continue; + break; + } + + if (np_t) { + *np_t = ISAKMP_NPTYPE_T; + prop->num_t++; + } + + /* get attribute length */ + attrlen = 0; + if (pp->lifetime) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (pp->lifetime > 0xffff) + attrlen += sizeof(u_int32_t); + } + if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (pp->lifebyte > 0xffff) + attrlen += sizeof(u_int32_t); + } + attrlen += sizeof(struct isakmp_data); /* enc mode */ + if (tr->encklen) + attrlen += sizeof(struct isakmp_data); + + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + /* non authentication mode ? */ + if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) + attrlen += sizeof(struct isakmp_data); + break; + case IPSECDOI_PROTO_IPSEC_AH: + if (tr->authtype == IPSECDOI_ATTR_AUTH_NONE) { + plog(LLV_ERROR, LOCATION, NULL, + "no authentication algorithm found " + "but protocol is AH.\n"); + vfree(p); + return NULL; + } + attrlen += sizeof(struct isakmp_data); + break; + case IPSECDOI_PROTO_IPCOMP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid protocol: %d\n", pr->proto_id); + vfree(p); + return NULL; + } + + if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group)) + attrlen += sizeof(struct isakmp_data); + + p = vrealloc(p, p->l + sizeof(*trns) + attrlen); + if (p == NULL) + return NULL; + prop = (struct isakmp_pl_p *)p->v; + + /* set transform's values */ + trns = (struct isakmp_pl_t *)(p->v + trnsoff); + trns->h.np = ISAKMP_NPTYPE_NONE; + trns->t_no = tr->trns_no; + trns->t_id = tr->trns_id; + + /* set attributes */ + x = x0 = p->v + trnsoff + sizeof(*trns); + + if (pp->lifetime) { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_SEC); + if (pp->lifetime > 0xffff) { + u_int32_t v = htonl((u_int32_t)pp->lifetime); + x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD, + pp->lifetime); + } + } + + if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_KB); + if (pp->lifebyte > 0xffff) { + u_int32_t v = htonl((u_int32_t)pp->lifebyte); + x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD, + pp->lifebyte); + } + } + + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_ENC_MODE, pr->encmode); + + if (tr->encklen) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_KEY_LENGTH, tr->encklen); + + /* mandatory check has done above. */ + if ((pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP && tr->authtype != IPSECDOI_ATTR_AUTH_NONE) + || pr->proto_id == IPSECDOI_PROTO_IPSEC_AH) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_AUTH, tr->authtype); + + if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group)) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_GRP_DESC, + iph2->sainfo->pfs_group); + + /* update length of this transform. */ + trns = (struct isakmp_pl_t *)(p->v + trnsoff); + trns->h.len = htons(sizeof(*trns) + attrlen); + + /* save buffer to pre-next payload */ + np_t = &trns->h.np; + + trnsoff += (sizeof(*trns) + attrlen); + } + + if (np_t == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no suitable proposal was created.\n"); + return NULL; + } + + /* update length of this protocol. */ + prop->h.len = htons(p->l); + + return p; +} + +/* + * create phase2 proposal from policy configuration. + * NOT INCLUDING isakmp general header of SA payload. + * This function is called by initiator only. + */ +int +ipsecdoi_setph2proposal(iph2) + struct ph2handle *iph2; +{ + struct saprop *proposal, *a; + struct saproto *b = NULL; + vchar_t *q; + struct ipsecdoi_sa_b *sab; + struct isakmp_pl_p *prop; + size_t propoff; /* for previous field of type of next payload. */ + + proposal = iph2->proposal; + + iph2->sa = vmalloc(sizeof(*sab)); + if (iph2->sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + return -1; + } + + /* create SA payload */ + sab = (struct ipsecdoi_sa_b *)iph2->sa->v; + sab->doi = htonl(IPSEC_DOI); + sab->sit = htonl(IPSECDOI_SIT_IDENTITY_ONLY); /* XXX configurable ? */ + + prop = NULL; + propoff = 0; + for (a = proposal; a; a = a->next) { + for (b = a->head; b; b = b->next) { +#ifdef ENABLE_NATT + if (iph2->ph1->natt_flags & NAT_DETECTED) { + int udp_diff = iph2->ph1->natt_options->mode_udp_diff; + plog (LLV_INFO, LOCATION, NULL, + "NAT detected -> UDP encapsulation " + "(ENC_MODE %d->%d).\n", + b->encmode, + b->encmode+udp_diff); + /* Tunnel -> UDP-Tunnel, Transport -> UDP_Transport */ + b->encmode += udp_diff; + b->udp_encap = 1; + } +#endif + + q = setph2proposal0(iph2, a, b); + if (q == NULL) { + VPTRINIT(iph2->sa); + return -1; + } + + iph2->sa = vrealloc(iph2->sa, iph2->sa->l + q->l); + if (iph2->sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + if (q) + vfree(q); + return -1; + } + memcpy(iph2->sa->v + iph2->sa->l - q->l, q->v, q->l); + if (propoff != 0) { + prop = (struct isakmp_pl_p *)(iph2->sa->v + + propoff); + prop->h.np = ISAKMP_NPTYPE_P; + } + propoff = iph2->sa->l - q->l; + + vfree(q); + } + } + + return 0; +} + +#ifdef __APPLE__ +/* + * return 1 if all of the given protocols are transport mode. + */ +int +ipsecdoi_tunnelmode(iph2) + struct ph2handle *iph2; +{ + struct saprop *pp; + struct saproto *pr = NULL; + + for (pp = iph2->proposal; pp; pp = pp->next) { + for (pr = pp->head; pr; pr = pr->next) { + if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TUNNEL && + pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC && + pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT) + return 0; + } + } + + return 1; +} +#endif + +/* + * return 1 if all of the given protocols are transport mode. + */ +int +ipsecdoi_transportmode(pp) + struct saprop *pp; +{ + struct saproto *pr = NULL; + + for (; pp; pp = pp->next) { + for (pr = pp->head; pr; pr = pr->next) { + if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS) + return 0; + } + } + + return 1; +} + +int +ipsecdoi_get_defaultlifetime() +{ + return IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; +} + +int +ipsecdoi_checkalgtypes(proto_id, enc, auth, comp) + int proto_id, enc, auth, comp; +{ +#define TMPALGTYPE2STR(n) s_algtype(algclass_ipsec_##n, n) + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + if (enc == 0 || comp != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "ESP enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + case IPSECDOI_PROTO_IPSEC_AH: + if (enc != 0 || auth == 0 || comp != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "AH enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + case IPSECDOI_PROTO_IPCOMP: + if (enc != 0 || auth != 0 || comp == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "IPcomp enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid ipsec protocol %d\n", proto_id); + return -1; + } +#undef TMPALGTYPE2STR + return 0; +} + +int +ipproto2doi(proto) + int proto; +{ + switch (proto) { + case IPPROTO_AH: + return IPSECDOI_PROTO_IPSEC_AH; + case IPPROTO_ESP: + return IPSECDOI_PROTO_IPSEC_ESP; + case IPPROTO_IPCOMP: + return IPSECDOI_PROTO_IPCOMP; + } + return -1; /* XXX */ +} + +int +doi2ipproto(proto) + int proto; +{ + switch (proto) { + case IPSECDOI_PROTO_IPSEC_AH: + return IPPROTO_AH; + case IPSECDOI_PROTO_IPSEC_ESP: + return IPPROTO_ESP; + case IPSECDOI_PROTO_IPCOMP: + return IPPROTO_IPCOMP; + } + return -1; /* XXX */ +} + +/* + * check the following: + * - In main mode with pre-shared key, only address type can be used. + * - if proper type for phase 1 ? + * - if phase 1 ID payload conformed RFC2407 4.6.2. + * (proto, port) must be (0, 0), (udp, 500) or (udp, [specified]). + * - if ID payload sent from peer is equal to the ID expected by me. + * + * both of "id" and "id_p" should be ID payload without general header, + */ +int +ipsecdoi_checkid1(iph1) + struct ph1handle *iph1; +{ + struct ipsecdoi_id_b *id_b; + struct sockaddr *sa; + caddr_t sa1, sa2; + + if (iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid iph1 passed id_p == NULL\n"); + return ISAKMP_INTERNAL_ERROR; + } + if (iph1->id_p->l < sizeof(*id_b)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid value passed as \"ident\" (len=%lu)\n", + (u_long)iph1->id_p->l); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; + + /* In main mode with pre-shared key, only address type can be used. + * If NAT Traversal being used and peer is behind nat and + * natt version = 02 - allow non-address ID type. + */ + if (iph1->etype == ISAKMP_ETYPE_IDENT + && iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY +#ifdef ENABLE_NATT + && (iph1->natt_flags & NAT_DETECTED_PEER) == 0 +#endif + ) { + if (id_b->type != IPSECDOI_ID_IPV4_ADDR + && id_b->type != IPSECDOI_ID_IPV6_ADDR) { + plog(LLV_ERROR, LOCATION, NULL, + "Expecting IP address type in main mode, " + "but %s.\n", s_ipsecdoi_ident(id_b->type)); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + } + + /* if proper type for phase 1 ? */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + plog(LLV_WARNING, LOCATION, NULL, + "such ID type %s is not proper.\n", + s_ipsecdoi_ident(id_b->type)); + /*FALLTHROUGH*/ + } + + /* if phase 1 ID payload conformed RFC2407 4.6.2. */ + if (id_b->type == IPSECDOI_ID_IPV4_ADDR || // %%%% BUG_FIX - should be || not && + id_b->type == IPSECDOI_ID_IPV6_ADDR) { + + if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) { + plog(LLV_WARNING, LOCATION, NULL, + "protocol ID and Port mismatched. " + "proto_id:%d port:%d\n", + id_b->proto_id, ntohs(id_b->port)); + /*FALLTHROUGH*/ + + } else if (id_b->proto_id == IPPROTO_UDP) { + /* + * copmaring with expected port. + * always permit if port is equal to PORT_ISAKMP + */ + if (ntohs(id_b->port) != PORT_ISAKMP) { + + u_int16_t port; + + switch (iph1->remote->sa_family) { + case AF_INET: + port = ((struct sockaddr_in *)iph1->remote)->sin_port; + break; +#ifdef INET6 + case AF_INET6: + port = ((struct sockaddr_in6 *)iph1->remote)->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + iph1->remote->sa_family); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + if (ntohs(id_b->port) != port) { + plog(LLV_WARNING, LOCATION, NULL, + "port %d expected, but %d\n", + port, ntohs(id_b->port)); + /*FALLTHROUGH*/ + } + } + } + } + + /* compare with the ID if specified. */ + if (genlist_next(iph1->rmconf->idvl_p, 0)) { + vchar_t *ident0 = NULL; + vchar_t ident; + struct idspec *id; + struct genlist_entry *gpb; + + for (id = genlist_next (iph1->rmconf->idvl_p, &gpb); id; id = genlist_next (0, &gpb)) { + /* check the type of both IDs */ + if (id->idtype != doi2idtype(id_b->type)) + continue; /* ID type mismatch */ + if (id->id == 0) + goto matched; + + /* compare defined ID with the ID sent by peer. */ + if (ident0 != NULL) + vfree(ident0); + ident0 = getidval(id->idtype, id->id); + + switch (id->idtype) { + case IDTYPE_ASN1DN: + ident.v = (caddr_t)(id_b + 1); + ident.l = iph1->id_p->l - 1; /* had ident.l = ident0->l; but why?? */ + /* is the actual packet contents length sometimes wrong? */ + if (eay_cmp_asn1dn(ident0, &ident) == 0) + goto matched; + break; + case IDTYPE_ADDRESS: + sa = (struct sockaddr *)ident0->v; + sa2 = (caddr_t)(id_b + 1); + switch (sa->sa_family) { + case AF_INET: + if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in_addr)) + continue; /* ID value mismatch */ + sa1 = (caddr_t)&((struct sockaddr_in *)sa)->sin_addr; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0) + goto matched; + break; +#ifdef INET6 + case AF_INET6: + if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in6_addr)) + continue; /* ID value mismatch */ + sa1 = (caddr_t)&((struct sockaddr_in6 *)sa)->sin6_addr; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0) + goto matched; + break; +#endif + default: + break; + } + break; + default: + if (memcmp(ident0->v, id_b + 1, ident0->l) == 0) + goto matched; + break; + } + } + if (ident0 != NULL) { + vfree(ident0); + ident0 = NULL; + } + plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n"); + if (iph1->rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; +matched: /* ID value match */ + if (ident0 != NULL) + vfree(ident0); + } + + return 0; +} + +/* + * create ID payload for phase 1 and set into iph1->id. + * NOT INCLUDING isakmp general header. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_setid1(iph1) + struct ph1handle *iph1; +{ + vchar_t *ret = NULL; + struct ipsecdoi_id_b id_b; + vchar_t *ident = NULL; + struct sockaddr *ipid = NULL; + + /* init */ + id_b.proto_id = 0; + id_b.port = 0; + ident = NULL; + + switch (iph1->rmconf->idvtype) { + case IDTYPE_FQDN: + id_b.type = IPSECDOI_ID_FQDN; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; + case IDTYPE_USERFQDN: + id_b.type = IPSECDOI_ID_USER_FQDN; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; + case IDTYPE_KEYID: +#ifdef __APPLE__ + case IDTYPE_KEYIDUSE: +#endif + id_b.type = IPSECDOI_ID_KEY_ID; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; + case IDTYPE_ASN1DN: + id_b.type = IPSECDOI_ID_DER_ASN1_DN; + if (iph1->rmconf->idv) { + /* XXX it must be encoded to asn1dn. */ + ident = vdup(iph1->rmconf->idv); + } else { + if (oakley_getmycert(iph1) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get own CERT.\n"); + goto err; + } + ident = eay_get_x509asn1subjectname(&iph1->cert->cert); + } + break; + case IDTYPE_ADDRESS: + /* + * if the value of the id type was set by the configuration + * file, then use it. otherwise the value is get from local + * ip address by using ike negotiation. + */ + if (iph1->rmconf->idv) + ipid = (struct sockaddr *)iph1->rmconf->idv->v; + /*FALLTHROUGH*/ + default: + { + int l; + caddr_t p; + + if (ipid == NULL) + ipid = iph1->local; + + /* use IP address */ + switch (ipid->sa_family) { + case AF_INET: + id_b.type = IPSECDOI_ID_IPV4_ADDR; + l = sizeof(struct in_addr); + p = (caddr_t)&((struct sockaddr_in *)ipid)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + id_b.type = IPSECDOI_ID_IPV6_ADDR; + l = sizeof(struct in6_addr); + p = (caddr_t)&((struct sockaddr_in6 *)ipid)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid address family.\n"); + goto err; + } + id_b.proto_id = IPPROTO_UDP; + id_b.port = htons(PORT_ISAKMP); + ident = vmalloc(l); + if (!ident) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return 0; + } + memcpy(ident->v, p, ident->l); + } + } + if (!ident) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return 0; + } + + ret = vmalloc(sizeof(id_b) + ident->l); + if (ret == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + goto err; + } + + memcpy(ret->v, &id_b, sizeof(id_b)); + memcpy(ret->v + sizeof(id_b), ident->v, ident->l); + + iph1->id = ret; + + plog(LLV_DEBUG, LOCATION, NULL, + "use ID type of %s\n", s_ipsecdoi_ident(id_b.type)); + if (ident) + vfree(ident); + return 0; + +err: + if (ident) + vfree(ident); + plog(LLV_ERROR, LOCATION, NULL, "failed get my ID\n"); + return -1; +} + +static vchar_t * +getidval(type, val) + int type; + vchar_t *val; +{ + vchar_t *new = NULL; + + if (val) + new = vdup(val); + else if (lcconf->ident[type]) + new = vdup(lcconf->ident[type]); + + return new; +} + +/* it's only called by cfparse.y. */ +int +set_identifier(vpp, type, value) + vchar_t **vpp, *value; + int type; +{ + vchar_t *new = NULL; + + /* simply return if value is null. */ + if (!value){ + if( type == IDTYPE_FQDN || type == IDTYPE_USERFQDN){ + plog(LLV_ERROR, LOCATION, NULL, + "No %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn"); + return -1; + } + return 0; + } + + switch (type) { + case IDTYPE_FQDN: + case IDTYPE_USERFQDN: + if(value->l <= 1){ + plog(LLV_ERROR, LOCATION, NULL, + "Empty %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn"); + return -1; + } +#ifdef __APPLE__ + case IDTYPE_KEYIDUSE: +#endif +#ifdef ENABLE_HYBRID + case IDTYPE_LOGIN: +#endif + /* length is adjusted since QUOTEDSTRING teminates NULL. */ + new = vmalloc(value->l - 1); + if (new == NULL) + return -1; + memcpy(new->v, value->v, new->l); + break; + case IDTYPE_KEYID: + { + FILE *fp; + char b[512]; + int tlen, len; + + fp = fopen(value->v, "r"); + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "can not open %s\n", value->v); + return -1; + } + tlen = 0; + while ((len = fread(b, 1, sizeof(b), fp)) != 0) { + new = vrealloc(new, tlen + len); + if (!new) { + fclose(fp); + return -1; + } + memcpy(new->v + tlen, b, len); + tlen += len; + } + break; + } + case IDTYPE_ADDRESS: + { + struct sockaddr *sa; + + /* length is adjusted since QUOTEDSTRING teminates NULL. */ + if (value->l == 0) + break; + + sa = str2saddr(value->v, NULL); + if (sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid ip address %s\n", value->v); + return -1; + } + + new = vmalloc(sysdep_sa_len(sa)); + if (new == NULL) + return -1; + memcpy(new->v, sa, new->l); + break; + } + case IDTYPE_ASN1DN: + if (value->v[0] == '~') + /* Hex-encoded ASN1 strings */ + new = eay_hex2asn1dn(value->v + 1, - 1); + else + /* DN encoded strings */ + new = eay_str2asn1dn(value->v, value->l - 1); + + if (new == NULL) + return -1; + + if (loglevel >= LLV_DEBUG) { + X509_NAME *xn; + BIO *bio; + unsigned char *ptr = (unsigned char *) new->v, *buf; + size_t len; + char save; + + xn = d2i_X509_NAME(NULL, (void *)&ptr, new->l); + bio = BIO_new(BIO_s_mem()); + + X509_NAME_print_ex(bio, xn, 0, 0); + len = BIO_get_mem_data(bio, &ptr); + save = ptr[len]; + ptr[len] = 0; + plog(LLV_DEBUG, LOCATION, NULL, "Parsed DN: %s\n", ptr); + ptr[len] = save; + X509_NAME_free(xn); + BIO_free(bio); + } + + break; + } + + *vpp = new; + + return 0; +} + +/* + * create ID payload for phase 2, and set into iph2->id and id_p. There are + * NOT INCLUDING isakmp general header. + * this function is for initiator. responder will get to copy from payload. + * responder ID type is always address type. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_setid2(iph2) + struct ph2handle *iph2; +{ + struct secpolicy *sp; + + /* check there is phase 2 handler ? */ + sp = getspbyspid(iph2->spid); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found for spid:%u.\n", iph2->spid); + return -1; + } + + iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + if (iph2->id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp->spidx)); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, "use local ID type %s\n", + s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type)); + + /* remote side */ + iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, sp->spidx.ul_proto); + if (iph2->id_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp->spidx)); + VPTRINIT(iph2->id); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "use remote ID type %s\n", + s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id_p->v)->type)); + + return 0; +} + +/* + * set address type of ID. + * NOT INCLUDING general header. + */ +vchar_t * +ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + vchar_t *new; + int type, len1, len2; + caddr_t sa; + u_short port; + + /* + * Q. When type is SUBNET, is it allowed to be ::1/128. + * A. Yes. (consensus at bake-off) + */ + switch (saddr->sa_family) { + case AF_INET: + len1 = sizeof(struct in_addr); + if ( +#if 0 + prefixlen == ~0 +#else + prefixlen == (sizeof(struct in_addr) << 3) +#endif + ) { + type = IPSECDOI_ID_IPV4_ADDR; + len2 = 0; + } else { + type = IPSECDOI_ID_IPV4_ADDR_SUBNET; + len2 = sizeof(struct in_addr); + } + sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr; + port = ((struct sockaddr_in *)(saddr))->sin_port; + break; +#ifdef INET6 + case AF_INET6: + len1 = sizeof(struct in6_addr); + if ( +#if 0 + prefixlen == ~0 +#else + prefixlen == (sizeof(struct in6_addr) << 3) +#endif + ) { + type = IPSECDOI_ID_IPV6_ADDR; + len2 = 0; + } else { + type = IPSECDOI_ID_IPV6_ADDR_SUBNET; + len2 = sizeof(struct in6_addr); + } + sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr; + port = ((struct sockaddr_in6 *)(saddr))->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d.\n", saddr->sa_family); + return NULL; + } + + /* get ID buffer */ + new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return NULL; + } + + memset(new->v, 0, new->l); + + /* set the part of header. */ + ((struct ipsecdoi_id_b *)new->v)->type = type; + + /* set ul_proto and port */ + /* + * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card + * because 0 means port number of 0. Instead of 0, we use IPSEC_*_ANY. + */ + ((struct ipsecdoi_id_b *)new->v)->proto_id = + ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto; + ((struct ipsecdoi_id_b *)new->v)->port = + port == IPSEC_PORT_ANY ? 0 : port; + memcpy(new->v + sizeof(struct ipsecdoi_id_b), sa, len1); + + /* set address */ + + /* set prefix */ + if (len2) { + u_char *p = (unsigned char *) new->v + + sizeof(struct ipsecdoi_id_b) + len1; + u_int bits = prefixlen; + + while (bits >= 8) { + *p++ = 0xff; + bits -= 8; + } + + if (bits > 0) + *p = ~((1 << (8 - bits)) - 1); + } + + return new; +} + +/* + * create sockaddr structure from ID payload (buf). + * buffers (saddr, prefixlen, ul_proto) must be allocated. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) + vchar_t *buf; + struct sockaddr *saddr; + u_int8_t *prefixlen; + u_int16_t *ul_proto; +{ + struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v; + u_int plen = 0; + + /* + * When a ID payload of subnet type with a IP address of full bit + * masked, it has to be processed as host address. + * e.g. below 2 type are same. + * type = ipv6 subnet, data = 2001::1/128 + * type = ipv6 address, data = 2001::1 + */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in); +#endif + saddr->sa_family = AF_INET; + ((struct sockaddr_in *)saddr)->sin_port = + (id_b->port == 0 + ? IPSEC_PORT_ANY + : id_b->port); /* see sockaddr2id() */ + memcpy(&((struct sockaddr_in *)saddr)->sin_addr, + buf->v + sizeof(*id_b), sizeof(struct in_addr)); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in6); +#endif + saddr->sa_family = AF_INET6; + ((struct sockaddr_in6 *)saddr)->sin6_port = + (id_b->port == 0 + ? IPSEC_PORT_ANY + : id_b->port); /* see sockaddr2id() */ + memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr, + buf->v + sizeof(*id_b), sizeof(struct in6_addr)); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported ID type %d\n", id_b->type); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + /* get prefix length */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + case IPSECDOI_ID_IPV4_ADDR_SUBNET: +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: +#endif + { + u_char *p; + u_int max; + int alen = sizeof(struct in_addr); + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + alen = sizeof(struct in_addr); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + alen = sizeof(struct in6_addr); + break; +#endif + } + + /* sanity check */ + if (buf->l < alen) + return ISAKMP_INTERNAL_ERROR; + + /* get subnet mask length */ + plen = 0; + max = alen <<3; + + p = (unsigned char *) buf->v + + sizeof(struct ipsecdoi_id_b) + + alen; + + for (; *p == 0xff; p++) { + if (plen >= max) + break; + plen += 8; + } + + if (plen < max) { + u_int l = 0; + u_char b = ~(*p); + + while (b) { + b >>= 1; + l++; + } + + l = 8 - l; + plen += l; + } + } + break; + } + + *prefixlen = plen; + *ul_proto = id_b->proto_id == 0 + ? IPSEC_ULPROTO_ANY + : id_b->proto_id; /* see sockaddr2id() */ + + return 0; +} + +/* + * make printable string from ID payload except of general header. + */ +const char * +ipsecdoi_id2str(id) + const vchar_t *id; +{ + static char buf[256]; + + /* XXX */ + buf[0] = '\0'; + + return buf; +} + +/* + * set IPsec data attributes into a proposal. + * NOTE: MUST called per a transform. + */ +int +ipsecdoi_t2satrns(t, pp, pr, tr) + struct isakmp_pl_t *t; + struct saprop *pp; + struct saproto *pr; + struct satrns *tr; +{ + struct isakmp_data *d, *prev; + int flag, type; + int error = -1; + int life_t; + int tlen; + + tr->trns_no = t->t_no; + tr->trns_id = t->t_id; + + tlen = ntohs(t->h.len) - sizeof(*t); + prev = (struct isakmp_data *)NULL; + d = (struct isakmp_data *)(t + 1); + + /* default */ + life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT; + pp->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; + pp->lifebyte = 0; + tr->authtype = IPSECDOI_ATTR_AUTH_NONE; + + while (tlen > 0) { + + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_ipsecdoi_attr(type), flag, + s_ipsecdoi_attr_v(type, ntohs(d->lorv))); + + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE: + { + int type = ntohs(d->lorv); + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + life_t = type; + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "invalid life duration type. " + "use default\n"); + life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT; + break; + } + break; + } + case IPSECDOI_ATTR_SA_LD: + if (prev == NULL + || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) != + IPSECDOI_ATTR_SA_LD_TYPE) { + plog(LLV_ERROR, LOCATION, NULL, + "life duration must follow ltype\n"); + break; + } + + { + u_int32_t t; + vchar_t *ld_buf = NULL; + + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + ld_buf = vmalloc(sizeof(d->lorv)); + if (ld_buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get LD buffer.\n"); + goto end; + } + memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv)); + } else { + int len = ntohs(d->lorv); + /* i.e. ISAKMP_GEN_TLV */ + ld_buf = vmalloc(len); + if (ld_buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get LD buffer.\n"); + goto end; + } + memcpy(ld_buf->v, d + 1, len); + } + switch (life_t) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + t = ipsecdoi_set_ld(ld_buf); + vfree(ld_buf); + if (t == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto end; + } + /* lifetime must be equal in a proposal. */ + if (pp->lifetime == IPSECDOI_ATTR_SA_LD_SEC_DEFAULT) + pp->lifetime = t; + else if (pp->lifetime != t) { + plog(LLV_ERROR, LOCATION, NULL, + "lifetime mismatched " + "in a proposal, " + "prev:%ld curr:%u.\n", + (long)pp->lifetime, t); + goto end; + } + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + t = ipsecdoi_set_ld(ld_buf); + vfree(ld_buf); + if (t == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto end; + } + /* lifebyte must be equal in a proposal. */ + if (pp->lifebyte == 0) + pp->lifebyte = t; + else if (pp->lifebyte != t) { + plog(LLV_ERROR, LOCATION, NULL, + "lifebyte mismatched " + "in a proposal, " + "prev:%d curr:%u.\n", + pp->lifebyte, t); + goto end; + } + break; + default: + vfree(ld_buf); + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type: %d\n", life_t); + goto end; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + /* + * RFC2407: 4.5 IPSEC Security Association Attributes + * Specifies the Oakley Group to be used in a PFS QM + * negotiation. For a list of supported values, see + * Appendix A of [IKE]. + */ + if (pp->pfs_group == 0) + pp->pfs_group = (u_int16_t)ntohs(d->lorv); + else if (pp->pfs_group != (u_int16_t)ntohs(d->lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs_group mismatched " + "in a proposal.\n"); + goto end; + } + break; + + case IPSECDOI_ATTR_ENC_MODE: + if (pr->encmode && + pr->encmode != (u_int16_t)ntohs(d->lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple encmode exist " + "in a transform.\n"); + goto end; + } + pr->encmode = (u_int16_t)ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_AUTH: + if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple authtype exist " + "in a transform.\n"); + goto end; + } + tr->authtype = (u_int16_t)ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_KEY_LENGTH: + if (pr->proto_id != IPSECDOI_PROTO_IPSEC_ESP) { + plog(LLV_ERROR, LOCATION, NULL, + "key length defined but not ESP"); + goto end; + } + tr->encklen = ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + default: + break; + } + + prev = d; + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + ntohs(d->lorv)); + d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv)); + } + } + + error = 0; +end: + return error; +} + +int +ipsecdoi_authalg2trnsid(alg) + int alg; +{ + switch (alg) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + return IPSECDOI_AH_MD5; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + return IPSECDOI_AH_SHA; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256: + return IPSECDOI_AH_SHA256; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384: + return IPSECDOI_AH_SHA384; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512: + return IPSECDOI_AH_SHA512; + case IPSECDOI_ATTR_AUTH_DES_MAC: + return IPSECDOI_AH_DES; + case IPSECDOI_ATTR_AUTH_KPDK: + return IPSECDOI_AH_MD5; /* XXX */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication algorithm:%d\n", alg); + } + return -1; +} + +#ifdef HAVE_GSSAPI +struct isakmpsa * +fixup_initiator_sa(match, received) + struct isakmpsa *match, *received; +{ + if (received->gssid != NULL) + match->gssid = vdup(received->gssid); + + return match; +} +#endif + +static int rm_idtype2doi[] = { + 255, /* IDTYPE_UNDEFINED, 0 */ + IPSECDOI_ID_FQDN, /* IDTYPE_FQDN, 1 */ + IPSECDOI_ID_USER_FQDN, /* IDTYPE_USERFQDN, 2 */ + IPSECDOI_ID_KEY_ID, /* IDTYPE_KEYID, 3 */ + 255, /* IDTYPE_ADDRESS, 4 + * it expands into 4 types by another function. */ + IPSECDOI_ID_DER_ASN1_DN, /* IDTYPE_ASN1DN, 5 */ +#ifdef ENABLE_HYBRID + 255, /* IDTYPE_LOGIN, 6 */ +#endif +}; + +/* + * convert idtype to DOI value. + * OUT 255 : NG + * other: converted. + */ +int +idtype2doi(idtype) + int idtype; +{ + if (ARRAYLEN(rm_idtype2doi) > idtype) + return rm_idtype2doi[idtype]; + return 255; +} + +int +doi2idtype(doi) + int doi; +{ + switch(doi) { + case IPSECDOI_ID_FQDN: + return(IDTYPE_FQDN); + case IPSECDOI_ID_USER_FQDN: + return(IDTYPE_USERFQDN); + case IPSECDOI_ID_KEY_ID: + return(IDTYPE_KEYID); + case IPSECDOI_ID_DER_ASN1_DN: + return(IDTYPE_ASN1DN); + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + return(IDTYPE_ADDRESS); + default: + plog(LLV_WARNING, LOCATION, NULL, + "Inproper idtype:%s in this function.\n", + s_ipsecdoi_ident(doi)); + return(IDTYPE_ADDRESS); /* XXX */ + } + /*NOTREACHED*/ +} + +#ifdef ENABLE_HYBRID +static int +switch_authmethod(authmethod) + int authmethod; +{ + switch(authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I; + break; + /* Those are not implemented */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I; + break; + default: + break; + } + + return authmethod; +} +#endif diff --git a/ipsec-tools/racoon/ipsec_doi.h b/ipsec-tools/racoon/ipsec_doi.h new file mode 100644 index 0000000..9d5e7a9 --- /dev/null +++ b/ipsec-tools/racoon/ipsec_doi.h @@ -0,0 +1,249 @@ +/* $Id: ipsec_doi.h,v 1.9.2.2 2005/10/17 16:23:50 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _IPSEC_DOI_H +#define _IPSEC_DOI_H + +/* refered to RFC2407 */ + +#define IPSEC_DOI 1 + +/* 4.2 IPSEC Situation Definition */ +#define IPSECDOI_SIT_IDENTITY_ONLY 0x00000001 +#define IPSECDOI_SIT_SECRECY 0x00000002 +#define IPSECDOI_SIT_INTEGRITY 0x00000004 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ + /* 4.4.2 IPSEC ISAKMP Transform Values */ +#define IPSECDOI_PROTO_ISAKMP 1 +#define IPSECDOI_KEY_IKE 1 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPSEC_AH 2 + /* 4.4.3 IPSEC AH Transform Values */ +#define IPSECDOI_AH_MD5 2 +#define IPSECDOI_AH_SHA 3 +#define IPSECDOI_AH_DES 4 +#define IPSECDOI_AH_SHA256 5 +#define IPSECDOI_AH_SHA384 6 +#define IPSECDOI_AH_SHA512 7 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPSEC_ESP 3 + /* 4.4.4 IPSEC ESP Transform Identifiers */ +#define IPSECDOI_ESP_DES_IV64 1 +#define IPSECDOI_ESP_DES 2 +#define IPSECDOI_ESP_3DES 3 +#define IPSECDOI_ESP_RC5 4 +#define IPSECDOI_ESP_IDEA 5 +#define IPSECDOI_ESP_CAST 6 +#define IPSECDOI_ESP_BLOWFISH 7 +#define IPSECDOI_ESP_3IDEA 8 +#define IPSECDOI_ESP_DES_IV32 9 +#define IPSECDOI_ESP_RC4 10 +#define IPSECDOI_ESP_NULL 11 +#define IPSECDOI_ESP_AES 12 +#if 1 + /* draft-ietf-ipsec-ciph-aes-cbc-00.txt */ +#define IPSECDOI_ESP_TWOFISH 253 +#else + /* SSH uses these value for now */ +#define IPSECDOI_ESP_TWOFISH 250 +#endif + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPCOMP 4 + /* 4.4.5 IPSEC IPCOMP Transform Identifiers */ +#define IPSECDOI_IPCOMP_OUI 1 +#define IPSECDOI_IPCOMP_DEFLATE 2 +#define IPSECDOI_IPCOMP_LZS 3 + +/* 4.5 IPSEC Security Association Attributes */ +/* NOTE: default value is not included in a packet. */ +#define IPSECDOI_ATTR_SA_LD_TYPE 1 /* B */ +#define IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT 1 +#define IPSECDOI_ATTR_SA_LD_TYPE_SEC 1 +#define IPSECDOI_ATTR_SA_LD_TYPE_KB 2 +#define IPSECDOI_ATTR_SA_LD_TYPE_MAX 3 +#define IPSECDOI_ATTR_SA_LD 2 /* V */ +#define IPSECDOI_ATTR_SA_LD_SEC_DEFAULT 28800 /* 8 hours */ +#define IPSECDOI_ATTR_SA_LD_KB_MAX (~(1 << ((sizeof(int) << 3) - 1))) +#define IPSECDOI_ATTR_GRP_DESC 3 /* B */ +#define IPSECDOI_ATTR_ENC_MODE 4 /* B */ + /* default value: host dependent */ +#define IPSECDOI_ATTR_ENC_MODE_ANY 0 /* NOTE:internal use */ +#define IPSECDOI_ATTR_ENC_MODE_TUNNEL 1 +#define IPSECDOI_ATTR_ENC_MODE_TRNS 2 + +/* NAT-T draft-ietf-ipsec-nat-t-ike-05 and later */ +#define IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC 3 +#define IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC 4 + +/* NAT-T up to draft-ietf-ipsec-nat-t-ike-04 */ +#define IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT 61443 +#define IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT 61444 + +#define IPSECDOI_ATTR_AUTH 5 /* B */ + /* 0 means not to use authentication. */ +#define IPSECDOI_ATTR_AUTH_HMAC_MD5 1 +#define IPSECDOI_ATTR_AUTH_HMAC_SHA1 2 +#define IPSECDOI_ATTR_AUTH_DES_MAC 3 +#define IPSECDOI_ATTR_AUTH_KPDK 4 /*RFC-1826(Key/Pad/Data/Key)*/ +#define IPSECDOI_ATTR_AUTH_HMAC_SHA2_256 5 +#define IPSECDOI_ATTR_AUTH_HMAC_SHA2_384 6 +#define IPSECDOI_ATTR_AUTH_HMAC_SHA2_512 7 +#define IPSECDOI_ATTR_AUTH_NONE 254 /* NOTE:internal use */ + /* + * When negotiating ESP without authentication, the Auth + * Algorithm attribute MUST NOT be included in the proposal. + * When negotiating ESP without confidentiality, the Auth + * Algorithm attribute MUST be included in the proposal and + * the ESP transform ID must be ESP_NULL. + */ +#define IPSECDOI_ATTR_KEY_LENGTH 6 /* B */ +#define IPSECDOI_ATTR_KEY_ROUNDS 7 /* B */ +#define IPSECDOI_ATTR_COMP_DICT_SIZE 8 /* B */ +#define IPSECDOI_ATTR_COMP_PRIVALG 9 /* V */ + +/* 4.6.1 Security Association Payload */ +struct ipsecdoi_pl_sa { + struct isakmp_gen h; + struct ipsecdoi_sa_b { + u_int32_t doi; /* Domain of Interpretation */ + u_int32_t sit; /* Situation */ + } b; + /* followed by Leveled Domain Identifier and so on. */ +} __attribute__((__packed__)); + +struct ipsecdoi_secrecy_h { + u_int16_t len; + u_int16_t reserved; + /* followed by the value */ +} __attribute__((__packed__)); + +/* 4.6.2 Identification Payload Content */ +struct ipsecdoi_pl_id { + struct isakmp_gen h; + struct ipsecdoi_id_b { + u_int8_t type; /* ID Type */ + u_int8_t proto_id; /* Protocol ID */ + u_int16_t port; /* Port */ + } b; + /* followed by Identification Data */ +} __attribute__((__packed__)); + +#define IPSECDOI_ID_IPV4_ADDR 1 +#define IPSECDOI_ID_FQDN 2 +#define IPSECDOI_ID_USER_FQDN 3 +#define IPSECDOI_ID_IPV4_ADDR_SUBNET 4 +#define IPSECDOI_ID_IPV6_ADDR 5 +#define IPSECDOI_ID_IPV6_ADDR_SUBNET 6 +#define IPSECDOI_ID_IPV4_ADDR_RANGE 7 +#define IPSECDOI_ID_IPV6_ADDR_RANGE 8 +#define IPSECDOI_ID_DER_ASN1_DN 9 +#define IPSECDOI_ID_DER_ASN1_GN 10 +#define IPSECDOI_ID_KEY_ID 11 + +/* compressing doi type, it's internal use. */ +#define IDTYPE_UNDEFINED 0 +#define IDTYPE_FQDN 1 +#define IDTYPE_USERFQDN 2 +#define IDTYPE_KEYID 3 +#define IDTYPE_ADDRESS 4 +#define IDTYPE_ASN1DN 5 +#define IDTYPE_LOGIN 6 +#define IDTYPE_SUBNET 7 +#ifdef __APPLE__ +#define IDTYPE_KEYIDUSE 8 + +/* shared secret type, it's internal use. */ +#define SECRETTYPE_USE 0 +#define SECRETTYPE_KEY 1 +#define SECRETTYPE_KEYCHAIN 2 +#define SECRETTYPE_KEYCHAIN_BY_ID 3 + +/* verification modules */ +#define VERIFICATION_MODULE_OPENSSL 0 +#define VERIFICATION_MODULE_SEC_FRAMEWORK 1 + +/* verification options */ +#define VERIFICATION_OPTION_NONE 0 +#define VERIFICATION_OPTION_PEERS_IDENTIFIER 1 +#define VERIFICATION_OPTION_OPEN_DIR 2 +#endif + +/* The use for checking proposal payload. This is not exchange type. */ +#define IPSECDOI_TYPE_PH1 0 +#define IPSECDOI_TYPE_PH2 1 + +struct isakmpsa; +struct ipsecdoi_pl_sa; +struct saprop; +struct saproto; +struct satrns; +struct prop_pair; + +extern int ipsecdoi_checkph1proposal __P((vchar_t *, struct ph1handle *)); +extern int ipsecdoi_selectph2proposal __P((struct ph2handle *)); +extern int ipsecdoi_checkph2proposal __P((struct ph2handle *)); + +extern struct prop_pair **get_proppair __P((vchar_t *, int)); +extern vchar_t *get_sabyproppair __P((struct prop_pair *, struct ph1handle *)); +extern int ipsecdoi_updatespi __P((struct ph2handle *iph2)); +extern vchar_t *get_sabysaprop __P((struct saprop *, vchar_t *)); +extern int ipsecdoi_checkid1 __P((struct ph1handle *)); +extern int ipsecdoi_setid1 __P((struct ph1handle *)); +extern int set_identifier __P((vchar_t **, int, vchar_t *)); +extern int ipsecdoi_setid2 __P((struct ph2handle *)); +extern vchar_t *ipsecdoi_sockaddr2id __P((struct sockaddr *, u_int, u_int)); +extern int ipsecdoi_id2sockaddr __P((vchar_t *, struct sockaddr *, + u_int8_t *, u_int16_t *)); +extern const char *ipsecdoi_id2str __P((const vchar_t *)); + +extern vchar_t *ipsecdoi_setph1proposal __P((struct isakmpsa *)); +extern int ipsecdoi_setph2proposal __P((struct ph2handle *)); +extern int ipsecdoi_transportmode __P((struct saprop *)); +#ifdef __APPLE__ +extern int ipsecdoi_tunnelmode __P((struct ph2handle *)); +#endif +extern int ipsecdoi_get_defaultlifetime __P((void)); +extern int ipsecdoi_checkalgtypes __P((int, int, int, int)); +extern int ipproto2doi __P((int)); +extern int doi2ipproto __P((int)); + +extern int ipsecdoi_t2satrns __P((struct isakmp_pl_t *, + struct saprop *, struct saproto *, struct satrns *)); +extern int ipsecdoi_authalg2trnsid __P((int)); +extern int idtype2doi __P((int)); +extern int doi2idtype __P((int)); + + +#endif /* _IPSEC_DOI_H */ diff --git a/ipsec-tools/racoon/isakmp.c b/ipsec-tools/racoon/isakmp.c new file mode 100644 index 0000000..5fa5e07 --- /dev/null +++ b/ipsec-tools/racoon/isakmp.c @@ -0,0 +1,3633 @@ +/* $Id: isakmp.c,v 1.34.2.21 2006/02/02 10:31:01 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifdef __APPLE__ +#define __APPLE_API_PRIVATE +#endif + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#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 +#include + +# ifndef SOL_UDP +# define SOL_UDP 17 +# endif +# endif /* __linux__ */ +# if defined(__NetBSD__) || defined(__FreeBSD__) +# include +# include +# 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; +} + +/* %%% + * Interface between PF_KEYv2 and ISAKMP + */ +/* + * receive ACQUIRE from kernel, and begin either phase1 or phase2. + * if phase1 has been finished, begin phase2. + */ +int +isakmp_post_acquire(iph2) + struct ph2handle *iph2; +{ + struct remoteconf *rmconf; + struct ph1handle *iph1 = NULL; + + /* search appropreate configuration with masking port. */ + rmconf = getrmconf(iph2->dst); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no configuration found for %s.\n", + saddrwop2str(iph2->dst)); + return -1; + } + + /* if passive mode, ignore the acquire message */ + if (rmconf->passive) { + plog(LLV_DEBUG, LOCATION, NULL, + "because of passive mode, " + "ignore the acquire message for %s.\n", + saddrwop2str(iph2->dst)); + return 0; + } + + /* + * Search isakmp status table by address and port + * If NAT-T is in use, consider null ports as a + * wildcard and use IKE ports instead. + */ +#ifdef ENABLE_NATT + if (!extract_port(iph2->src) && !extract_port(iph2->dst)) { + if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) { + set_port(iph2->src, extract_port(iph1->local)); + set_port(iph2->dst, extract_port(iph1->remote)); + } + } else { + iph1 = getph1byaddr(iph2->src, iph2->dst); + } +#else + iph1 = getph1byaddr(iph2->src, iph2->dst); +#endif + + /* no ISAKMP-SA found. */ + if (iph1 == NULL) { + struct sched *sc; + + iph2->retry_checkph1 = lcconf->retry_checkph1; + sc = sched_new(1, isakmp_chkph1there_stub, iph2); + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA request for %s queued " + "due to no phase1 found.\n", + saddrwop2str(iph2->dst)); + + /* start phase 1 negotiation as a initiator. */ + if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src) < 0) { + SCHED_KILL(sc); + return -1; + } + + return 0; + /*NOTREACHED*/ + } + + /* found ISAKMP-SA, but on negotiation. */ + if (iph1->status != PHASE1ST_ESTABLISHED) { + iph2->retry_checkph1 = lcconf->retry_checkph1; + sched_new(1, isakmp_chkph1there_stub, iph2); + plog(LLV_INFO, LOCATION, iph2->dst, + "request for establishing IPsec-SA was queued " + "due to no phase1 found.\n"); + return 0; + /*NOTREACHED*/ + } + + /* found established ISAKMP-SA */ + /* i.e. iph1->status == PHASE1ST_ESTABLISHED */ + + /* found ISAKMP-SA. */ + plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); + + /* begin quick mode */ + if (isakmp_ph2begin_i(iph1, iph2)) + return -1; + + return 0; +} + +/* + * receive GETSPI from kernel. + */ +int +isakmp_post_getspi(iph2) + struct ph2handle *iph2; +{ +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* don't process it because there is no suitable phase1-sa. */ + if (iph2->ph1->status == PHASE1ST_EXPIRED) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "the negotiation is stopped, " + "because there is no suitable ISAKMP-SA.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] + [iph2->side] + [iph2->status])(iph2, NULL) != 0) + return -1; +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", + s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* called by scheduler */ +void +isakmp_chkph1there_stub(p) + void *p; +{ + isakmp_chkph1there((struct ph2handle *)p); +} + +void +isakmp_chkph1there(iph2) + struct ph2handle *iph2; +{ + struct ph1handle *iph1; + + iph2->retry_checkph1--; + if (iph2->retry_checkph1 < 0) { + plog(LLV_ERROR, LOCATION, iph2->dst, + "phase2 negotiation failed " + "due to time up waiting for phase1. %s\n", + sadbsecas2str(iph2->dst, iph2->src, + iph2->satype, 0, 0)); + plog(LLV_INFO, LOCATION, NULL, + "delete phase 2 handler.\n"); + + /* send acquire to kernel as error */ + pk_sendeacquire(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return; + } + + /* + * Search isakmp status table by address and port + * If NAT-T is in use, consider null ports as a + * wildcard and use IKE ports instead. + */ +#ifdef ENABLE_NATT + if (!extract_port(iph2->src) && !extract_port(iph2->dst)) { + if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) { + /* + * cannot set ph2 ports until after switch to natt port + * otherwise this function will never again find phase 1 + */ + if (iph1->status == PHASE1ST_ESTABLISHED) { + set_port(iph2->src, extract_port(iph1->local)); + set_port(iph2->dst, extract_port(iph1->remote)); + } + } + } else { + iph1 = getph1byaddr(iph2->src, iph2->dst); + } +#else + iph1 = getph1byaddr(iph2->src, iph2->dst); +#endif + + /* XXX Even if ph1 as responder is there, should we not start + * phase 2 negotiation ? */ + if (iph1 != NULL + && iph1->status == PHASE1ST_ESTABLISHED) { + /* found isakmp-sa */ + /* begin quick mode */ + (void)isakmp_ph2begin_i(iph1, iph2); + return; + } + + /* no isakmp-sa found */ + sched_new(1, isakmp_chkph1there_stub, iph2); + + return; +} + +/* copy variable data into ALLOCATED buffer. */ +caddr_t +isakmp_set_attr_v(buf, type, val, len) + caddr_t buf; + int type; + caddr_t val; + int len; +{ + struct isakmp_data *data; + + data = (struct isakmp_data *)buf; + data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV); + data->lorv = htons((u_int16_t)len); + memcpy(data + 1, val, len); + + return buf + sizeof(*data) + len; +} + +/* copy fixed length data into ALLOCATED buffer. */ +caddr_t +isakmp_set_attr_l(buf, type, val) + caddr_t buf; + int type; + u_int32_t val; +{ + struct isakmp_data *data; + + data = (struct isakmp_data *)buf; + data->type = htons((u_int16_t)type | ISAKMP_GEN_TV); + data->lorv = htons((u_int16_t)val); + + return buf + sizeof(*data); +} + +/* add a variable data attribute to the buffer by reallocating it. */ +vchar_t * +isakmp_add_attr_v(buf0, type, val, len) + vchar_t *buf0; + int type; + caddr_t val; + int len; +{ + vchar_t *buf = NULL; + struct isakmp_data *data; + int tlen; + int oldlen = 0; + + tlen = sizeof(*data) + len; + + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, oldlen + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a attribute buffer.\n"); + return NULL; + } + + data = (struct isakmp_data *)(buf->v + oldlen); + data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV); + data->lorv = htons((u_int16_t)len); + memcpy(data + 1, val, len); + + return buf; +} + +/* add a fixed data attribute to the buffer by reallocating it. */ +vchar_t * +isakmp_add_attr_l(buf0, type, val) + vchar_t *buf0; + int type; + u_int32_t val; +{ + vchar_t *buf = NULL; + struct isakmp_data *data; + int tlen; + int oldlen = 0; + + tlen = sizeof(*data); + + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, oldlen + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a attribute buffer.\n"); + return NULL; + } + + data = (struct isakmp_data *)(buf->v + oldlen); + data->type = htons((u_int16_t)type | ISAKMP_GEN_TV); + data->lorv = htons((u_int16_t)val); + + return buf; +} + +/* + * calculate cookie and set. + */ +int +isakmp_newcookie(place, remote, local) + caddr_t place; + struct sockaddr *remote; + struct sockaddr *local; +{ + vchar_t *buf = NULL, *buf2 = NULL; + char *p; + int blen; + int alen; + caddr_t sa1, sa2; + time_t t; + int error = -1; + u_short port; + + + if (remote->sa_family != local->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch, remote:%d local:%d\n", + remote->sa_family, local->sa_family); + goto end; + } + switch (remote->sa_family) { + case AF_INET: + alen = sizeof(struct in_addr); + sa1 = (caddr_t)&((struct sockaddr_in *)remote)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)local)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + alen = sizeof(struct in_addr); + sa1 = (caddr_t)&((struct sockaddr_in6 *)remote)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)local)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", remote->sa_family); + goto end; + } + blen = (alen + sizeof(u_short)) * 2 + + sizeof(time_t) + lcconf->secret_size; + buf = vmalloc(blen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a cookie.\n"); + goto end; + } + p = buf->v; + + /* copy my address */ + memcpy(p, sa1, alen); + p += alen; + port = ((struct sockaddr_in *)remote)->sin_port; + memcpy(p, &port, sizeof(u_short)); + p += sizeof(u_short); + + /* copy target address */ + memcpy(p, sa2, alen); + p += alen; + port = ((struct sockaddr_in *)local)->sin_port; + memcpy(p, &port, sizeof(u_short)); + p += sizeof(u_short); + + /* copy time */ + t = time(0); + memcpy(p, (caddr_t)&t, sizeof(t)); + p += sizeof(t); + + /* copy random value */ + buf2 = eay_set_random(lcconf->secret_size); + if (buf2 == NULL) + goto end; + memcpy(p, buf2->v, lcconf->secret_size); + p += lcconf->secret_size; + vfree(buf2); + + buf2 = eay_sha1_one(buf); + memcpy(place, buf2->v, sizeof(cookie_t)); + + sa1 = val2str(place, sizeof (cookie_t)); + plog(LLV_DEBUG, LOCATION, NULL, "new cookie:\n%s\n", sa1); + racoon_free(sa1); + + error = 0; +end: + if (buf != NULL) + vfree(buf); + if (buf2 != NULL) + vfree(buf2); + return error; +} + +/* + * save partner's(payload) data into phhandle. + */ +int +isakmp_p2ph(buf, gen) + vchar_t **buf; + struct isakmp_gen *gen; +{ + /* XXX to be checked in each functions for logging. */ + if (*buf) { + plog(LLV_WARNING, LOCATION, NULL, + "ignore this payload, same payload type exist.\n"); + return -1; + } + + *buf = vmalloc(ntohs(gen->len) - sizeof(*gen)); + if (*buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return -1; + } + memcpy((*buf)->v, gen + 1, (*buf)->l); + + return 0; +} + +u_int32_t +isakmp_newmsgid2(iph1) + struct ph1handle *iph1; +{ + u_int32_t msgid2; + + do { + msgid2 = eay_random(); + } while (getph2bymsgid(iph1, msgid2)); + + return msgid2; +} + +/* + * set values into allocated buffer of isakmp header for phase 1 + */ +static caddr_t +set_isakmp_header(vbuf, iph1, nptype, etype, flags, msgid) + vchar_t *vbuf; + struct ph1handle *iph1; + int nptype; + u_int8_t etype; + u_int8_t flags; + u_int32_t msgid; +{ + struct isakmp *isakmp; + + if (vbuf->l < sizeof(*isakmp)) + return NULL; + + isakmp = (struct isakmp *)vbuf->v; + + memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = nptype; + isakmp->v = iph1->version; + isakmp->etype = etype; + isakmp->flags = flags; + isakmp->msgid = msgid; + isakmp->len = htonl(vbuf->l); + + return vbuf->v + sizeof(*isakmp); +} + +/* + * set values into allocated buffer of isakmp header for phase 1 + */ +caddr_t +set_isakmp_header1(vbuf, iph1, nptype) + vchar_t *vbuf; + struct ph1handle *iph1; + int nptype; +{ + return set_isakmp_header (vbuf, iph1, nptype, iph1->etype, iph1->flags, iph1->msgid); +} + +/* + * set values into allocated buffer of isakmp header for phase 2 + */ +caddr_t +set_isakmp_header2(vbuf, iph2, nptype) + vchar_t *vbuf; + struct ph2handle *iph2; + int nptype; +{ + return set_isakmp_header (vbuf, iph2->ph1, nptype, ISAKMP_ETYPE_QUICK, iph2->flags, iph2->msgid); +} + +/* + * set values into allocated buffer of isakmp payload. + */ +caddr_t +set_isakmp_payload(buf, src, nptype) + caddr_t buf; + vchar_t *src; + int nptype; +{ + struct isakmp_gen *gen; + caddr_t p = buf; + + plog(LLV_DEBUG, LOCATION, NULL, "add payload of len %zu, next type %d\n", + src->l, nptype); + + gen = (struct isakmp_gen *)p; + gen->np = nptype; + gen->len = htons(sizeof(*gen) + src->l); + p += sizeof(*gen); + memcpy(p, src->v, src->l); + p += src->l; + + return p; +} + +static int +etypesw1(etype) + int etype; +{ + switch (etype) { + case ISAKMP_ETYPE_IDENT: + return 1; + case ISAKMP_ETYPE_AGG: + return 2; + case ISAKMP_ETYPE_BASE: + return 3; + default: + return 0; + } + /*NOTREACHED*/ +} + +static int +etypesw2(etype) + int etype; +{ + switch (etype) { + case ISAKMP_ETYPE_QUICK: + return 1; + default: + return 0; + } + /*NOTREACHED*/ +} + +#ifdef HAVE_PRINT_ISAKMP_C +/* for print-isakmp.c */ +char *snapend; +extern void isakmp_print __P((const u_char *, u_int, const u_char *)); + +char *getname __P((const u_char *)); +#ifdef INET6 +char *getname6 __P((const u_char *)); +#endif +int safeputchar __P((int)); + +/* + * Return a name for the IP address pointed to by ap. This address + * is assumed to be in network byte order. + */ +char * +getname(ap) + const u_char *ap; +{ + struct sockaddr_in addr; + static char ntop_buf[NI_MAXHOST]; + + memset(&addr, 0, sizeof(addr)); +#ifndef __linux__ + addr.sin_len = sizeof(struct sockaddr_in); +#endif + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr, ap, sizeof(addr.sin_addr)); + if (getnameinfo((struct sockaddr *)&addr, sizeof(addr), + ntop_buf, sizeof(ntop_buf), NULL, 0, + NI_NUMERICHOST | niflags)) + strlcpy(ntop_buf, "?", sizeof(ntop_buf)); + + return ntop_buf; +} + +#ifdef INET6 +/* + * Return a name for the IP6 address pointed to by ap. This address + * is assumed to be in network byte order. + */ +char * +getname6(ap) + const u_char *ap; +{ + struct sockaddr_in6 addr; + static char ntop_buf[NI_MAXHOST]; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_len = sizeof(struct sockaddr_in6); + addr.sin6_family = AF_INET6; + memcpy(&addr.sin6_addr, ap, sizeof(addr.sin6_addr)); + if (getnameinfo((struct sockaddr *)&addr, addr.sin6_len, + ntop_buf, sizeof(ntop_buf), NULL, 0, + NI_NUMERICHOST | niflags)) + strlcpy(ntop_buf, "?", sizeof(ntop_buf)); + + return ntop_buf; +} +#endif /* INET6 */ + +int +safeputchar(c) + int c; +{ + unsigned char ch; + + ch = (unsigned char)(c & 0xff); + if (c < 0x80 && isprint(c)) + return printf("%c", c & 0xff); + else + return printf("\\%03o", c & 0xff); +} + +void +isakmp_printpacket(msg, from, my, decoded) + vchar_t *msg; + struct sockaddr *from; + struct sockaddr *my; + int decoded; +{ +#ifdef YIPS_DEBUG + struct timeval tv; + int s; + char hostbuf[NI_MAXHOST]; + char portbuf[NI_MAXSERV]; + struct isakmp *isakmp; + vchar_t *buf; +#endif + + if (loglevel < LLV_DEBUG) + return; + +#ifdef YIPS_DEBUG + plog(LLV_DEBUG, LOCATION, NULL, "begin.\n"); + + gettimeofday(&tv, NULL); + s = tv.tv_sec % 3600; + printf("%02d:%02d.%06u ", s / 60, s % 60, (u_int32_t)tv.tv_usec); + + if (from) { + if (getnameinfo(from, sysdep_sa_len(from), hostbuf, sizeof(hostbuf), + portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { + strlcpy(hostbuf, "?", sizeof(hostbuf)); + strlcpy(portbuf, "?", sizeof(portbuf)); + } + printf("%s:%s", hostbuf, portbuf); + } else + printf("?"); + printf(" -> "); + if (my) { + if (getnameinfo(my, sysdep_sa_len(my), hostbuf, sizeof(hostbuf), + portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { + strlcpy(hostbuf, "?", sizeof(hostbuf)); + strlcpy(portbuf, "?", sizeof(portbuf)); + } + printf("%s:%s", hostbuf, portbuf); + } else + printf("?"); + printf(": "); + + buf = vdup(msg); + if (!buf) { + printf("(malloc fail)\n"); + return; + } + if (decoded) { + isakmp = (struct isakmp *)buf->v; + if (isakmp->flags & ISAKMP_FLAG_E) { +#if 0 + int pad; + pad = *(u_char *)(buf->v + buf->l - 1); + if (buf->l < pad && 2 < vflag) + printf("(wrong padding)"); +#endif + isakmp->flags &= ~ISAKMP_FLAG_E; + } + } + + snapend = buf->v + buf->l; + isakmp_print(buf->v, buf->l, NULL); + vfree(buf); + printf("\n"); + fflush(stdout); + + return; +#endif +} +#endif /*HAVE_PRINT_ISAKMP_C*/ + +int +copy_ph1addresses(iph1, rmconf, remote, local) + struct ph1handle *iph1; + struct remoteconf *rmconf; + struct sockaddr *remote, *local; +{ + u_short *port = NULL; + + /* address portion must be grabbed from real remote address "remote" */ + iph1->remote = dupsaddr(remote); + if (iph1->remote == NULL) { + delph1(iph1); + return -1; + } + + /* + * if remote has no port # (in case of initiator - from ACQUIRE msg) + * - if remote.conf specifies port #, use that + * - if remote.conf does not, use 500 + * if remote has port # (in case of responder - from recvfrom(2)) + * respect content of "remote". + */ + switch (iph1->remote->sa_family) { + case AF_INET: + port = &((struct sockaddr_in *)iph1->remote)->sin_port; + if (*port) + break; + *port = ((struct sockaddr_in *)rmconf->remote)->sin_port; + if (*port) + break; + *port = htons(PORT_ISAKMP); + break; +#ifdef INET6 + case AF_INET6: + port = &((struct sockaddr_in6 *)iph1->remote)->sin6_port; + if (*port) + break; + *port = ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; + if (*port) + break; + *port = htons(PORT_ISAKMP); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + return -1; + } + + if (local == NULL) + iph1->local = getlocaladdr(iph1->remote); + else + iph1->local = dupsaddr(local); + if (iph1->local == NULL) { + delph1(iph1); + return -1; + } + port = NULL; + switch (iph1->local->sa_family) { + case AF_INET: + port = &((struct sockaddr_in *)iph1->local)->sin_port; + if (*port) + break; + *port = ((struct sockaddr_in *)local)->sin_port; + if (*port) + break; + *port = getmyaddrsport(iph1->local); + break; +#ifdef INET6 + case AF_INET6: + port = &((struct sockaddr_in6 *)iph1->local)->sin6_port; + if (*port) + break; + *port = ((struct sockaddr_in6 *)local)->sin6_port; + if (*port) + break; + *port = getmyaddrsport(iph1->local); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->local->sa_family); + delph1(iph1); + return -1; + } +#ifdef ENABLE_NATT + if ( port != NULL && *port == htons(lcconf->port_isakmp_natt) ) { + plog (LLV_DEBUG, LOCATION, NULL, "Marking ports as changed\n"); + iph1->natt_flags |= NAT_ADD_NON_ESP_MARKER; + } +#endif + + return 0; +} + +static int +nostate1(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + plog(LLV_ERROR, LOCATION, iph1->remote, "wrong state %u.\n", + iph1->status); + return -1; +} + +static int +nostate2(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, "wrong state %u.\n", + iph2->status); + return -1; +} + +void +log_ph1established(iph1) + const struct ph1handle *iph1; +{ + char *src, *dst; + + src = strdup(saddr2str(iph1->local)); + dst = strdup(saddr2str(iph1->remote)); + plog(LLV_INFO, LOCATION, NULL, + "ISAKMP-SA established %s-%s spi:%s\n", + src, dst, + isakmp_pindex(&iph1->index, 0)); + EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_UP, NULL); + racoon_free(src); + racoon_free(dst); + + return; +} + +struct payload_list * +isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_type) +{ + if (! plist) { + plist = racoon_malloc (sizeof (struct payload_list)); + plist->prev = NULL; + } + else { + plist->next = racoon_malloc (sizeof (struct payload_list)); + plist->next->prev = plist; + plist = plist->next; + } + + plist->next = NULL; + plist->payload = payload; + plist->payload_type = payload_type; + + return plist; +} + +vchar_t * +isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) +{ + struct payload_list *ptr, *first; + size_t tlen = sizeof (struct isakmp), n = 0; + vchar_t *buf; + char *p; + + if (plist == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "in isakmp_plist_set_all: plist == NULL\n"); + return NULL; + } + + /* Seek to the first item. */ + ptr = *plist; + while (ptr->prev) + ptr = ptr->prev; + first = ptr; + + /* Compute the whole length. */ + while (ptr) { + tlen += ptr->payload->l + sizeof (struct isakmp_gen); + ptr = ptr->next; + } + + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + ptr = first; + + p = set_isakmp_header1(buf, iph1, ptr->payload_type); + if (p == NULL) + goto end; + + while (ptr) + { + p = set_isakmp_payload (p, ptr->payload, ptr->next ? ptr->next->payload_type : ISAKMP_NPTYPE_NONE); + first = ptr; + ptr = ptr->next; + racoon_free (first); + /* ptr->prev = NULL; first = NULL; ... omitted. */ + n++; + } + + *plist = NULL; + + return buf; +end: + return NULL; +} + +#ifdef ENABLE_FRAG +int +frag_handler(iph1, msg, remote, local) + struct ph1handle *iph1; + vchar_t *msg; + struct sockaddr *remote; + struct sockaddr *local; +{ + vchar_t *newmsg; + + if (isakmp_frag_extract(iph1, msg) == 1) { + if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "Packet reassembly failed\n"); + return -1; + } + return isakmp_main(newmsg, remote, local); + } + + return 0; +} +#endif + +void +script_hook(iph1, script) + struct ph1handle *iph1; + int script; +{ +#define IP_MAX 40 +#define PORT_MAX 6 + char addrstr[IP_MAX]; + char portstr[PORT_MAX]; + char **envp = NULL; + int envc = 1; + struct sockaddr_in *sin; + char **c; + + if (iph1->rmconf->script[script] == -1) + return; + +#ifdef ENABLE_HYBRID + (void)isakmp_cfg_setenv(iph1, &envp, &envc); +#endif + + /* local address */ + sin = (struct sockaddr_in *)iph1->local; + inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX); + snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port)); + + if (script_env_append(&envp, &envc, "LOCAL_ADDR", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_ADDR\n"); + goto out; + } + + if (script_env_append(&envp, &envc, "LOCAL_PORT", portstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_PORT\n"); + goto out; + } + + /* Peer address */ + sin = (struct sockaddr_in *)iph1->remote; + inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX); + snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port)); + + if (script_env_append(&envp, &envc, "REMOTE_ADDR", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set REMOTE_ADDR\n"); + goto out; + } + + if (script_env_append(&envp, &envc, "REMOTE_PORT", portstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set REMOTEL_PORT\n"); + goto out; + } + + if (privsep_script_exec(iph1->rmconf->script[script], + script, envp) != 0) + plog(LLV_ERROR, LOCATION, NULL, + "Script %s execution failed\n", script_names[script]); + +out: + for (c = envp; *c; c++) + racoon_free(*c); + + racoon_free(envp); + + return; +} + +int +script_env_append(envp, envc, name, value) + char ***envp; + int *envc; + char *name; + char *value; +{ + char *envitem; + char **newenvp; + int newenvc; + int envitemlen = strlen(name) + 1 + strlen(value) + 1; + + envitem = racoon_malloc(envitemlen); + if (envitem == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + snprintf(envitem, envitemlen, "%s=%s", name, value); + + newenvc = (*envc) + 1; + newenvp = racoon_realloc(*envp, newenvc * sizeof(char *)); + if (newenvp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + + newenvp[newenvc - 2] = envitem; + newenvp[newenvc - 1] = NULL; + + *envp = newenvp; + *envc = newenvc; + return 0; +} + +int +script_exec(script, name, envp) + int script; + int name; + char *const envp[]; +{ + char *argv[] = { NULL, NULL, NULL }; + vchar_t **sp; + + if (script_paths == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: script_paths was not initialized\n"); + return -1; + } + + sp = (vchar_t **)(script_paths->v); + + argv[0] = sp[script]->v; + argv[1] = script_names[name]; + argv[2] = NULL; + + switch (fork()) { + case 0: + execve(argv[0], argv, envp); + plog(LLV_ERROR2, LOCATION, NULL, + "execve(\"%s\") failed: %s\n", + argv[0], strerror(errno)); + _exit(1); + break; + case -1: + plog(LLV_ERROR, LOCATION, NULL, + "Cannot fork: %s\n", strerror(errno)); + return -1; + break; + default: + break; + } + + return 0; +} + +void +purge_remote(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL; + struct sadb_msg *msg, *next, *end; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + caddr_t mhp[SADB_EXT_MAX + 1]; + u_int proto_id; + struct ph2handle *iph2; + struct ph1handle *new_iph1; + + plog(LLV_INFO, LOCATION, NULL, + "purging ISAKMP-SA spi=%s.\n", + isakmp_pindex(&(iph1->index), iph1->msgid)); + + /* Mark as expired. */ + iph1->status = PHASE1ST_EXPIRED; + + /* Check if we have another, still valid, phase1 SA. */ + new_iph1 = getph1byaddr(iph1->local, iph1->remote); + + /* + * Delete all orphaned or binded to the deleting ph1handle phase2 SAs. + * Keep all others phase2 SAs. + */ + buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + while (msg < end) { + if ((msg->sadb_msg_len << 3) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + if (!sa || + !mhp[SADB_EXT_ADDRESS_SRC] || + !mhp[SADB_EXT_ADDRESS_DST]) { + msg = next; + continue; + } + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if (sa->sadb_sa_state != SADB_SASTATE_LARVAL && + sa->sadb_sa_state != SADB_SASTATE_MATURE && + sa->sadb_sa_state != SADB_SASTATE_DYING) { + msg = next; + continue; + } + + /* check in/outbound SAs */ + if ((CMPSADDR(iph1->local, src) || CMPSADDR(iph1->remote, dst)) && + (CMPSADDR(iph1->local, dst) || CMPSADDR(iph1->remote, src))) { + msg = next; + continue; + } + + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + + /* Check if there is another valid ISAKMP-SA */ + if (new_iph1 != NULL) { + + if (iph2 == NULL) { + /* No handler... still send a pfkey_delete message, but log this !*/ + plog(LLV_INFO, LOCATION, NULL, + "Unknown IPsec-SA spi=%u, hmmmm?\n", + ntohl(sa->sadb_sa_spi)); + }else{ + + /* + * If we have a new ph1, do not purge IPsec-SAs binded + * to a different ISAKMP-SA + */ + if (iph2->ph1 != NULL && iph2->ph1 != iph1){ + msg = next; + continue; + } + + /* If the ph2handle is established, do not purge IPsec-SA */ + if (iph2->status == PHASE2ST_ESTABLISHED || + iph2->status == PHASE2ST_EXPIRED) { + + plog(LLV_INFO, LOCATION, NULL, + "keeping IPsec-SA spi=%u - found valid ISAKMP-SA spi=%s.\n", + ntohl(sa->sadb_sa_spi), + isakmp_pindex(&(new_iph1->index), new_iph1->msgid)); + msg = next; + continue; + } + } + } + + + pfkey_send_delete(lcconf->sock_pfkey, + msg->sadb_msg_satype, + IPSEC_MODE_ANY, + src, dst, sa->sadb_sa_spi); + + /* delete a relative phase 2 handle. */ + if (iph2 != NULL) { + delete_spd(iph2); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + + plog(LLV_INFO, LOCATION, NULL, + "purged IPsec-SA spi=%u.\n", + ntohl(sa->sadb_sa_spi)); + + msg = next; + } + + if (buf) + vfree(buf); + + /* Mark the phase1 handler as EXPIRED */ + plog(LLV_INFO, LOCATION, NULL, + "purged ISAKMP-SA spi=%s.\n", + isakmp_pindex(&(iph1->index), iph1->msgid)); + + if (iph1->sce) + SCHED_KILL(iph1->sce); + + iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); +} + +void +delete_spd(iph2) + struct ph2handle *iph2; +{ + if (iph2 == NULL) + return; + + /* Delete the SPD entry if we generated it + */ + if (iph2->generated_spidx) { + struct policyindex spidx; + struct sockaddr_storage addr; + u_int8_t pref; + struct sockaddr *src = iph2->src; + struct sockaddr *dst = iph2->dst; + int error; + int idi2type = 0;/* switch whether copy IDs into id[src,dst]. */ + + plog(LLV_INFO, LOCATION, NULL, + "generated policy, deleting it.\n"); + + memset(&spidx, 0, sizeof(spidx)); + iph2->spidx_gen = (caddr_t )&spidx; + + /* make inbound policy */ + iph2->src = dst; + iph2->dst = src; + spidx.dir = IPSEC_DIR_INBOUND; + spidx.ul_proto = 0; + + /* + * Note: code from get_proposal_r + */ + +#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type + + /* + * make destination address in spidx from either ID payload + * or phase 1 address into a address in spidx. + */ + if (iph2->id != NULL + && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a destination address of a policy */ + error = ipsecdoi_id2sockaddr(iph2->id, + (struct sockaddr *)&spidx.dst, + &spidx.prefd, &spidx.ul_proto); + if (error) + goto purge; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * note that the phase 1 source address is used as + * a destination address to search for a inbound + * policy entry because rcoon is responder. + */ + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { + if ((error = + setscopeid((struct sockaddr *)&spidx.dst, + iph2->src)) != 0) + goto purge; + } +#endif + + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) + idi2type = _XIDT(iph2->id); + + } else { + + plog(LLV_DEBUG, LOCATION, NULL, + "get a destination address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* + * copy the SOURCE address of IKE into the + * DESTINATION address of the key to search the + * SPD because the direction of policy is inbound. + */ + memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src)); + switch (spidx.dst.ss_family) { + case AF_INET: + spidx.prefd = + sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefd = + sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefd = 0; + break; + } + } + + /* make source address in spidx */ + if (iph2->id_p != NULL + && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a source address of inbound SA */ + error = ipsecdoi_id2sockaddr(iph2->id_p, + (struct sockaddr *)&spidx.src, + &spidx.prefs, &spidx.ul_proto); + if (error) + goto purge; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * for more detail, see above of this function. + */ + if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { + error = + setscopeid((struct sockaddr *)&spidx.src, + iph2->dst); + if (error) + goto purge; + } +#endif + + /* make id[src,dst] if both ID types are IP address and same */ + if (_XIDT(iph2->id_p) == idi2type + && spidx.dst.ss_family == spidx.src.ss_family) { + iph2->src_id = + dupsaddr((struct sockaddr *)&spidx.dst); + iph2->dst_id = + dupsaddr((struct sockaddr *)&spidx.src); + } + + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "get a source address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* see above comment. */ + memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); + switch (spidx.src.ss_family) { + case AF_INET: + spidx.prefs = + sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefs = + sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefs = 0; + break; + } + } + +#undef _XIDT + + plog(LLV_DEBUG, LOCATION, NULL, + "get a src address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.src), + spidx.prefs, spidx.ul_proto); + plog(LLV_DEBUG, LOCATION, NULL, + "get dst address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.dst), + spidx.prefd, spidx.ul_proto); + + /* + * convert the ul_proto if it is 0 + * because 0 in ID payload means a wild card. + */ + if (spidx.ul_proto == 0) + spidx.ul_proto = IPSEC_ULPROTO_ANY; + +#undef _XIDT + + /* End of code from get_proposal_r + */ + + if (pk_sendspddelete(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spddelete(inbound) failed.\n"); + }else{ + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spddelete(inbound) sent.\n"); + } + +#ifdef HAVE_POLICY_FWD + /* make forward policy if required */ + if (tunnel_mode_prop(iph2->approval)) { + spidx.dir = IPSEC_DIR_FWD; + if (pk_sendspddelete(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spddelete(forward) failed.\n"); + }else{ + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spddelete(forward) sent.\n"); + } + } +#endif + + /* make outbound policy */ + iph2->src = src; + iph2->dst = dst; + spidx.dir = IPSEC_DIR_OUTBOUND; + addr = spidx.src; + spidx.src = spidx.dst; + spidx.dst = addr; + pref = spidx.prefs; + spidx.prefs = spidx.prefd; + spidx.prefd = pref; + + if (pk_sendspddelete(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spddelete(outbound) failed.\n"); + }else{ + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spddelete(outbound) sent.\n"); + } +purge: + iph2->spidx_gen=NULL; + } +} + +#ifdef INET6 +u_int32_t +setscopeid(sp_addr0, sa_addr0) + struct sockaddr *sp_addr0, *sa_addr0; +{ + struct sockaddr_in6 *sp_addr, *sa_addr; + + sp_addr = (struct sockaddr_in6 *)sp_addr0; + sa_addr = (struct sockaddr_in6 *)sa_addr0; + + if (!IN6_IS_ADDR_LINKLOCAL(&sp_addr->sin6_addr) + && !IN6_IS_ADDR_SITELOCAL(&sp_addr->sin6_addr) + && !IN6_IS_ADDR_MULTICAST(&sp_addr->sin6_addr)) + return 0; + + /* this check should not be here ? */ + if (sa_addr->sin6_family != AF_INET6) { + plog(LLV_ERROR, LOCATION, NULL, + "can't get scope ID: family mismatch\n"); + return -1; + } + + if (!IN6_IS_ADDR_LINKLOCAL(&sa_addr->sin6_addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "scope ID is not supported except of lladdr.\n"); + return -1; + } + + sp_addr->sin6_scope_id = sa_addr->sin6_scope_id; + + return 0; +} +#endif diff --git a/ipsec-tools/racoon/isakmp.h b/ipsec-tools/racoon/isakmp.h new file mode 100644 index 0000000..06ee511 --- /dev/null +++ b/ipsec-tools/racoon/isakmp.h @@ -0,0 +1,447 @@ +/* $Id: isakmp.h,v 1.10 2005/01/29 16:34:25 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_H +#define _ISAKMP_H + +/* refer to RFC 2408 */ + +/* must include first. */ +/* must include "isakmp_var.h" first. */ + +#define INITIATOR 0 /* synonym sender */ +#define RESPONDER 1 /* synonym receiver */ + +#define GENERATE 1 +#define VALIDATE 0 + +/* 3.1 ISAKMP Header Format + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Initiator ! + ! Cookie ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Responder ! + ! Cookie ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Message ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct isakmp { + cookie_t i_ck; /* Initiator Cookie */ + cookie_t r_ck; /* Responder Cookie */ + u_int8_t np; /* Next Payload Type */ + u_int8_t v; + u_int8_t etype; /* Exchange Type */ + u_int8_t flags; /* Flags */ + u_int32_t msgid; + u_int32_t len; /* Length */ +} __attribute__((__packed__)); + +/* Next Payload Type */ +#define ISAKMP_NPTYPE_NONE 0 /* NONE*/ +#define ISAKMP_NPTYPE_SA 1 /* Security Association */ +#define ISAKMP_NPTYPE_P 2 /* Proposal */ +#define ISAKMP_NPTYPE_T 3 /* Transform */ +#define ISAKMP_NPTYPE_KE 4 /* Key Exchange */ +#define ISAKMP_NPTYPE_ID 5 /* Identification */ +#define ISAKMP_NPTYPE_CERT 6 /* Certificate */ +#define ISAKMP_NPTYPE_CR 7 /* Certificate Request */ +#define ISAKMP_NPTYPE_HASH 8 /* Hash */ +#define ISAKMP_NPTYPE_SIG 9 /* Signature */ +#define ISAKMP_NPTYPE_NONCE 10 /* Nonce */ +#define ISAKMP_NPTYPE_N 11 /* Notification */ +#define ISAKMP_NPTYPE_D 12 /* Delete */ +#define ISAKMP_NPTYPE_VID 13 /* Vendor ID */ +#define ISAKMP_NPTYPE_ATTR 14 /* Attribute */ + + +/* NAT-T draft-ietf-ipsec-nat-t-ike-05 and later */ +/* XXX conflicts with values assigned to RFC 3547 */ +#define ISAKMP_NPTYPE_NATD_BADDRAFT 15 /* NAT Discovery */ +#define ISAKMP_NPTYPE_NATOA_BADDRAFT 16 /* NAT Original Address */ + + +/* NAT-T RFC */ +#define ISAKMP_NPTYPE_NATD_RFC 20 /* NAT Discovery */ +#define ISAKMP_NPTYPE_NATOA_RFC 21 /* NAT Original Address */ + +/* NAT-T up to draft-ietf-ipsec-nat-t-ike-04 */ +#define ISAKMP_NPTYPE_NATD_DRAFT 130 /* NAT Discovery */ +#define ISAKMP_NPTYPE_NATOA_DRAFT 131 /* NAT Original Address */ + +/* Frag does not seems to be documented */ +#define ISAKMP_NPTYPE_FRAG 132 /* IKE fragmentation payload */ + +#define ISAKMP_NPTYPE_MAX 17 + /* 128 - 255 Private Use */ + +/* + * The following are valid when the Vendor ID is one of the + * following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + * + * See draft-ietf-ipsec-isakmp-gss-auth-06.txt. + */ +#define ISAKMP_NPTYPE_GSS 129 /* GSS token */ + +#define ISAKMP_MAJOR_VERSION 1 +#define ISAKMP_MINOR_VERSION 0 +#define ISAKMP_VERSION_NUMBER 0x10 +#define ISAKMP_GETMAJORV(v) (((v) & 0xf0) >> 4) +#define ISAKMP_SETMAJORV(v, m) ((v) = ((v) & 0x0f) | (((m) << 4) & 0xf0)) +#define ISAKMP_GETMINORV(v) ((v) & 0x0f) +#define ISAKMP_SETMINORV(v, m) ((v) = ((v) & 0xf0) | ((m) & 0x0f)) + +/* Exchange Type */ +#define ISAKMP_ETYPE_NONE 0 /* NONE */ +#define ISAKMP_ETYPE_BASE 1 /* Base */ +#define ISAKMP_ETYPE_IDENT 2 /* Identity Proteciton */ +#define ISAKMP_ETYPE_AUTH 3 /* Authentication Only */ +#define ISAKMP_ETYPE_AGG 4 /* Aggressive */ +#define ISAKMP_ETYPE_INFO 5 /* Informational */ +#define ISAKMP_ETYPE_CFG 6 /* Mode config */ +/* Additional Exchange Type */ +#define ISAKMP_ETYPE_QUICK 32 /* Quick Mode */ +#define ISAKMP_ETYPE_NEWGRP 33 /* New group Mode */ +#define ISAKMP_ETYPE_ACKINFO 34 /* Acknowledged Informational */ + +/* Flags */ +#define ISAKMP_FLAG_E 0x01 /* Encryption Bit */ +#define ISAKMP_FLAG_C 0x02 /* Commit Bit */ +#define ISAKMP_FLAG_A 0x04 /* Authentication Only Bit */ + +/* 3.2 Payload Generic Header + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct isakmp_gen { + u_int8_t np; /* Next Payload */ + u_int8_t reserved; /* RESERVED, unused, must set to 0 */ + u_int16_t len; /* Payload Length */ +} __attribute__((__packed__)); + +/* 3.3 Data Attributes + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !A! Attribute Type ! AF=0 Attribute Length ! + !F! ! AF=1 Attribute Value ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . AF=0 Attribute Value . + . AF=1 Not Transmitted . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct isakmp_data { + u_int16_t type; /* defined by DOI-spec, and Attribute Format */ + u_int16_t lorv; /* if f equal 1, Attribute Length */ + /* if f equal 0, Attribute Value */ + /* if f equal 1, Attribute Value */ +} __attribute__((__packed__)); +#define ISAKMP_GEN_TLV 0x0000 +#define ISAKMP_GEN_TV 0x8000 + /* mask for type of attribute format */ +#define ISAKMP_GEN_MASK 0x8000 + +#if 0 +/* MAY NOT be used, because of being defined in ipsec-doi. */ +/* 3.4 Security Association Payload */ +struct isakmp_pl_sa { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int32_t sit; /* Situation */ +} __attribute__((__packed__)); +#endif + +/* 3.5 Proposal Payload */ + /* + The value of the next payload field MUST only contain the value "2" + or "0". If there are additional Proposal payloads in the message, + then this field will be 2. If the current Proposal payload is the + last within the security association proposal, then this field will + be 0. + */ +struct isakmp_pl_p { + struct isakmp_gen h; + u_int8_t p_no; /* Proposal # */ + u_int8_t proto_id; /* Protocol */ + u_int8_t spi_size; /* SPI Size */ + u_int8_t num_t; /* Number of Transforms */ + /* SPI */ +} __attribute__((__packed__)); + +/* 3.6 Transform Payload */ + /* + The value of the next payload field MUST only contain the value "3" + or "0". If there are additional Transform payloads in the proposal, + then this field will be 3. If the current Transform payload is the + last within the proposal, then this field will be 0. + */ +struct isakmp_pl_t { + struct isakmp_gen h; + u_int8_t t_no; /* Transform # */ + u_int8_t t_id; /* Transform-Id */ + u_int16_t reserved; /* RESERVED2 */ + /* SA Attributes */ +} __attribute__((__packed__)); + +/* 3.7 Key Exchange Payload */ +struct isakmp_pl_ke { + struct isakmp_gen h; + /* Key Exchange Data */ +} __attribute__((__packed__)); + +#if 0 +/* NOTE: MUST NOT use because of being defined in ipsec-doi instead them. */ +/* 3.8 Identification Payload */ +struct isakmp_pl_id { + struct isakmp_gen h; + union { + u_int8_t id_type; /* ID Type */ + u_int32_t doi_data; /* DOI Specific ID Data */ + } d; + /* Identification Data */ +} __attribute__((__packed__)); +/* A.4 ISAKMP Identification Type Values */ +#define ISAKMP_ID_IPV4_ADDR 0 +#define ISAKMP_ID_IPV4_ADDR_SUBNET 1 +#define ISAKMP_ID_IPV6_ADDR 2 +#define ISAKMP_ID_IPV6_ADDR_SUBNET 3 +#endif + +/* 3.9 Certificate Payload */ +struct isakmp_pl_cert { + struct isakmp_gen h; + /* + * Encoding type of 1 octet follows immediately, + * variable length CERT data follows encoding type. + */ +} __attribute__((__packed__)); + +/* Certificate Type */ +#define ISAKMP_CERT_NONE 0 +#define ISAKMP_CERT_PKCS7 1 +#define ISAKMP_CERT_PGP 2 +#define ISAKMP_CERT_DNS 3 +#define ISAKMP_CERT_X509SIGN 4 +#define ISAKMP_CERT_X509KE 5 +#define ISAKMP_CERT_KERBEROS 6 +#define ISAKMP_CERT_CRL 7 +#define ISAKMP_CERT_ARL 8 +#define ISAKMP_CERT_SPKI 9 +#define ISAKMP_CERT_X509ATTR 10 +#define ISAKMP_CERT_PLAINRSA 11 + +/* the method to get peers certificate */ +#define ISAKMP_GETCERT_PAYLOAD 1 +#define ISAKMP_GETCERT_LOCALFILE 2 +#define ISAKMP_GETCERT_DNS 3 + +/* 3.10 Certificate Request Payload */ +struct isakmp_pl_cr { + struct isakmp_gen h; + u_int8_t num_cert; /* # Cert. Types */ + /* + Certificate Types (variable length) + -- Contains a list of the types of certificates requested, + sorted in order of preference. Each individual certificate + type is 1 octet. This field is NOT required. + */ + /* # Certificate Authorities (1 octet) */ + /* Certificate Authorities (variable length) */ +} __attribute__((__packed__)); + +/* 3.11 Hash Payload */ +struct isakmp_pl_hash { + struct isakmp_gen h; + /* Hash Data */ +} __attribute__((__packed__)); + +/* 3.12 Signature Payload */ +struct isakmp_pl_sig { + struct isakmp_gen h; + /* Signature Data */ +} __attribute__((__packed__)); + +/* 3.13 Nonce Payload */ +struct isakmp_pl_nonce { + struct isakmp_gen h; + /* Nonce Data */ +} __attribute__((__packed__)); + +/* 3.14 Notification Payload */ +struct isakmp_pl_n { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-ID */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t type; /* Notify Message Type */ + /* SPI */ + /* Notification Data */ +} __attribute__((__packed__)); + +/* 3.14.1 Notify Message Types */ +/* NOTIFY MESSAGES - ERROR TYPES */ +#define ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE 1 +#define ISAKMP_NTYPE_DOI_NOT_SUPPORTED 2 +#define ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED 3 +#define ISAKMP_NTYPE_INVALID_COOKIE 4 +#define ISAKMP_NTYPE_INVALID_MAJOR_VERSION 5 +#define ISAKMP_NTYPE_INVALID_MINOR_VERSION 6 +#define ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE 7 +#define ISAKMP_NTYPE_INVALID_FLAGS 8 +#define ISAKMP_NTYPE_INVALID_MESSAGE_ID 9 +#define ISAKMP_NTYPE_INVALID_PROTOCOL_ID 10 +#define ISAKMP_NTYPE_INVALID_SPI 11 +#define ISAKMP_NTYPE_INVALID_TRANSFORM_ID 12 +#define ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED 13 +#define ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN 14 +#define ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX 15 +#define ISAKMP_NTYPE_PAYLOAD_MALFORMED 16 +#define ISAKMP_NTYPE_INVALID_KEY_INFORMATION 17 +#define ISAKMP_NTYPE_INVALID_ID_INFORMATION 18 +#define ISAKMP_NTYPE_INVALID_CERT_ENCODING 19 +#define ISAKMP_NTYPE_INVALID_CERTIFICATE 20 +#define ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX 21 +#define ISAKMP_NTYPE_INVALID_CERT_AUTHORITY 22 +#define ISAKMP_NTYPE_INVALID_HASH_INFORMATION 23 +#define ISAKMP_NTYPE_AUTHENTICATION_FAILED 24 +#define ISAKMP_NTYPE_INVALID_SIGNATURE 25 +#define ISAKMP_NTYPE_ADDRESS_NOTIFICATION 26 +#define ISAKMP_NTYPE_NOTIFY_SA_LIFETIME 27 +#define ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE 28 +#define ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE 29 +#define ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS 30 +/* NOTIFY MESSAGES - STATUS TYPES */ +#define ISAKMP_NTYPE_CONNECTED 16384 +/* 4.6.3 IPSEC DOI Notify Message Types */ +#define ISAKMP_NTYPE_RESPONDER_LIFETIME 24576 +#define ISAKMP_NTYPE_REPLAY_STATUS 24577 +#define ISAKMP_NTYPE_INITIAL_CONTACT 24578 + +/* DPD */ +#define ISAKMP_NTYPE_R_U_THERE 36136 +#define ISAKMP_NTYPE_R_U_THERE_ACK 36137 + +#define ISAKMP_NTYPE_LOAD_BALANCE 40501 +#define ISAKMP_NTYPE_HEARTBEAT 40503 + +/* using only to log */ +#define ISAKMP_LOG_RETRY_LIMIT_REACHED 65530 + +/* XXX means internal error but it's not reserved by any drafts... */ +#define ISAKMP_INTERNAL_ERROR -1 + +/* 3.15 Delete Payload */ +struct isakmp_pl_d { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-Id */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t num_spi; /* # of SPIs */ + /* SPI(es) */ +} __attribute__((__packed__)); + +/* natoa payload */ +struct isakmp_pl_natoa { + struct isakmp_gen h; + u_int8_t id_type; /* address type */ + u_int8_t reserved1; /* reserved */ + u_int16_t reserved2; /* reserved */ + /* IP address */ +} __attribute__((__packed__)); + +struct payload_list { + struct payload_list *next, *prev; + vchar_t *payload; + int payload_type; +}; + + +/* See draft-ietf-ipsec-isakmp-mode-cfg-04.txt, 3.2 */ +struct isakmp_pl_attr { + struct isakmp_gen h; + u_int8_t type; /* Exchange type */ + u_int8_t res2; + u_int16_t id; /* Per transaction id */ +} __attribute__((__packed__)); + +/* Exchange type */ +#define ISAKMP_CFG_REQUEST 1 +#define ISAKMP_CFG_REPLY 2 +#define ISAKMP_CFG_SET 3 +#define ISAKMP_CFG_ACK 4 + +/* IKE fragmentation payload */ +struct isakmp_frag { + u_int16_t unknown0; /* always set to zero? */ + u_int16_t len; + u_int16_t unknown1; /* always set to 1? */ + u_int8_t index; + u_int8_t flags; +} __attribute__((__packed__)); + +/* flags */ +#define ISAKMP_FRAG_LAST 1 + +/* DPD R-U-THERE / R-U-THERE-ACK Payload */ +struct isakmp_pl_ru { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-Id */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t type; /* Notify type */ + cookie_t i_ck; /* Initiator Cookie */ + cookie_t r_ck; /* Responder cookie*/ + u_int32_t data; /* Notification data */ +} __attribute__((__packed__)); + +/* Load Balance Notification */ +struct isakmp_pl_lb { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-Id */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t type; /* Notify type */ + cookie_t i_ck; /* Initiator Cookie */ + cookie_t r_ck; /* Responder cookie*/ + u_int32_t address; /* redirect address */ +} __attribute__((__packed__)); + +#endif /* _ISAKMP_H */ diff --git a/ipsec-tools/racoon/isakmp_agg.c b/ipsec-tools/racoon/isakmp_agg.c new file mode 100644 index 0000000..eea7726 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_agg.c @@ -0,0 +1,1514 @@ +/* $Id: isakmp_agg.c,v 1.20.2.5 2005/11/21 09:46:23 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Aggressive Exchange (Aggressive Mode) */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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, Pubkey_r, Pubkey_r + * rev: HDR, SA, [ HASH(1),] Pubkey_r, Ke_i, + * Ke_i [, 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, PubKey_i, PubKey_i, HASH_R + * rev: HDR, SA, PubKey_i, Ke_r, 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, Pubkey_r, Pubkey_r + * rev: HDR, SA, [ HASH(1),] Pubkey_r, Ke_i, + * Ke_i [, 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, PubKey_i, PubKey_i, HASH_R + * rev: HDR, SA, PubKey_i, Ke_r, Ke_r, HASH_R + */ +int +agg_r1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct payload_list *plist = NULL; + int need_cr = 0; + int need_cert = 0; + vchar_t *cr = NULL; + vchar_t *vid = NULL; + int error = -1; +#ifdef ENABLE_HYBRID + vchar_t *xauth_vid = NULL; + vchar_t *unity_vid = NULL; +#endif +#ifdef ENABLE_NATT + vchar_t *vid_natt = NULL; + vchar_t *natd[2] = { NULL, NULL }; +#endif +#ifdef ENABLE_DPD + vchar_t *vid_dpd = NULL; +#endif + +#ifdef HAVE_GSSAPI + int gsslen; + vchar_t *gsstoken = NULL, *gsshash = NULL; + vchar_t *gss_sa = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* set responder's cookie */ + isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local); + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + + /* generate DH public value */ + if (oakley_dh_generate(iph1->rmconf->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid(iph1) < 0) + goto end; + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->rmconf->proposal->authmethod == + OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + gssapi_get_rtoken(iph1, &gsslen); +#endif + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_R\n"); + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + if (iph1->hash == NULL) { +#ifdef HAVE_GSSAPI + if (gssapi_more_tokens(iph1)) + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); +#endif + goto end; + } + + /* create CR if need */ + if (iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } + +#ifdef ENABLE_NATT + /* Has the peer announced NAT-T? */ + if (NATT_AVAILABLE(iph1)) { + /* set chosen VID */ + vid_natt = set_vendorid(iph1->natt_options->version); + + /* generate NAT-D payloads */ + plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n"); + if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->remote)); + goto end; + } + + if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->local)); + goto end; + } + } +#endif +#ifdef ENABLE_DPD + /* Only send DPD support if remote announced DPD and if DPD support is active */ + if (iph1->dpd_support && iph1->rmconf->dpd) + vid_dpd = set_vendorid(VENDORID_DPD); +#endif + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + /* set SA payload to reply */ + plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA); + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* create isakmp NONCE payload */ + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); + + /* create isakmp ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + + /* create isakmp HASH payload */ + plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH); + + /* append vendor id, if needed */ + if (vid) + plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID); + + /* create isakmp CR payload if needed */ + if (need_cr) + plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR); + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: +#endif + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert != NULL && iph1->rmconf->send_cert) + need_cert = 1; + + /* set SA payload to reply */ + plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA); + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* create isakmp NONCE payload */ + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); + + /* add ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + + /* add CERT payload if there */ + if (need_cert) + plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT); + + /* add SIG payload */ + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); + + /* append vendor id, if needed */ + if (vid) + plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID); + +#ifdef ENABLE_HYBRID + if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) { + if ((xauth_vid = set_vendorid(VENDORID_XAUTH)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot create Xauth vendor ID\n"); + goto end; + } + plist = isakmp_plist_append(plist, + xauth_vid, ISAKMP_NPTYPE_VID); + } + + if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_UNITY) { + if ((unity_vid = set_vendorid(VENDORID_UNITY)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot create Unity vendor ID\n"); + goto end; + } + plist = isakmp_plist_append(plist, + unity_vid, ISAKMP_NPTYPE_VID); + } +#endif + + /* create isakmp CR payload if needed */ + if (need_cr) + plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR); + break; + + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* create buffer to send isakmp payload */ + gsshash = gssapi_wraphash(iph1); + if (gsshash == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to wrap hash\n"); + /* + * This is probably due to the GSS roundtrips not + * being finished yet. Return this error in + * the hope that a fallback to main mode will + * be done. + */ + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); + goto end; + } + if (iph1->approval->gssid != NULL) + gss_sa = ipsecdoi_setph1proposal(iph1->approval); + else + gss_sa = iph1->sa_ret; + + /* set SA payload to reply */ + plist = isakmp_plist_append(plist, gss_sa, ISAKMP_NPTYPE_SA); + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* create isakmp NONCE payload */ + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); + + /* create isakmp ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + + /* create GSS payload */ + gssapi_get_token_to_send(iph1, &gsstoken); + plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); + + /* create isakmp HASH payload */ + plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH); + + /* append vendor id, if needed */ + if (vid) + plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID); + + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, "Invalid authmethod %d\n", + iph1->approval->authmethod); + goto end; + break; + } + +#ifdef ENABLE_NATT + /* append NAT-T payloads */ + if (vid_natt) { + /* chosen VID */ + plist = isakmp_plist_append(plist, vid_natt, ISAKMP_NPTYPE_VID); + /* NAT-D */ +#ifdef __APPLE__ + /* old Apple version sends natd payloads in the wrong order */ + if (iph1->natt_options->version == VENDORID_NATT_APPLE) { + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + } else +#endif + { + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + } + } +#endif +#ifdef ENABLE_DPD + if (vid_dpd) + plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID); +#endif + + iph1->sendbuf = isakmp_plist_set_all (&plist, iph1); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 1); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG1SENT; + +#ifdef ENABLE_VPNCONTROL_PORT + vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL); +#endif + + error = 0; + +end: + if (cr) + vfree(cr); + if (vid) + vfree(vid); +#ifdef ENABLE_HYBRID + if (xauth_vid) + vfree(xauth_vid); + if (unity_vid) + vfree(unity_vid); +#endif +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); + if (gsshash) + vfree(gsshash); + if (gss_sa != iph1->sa_ret) + vfree(gss_sa); +#endif +#ifdef ENABLE_DPD + if (vid_dpd) + vfree(vid_dpd); +#endif + + return error; +} + +/* + * receive from initiator + * psk: HDR, HASH_I + * gssapi: HDR, HASH_I + * sig: HDR, [ CERT, ] SIG_I + * rsa: HDR, HASH_I + * rev: HDR, HASH_I + */ +int +agg_r2recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + int ptype; + +#ifdef ENABLE_NATT + int natd_seq = 0; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* decrypting if need. */ + /* XXX configurable ? */ + if (ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + msg = oakley_do_decrypt(iph1, msg0, + iph1->ivm->iv, iph1->ivm->ive); + if (msg == NULL) + goto end; + } else + msg = vdup(msg0); + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + iph1->pl_hash = NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph1); + break; + +#ifdef ENABLE_NATT + case ISAKMP_NPTYPE_NATD_DRAFT: + case ISAKMP_NPTYPE_NATD_RFC: +#ifdef __APPLE__ + case ISAKMP_NPTYPE_NATD_BADDRAFT: +#endif + if (NATT_AVAILABLE(iph1) && iph1->natt_options != NULL && + pa->type == iph1->natt_options->payload_nat_d) + { + vchar_t *natd_received = NULL; + int natd_verified; + + if (isakmp_p2ph (&natd_received, pa->ptr) < 0) + goto end; + + if (natd_seq == 0) + iph1->natt_flags |= NAT_DETECTED; + + natd_verified = natt_compare_addr_hash (iph1, + natd_received, natd_seq++); + + plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n", + natd_seq - 1, + natd_verified ? "verified" : "doesn't match"); + + vfree (natd_received); + break; + } + /* %%%% Be lenient here - some servers send natd payloads */ + /* when no nat is detected */ + break; +#endif + + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + +#ifdef ENABLE_NATT + if (NATT_AVAILABLE(iph1)) + plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n", + iph1->natt_flags & NAT_DETECTED ? + "detected:" : "not detected", + iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "", + iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : ""); +#endif + + /* validate authentication value */ + ptype = oakley_validate_auth(iph1); + if (ptype != 0) { + if (ptype == -1) { + /* message printed inner oakley_validate_auth() */ + goto end; + } + EVT_PUSH(iph1->local, iph1->remote, + EVTT_PEERPH1AUTH_FAILED, NULL); + isakmp_info_send_n1(iph1, ptype, NULL); + goto end; + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); + if (error) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + } + + return error; +} + +/* + * status update and establish isakmp sa. + */ +int +agg_r2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* IV synchronized when packet encrypted. */ + /* see handler.h about IV synchronization. */ + if (ISSET(((struct isakmp *)msg->v)->flags, ISAKMP_FLAG_E)) + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l); + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + return error; +} diff --git a/ipsec-tools/racoon/isakmp_agg.h b/ipsec-tools/racoon/isakmp_agg.h new file mode 100644 index 0000000..8bf35ed --- /dev/null +++ b/ipsec-tools/racoon/isakmp_agg.h @@ -0,0 +1,44 @@ +/* $Id: isakmp_agg.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_AGG_H +#define _ISAKMP_AGG_H + +extern int agg_i1send __P((struct ph1handle *, vchar_t *)); +extern int agg_i2recv __P((struct ph1handle *, vchar_t *)); +extern int agg_i2send __P((struct ph1handle *, vchar_t *)); + +extern int agg_r1recv __P((struct ph1handle *, vchar_t *)); +extern int agg_r1send __P((struct ph1handle *, vchar_t *)); +extern int agg_r2recv __P((struct ph1handle *, vchar_t *)); +extern int agg_r2send __P((struct ph1handle *, vchar_t *)); + +#endif /* _ISAKMP_AGG_H */ diff --git a/ipsec-tools/racoon/isakmp_base.c b/ipsec-tools/racoon/isakmp_base.c new file mode 100644 index 0000000..f33b733 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_base.c @@ -0,0 +1,1237 @@ +/* $KAME: isakmp_base.c,v 1.49 2003/11/13 02:30:20 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Base Exchange (Base Mode) */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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),] Pubkey_r, Pubkey_r + * rev: HDR, SA, [HASH(1),] Pubkey_r, 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, PubKey_i, PubKey_i + * rev: HDR, SA, PubKey_i, 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_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_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),] Pubkey_r, Pubkey_r + * rev: HDR, SA, [HASH(1),] Pubkey_r, 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, PubKey_i, PubKey_i + * rev: HDR, SA, PubKey_i, 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_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_r, HASH_R + */ +int +base_r2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct payload_list *plist = NULL; + vchar_t *vid = NULL; + int need_cert = 0; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + iph1->hash = oakley_ph1hash_base_r(iph1, GENERATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication method %d\n", + iph1->approval->authmethod); + goto end; + } + if (iph1->hash == NULL) + goto end; + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + vid = set_vendorid(iph1->approval->vendorid); + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* create isakmp HASH payload */ + plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH); + + /* append vendor id, if needed */ + if (vid) + plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID); + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert && iph1->rmconf->send_cert) + need_cert = 1; + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* add CERT payload if there */ + if (need_cert) + plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT); + /* add SIG payload */ + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); + break; + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* ... */ + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, "invalid authmethod %d\n", + iph1->approval->authmethod); + goto end; + break; + } + +#ifdef ENABLE_NATT + /* generate NAT-D payloads */ + if (NATT_AVAILABLE(iph1)) + { + vchar_t *natd[2] = { NULL, NULL }; + + plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n"); + if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->remote)); + goto end; + } + + if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->local)); + goto end; + } + +#ifdef __APPLE__ + /* old Apple version sends natd payloads in the wrong order */ + if (iph1->natt_options->version == VENDORID_NATT_APPLE) { + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + } else +#endif + { + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + } + } +#endif + + iph1->sendbuf = isakmp_plist_set_all (&plist, iph1); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send HDR;KE;NONCE to responder */ + if (isakmp_send(iph1, iph1->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + if (vid) + vfree(vid); + return error; +} diff --git a/ipsec-tools/racoon/isakmp_base.h b/ipsec-tools/racoon/isakmp_base.h new file mode 100644 index 0000000..d6ecd63 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_base.h @@ -0,0 +1,46 @@ +/* $Id: isakmp_base.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_BASE_H +#define _ISAKMP_BASE_H + +extern int base_i1send __P((struct ph1handle *, vchar_t *)); +extern int base_i2recv __P((struct ph1handle *, vchar_t *)); +extern int base_i2send __P((struct ph1handle *, vchar_t *)); +extern int base_i3recv __P((struct ph1handle *, vchar_t *)); +extern int base_i3send __P((struct ph1handle *, vchar_t *)); + +extern int base_r1recv __P((struct ph1handle *, vchar_t *)); +extern int base_r1send __P((struct ph1handle *, vchar_t *)); +extern int base_r2recv __P((struct ph1handle *, vchar_t *)); +extern int base_r2send __P((struct ph1handle *, vchar_t *)); + +#endif /* _ISAKMP_BASE_H */ diff --git a/ipsec-tools/racoon/isakmp_cfg.c b/ipsec-tools/racoon/isakmp_cfg.c new file mode 100644 index 0000000..56e96de --- /dev/null +++ b/ipsec-tools/racoon/isakmp_cfg.c @@ -0,0 +1,1600 @@ +/* $Id: isakmp_cfg.c,v 1.26.2.7 2006/01/07 23:50:42 manubsd Exp $ */ + +/* + * Copyright (C) 2004-2006 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#ifdef HAVE_LIBRADIUS +#include +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "handler.h" +#include "evt.h" +#include "throttle.h" +#include "remoteconf.h" +#include "crypto_openssl.h" +#include "isakmp_inf.h" +#include "isakmp_xauth.h" +#include "isakmp_unity.h" +#include "isakmp_cfg.h" +#include "strnames.h" +#include "admin.h" +#include "privsep.h" + +struct isakmp_cfg_config isakmp_cfg_config = { + 0x00000000, /* network4 */ + 0x00000000, /* netmask4 */ + 0x00000000, /* dns4 */ + 0x00000000, /* nbns4 */ + NULL, /* pool */ + ISAKMP_CFG_AUTH_SYSTEM, /* authsource */ + ISAKMP_CFG_CONF_LOCAL, /* confsource */ + ISAKMP_CFG_ACCT_NONE, /* accounting */ + ISAKMP_CFG_MAX_CNX, /* pool_size */ + THROTTLE_PENALTY, /* auth_throttle */ + ISAKMP_CFG_MOTD, /* motd */ + 0, /* pfs_group */ + 0, /* save_passwd */ +}; + +static vchar_t *buffer_cat(vchar_t *s, vchar_t *append); +static vchar_t *isakmp_cfg_net(struct ph1handle *, struct isakmp_data *); +#if 0 +static vchar_t *isakmp_cfg_void(struct ph1handle *, struct isakmp_data *); +#endif +static vchar_t *isakmp_cfg_addr4(struct ph1handle *, + struct isakmp_data *, in_addr_t *); +static void isakmp_cfg_getaddr4(struct isakmp_data *, struct in_addr *); + +#define ISAKMP_CFG_LOGIN 1 +#define ISAKMP_CFG_LOGOUT 2 +static int isakmp_cfg_accounting(struct ph1handle *, int); +#ifdef HAVE_LIBRADIUS +static int isakmp_cfg_accounting_radius(struct ph1handle *, int); +#endif + +/* + * Handle an ISAKMP config mode packet + * We expect HDR, HASH, ATTR + */ +void +isakmp_cfg_r(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp *packet; + struct isakmp_gen *ph; + int tlen; + char *npp; + int np; + vchar_t *dmsg; + struct isakmp_ivm *ivm; + + /* Check that the packet is long enough to have a header */ + if (msg->l < sizeof(*packet)) { + plog(LLV_ERROR, LOCATION, NULL, "Unexpected short packet\n"); + return; + } + + packet = (struct isakmp *)msg->v; + + /* Is it encrypted? It should be encrypted */ + if ((packet->flags & ISAKMP_FLAG_E) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "User credentials sent in cleartext!\n"); + return; + } + + /* + * Decrypt the packet. If this is the beginning of a new + * exchange, reinitialize the IV + */ + if (iph1->mode_cfg->ivm == NULL) + iph1->mode_cfg->ivm = + isakmp_cfg_newiv(iph1, packet->msgid); + ivm = iph1->mode_cfg->ivm; + + dmsg = oakley_do_decrypt(iph1, msg, ivm->iv, ivm->ive); + if (dmsg == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to decrypt message\n"); + return; + } + + plog(LLV_DEBUG, LOCATION, NULL, "MODE_CFG packet\n"); + plogdump(LLV_DEBUG, dmsg->v, dmsg->l); + + /* Now work with the decrypted packet */ + packet = (struct isakmp *)dmsg->v; + tlen = dmsg->l - sizeof(*packet); + ph = (struct isakmp_gen *)(packet + 1); + + np = packet->np; + while ((tlen > 0) && (np != ISAKMP_NPTYPE_NONE)) { + /* Check that the payload header fits in the packet */ + if (tlen < sizeof(*ph)) { + plog(LLV_WARNING, LOCATION, NULL, + "Short payload header\n"); + goto out; + } + + /* Check that the payload fits in the packet */ + if (tlen < ntohs(ph->len)) { + plog(LLV_WARNING, LOCATION, NULL, + "Short payload\n"); + goto out; + } + + plog(LLV_DEBUG, LOCATION, NULL, "Seen payload %d\n", np); + plogdump(LLV_DEBUG, ph, ntohs(ph->len)); + + switch(np) { + case ISAKMP_NPTYPE_HASH: { + vchar_t *check; + vchar_t *payload; + size_t plen; + struct isakmp_gen *nph; + + plen = ntohs(ph->len); + nph = (struct isakmp_gen *)((char *)ph + plen); + plen = ntohs(nph->len); + + if ((payload = vmalloc(plen)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + goto out; + } + memcpy(payload->v, nph, plen); + + if ((check = oakley_compute_hash1(iph1, + packet->msgid, payload)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot compute hash\n"); + vfree(payload); + goto out; + } + + if (memcmp(ph + 1, check->v, check->l) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Hash verification failed\n"); + vfree(payload); + vfree(check); + goto out; + } + vfree(payload); + vfree(check); + break; + } + case ISAKMP_NPTYPE_ATTR: { + struct isakmp_pl_attr *attrpl; + + attrpl = (struct isakmp_pl_attr *)ph; + isakmp_cfg_attr_r(iph1, packet->msgid, attrpl); + + break; + } + default: + plog(LLV_WARNING, LOCATION, NULL, + "Unexpected next payload %d\n", np); + /* Skip to the next payload */ + break; + } + + /* Move to the next payload */ + np = ph->np; + tlen -= ntohs(ph->len); + npp = (char *)ph; + ph = (struct isakmp_gen *)(npp + ntohs(ph->len)); + } + +out: + vfree(dmsg); +} + +int +isakmp_cfg_attr_r(iph1, msgid, attrpl) + struct ph1handle *iph1; + u_int32_t msgid; + struct isakmp_pl_attr *attrpl; +{ + int type = attrpl->type; + + switch (type) { + case ISAKMP_CFG_ACK: + /* ignore, but this is the time to reinit the IV */ + oakley_delivm(iph1->mode_cfg->ivm); + iph1->mode_cfg->ivm = NULL; + return 0; + break; + + case ISAKMP_CFG_REPLY: + return isakmp_cfg_reply(iph1, attrpl); + break; + + case ISAKMP_CFG_REQUEST: + iph1->msgid = msgid; + return isakmp_cfg_request(iph1, attrpl); + break; + + case ISAKMP_CFG_SET: + iph1->msgid = msgid; + return isakmp_cfg_set(iph1, attrpl); + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "Unepected configuration exchange type %d\n", type); + return -1; + break; + } + + return 0; +} + +int +isakmp_cfg_reply(iph1, attrpl) + struct ph1handle *iph1; + struct isakmp_pl_attr *attrpl; +{ + struct isakmp_data *attr; + int tlen; + size_t alen; + char *npp; + int type; + struct sockaddr_in *sin; + + tlen = ntohs(attrpl->h.len); + attr = (struct isakmp_data *)(attrpl + 1); + tlen -= sizeof(*attrpl); + + while (tlen > 0) { + type = ntohs(attr->type); + + /* Handle short attributes */ + if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { + type &= ~ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "Short attribute %d = %d\n", + type, ntohs(attr->lorv)); + + switch (type) { + case XAUTH_TYPE: + xauth_attr_reply(iph1, attr, ntohs(attrpl->id)); + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored short attribute %d\n", type); + break; + } + + tlen -= sizeof(*attr); + attr++; + continue; + } + + type = ntohs(attr->type); + alen = ntohs(attr->lorv); + + /* Check that the attribute fit in the packet */ + if (tlen < alen) { + plog(LLV_ERROR, LOCATION, NULL, + "Short attribute %d\n", type); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "Attribute %d, len %zu\n", type, alen); + + switch(type) { + case XAUTH_TYPE: + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_STATUS: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + xauth_attr_reply(iph1, attr, ntohs(attrpl->id)); + break; + case INTERNAL_IP4_ADDRESS: + isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->addr4); + iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_ADDR4; + break; + case INTERNAL_IP4_NETMASK: + isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->mask4); + iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_MASK4; + break; + case INTERNAL_IP4_DNS: + isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->dns4); + iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_DNS4; + break; + case INTERNAL_IP4_NBNS: + isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->wins4); + iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_WINS4; + break; + case INTERNAL_IP4_SUBNET: + case INTERNAL_ADDRESS_EXPIRY: + case UNITY_BANNER: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_PFS: + case UNITY_FW_TYPE: + case UNITY_BACKUP_SERVERS: + case UNITY_DDNS_HOSTNAME: + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", type); + break; + } + + npp = (char *)attr; + attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen); + tlen -= (sizeof(*attr) + alen); + } + + /* + * Call the SA up script hook now that we have the configuration + * It is done at the end of phase 1 if ISAKMP mode config is not + * requested. + */ + if ((iph1->status == PHASE1ST_ESTABLISHED) && + iph1->rmconf->mode_cfg) + script_hook(iph1, SCRIPT_PHASE1_UP); + +#ifdef ENABLE_ADMINPORT + { + vchar_t *buf; + + alen = ntohs(attrpl->h.len) - sizeof(*attrpl); + if ((buf = vmalloc(alen)) == NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + } else { + memcpy(buf->v, attrpl + 1, buf->l); + EVT_PUSH(iph1->local, iph1->remote, + EVTT_ISAKMP_CFG_DONE, buf); + vfree(buf); + } + } +#endif + + return 0; +} + +int +isakmp_cfg_request(iph1, attrpl) + struct ph1handle *iph1; + struct isakmp_pl_attr *attrpl; +{ + struct isakmp_data *attr; + int tlen; + size_t alen; + char *npp; + vchar_t *payload; + struct isakmp_pl_attr *reply; + vchar_t *reply_attr; + int type; + int error = -1; + + if ((payload = vmalloc(sizeof(*reply))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return -1; + } + memset(payload->v, 0, sizeof(*reply)); + + tlen = ntohs(attrpl->h.len); + attr = (struct isakmp_data *)(attrpl + 1); + tlen -= sizeof(*attrpl); + + while (tlen > 0) { + reply_attr = NULL; + type = ntohs(attr->type); + + /* Handle short attributes */ + if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { + type &= ~ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "Short attribute %d = %d\n", + type, ntohs(attr->lorv)); + + switch (type) { + case XAUTH_TYPE: + reply_attr = isakmp_xauth_req(iph1, attr); + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored short attribute %d\n", type); + break; + } + + tlen -= sizeof(*attr); + attr++; + + if (reply_attr != NULL) { + payload = buffer_cat(payload, reply_attr); + vfree(reply_attr); + } + + continue; + } + + type = ntohs(attr->type); + alen = ntohs(attr->lorv); + + /* Check that the attribute fit in the packet */ + if (tlen < alen) { + plog(LLV_ERROR, LOCATION, NULL, + "Short attribute %d\n", type); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "Attribute %d, len %zu\n", type, alen); + + switch(type) { + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_IP4_SUBNET: + reply_attr = isakmp_cfg_net(iph1, attr); + break; + + case XAUTH_TYPE: + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_STATUS: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + reply_attr = isakmp_xauth_req(iph1, attr); + break; + + case APPLICATION_VERSION: + reply_attr = isakmp_cfg_string(iph1, + attr, ISAKMP_CFG_RACOON_VERSION); + break; + + case UNITY_BANNER: + case UNITY_PFS: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_DDNS_HOSTNAME: + case UNITY_FW_TYPE: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_BACKUP_SERVERS: + reply_attr = isakmp_unity_req(iph1, attr); + break; + + case INTERNAL_ADDRESS_EXPIRY: + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", type); + break; + } + + npp = (char *)attr; + attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen); + tlen -= (sizeof(*attr) + alen); + + if (reply_attr != NULL) { + payload = buffer_cat(payload, reply_attr); + vfree(reply_attr); + } + + } + + reply = (struct isakmp_pl_attr *)payload->v; + reply->h.len = htons(payload->l); + reply->type = ISAKMP_CFG_REPLY; + reply->id = attrpl->id; + + error = isakmp_cfg_send(iph1, payload, + ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0); + + /* Reinit the IV */ + oakley_delivm(iph1->mode_cfg->ivm); + iph1->mode_cfg->ivm = NULL; +end: + vfree(payload); + + return error; +} + +int +isakmp_cfg_set(iph1, attrpl) + struct ph1handle *iph1; + struct isakmp_pl_attr *attrpl; +{ + struct isakmp_data *attr; + int tlen; + size_t alen; + char *npp; + vchar_t *payload; + struct isakmp_pl_attr *reply; + vchar_t *reply_attr; + int type; + int error = -1; + + if ((payload = vmalloc(sizeof(*reply))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return -1; + } + memset(payload->v, 0, sizeof(*reply)); + + tlen = ntohs(attrpl->h.len); + attr = (struct isakmp_data *)(attrpl + 1); + tlen -= sizeof(*attrpl); + + /* + * We should send ack for the attributes we accepted + */ + while (tlen > 0) { + reply_attr = NULL; + type = ntohs(attr->type); + + switch (type & ~ISAKMP_GEN_MASK) { + case XAUTH_STATUS: + reply_attr = isakmp_xauth_set(iph1, attr); + break; + default: + plog(LLV_DEBUG, LOCATION, NULL, + "Unexpected SET attribute %d\n", + type & ~ISAKMP_GEN_MASK); + break; + } + + if ((reply_attr = vmalloc(sizeof(*reply_attr))) != NULL) { + payload = buffer_cat(payload, reply_attr); + vfree(reply_attr); + } + + /* + * Move to next attribute. If we run out of the packet, + * tlen becomes negative and we exit. + */ + if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { + tlen -= sizeof(*attr); + attr++; + } else { + alen = ntohs(attr->lorv); + tlen -= (sizeof(*attr) + alen); + npp = (char *)attr; + attr = (struct isakmp_data *) + (npp + sizeof(*attr) + alen); + } + } + + reply = (struct isakmp_pl_attr *)payload->v; + reply->h.len = htons(payload->l); + reply->type = ISAKMP_CFG_ACK; + reply->id = attrpl->id; + + error = isakmp_cfg_send(iph1, payload, + ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0); + + if (iph1->mode_cfg->flags & ISAKMP_CFG_DELETE_PH1) { + if (iph1->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(iph1); + remph1(iph1); + delph1(iph1); + } +end: + vfree(payload); + + /* + * If required, request ISAKMP mode config information + */ + if ((iph1->rmconf->mode_cfg) && (error == 0)) + error = isakmp_cfg_getconfig(iph1); + + return error; +} + + +static vchar_t * +buffer_cat(s, append) + vchar_t *s; + vchar_t *append; +{ + vchar_t *new; + + new = vmalloc(s->l + append->l); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return s; + } + + memcpy(new->v, s->v, s->l); + memcpy(new->v + s->l, append->v, append->l); + + vfree(s); + return new; +} + +static vchar_t * +isakmp_cfg_net(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + int type; + in_addr_t addr4; + + type = ntohs(attr->type); + + /* + * Don't give an address to a peer that did not succeed Xauth + */ + if (xauth_check(iph1) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Attempt to start phase config whereas Xauth failed\n"); + return NULL; + } + + switch(type) { + case INTERNAL_IP4_ADDRESS: + switch(isakmp_cfg_config.confsource) { +#ifdef HAVE_LIBRADIUS + case ISAKMP_CFG_CONF_RADIUS: + if ((iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_RADIUS) + && (iph1->mode_cfg->addr4.s_addr != htonl(-2))) + /* + * -2 is 255.255.255.254, RADIUS uses that + * to instruct the NAS to use a local pool + */ + break; + plog(LLV_INFO, LOCATION, NULL, + "No IP from RADIUS, using local pool\n"); + /* FALLTHROUGH */ +#endif + case ISAKMP_CFG_CONF_LOCAL: + if (isakmp_cfg_getport(iph1) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "Port pool depleted\n"); + break; + } + + iph1->mode_cfg->addr4.s_addr = + htonl(ntohl(isakmp_cfg_config.network4) + + iph1->mode_cfg->port); + iph1->mode_cfg->flags |= ISAKMP_CFG_ADDR4_LOCAL; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected confsource\n"); + } + + if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGIN) != 0) + plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n"); + + return isakmp_cfg_addr4(iph1, + attr, &iph1->mode_cfg->addr4.s_addr); + break; + + case INTERNAL_IP4_NETMASK: + switch(isakmp_cfg_config.confsource) { +#ifdef HAVE_LIBRADIUS + case ISAKMP_CFG_CONF_RADIUS: + if (iph1->mode_cfg->flags & ISAKMP_CFG_MASK4_RADIUS) + break; + plog(LLV_INFO, LOCATION, NULL, + "No mask from RADIUS, using local pool\n"); + /* FALLTHROUGH */ +#endif + case ISAKMP_CFG_CONF_LOCAL: + iph1->mode_cfg->mask4.s_addr + = isakmp_cfg_config.netmask4; + iph1->mode_cfg->flags |= ISAKMP_CFG_MASK4_LOCAL; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected confsource\n"); + } + return isakmp_cfg_addr4(iph1, attr, + &iph1->mode_cfg->mask4.s_addr); + break; + + case INTERNAL_IP4_DNS: + return isakmp_cfg_addr4(iph1, + attr, &isakmp_cfg_config.dns4); + break; + + case INTERNAL_IP4_NBNS: + return isakmp_cfg_addr4(iph1, + attr, &isakmp_cfg_config.nbns4); + break; + + case INTERNAL_IP4_SUBNET: + return isakmp_cfg_addr4(iph1, + attr, &isakmp_cfg_config.network4); + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, "Unexpected type %d\n", type); + break; + } + + return NULL; +} + +#if 0 +static vchar_t * +isakmp_cfg_void(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + vchar_t *buffer; + struct isakmp_data *new; + + if ((buffer = vmalloc(sizeof(*attr))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return NULL; + } + + new = (struct isakmp_data *)buffer->v; + + new->type = attr->type; + new->lorv = htons(0); + + return buffer; +} +#endif + +vchar_t * +isakmp_cfg_copy(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + vchar_t *buffer; + size_t len = 0; + + if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TLV) + len = ntohs(attr->lorv); + + if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return NULL; + } + + memcpy(buffer->v, attr, sizeof(*attr) + ntohs(attr->lorv)); + + return buffer; +} + +vchar_t * +isakmp_cfg_short(iph1, attr, value) + struct ph1handle *iph1; + struct isakmp_data *attr; + int value; +{ + vchar_t *buffer; + struct isakmp_data *new; + int type; + + if ((buffer = vmalloc(sizeof(*attr))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return NULL; + } + + new = (struct isakmp_data *)buffer->v; + type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; + + new->type = htons(type | ISAKMP_GEN_TV); + new->lorv = htons(value); + + return buffer; +} + +vchar_t * +isakmp_cfg_string(iph1, attr, string) + struct ph1handle *iph1; + struct isakmp_data *attr; + char *string; +{ + vchar_t *buffer; + struct isakmp_data *new; + size_t len; + char *data; + + len = strlen(string); + if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return NULL; + } + + new = (struct isakmp_data *)buffer->v; + + new->type = attr->type; + new->lorv = htons(len); + data = (char *)(new + 1); + + memcpy(data, string, len); + + return buffer; +} + +static vchar_t * +isakmp_cfg_addr4(iph1, attr, addr) + struct ph1handle *iph1; + struct isakmp_data *attr; + in_addr_t *addr; +{ + vchar_t *buffer; + struct isakmp_data *new; + size_t len; + + len = sizeof(*addr); + if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return NULL; + } + + new = (struct isakmp_data *)buffer->v; + + new->type = attr->type; + new->lorv = htons(len); + memcpy(new + 1, addr, len); + + return buffer; +} + +struct isakmp_ivm * +isakmp_cfg_newiv(iph1, msgid) + struct ph1handle *iph1; + u_int32_t msgid; +{ + struct isakmp_cfg_state *ics = iph1->mode_cfg; + + if (ics == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "isakmp_cfg_newiv called without mode config state\n"); + return NULL; + } + + if (ics->ivm != NULL) + oakley_delivm(ics->ivm); + + ics->ivm = oakley_newiv2(iph1, msgid); + + return ics->ivm; +} + +/* Derived from isakmp_info_send_common */ +int +isakmp_cfg_send(iph1, payload, np, flags, new_exchange) + struct ph1handle *iph1; + vchar_t *payload; + u_int32_t np; + int flags; + int new_exchange; +{ + struct ph2handle *iph2 = NULL; + vchar_t *hash = NULL; + struct isakmp *isakmp; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = -1; + struct isakmp_cfg_state *ics = iph1->mode_cfg; + + /* Check if phase 1 is established */ + if ((iph1->status != PHASE1ST_ESTABLISHED) || + (iph1->local == NULL) || + (iph1->remote == NULL)) { + plog(LLV_ERROR, LOCATION, NULL, + "ISAKMP mode config exchange with immature phase 1\n"); + goto end; + } + + /* add new entry to isakmp status table */ + iph2 = newph2(); + if (iph2 == NULL) + goto end; + + iph2->dst = dupsaddr(iph1->remote); + iph2->src = dupsaddr(iph1->local); + switch (iph1->remote->sa_family) { + case AF_INET: +#ifndef ENABLE_NATT + ((struct sockaddr_in *)iph2->dst)->sin_port = 0; + ((struct sockaddr_in *)iph2->src)->sin_port = 0; +#endif + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0; + ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + delph2(iph2); + goto end; + } + iph2->ph1 = iph1; + iph2->side = INITIATOR; + iph2->status = PHASE2ST_START; + + if (new_exchange) + iph2->msgid = isakmp_newmsgid2(iph1); + else + iph2->msgid = iph1->msgid; + + /* get IV and HASH(1) if skeyid_a was generated. */ + if (iph1->skeyid_a != NULL) { + if (new_exchange) { + if (isakmp_cfg_newiv(iph1, iph2->msgid) == NULL) { + delph2(iph2); + goto end; + } + } + + /* generate HASH(1) */ + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload); + if (hash == NULL) { + delph2(iph2); + goto end; + } + + /* initialized total buffer length */ + tlen = hash->l; + tlen += sizeof(*gen); + } else { + /* IKE-SA is not established */ + hash = NULL; + + /* initialized total buffer length */ + tlen = 0; + } + if ((flags & ISAKMP_FLAG_A) == 0) + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E); + else + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A); + + insph2(iph2); + bindph12(iph1, iph2); + + tlen += sizeof(*isakmp) + payload->l; + + /* create buffer for isakmp payload */ + iph2->sendbuf = vmalloc(tlen); + if (iph2->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto err; + } + + /* create isakmp header */ + isakmp = (struct isakmp *)iph2->sendbuf->v; + memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH; + isakmp->v = iph1->version; + isakmp->etype = ISAKMP_ETYPE_CFG; + isakmp->flags = iph2->flags; + memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); + isakmp->len = htonl(tlen); + p = (char *)(isakmp + 1); + + /* create HASH payload */ + if (hash != NULL) { + gen = (struct isakmp_gen *)p; + gen->np = np & 0xff; + gen->len = htons(sizeof(*gen) + hash->l); + p += sizeof(*gen); + memcpy(p, hash->v, hash->l); + p += hash->l; + } + + /* add payload */ + memcpy(p, payload->v, payload->l); + p += payload->l; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1); +#endif + + /* encoding */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) { + vchar_t *tmp; + + tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, + ics->ivm->ive, ics->ivm->iv); + VPTRINIT(iph2->sendbuf); + if (tmp == NULL) + goto err; + iph2->sendbuf = tmp; + } + + /* HDR*, HASH(1), ATTR */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) { + VPTRINIT(iph2->sendbuf); + goto err; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "sendto mode config %s.\n", s_isakmp_nptype(np)); + + /* + * XXX We might need to resend the message... + */ + + error = 0; + VPTRINIT(iph2->sendbuf); + +err: + if (iph2->sendbuf != NULL) + vfree(iph2->sendbuf); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); +end: + if (hash) + vfree(hash); + return error; +} + + +void +isakmp_cfg_rmstate(iph1) + struct ph1handle *iph1; +{ + struct isakmp_cfg_state *state = iph1->mode_cfg; + + if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGOUT) != 0) + plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n"); + + if (state->flags & ISAKMP_CFG_PORT_ALLOCATED) + isakmp_cfg_putport(iph1, state->port); + + xauth_rmstate(&state->xauth); + + racoon_free(state); + iph1->mode_cfg = NULL; + + return; +} + +struct isakmp_cfg_state * +isakmp_cfg_mkstate(void) +{ + struct isakmp_cfg_state *state; + + if ((state = racoon_malloc(sizeof(*state))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory for mode config state\n"); + return NULL; + } + memset(state, 0, sizeof(*state)); + + return state; +} + +int +isakmp_cfg_getport(iph1) + struct ph1handle *iph1; +{ + unsigned int i; + size_t size = isakmp_cfg_config.pool_size; + + if (iph1->mode_cfg->flags & ISAKMP_CFG_PORT_ALLOCATED) + return iph1->mode_cfg->port; + + if (isakmp_cfg_config.port_pool == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "isakmp_cfg_config.port_pool == NULL\n"); + return -1; + } + + for (i = 0; i < size; i++) { + if (isakmp_cfg_config.port_pool[i].used == 0) + break; + } + + if (i == size) { + plog(LLV_ERROR, LOCATION, NULL, + "No more addresses available\n"); + return -1; + } + + isakmp_cfg_config.port_pool[i].used = 1; + + plog(LLV_INFO, LOCATION, NULL, "Using port %d\n", i); + + iph1->mode_cfg->flags |= ISAKMP_CFG_PORT_ALLOCATED; + iph1->mode_cfg->port = i; + + return i; +} + +int +isakmp_cfg_putport(iph1, index) + struct ph1handle *iph1; + unsigned int index; +{ + if (isakmp_cfg_config.port_pool == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "isakmp_cfg_config.port_pool == NULL\n"); + return -1; + } + + if (isakmp_cfg_config.port_pool[index].used == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Attempt to release an unallocated address (port %d)\n", + index); + return -1; + } + +#ifdef HAVE_LIBPAM + /* Cleanup PAM status associated with the port */ + if (isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_PAM) + privsep_cleanup_pam(index); +#endif + isakmp_cfg_config.port_pool[index].used = 0; + iph1->mode_cfg->flags &= ISAKMP_CFG_PORT_ALLOCATED; + + plog(LLV_INFO, LOCATION, NULL, "Released port %d\n", index); + + return 0; +} + +#ifdef HAVE_LIBPAM +void +cleanup_pam(port) + int port; +{ + if (isakmp_cfg_config.port_pool[port].pam != NULL) { + pam_end(isakmp_cfg_config.port_pool[port].pam, PAM_SUCCESS); + isakmp_cfg_config.port_pool[port].pam = NULL; + } + + return; +} +#endif + +/* Accounting, only for RADIUS or PAM */ +static int +isakmp_cfg_accounting(iph1, inout) + struct ph1handle *iph1; + int inout; +{ +#ifdef HAVE_LIBPAM + if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_PAM) + return privsep_accounting_pam(iph1->mode_cfg->port, + inout); +#endif +#ifdef HAVE_LIBRADIUS + if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS) + return isakmp_cfg_accounting_radius(iph1, inout); +#endif + return 0; +} + +#ifdef HAVE_LIBPAM +int +isakmp_cfg_accounting_pam(port, inout) + int port; + int inout; +{ + int error = 0; + pam_handle_t *pam; + + if (isakmp_cfg_config.port_pool == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "isakmp_cfg_config.port_pool == NULL\n"); + return -1; + } + + pam = isakmp_cfg_config.port_pool[port].pam; + if (pam == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "pam handle is NULL\n"); + return -1; + } + + switch (inout) { + case ISAKMP_CFG_LOGIN: + error = pam_open_session(pam, 0); + break; + case ISAKMP_CFG_LOGOUT: + error = pam_close_session(pam, 0); + pam_end(pam, error); + isakmp_cfg_config.port_pool[port].pam = NULL; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n"); + break; + } + + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pam_open_session/pam_close_session failed: %s\n", + pam_strerror(pam, error)); + return -1; + } + + return 0; +} +#endif /* HAVE_LIBPAM */ + +#ifdef HAVE_LIBRADIUS +static int +isakmp_cfg_accounting_radius(iph1, inout) + struct ph1handle *iph1; + int inout; +{ + /* For first time use, initialize Radius */ + if (radius_acct_state == NULL) { + if ((radius_acct_state = rad_acct_open()) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot init librradius\n"); + return -1; + } + + if (rad_config(radius_acct_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open librarius config file: %s\n", + rad_strerror(radius_acct_state)); + rad_close(radius_acct_state); + radius_acct_state = NULL; + return -1; + } + } + + if (rad_create_request(radius_acct_state, + RAD_ACCOUNTING_REQUEST) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_create_request failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + if (rad_put_string(radius_acct_state, RAD_USER_NAME, + iph1->mode_cfg->login) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_string failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + switch (inout) { + case ISAKMP_CFG_LOGIN: + inout = RAD_START; + break; + case ISAKMP_CFG_LOGOUT: + inout = RAD_STOP; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n"); + break; + } + + if (rad_put_addr(radius_acct_state, + RAD_FRAMED_IP_ADDRESS, iph1->mode_cfg->addr4) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_addr failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + if (rad_put_addr(radius_acct_state, + RAD_LOGIN_IP_HOST, iph1->mode_cfg->addr4) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_addr failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + if (rad_put_int(radius_acct_state, RAD_ACCT_STATUS_TYPE, inout) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_int failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + if (isakmp_cfg_radius_common(radius_acct_state, + iph1->mode_cfg->port) != 0) + return -1; + + if (rad_send_request(radius_acct_state) != RAD_ACCOUNTING_RESPONSE) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_send_request failed: %s\n", + rad_strerror(radius_acct_state)); + return -1; + } + + return 0; +} +#endif /* HAVE_LIBRADIUS */ + +/* + * Attributes common to all RADIUS requests + */ +#ifdef HAVE_LIBRADIUS +int +isakmp_cfg_radius_common(radius_state, port) + struct rad_handle *radius_state; + int port; +{ + struct utsname name; + static struct hostent *host = NULL; + struct in_addr nas_addr; + + /* + * Find our own IP by resolving our nodename + */ + if (host == NULL) { + if (uname(&name) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "uname failed: %s\n", strerror(errno)); + return -1; + } + + if ((host = gethostbyname(name.nodename)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gethostbyname failed: %s\n", strerror(errno)); + return -1; + } + } + + memcpy(&nas_addr, host->h_addr, sizeof(nas_addr)); + if (rad_put_addr(radius_state, RAD_NAS_IP_ADDRESS, nas_addr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_addr failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (rad_put_int(radius_state, RAD_NAS_PORT, port) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_int failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (rad_put_int(radius_state, RAD_NAS_PORT_TYPE, RAD_VIRTUAL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_int failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (rad_put_int(radius_state, RAD_SERVICE_TYPE, RAD_FRAMED) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_int failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + return 0; +} +#endif + +int +isakmp_cfg_getconfig(iph1) + struct ph1handle *iph1; +{ + vchar_t *buffer; + struct isakmp_pl_attr *attrpl; + struct isakmp_data *attr; + size_t len; + int error; + int attrcount; + int i; + int attrlist[] = { + INTERNAL_IP4_ADDRESS, + INTERNAL_IP4_NETMASK, + INTERNAL_IP4_DNS, + INTERNAL_IP4_NBNS, + UNITY_BANNER, + APPLICATION_VERSION, + }; + + attrcount = sizeof(attrlist) / sizeof(*attrlist); + len = sizeof(*attrpl) + sizeof(*attr) * attrcount; + + if ((buffer = vmalloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return -1; + } + + attrpl = (struct isakmp_pl_attr *)buffer->v; + attrpl->h.len = htons(len); + attrpl->type = ISAKMP_CFG_REQUEST; + attrpl->id = htons((u_int16_t)(eay_random() & 0xffff)); + + attr = (struct isakmp_data *)(attrpl + 1); + + for (i = 0; i < attrcount; i++) { + attr->type = htons(attrlist[i]); + attr->lorv = htons(0); + attr++; + } + + error = isakmp_cfg_send(iph1, buffer, + ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1); + + vfree(buffer); + + return error; +} + +static void +isakmp_cfg_getaddr4(attr, ip) + struct isakmp_data *attr; + struct in_addr *ip; +{ + size_t alen = ntohs(attr->lorv); + in_addr_t *addr; + + if (alen != sizeof(*ip)) { + plog(LLV_ERROR, LOCATION, NULL, "Bad IPv4 address len\n"); + return; + } + + addr = (in_addr_t *)(attr + 1); + ip->s_addr = *addr; + + return; +} + +int +isakmp_cfg_setenv(iph1, envp, envc) + struct ph1handle *iph1; + char ***envp; + int *envc; +{ +#define IP_MAX 40 + char addrstr[IP_MAX]; + + /* + * Internal IPv4 address, either if + * we are a client or a server. + */ + if ((iph1->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) || +#ifdef HAVE_LIBRADIUS + (iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_RADIUS) || +#endif + (iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_LOCAL)) { + inet_ntop(AF_INET, &iph1->mode_cfg->addr4, + addrstr, IP_MAX); + } else + addrstr[0] = '\0'; + + if (script_env_append(envp, envc, "INTERNAL_ADDR4", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_ADDR4\n"); + return -1; + } + + /* Internal IPv4 mask */ + if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_MASK4) + inet_ntop(AF_INET, &iph1->mode_cfg->mask4, + addrstr, IP_MAX); + else + addrstr[0] = '\0'; + + /* + * During several releases, documentation adverised INTERNAL_NETMASK4 + * while code was using INTERNAL_MASK4. We now do both. + */ + if (script_env_append(envp, envc, "INTERNAL_MASK4", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_MASK4\n"); + return -1; + } + + if (script_env_append(envp, envc, "INTERNAL_NETMASK4", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot set INTERNAL_NETMASK4\n"); + return -1; + } + + + /* Internal IPv4 DNS */ + if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_DNS4) + inet_ntop(AF_INET, &iph1->mode_cfg->dns4, + addrstr, IP_MAX); + else + addrstr[0] = '\0'; + + if (script_env_append(envp, envc, "INTERNAL_DNS4", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_DNS4\n"); + return -1; + } + + /* Internal IPv4 WINS */ + if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_WINS4) + inet_ntop(AF_INET, &iph1->mode_cfg->wins4, + addrstr, IP_MAX); + else + addrstr[0] = '\0'; + + if (script_env_append(envp, envc, "INTERNAL_WINS4", addrstr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_WINS4\n"); + return -1; + } + + return 0; +} diff --git a/ipsec-tools/racoon/isakmp_cfg.h b/ipsec-tools/racoon/isakmp_cfg.h new file mode 100644 index 0000000..ba45ef8 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_cfg.h @@ -0,0 +1,176 @@ +/* $KAME$ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_LIBPAM +#ifdef __APPLE__ +#include +#else +#include +#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 " + +/* + * Global configuration for ISAKMP mode confiration address allocation + * Readen from the mode_cfg section of racoon.conf + */ +struct isakmp_cfg_port { + char used; +#ifdef HAVE_LIBPAM + pam_handle_t *pam; +#endif +}; + +struct isakmp_cfg_config { + in_addr_t network4; + in_addr_t netmask4; + in_addr_t dns4; + in_addr_t nbns4; + struct isakmp_cfg_port *port_pool; + int authsource; + int confsource; + int accounting; + size_t pool_size; + int auth_throttle; + char motd[MAXPATHLEN + 1]; + int pfs_group; + int save_passwd; +}; + +/* For authsource */ +#define ISAKMP_CFG_AUTH_SYSTEM 0 +#define ISAKMP_CFG_AUTH_RADIUS 1 +#define ISAKMP_CFG_AUTH_PAM 2 + +/* For confsource */ +#define ISAKMP_CFG_CONF_LOCAL 0 +#define ISAKMP_CFG_CONF_RADIUS 1 + +/* For accounting */ +#define ISAKMP_CFG_ACCT_NONE 0 +#define ISAKMP_CFG_ACCT_RADIUS 1 +#define ISAKMP_CFG_ACCT_PAM 2 + +/* For pool_size */ +#define ISAKMP_CFG_MAX_CNX 255 + +/* For motd */ +#define ISAKMP_CFG_MOTD "/etc/motd" + +extern struct isakmp_cfg_config isakmp_cfg_config; + +/* + * ISAKMP mode config state + */ +#define LOGINLEN 31 +struct isakmp_cfg_state { + int flags; /* See below */ + unsigned int port; /* address index */ + char login[LOGINLEN + 1]; /* login */ + struct in_addr addr4; /* IPv4 address */ + struct in_addr mask4; /* IPv4 netmask */ + struct in_addr dns4; /* IPv4 DNS (when client only) */ + struct in_addr wins4; /* IPv4 WINS (when client only) */ + struct xauth_state xauth; /* Xauth state, if revelant */ + struct isakmp_ivm *ivm; /* XXX Use iph1's ivm? */ +}; + +/* flags */ +#define ISAKMP_CFG_VENDORID_XAUTH 0x01 /* Supports Xauth */ +#define ISAKMP_CFG_VENDORID_UNITY 0x02 /* Cisco Unity compliant */ +#define ISAKMP_CFG_PORT_ALLOCATED 0x04 /* Port allocated */ +#define ISAKMP_CFG_ADDR4_RADIUS 0x08 /* Address from RADIUS */ +#define ISAKMP_CFG_MASK4_RADIUS 0x10 /* Netmask from RADIUS */ +#define ISAKMP_CFG_ADDR4_LOCAL 0x20 /* Address from local pool */ +#define ISAKMP_CFG_MASK4_LOCAL 0x40 /* Netmask from local pool */ +#define ISAKMP_CFG_GOT_ADDR4 0x80 /* Client got address */ +#define ISAKMP_CFG_GOT_MASK4 0x100 /* Client got mask */ +#define ISAKMP_CFG_GOT_DNS4 0x200 /* Client got DNS */ +#define ISAKMP_CFG_GOT_WINS4 0x400 /* Client got WINS */ +#define ISAKMP_CFG_DELETE_PH1 0x800 /* phase 1 should be deleted */ + +struct isakmp_pl_attr; +struct ph1handle; +struct isakmp_ivm; +void isakmp_cfg_r(struct ph1handle *, vchar_t *); +int isakmp_cfg_attr_r(struct ph1handle *, u_int32_t, struct isakmp_pl_attr *); +int isakmp_cfg_reply(struct ph1handle *, struct isakmp_pl_attr *); +int isakmp_cfg_request(struct ph1handle *, struct isakmp_pl_attr *); +int isakmp_cfg_set(struct ph1handle *, struct isakmp_pl_attr *); +int isakmp_cfg_send(struct ph1handle *, vchar_t *, u_int32_t, int, int); +struct isakmp_ivm *isakmp_cfg_newiv(struct ph1handle *, u_int32_t); +void isakmp_cfg_rmstate(struct ph1handle *); +struct isakmp_cfg_state *isakmp_cfg_mkstate(void); +vchar_t *isakmp_cfg_copy(struct ph1handle *, struct isakmp_data *); +vchar_t *isakmp_cfg_short(struct ph1handle *, struct isakmp_data *, int); +vchar_t *isakmp_cfg_string(struct ph1handle *, struct isakmp_data *, char *); +int isakmp_cfg_getconfig(struct ph1handle *); +int isakmp_cfg_setenv(struct ph1handle *, char ***, int *); + +int isakmp_cfg_getport(struct ph1handle *); +int isakmp_cfg_putport(struct ph1handle *, unsigned int); + +#ifdef HAVE_LIBRADIUS +struct rad_handle; +extern struct rad_handle *radius_acct_state; +int isakmp_cfg_radius_common(struct rad_handle *, int); +#endif + +#ifdef HAVE_LIBPAM +int isakmp_cfg_accounting_pam(int, int); +void cleanup_pam(int); +#endif diff --git a/ipsec-tools/racoon/isakmp_frag.c b/ipsec-tools/racoon/isakmp_frag.c new file mode 100644 index 0000000..e728c74 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_frag.c @@ -0,0 +1,353 @@ +/* $Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "handler.h" +#include "isakmp_frag.h" +#include "strnames.h" + +int +isakmp_sendfrags(iph1, buf) + struct ph1handle *iph1; + vchar_t *buf; +{ + struct isakmp *hdr; + struct isakmp_frag *fraghdr; + caddr_t data; + caddr_t sdata; + size_t datalen; + size_t max_datalen; + size_t fraglen; + vchar_t *frag; + unsigned int trailer; + unsigned int fragnum = 0; + size_t len; + int etype; + + /* + * Catch the exchange type for later: the fragments and the + * fragmented packet must have the same exchange type. + */ + hdr = (struct isakmp *)buf->v; + etype = hdr->etype; + + /* + * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN + * First compute the maximum data length that will fit in it + */ + max_datalen = ISAKMP_FRAG_MAXLEN - + (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(trailer)); + + sdata = buf->v; + len = buf->l; + + while (len > 0) { + fragnum++; + + if (len > max_datalen) + datalen = max_datalen; + else + datalen = len; + + fraglen = sizeof(*hdr) + + sizeof(*fraghdr) + + datalen; + + if ((frag = vmalloc(fraglen)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return -1; + } + + set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG); + hdr = (struct isakmp *)frag->v; + hdr->etype = etype; + + fraghdr = (struct isakmp_frag *)(hdr + 1); + fraghdr->unknown0 = htons(0); + fraghdr->len = htons(fraglen - sizeof(*hdr)); + fraghdr->unknown1 = htons(1); + fraghdr->index = fragnum; + if (len == datalen) + fraghdr->flags = ISAKMP_FRAG_LAST; + else + fraghdr->flags = 0; + + data = (caddr_t)(fraghdr + 1); + memcpy(data, sdata, datalen); + + if (isakmp_send(iph1, frag) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n"); + return -1; + } + + vfree(frag); + + len -= datalen; + sdata += datalen; + } + + return fragnum; +} + +unsigned int +vendorid_frag_cap(gen) + struct isakmp_gen *gen; +{ + int *hp; + + hp = (int *)(gen + 1); + + return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]); +} + +int +isakmp_frag_extract(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp *isakmp; + struct isakmp_frag *frag; + struct isakmp_frag_item *item; + vchar_t *buf; + size_t len; + int last_frag = 0; + char *data; + int i; + + if (msg->l < sizeof(*isakmp) + sizeof(*frag)) { + plog(LLV_ERROR, LOCATION, NULL, "Message too short\n"); + return -1; + } + + isakmp = (struct isakmp *)msg->v; + frag = (struct isakmp_frag *)(isakmp + 1); + + /* + * frag->len is the frag payload data plus the frag payload header, + * whose size is sizeof(*frag) + */ + if (msg->l < sizeof(*isakmp) + ntohs(frag->len)) { + plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n"); + return -1; + } + + if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + return -1; + } + + if ((item = racoon_malloc(sizeof(*item))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + vfree(buf); + return -1; + } + + data = (char *)(frag + 1); + memcpy(buf->v, data, buf->l); + + item->frag_num = frag->index; + item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); + item->frag_next = NULL; + item->frag_packet = buf; + + /* Look for the last frag while inserting the new item in the chain */ + if (item->frag_last) + last_frag = item->frag_num; + + if (iph1->frag_chain == NULL) { + iph1->frag_chain = item; + } else { + struct isakmp_frag_item *current; + + current = iph1->frag_chain; + while (current->frag_next) { + if (current->frag_last) + last_frag = item->frag_num; + current = current->frag_next; + } + current->frag_next = item; + } + + /* If we saw the last frag, check if the chain is complete */ + if (last_frag != 0) { + for (i = 1; i <= last_frag; i++) { + item = iph1->frag_chain; + do { + if (item->frag_num == i) + break; + item = item->frag_next; + } while (item != NULL); + + if (item == NULL) /* Not found */ + break; + } + + if (item != NULL) /* It is complete */ + return 1; + } + + return 0; +} + +vchar_t * +isakmp_frag_reassembly(iph1) + struct ph1handle *iph1; +{ + struct isakmp_frag_item *item; + size_t len = 0; + vchar_t *buf = NULL; + int frag_count = 0; + int i; + char *data; + + if ((item = iph1->frag_chain) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n"); + goto out; + } + + do { + frag_count++; + len += item->frag_packet->l; + item = item->frag_next; + } while (item != NULL); + + if ((buf = vmalloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); + goto out; + } + data = buf->v; + + for (i = 1; i <= frag_count; i++) { + item = iph1->frag_chain; + do { + if (item->frag_num == i) + break; + item = item->frag_next; + } while (item != NULL); + + if (item == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Missing fragment #%d\n", i); + vfree(buf); + buf = NULL; + goto out; + } + memcpy(data, item->frag_packet->v, item->frag_packet->l); + data += item->frag_packet->l; + } + +out: + item = iph1->frag_chain; + do { + struct isakmp_frag_item *next_item; + + next_item = item->frag_next; + + vfree(item->frag_packet); + racoon_free(item); + + item = next_item; + } while (item != NULL); + + iph1->frag_chain = NULL; + + return buf; +} + +vchar_t * +isakmp_frag_addcap(buf, cap) + vchar_t *buf; + int cap; +{ + int *capp; + size_t len; + + /* If the capability has not been added, add room now */ + len = buf->l; + if (len == MD5_DIGEST_LENGTH) { + if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return NULL; + } + capp = (int *)(buf->v + len); + *capp = htonl(0); + } + + capp = (int *)(buf->v + MD5_DIGEST_LENGTH); + *capp |= htonl(cap); + + return buf; +} + diff --git a/ipsec-tools/racoon/isakmp_frag.h b/ipsec-tools/racoon/isakmp_frag.h new file mode 100644 index 0000000..52ee10a --- /dev/null +++ b/ipsec-tools/racoon/isakmp_frag.h @@ -0,0 +1,49 @@ +/* $Id: isakmp_frag.h,v 1.2 2004/10/24 16:51:24 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* IKE fragmentation capabilities */ +#define VENDORID_FRAG_BASE 0x40000000 +#define VENDORID_FRAG_AGG 0x80000000 + +#define ISAKMP_FRAG_MAXLEN 552 + +struct isakmp_frag_item { + int frag_num; + int frag_last; + struct isakmp_frag_item *frag_next; + vchar_t *frag_packet; +}; + +int isakmp_sendfrags(struct ph1handle *, vchar_t *); +unsigned int vendorid_frag_cap(struct isakmp_gen *); +int isakmp_frag_extract(struct ph1handle *, vchar_t *); +vchar_t *isakmp_frag_reassembly(struct ph1handle *); +vchar_t *isakmp_frag_addcap(vchar_t *, int); diff --git a/ipsec-tools/racoon/isakmp_ident.c b/ipsec-tools/racoon/isakmp_ident.c new file mode 100644 index 0000000..d9e6cf9 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_ident.c @@ -0,0 +1,1792 @@ +/* $Id: isakmp_ident.c,v 1.13.2.2 2005/11/21 09:46:23 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Identity Protecion Exchange (Main Mode) */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<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, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, 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), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<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, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, 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), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<Ke_i] + * responders 2nd exchnage send to initiator + * psk: HDR, KE, Nr + * sig: HDR, KE, Nr [, CR ] + * rsa: HDR, KE, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, Ke_r, + */ +static vchar_t * +ident_ir2mx(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = 0; + struct payload_list *plist = NULL; + int need_cr = 0; + vchar_t *cr = NULL; + vchar_t *vid = NULL; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif +#ifdef ENABLE_NATT + vchar_t *natd[2] = { NULL, NULL }; +#endif + + /* create CR if need */ + if (iph1->side == RESPONDER + && iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + gssapi_get_token_to_send(iph1, &gsstoken); +#endif + + /* create isakmp KE payload */ + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); + + /* create isakmp NONCE payload */ + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); +#endif + + /* append vendor id, if needed */ + if (vid) + plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID); + + /* create isakmp CR payload if needed */ + if (need_cr) + plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR); + +#ifdef ENABLE_NATT + /* generate and append NAT-D payloads */ + if (NATT_AVAILABLE(iph1) && iph1->status == PHASE1ST_MSG2RECEIVED) + { + if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->remote)); + goto end; + } + + if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "NAT-D hashing failed for %s\n", saddr2str(iph1->local)); + goto end; + } + + plog (LLV_INFO, LOCATION, NULL, "Adding remote and local NAT-D payloads.\n"); +#ifdef __APPLE__ + /* old Apple version sends natd payloads in the wrong order */ + if (iph1->natt_options->version == VENDORID_NATT_APPLE) { + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + } else +#endif + { + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); + } + } +#endif + + buf = isakmp_plist_set_all (&plist, iph1); + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (cr) + vfree(cr); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); +#endif + if (vid) + vfree(vid); + +#ifdef ENABLE_NATT + if (natd[0]) + vfree(natd[0]); + if (natd[1]) + vfree(natd[1]); +#endif + + return buf; +} + +/* + * This is used in main mode for: + * initiator's 4th exchange send to responder + * psk: HDR*, IDi1, HASH_I + * sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I + * gssapi: HDR*, [ IDi1, ] < GSSi(n) | HASH_I > + * rsa: HDR*, HASH_I + * rev: HDR*, HASH_I + * responders 3rd exchnage send to initiator + * psk: HDR*, IDr1, HASH_R + * sig: HDR*, IDr1, [ CERT, ] SIG_R + * gssapi: HDR*, [ IDr1, ] < GSSr(n) | HASH_R > + * rsa: HDR*, HASH_R + * rev: HDR*, HASH_R + */ +static vchar_t * +ident_ir3mx(iph1) + struct ph1handle *iph1; +{ + struct payload_list *plist = NULL; + vchar_t *buf = NULL, *new = NULL; + int need_cr = 0; + int need_cert = 0; + vchar_t *cr = NULL; + int error = -1; +#ifdef HAVE_GSSAPI + int nptype; + vchar_t *gsstoken = NULL; + vchar_t *gsshash = NULL; +#endif + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + /* create isakmp ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + + /* create isakmp HASH payload */ + plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH); + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + /* create CR if need */ + if (iph1->side == INITIATOR + && iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } + + if (iph1->cert != NULL && iph1->rmconf->send_cert) + need_cert = 1; + + /* add ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + + /* add CERT payload if there */ + if (need_cert) + plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT); + /* add SIG payload */ + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); + + /* create isakmp CR payload */ + if (need_cr) + plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR); + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + if (iph1->hash != NULL) { + gsshash = gssapi_wraphash(iph1); + if (gsshash == NULL) + goto end; + } else { + gssapi_get_token_to_send(iph1, &gsstoken); + } + + if (!gssapi_id_sent(iph1)) { + /* create isakmp ID payload */ + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); + gssapi_set_id_sent(iph1); + } + + if (iph1->hash != NULL) + /* create isakmp HASH payload */ + plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH); + else + plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication type %d\n", + iph1->approval->authmethod); + goto end; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication type %d\n", + iph1->approval->authmethod); + goto end; + } + + buf = isakmp_plist_set_all (&plist, iph1); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph1->local, iph1->remote, 1); +#endif + + /* encoding */ + new = oakley_do_encrypt(iph1, buf, iph1->ivm->ive, iph1->ivm->iv); + if (new == NULL) + goto end; + + vfree(buf); + + buf = new; + + error = 0; + +end: + if (cr) + vfree(cr); + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + + return buf; +} diff --git a/ipsec-tools/racoon/isakmp_ident.h b/ipsec-tools/racoon/isakmp_ident.h new file mode 100644 index 0000000..38fb875 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_ident.h @@ -0,0 +1,50 @@ +/* $Id: isakmp_ident.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_IDENT_H +#define _ISAKMP_IDENT_H + +extern int ident_i1send __P((struct ph1handle *, vchar_t *)); +extern int ident_i2recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i2send __P((struct ph1handle *, vchar_t *)); +extern int ident_i3recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i3send __P((struct ph1handle *, vchar_t *)); +extern int ident_i4recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i4send __P((struct ph1handle *, vchar_t *)); + +extern int ident_r1recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r1send __P((struct ph1handle *, vchar_t *)); +extern int ident_r2recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r2send __P((struct ph1handle *, vchar_t *)); +extern int ident_r3recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r3send __P((struct ph1handle *, vchar_t *)); + +#endif /* _ISAKMP_IDENT_H */ diff --git a/ipsec-tools/racoon/isakmp_inf.c b/ipsec-tools/racoon/isakmp_inf.c new file mode 100644 index 0000000..a681061 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_inf.c @@ -0,0 +1,1799 @@ +/* $Id: isakmp_inf.c,v 1.14.4.9 2005/08/02 15:09:26 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif +#include +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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 *)); + +/* %%% + * Information Exchange + */ +/* + * receive Information + */ +int +isakmp_info_recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + int error = -1; + struct isakmp *isakmp; + struct isakmp_gen *gen; + void *p; + vchar_t *hash, *payload; + struct isakmp_gen *nd; + u_int8_t np; + int encrypted; + + plog(LLV_DEBUG, LOCATION, NULL, "receive Information.\n"); + + encrypted = ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E); + + /* Use new IV to decrypt Informational message. */ + if (encrypted) { + + struct isakmp_ivm *ivm; + + /* compute IV */ + ivm = oakley_newiv2(iph1, ((struct isakmp *)msg0->v)->msgid); + if (ivm == NULL) + return -1; + + msg = oakley_do_decrypt(iph1, msg0, ivm->iv, ivm->ive); + oakley_delivm(ivm); + if (msg == NULL) + return -1; + + } else + msg = vdup(msg0); + + /* Safety check */ + if (msg->l < sizeof(*isakmp) + sizeof(*gen)) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information because the " + "message is way too short\n"); + goto end; + } + + isakmp = (struct isakmp *)msg->v; + gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp)); + np = gen->np; + + if (encrypted) { + if (isakmp->np != ISAKMP_NPTYPE_HASH) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information because the " + "message has no hash payload.\n"); + goto end; + } + + if (iph1->status != PHASE1ST_ESTABLISHED) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information because ISAKMP-SA " + "has not been established yet.\n"); + goto end; + } + + /* Safety check */ + if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information because the " + "message is too short\n"); + goto end; + } + + p = (caddr_t) gen + sizeof(struct isakmp_gen); + nd = (struct isakmp_gen *) ((caddr_t) gen + ntohs(gen->len)); + + /* nd length check */ + if (ntohs(nd->len) > msg->l - (sizeof(struct isakmp) + + ntohs(gen->len))) { + plog(LLV_ERROR, LOCATION, NULL, + "too long payload length (broken message?)\n"); + goto end; + } + + if (ntohs(nd->len) < sizeof(*nd)) { + plog(LLV_ERROR, LOCATION, NULL, + "too short payload length (broken message?)\n"); + goto end; + } + + payload = vmalloc(ntohs(nd->len)); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory\n"); + goto end; + } + + memcpy(payload->v, (caddr_t) nd, ntohs(nd->len)); + + /* compute HASH */ + hash = oakley_compute_hash1(iph1, isakmp->msgid, payload); + if (hash == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot compute hash\n"); + + vfree(payload); + goto end; + } + + if (ntohs(gen->len) - sizeof(struct isakmp_gen) != hash->l) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information due to hash length mismatch\n"); + + vfree(hash); + vfree(payload); + goto end; + } + + if (memcmp(p, hash->v, hash->l) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ignore information due to hash mismatch\n"); + + vfree(hash); + vfree(payload); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "hash validated.\n"); + + vfree(hash); + vfree(payload); + } else { + /* make sure the packet were encrypted after the beginning of phase 1. */ + switch (iph1->etype) { + case ISAKMP_ETYPE_AGG: + case ISAKMP_ETYPE_BASE: + case ISAKMP_ETYPE_IDENT: + if ((iph1->side == INITIATOR && iph1->status < PHASE1ST_MSG3SENT) + || (iph1->side == RESPONDER && iph1->status < PHASE1ST_MSG2SENT)) { + break; + } + /*FALLTHRU*/ + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "%s message must be encrypted\n", + s_isakmp_nptype(np)); + goto end; + } + } + + switch (np) { + case ISAKMP_NPTYPE_N: + isakmp_info_recv_n(iph1, msg, encrypted); + break; + case ISAKMP_NPTYPE_D: + if (encrypted) + isakmp_info_recv_d(iph1, msg); + else + plog(LLV_ERROR, LOCATION, iph1->remote, + "unencrypted information message with delete payload received\n"); + break; + case ISAKMP_NPTYPE_NONCE: + /* XXX to be 6.4.2 ike-01.txt */ + /* XXX IV is to be synchronized. */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore Acknowledged Informational\n"); + break; + default: + /* don't send information, see isakmp_ident_r1() */ + error = 0; + plog(LLV_ERROR, LOCATION, iph1->remote, + "reject the packet, " + "received unexpecting payload type %d.\n", + gen->np); + break; + } + + end: + if (msg != NULL) + vfree(msg); + + return 0; +} + +/* + * send Delete payload (for ISAKMP SA) in Informational exchange. + */ +int +isakmp_info_send_d1(iph1) + struct ph1handle *iph1; +{ + struct isakmp_pl_d *d; + vchar_t *payload = NULL; + int tlen; + int error = 0; + + if (iph1->status != PHASE2ST_ESTABLISHED) + return 0; + + /* create delete payload */ + + /* send SPIs of inbound SAs. */ + /* XXX should send outbound SAs's ? */ + tlen = sizeof(*d) + sizeof(isakmp_index); + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for payload.\n"); + return errno; + } + + d = (struct isakmp_pl_d *)payload->v; + d->h.np = ISAKMP_NPTYPE_NONE; + d->h.len = htons(tlen); + d->doi = htonl(IPSEC_DOI); + d->proto_id = IPSECDOI_PROTO_ISAKMP; + d->spi_size = sizeof(isakmp_index); + d->num_spi = htons(1); + memcpy(d + 1, &iph1->index, sizeof(isakmp_index)); + + error = isakmp_info_send_common(iph1, payload, + ISAKMP_NPTYPE_D, 0); + vfree(payload); + + return error; +} + +/* + * send Delete payload (for IPsec SA) in Informational exchange, based on + * pfkey msg. It sends always single SPI. + */ +int +isakmp_info_send_d2(iph2) + struct ph2handle *iph2; +{ + struct ph1handle *iph1; + struct saproto *pr; + struct isakmp_pl_d *d; + vchar_t *payload = NULL; + int tlen; + int error = 0; + u_int8_t *spi; + + if (iph2->status != PHASE2ST_ESTABLISHED) + return 0; + + /* + * don't send delete information if there is no phase 1 handler. + * It's nonsensical to negotiate phase 1 to send the information. + */ + iph1 = getph1byaddr(iph2->src, iph2->dst); + if (iph1 == NULL) + return 0; + + /* create delete payload */ + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + + /* send SPIs of inbound SAs. */ + /* + * XXX should I send outbound SAs's ? + * I send inbound SAs's SPI only at the moment because I can't + * decode any more if peer send encoded packet without aware of + * deletion of SA. Outbound SAs don't come under the situation. + */ + tlen = sizeof(*d) + pr->spisize; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for payload.\n"); + return errno; + } + + d = (struct isakmp_pl_d *)payload->v; + d->h.np = ISAKMP_NPTYPE_NONE; + d->h.len = htons(tlen); + d->doi = htonl(IPSEC_DOI); + d->proto_id = pr->proto_id; + d->spi_size = pr->spisize; + d->num_spi = htons(1); + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + spi = (u_int8_t *)&pr->spi; + spi += sizeof(pr->spi); + spi -= pr->spisize; + memcpy(d + 1, spi, pr->spisize); + + error = isakmp_info_send_common(iph1, payload, + ISAKMP_NPTYPE_D, 0); + vfree(payload); + } + + return error; +} + +/* + * send Notification payload (for without ISAKMP SA) in Informational exchange + */ +int +isakmp_info_send_nx(isakmp, remote, local, type, data) + struct isakmp *isakmp; + struct sockaddr *remote, *local; + int type; + vchar_t *data; +{ + struct ph1handle *iph1 = NULL; + struct remoteconf *rmconf; + vchar_t *payload = NULL; + int tlen; + int error = -1; + struct isakmp_pl_n *n; + int spisiz = 0; /* see below */ + + /* search appropreate configuration */ + rmconf = getrmconf(remote); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "no configuration found for peer address.\n"); + goto end; + } + + /* add new entry to isakmp status table. */ + iph1 = newph1(); + if (iph1 == NULL) + return -1; + + memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t)); + isakmp_newcookie((char *)&iph1->index.r_ck, remote, local); + iph1->status = PHASE1ST_START; + iph1->rmconf = rmconf; + iph1->side = INITIATOR; + iph1->version = isakmp->v; + iph1->flags = 0; + iph1->msgid = 0; /* XXX */ +#ifdef ENABLE_HYBRID + if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) + return -1; +#endif +#ifdef ENABLE_FRAG + iph1->frag = 0; + iph1->frag_chain = NULL; +#endif + + /* copy remote address */ + if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) + return -1; + + tlen = sizeof(*n) + spisiz; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); + n->proto_id = IPSECDOI_KEY_IKE; + n->spi_size = spisiz; + n->type = htons(type); + if (spisiz) + memset(n + 1, 0, spisiz); /*XXX*/ + if (data) + memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); + +#ifdef ENABLE_VPNCONTROL_PORT + { + u_int32_t address; + if (type == ISAKMP_INTERNAL_ERROR || + type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) { + if (remote->sa_family == AF_INET) + address = ((struct sockaddr_in *)remote)->sin_addr.s_addr; + else + address = 0; + (void)vpncontrol_notify_ike_failed(type, FROM_LOCAL, address, + (data ? data->l : 0), (data ? data->v : NULL)); + } + } +#endif + + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); + vfree(payload); + + end: + if (iph1 != NULL) + delph1(iph1); + + return error; +} + +/* + * send Notification payload (for ISAKMP SA) in Informational exchange + */ +int +isakmp_info_send_n1(iph1, type, data) + struct ph1handle *iph1; + int type; + vchar_t *data; +{ + vchar_t *payload = NULL; + int tlen; + int error = 0; + struct isakmp_pl_n *n; + int spisiz; + + /* + * note on SPI size: which description is correct? I have chosen + * this to be 0. + * + * RFC2408 3.1, 2nd paragraph says: ISAKMP SA is identified by + * Initiator/Responder cookie and SPI has no meaning, SPI size = 0. + * RFC2408 3.1, first paragraph on page 40: ISAKMP SA is identified + * by cookie and SPI has no meaning, 0 <= SPI size <= 16. + * RFC2407 4.6.3.3, INITIAL-CONTACT is required to set to 16. + */ + if (type == ISAKMP_NTYPE_INITIAL_CONTACT || + type == ISAKMP_NTYPE_LOAD_BALANCE) + spisiz = sizeof(isakmp_index); + else + spisiz = 0; + + tlen = sizeof(*n) + spisiz; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + return errno; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(iph1->rmconf->doitype); + n->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX to be configurable ? */ + n->spi_size = spisiz; + n->type = htons(type); + if (spisiz) + memcpy(n + 1, &iph1->index, sizeof(isakmp_index)); + if (data) + memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); + +#ifdef ENABLE_VPNCONTROL_PORT + { + u_int32_t address; + + if (type == ISAKMP_INTERNAL_ERROR || + type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) { + if (iph1->remote->sa_family == AF_INET) + address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr; + else + address = 0; + (void)vpncontrol_notify_ike_failed(type, FROM_LOCAL, address, + (data ? data->l : 0), (data ? data->v : NULL)); + } + } +#endif + + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph1->flags); + vfree(payload); + + return error; +} + +/* + * send Notification payload (for IPsec SA) in Informational exchange + */ +int +isakmp_info_send_n2(iph2, type, data) + struct ph2handle *iph2; + int type; + vchar_t *data; +{ + struct ph1handle *iph1 = iph2->ph1; + vchar_t *payload = NULL; + int tlen; + int error = 0; + struct isakmp_pl_n *n; + struct saproto *pr; + + if (!iph2->approval) + return EINVAL; + + pr = iph2->approval->head; + + /* XXX must be get proper spi */ + tlen = sizeof(*n) + pr->spisize; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + return errno; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ + n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ + n->spi_size = pr->spisize; + n->type = htons(type); + *(u_int32_t *)(n + 1) = pr->spi; + if (data) + memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); + + iph2->flags |= ISAKMP_FLAG_E; /* XXX Should we do FLAG_A ? */ + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph2->flags); + vfree(payload); + + return error; +} + +/* + * send Information + * When ph1->skeyid_a == NULL, send message without encoding. + */ +int +isakmp_info_send_common(iph1, payload, np, flags) + struct ph1handle *iph1; + vchar_t *payload; + u_int32_t np; + int flags; +{ + struct ph2handle *iph2 = NULL; + vchar_t *hash = NULL; + struct isakmp *isakmp; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = -1; + + /* add new entry to isakmp status table */ + iph2 = newph2(); + if (iph2 == NULL) + goto end; + + iph2->dst = dupsaddr(iph1->remote); + iph2->src = dupsaddr(iph1->local); + switch (iph1->remote->sa_family) { + case AF_INET: +#ifndef ENABLE_NATT + ((struct sockaddr_in *)iph2->dst)->sin_port = 0; + ((struct sockaddr_in *)iph2->src)->sin_port = 0; +#endif + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0; + ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + delph2(iph2); + goto end; + } + iph2->ph1 = iph1; + iph2->side = INITIATOR; + iph2->status = PHASE2ST_START; + iph2->msgid = isakmp_newmsgid2(iph1); + + /* get IV and HASH(1) if skeyid_a was generated. */ + if (iph1->skeyid_a != NULL) { + iph2->ivm = oakley_newiv2(iph1, iph2->msgid); + if (iph2->ivm == NULL) { + delph2(iph2); + goto end; + } + + /* generate HASH(1) */ + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload); + if (hash == NULL) { + delph2(iph2); + goto end; + } + + /* initialized total buffer length */ + tlen = hash->l; + tlen += sizeof(*gen); + } else { + /* IKE-SA is not established */ + hash = NULL; + + /* initialized total buffer length */ + tlen = 0; + } + if ((flags & ISAKMP_FLAG_A) == 0) + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E); + else + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A); + + insph2(iph2); + bindph12(iph1, iph2); + + tlen += sizeof(*isakmp) + payload->l; + + /* create buffer for isakmp payload */ + iph2->sendbuf = vmalloc(tlen); + if (iph2->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto err; + } + + /* create isakmp header */ + isakmp = (struct isakmp *)iph2->sendbuf->v; + memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH; + isakmp->v = iph1->version; + isakmp->etype = ISAKMP_ETYPE_INFO; + isakmp->flags = iph2->flags; + memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); + isakmp->len = htonl(tlen); + p = (char *)(isakmp + 1); + + /* create HASH payload */ + if (hash != NULL) { + gen = (struct isakmp_gen *)p; + gen->np = np & 0xff; + gen->len = htons(sizeof(*gen) + hash->l); + p += sizeof(*gen); + memcpy(p, hash->v, hash->l); + p += hash->l; + } + + /* add payload */ + memcpy(p, payload->v, payload->l); + p += payload->l; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1); +#endif + + /* encoding */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) { + vchar_t *tmp; + + tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, iph2->ivm->ive, + iph2->ivm->iv); + VPTRINIT(iph2->sendbuf); + if (tmp == NULL) + goto err; + iph2->sendbuf = tmp; + } + + /* HDR*, HASH(1), N */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) { + VPTRINIT(iph2->sendbuf); + goto err; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "sendto Information %s.\n", s_isakmp_nptype(np)); + + /* + * don't resend notify message because peer can use Acknowledged + * Informational if peer requires the reply of the notify message. + */ + + /* XXX If Acknowledged Informational required, don't delete ph2handle */ + error = 0; + VPTRINIT(iph2->sendbuf); + goto err; /* XXX */ + +end: + if (hash) + vfree(hash); + return error; + +err: + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + goto end; +} + +/* + * add a notify payload to buffer by reallocating buffer. + * If buf == NULL, the function only create a notify payload. + * + * XXX Which is SPI to be included, inbound or outbound ? + */ +vchar_t * +isakmp_add_pl_n(buf0, np_p, type, pr, data) + vchar_t *buf0; + u_int8_t **np_p; + int type; + struct saproto *pr; + vchar_t *data; +{ + vchar_t *buf = NULL; + struct isakmp_pl_n *n; + int tlen; + int oldlen = 0; + + if (*np_p) + **np_p = ISAKMP_NPTYPE_N; + + tlen = sizeof(*n) + pr->spisize; + + if (data) + tlen += data->l; + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, buf0->l + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a payload buffer.\n"); + return NULL; + } + + n = (struct isakmp_pl_n *)(buf->v + oldlen); + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ + n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ + n->spi_size = pr->spisize; + n->type = htons(type); + *(u_int32_t *)(n + 1) = pr->spi; /* XXX */ + if (data) + memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); + + /* save the pointer of next payload type */ + *np_p = &n->h.np; + + return buf; +} + +/* + * handling to receive Notification payload + */ +static int +isakmp_info_recv_n(iph1, msg, encrypted) + struct ph1handle *iph1; + vchar_t *msg; + int encrypted; +{ + struct isakmp_pl_n *n = NULL; + u_int type; + vchar_t *pbuf; + struct isakmp_parse_t *pa, *pap; + char *spi; + + if (!(pbuf = isakmp_parse(msg))) + return -1; + pa = (struct isakmp_parse_t *)pbuf->v; + for (pap = pa; pap->type; pap++) { + switch (pap->type) { + case ISAKMP_NPTYPE_HASH: + /* do something here */ + break; + case ISAKMP_NPTYPE_NONCE: + /* send to ack */ + break; + case ISAKMP_NPTYPE_N: + n = (struct isakmp_pl_n *)pap->ptr; + break; + default: + vfree(pbuf); + return -1; + } + } + vfree(pbuf); + if (!n) + return -1; + + type = ntohs(n->type); + + switch (type) { + case ISAKMP_NTYPE_CONNECTED: + case ISAKMP_NTYPE_RESPONDER_LIFETIME: + case ISAKMP_NTYPE_REPLAY_STATUS: + /* do something */ + break; + case ISAKMP_NTYPE_INITIAL_CONTACT: + if (encrypted) + info_recv_initialcontact(iph1); + else + plog(LLV_ERROR, LOCATION, iph1->remote, + "unencrypted INITIAL_CONTACT message received"); + break; +#ifdef ENABLE_DPD + case ISAKMP_NTYPE_R_U_THERE: + if (encrypted) + isakmp_info_recv_r_u(iph1, (struct isakmp_pl_ru *)n, + ((struct isakmp *)msg->v)->msgid); + else + plog(LLV_ERROR, LOCATION, iph1->remote, + "unencrypted R_U_THERE message received"); + break; + case ISAKMP_NTYPE_R_U_THERE_ACK: + if (encrypted) + isakmp_info_recv_r_u_ack(iph1, (struct isakmp_pl_ru *)n, + ((struct isakmp *)msg->v)->msgid); + else + plog(LLV_ERROR, LOCATION, iph1->remote, + "unencrypted R_U_THERE_ACK received"); + break; +#endif + +#ifdef ENABLE_VPNCONTROL_PORT + case ISAKMP_NTYPE_LOAD_BALANCE: + isakmp_info_recv_lb(iph1, (struct isakmp_pl_lb *)n, encrypted); + break; +#endif + + default: + if (encrypted) { + u_int32_t msgid = ((struct isakmp *)msg->v)->msgid; + struct ph2handle *iph2; + + /* XXX there is a potential of dos attack. */ + if (msgid == 0) { + /* delete ph1 */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete phase1 handle.\n"); + return -1; + } else { + iph2 = getph2bymsgid(iph1, msgid); + if (iph2 == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "unknown notify message, " + "no phase2 handle found.\n"); + } else { + /* sanity check */ + if (n->h.len < (sizeof(struct isakmp_pl_n) + n->spi_size)) + plog(LLV_ERROR, LOCATION, iph1->remote, + "notification payload length invalid.\n"); + else { + +#ifdef ENABLE_VPNCONTROL_PORT + + u_int32_t address; + u_int16_t data_len = n->h.len - (sizeof(struct isakmp_pl_n) + n->spi_size); + u_int8_t *data_ptr = ((u_int8_t *)n) + (n->h.len - data_len); + + if (type == ISAKMP_INTERNAL_ERROR || + type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) { + if (iph1->remote->sa_family == AF_INET) + address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr; + else + address = 0; + + vpncontrol_notify_ike_failed(type, FROM_REMOTE, address, data_len, data_ptr); + } +#endif + /* delete ph2 */ + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + } + } + } else + plog(LLV_ERROR, LOCATION, iph1->remote, + "unencrypted notification message received"); + break; + } + + /* get spi and allocate */ + if (ntohs(n->h.len) < sizeof(*n) + n->spi_size) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid spi_size in notification payload.\n"); + return -1; + } + spi = val2str((char *)(n + 1), n->spi_size); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "notification message %d:%s, " + "doi=%d proto_id=%d spi=%s(size=%d).\n", + type, s_isakmp_notify_msg(type), + ntohl(n->doi), n->proto_id, spi, n->spi_size); + + racoon_free(spi); + + return(0); +} + +void +purge_isakmp_spi(proto, spi, n) + int proto; + isakmp_index *spi; /*network byteorder*/ + size_t n; +{ + struct ph1handle *iph1; + size_t i; + + for (i = 0; i < n; i++) { + iph1 = getph1byindex(&spi[i]); + if (!iph1) + continue; + + plog(LLV_INFO, LOCATION, NULL, + "purged ISAKMP-SA proto_id=%s spi=%s.\n", + s_ipsecdoi_proto(proto), + isakmp_pindex(&spi[i], 0)); + + if (iph1->sce) + SCHED_KILL(iph1->sce); + iph1->status = PHASE1ST_EXPIRED; + iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + } +} + +static void +purge_ipsec_spi(dst0, proto, spi, n) + struct sockaddr *dst0; + int proto; + u_int32_t *spi; /*network byteorder*/ + size_t n; +{ + vchar_t *buf = NULL; + struct sadb_msg *msg, *next, *end; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + size_t i; + caddr_t mhp[SADB_EXT_MAX + 1]; + + buf = pfkey_dump_sadb(ipsecdoi2pfkey_proto(proto)); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + while (msg < end) { + if ((msg->sadb_msg_len << 3) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + if (!sa + || !mhp[SADB_EXT_ADDRESS_SRC] + || !mhp[SADB_EXT_ADDRESS_DST]) { + msg = next; + continue; + } + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if (sa->sadb_sa_state != SADB_SASTATE_MATURE + && sa->sadb_sa_state != SADB_SASTATE_DYING) { + msg = next; + continue; + } + + /* XXX n^2 algorithm, inefficient */ + + /* don't delete inbound SAs at the moment */ + /* XXX should we remove SAs with opposite direction as well? */ + if (CMPSADDR(dst0, dst)) { + msg = next; + continue; + } + + for (i = 0; i < n; i++) { + plog(LLV_DEBUG, LOCATION, NULL, + "check spi(packet)=%u spi(db)=%u.\n", + ntohl(spi[i]), ntohl(sa->sadb_sa_spi)); + if (spi[i] != sa->sadb_sa_spi) + continue; + + pfkey_send_delete(lcconf->sock_pfkey, + msg->sadb_msg_satype, + IPSEC_MODE_ANY, + src, dst, sa->sadb_sa_spi); + + /* + * delete a relative phase 2 handler. + * continue to process if no relative phase 2 handler + * exists. + */ + iph2 = getph2bysaidx(src, dst, proto, spi[i]); + if (iph2) { + delete_spd(iph2); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + + plog(LLV_INFO, LOCATION, NULL, + "purged IPsec-SA proto_id=%s spi=%u.\n", + s_ipsecdoi_proto(proto), + ntohl(spi[i])); + } + + msg = next; + } + + if (buf) + vfree(buf); +} + +/* + * delete all phase2 sa relatived to the destination address. + * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore + * an INITIAL-CONTACT if we have contacted the peer. This matches the + * Sun IKE behavior, and makes rekeying work much better when the peer + * restarts. + */ +static void +info_recv_initialcontact(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL; + struct sadb_msg *msg, *next, *end; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + caddr_t mhp[SADB_EXT_MAX + 1]; + int proto_id, i; + struct ph2handle *iph2; +#if 0 + char *loc, *rem; +#endif + + if (f_local) + return; + +#if 0 + loc = strdup(saddrwop2str(iph1->local)); + rem = strdup(saddrwop2str(iph1->remote)); + + /* + * Purge all IPSEC-SAs for the peer. We can do this + * the easy way (using a PF_KEY SADB_DELETE extension) + * or we can do it the hard way. + */ + for (i = 0; i < pfkey_nsatypes; i++) { + proto_id = pfkey2ipsecdoi_proto(pfkey_satypes[i].ps_satype); + + plog(LLV_INFO, LOCATION, NULL, + "purging %s SAs for %s -> %s\n", + pfkey_satypes[i].ps_name, loc, rem); + if (pfkey_send_delete_all(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, + iph1->local, iph1->remote) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "delete_all %s -> %s failed for %s (%s)\n", + loc, rem, + pfkey_satypes[i].ps_name, ipsec_strerror()); + goto the_hard_way; + } + + deleteallph2(iph1->local, iph1->remote, proto_id); + + plog(LLV_INFO, LOCATION, NULL, + "purging %s SAs for %s -> %s\n", + pfkey_satypes[i].ps_name, rem, loc); + if (pfkey_send_delete_all(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, + iph1->remote, iph1->local) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "delete_all %s -> %s failed for %s (%s)\n", + rem, loc, + pfkey_satypes[i].ps_name, ipsec_strerror()); + goto the_hard_way; + } + + deleteallph2(iph1->remote, iph1->local, proto_id); + } + + racoon_free(loc); + racoon_free(rem); + return; + + the_hard_way: + racoon_free(loc); + racoon_free(rem); +#endif + + buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + while (msg < end) { + if ((msg->sadb_msg_len << 3) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + msg = next; + continue; + } + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if (sa->sadb_sa_state != SADB_SASTATE_MATURE + && sa->sadb_sa_state != SADB_SASTATE_DYING) { + msg = next; + continue; + } + + /* + * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that + * announces the sender of the message was rebooted. + * it is interpreted to delete all SAs which source address + * is the sender of the message. + * racoon only deletes SA which is matched both the + * source address and the destination accress. + */ +#ifdef ENABLE_NATT + /* + * XXX RFC 3947 says that whe MUST NOT use IP+port to find old SAs + * from this peer ! + */ + if(iph1->natt_flags & NAT_DETECTED){ + if (CMPSADDR(iph1->local, src) == 0 && + CMPSADDR(iph1->remote, dst) == 0) + ; + else if (CMPSADDR(iph1->remote, src) == 0 && + CMPSADDR(iph1->local, dst) == 0) + ; + else { + msg = next; + continue; + } + } else +#endif + /* If there is no NAT-T, we don't have to check addr + port... + * XXX what about a configuration with a remote peers which is not + * NATed, but which NATs some other peers ? + * Here, the INITIAl-CONTACT would also flush all those NATed peers !! + */ + if (cmpsaddrwop(iph1->local, src) == 0 && + cmpsaddrwop(iph1->remote, dst) == 0) + ; + else if (cmpsaddrwop(iph1->remote, src) == 0 && + cmpsaddrwop(iph1->local, dst) == 0) + ; + else { + msg = next; + continue; + } + + /* + * Make sure this is an SATYPE that we manage. + * This is gross; too bad we couldn't do it the + * easy way. + */ + for (i = 0; i < pfkey_nsatypes; i++) { + if (pfkey_satypes[i].ps_satype == + msg->sadb_msg_satype) + break; + } + if (i == pfkey_nsatypes) { + msg = next; + continue; + } + + plog(LLV_INFO, LOCATION, NULL, + "purging spi=%u.\n", ntohl(sa->sadb_sa_spi)); + pfkey_send_delete(lcconf->sock_pfkey, + msg->sadb_msg_satype, + IPSEC_MODE_ANY, src, dst, sa->sadb_sa_spi); + + /* + * delete a relative phase 2 handler. + * continue to process if no relative phase 2 handler + * exists. + */ + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2) { + delete_spd(iph2); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + + msg = next; + } + + vfree(buf); +} + +/* + * handling to receive Deletion payload + */ +static int +isakmp_info_recv_d(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_pl_d *d; + int tlen, num_spi; + vchar_t *pbuf; + struct isakmp_parse_t *pa, *pap; + int protected = 0; + union { + u_int32_t spi32; + u_int16_t spi16[2]; + } spi; + + /* validate the type of next payload */ + if (!(pbuf = isakmp_parse(msg))) + return -1; + pa = (struct isakmp_parse_t *)pbuf->v; + for (pap = pa; pap->type; pap++) { + switch (pap->type) { + case ISAKMP_NPTYPE_D: + break; + case ISAKMP_NPTYPE_HASH: + if (pap == pa) { + protected++; + break; + } + plog(LLV_ERROR, LOCATION, iph1->remote, + "received next payload type %d " + "in wrong place (must be the first payload).\n", + pap->type); + vfree(pbuf); + return -1; + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "reject the packet, " + "received unexpecting payload type %d.\n", + pap->type); + vfree(pbuf); + return 0; + } + } + + if (!protected) { + plog(LLV_ERROR, LOCATION, NULL, + "delete payload is not proteted, " + "ignored.\n"); + vfree(pbuf); + return -1; + } + + /* process a delete payload */ + for (pap = pa; pap->type; pap++) { + if (pap->type != ISAKMP_NPTYPE_D) + continue; + + d = (struct isakmp_pl_d *)pap->ptr; + + if (ntohl(d->doi) != IPSEC_DOI) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with invalid doi:%d.\n", + ntohl(d->doi)); +#ifdef ENABLE_HYBRID + /* + * At deconnexion time, Cisco VPN client does this + * with a zero DOI. Don't give up in that situation. + */ + if (((iph1->mode_cfg->flags & + ISAKMP_CFG_VENDORID_UNITY) == 0) || (d->doi != 0)) + continue; +#else + continue; +#endif + } + + num_spi = ntohs(d->num_spi); + tlen = ntohs(d->h.len) - sizeof(struct isakmp_pl_d); + + if (tlen != num_spi * d->spi_size) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "deletion payload with invalid length.\n"); + vfree(pbuf); + return -1; + } + + switch (d->proto_id) { + case IPSECDOI_PROTO_ISAKMP: + if (d->spi_size != sizeof(isakmp_index)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + + if (iph1->scr) + SCHED_KILL(iph1->scr); + + purge_remote(iph1); + break; + + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + if (d->spi_size != sizeof(u_int32_t)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + EVT_PUSH(iph1->local, iph1->remote, + EVTT_PEER_DELETE, NULL); + purge_ipsec_spi(iph1->remote, d->proto_id, + (u_int32_t *)(d + 1), num_spi); + break; + + case IPSECDOI_PROTO_IPCOMP: + /* need to handle both 16bit/32bit SPI */ + memset(&spi, 0, sizeof(spi)); + if (d->spi_size == sizeof(spi.spi16[1])) { + memcpy(&spi.spi16[1], d + 1, + sizeof(spi.spi16[1])); + } else if (d->spi_size == sizeof(spi.spi32)) + memcpy(&spi.spi32, d + 1, sizeof(spi.spi32)); + else { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + purge_ipsec_spi(iph1->remote, d->proto_id, + &spi.spi32, num_spi); + break; + + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "deletion message received, " + "invalid proto_id: %d\n", + d->proto_id); + continue; + } + + plog(LLV_DEBUG, LOCATION, NULL, "purged SAs.\n"); + } + + vfree(pbuf); + + return 0; +} + +void +isakmp_check_notify(gen, iph1) + struct isakmp_gen *gen; /* points to Notify payload */ + struct ph1handle *iph1; +{ + struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen; + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "Notify Message received\n"); + + switch (ntohs(notify->type)) { + case ISAKMP_NTYPE_CONNECTED: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore CONNECTED notification.\n"); + break; + case ISAKMP_NTYPE_RESPONDER_LIFETIME: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore RESPONDER-LIFETIME notification.\n"); + break; + case ISAKMP_NTYPE_REPLAY_STATUS: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore REPLAY-STATUS notification.\n"); + break; + case ISAKMP_NTYPE_INITIAL_CONTACT: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore INITIAL-CONTACT notification, " + "because it is only accepted after phase1.\n"); + break; + case ISAKMP_NTYPE_LOAD_BALANCE: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore LOAD-BALANCE notification, " + "because it is only accepted after phase1.\n"); + break; + case ISAKMP_NTYPE_HEARTBEAT: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore HEARTBEAT notification\n"); + break; + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received unknown notification type %u.\n", + ntohs(notify->type)); + } + + return; +} + +#ifdef ENABLE_VPNCONTROL_PORT +static int +isakmp_info_recv_lb(iph1, n, encrypted) + struct ph1handle *iph1; + struct isakmp_pl_lb *n; + int encrypted; +{ + + if (iph1->side != INITIATOR) + { + plog(LLV_DEBUG, LOCATION, NULL, + "LOAD-BALANCE notification ignored - we are not the initiator.\n"); + return 0; + } + if (iph1->remote->sa_family != AF_INET) { + plog(LLV_DEBUG, LOCATION, NULL, + "LOAD-BALANCE notification ignored - only supported for IPv4.\n"); + return 0; + } + if (!encrypted) { + plog(LLV_DEBUG, LOCATION, NULL, + "LOAD-BALANCE notification ignored - not protected.\n"); + return 0; + } + if (ntohs(n->h.len) != sizeof(struct isakmp_pl_lb)) { + plog(LLV_DEBUG, LOCATION, NULL, + "Invalid length of payload\n"); + return -1; + } + vpncontrol_notify_ike_failed(ISAKMP_NTYPE_LOAD_BALANCE, FROM_REMOTE, + ((struct sockaddr_in*)iph1->remote)->sin_addr.s_addr, 4, (u_int8_t*)(&(n->address))); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "received LOAD_BALANCE notification - redirect address=%x.\n", + ntohl(n->address)); + + return 0; +} +#endif + +#ifdef ENABLE_DPD +static int +isakmp_info_recv_r_u (iph1, ru, msgid) + struct ph1handle *iph1; + struct isakmp_pl_ru *ru; + u_int32_t msgid; +{ + struct isakmp_pl_ru *ru_ack; + vchar_t *payload = NULL; + int tlen; + int error = 0; + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "DPD R-U-There received\n"); + + /* XXX should compare cookies with iph1->index? + Or is this already done by calling function? */ + tlen = sizeof(*ru_ack); + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + return errno; + } + + ru_ack = (struct isakmp_pl_ru *)payload->v; + ru_ack->h.np = ISAKMP_NPTYPE_NONE; + ru_ack->h.len = htons(tlen); + ru_ack->doi = htonl(IPSEC_DOI); + ru_ack->type = htons(ISAKMP_NTYPE_R_U_THERE_ACK); + ru_ack->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ? */ + ru_ack->spi_size = sizeof(isakmp_index); + memcpy(ru_ack->i_ck, ru->i_ck, sizeof(cookie_t)); + memcpy(ru_ack->r_ck, ru->r_ck, sizeof(cookie_t)); + ru_ack->data = ru->data; + + /* XXX Should we do FLAG_A ? */ + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, + ISAKMP_FLAG_E); + vfree(payload); + + plog(LLV_DEBUG, LOCATION, NULL, "received a valid R-U-THERE, ACK sent\n"); + + /* Should we mark tunnel as active ? */ + return error; +} + +static int +isakmp_info_recv_r_u_ack (iph1, ru, msgid) + struct ph1handle *iph1; + struct isakmp_pl_ru *ru; + u_int32_t msgid; +{ + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "DPD R-U-There-Ack received\n"); + + /* XXX Maintain window of acceptable sequence numbers ? + * => ru->data <= iph2->dpd_seq && + * ru->data >= iph2->dpd_seq - iph2->dpd_fails ? */ + if (ntohl(ru->data) != iph1->dpd_seq-1) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "Wrong DPD sequence number (%d, %d expected).\n", + ntohl(ru->data), iph1->dpd_seq-1); + return 0; + } + + if (memcmp(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)) || + memcmp(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t))) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "Cookie mismatch in DPD ACK!.\n"); + return 0; + } + + iph1->dpd_fails = 0; + + /* Useless ??? */ + iph1->dpd_lastack = time(NULL); + + if (iph1->dpd_r_u != NULL) + SCHED_KILL(iph1->dpd_r_u); + + isakmp_sched_r_u(iph1, 0); + + plog(LLV_DEBUG, LOCATION, NULL, "received an R-U-THERE-ACK\n"); + + return 0; +} + + +/* + * send Delete payload (for ISAKMP SA) in Informational exchange. + */ +static void +isakmp_info_send_r_u(arg) + void *arg; +{ + struct ph1handle *iph1 = arg; + + /* create R-U-THERE payload */ + struct isakmp_pl_ru *ru; + vchar_t *payload = NULL; + int tlen; + int error = 0; + + plog(LLV_DEBUG, LOCATION, iph1->remote, "DPD monitoring....\n"); + + if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) { + EVT_PUSH(iph1->local, iph1->remote, EVTT_DPD_TIMEOUT, NULL); + purge_remote(iph1); + plog(LLV_DEBUG, LOCATION, iph1->remote, + "DPD: remote seems to be dead\n"); + + /* Do not reschedule here: phase1 is deleted, + * DPD will be reactivated when a new ph1 will be negociated + */ + return; + } + + /* TODO: check recent activity to avoid useless sends... */ + + /* XXX: why do we have a NULL LIST_FIRST even when a Phase2 exists ??? */ +#if 0 + if (LIST_FIRST(&iph1->ph2tree) == NULL){ + /* XXX: No Ph2 => no need to test ph1 ? + */ + /* Reschedule the r_u_there.... + XXX: reschedule when a new ph2 ? + */ + isakmp_sched_r_u(iph1, 0); + plog(LLV_DEBUG, LOCATION, iph1->remote, + "no phase2 handler, rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_interval); + return 0; + } +#endif + + tlen = sizeof(*ru); + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for payload.\n"); + return; + } + ru = (struct isakmp_pl_ru *)payload->v; + ru->h.np = ISAKMP_NPTYPE_NONE; + ru->h.len = htons(tlen); + ru->doi = htonl(IPSEC_DOI); + ru->type = htons(ISAKMP_NTYPE_R_U_THERE); + ru->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ?*/ + ru->spi_size = sizeof(isakmp_index); + + memcpy(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)); + memcpy(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t)); + + if (iph1->dpd_seq == 0){ + /* generate a random seq which is not too big */ + srand(time(NULL)); + iph1->dpd_seq = rand() & 0x0fff; + } + + ru->data = htonl(iph1->dpd_seq); + + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); + vfree(payload); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "DPD R-U-There sent (%d)\n", error); + + /* will be decreased if ACK received... */ + iph1->dpd_fails++; + + /* XXX should be increased only when ACKed ? */ + iph1->dpd_seq++; + + /* Reschedule the r_u_there with a short delay, + * will be deleted/rescheduled if ACK received before */ + isakmp_sched_r_u(iph1, 1); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_retry); +} + +/* Schedule a new R-U-THERE */ +int +isakmp_sched_r_u(iph1, retry) + struct ph1handle *iph1; + int retry; +{ + if(iph1 == NULL || + iph1->rmconf == NULL) + return 1; + + + if(iph1->dpd_support == 0 || + iph1->rmconf->dpd_interval == 0) + return 0; + + if(retry) + iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_retry, + isakmp_info_send_r_u, iph1); + else + sched_new(iph1->rmconf->dpd_interval, + isakmp_info_send_r_u, iph1); + + return 0; +} +#endif diff --git a/ipsec-tools/racoon/isakmp_inf.h b/ipsec-tools/racoon/isakmp_inf.h new file mode 100644 index 0000000..4f22ece --- /dev/null +++ b/ipsec-tools/racoon/isakmp_inf.h @@ -0,0 +1,55 @@ +/* $Id: isakmp_inf.h,v 1.4 2004/11/16 15:44:46 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_INF_H +#define _ISAKMP_INF_H + +struct saproto; +extern int isakmp_info_recv __P((struct ph1handle *, vchar_t *)); +extern int isakmp_info_send_d1 __P((struct ph1handle *)); +extern int isakmp_info_send_d2 __P((struct ph2handle *)); +extern int isakmp_info_send_nx __P((struct isakmp *, + struct sockaddr *, struct sockaddr *, int, vchar_t *)); +extern int isakmp_info_send_n1 __P((struct ph1handle *, int, vchar_t *)); +extern int isakmp_info_send_n2 __P((struct ph2handle *, int, vchar_t *)); +extern int isakmp_info_send_common __P((struct ph1handle *, + vchar_t *, u_int32_t, int)); + +extern vchar_t * isakmp_add_pl_n __P((vchar_t *, u_int8_t **, int, + struct saproto *, vchar_t *)); + +extern void isakmp_check_notify __P((struct isakmp_gen *, struct ph1handle *)); + +#ifdef ENABLE_DPD +extern int isakmp_sched_r_u __P((struct ph1handle *, int)); +#endif + +#endif /* _ISAKMP_INF_H */ diff --git a/ipsec-tools/racoon/isakmp_newg.c b/ipsec-tools/racoon/isakmp_newg.c new file mode 100644 index 0000000..0db0107 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_newg.c @@ -0,0 +1,230 @@ +/* $KAME: isakmp_newg.c,v 1.10 2002/09/27 05:55:52 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "cfparse_proto.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_newg.h" +#include "oakley.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "handler.h" +#include "pfkey.h" +#include "admin.h" +#include "str2val.h" +#include "vendorid.h" + +/* + * New group mode as responder + */ +int +isakmp_newgroup_r(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ +#if 0 + struct isakmp *isakmp = (struct isakmp *)msg->v; + struct isakmp_pl_hash *hash = NULL; + struct isakmp_pl_sa *sa = NULL; + int error = -1; + vchar_t *buf; + struct oakley_sa *osa; + int len; + + /* validate the type of next payload */ + /* + * ISAKMP_ETYPE_NEWGRP, + * ISAKMP_NPTYPE_HASH, (ISAKMP_NPTYPE_VID), ISAKMP_NPTYPE_SA, + * ISAKMP_NPTYPE_NONE + */ + { + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + + if ((pbuf = isakmp_parse(msg)) == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + if (hash) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received multiple payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_SA: + if (sa) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received multiple payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + sa = (struct isakmp_pl_sa *)pa->ptr; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + } + vfree(pbuf); + + if (!hash || !sa) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "no HASH, or no SA payload.\n"); + goto end; + } + } + + /* validate HASH */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + plog(LLV_DEBUG, LOCATION, NULL, "validate HASH\n"); + + len = sizeof(isakmp->msgid) + ntohs(sa->h.len); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + memcpy(buf->v, &isakmp->msgid, sizeof(isakmp->msgid)); + memcpy(buf->v + sizeof(isakmp->msgid), sa, ntohs(sa->h.len)); + + plog(LLV_DEBUG, LOCATION, NULL, "hash source\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + my_hash = isakmp_prf(iph1->skeyid_a, buf, iph1); + vfree(buf); + if (my_hash == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "hash result\n"); + plogdump(LLV_DEBUG, my_hash->v, my_hash->l); + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "original hash\n")); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash))); + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "HASH mismatch.\n"); + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_HASH_INFORMATION, NULL); + goto end; + } + } + + /* check SA payload and get new one for use */ + buf = ipsecdoi_get_proposal((struct ipsecdoi_sa *)sa, + OAKLEY_NEWGROUP_MODE); + if (buf == NULL) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + goto end; + } + + /* save sa parameters */ + osa = ipsecdoi_get_oakley(buf); + if (osa == NULL) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + goto end; + } + vfree(buf); + + switch (osa->dhgrp) { + case OAKLEY_ATTR_GRP_DESC_MODP768: + case OAKLEY_ATTR_GRP_DESC_MODP1024: + case OAKLEY_ATTR_GRP_DESC_MODP1536: + /*XXX*/ + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + plog(LLV_ERROR, LOCATION, NULL, + "dh group %d isn't supported.\n", osa->dhgrp); + goto end; + } + + plog(LLV_INFO, LOCATION, iph1->remote, + "got new dh group %s.\n", isakmp_pindex(&iph1->index, 0)); + + error = 0; + +end: + if (error) { + if (iph1 != NULL) + (void)isakmp_free_ph1(iph1); + } + return error; +#endif + return 0; +} + diff --git a/ipsec-tools/racoon/isakmp_newg.h b/ipsec-tools/racoon/isakmp_newg.h new file mode 100644 index 0000000..2a52b1e --- /dev/null +++ b/ipsec-tools/racoon/isakmp_newg.h @@ -0,0 +1,37 @@ +/* $Id: isakmp_newg.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_NEWG_H +#define _ISAKMP_NEWG_H + +extern int isakmp_newgroup_r __P((struct ph1handle *, vchar_t *)); + +#endif /* _ISAKMP_NEWG_H */ diff --git a/ipsec-tools/racoon/isakmp_quick.c b/ipsec-tools/racoon/isakmp_quick.c new file mode 100644 index 0000000..fc3c259 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_quick.c @@ -0,0 +1,2238 @@ +/* $Id: isakmp_quick.c,v 1.13.2.7 2005/07/20 08:02:05 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#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 *)); + +/* %%% + * Quick Mode + */ +/* + * begin Quick Mode as initiator. send pfkey getspi message to kernel. + */ +int +quick_i1prep(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; /* must be null pointer */ +{ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS2) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + iph2->msgid = isakmp_newmsgid2(iph2->ph1); + iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid); + if (iph2->ivm == NULL) + return 0; + + iph2->status = PHASE2ST_GETSPISENT; + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* send getspi message */ + if (pk_sendgetspi(iph2) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); + + iph2->sce = sched_new(lcconf->wait_ph2complete, + pfkey_timeover_stub, iph2); + + error = 0; + +end: + return error; +} + +/* + * send to responder + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + */ +int +quick_i1send(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; /* must be null pointer */ +{ + vchar_t *body = NULL; + vchar_t *hash = NULL; + vchar_t *natoa_i = NULL; + vchar_t *natoa_r = NULL; + int natoa_type = 0; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + int pfsgroup, idci, idcr; + int np; + struct ipsecdoi_id_b *id, *id_p; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph2->status != PHASE2ST_GETSPIDONE) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* create SA payload for my proposal */ + if (ipsecdoi_setph2proposal(iph2) < 0) + goto end; + + /* generate NONCE value */ + iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); + if (iph2->nonce == NULL) + goto end; + + /* + * DH value calculation is kicked out into cfparse.y. + * because pfs group can not be negotiated, it's only to be checked + * acceptable. + */ + /* generate KE value if need */ + pfsgroup = iph2->proposal->pfs_group; + if (pfsgroup) { + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set DH value.\n"); + goto end; + } + if (oakley_dh_generate(iph2->pfsgrp, + &iph2->dhpub, &iph2->dhpriv) < 0) { + goto end; + } + } + + /* generate ID value */ + if (ipsecdoi_setid2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "IDci:"); + plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); + plog(LLV_DEBUG, LOCATION, NULL, "IDcr:"); + plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); + + /* + * we do not attach IDci nor IDcr, under the following condition: + * - all proposals are transport mode + * - no MIP6 or proxy + * - id payload suggests to encrypt all the traffic (no specific + * protocol type) + */ + id = (struct ipsecdoi_id_b *)iph2->id->v; + id_p = (struct ipsecdoi_id_b *)iph2->id_p->v; + if (id->proto_id == 0 + && id_p->proto_id == 0 + && iph2->ph1->rmconf->support_proxy == 0 + && ipsecdoi_transportmode(iph2->proposal)) { + idci = idcr = 0; + } else + idci = idcr = 1; + + /* create SA;NONCE payload, and KE if need, and IDii, IDir. */ + tlen = + sizeof(*gen) + iph2->sa->l + + sizeof(*gen) + iph2->nonce->l; + if (pfsgroup) + tlen += (sizeof(*gen) + iph2->dhpub->l); + if (idci) + tlen += sizeof(*gen) + iph2->id->l; + if (idcr) + tlen += sizeof(*gen) + iph2->id_p->l; + +#ifdef NOT_NOW +#ifdef ENABLE_NATT + /* + * create natoa payloads if needed but only + * if transport mode proposals are present + */ + if (ipsecdoi_tunnelmode(iph2) != 1) { + natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r); + if (natoa_type == -1) + goto end; + else if (natoa_type != 0) { + tlen += sizeof(*gen) + natoa_i->l; + tlen += sizeof(*gen) + natoa_r->l; + } + } +#endif +#endif + + body = vmalloc(tlen); + if (body == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + p = body->v; + + /* add SA payload */ + p = set_isakmp_payload(p, iph2->sa, ISAKMP_NPTYPE_NONCE); + + /* add NONCE payload */ + if (pfsgroup) + np = ISAKMP_NPTYPE_KE; + else if (idci || idcr) + np = ISAKMP_NPTYPE_ID; + else +#ifdef NOT_NOW + np = (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE); +#else + np = ISAKMP_NPTYPE_NONE; +#endif + p = set_isakmp_payload(p, iph2->nonce, np); + + /* add KE payload if need. */ +#ifdef NOT_NOW + np = (idci || idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE); +#else + np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; +#endif + if (pfsgroup) + p = set_isakmp_payload(p, iph2->dhpub, np); + + /* IDci */ +#ifdef NOT_NOW + np = (idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE); +#else + np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; +#endif + if (idci) + p = set_isakmp_payload(p, iph2->id, np); + + /* IDcr */ + if (idcr) +#ifdef NOT_NOW + p = set_isakmp_payload(p, iph2->id_p, natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE); + + /* natoa */ + if (natoa_type) { + p = set_isakmp_payload(p, natoa_i, natoa_type); + p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE); + } +#else + p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE); +#endif + + /* generate HASH(1) */ + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body); + if (hash == NULL) + goto end; + + /* send isakmp payload */ + iph2->sendbuf = quick_ir1mx(iph2, body, hash); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_MSG1SENT; + + error = 0; + +end: + if (body != NULL) + vfree(body); + if (hash != NULL) + vfree(hash); +#ifdef NOT_NOW + if (natoa_i) + vfree(natoa_i); + if (natoa_r) + vfree(natoa_r); +#endif + + return error; +} + +/* + * receive from responder + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + */ +int +quick_i2recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *hbuf = NULL; /* for hash computing. */ + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp *isakmp = (struct isakmp *)msg0->v; + struct isakmp_pl_hash *hash = NULL; + int f_id; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* create buffer for validating HASH(2) */ + /* + * ordering rule: + * 1. the first one must be HASH + * 2. the second one must be SA (added in isakmp-oakley-05!) + * 3. two IDs must be considered as IDci, then IDcr + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_HASH) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + pa++; + + /* + * this restriction was introduced in isakmp-oakley-05. + * we do not check this for backward compatibility. + * TODO: command line/config file option to enable/disable this code + */ + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_WARNING, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + } + + /* allocate buffer for computing HASH(2) */ + tlen = iph2->nonce->l + + ntohl(isakmp->len) - sizeof(*isakmp); + hbuf = vmalloc(tlen); + if (hbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + p = hbuf->v + iph2->nonce->l; /* retain the space for Ni_b */ + + /* + * parse the payloads. + * copy non-HASH payloads into hbuf, so that we can validate HASH. + */ + iph2->sa_ret = NULL; + f_id = 0; /* flag to use checking ID */ + tlen = 0; /* count payload length except of HASH payload. */ + for (; pa->type; pa++) { + + /* copy to buffer for HASH */ + /* Don't modify the payload */ + memcpy(p, pa->ptr, pa->len); + + switch (pa->type) { + case ISAKMP_NPTYPE_SA: + if (iph2->sa_ret != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Ignored, multiple SA " + "isn't supported.\n"); + break; + } + if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_ID: + { + vchar_t *vp; + + /* check ID value */ + if (f_id == 0) { + /* for IDci */ + f_id = 1; + vp = iph2->id; + } else { + /* for IDcr */ + vp = iph2->id_p; + } + + /* These ids may not match when natt is used with some devices. + * RFC 2407 says that the protocol and port fields should be ignored + * if they are zero, therefore they need to be checked individually. + */ + struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v; + struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr; + + if (id_ptr->type != idp_ptr->b.type + || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id) + || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port) + || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id), + vp->l - sizeof(struct ipsecdoi_id_b))) { + //%%% BUG_FIX - to support some servers + if (iph2->ph1->natt_flags & NAT_DETECTED) { + plog(LLV_WARNING, LOCATION, NULL, + "mismatched ID was returned - ignored because nat traversal is being used.\n"); + break; + } + plog(LLV_ERROR, LOCATION, NULL, + "mismatched ID was returned.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } + } + + break; + + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + +#ifdef ENABLE_NATT + case ISAKMP_NPTYPE_NATOA_DRAFT: + case ISAKMP_NPTYPE_NATOA_BADDRAFT: + case ISAKMP_NPTYPE_NATOA_RFC: + /* Ignore original source/destination messages */ + break; +#endif + + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + + p += pa->len; + + /* compute true length of payload. */ + tlen += pa->len; + } + + /* payload existency check */ + if (hash == NULL || iph2->sa_ret == NULL || iph2->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* Fixed buffer for calculating HASH */ + memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l); + plog(LLV_DEBUG, LOCATION, NULL, + "HASH allocated:hbuf->l=%zu actual:tlen=%zu\n", + hbuf->l, tlen + iph2->nonce->l); + /* adjust buffer length for HASH */ + hbuf->l = iph2->nonce->l + tlen; + + /* validate HASH(2) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(2) received:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(2) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* validity check SA payload sent from responder */ + if (ipsecdoi_checkph2proposal(iph2) < 0) { + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_STATUS6; + + error = 0; + +end: + if (hbuf) + vfree(hbuf); + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); + + if (error) { + VPTRINIT(iph2->sa_ret); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + } + + return error; +} + +/* + * send to responder + * HDR*, HASH(3) + */ +int +quick_i2send(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *buf = NULL; + vchar_t *hash = NULL; + char *p = NULL; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS6) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* generate HASH(3) */ + { + vchar_t *tmp = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) generate\n"); + + tmp = vmalloc(iph2->nonce->l + iph2->nonce_p->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce->v, iph2->nonce->l); + memcpy(tmp->v + iph2->nonce->l, iph2->nonce_p->v, iph2->nonce_p->l); + + hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + + if (hash == NULL) + goto end; + } + + /* create buffer for isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(struct isakmp_gen) + hash->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* create isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH(3) payload */ + p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (iph2->sendbuf == NULL) + goto end; + + /* if there is commit bit, need resending */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + } else { + /* send the packet */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) + goto end; + } + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, + iph2->sendbuf, msg0) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* compute both of KEYMATs */ + if (oakley_compute_keymat(iph2, INITIATOR) < 0) + goto end; + + iph2->status = PHASE2ST_ADDSA; + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* if there is commit bit don't set up SA now. */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + iph2->status = PHASE2ST_COMMIT; + error = 0; + goto end; + } + + /* Do UPDATE for initiator */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + if (msg != NULL) + vfree(msg); + if (hash != NULL) + vfree(hash); + + return error; +} + +/* + * receive from responder + * HDR#*, HASH(4), notify + */ +int +quick_i3recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp_pl_hash *hash = NULL; + vchar_t *notify = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_COMMIT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + notify = vmalloc(pa->len); + if (notify == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get notify buffer.\n"); + goto end; + } + memcpy(notify->v, pa->ptr, notify->l); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (hash == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* validate HASH(4) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + vchar_t *tmp = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); + vfree(tmp); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(4) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + iph2->status = PHASE2ST_ADDSA; + iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* Do UPDATE for initiator */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + error = 0; + +end: + if (msg != NULL) + vfree(msg); + if (pbuf != NULL) + vfree(pbuf); + if (notify != NULL) + vfree(notify); + + return error; +} + +/* + * receive from initiator + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + */ +int +quick_r1recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *hbuf = NULL; /* for hash computing. */ + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp *isakmp = (struct isakmp *)msg0->v; + struct isakmp_pl_hash *hash = NULL; + char *p; + int tlen; + int f_id_order; /* for ID payload detection */ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypting */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + /* decrypt packet */ + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* create buffer for using to validate HASH(1) */ + /* + * ordering rule: + * 1. the first one must be HASH + * 2. the second one must be SA (added in isakmp-oakley-05!) + * 3. two IDs must be considered as IDci, then IDcr + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_HASH) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + pa++; + + /* + * this restriction was introduced in isakmp-oakley-05. + * we do not check this for backward compatibility. + * TODO: command line/config file option to enable/disable this code + */ + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_WARNING, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; + } + + /* allocate buffer for computing HASH(1) */ + tlen = ntohl(isakmp->len) - sizeof(*isakmp); + hbuf = vmalloc(tlen); + if (hbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + p = hbuf->v; + + /* + * parse the payloads. + * copy non-HASH payloads into hbuf, so that we can validate HASH. + */ + iph2->sa = NULL; /* we don't support multi SAs. */ + iph2->nonce_p = NULL; + iph2->dhpub_p = NULL; + iph2->id_p = NULL; + iph2->id = NULL; + tlen = 0; /* count payload length except of HASH payload. */ + + /* + * IDi2 MUST be immediatelly followed by IDr2. We allowed the + * illegal case, but logged. First ID payload is to be IDi2. + * And next ID payload is to be IDr2. + */ + f_id_order = 0; + + for (; pa->type; pa++) { + + /* copy to buffer for HASH */ + /* Don't modify the payload */ + memcpy(p, pa->ptr, pa->len); + + if (pa->type != ISAKMP_NPTYPE_ID) + f_id_order = 0; + + switch (pa->type) { + case ISAKMP_NPTYPE_SA: + if (iph2->sa != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Multi SAs isn't supported.\n"); + goto end; + } + if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_ID: + if (iph2->id_p == NULL) { + /* for IDci */ + f_id_order++; + + if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0) + goto end; + + } else if (iph2->id == NULL) { + /* for IDcr */ + if (f_id_order == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "IDr2 payload is not " + "immediatelly followed " + "by IDi2. We allowed.\n"); + /* XXX we allowed in this case. */ + } + + if (isakmp_p2ph(&iph2->id, pa->ptr) < 0) + goto end; + } else { + plog(LLV_ERROR, LOCATION, NULL, + "received too many ID payloads.\n"); + plogdump(LLV_ERROR, iph2->id->v, iph2->id->l); + error = ISAKMP_NTYPE_INVALID_ID_INFORMATION; + goto end; + } + break; + + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + +#ifdef ENABLE_NATT + case ISAKMP_NPTYPE_NATOA_DRAFT: + case ISAKMP_NPTYPE_NATOA_BADDRAFT: + case ISAKMP_NPTYPE_NATOA_RFC: + /* Ignore original source/destination messages */ + break; +#endif + + default: + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpected payload type %d.\n", + pa->type); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + + p += pa->len; + + /* compute true length of payload. */ + tlen += pa->len; + } + + /* payload existency check */ + if (hash == NULL || iph2->sa == NULL || iph2->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "expected isakmp payloads missing.\n"); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + + if (iph2->id_p) { + plog(LLV_DEBUG, LOCATION, NULL, "received IDci2:"); + plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); + } + if (iph2->id) { + plog(LLV_DEBUG, LOCATION, NULL, "received IDcr2:"); + plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); + } + + /* adjust buffer length for HASH */ + hbuf->l = tlen; + + /* validate HASH(1) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + r_hash = (caddr_t)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(1) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(1) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* get sainfo */ + error = get_sainfo_r(iph2); + if (error) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + goto end; + } + + /* check the existence of ID payload and create responder's proposal */ + error = get_proposal_r(iph2); + switch (error) { + case -2: + /* generate a policy template from peer's proposal */ + if (set_proposal_from_proposal(iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to generate a proposal template " + "from client's proposal.\n"); + return ISAKMP_INTERNAL_ERROR; + } + /*FALLTHROUGH*/ + case 0: + /* select single proposal or reject it. */ + if (ipsecdoi_selectph2proposal(iph2) < 0) { + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "failed to get proposal for responder.\n"); + goto end; + } + + /* check KE and attribute of PFS */ + if (iph2->dhpub_p != NULL && iph2->approval->pfs_group == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no PFS is specified, but peer sends KE.\n"); + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + if (iph2->dhpub_p == NULL && iph2->approval->pfs_group != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "PFS is specified, but peer doesn't sends KE.\n"); + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + + /* + * save the packet from the initiator in order to resend the + * responder's first packet against this packet. + */ + iph2->msg1 = vdup(msg0); + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_STATUS2; + + error = 0; + +end: + if (hbuf) + vfree(hbuf); + if (msg) + vfree(msg); + if (pbuf) + vfree(pbuf); + + if (error) { + VPTRINIT(iph2->sa); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + } + + return error; +} + +/* + * call pfkey_getspi. + */ +int +quick_r1prep(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS2) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + iph2->status = PHASE2ST_GETSPISENT; + + /* send getspi message */ + if (pk_sendgetspi(iph2) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); + + iph2->sce = sched_new(lcconf->wait_ph2complete, + pfkey_timeover_stub, iph2); + + error = 0; + +end: + return error; +} + +/* + * send to initiator + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + */ +int +quick_r2send(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + vchar_t *body = NULL; + vchar_t *hash = NULL; + vchar_t *natoa_i = NULL; + vchar_t *natoa_r = NULL; + int natoa_type = 0; + int encmode; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + int pfsgroup; + u_int8_t *np_p = NULL; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph2->status != PHASE2ST_GETSPIDONE) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* update responders SPI */ + if (ipsecdoi_updatespi(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "failed to update spi.\n"); + goto end; + } + + /* generate NONCE value */ + iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); + if (iph2->nonce == NULL) + goto end; + + /* generate KE value if need */ + pfsgroup = iph2->approval->pfs_group; + if (iph2->dhpub_p != NULL && pfsgroup != 0) { + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set DH value.\n"); + goto end; + } + /* generate DH public value */ + if (oakley_dh_generate(iph2->pfsgrp, + &iph2->dhpub, &iph2->dhpriv) < 0) { + goto end; + } + } + + /* create SA;NONCE payload, and KE and ID if need */ + tlen = sizeof(*gen) + iph2->sa_ret->l + + sizeof(*gen) + iph2->nonce->l; + if (iph2->dhpub_p != NULL && pfsgroup != 0) + tlen += (sizeof(*gen) + iph2->dhpub->l); + if (iph2->id_p != NULL) + tlen += (sizeof(*gen) + iph2->id_p->l + + sizeof(*gen) + iph2->id->l); + +#ifdef NOT_NOW +#ifdef ENABLE_NATT + /* create natoa payloads if needed */ + encmode = iph2->approval->head->encmode; + if (encmode == IPSECDOI_ATTR_ENC_MODE_TRNS || + encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC || + encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT) { + + natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r); + if (natoa_type == -1) + goto end; + else if (natoa_type != 0) { + tlen += sizeof(*gen) + natoa_i->l; + tlen += sizeof(*gen) + natoa_r->l; + } + } +#endif +#endif + + + body = vmalloc(tlen); + if (body == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + p = body->v; + + /* make SA payload */ + p = set_isakmp_payload(body->v, iph2->sa_ret, ISAKMP_NPTYPE_NONCE); + + /* add NONCE payload */ + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ + p = set_isakmp_payload(p, iph2->nonce, + (iph2->dhpub_p != NULL && pfsgroup != 0) + ? ISAKMP_NPTYPE_KE + : (iph2->id_p != NULL + ? ISAKMP_NPTYPE_ID +#ifdef NOT_NOW + : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE))); +#else + : ISAKMP_NPTYPE_ID)); +#endif + + /* add KE payload if need. */ + if (iph2->dhpub_p != NULL && pfsgroup != 0) { + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ + p = set_isakmp_payload(p, iph2->dhpub, + (iph2->id_p == NULL) +#ifdef NOT_NOW + ? (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE) +#else + ? ISAKMP_NPTYPE_NONE +#endif + : ISAKMP_NPTYPE_ID); + } + + /* add ID payloads received. */ + if (iph2->id_p != NULL) { + /* IDci */ + p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID); + /* IDcr */ + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ +#ifdef NOT_NOW + p = set_isakmp_payload(p, iph2->id, (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)); +#else + p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE); +#endif + } + + /* add a RESPONDER-LIFETIME notify payload if needed */ + { + vchar_t *data = NULL; + struct saprop *pp = iph2->approval; + struct saproto *pr; + + if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_SEC) { + u_int32_t v = htonl((u_int32_t)pp->lifetime); + data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_SEC); + if (!data) + goto end; + data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + if (!data) + goto end; + } + if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_KB) { + u_int32_t v = htonl((u_int32_t)pp->lifebyte); + data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_KB); + if (!data) + goto end; + data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + if (!data) + goto end; + } + + /* + * XXX Is there only single RESPONDER-LIFETIME payload in a IKE message + * in the case of SA bundle ? + */ + if (data) { + for (pr = pp->head; pr; pr = pr->next) { + body = isakmp_add_pl_n(body, &np_p, + ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data); + if (!body) { + vfree(data); + return error; /* XXX */ + } + } + vfree(data); + } + } + +#ifdef NOT_NOW + /* natoa */ + if (natoa_type) { + p = set_isakmp_payload(p, natoa_i, natoa_type); + p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE); + } +#endif + + /* generate HASH(2) */ + { + vchar_t *tmp; + + tmp = vmalloc(iph2->nonce_p->l + body->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); + memcpy(tmp->v + iph2->nonce_p->l, body->v, body->l); + + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + + if (hash == NULL) + goto end; + } + + /* send isakmp payload */ + iph2->sendbuf = quick_ir1mx(iph2, body, hash); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_MSG1SENT; + + error = 0; + +end: + if (body != NULL) + vfree(body); + if (hash != NULL) + vfree(hash); +#ifdef NOT_NOW + if (natoa_i) + vfree(natoa_i); + if (natoa_r) + vfree(natoa_r); +#endif + + return error; +} + +/* + * receive from initiator + * HDR*, HASH(3) + */ +int +quick_r3recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp_pl_hash *hash = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (hash == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* validate HASH(3) */ + /* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + vchar_t *tmp = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + tmp = vmalloc(iph2->nonce_p->l + iph2->nonce->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); + memcpy(tmp->v + iph2->nonce_p->l, iph2->nonce->v, iph2->nonce->l); + + my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "HASH(3) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* if there is commit bit, don't set up SA now. */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + iph2->status = PHASE2ST_COMMIT; + } else + iph2->status = PHASE2ST_STATUS6; + + error = 0; + +end: + if (pbuf != NULL) + vfree(pbuf); + if (msg != NULL) + vfree(msg); + + return error; +} + +/* + * send to initiator + * HDR#*, HASH(4), notify + */ +int +quick_r3send(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *buf = NULL; + vchar_t *myhash = NULL; + struct isakmp_pl_n *n; + vchar_t *notify = NULL; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_COMMIT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* generate HASH(4) */ + /* XXX What can I do in the case of multiple different SA */ + plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) generate\n"); + + /* XXX What should I do if there are multiple SAs ? */ + tlen = sizeof(struct isakmp_pl_n) + iph2->approval->head->spisize; + notify = vmalloc(tlen); + if (notify == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get notify buffer.\n"); + goto end; + } + n = (struct isakmp_pl_n *)notify->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); + n->proto_id = iph2->approval->head->proto_id; + n->spi_size = sizeof(iph2->approval->head->spisize); + n->type = htons(ISAKMP_NTYPE_CONNECTED); + memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize); + + myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); + if (myhash == NULL) + goto end; + + /* create buffer for isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(struct isakmp_gen) + myhash->l + + notify->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* create isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH(4) payload */ + p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N); + + /* add notify payload */ + memcpy(p, notify->v, notify->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph2->status = PHASE2ST_COMMIT; + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + if (myhash != NULL) + vfree(myhash); + if (notify != NULL) + vfree(notify); + + return error; +} + +/* + * set SA to kernel. + */ +int +quick_r3prep(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS6) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* compute both of KEYMATs */ + if (oakley_compute_keymat(iph2, RESPONDER) < 0) + goto end; + + iph2->status = PHASE2ST_ADDSA; + iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* Do UPDATE as responder */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + /* + * set policies into SPD if the policy is generated + * from peer's policy. + */ + if (iph2->spidx_gen) { + + struct policyindex *spidx; + struct sockaddr_storage addr; + u_int8_t pref; + struct sockaddr *src = iph2->src; + struct sockaddr *dst = iph2->dst; + + /* make inbound policy */ + iph2->src = dst; + iph2->dst = src; + if (pk_sendspdupdate2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spdupdate2(inbound) failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spdupdate2(inbound) sent.\n"); + + spidx = (struct policyindex *)iph2->spidx_gen; +#ifdef HAVE_POLICY_FWD + /* make forward policy if required */ + if (tunnel_mode_prop(iph2->approval)) { + spidx->dir = IPSEC_DIR_FWD; + if (pk_sendspdupdate2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spdupdate2(forward) failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spdupdate2(forward) sent.\n"); + } +#endif + + /* make outbound policy */ + iph2->src = src; + iph2->dst = dst; + spidx->dir = IPSEC_DIR_OUTBOUND; + addr = spidx->src; + spidx->src = spidx->dst; + spidx->dst = addr; + pref = spidx->prefs; + spidx->prefs = spidx->prefd; + spidx->prefd = pref; + + if (pk_sendspdupdate2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spdupdate2(outbound) failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spdupdate2(outbound) sent.\n"); + + /* spidx_gen is unnecessary any more */ + delsp_bothdir((struct policyindex *)iph2->spidx_gen); + racoon_free(iph2->spidx_gen); + iph2->spidx_gen = NULL; + iph2->generated_spidx=1; + } + + error = 0; + +end: + if (msg != NULL) + vfree(msg); + + return error; +} + +/* + * create HASH, body (SA, NONCE) payload with isakmp header. + */ +static vchar_t * +quick_ir1mx(iph2, body, hash) + struct ph2handle *iph2; + vchar_t *body, *hash; +{ + struct isakmp *isakmp; + vchar_t *buf = NULL, *new = NULL; + char *p; + int tlen; + struct isakmp_gen *gen; + int error = ISAKMP_INTERNAL_ERROR; + + /* create buffer for isakmp payload */ + tlen = sizeof(*isakmp) + + sizeof(*gen) + hash->l + + body->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* re-set encryption flag, for serurity. */ + iph2->flags |= ISAKMP_FLAG_E; + + /* set isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH payload */ + /* XXX is next type always SA ? */ + p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_SA); + + /* add body payload */ + memcpy(p, body->v, body->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (new == NULL) + goto end; + + vfree(buf); + + buf = new; + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + + return buf; +} + +/* + * get remote's sainfo. + * NOTE: this function is for responder. + */ +static int +get_sainfo_r(iph2) + struct ph2handle *iph2; +{ + vchar_t *idsrc = NULL, *iddst = NULL; + int prefixlen; + int error = ISAKMP_INTERNAL_ERROR; + + if (iph2->id_p == NULL) { + switch (iph2->src->sa_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->src->sa_family); + goto end; + } + idsrc = ipsecdoi_sockaddr2id(iph2->src, prefixlen, + IPSEC_ULPROTO_ANY); + } else { + idsrc = vdup(iph2->id); + } + if (idsrc == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set ID for source.\n"); + goto end; + } + + if (iph2->id == NULL) { + switch (iph2->dst->sa_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->dst->sa_family); + goto end; + } + iddst = ipsecdoi_sockaddr2id(iph2->dst, prefixlen, + IPSEC_ULPROTO_ANY); + } else { + iddst = vdup(iph2->id_p); + } + if (iddst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set ID for destination.\n"); + goto end; + } + + iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p); + if (iph2->sainfo == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "get sa info: %s\n", sainfo2str(iph2->sainfo)); + + error = 0; +end: + if (idsrc) + vfree(idsrc); + if (iddst) + vfree(iddst); + + return error; +} + +/* + * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types + * are IP address and same address family. + * Then get remote's policy from SPD copied from kernel. + * If the type of ID payload is address or subnet type, then the index is + * made from the payload. If there is no ID payload, or the type of ID + * payload is NOT address type, then the index is made from the address + * pair of phase 1. + * NOTE: This function is only for responder. + */ +static int +get_proposal_r(iph2) + struct ph2handle *iph2; +{ + struct policyindex spidx; + struct secpolicy *sp_in, *sp_out; + int idi2type = 0; /* switch whether copy IDs into id[src,dst]. */ + int error = ISAKMP_INTERNAL_ERROR; + + /* check the existence of ID payload */ + if ((iph2->id_p != NULL && iph2->id == NULL) + || (iph2->id_p == NULL && iph2->id != NULL)) { + plog(LLV_ERROR, LOCATION, NULL, + "Both IDs wasn't found in payload.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + /* make sure if id[src,dst] is null. */ + if (iph2->src_id || iph2->dst_id) { + plog(LLV_ERROR, LOCATION, NULL, + "Why do ID[src,dst] exist already.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + memset(&spidx, 0, sizeof(spidx)); + +#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type + + /* make a spidx; a key to search SPD */ + spidx.dir = IPSEC_DIR_INBOUND; + spidx.ul_proto = 0; + + /* + * make destination address in spidx from either ID payload + * or phase 1 address into a address in spidx. + */ + if (iph2->id != NULL + && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a destination address of a policy */ + error = ipsecdoi_id2sockaddr(iph2->id, + (struct sockaddr *)&spidx.dst, + &spidx.prefd, &spidx.ul_proto); + if (error) + return error; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * note that the phase 1 source address is used as + * a destination address to search for a inbound policy entry + * because rcoon is responder. + */ + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { + error = setscopeid((struct sockaddr *)&spidx.dst, + iph2->src); + if (error) + return error; + } +#endif + + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) + idi2type = _XIDT(iph2->id); + + } else { + + plog(LLV_DEBUG, LOCATION, NULL, + "get a destination address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* + * copy the SOURCE address of IKE into the DESTINATION address + * of the key to search the SPD because the direction of policy + * is inbound. + */ + memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src)); + switch (spidx.dst.ss_family) { + case AF_INET: + spidx.prefd = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefd = sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefd = 0; + break; + } + } + + /* make source address in spidx */ + if (iph2->id_p != NULL + && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a source address of inbound SA */ + error = ipsecdoi_id2sockaddr(iph2->id_p, + (struct sockaddr *)&spidx.src, + &spidx.prefs, &spidx.ul_proto); + if (error) + return error; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * for more detail, see above of this function. + */ + if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { + error = setscopeid((struct sockaddr *)&spidx.src, + iph2->dst); + if (error) + return error; + } +#endif + + /* make id[src,dst] if both ID types are IP address and same */ + if (_XIDT(iph2->id_p) == idi2type + && spidx.dst.ss_family == spidx.src.ss_family) { + iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst); + iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src); + } + + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "get a source address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* see above comment. */ + memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); + switch (spidx.src.ss_family) { + case AF_INET: + spidx.prefs = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefs = sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefs = 0; + break; + } + } + +#undef _XIDT + + plog(LLV_DEBUG, LOCATION, NULL, + "get a src address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.src), + spidx.prefs, spidx.ul_proto); + plog(LLV_DEBUG, LOCATION, NULL, + "get dst address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.dst), + spidx.prefd, spidx.ul_proto); + + /* + * convert the ul_proto if it is 0 + * because 0 in ID payload means a wild card. + */ + if (spidx.ul_proto == 0) + spidx.ul_proto = IPSEC_ULPROTO_ANY; + + /* get inbound policy */ + sp_in = getsp_r(&spidx); + if (sp_in == NULL || sp_in->policy == IPSEC_POLICY_GENERATE) { + if (iph2->ph1->rmconf->gen_policy) { + plog(LLV_INFO, LOCATION, NULL, + "no policy found, " + "try to generate the policy : %s\n", + spidx2str(&spidx)); + iph2->spidx_gen = racoon_malloc(sizeof(spidx)); + if (!iph2->spidx_gen) { + plog(LLV_ERROR, LOCATION, NULL, + "buffer allocation failed.\n"); + return ISAKMP_INTERNAL_ERROR; + } + memcpy(iph2->spidx_gen, &spidx, sizeof(spidx)); + return -2; /* special value */ + } + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", spidx2str(&spidx)); + return ISAKMP_INTERNAL_ERROR; + } + /* Refresh existing generated policies + */ + if (iph2->ph1->rmconf->gen_policy) { + plog(LLV_INFO, LOCATION, NULL, + "Update the generated policy : %s\n", + spidx2str(&spidx)); + iph2->spidx_gen = racoon_malloc(sizeof(spidx)); + if (!iph2->spidx_gen) { + plog(LLV_ERROR, LOCATION, NULL, + "buffer allocation failed.\n"); + return ISAKMP_INTERNAL_ERROR; + } + memcpy(iph2->spidx_gen, &spidx, sizeof(spidx)); + } + + /* get outbound policy */ + { + struct sockaddr_storage addr; + u_int8_t pref; + + spidx.dir = IPSEC_DIR_OUTBOUND; + addr = spidx.src; + spidx.src = spidx.dst; + spidx.dst = addr; + pref = spidx.prefs; + spidx.prefs = spidx.prefd; + spidx.prefd = pref; + + sp_out = getsp_r(&spidx); + if (!sp_out) { + plog(LLV_WARNING, LOCATION, NULL, + "no outbound policy found: %s\n", + spidx2str(&spidx)); + } + } + + plog(LLV_DEBUG, LOCATION, NULL, + "suitable SP found:%s\n", spidx2str(&spidx)); + + /* + * In the responder side, the inbound policy should be using IPsec. + * outbound policy is not checked currently. + */ + if (sp_in->policy != IPSEC_POLICY_IPSEC) { + plog(LLV_ERROR, LOCATION, NULL, + "policy found, but no IPsec required: %s\n", + spidx2str(&spidx)); + return ISAKMP_INTERNAL_ERROR; + } + + /* set new proposal derived from a policy into the iph2->proposal. */ + if (set_proposal_from_policy(iph2, sp_in, sp_out) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to create saprop.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + return 0; +} diff --git a/ipsec-tools/racoon/isakmp_quick.h b/ipsec-tools/racoon/isakmp_quick.h new file mode 100644 index 0000000..4768b53 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_quick.h @@ -0,0 +1,48 @@ +/* $Id: isakmp_quick.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_QUICK_H +#define _ISAKMP_QUICK_H + +extern int quick_i1prep __P((struct ph2handle *, vchar_t *)); +extern int quick_i1send __P((struct ph2handle *, vchar_t *)); +extern int quick_i2recv __P((struct ph2handle *, vchar_t *)); +extern int quick_i2send __P((struct ph2handle *, vchar_t *)); +extern int quick_i3recv __P((struct ph2handle *, vchar_t *)); + +extern int quick_r1recv __P((struct ph2handle *, vchar_t *)); +extern int quick_r1prep __P((struct ph2handle *, vchar_t *)); +extern int quick_r2send __P((struct ph2handle *, vchar_t *)); +extern int quick_r3recv __P((struct ph2handle *, vchar_t *)); +extern int quick_r3send __P((struct ph2handle *, vchar_t *)); +extern int quick_r3prep __P((struct ph2handle *, vchar_t *)); + +#endif /* _ISAKMP_QUICK_H */ diff --git a/ipsec-tools/racoon/isakmp_unity.c b/ipsec-tools/racoon/isakmp_unity.c new file mode 100644 index 0000000..21a1962 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_unity.c @@ -0,0 +1,172 @@ +/* $Id: isakmp_unity.c,v 1.5.4.1 2005/05/10 09:45:46 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "handler.h" +#include "isakmp_xauth.h" +#include "isakmp_unity.h" +#include "isakmp_cfg.h" +#include "strnames.h" + +vchar_t * +isakmp_unity_req(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + int type; + vchar_t *reply_attr = NULL; + + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_UNITY) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Unity mode config request but the peer " + "did not declare itself as unity compliant\n"); + return NULL; + } + + type = ntohs(attr->type); + + /* Handle short attributes */ + if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { + type &= ~ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "Short attribute %d = %d\n", + type, ntohs(attr->lorv)); + + switch (type) { + default: + plog(LLV_DEBUG, LOCATION, NULL, + "Ignored short attribute %d\n", type); + break; + } + + return reply_attr; + } + + switch(type) { + case UNITY_BANNER: { +#define MAXMOTD 65536 + char buf[MAXMOTD + 1]; + int fd; + char *filename = &isakmp_cfg_config.motd[0]; + size_t len; + + if ((fd = open(filename, O_RDONLY, 0)) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open \"%s\"\n", filename); + return NULL; + } + + if ((len = read(fd, buf, MAXMOTD)) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot read \"%s\"\n", filename); + close(fd); + return NULL; + } + close(fd); + + buf[len] = '\0'; + reply_attr = isakmp_cfg_string(iph1, attr, buf); + + break; + } + + case UNITY_PFS: + reply_attr = isakmp_cfg_short(iph1, attr, + isakmp_cfg_config.pfs_group); + break; + + case UNITY_SAVE_PASSWD: + reply_attr = isakmp_cfg_short(iph1, attr, + isakmp_cfg_config.save_passwd); + break; + + case UNITY_DDNS_HOSTNAME: + reply_attr = isakmp_cfg_copy(iph1, attr); + break; + + case UNITY_DEF_DOMAIN: + case UNITY_FW_TYPE: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_BACKUP_SERVERS: + default: + plog(LLV_DEBUG, LOCATION, NULL, + "Ignored attribute %d\n", type); + return NULL; + break; + } + + return reply_attr; +} + + diff --git a/ipsec-tools/racoon/isakmp_unity.h b/ipsec-tools/racoon/isakmp_unity.h new file mode 100644 index 0000000..4f09af1 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_unity.h @@ -0,0 +1,45 @@ +/* $KAME$ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* ISAKMP mode config attributes specific to the Unity vendor Id */ +#define UNITY_BANNER 28672 +#define UNITY_SAVE_PASSWD 28673 +#define UNITY_DEF_DOMAIN 28674 +#define UNITY_SPLITDNS_NAME 28675 +#define UNITY_SPLIT_INCLUDE 28676 +#define UNITY_NATT_PORT 28677 +#define UNITY_LOCAL_LAN 28678 +#define UNITY_PFS 28679 +#define UNITY_FW_TYPE 28680 +#define UNITY_BACKUP_SERVERS 28681 +#define UNITY_DDNS_HOSTNAME 28682 + +vchar_t *isakmp_unity_req(struct ph1handle *, struct isakmp_data *); diff --git a/ipsec-tools/racoon/isakmp_var.h b/ipsec-tools/racoon/isakmp_var.h new file mode 100644 index 0000000..ef32d5b --- /dev/null +++ b/ipsec-tools/racoon/isakmp_var.h @@ -0,0 +1,136 @@ +/* $Id: isakmp_var.h,v 1.9.2.1 2005/05/07 17:26:06 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ISAKMP_VAR_H +#define _ISAKMP_VAR_H + +#include "vmbuf.h" + +#define PORT_ISAKMP 500 +#define PORT_ISAKMP_NATT 4500 + +#define DEFAULT_NONCE_SIZE 16 + +typedef u_char cookie_t[8]; +typedef u_char msgid_t[4]; + +typedef struct { /* i_cookie + r_cookie */ + cookie_t i_ck; + cookie_t r_ck; +} isakmp_index; + +struct isakmp_gen; +struct sched; + +struct sockaddr; +struct ph1handle; +struct ph2handle; +struct remoteconf; +struct isakmp_gen; +struct ipsecdoi_pl_id; /* XXX */ +struct isakmp_pl_ke; /* XXX */ +struct isakmp_pl_nonce; /* XXX */ + +extern int isakmp_handler __P((int)); +extern int isakmp_ph1begin_i __P((struct remoteconf *, struct sockaddr *, + struct sockaddr *)); + +extern vchar_t *isakmp_parsewoh __P((int, struct isakmp_gen *, int)); +extern vchar_t *isakmp_parse __P((vchar_t *)); + +extern int isakmp_init __P((void)); +extern void isakmp_cleanup __P((void)); + +extern const char *isakmp_pindex __P((const isakmp_index *, const u_int32_t)); +extern int isakmp_open __P((void)); +extern void isakmp_close __P((void)); +#ifdef __APPLE__ +extern void isakmp_close_sockets __P((void)); +extern void isakmp_close_unused __P((void)); +#endif +extern int isakmp_send __P((struct ph1handle *, vchar_t *)); + +extern void isakmp_ph1resend_stub __P((void *)); +extern int isakmp_ph1resend __P((struct ph1handle *)); +extern void isakmp_ph2resend_stub __P((void *)); +extern int isakmp_ph2resend __P((struct ph2handle *)); +extern void isakmp_ph1expire_stub __P((void *)); +extern void isakmp_ph1expire __P((struct ph1handle *)); +extern void isakmp_ph1delete_stub __P((void *)); +extern void isakmp_ph1delete __P((struct ph1handle *)); +extern void isakmp_ph2expire_stub __P((void *)); +extern void isakmp_ph2expire __P((struct ph2handle *)); +extern void isakmp_ph2delete_stub __P((void *)); +extern void isakmp_ph2delete __P((struct ph2handle *)); + +extern int isakmp_post_acquire __P((struct ph2handle *)); +extern int isakmp_post_getspi __P((struct ph2handle *)); +extern void isakmp_chkph1there_stub __P((void *)); +extern void isakmp_chkph1there __P((struct ph2handle *)); + +extern caddr_t isakmp_set_attr_v __P((caddr_t, int, caddr_t, int)); +extern caddr_t isakmp_set_attr_l __P((caddr_t, int, u_int32_t)); +extern vchar_t *isakmp_add_attr_v __P((vchar_t *, int, caddr_t, int)); +extern vchar_t *isakmp_add_attr_l __P((vchar_t *, int, u_int32_t)); + +extern int isakmp_newcookie __P((caddr_t, struct sockaddr *, struct sockaddr *)); + +extern int isakmp_p2ph __P((vchar_t **, struct isakmp_gen *)); + +extern u_int32_t isakmp_newmsgid2 __P((struct ph1handle *)); +extern caddr_t set_isakmp_header1 __P((vchar_t *, struct ph1handle *, int)); +extern caddr_t set_isakmp_header2 __P((vchar_t *, struct ph2handle *, int)); +extern caddr_t set_isakmp_payload __P((caddr_t, vchar_t *, int)); + +extern struct payload_list *isakmp_plist_append __P((struct payload_list *plist, + vchar_t *payload, int payload_type)); +extern vchar_t *isakmp_plist_set_all __P((struct payload_list **plist, + struct ph1handle *iph1)); + +#ifdef HAVE_PRINT_ISAKMP_C +extern void isakmp_printpacket __P((vchar_t *, struct sockaddr *, + struct sockaddr *, int)); +#endif + +extern int copy_ph1addresses __P(( struct ph1handle *, + struct remoteconf *, struct sockaddr *, struct sockaddr *)); +extern void log_ph1established __P((const struct ph1handle *)); + +extern void script_hook __P((struct ph1handle *, int)); +extern int script_env_append __P((char ***, int *, char *, char *)); +extern int script_exec __P((int, int, char * const *)); + +void purge_remote __P((struct ph1handle *)); +void delete_spd __P((struct ph2handle *)); +#ifdef INET6 +u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *)); +#endif +#endif /* _ISAKMP_VAR_H */ diff --git a/ipsec-tools/racoon/isakmp_xauth.c b/ipsec-tools/racoon/isakmp_xauth.c new file mode 100644 index 0000000..1bf87c1 --- /dev/null +++ b/ipsec-tools/racoon/isakmp_xauth.c @@ -0,0 +1,995 @@ +/* $Id: isakmp_xauth.c,v 1.17.2.5 2005/05/20 07:31:09 manubsd Exp $ */ + +/* + * Copyright (C) 2004-2005 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_SHADOW_H +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#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 + +struct rad_handle *radius_auth_state = NULL; +struct rad_handle *radius_acct_state = NULL; +#endif + +#ifdef HAVE_LIBPAM +#ifdef __APPLE__ +#include +#else +#include +#endif + +static char *PAM_usr = NULL; +static char *PAM_pwd = NULL; +static int PAM_conv(int, const struct pam_message **, + struct pam_response **, void *); +static struct pam_conv PAM_chat = { &PAM_conv, NULL }; +#endif + + +void +xauth_sendreq(iph1) + struct ph1handle *iph1; +{ + vchar_t *buffer; + struct isakmp_pl_attr *attr; + struct isakmp_data *typeattr; + struct isakmp_data *usrattr; + struct isakmp_data *pwdattr; + struct xauth_state *xst = &iph1->mode_cfg->xauth; + size_t tlen; + + /* Status checks */ + if (iph1->status != PHASE1ST_ESTABLISHED) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth request while phase 1 is not completed\n"); + return; + } + + if (xst->status != XAUTHST_NOTYET) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth request whith Xauth state %d\n", xst->status); + return; + } + + plog(LLV_INFO, LOCATION, NULL, "Sending Xauth request\n"); + + tlen = sizeof(*attr) + + + sizeof(*typeattr) + + + sizeof(*usrattr) + + + sizeof(*pwdattr); + + if ((buffer = vmalloc(tlen)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n"); + return; + } + + attr = (struct isakmp_pl_attr *)buffer->v; + memset(attr, 0, tlen); + + attr->h.len = htons(tlen); + attr->type = ISAKMP_CFG_REQUEST; + attr->id = htons(eay_random()); + + typeattr = (struct isakmp_data *)(attr + 1); + typeattr->type = htons(XAUTH_TYPE | ISAKMP_GEN_TV); + typeattr->lorv = htons(XAUTH_TYPE_GENERIC); + + usrattr = (struct isakmp_data *)(typeattr + 1); + usrattr->type = htons(XAUTH_USER_NAME | ISAKMP_GEN_TLV); + usrattr->lorv = htons(0); + + pwdattr = (struct isakmp_data *)(usrattr + 1); + pwdattr->type = htons(XAUTH_USER_PASSWORD | ISAKMP_GEN_TLV); + pwdattr->lorv = htons(0); + + isakmp_cfg_send(iph1, buffer, + ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1); + + vfree(buffer); + + xst->status = XAUTHST_REQSENT; + + return; +} + +void +xauth_attr_reply(iph1, attr, id) + struct ph1handle *iph1; + struct isakmp_data *attr; + int id; +{ + char **outlet = NULL; + size_t alen = 0; + int type; + struct xauth_state *xst = &iph1->mode_cfg->xauth; + + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth reply but peer did not declare " + "itself as Xauth capable\n"); + return; + } + + if (xst->status != XAUTHST_REQSENT) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth reply while Xauth state is %d\n", xst->status); + return; + } + + type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; + switch (type) { + case XAUTH_TYPE: + switch (ntohs(attr->lorv)) { + case XAUTH_TYPE_GENERIC: + xst->authtype = XAUTH_TYPE_GENERIC; + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "Unexpected authentication type %d\n", + ntohs(type)); + return; + } + break; + + case XAUTH_USER_NAME: + outlet = &xst->authdata.generic.usr; + break; + + case XAUTH_USER_PASSWORD: + outlet = &xst->authdata.generic.pwd; + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "ignored Xauth attribute %d\n", type); + break; + } + + if (outlet != NULL) { + alen = ntohs(attr->lorv); + + if ((*outlet = racoon_malloc(alen + 1)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory for Xauth Data\n"); + return; + } + + memcpy(*outlet, attr + 1, alen); + (*outlet)[alen] = '\0'; + outlet = NULL; + } + + + if ((xst->authdata.generic.usr != NULL) && + (xst->authdata.generic.pwd != NULL)) { + int port; + int res; + char *usr = xst->authdata.generic.usr; + char *pwd = xst->authdata.generic.pwd; + time_t throttle_delay = 0; + +#if 0 /* Real debug, don't do that at home */ + plog(LLV_DEBUG, LOCATION, NULL, + "Got username \"%s\", password \"%s\"\n", usr, pwd); +#endif + strncpy(iph1->mode_cfg->login, usr, LOGINLEN); + iph1->mode_cfg->login[LOGINLEN] = '\0'; + + res = -1; + if ((port = isakmp_cfg_getport(iph1)) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "Port pool depleted\n"); + goto skip_auth; + } + + switch (isakmp_cfg_config.authsource) { + case ISAKMP_CFG_AUTH_SYSTEM: + res = privsep_xauth_login_system(usr, pwd); + break; +#ifdef HAVE_LIBRADIUS + case ISAKMP_CFG_AUTH_RADIUS: + res = xauth_login_radius(iph1, usr, pwd); + break; +#endif +#ifdef HAVE_LIBPAM + case ISAKMP_CFG_AUTH_PAM: + res = privsep_xauth_login_pam(iph1->mode_cfg->port, + iph1->remote, usr, pwd); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected authentication source\n"); + res = -1; + break; + } + + /* + * On failure, throttle the connexion for the remote host + * in order to make password attacks more difficult. + */ + throttle_delay = throttle_host(iph1->remote, res) - time(NULL); + if (throttle_delay > 0) { + char *str; + + str = saddrwop2str(iph1->remote); + + plog(LLV_ERROR, LOCATION, NULL, + "Throttling in action for %s: delay %lds\n", + str, (unsigned long)throttle_delay); + res = -1; + } else { + throttle_delay = 0; + } + +skip_auth: + if (throttle_delay != 0) { + struct xauth_reply_arg *xra; + + if ((xra = racoon_malloc(sizeof(*xra))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "malloc failed, bypass throttling\n"); + xauth_reply(iph1, port, id, res); + return; + } + + /* + * We need to store the ph1, but it might have + * disapeared when xauth_reply is called, so + * store the index instead. + */ + xra->index = iph1->index; + xra->port = port; + xra->id = id; + xra->res = res; + sched_new(throttle_delay, xauth_reply_stub, xra); + } else { + xauth_reply(iph1, port, id, res); + } + } + + return; +} + +void +xauth_reply_stub(args) + void *args; +{ + struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args; + struct ph1handle *iph1; + + if ((iph1 = getph1byindex(&xra->index)) != NULL) + xauth_reply(iph1, xra->port, xra->id, xra->res); + else + plog(LLV_ERROR, LOCATION, NULL, + "Delayed Xauth reply: phase 1 no longer exists.\n"); + + racoon_free(xra); + return; +} + +void +xauth_reply(iph1, port, id, res) + struct ph1handle *iph1; + int port; + int id; +{ + struct xauth_state *xst = &iph1->mode_cfg->xauth; + char *usr = xst->authdata.generic.usr; + + if (res != 0) { + if (port != -1) + isakmp_cfg_putport(iph1, port); + + plog(LLV_INFO, LOCATION, NULL, + "login failed for user \"%s\"\n", usr); + + xauth_sendstatus(iph1, XAUTH_STATUS_FAIL, id); + xst->status = XAUTHST_NOTYET; + + /* Delete Phase 1 SA */ + if (iph1->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(iph1); + remph1(iph1); + delph1(iph1); + + return; + } + + xst->status = XAUTHST_OK; + plog(LLV_INFO, LOCATION, NULL, + "login succeeded for user \"%s\"\n", usr); + + xauth_sendstatus(iph1, XAUTH_STATUS_OK, id); + + return; +} + +void +xauth_sendstatus(iph1, status, id) + struct ph1handle *iph1; + int status; + int id; +{ + vchar_t *buffer; + struct isakmp_pl_attr *attr; + struct isakmp_data *stattr; + size_t tlen; + + tlen = sizeof(*attr) + + + sizeof(*stattr); + + if ((buffer = vmalloc(tlen)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n"); + return; + } + + attr = (struct isakmp_pl_attr *)buffer->v; + memset(attr, 0, tlen); + + attr->h.len = htons(tlen); + attr->type = ISAKMP_CFG_SET; + attr->id = htons(id); + + stattr = (struct isakmp_data *)(attr + 1); + stattr->type = htons(XAUTH_STATUS | ISAKMP_GEN_TV); + stattr->lorv = htons(status); + + isakmp_cfg_send(iph1, buffer, + ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1); + + vfree(buffer); + + return; +} + +#ifdef HAVE_LIBRADIUS +int +xauth_radius_init(void) +{ + /* For first time use, initialize Radius */ + if ((isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_RADIUS) && + (radius_auth_state == NULL)) { + if ((radius_auth_state = rad_auth_open()) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot init libradius\n"); + return -1; + } + + if (rad_config(radius_auth_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open librarius config file: %s\n", + rad_strerror(radius_auth_state)); + rad_close(radius_auth_state); + radius_auth_state = NULL; + return -1; + } + } + + if ((isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS) && + (radius_acct_state == NULL)) { + if ((radius_acct_state = rad_auth_open()) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot init libradius\n"); + return -1; + } + + if (rad_config(radius_acct_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open librarius config file: %s\n", + rad_strerror(radius_acct_state)); + rad_close(radius_acct_state); + radius_acct_state = NULL; + return -1; + } + } + + return 0; +} + +int +xauth_login_radius(iph1, usr, pwd) + struct ph1handle *iph1; + char *usr; + char *pwd; +{ + int res; + const void *data; + size_t len; + int type; + + if (rad_create_request(radius_auth_state, RAD_ACCESS_REQUEST) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_create_request failed: %s\n", + rad_strerror(radius_auth_state)); + return -1; + } + + if (rad_put_string(radius_auth_state, RAD_USER_NAME, usr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_string failed: %s\n", + rad_strerror(radius_auth_state)); + return -1; + } + + if (rad_put_string(radius_auth_state, RAD_USER_PASSWORD, pwd) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_string failed: %s\n", + rad_strerror(radius_auth_state)); + return -1; + } + + if (isakmp_cfg_radius_common(radius_auth_state, iph1->mode_cfg->port) != 0) + return -1; + + switch (res = rad_send_request(radius_auth_state)) { + case RAD_ACCESS_ACCEPT: + while ((type = rad_get_attr(radius_auth_state, &data, &len)) != 0) { + switch (type) { + case RAD_FRAMED_IP_ADDRESS: + iph1->mode_cfg->addr4 = rad_cvt_addr(data); + iph1->mode_cfg->flags + |= ISAKMP_CFG_ADDR4_RADIUS; + break; + + case RAD_FRAMED_IP_NETMASK: + iph1->mode_cfg->mask4 = rad_cvt_addr(data); + iph1->mode_cfg->flags + |= ISAKMP_CFG_MASK4_RADIUS; + break; + + default: + plog(LLV_INFO, LOCATION, NULL, + "Unexpected attribute: %d\n", type); + break; + } + } + + return 0; + break; + + case RAD_ACCESS_REJECT: + return -1; + break; + + case -1: + plog(LLV_ERROR, LOCATION, NULL, + "rad_send_request failed: %s\n", + rad_strerror(radius_auth_state)); + return -1; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "rad_send_request returned %d\n", res); + return -1; + break; + } + + return -1; +} +#endif + +#ifdef HAVE_LIBPAM +static int +PAM_conv(msg_count, msg, rsp, dontcare) + int msg_count; + const struct pam_message **msg; + struct pam_response **rsp; + void *dontcare; +{ + int i; + int replies = 0; + struct pam_response *reply = NULL; + + if ((reply = racoon_malloc(sizeof(*reply) * msg_count)) == NULL) + return PAM_CONV_ERR; + bzero(reply, sizeof(*reply) * msg_count); + + for (i = 0; i < msg_count; i++) { + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_ON: + /* Send the username, libpam frees resp */ + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = strdup(PAM_usr); + break; + + case PAM_PROMPT_ECHO_OFF: + /* Send the password, libpam frees resp */ + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = strdup(PAM_pwd); + break; + + case PAM_TEXT_INFO: + case PAM_ERROR_MSG: + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = NULL; + break; + + default: + if (reply != NULL) + racoon_free(reply); + return PAM_CONV_ERR; + break; + } + } + + if (reply != NULL) + *rsp = reply; + + return PAM_SUCCESS; +} + +int +xauth_login_pam(port, raddr, usr, pwd) + int port; + struct sockaddr *raddr; + char *usr; + char *pwd; +{ + int error; + int res; + const void *data; + size_t len; + int type; + char *remote; + pam_handle_t *pam = NULL; + + if (isakmp_cfg_config.port_pool == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "isakmp_cfg_config.port_pool == NULL\n"); + return -1; + } + + if ((error = pam_start("racoon", usr, + &PAM_chat, &isakmp_cfg_config.port_pool[port].pam)) != 0) { + if (isakmp_cfg_config.port_pool[port].pam == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "pam_start failed\n"); + return -1; + } else { + plog(LLV_ERROR, LOCATION, NULL, + "pam_start failed: %s\n", + pam_strerror(isakmp_cfg_config.port_pool[port].pam, + error)); + goto out; + } + } + pam = isakmp_cfg_config.port_pool[port].pam; + + if ((remote = strdup(saddrwop2str(raddr))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory: %s\n", strerror(errno)); + goto out; + } + + if ((error = pam_set_item(pam, PAM_RHOST, remote)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pam_set_item failed: %s\n", + pam_strerror(pam, error)); + goto out; + } + + PAM_usr = usr; + PAM_pwd = pwd; + error = pam_authenticate(pam, 0); + PAM_usr = NULL; + PAM_pwd = NULL; + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pam_authenticate failed: %s\n", + pam_strerror(pam, error)); + goto out; + } + + if ((error = pam_acct_mgmt(pam, 0)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pam_acct_mgmt failed: %s\n", + pam_strerror(pam, error)); + goto out; + } + + if ((error = pam_setcred(pam, 0)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pam_setcred failed: %s\n", + pam_strerror(pam, error)); + goto out; + } + + return 0; + +out: + pam_end(pam, error); + isakmp_cfg_config.port_pool[port].pam = NULL; + return -1; +} +#endif + +int +xauth_login_system(usr, pwd) + char *usr; + char *pwd; +{ + struct passwd *pw; + char *cryptpwd; + char *syscryptpwd; +#ifdef HAVE_SHADOW_H + struct spwd *spw; + + if ((spw = getspnam(usr)) == NULL) + return -1; + + syscryptpwd = spw->sp_pwdp; +#endif + + if ((pw = getpwnam(usr)) == NULL) + return -1; + +#ifndef HAVE_SHADOW_H + syscryptpwd = pw->pw_passwd; +#endif + + /* No root login. Ever. */ + if (pw->pw_uid == 0) + return -1; + + if ((cryptpwd = crypt(pwd, syscryptpwd)) == NULL) + return -1; + + if (strcmp(cryptpwd, syscryptpwd) == 0) + return 0; + + return -1; +} + +int +xauth_check(iph1) + struct ph1handle *iph1; +{ + struct xauth_state *xst = &iph1->mode_cfg->xauth; + + /* If we don't use Xauth, then we pass */ + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + /* The following are not yet implemented */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Hybrid auth negotiated but peer did not " + "announced as Xauth capable\n"); + return -1; + } + + if (xst->status != XAUTHST_OK) { + plog(LLV_ERROR, LOCATION, NULL, + "Hybrid auth negotiated but peer did not " + "succeed Xauth exchange\n"); + return -1; + } + + return 0; + break; + default: + return 0; + break; + } + + return 0; +} + +vchar_t * +isakmp_xauth_req(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + int type; + size_t dlen = 0; + int ashort = 0; + int value = 0; + vchar_t *buffer = NULL; + char *data; + vchar_t *usr = NULL; + vchar_t *pwd = NULL; + size_t skip = 0; + int freepwd = 0; + + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth mode config request but peer " + "did not declare itself as Xauth capable\n"); + return NULL; + } + + type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; + + /* Sanity checks */ + switch(type) { + case XAUTH_TYPE: + if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected long XAUTH_TYPE attribute\n"); + return NULL; + } + if (ntohs(attr->lorv) != XAUTH_TYPE_GENERIC) { + plog(LLV_ERROR, LOCATION, NULL, + "Unsupported Xauth authentication %d\n", + ntohs(attr->lorv)); + return NULL; + } + ashort = 1; + dlen = 0; + value = XAUTH_TYPE_GENERIC; + break; + + case XAUTH_USER_NAME: + if (iph1->rmconf->idvtype != IDTYPE_LOGIN) { + plog(LLV_ERROR, LOCATION, NULL, "Xauth performed " + "while identifier is not a login\n"); + return NULL; + } + + if (iph1->rmconf->idv == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Xauth performed " + "with no login supplied\n"); + return NULL; + } + + dlen = iph1->rmconf->idv->l; + break; + + case XAUTH_USER_PASSWORD: + if (iph1->rmconf->idvtype != IDTYPE_LOGIN) + return NULL; + + if (iph1->rmconf->idv == NULL) + return NULL; + + skip = sizeof(struct ipsecdoi_id_b); + if ((usr = vmalloc(iph1->rmconf->idv->l + skip)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return NULL; + } + + memset(usr->v, 0, skip); + memcpy(usr->v + skip, + iph1->rmconf->idv->v, + iph1->rmconf->idv->l); + + if (iph1->rmconf->key) { + /* A key given through racoonctl */ + pwd = iph1->rmconf->key; + } else { + if ((pwd = getpskbyname(usr)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "No password was found for login %s\n", + iph1->rmconf->idv->v); + vfree(usr); + return NULL; + } + /* We have to free it before returning */ + freepwd = 1; + } + vfree(usr); + + dlen = pwd->l; + + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", type); + return NULL; + break; + } + + if ((buffer = vmalloc(sizeof(*attr) + dlen)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + goto out; + } + + attr = (struct isakmp_data *)buffer->v; + if (ashort) { + attr->type = htons(type | ISAKMP_GEN_TV); + attr->lorv = htons(value); + goto out; + } + + attr->type = htons(type | ISAKMP_GEN_TLV); + attr->lorv = htons(dlen); + data = (char *)(attr + 1); + + switch(type) { + case XAUTH_USER_NAME: + memcpy(data, iph1->rmconf->idv->v, dlen); + break; + case XAUTH_USER_PASSWORD: + memcpy(data, pwd->v, dlen); + break; + default: + break; + } + +out: + if (freepwd) + vfree(pwd); + + return buffer; +} + +vchar_t * +isakmp_xauth_set(iph1, attr) + struct ph1handle *iph1; + struct isakmp_data *attr; +{ + int type; + vchar_t *buffer = NULL; + char *data; + + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth mode config set but peer " + "did not declare itself as Xauth capable\n"); + return NULL; + } + + type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; + + switch(type) { + case XAUTH_STATUS: + /* If we got a failure, delete iph1 */ + if (ntohs(attr->lorv) != XAUTH_STATUS_OK) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth authentication failed\n"); + + EVT_PUSH(iph1->local, iph1->remote, + EVTT_XAUTH_FAILED, NULL); + + iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1; + } else { + EVT_PUSH(iph1->local, + iph1->remote, EVTT_XAUTH_SUCCESS, NULL); + } + + + /* We acknowledge it */ + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", type); + return NULL; + break; + } + + if ((buffer = vmalloc(sizeof(*attr))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return NULL; + } + + attr = (struct isakmp_data *)buffer->v; + attr->type = htons(type | ISAKMP_GEN_TV); + attr->lorv = htons(0); + + return buffer; +} + + +void +xauth_rmstate(xst) + struct xauth_state *xst; +{ + switch (xst->authtype) { + case XAUTH_TYPE_GENERIC: + if (xst->authdata.generic.usr) + racoon_free(xst->authdata.generic.usr); + + if (xst->authdata.generic.pwd) + racoon_free(xst->authdata.generic.pwd); + + break; + + case XAUTH_TYPE_CHAP: + case XAUTH_TYPE_OTP: + case XAUTH_TYPE_SKEY: + plog(LLV_WARNING, LOCATION, NULL, + "Unsupported authtype %d\n", xst->authtype); + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "Unexpected authtype %d\n", xst->authtype); + break; + } + + return; +} + diff --git a/ipsec-tools/racoon/isakmp_xauth.h b/ipsec-tools/racoon/isakmp_xauth.h new file mode 100644 index 0000000..5d4bdbb --- /dev/null +++ b/ipsec-tools/racoon/isakmp_xauth.h @@ -0,0 +1,96 @@ +/* $KAME$ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* ISAKMP mode config attribute types specific to the Xauth vendor ID */ +#define XAUTH_TYPE 16520 +#define XAUTH_USER_NAME 16521 +#define XAUTH_USER_PASSWORD 16522 +#define XAUTH_PASSCODE 16523 +#define XAUTH_MESSAGE 16524 +#define XAUTH_CHALLENGE 16525 +#define XAUTH_DOMAIN 16526 +#define XAUTH_STATUS 16527 +#define XAUTH_NEXT_PIN 16528 +#define XAUTH_ANSWER 16529 + +/* Types for XAUTH_TYPE */ +#define XAUTH_TYPE_GENERIC 0 +#define XAUTH_TYPE_CHAP 1 +#define XAUTH_TYPE_OTP 2 +#define XAUTH_TYPE_SKEY 3 + +/* Values for XAUTH_STATUS */ +#define XAUTH_STATUS_FAIL 0 +#define XAUTH_STATUS_OK 1 + +struct xauth_state { + int status; + int vendorid; + int authtype; + union { + struct authgeneric { + char *usr; + char *pwd; + } generic; + } authdata; +}; + +/* status */ +#define XAUTHST_NOTYET 0 +#define XAUTHST_REQSENT 1 +#define XAUTHST_OK 2 + +struct xauth_reply_arg { + isakmp_index index; + int port; + int id; + int res; +}; + +struct ph1handle; +void xauth_sendreq(struct ph1handle *); +void xauth_attr_reply(struct ph1handle *, struct isakmp_data *, int); +int xauth_login_system(char *, char *); +void xauth_sendstatus(struct ph1handle *, int, int); +int xauth_check(struct ph1handle *); +vchar_t *isakmp_xauth_req(struct ph1handle *, struct isakmp_data *); +vchar_t *isakmp_xauth_set(struct ph1handle *, struct isakmp_data *); +void xauth_rmstate(struct xauth_state *); +void xauth_reply_stub(void *); +void xauth_reply(struct ph1handle *, int, int, int); + +#ifdef HAVE_LIBRADIUS +int xauth_login_radius(struct ph1handle *, char *, char *); +int xauth_radius_init(void); +#endif +#ifdef HAVE_LIBPAM +int xauth_login_pam(int, struct sockaddr *, char *, char *); +#endif diff --git a/ipsec-tools/racoon/kmpstat.c b/ipsec-tools/racoon/kmpstat.c new file mode 100644 index 0000000..b9eec1a --- /dev/null +++ b/ipsec-tools/racoon/kmpstat.c @@ -0,0 +1,230 @@ +/* $KAME: kmpstat.c,v 1.33 2004/08/16 08:20:28 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" +#include "sockmisc.h" + +#include "racoonctl.h" +#include "admin.h" +#include "schedule.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_xauth.h" +#include "isakmp_var.h" +#include "isakmp_cfg.h" +#include "isakmp_unity.h" +#include "oakley.h" +#include "handler.h" +#include "pfkey.h" +#include "admin.h" +#include "evt.h" +#include "admin_var.h" +#include "ipsec_doi.h" + +u_int32_t racoonctl_interface = RACOONCTL_INTERFACE; +u_int32_t racoonctl_interface_major = RACOONCTL_INTERFACE_MAJOR; + +static int so; +u_int32_t loglevel = 0; + +int +com_init() +{ + struct sockaddr_un name; + + memset(&name, 0, sizeof(name)); + name.sun_family = AF_UNIX; + snprintf(name.sun_path, sizeof(name.sun_path), + "%s", ADMINSOCK_PATH); + + so = socket(AF_UNIX, SOCK_STREAM, 0); + if (so < 0) + return -1; + + if (connect(so, (struct sockaddr *)&name, sizeof(name)) < 0) { + (void)close(so); + return -1; + } + + return 0; +} + +int +com_send(combuf) + vchar_t *combuf; +{ + int len; + + if ((len = send(so, combuf->v, combuf->l, 0)) == -1) { + perror("send"); + (void)close(so); + return -1; + } + + return 0; +} + +int +com_recv(combufp) + vchar_t **combufp; +{ + struct admin_com h, *com; + caddr_t buf; + int len; + int l = 0; + caddr_t p; + + if (combufp == NULL) + return -1; + + /* receive by PEEK */ + if ((len = recv(so, &h, sizeof(h), MSG_PEEK)) == -1) + goto bad1; + + /* sanity check */ + if (len < sizeof(h)) + goto bad1; + + if (h.ac_errno) { + errno = h.ac_errno; + goto bad1; + } + + /* allocate buffer */ + if ((*combufp = vmalloc(h.ac_len)) == NULL) + goto bad1; + + /* read real message */ + p = (*combufp)->v; + while (l < len) { + if ((len = recv(so, p, h.ac_len, 0)) < 0) { + perror("recv"); + goto bad2; + } + l += len; + p += len; + } + + return 0; + +bad2: + vfree(*combufp); +bad1: + *combufp = NULL; + return -1; +} + +/* + * Dumb plog functions (used by sockmisc.c) + */ +void +plog(int pri, const char *func, struct sockaddr *sa, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +void +plogdump(pri, data, len) + int pri; + void *data; + size_t len; +{ + return; +} + +struct sockaddr * +get_sockaddr(family, name, port) + int family; + char *name, *port; +{ + struct addrinfo hint, *ai; + int error; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = PF_UNSPEC; + hint.ai_family = family; + hint.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(name, port, &hint, &ai); + if (error != 0) { + printf("%s: %s/%s\n", gai_strerror(error), name, port); + return NULL; + } + + return ai->ai_addr; +} diff --git a/ipsec-tools/racoon/localconf.c b/ipsec-tools/racoon/localconf.c new file mode 100644 index 0000000..73f01f9 --- /dev/null +++ b/ipsec-tools/racoon/localconf.c @@ -0,0 +1,479 @@ +/* $KAME: localconf.c,v 1.33 2001/08/09 07:32:19 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 +#include +#endif + +struct localconf *lcconf; + +static void setdefault __P((void)); + +void +initlcconf() +{ + lcconf = racoon_calloc(1, sizeof(*lcconf)); + if (lcconf == NULL) + errx(1, "failed to allocate local conf."); + + setdefault(); + lcconf->sock_vpncontrol = -1; /* not to be done during flush */ + lcconf->racoon_conf = LC_DEFAULT_CF; +} + +void +flushlcconf() +{ + int i; + + setdefault(); + clear_myaddr(); + for (i = 0; i < LC_PATHTYPE_MAX; i++) { + if (lcconf->pathinfo[i]) { + racoon_free(lcconf->pathinfo[i]); + lcconf->pathinfo[i] = NULL; + } + } + for (i = 0; i < LC_IDENTTYPE_MAX; i++) { + if (lcconf->ident[i]) + vfree(lcconf->ident[i]); + lcconf->ident[i] = NULL; + } +} + +static void +setdefault() +{ + lcconf->uid = 0; + lcconf->gid = 0; + lcconf->chroot = NULL; + lcconf->autograbaddr = 1; + lcconf->port_isakmp = PORT_ISAKMP; + lcconf->port_isakmp_natt = PORT_ISAKMP_NATT; + lcconf->default_af = AF_INET; + lcconf->pad_random = LC_DEFAULT_PAD_RANDOM; + lcconf->pad_randomlen = LC_DEFAULT_PAD_RANDOMLEN; + lcconf->pad_maxsize = LC_DEFAULT_PAD_MAXSIZE; + lcconf->pad_strict = LC_DEFAULT_PAD_STRICT; + lcconf->pad_excltail = LC_DEFAULT_PAD_EXCLTAIL; + lcconf->retry_counter = LC_DEFAULT_RETRY_COUNTER; + lcconf->retry_interval = LC_DEFAULT_RETRY_INTERVAL; + lcconf->count_persend = LC_DEFAULT_COUNT_PERSEND; + lcconf->secret_size = LC_DEFAULT_SECRETSIZE; + lcconf->retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1; + lcconf->wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE; + lcconf->strict_address = FALSE; + lcconf->complex_bundle = TRUE; /*XXX FALSE;*/ + lcconf->gss_id_enc = LC_GSSENC_UTF16LE; /* Windows compatibility */ + lcconf->natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL; + lcconf->auto_exit_delay = 0; + lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_SET; +} + +/* + * get PSK by string. + */ +vchar_t * +getpskbyname(id0) + vchar_t *id0; +{ + char *id; + vchar_t *key = NULL; + + id = racoon_calloc(1, 1 + id0->l - sizeof(struct ipsecdoi_id_b)); + if (id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get psk buffer.\n"); + goto end; + } + memcpy(id, id0->v + sizeof(struct ipsecdoi_id_b), + id0->l - sizeof(struct ipsecdoi_id_b)); + id[id0->l - sizeof(struct ipsecdoi_id_b)] = '\0'; + + key = privsep_getpsk(id, id0->l - sizeof(struct ipsecdoi_id_b)); + +end: + if (id) + racoon_free(id); + return key; +} + +#ifdef __APPLE__ +/* + * get PSK from keyChain. + */ +vchar_t * +getpskfromkeychain(const char *name, u_int8_t etype, int secrettype, vchar_t *id_p) +{ + SecKeychainRef keychain = NULL; + vchar_t *key = NULL; + void *cur_password = NULL; + UInt32 cur_password_len = 0; + OSStatus status; + char serviceName[] = "com.apple.net.racoon"; + + status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); + if (status != noErr) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set system keychain domain.\n"); + goto end; + } + + status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, + &keychain); + if (status != noErr) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get system keychain domain.\n"); + goto end; + } + + if (secrettype == SECRETTYPE_KEYCHAIN_BY_ID && etype == ISAKMP_ETYPE_AGG) { + /* try looking up based on peers id */ + + char* peer_id; + int idlen = id_p->l - sizeof(struct ipsecdoi_id_b); + u_int8_t id_type = ((struct ipsecdoi_id_b *)(id_p->v))->type; + + switch (id_type) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + case IPSECDOI_ID_DER_ASN1_DN: + case IPSECDOI_ID_DER_ASN1_GN: + goto end; + break; + + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + case IPSECDOI_ID_KEY_ID: + peer_id = racoon_malloc(idlen); + if (peer_id == NULL) + goto end; + memcpy(peer_id, id_p->v + sizeof(struct ipsecdoi_id_b), idlen); + *(peer_id + idlen) = '\0'; + plog(LLV_ERROR, LOCATION, NULL, + "getting shared secret from keychain using %s.\n", peer_id); + + break; + default: + goto end; + break; + } + + status = SecKeychainFindGenericPassword(keychain, + strlen(serviceName), + serviceName, + idlen, + peer_id, + &cur_password_len, + &cur_password, + NULL); + + if (status == noErr) + goto end; + /* otherwise fall through to use the default value */ + } + + /* use the value in remote config sharedsecret field + this is either the value specified for lookup or the + default when lookup by id fails. + */ + status = SecKeychainFindGenericPassword(keychain, + strlen(serviceName), + serviceName, + strlen(name), + name, + &cur_password_len, + &cur_password, + NULL); + + /* try find it using using only name. */ + if (status == errSecItemNotFound) + status = SecKeychainFindGenericPassword(keychain, + strlen(name), + name, + 0, + 0, + &cur_password_len, + &cur_password, + NULL); + + switch (status) { + + case noErr : + goto end; + break; + + case errSecItemNotFound : + break; + + default : + plog(LLV_ERROR, LOCATION, NULL, + "failed to get preshared key from system keychain (error %d).\n", status); + } + +end: + + if (cur_password) { + key = vmalloc(cur_password_len + 1); + if (key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate key buffer.\n"); + } else { + memcpy(key->v, cur_password, key->l); + key->v[cur_password_len] = 0; + } + free(cur_password); + } + + if (keychain) + CFRelease(keychain); + + return key; +} +#endif + +/* + * get PSK by address. + */ +vchar_t * +getpskbyaddr(remote) + struct sockaddr *remote; +{ + vchar_t *key = NULL; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + GETNAMEINFO(remote, addr, port); + + key = privsep_getpsk(addr, strlen(addr)); + + return key; +} + +vchar_t * +getpsk(str, len) + const char *str; + const int len; +{ + FILE *fp; + char buf[1024]; /* XXX how is variable length ? */ + vchar_t *key = NULL; + char *p, *q; + size_t keylen; + char *k = NULL; + + if (safefile(lcconf->pathinfo[LC_PATHTYPE_PSK], 1) == 0) + fp = fopen(lcconf->pathinfo[LC_PATHTYPE_PSK], "r"); + else + fp = NULL; + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to open pre_share_key file %s\n", + lcconf->pathinfo[LC_PATHTYPE_PSK]); + return NULL; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* comment line */ + if (buf[0] == '#') + continue; + + /* search the end of 1st string. */ + for (p = buf; *p != '\0' && !isspace((int)*p); p++) + ; + if (*p == '\0') + continue; /* no 2nd parameter */ + *p = '\0'; + /* search the 1st of 2nd string. */ + while (isspace((int)*++p)) + ; + if (*p == '\0') + continue; /* no 2nd parameter */ + p--; + if (strncmp(buf, str, len) == 0 && buf[len] == '\0') { + p++; + keylen = 0; + for (q = p; *q != '\0' && *q != '\n'; q++) + keylen++; + *q = '\0'; + + /* fix key if hex string */ + if (strncmp(p, "0x", 2) == 0) { + k = str2val(p + 2, 16, &keylen); + if (k == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get psk buffer.\n"); + goto end; + } + p = k; + } + + key = vmalloc(keylen); + if (key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate key buffer.\n"); + goto end; + } + memcpy(key->v, p, key->l); + if (k) + racoon_free(k); + goto end; + } + } + +end: + fclose(fp); + return key; +} + +/* + * get a file name of a type specified. + */ +void +getpathname(path, len, type, name) + char *path; + int len, type; + const char *name; +{ + snprintf(path, len, "%s%s%s", + name[0] == '/' ? "" : lcconf->pathinfo[type], + name[0] == '/' ? "" : "/", + name); + + plog(LLV_DEBUG, LOCATION, NULL, "filename: %s\n", path); +} + +#if 0 /* DELETEIT */ +static int lc_doi2idtype[] = { + -1, + -1, + LC_IDENTTYPE_FQDN, + LC_IDENTTYPE_USERFQDN, + -1, + -1, + -1, + -1, + -1, + LC_IDENTTYPE_CERTNAME, + -1, + LC_IDENTTYPE_KEYID, +}; + +/* + * convert DOI value to idtype + * OUT -1 : NG + * other: converted. + */ +int +doi2idtype(idtype) + int idtype; +{ + if (ARRAYLEN(lc_doi2idtype) > idtype) + return lc_doi2idtype[idtype]; + return -1; +} +#endif + +static int lc_sittype2doi[] = { + IPSECDOI_SIT_IDENTITY_ONLY, + IPSECDOI_SIT_SECRECY, + IPSECDOI_SIT_INTEGRITY, +}; + +/* + * convert sittype to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +sittype2doi(sittype) + int sittype; +{ + if (ARRAYLEN(lc_sittype2doi) > sittype) + return lc_sittype2doi[sittype]; + return -1; +} + +static int lc_doitype2doi[] = { + IPSEC_DOI, +}; + +/* + * convert doitype to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +doitype2doi(doitype) + int doitype; +{ + if (ARRAYLEN(lc_doitype2doi) > doitype) + return lc_doitype2doi[doitype]; + return -1; +} + diff --git a/ipsec-tools/racoon/localconf.h b/ipsec-tools/racoon/localconf.h new file mode 100644 index 0000000..f99d1a7 --- /dev/null +++ b/ipsec-tools/racoon/localconf.h @@ -0,0 +1,167 @@ +/* $Id: localconf.h,v 1.9.2.3 2005/11/06 17:18:26 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LOCALCONF_H +#define _LOCALCONF_H + +/* local configuration */ + +#define LC_DEFAULT_CF SYSCONFDIR "/racoon.conf" + +#define LC_PATHTYPE_INCLUDE 0 +#define LC_PATHTYPE_PSK 1 +#define LC_PATHTYPE_CERT 2 +#define LC_PATHTYPE_BACKUPSA 3 +#define LC_PATHTYPE_SCRIPT 4 +#define LC_PATHTYPE_PIDFILE 5 +#define LC_PATHTYPE_LOGFILE 6 +#define LC_PATHTYPE_MAX 7 + +#define LC_DEFAULT_PAD_MAXSIZE 20 +#define LC_DEFAULT_PAD_RANDOM TRUE +#define LC_DEFAULT_PAD_RANDOMLEN FALSE +#define LC_DEFAULT_PAD_STRICT FALSE +#define LC_DEFAULT_PAD_EXCLTAIL TRUE +#define LC_DEFAULT_RETRY_COUNTER 5 +#define LC_DEFAULT_RETRY_INTERVAL 10 +#define LC_DEFAULT_COUNT_PERSEND 1 +#define LC_DEFAULT_RETRY_CHECKPH1 30 +#define LC_DEFAULT_WAIT_PH2COMPLETE 30 +#define LC_DEFAULT_NATT_KA_INTERVAL 20 + +#define LC_DEFAULT_SECRETSIZE 16 /* 128 bits */ + +#define LC_IDENTTYPE_MAX 5 /* XXX */ + +#define LC_GSSENC_UTF16LE 0 /* GSS ID in UTF-16LE */ +#define LC_GSSENC_LATIN1 1 /* GSS ID in ISO-Latin-1 */ +#define LC_GSSENC_MAX 2 + +#define LC_AUTOEXITSTATE_SET 0x00000001 +#define LC_AUTOEXITSTATE_CLIENT 0x00000010 +#define LC_AUTOEXITSTATE_ENABLED 0x00000011 /* both VPN client and set */ + + +struct vpnctl_socket_elem { + LIST_ENTRY(vpnctl_socket_elem) chain; + int sock; + LIST_HEAD(_bound_addrs, bound_addr) bound_addresses; +}; + +struct bound_addr { + LIST_ENTRY(bound_addr) chain; + u_int32_t address; +}; + +struct redirect { + LIST_ENTRY(redirect) chain; + u_int32_t cluster_address; + u_int32_t redirect_address; + u_int16_t force; +}; + + +struct localconf { + char *racoon_conf; /* configuration filename */ + + uid_t uid; + gid_t gid; + char *chroot; /* chroot path */ + u_int16_t port_isakmp; /* port for isakmp as default */ + u_int16_t port_isakmp_natt; /* port for NAT-T use */ + u_int16_t port_admin; /* port for admin */ + int default_af; /* default address family */ + + int sock_admin; + int sock_vpncontrol; + int sock_pfkey; + int rtsock; /* routing socket */ + LIST_HEAD(_vpnctl_socket_elem_, vpnctl_socket_elem) vpnctl_comm_socks; + LIST_HEAD(_redirect_, redirect) redirect_addresses; + int auto_exit_state; /* auto exit state */ + int auto_exit_delay; /* auto exit delay until exit */ + struct sched *auto_exit_sched; /* auto exit schedule */ + + int autograbaddr; + struct myaddrs *myaddrs; + + char *logfile_param; /* from command line */ + char *pathinfo[LC_PATHTYPE_MAX]; + vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */ + + int pad_random; + int pad_randomlen; + int pad_maxsize; + int pad_strict; + int pad_excltail; + + int retry_counter; /* times to retry. */ + int retry_interval; /* interval each retry. */ + int count_persend; /* the number of packets each retry. */ + /* above 3 values are copied into a handler. */ + + int retry_checkph1; + int wait_ph2complete; + + int natt_ka_interval; /* NAT-T keepalive interval. */ + + int secret_size; + int strict_address; /* strictly check addresses. */ + + int complex_bundle; + /* + * If we want to make a packet "IP2 AH ESP IP1 ULP", + * the SPD in KAME expresses AH transport + ESP tunnel. + * So racoon sent the proposal contained such the order. + * But lots of implementation interprets AH tunnel + ESP + * tunnel in this case. racoon has changed the format, + * usually uses this format. If the option, 'complex_bundle' + * is enable, racoon uses old format. + */ + + int gss_id_enc; /* GSS ID encoding to use */ +}; + +extern struct localconf *lcconf; + +extern void initlcconf __P((void)); +extern void flushlcconf __P((void)); +extern vchar_t *getpskbyname __P((vchar_t *)); +extern vchar_t *getpskbyaddr __P((struct sockaddr *)); +#ifdef __APPLE__ +extern vchar_t *getpskfromkeychain __P((const char *, u_int8_t, int, vchar_t *)); +#endif +extern void getpathname __P((char *, int, int, const char *)); +extern int sittype2doi __P((int)); +extern int doitype2doi __P((int)); +extern vchar_t *getpsk __P((const char *, const int)); + +#endif /* _LOCALCONF_H */ diff --git a/ipsec-tools/racoon/logger.c b/ipsec-tools/racoon/logger.c new file mode 100644 index 0000000..03a3ac6 --- /dev/null +++ b/ipsec-tools/racoon/logger.c @@ -0,0 +1,260 @@ +/* $KAME: logger.c,v 1.9 2002/09/03 14:37:03 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "logger.h" +#include "var.h" +#include "gcmalloc.h" + +struct log * +log_open(siz, fname) + size_t siz; + char *fname; +{ + struct log *p; + + p = (struct log *)racoon_malloc(sizeof(*p)); + if (p == NULL) + return NULL; + memset(p, 0, sizeof(*p)); + + p->buf = (char **)racoon_malloc(sizeof(char *) * siz); + if (p->buf == NULL) { + racoon_free(p); + return NULL; + } + memset(p->buf, 0, sizeof(char *) * siz); + + p->tbuf = (time_t *)racoon_malloc(sizeof(time_t *) * siz); + if (p->tbuf == NULL) { + racoon_free(p->buf); + racoon_free(p); + return NULL; + } + memset(p->tbuf, 0, sizeof(time_t *) * siz); + + p->siz = siz; + if (fname) + p->fname = strdup(fname); + + return p; +} + +/* + * append string to ring buffer. + * string must be \n-terminated (since we add timestamps). + * even if not, we'll add \n to avoid formatting mistake (see log_close()). + */ +void +log_add(p, str) + struct log *p; + char *str; +{ + /* syslog if p->fname == NULL? */ + if (p->buf[p->head]) + racoon_free(p->buf[p->head]); + p->buf[p->head] = strdup(str); + p->tbuf[p->head] = time(NULL); + p->head++; + p->head %= p->siz; +} + +/* + * write out string to the log file, as is. + * \n-termination is up to the caller. if you don't add \n, the file + * format may be broken. + */ +int +log_print(p, str) + struct log *p; + char *str; +{ + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + fprintf(fp, "%s", str); + fclose(fp); + + return 0; +} + +int +log_vprint(struct log *p, const char *fmt, ...) +{ + va_list ap; + + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + fclose(fp); + + return 0; +} + +int +log_vaprint(struct log *p, const char *fmt, va_list ap) +{ + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + vfprintf(fp, fmt, ap); + fclose(fp); + + return 0; +} + +/* + * write out content of ring buffer, and reclaim the log structure + */ +int +log_close(p) + struct log *p; +{ + FILE *fp; + int i, j; + char ts[256]; + struct tm *tm; + + if (p->fname == NULL) + goto nowrite; + fp = fopen(p->fname, "a"); + if (fp == NULL) + goto nowrite; + + for (i = 0; i < p->siz; i++) { + j = (p->head + i) % p->siz; + if (p->buf[j]) { + tm = localtime(&p->tbuf[j]); + strftime(ts, sizeof(ts), "%B %d %T", tm); + fprintf(fp, "%s: %s\n", ts, p->buf[j]); + if (*(p->buf[j] + strlen(p->buf[j]) - 1) != '\n') + fprintf(fp, "\n"); + } + } + fclose(fp); + +nowrite: + log_free(p); + return 0; +} + +void +log_free(p) + struct log *p; +{ + int i; + + for (i = 0; i < p->siz; i++) + racoon_free(p->buf[i]); + racoon_free(p->buf); + racoon_free(p->tbuf); + if (p->fname) + racoon_free(p->fname); + racoon_free(p); +} + +#ifdef TEST +struct log *l; + +void +vatest(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + log_vaprint(l, fmt, ap); + va_end(ap); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + int i; + + l = log_open(30, "/tmp/hoge"); + if (l == NULL) + errx(1, "hoge"); + + for (i = 0; i < 50; i++) { + log_add(l, "foo"); + log_add(l, "baa"); + log_add(l, "baz"); + } + log_print(l, "hoge\n"); + log_vprint(l, "hoge %s\n", "this is test"); + vatest("%s %s\n", "this is", "vprint test"); + abort(); + log_free(l); +} + +#endif + diff --git a/ipsec-tools/racoon/logger.h b/ipsec-tools/racoon/logger.h new file mode 100644 index 0000000..a5bfb3f --- /dev/null +++ b/ipsec-tools/racoon/logger.h @@ -0,0 +1,51 @@ +/* $Id: logger.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LOGGER_H +#define _LOGGER_H + +struct log { + int head; + int siz; + char **buf; + time_t *tbuf; + char *fname; +}; + +extern struct log *log_open __P((size_t, char *)); +extern void log_add __P((struct log *, char *)); +extern int log_print __P((struct log *, char *)); +extern int log_vprint __P((struct log *, const char *, ...)); +extern int log_vaprint __P((struct log *, const char *, va_list)); +extern int log_close __P((struct log *)); +extern void log_free __P((struct log *)); + +#endif /* _LOGGER_H */ diff --git a/ipsec-tools/racoon/main.c b/ipsec-tools/racoon/main.c new file mode 100644 index 0000000..f325c90 --- /dev/null +++ b/ipsec-tools/racoon/main.c @@ -0,0 +1,469 @@ +/* $Id: main.c,v 1.14.2.3 2005/11/06 17:18:26 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +/* + * If we're using a debugging malloc library, this may define our + * wrapper stubs. + */ +#define RACOON_MAIN_PROGRAM +#include "gcmalloc.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "cfparse_proto.h" +#include "isakmp_var.h" +#ifdef HAVE_LIBRADIUS +#include "isakmp.h" +#include "isakmp_xauth.h" +#endif +#include "remoteconf.h" +#include "localconf.h" +#include "session.h" +#include "oakley.h" +#include "pfkey.h" +#include "crypto_openssl.h" +#include "backupsa.h" +#include "vendorid.h" + +//#include "package_version.h" + +int f_local = 0; /* local test mode. behave like a wall. */ +int vflag = 1; /* for print-isakmp.c */ +static int loading_sa = 0; /* install sa when racoon boots up. */ +static int dump_config = 0; /* dump parsed config file. */ +static int exec_done = 0; /* we've already been exec'd */ + +#ifdef TOP_PACKAGE +static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")"; +#else /* TOP_PACKAGE */ +static char version[] = "@(#) racoon / IPsec-tools"; +#endif /* TOP_PACKAGE */ + +int main __P((int, char **)); +static void usage __P((void)); +static void parse __P((int, char **)); +static void restore_params __P((void)); +static void save_params __P((void)); +static void saverestore_params __P((int)); +static void cleanup_pidfile __P((void)); + +pid_t racoon_pid = 0; +int print_pid = 1; /* for racoon only */ + +void +usage() +{ + printf("usage: racoon [-BdFve%s] %s[-f (file)] [-l (file)] [-p (port)]\n", +#ifdef INET6 + "46", +#else + "", +#endif +#ifdef ENABLE_ADMINPORT + "[-a (port)] " +#else + "" +#endif + ); + printf(" -B: install SA to the kernel from the file " + "specified by the configuration file.\n"); + printf(" -d: debug level, more -d will generate more debug message.\n"); + printf(" -C: dump parsed config file.\n"); + printf(" -L: include location in debug messages\n"); + printf(" -F: run in foreground, do not become daemon.\n"); + printf(" -v: be more verbose\n"); + printf(" -e: enable auto exit\n"); +#ifdef INET6 + printf(" -4: IPv4 mode.\n"); + printf(" -6: IPv6 mode.\n"); +#endif +#ifdef ENABLE_ADMINPORT + printf(" -a: port number for admin port.\n"); +#endif + printf(" -f: pathname for configuration file.\n"); + printf(" -l: pathname for log file.\n"); + printf(" -p: port number for isakmp (default: %d).\n", PORT_ISAKMP); + printf(" -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT); + exit(1); +} + +int +main(ac, av) + int ac; + char **av; +{ + int error; + + if (geteuid() != 0) { + errx(1, "must be root to invoke this program."); + /* NOTREACHED*/ + } + + /* + * Don't let anyone read files I write. Although some files (such as + * the PID file) can be other readable, we dare to use the global mask, + * because racoon uses fopen(3), which can't specify the permission + * at the creation time. + */ + umask(077); + if (umask(077) != 077) { + errx(1, "could not set umask"); + /* NOTREACHED*/ + } + +#ifdef DEBUG_RECORD_MALLOCATION + DRM_init(); +#endif + + eay_init(); + initlcconf(); + initrmconf(); + oakley_dhinit(); + compute_vendorids(); + + parse(ac, av); + if (lcconf->logfile_param) + plogset(lcconf->logfile_param); + ploginit(); + + plog(LLV_INFO, LOCATION, NULL, "***** racoon started: pid=%d started by: %d\n", getpid(), getppid()); + plog(LLV_INFO, LOCATION, NULL, "%s\n", version); + plog(LLV_INFO, LOCATION, NULL, "@(#)" + "This product linked %s (http://www.openssl.org/)" + "\n", eay_version()); + + if (pfkey_init() < 0) { + errx(1, "something error happened " + "while pfkey initializing."); + /* NOTREACHED*/ + } + + /* + * in order to prefer the parameters by command line, + * saving some parameters before parsing configuration file. + */ + save_params(); + error = cfparse(); + if (error != 0) + errx(1, "failed to parse configuration file."); + restore_params(); + if (lcconf->logfile_param == NULL) + plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); + +#ifdef ENABLE_NATT + /* Tell the kernel which port to use for UDP encapsulation */ + { + int udp_port = PORT_ISAKMP_NATT; + if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &udp_port, sizeof(udp_port)) != 0) + errx(1, "couldn't set net.inet.ipsec.esp_port to %d. (%s)", + udp_port, strerror(errno)); + } +#endif + +#ifdef HAVE_LIBRADIUS + if (xauth_radius_init() != 0) { + errx(1, "could not initialize libradius"); + /* NOTREACHED*/ + } +#endif + + if (dump_config) + dumprmconf (); + + /* + * install SAs from the specified file. If the file is not specified + * by the configuration file, racoon will exit. + */ + if (loading_sa && !f_local) { + if (backupsa_from_file() != 0) + errx(1, "something error happened " + "SA recovering."); + } + + if (f_foreground) + close(0); + else if (exec_done) { + if (atexit(cleanup_pidfile) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot register pidfile cleanup"); + } + } else { + #define MAX_EXEC_ARGS 32 + + char *args[MAX_EXEC_ARGS + 1]; + char *env[1] = {0}; + int i; + + if (ac > MAX_EXEC_ARGS) { + plog(LLV_ERROR, LOCATION, NULL, + "too many arguments.\n"); + exit(1); + } + + if (daemon(0, 0) < 0) { + errx(1, "failed to be daemon. (%s)", + strerror(errno)); + } + + /* Radar 5129006 - Prevent non-root user from killing racoon + * when launched by setuid process + */ + if (setuid(0)) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot set uid.\n"); + exit(1); + } + if (setgid(0)) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot set gid.\n"); + exit(1); + } + + /* setup args to re-exec - for CoreFoundation issues */ + args[0] = PATHRACOON; + for (i = 1; i < ac; i++) + args[i] = *(av + i); + args[ac] = "-x"; /* tells racoon its been exec'd */ + args[ac+1] = 0; + + execve(PATHRACOON, args, env); + plog(LLV_ERROR, LOCATION, NULL, + "failed to exec racoon. (%s)", strerror(errno)); + exit(1); + } + + session(); + + exit(0); +} + + +static void +cleanup_pidfile() +{ + char pid_file[MAXPATHLEN]; + pid_t p = getpid(); + + /* if it's not child process, clean everything */ + if (racoon_pid == p) { + if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) + strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN); + else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') + strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + else { + strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN); + strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + } + (void) unlink(pid_file); + } +} + + +static void +parse(ac, av) + int ac; + char **av; +{ + extern char *optarg; + extern int optind; + int c; +#ifdef YYDEBUG + extern int yydebug; +#endif + + pname = strrchr(*av, '/'); + if (pname) + pname++; + else + pname = *av; + +#if 0 /* for debugging */ + loglevel += 2; + plogset("/tmp/racoon.log"); +#endif + + while ((c = getopt(ac, av, "dLFp:P:a:f:l:veZBCx" +#ifdef YYDEBUG + "y" +#endif +#ifdef INET6 + "46" +#endif + )) != -1) { + switch (c) { + case 'd': + loglevel++; + break; + case 'L': + print_location = 1; + break; + case 'F': + printf("Foreground mode.\n"); + f_foreground = 1; + break; + case 'p': + lcconf->port_isakmp = atoi(optarg); + break; + case 'P': + lcconf->port_isakmp_natt = atoi(optarg); + break; + case 'a': +#ifdef ENABLE_ADMINPORT + lcconf->port_admin = atoi(optarg); + break; +#else + fprintf(stderr, "%s: the option is disabled " + "in the configuration\n", pname); + exit(1); +#endif + case 'f': + lcconf->racoon_conf = optarg; + break; + case 'l': + lcconf->logfile_param = optarg; + break; + case 'v': + vflag++; + break; + case 'e': + lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; + break; + case 'x': + exec_done = 1; + break; + case 'Z': + /* + * only local test. + * To specify -Z option and to choice a appropriate + * port number for ISAKMP, you can launch some racoons + * on the local host for debug. + * pk_sendadd() on initiator side is always failed + * even if this flag is used. Because there is same + * spi in the SAD which is inserted by pk_sendgetspi() + * on responder side. + */ + printf("Local test mode.\n"); + f_local = 1; + break; +#ifdef YYDEBUG + case 'y': + yydebug = 1; + break; +#endif +#ifdef INET6 + case '4': + lcconf->default_af = AF_INET; + break; + case '6': + lcconf->default_af = AF_INET6; + break; +#endif + case 'B': + loading_sa++; + break; + case 'C': + dump_config++; + break; + default: + usage(); + /* NOTREACHED */ + } + } + ac -= optind; + av += optind; + + if (ac != 0) { + usage(); + /* NOTREACHED */ + } + + return; +} + +static void +restore_params() +{ + saverestore_params(1); +} + +static void +save_params() +{ + saverestore_params(0); +} + +static void +saverestore_params(f) + int f; +{ + static u_int16_t s_port_isakmp; +#ifdef ENABLE_ADMINPORT + static u_int16_t s_port_admin; +#endif + + /* 0: save, 1: restore */ + if (f) { + lcconf->port_isakmp = s_port_isakmp; +#ifdef ENABLE_ADMINPORT + lcconf->port_admin = s_port_admin; +#endif + } else { + s_port_isakmp = lcconf->port_isakmp; +#ifdef ENABLE_ADMINPORT + s_port_admin = lcconf->port_admin; +#endif + } +} diff --git a/ipsec-tools/racoon/misc.c b/ipsec-tools/racoon/misc.c new file mode 100644 index 0000000..07e5390 --- /dev/null +++ b/ipsec-tools/racoon/misc.c @@ -0,0 +1,169 @@ +/* $KAME: misc.c,v 1.23 2001/08/16 14:37:29 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "debug.h" + +#if 0 +static int bindump __P((void *, size_t)); + +static int +bindump(buf0, len) + void *buf0; + size_t len; +{ + unsigned char *buf = (unsigned char *)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if ((buf[i] & 0x80) || !isprint(buf[i])) + printf("\\x%x", buf[i]); + else + printf("%c", buf[i]); + } + printf("\n"); + + return 0; +} +#endif + +int +hexdump(buf0, len) + void *buf0; + size_t len; +{ + caddr_t buf = (caddr_t)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + printf("\n"); + + return 0; +} + +char * +bit2str(n, bl) + int n, bl; +{ +#define MAXBITLEN 128 + static char b[MAXBITLEN + 1]; + int i; + + if (bl > MAXBITLEN) + return "Failed to convert."; /* NG */ + memset(b, '0', bl); + b[bl] = '\0'; + + for (i = 0; i < bl; i++) { + if (n & (1 << i)) + b[bl - 1 - i] = '1'; + } + + return b; +} + +const char * +debug_location(file, line, func) + const char *file; + int line; + const char *func; +{ + static char buf[1024]; + const char *p; + + /* truncate pathname */ + p = strrchr(file, '/'); + if (p) + p++; + else + p = file; + + if (func) + snprintf(buf, sizeof(buf), "%s:%d:%s()", p, line, func); + else + snprintf(buf, sizeof(buf), "%s:%d", p, line); + + return buf; +} + +/* + * get file size. + * -1: error occured. + */ +int +getfsize(path) + char *path; +{ + struct stat st; + + if (stat(path, &st) != 0) + return -1; + else + return st.st_size; +} + +/* + * calculate the difference between two times. + * t1: start + * t2: end + */ +double +timedelta(t1, t2) + struct timeval *t1, *t2; +{ + if (t2->tv_usec >= t1->tv_usec) + return t2->tv_sec - t1->tv_sec + + (double)(t2->tv_usec - t1->tv_usec) / 1000000; + + return t2->tv_sec - t1->tv_sec - 1 + + (double)(1000000 + t2->tv_usec - t1->tv_usec) / 1000000; +} diff --git a/ipsec-tools/racoon/misc.h b/ipsec-tools/racoon/misc.h new file mode 100644 index 0000000..8f90cc9 --- /dev/null +++ b/ipsec-tools/racoon/misc.h @@ -0,0 +1,61 @@ +/* $Id: misc.h,v 1.6.10.1 2005/11/06 17:18:26 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MISC_H +#define _MISC_H + +#define BIT2STR(b) bit2str(b, sizeof(b)<<3) + +#ifdef HAVE_FUNC_MACRO +#define LOCATION debug_location(__FILE__, __LINE__, __func__) +#else +#define LOCATION debug_location(__FILE__, __LINE__, NULL) +#endif + +extern int hexdump __P((void *, size_t)); +extern char *bit2str __P((int, int)); +extern void *get_newbuf __P((void *, size_t)); +extern const char *debug_location __P((const char *, int, const char *)); +extern int getfsize __P((char *)); +struct timeval; +extern double timedelta __P((struct timeval *, struct timeval *)); + +#ifndef HAVE_STRLCPY +#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0') +#endif + +#ifndef HAVE_STRLCAT +#define strlcat(d,s,l) strncat(d,s,(l)-strlen(d)-1) +#endif + +#include "libpfkey.h" + +#endif /* _MISC_H */ diff --git a/ipsec-tools/racoon/nattraversal.c b/ipsec-tools/racoon/nattraversal.c new file mode 100644 index 0000000..a9c02b1 --- /dev/null +++ b/ipsec-tools/racoon/nattraversal.c @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include + +#ifdef __linux__ +#include +#endif +#if defined(__NetBSD__) || defined (__FreeBSD__) +#include +#endif + +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "sockmisc.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "ipsec_doi.h" +#include "vendorid.h" +#include "handler.h" +#include "crypto_openssl.h" +#include "schedule.h" +#include "nattraversal.h" +#include "grabmyaddr.h" + +struct natt_ka_addrs { + struct sockaddr *src; + struct sockaddr *dst; + unsigned in_use; + + TAILQ_ENTRY(natt_ka_addrs) chain; +}; + +static TAILQ_HEAD(_natt_ka_addrs, natt_ka_addrs) ka_tree; + +/* + * check if the given vid is NAT-T. + */ +int +natt_vendorid (int vid) +{ + return ( +#ifdef ENABLE_NATT_00 + vid == VENDORID_NATT_00 || +#endif +#ifdef ENABLE_NATT_01 + vid == VENDORID_NATT_01 || +#endif +#ifdef ENABLE_NATT_02 + vid == VENDORID_NATT_02 || + vid == VENDORID_NATT_02_N || +#endif +#ifdef ENABLE_NATT_03 + vid == VENDORID_NATT_03 || +#endif +#ifdef ENABLE_NATT_04 + vid == VENDORID_NATT_04 || +#endif +#ifdef ENABLE_NATT_05 + vid == VENDORID_NATT_05 || +#endif +#ifdef ENABLE_NATT_06 + vid == VENDORID_NATT_06 || +#endif +#ifdef ENABLE_NATT_07 + vid == VENDORID_NATT_07 || +#endif +#ifdef ENABLE_NATT_08 + vid == VENDORID_NATT_08 || +#endif +#ifdef ENABLE_NATT_APPLE + vid == VENDORID_NATT_APPLE || +#endif + /* Always enable NATT RFC if ENABLE_NATT + */ + vid == VENDORID_NATT_RFC); +} + +vchar_t * +natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr) +{ + vchar_t *natd; + vchar_t *buf; + char *ptr; + void *addr_ptr, *addr_port; + size_t buf_size, addr_size; + + plog (LLV_INFO, LOCATION, addr, "Hashing %s with algo #%d %s\n", + saddr2str(addr), iph1->approval->hashtype, + (iph1->rmconf->nat_traversal == NATT_FORCE)?"(NAT-T forced)":""); + + if (addr->sa_family == AF_INET) { + addr_size = sizeof (struct in_addr); /* IPv4 address */ + addr_ptr = &((struct sockaddr_in *)addr)->sin_addr; + addr_port = &((struct sockaddr_in *)addr)->sin_port; + } + else if (addr->sa_family == AF_INET6) { + addr_size = sizeof (struct in6_addr); /* IPv6 address */ + addr_ptr = &((struct sockaddr_in6 *)addr)->sin6_addr; + addr_port = &((struct sockaddr_in6 *)addr)->sin6_port; + } + else { + plog (LLV_ERROR, LOCATION, addr, "Unsupported address family #0x%x\n", addr->sa_family); + return NULL; + } + + buf_size = 2 * sizeof (cookie_t); /* CKY-I + CKY+R */ + buf_size += addr_size + 2; /* Address + Port */ + + if ((buf = vmalloc (buf_size)) == NULL) + return NULL; + + ptr = buf->v; + + /* Copy-in CKY-I */ + memcpy (ptr, iph1->index.i_ck, sizeof (cookie_t)); + ptr += sizeof (cookie_t); + + /* Copy-in CKY-I */ + memcpy (ptr, iph1->index.r_ck, sizeof (cookie_t)); + ptr += sizeof (cookie_t); + + /* Copy-in Address (or zeroes if NATT_FORCE) */ + if (iph1->rmconf->nat_traversal == NATT_FORCE) + memset (ptr, 0, addr_size); + else + memcpy (ptr, addr_ptr, addr_size); + ptr += addr_size; + + /* Copy-in Port number */ + memcpy (ptr, addr_port, 2); + + natd = oakley_hash (buf, iph1); + vfree(buf); + + return natd; +} + +int +natt_compare_addr_hash (struct ph1handle *iph1, vchar_t *natd_received, + int natd_seq) +{ + vchar_t *natd_computed; + u_int32_t flag; + int verified = 0; + + if (iph1->rmconf->nat_traversal == NATT_FORCE) + return verified; + +#ifdef __APPLE__ + /* old APPLE version sends natd payload in the wrong order */ + if (iph1->natt_options->version == VENDORID_NATT_APPLE) { + if (natd_seq == 0) { + natd_computed = natt_hash_addr (iph1, iph1->remote); + flag = NAT_DETECTED_PEER; + } + else { + natd_computed = natt_hash_addr (iph1, iph1->local); + flag = NAT_DETECTED_ME; + } + } else +#endif + { + if (natd_seq == 0) { + natd_computed = natt_hash_addr (iph1, iph1->local); + flag = NAT_DETECTED_ME; + } + else { + natd_computed = natt_hash_addr (iph1, iph1->remote); + flag = NAT_DETECTED_PEER; + } + } + + if (natd_received->l == natd_computed->l && + memcmp (natd_received->v, natd_computed->v, natd_received->l) == 0) { + iph1->natt_flags &= ~flag; + verified = 1; + } + + vfree (natd_computed); + + return verified; +} + +int +natt_udp_encap (int encmode) +{ + return (encmode == IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC || + encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC || + encmode == IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT || + encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT); +} + +int +natt_fill_options (struct ph1natt_options *opts, int version) +{ + if (! opts) + return -1; + + opts->version = version; + + switch (version) { +#ifndef __APPLE__ + case VENDORID_NATT_00: + case VENDORID_NATT_01: + opts->float_port = 0; /* No port floating for those drafts */ + opts->payload_nat_d = ISAKMP_NPTYPE_NATD_DRAFT; + opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_DRAFT; + opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT; + opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT; + opts->encaps_type = UDP_ENCAP_ESPINUDP_NON_IKE; + break; +#endif + + case VENDORID_NATT_02: + case VENDORID_NATT_02_N: + case VENDORID_NATT_03: + opts->float_port = lcconf->port_isakmp_natt; + opts->payload_nat_d = ISAKMP_NPTYPE_NATD_DRAFT; + opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_DRAFT; + opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT; + opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT; + opts->encaps_type = UDP_ENCAP_ESPINUDP; + break; + case VENDORID_NATT_04: + case VENDORID_NATT_05: + case VENDORID_NATT_06: + case VENDORID_NATT_07: + case VENDORID_NATT_08: +#ifdef __APPLE__ + case VENDORID_NATT_APPLE: + opts->float_port = lcconf->port_isakmp_natt; + opts->payload_nat_d = ISAKMP_NPTYPE_NATD_BADDRAFT; + opts->payload_nat_oa = ISAKMP_NPTYPE_NONE; + opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC; + opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC; + opts->encaps_type = UDP_ENCAP_ESPINUDP; + break; +#endif + case VENDORID_NATT_RFC: + opts->float_port = lcconf->port_isakmp_natt; + opts->payload_nat_d = ISAKMP_NPTYPE_NATD_RFC; + opts->payload_nat_oa = ISAKMP_NPTYPE_NATOA_RFC; + opts->mode_udp_tunnel = IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC; + opts->mode_udp_transport = IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC; + opts->encaps_type = UDP_ENCAP_ESPINUDP; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported NAT-T version: %s\n", + vid_string_by_id(version)); + return -1; + } + + opts->mode_udp_diff = opts->mode_udp_tunnel - IPSECDOI_ATTR_ENC_MODE_TUNNEL; + + return 0; +} + +#ifdef NOT_NOW +static int +create_natoa_payloads(struct ph2handle *iph2, vchar_t **natoa_i, vchar_t **natoa_r) +{ + int natoa_type = 0; + int natt_type; + vchar_t *i; + vchar_t *r; + u_int8_t *p; + size_t src_size; + size_t dst_size; + + *natoa_i = *natoa_r = NULL; + + + /* create natoa payloads if natt being used */ + /* don't send if type == apple */ + if ((natt_type = natd_hasnat(iph2->ph1)) != 0) + if (natt_type == natt_type_rfc) + natoa_type = ISAKMP_NPTYPE_NATOA_RFC; + else if (natt_type == natt_type_02 || natt_type == natt_type_02N) + natoa_type = ISAKMP_NPTYPE_NATOA_DRAFT; + + if (natoa_type == 0) + return 0; + + switch (iph2->src->sa_family) { + case AF_INET: + src_size = sizeof(in_addr_t); + break; +#ifdef INET6 + case AF_INET6: + src_size = sizeof(struct in6_addr); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid address family: %d\n", iph2->src->sa_family); + return -1; + } + + switch (iph2->dst->sa_family) { + case AF_INET: + dst_size = sizeof(in_addr_t); + break; +#ifdef INET6 + case AF_INET6: + dst_size = sizeof(struct in6_addr); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid address family: %d\n", iph2->dst->sa_family); + return -1; + } + + i = vmalloc(sizeof(struct isakmp_pl_natoa) + src_size - sizeof(struct isakmp_gen)); + r = vmalloc(sizeof(struct isakmp_pl_natoa) + dst_size - sizeof(struct isakmp_gen)); + if (i == NULL || r == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for natoa payload.\n"); + return -1; + } + + /* copy src address */ + p = i->v; + + switch (iph2->src->sa_family) { + case AF_INET: + *p = IPSECDOI_ID_IPV4_ADDR; + bcopy(&(((struct sockaddr_in *)iph2->src)->sin_addr.s_addr), p + sizeof(u_int32_t), src_size); + break; +#ifdef INET6 + case AF_INET6: + *p = IPSECDOI_ID_IPV6_ADDR; + bcopy(&(((struct sockaddr_in6 *)iph2->src)->sin6_addr), p + sizeof(u_int32_t), src_size); + break; +#endif + } + + /* copy dst address */ + p = r->v; + + switch (iph2->dst->sa_family) { + case AF_INET: + *p = IPSECDOI_ID_IPV4_ADDR; + bcopy(&(((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr), p + sizeof(u_int32_t), dst_size); + break; +#ifdef INET6 + case AF_INET6: + *p = IPSECDOI_ID_IPV6_ADDR; + bcopy(&(((struct sockaddr_in6 *)iph2->dst)->sin6_addr), p + sizeof(u_int32_t), dst_size); + break; +#endif + } + + *natoa_i = i; + *natoa_r = r; + return natoa_type; +} +#endif + + +void +natt_float_ports (struct ph1handle *iph1) +{ + + if (! (iph1->natt_flags && NAT_DETECTED) ) + return; + if (! iph1->natt_options->float_port){ + /* Drafts 00 / 01, just schedule keepalive */ +#ifndef __APPLE__ + natt_keepalive_add_ph1 (iph1); +#endif + return; + } + + /* + * Only switch ports if port == isakmp port. + * In the case where ports are set from policy or from + * remote config we could be talking to a device behind + * a nat using the translated port. + */ + if (*get_port_ptr(iph1->local) == htons(lcconf->port_isakmp)) + set_port (iph1->local, iph1->natt_options->float_port); + if (*get_port_ptr(iph1->remote) == htons(lcconf->port_isakmp)) + set_port (iph1->remote, iph1->natt_options->float_port); + iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER; + + +#ifndef __APPLE__ + natt_keepalive_add_ph1 (iph1); +#endif +} + +void +natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric) +{ + if (! iph1->natt_options) + iph1->natt_options = racoon_calloc (1, sizeof (*iph1->natt_options)); + + if (! iph1->natt_options) { + plog (LLV_ERROR, LOCATION, NULL, + "Allocating memory for natt_options failed!\n"); + return; + } + + if (iph1->natt_options->version < vid_numeric) + if (natt_fill_options (iph1->natt_options, vid_numeric) == 0) + iph1->natt_flags |= NAT_ANNOUNCED; +} + +#ifndef __APPLE__ +/* NAT keepalive functions */ +static void +natt_keepalive_send (void *param) +{ + struct natt_ka_addrs *ka, *next = NULL; + char keepalive_packet[] = { 0xff }; + size_t len; + int s; + + for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) { + next = TAILQ_NEXT(ka, chain); + + s = getsockmyaddr(ka->src); + if (s == -1) { + TAILQ_REMOVE (&ka_tree, ka, chain); + racoon_free (ka); + continue; + } + plog (LLV_DEBUG, LOCATION, NULL, "KA: %s\n", + saddr2str_fromto("%s->%s", ka->src, ka->dst)); + len = sendfromto(s, keepalive_packet, sizeof (keepalive_packet), + ka->src, ka->dst, 1); + if (len == -1) + plog(LLV_ERROR, LOCATION, NULL, "KA: sendfromto failed: %s\n", + strerror (errno)); + } + + sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL); +} + +void +natt_keepalive_init (void) +{ + TAILQ_INIT(&ka_tree); + + /* To disable sending KAs set natt_ka_interval=0 */ + if (lcconf->natt_ka_interval > 0) + sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL); +} + +int +natt_keepalive_add (struct sockaddr *src, struct sockaddr *dst) +{ + struct natt_ka_addrs *ka = NULL, *new_addr; + + TAILQ_FOREACH (ka, &ka_tree, chain) { + if (cmpsaddrstrict(ka->src, src) == 0 && + cmpsaddrstrict(ka->dst, dst) == 0) { + ka->in_use++; + plog (LLV_INFO, LOCATION, NULL, "KA found: %s (in_use=%u)\n", + saddr2str_fromto("%s->%s", src, dst), ka->in_use); + return 0; + } + } + + plog (LLV_INFO, LOCATION, NULL, "KA list add: %s\n", saddr2str_fromto("%s->%s", src, dst)); + + new_addr = (struct natt_ka_addrs *)racoon_malloc(sizeof(*new_addr)); + if (! new_addr) { + plog (LLV_ERROR, LOCATION, NULL, "Can't allocate new KA list item\n"); + return -1; + } + + new_addr->src = dupsaddr(src); + new_addr->dst = dupsaddr(dst); + new_addr->in_use = 1; + TAILQ_INSERT_TAIL(&ka_tree, new_addr, chain); + + return 0; +} + +int +natt_keepalive_add_ph1 (struct ph1handle *iph1) +{ + int ret = 0; + + /* Should only the NATed host send keepalives? + If yes, add '(iph1->natt_flags & NAT_DETECTED_ME)' + to the following condition. */ + if (iph1->natt_flags & NAT_DETECTED && + ! (iph1->natt_flags & NAT_KA_QUEUED)) { + ret = natt_keepalive_add (iph1->local, iph1->remote); + if (ret == 0) + iph1->natt_flags |= NAT_KA_QUEUED; + } + + return ret; +} + +void +natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst) +{ + struct natt_ka_addrs *ka, *next = NULL; + + plog (LLV_INFO, LOCATION, NULL, "KA remove: %s\n", saddr2str_fromto("%s->%s", src, dst)); + + for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) { + next = TAILQ_NEXT(ka, chain); + + plog (LLV_DEBUG, LOCATION, NULL, "KA tree dump: %s (in_use=%u)\n", + saddr2str_fromto("%s->%s", src, dst), ka->in_use); + + if (cmpsaddrstrict(ka->src, src) == 0 && + cmpsaddrstrict(ka->dst, dst) == 0 && + -- ka->in_use <= 0) { + + plog (LLV_DEBUG, LOCATION, NULL, "KA removing this one...\n"); + + TAILQ_REMOVE (&ka_tree, ka, chain); + racoon_free (ka); + /* Should we break here? Every pair of addresses should + be inserted only once, but who knows :-) Lets traverse + the whole list... */ + } + } +} +#endif /* __APPLE__ */ + +static struct remoteconf * +natt_enabled_in_rmconf_stub (struct remoteconf *rmconf, void *data) +{ + return (rmconf->nat_traversal ? rmconf : NULL); +} + +int +natt_enabled_in_rmconf () +{ + return foreachrmconf (natt_enabled_in_rmconf_stub, NULL) != NULL; +} + + +struct payload_list * +isakmp_plist_append_natt_vids (struct payload_list *plist, vchar_t *vid_natt[MAX_NATT_VID_COUNT]){ + int i, vid_natt_i = 0; + + if(vid_natt == NULL) + return NULL; + + for (i = 0; i < MAX_NATT_VID_COUNT; i++) + vid_natt[i]=NULL; + + /* Puts the olders VIDs last, as some implementations may choose the first + * NATT VID given + */ + + /* Always set RFC VID + */ + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_RFC)) != NULL) + vid_natt_i++; +#ifdef ENABLE_NATT_APPLE + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_APPLE)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_08 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_08)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_07 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_07)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_06 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_06)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_05 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_05)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_04 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_04)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_03 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_03)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_02 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02)) != NULL) + vid_natt_i++; + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_02_N)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_01 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_01)) != NULL) + vid_natt_i++; +#endif +#ifdef ENABLE_NATT_00 + if ((vid_natt[vid_natt_i] = set_vendorid(VENDORID_NATT_00)) != NULL) + vid_natt_i++; +#endif + /* set VID payload for NAT-T */ + for (i = 0; i < vid_natt_i; i++) + plist = isakmp_plist_append(plist, vid_natt[i], ISAKMP_NPTYPE_VID); + + return plist; +} diff --git a/ipsec-tools/racoon/nattraversal.h b/ipsec-tools/racoon/nattraversal.h new file mode 100644 index 0000000..f03c76c --- /dev/null +++ b/ipsec-tools/racoon/nattraversal.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , SUSE Labs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NATTRAVERSAL_H +#define _NATTRAVERSAL_H + +#include "vendorid.h" + +#ifdef __APPLE__ +#define UDP_ENCAP_ESPINUDP 2 /* to make it compile - we don't use this */ +#endif + +#define NAT_ANNOUNCED (1L<<0) +#define NAT_DETECTED_ME (1L<<1) +#define NAT_DETECTED_PEER (1L<<2) +#define NAT_PORTS_CHANGED (1L<<3) +#define NAT_KA_QUEUED (1L<<4) +#define NAT_ADD_NON_ESP_MARKER (1L<<5) + +#define NATT_AVAILABLE(ph1) ((iph1)->natt_flags & NAT_ANNOUNCED) + +#define NAT_DETECTED (NAT_DETECTED_ME | NAT_DETECTED_PEER) + +#define NON_ESP_MARKER_LEN sizeof(u_int32_t) +#define NON_ESP_MARKER_USE(iph1) ((iph1)->natt_flags & NAT_ADD_NON_ESP_MARKER) + +/* These are the values from parsing "remote {}" + block of the config file. */ +#define NATT_OFF FALSE /* = 0 */ +#define NATT_ON TRUE /* = 1 */ +#define NATT_FORCE 2 + +struct ph1natt_options { + int version; + u_int16_t float_port; + u_int16_t mode_udp_tunnel; + u_int16_t mode_udp_transport; + u_int16_t encaps_type; /* ESPINUDP / ESPINUDP_NON_IKE */ + u_int16_t mode_udp_diff; + u_int16_t payload_nat_d; + u_int16_t payload_nat_oa; +}; + +struct ph2natt { + u_int8_t type; + u_int16_t sport; + u_int16_t dport; + struct sockaddr *oa; + u_int16_t frag; +}; + +int natt_vendorid (int vid); +vchar_t *natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr); +int natt_compare_addr_hash (struct ph1handle *iph1, vchar_t *natd_received, int natd_seq); +int natt_udp_encap (int encmode); +int natt_fill_options (struct ph1natt_options *opts, int version); +void natt_float_ports (struct ph1handle *iph1); +void natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric); +#ifdef NOT_NOW +int create_natoa_payloads(struct ph2handle *iph2, vchar_t **, vchar_t **); +#endif + +struct payload_list * +isakmp_plist_append_natt_vids (struct payload_list *plist, vchar_t *vid_natt[MAX_NATT_VID_COUNT]); + +#ifndef __APPLE__ +/* NAT keepalive functions */ +void natt_keepalive_init (void); +int natt_keepalive_add (struct sockaddr *src, struct sockaddr *dst); +int natt_keepalive_add_ph1 (struct ph1handle *iph1); +void natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst); +#endif + +/* Walk through all rmconfigs and tell if NAT-T is enabled in at least one. */ +int natt_enabled_in_rmconf (void); + +#endif /* _NATTRAVERSAL_H */ diff --git a/ipsec-tools/racoon/netdb_dnssec.h b/ipsec-tools/racoon/netdb_dnssec.h new file mode 100644 index 0000000..b83273d --- /dev/null +++ b/ipsec-tools/racoon/netdb_dnssec.h @@ -0,0 +1,72 @@ +/* $Id: netdb_dnssec.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NETDB_DNSSEC_H +#define _NETDB_DNSSEC_H + +#ifndef T_CERT +#define T_CERT 37 /* defined by RFC2538 section 2 */ +#endif + +/* RFC2538 section 2.1 */ +#define DNSSEC_TYPE_PKIX 1 +#define DNSSEC_TYPE_SPKI 2 +#define DNSSEC_TYPE_PGP 3 +#define DNSSEC_TYPE_URI 4 +#define DNSSEC_TYPE_OID 5 + +/* RFC2535 section 3.2 */ +#define DNSSEC_ALG_RSAMD5 1 +#define DNSSEC_ALG_DH 2 +#define DNSSEC_ALG_DSA 3 +#define DNSSEC_ALG_ECC 4 +#define DNSSEC_ALG_PRIVATEDNS 5 +#define DNSSEC_ALG_PRIVATEOID 6 + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct certinfo { + int ci_type; /* certificate type */ + int ci_keytag; /* keytag */ + int ci_algorithm; /* algorithm */ + int ci_flags; /* currently, 1:valid or 0:uncertain */ + size_t ci_certlen; /* length of certificate */ + char *ci_cert; /* certificate */ + struct certinfo *ci_next; /* next structure */ +}; + +extern void freecertinfo __P((struct certinfo *)); +extern int getcertsbyname __P((char *, struct certinfo **)); + +#endif /* _NETDB_DNSSEC_H */ diff --git a/ipsec-tools/racoon/oakley.c b/ipsec-tools/racoon/oakley.c new file mode 100644 index 0000000..1d52885 --- /dev/null +++ b/ipsec-tools/racoon/oakley.c @@ -0,0 +1,3626 @@ +/* $Id: oakley.c,v 1.17.2.5 2005/10/04 09:54:27 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include /* XXX for subjectaltname */ +#include /* XXX for subjectaltname */ + +#include +#include + +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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 +#endif + + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +#define OUTBOUND_SA 0 +#define INBOUND_SA 1 + +#ifdef __APPLE__ +#define CERT_CHECKID_FROM_PEER 0 +#define CERT_CHECKID_FROM_RMCONFIG 1 +#endif + +#define INITDHVAL(a, s, d, t) \ +do { \ + vchar_t buf; \ + buf.v = str2val((s), 16, &buf.l); \ + memset(&a, 0, sizeof(struct dhgroup)); \ + a.type = (t); \ + a.prime = vdup(&buf); \ + a.gen1 = 2; \ + a.gen2 = 0; \ + racoon_free(buf.v); \ +} while(0); + +struct dhgroup dh_modp768; +struct dhgroup dh_modp1024; +struct dhgroup dh_modp1536; +struct dhgroup dh_modp2048; +struct dhgroup dh_modp3072; +struct dhgroup dh_modp4096; +struct dhgroup dh_modp6144; +struct dhgroup dh_modp8192; + + +static int oakley_check_dh_pub __P((vchar_t *, vchar_t **)); +static int oakley_compute_keymat_x __P((struct ph2handle *, int, int)); +static int get_cert_fromlocal __P((struct ph1handle *, int)); +static int get_plainrsa_fromlocal __P((struct ph1handle *, int)); +#ifdef __APPLE__ +static int oakley_check_certid __P((struct ph1handle *iph1, int)); +static int oakley_check_certid_1 __P((struct ph1handle*, int, int, void*)); +#else +static int oakley_check_certid __P((struct ph1handle *iph1)); +#endif +static int check_typeofcertname __P((int, int)); +static cert_t *save_certbuf __P((struct isakmp_gen *)); +static cert_t *save_certx509 __P((X509 *)); +static int oakley_padlen __P((int, int)); + +#ifdef __APPLE__ +static int base64toCFData(vchar_t *, CFDataRef*); +#endif + +int +oakley_get_defaultlifetime() +{ + return OAKLEY_ATTR_SA_LD_SEC_DEFAULT; +} + +int +oakley_dhinit() +{ + /* set DH MODP */ + INITDHVAL(dh_modp768, OAKLEY_PRIME_MODP768, + OAKLEY_ATTR_GRP_DESC_MODP768, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp1024, OAKLEY_PRIME_MODP1024, + OAKLEY_ATTR_GRP_DESC_MODP1024, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp1536, OAKLEY_PRIME_MODP1536, + OAKLEY_ATTR_GRP_DESC_MODP1536, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp2048, OAKLEY_PRIME_MODP2048, + OAKLEY_ATTR_GRP_DESC_MODP2048, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp3072, OAKLEY_PRIME_MODP3072, + OAKLEY_ATTR_GRP_DESC_MODP3072, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp4096, OAKLEY_PRIME_MODP4096, + OAKLEY_ATTR_GRP_DESC_MODP4096, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp6144, OAKLEY_PRIME_MODP6144, + OAKLEY_ATTR_GRP_DESC_MODP6144, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp8192, OAKLEY_PRIME_MODP8192, + OAKLEY_ATTR_GRP_DESC_MODP8192, OAKLEY_ATTR_GRP_TYPE_MODP); + + return 0; +} + +void +oakley_dhgrp_free(dhgrp) + struct dhgroup *dhgrp; +{ + if (dhgrp->prime) + vfree(dhgrp->prime); + if (dhgrp->curve_a) + vfree(dhgrp->curve_a); + if (dhgrp->curve_b) + vfree(dhgrp->curve_b); + if (dhgrp->order) + vfree(dhgrp->order); + racoon_free(dhgrp); +} + +/* + * RFC2409 5 + * The length of the Diffie-Hellman public value MUST be equal to the + * length of the prime modulus over which the exponentiation was + * performed, prepending zero bits to the value if necessary. + */ +static int +oakley_check_dh_pub(prime, pub0) + vchar_t *prime, **pub0; +{ + vchar_t *tmp; + vchar_t *pub = *pub0; + + if (prime->l == pub->l) + return 0; + + if (prime->l < pub->l) { + /* what should i do ? */ + plog(LLV_ERROR, LOCATION, NULL, + "invalid public information was generated.\n"); + return -1; + } + + /* prime->l > pub->l */ + tmp = vmalloc(prime->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get DH buffer.\n"); + return -1; + } + memcpy(tmp->v + prime->l - pub->l, pub->v, pub->l); + + vfree(*pub0); + *pub0 = tmp; + + return 0; +} + +/* + * compute sharing secret of DH + * IN: *dh, *pub, *priv, *pub_p + * OUT: **gxy + */ +int +oakley_dh_compute(dh, pub, priv, pub_p, gxy) + const struct dhgroup *dh; + vchar_t *pub, *priv, *pub_p, **gxy; +{ +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + if ((*gxy = vmalloc(dh->prime->l)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get DH buffer.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + if (eay_dh_compute(dh->prime, dh->gen1, pub, priv, pub_p, gxy) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to compute dh value.\n"); + return -1; + } + break; + case OAKLEY_ATTR_GRP_TYPE_ECP: + case OAKLEY_ATTR_GRP_TYPE_EC2N: + plog(LLV_ERROR, LOCATION, NULL, + "dh type %d isn't supported.\n", dh->type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid dh type %d.\n", dh->type); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's shared.\n"); + plogdump(LLV_DEBUG, (*gxy)->v, (*gxy)->l); + + return 0; +} + +/* + * generate values of DH + * IN: *dh + * OUT: **pub, **priv + */ +int +oakley_dh_generate(dh, pub, priv) + const struct dhgroup *dh; + vchar_t **pub, **priv; +{ +#ifdef ENABLE_STATS + struct timeval start, end; + gettimeofday(&start, NULL); +#endif + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + if (eay_dh_generate(dh->prime, dh->gen1, dh->gen2, pub, priv) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to compute dh value.\n"); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_TYPE_ECP: + case OAKLEY_ATTR_GRP_TYPE_EC2N: + plog(LLV_ERROR, LOCATION, NULL, + "dh type %d isn't supported.\n", dh->type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid dh type %d.\n", dh->type); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + + if (oakley_check_dh_pub(dh->prime, pub) != 0) + return -1; + + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's private.\n"); + plogdump(LLV_DEBUG, (*priv)->v, (*priv)->l); + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's public.\n"); + plogdump(LLV_DEBUG, (*pub)->v, (*pub)->l); + + return 0; +} + +/* + * copy pre-defined dhgroup values. + */ +int +oakley_setdhgroup(group, dhgrp) + int group; + struct dhgroup **dhgrp; +{ + struct dhgroup *g; + + *dhgrp = NULL; /* just make sure, initialize */ + + g = alg_oakley_dhdef_group(group); + if (g == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid DH parameter grp=%d.\n", group); + return -1; + } + + if (!g->type || !g->prime || !g->gen1) { + /* unsuported */ + plog(LLV_ERROR, LOCATION, NULL, + "unsupported DH parameters grp=%d.\n", group); + return -1; + } + + *dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); + if (*dhgrp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get DH buffer.\n"); + return 0; + } + + /* set defined dh vlaues */ + memcpy(*dhgrp, g, sizeof(*g)); + (*dhgrp)->prime = vdup(g->prime); + + return 0; +} + +/* + * PRF + * + * NOTE: we do not support prf with different input/output bitwidth, + * so we do not implement RFC2409 Appendix B (DOORAK-MAC example) in + * oakley_compute_keymat(). If you add support for such prf function, + * modify oakley_compute_keymat() accordingly. + */ +vchar_t * +oakley_prf(key, buf, iph1) + vchar_t *key, *buf; + struct ph1handle *iph1; +{ + vchar_t *res = NULL; + int type; + + if (iph1->approval == NULL) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else + type = iph1->approval->hashtype; + + res = alg_oakley_hmacdef_one(type, key, buf); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hmac algorithm %d.\n", type); + return NULL; + } + + return res; +} + +/* + * hash + */ +vchar_t * +oakley_hash(buf, iph1) + vchar_t *buf; + struct ph1handle *iph1; +{ + vchar_t *res = NULL; + int type; + + if (iph1->approval == NULL) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else + type = iph1->approval->hashtype; + + res = alg_oakley_hashdef_one(type, buf); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hash algorithm %d.\n", type); + return NULL; + } + + return res; +} + +/* + * compute KEYMAT + * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. + */ +int +oakley_compute_keymat(iph2, side) + struct ph2handle *iph2; + int side; +{ + int error = -1; + + /* compute sharing secret of DH when PFS */ + if (iph2->approval->pfs_group && iph2->dhpub_p) { + if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub, + iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0) + goto end; + } + + /* compute keymat */ + if (oakley_compute_keymat_x(iph2, side, INBOUND_SA) < 0 + || oakley_compute_keymat_x(iph2, side, OUTBOUND_SA) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT computed.\n"); + + error = 0; + +end: + return error; +} + +/* + * compute KEYMAT. + * KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b). + * If PFS is desired and KE payloads were exchanged, + * KEYMAT = prf(SKEYID_d, g(qm)^xy | protocol | SPI | Ni_b | Nr_b) + * + * NOTE: we do not support prf with different input/output bitwidth, + * so we do not implement RFC2409 Appendix B (DOORAK-MAC example). + */ +static int +oakley_compute_keymat_x(iph2, side, sa_dir) + struct ph2handle *iph2; + int side; + int sa_dir; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + char *p; + int len; + int error = -1; + int pfs = 0; + int dupkeymat; /* generate K[1-dupkeymat] */ + struct saproto *pr; + struct satrns *tr; + int encklen, authklen, l; + + pfs = ((iph2->approval->pfs_group && iph2->dhgxy) ? 1 : 0); + + len = pfs ? iph2->dhgxy->l : 0; + len += (1 + + sizeof(u_int32_t) /* XXX SPI size */ + + iph2->nonce->l + + iph2->nonce_p->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + goto end; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + p = buf->v; + + /* if PFS */ + if (pfs) { + memcpy(p, iph2->dhgxy->v, iph2->dhgxy->l); + p += iph2->dhgxy->l; + } + + p[0] = pr->proto_id; + p += 1; + + memcpy(p, (sa_dir == INBOUND_SA ? &pr->spi : &pr->spi_p), + sizeof(pr->spi)); + p += sizeof(pr->spi); + + bp = (side == INITIATOR ? iph2->nonce : iph2->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (side == INITIATOR ? iph2->nonce_p : iph2->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + /* compute IV */ + plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT compute with\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* res = K1 */ + res = oakley_prf(iph2->ph1->skeyid_d, buf, iph2->ph1); + if (res == NULL) + goto end; + + /* compute key length needed */ + encklen = authklen = 0; + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + for (tr = pr->head; tr; tr = tr->next) { + l = alg_ipsec_encdef_keylen(tr->trns_id, + tr->encklen); + if (l > encklen) + encklen = l; + + l = alg_ipsec_hmacdef_hashlen(tr->authtype); + if (l > authklen) + authklen = l; + } + break; + case IPSECDOI_PROTO_IPSEC_AH: + for (tr = pr->head; tr; tr = tr->next) { + l = alg_ipsec_hmacdef_hashlen(tr->trns_id); + if (l > authklen) + authklen = l; + } + break; + default: + break; + } + plog(LLV_DEBUG, LOCATION, NULL, "encklen=%d authklen=%d\n", + encklen, authklen); + + dupkeymat = (encklen + authklen) / 8 / res->l; + dupkeymat += 2; /* safety mergin */ + if (dupkeymat < 3) + dupkeymat = 3; + plog(LLV_DEBUG, LOCATION, NULL, + "generating %zu bits of key (dupkeymat=%d)\n", + dupkeymat * 8 * res->l, dupkeymat); + if (0 < --dupkeymat) { + vchar_t *prev = res; /* K(n-1) */ + vchar_t *seed = NULL; /* seed for Kn */ + size_t l; + + /* + * generating long key (isakmp-oakley-08 5.5) + * KEYMAT = K1 | K2 | K3 | ... + * where + * src = [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b + * K1 = prf(SKEYID_d, src) + * K2 = prf(SKEYID_d, K1 | src) + * K3 = prf(SKEYID_d, K2 | src) + * Kn = prf(SKEYID_d, K(n-1) | src) + */ + plog(LLV_DEBUG, LOCATION, NULL, + "generating K1...K%d for KEYMAT.\n", + dupkeymat + 1); + + seed = vmalloc(prev->l + buf->l); + if (seed == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + if (prev && prev != res) + vfree(prev); + goto end; + } + + while (dupkeymat--) { + vchar_t *this = NULL; /* Kn */ + + memcpy(seed->v, prev->v, prev->l); + memcpy(seed->v + prev->l, buf->v, buf->l); + this = oakley_prf(iph2->ph1->skeyid_d, seed, + iph2->ph1); + if (!this) { + plog(LLV_ERROR, LOCATION, NULL, + "oakley_prf memory overflow\n"); + if (prev && prev != res) + vfree(prev); + vfree(this); + vfree(seed); + goto end; + } + + l = res->l; + res = vrealloc(res, l + this->l); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + if (prev && prev != res) + vfree(prev); + vfree(this); + vfree(seed); + goto end; + } + memcpy(res->v + l, this->v, this->l); + + if (prev && prev != res) + vfree(prev); + prev = this; + this = NULL; + } + + if (prev && prev != res) + vfree(prev); + vfree(seed); + } + + plogdump(LLV_DEBUG, res->v, res->l); + + if (sa_dir == INBOUND_SA) + pr->keymat = res; + else + pr->keymat_p = res; + res = NULL; + } + + error = 0; + +end: + if (error) { + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + if (pr->keymat) { + vfree(pr->keymat); + pr->keymat = NULL; + } + if (pr->keymat_p) { + vfree(pr->keymat_p); + pr->keymat_p = NULL; + } + } + } + + if (buf != NULL) + vfree(buf); + if (res) + vfree(res); + + return error; +} + +#if notyet +/* + * NOTE: Must terminate by NULL. + */ +vchar_t * +oakley_compute_hashx(struct ph1handle *iph1, ...) +{ + vchar_t *buf, *res; + vchar_t *s; + caddr_t p; + int len; + + va_list ap; + + /* get buffer length */ + va_start(ap, iph1); + len = 0; + while ((s = va_arg(ap, vchar_t *)) != NULL) { + len += s->l + } + va_end(ap); + + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + return NULL; + } + + /* set buffer */ + va_start(ap, iph1); + p = buf->v; + while ((s = va_arg(ap, char *)) != NULL) { + memcpy(p, s->v, s->l); + p += s->l; + } + va_end(ap); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + vfree(buf); + if (res == NULL) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + + return res; +} +#endif + +/* + * compute HASH(3) prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. + */ +vchar_t * +oakley_compute_hash3(iph1, msgid, body) + struct ph1handle *iph1; + u_int32_t msgid; + vchar_t *body; +{ + vchar_t *buf = 0, *res = 0; + int len; + int error = -1; + + /* create buffer */ + len = 1 + sizeof(u_int32_t) + body->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + buf->v[0] = 0; + + memcpy(buf->v + 1, (char *)&msgid, sizeof(msgid)); + + memcpy(buf->v + 1 + sizeof(u_int32_t), body->v, body->l); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute HASH type of prf(SKEYID_a, M-ID | buffer) + * e.g. + * for quick mode HASH(1): + * prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ]) + * for quick mode HASH(2): + * prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ]) + * for Informational exchange: + * prf(SKEYID_a, M-ID | N/D) + */ +vchar_t * +oakley_compute_hash1(iph1, msgid, body) + struct ph1handle *iph1; + u_int32_t msgid; + vchar_t *body; +{ + vchar_t *buf = NULL, *res = NULL; + char *p; + int len; + int error = -1; + + /* create buffer */ + len = sizeof(u_int32_t) + body->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + p = buf->v; + + memcpy(buf->v, (char *)&msgid, sizeof(msgid)); + p += sizeof(u_int32_t); + + memcpy(p, body->v, body->l); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute phase1 HASH + * main/aggressive + * I-digest = prf(SKEYID, g^i | g^r | CKY-I | CKY-R | SAi_b | ID_i1_b) + * R-digest = prf(SKEYID, g^r | g^i | CKY-R | CKY-I | SAi_b | ID_r1_b) + * for gssapi, also include all GSS tokens, and call gss_wrap on the result + */ +vchar_t * +oakley_ph1hash_common(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + char *p, *bp2; + int len, bl; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstokens = NULL; +#endif + + /* create buffer */ + len = iph1->dhpub->l + + iph1->dhpub_p->l + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (iph1->gi_i != NULL && iph1->gi_r != NULL) { + bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); + len += bp->l; + } + if (sw == GENERATE) + gssapi_get_itokens(iph1, &gsstokens); + else + gssapi_get_rtokens(iph1, &gsstokens); + if (gsstokens == NULL) + return NULL; + len += gsstokens->l; + } +#endif + + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + p = buf->v; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + if (iph1->side == INITIATOR) + bp2 = (sw == GENERATE ? + (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); + else + bp2 = (sw == GENERATE ? + (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); + bl = sizeof(cookie_t); + memcpy(p, bp2, bl); + p += bl; + + if (iph1->side == INITIATOR) + bp2 = (sw == GENERATE ? + (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); + else + bp2 = (sw == GENERATE ? + (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); + bl = sizeof(cookie_t); + memcpy(p, bp2, bl); + p += bl; + + bp = iph1->sa; + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->id : iph1->id_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (iph1->gi_i != NULL && iph1->gi_r != NULL) { + bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); + memcpy(p, bp->v, bp->l); + p += bp->l; + } + memcpy(p, gsstokens->v, gsstokens->l); + p += gsstokens->l; + } +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); +#ifdef HAVE_GSSAPI + if (gsstokens != NULL) + vfree(gsstokens); +#endif + return res; +} + +/* + * compute HASH_I on base mode. + * base:psk,rsa + * HASH_I = prf(SKEYID, g^xi | CKY-I | CKY-R | SAi_b | IDii_b) + * base:sig + * HASH_I = prf(hash(Ni_b | Nr_b), g^xi | CKY-I | CKY-R | SAi_b | IDii_b) + */ +vchar_t * +oakley_ph1hash_base_i(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + vchar_t *hashkey = NULL; + vchar_t *hash = NULL; /* for signature mode */ + char *p; + int len; + int error = -1; + + /* sanity check */ + if (iph1->etype != ISAKMP_ETYPE_BASE) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype for this hash function\n"); + return NULL; + } + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + if (iph1->skeyid == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + return NULL; + } + hashkey = iph1->skeyid; + break; + + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: +#endif + /* make hash for seed */ + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + hash = oakley_hash(buf, iph1); + if (hash == NULL) + goto end; + vfree(buf); + buf = NULL; + + hashkey = hash; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication method %d\n", + iph1->approval->authmethod); + return NULL; + + } + + len = (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + + memcpy(p, iph1->sa->v, iph1->sa->l); + p += iph1->sa->l; + + bp = (sw == GENERATE ? iph1->id : iph1->id_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH_I with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(hashkey, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH_I computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (hash != NULL) + vfree(hash); + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute HASH_R on base mode for signature method. + * base: + * HASH_R = prf(hash(Ni_b | Nr_b), g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b) + */ +vchar_t * +oakley_ph1hash_base_r(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + vchar_t *hash = NULL; + char *p; + int len; + int error = -1; + + /* sanity check */ + if (iph1->etype != ISAKMP_ETYPE_BASE) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype for this hash function\n"); + return NULL; + } + if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG +#ifdef ENABLE_HYBRID + && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I + && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I +#endif + && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG) { + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication method %d\n", + iph1->approval->authmethod); + return NULL; + } + + /* make hash for seed */ + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + hash = oakley_hash(buf, iph1); + if (hash == NULL) + goto end; + vfree(buf); + buf = NULL; + + /* make really hash */ + len = (sw == GENERATE ? iph1->dhpub_p->l : iph1->dhpub->l) + + (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id_p->l : iph1->id->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + + bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + + memcpy(p, iph1->sa->v, iph1->sa->l); + p += iph1->sa->l; + + bp = (sw == GENERATE ? iph1->id_p : iph1->id); + memcpy(p, bp->v, bp->l); + p += bp->l; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(hash, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + if (hash) + vfree(hash); + return res; +} + +/* + * compute each authentication method in phase 1. + * OUT: + * 0: OK + * -1: error + * other: error to be reply with notification. + * the value is notification type. + */ +int +oakley_validate_auth(iph1) + struct ph1handle *iph1; +{ + vchar_t *my_hash = NULL; + int result; +#ifdef HAVE_GSSAPI + vchar_t *gsshash = NULL; +#endif +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + /* validate HASH */ + { + char *r_hash; + + if (iph1->id_p == NULL || iph1->pl_hash == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + + r_hash = (caddr_t)(iph1->pl_hash + 1); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH received:"); + plogdump(LLV_DEBUG, r_hash, + ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash)); + + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + if (my_hash == NULL) + return ISAKMP_INTERNAL_ERROR; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + plog(LLV_DEBUG, LOCATION, NULL, "HASH for PSK validated.\n"); + } + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: +#endif + { + int error = 0; + int certtype = 0; + + /* validation */ + if (iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "no ID payload was passed.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + if (iph1->sig_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "no SIG payload was passed.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SIGN passed:\n"); + plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l); + + /* get peer's cert */ + switch (iph1->rmconf->getcert_method) { + case ISAKMP_GETCERT_PAYLOAD: + if (iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no peer's CERT payload found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + break; + case ISAKMP_GETCERT_LOCALFILE: + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + if (iph1->rmconf->peerscertfile == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no peer's CERT file found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + /* don't use cached cert */ + if (iph1->cert_p != NULL) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + } + + error = get_cert_fromlocal(iph1, 0); + break; + + case ISAKMP_CERT_PLAINRSA: + error = get_plainrsa_fromlocal(iph1, 0); + break; + } + if (error) + return ISAKMP_INTERNAL_ERROR; + break; + case ISAKMP_GETCERT_DNS: + if (iph1->rmconf->peerscertfile != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "why peer's CERT file is defined " + "though getcert method is dns ?\n"); + return ISAKMP_INTERNAL_ERROR; + } + + /* don't use cached cert */ + if (iph1->cert_p != NULL) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + } + + iph1->cert_p = dnssec_getcert(iph1->id_p); + if (iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no CERT RR found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid getcert_mothod: %d\n", + iph1->rmconf->getcert_method); + return ISAKMP_INTERNAL_ERROR; + } + + /* compare ID payload and certificate name */ + if (iph1->rmconf->verify_cert && +#ifdef __APPLE__ + (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) != 0) +#else + (error = oakley_check_certid(iph1)) != 0) +#endif + return error; + +#ifdef __APPLE__ + + /* check configured peers identifier against cert IDs */ + /* allows checking of specified ID against multiple ids in the cert */ + /* such as multiple domain names */ + if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER && + (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_RMCONFIG)) != 0) + return error; + + /* check cert common name against Open Directory authentication group */ + if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_OPEN_DIR) { + + vchar_t *user_id = NULL; + + user_id = eay_get_x509_common_name(&iph1->cert_p->cert); + if (user_id) { + // the following functions will check if user_id == 0 + if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "the peer is not authorized for access.\n"); + vfree(user_id); + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; + } + vfree(user_id); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "the peer is not authorized for access - user ID not found.\n"); + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; + } + } +#endif + + /* verify certificate */ + if (iph1->rmconf->verify_cert + && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) { + certtype = iph1->rmconf->certtype; +#ifdef ENABLE_HYBRID + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + certtype = iph1->cert_p->type; + break; + default: + break; + } +#endif + switch (certtype) { + case ISAKMP_CERT_X509SIGN: +#ifdef __APPLE__ + if (iph1->rmconf->cert_verification == VERIFICATION_MODULE_SEC_FRAMEWORK) + error = crypto_cssm_check_x509cert(&iph1->cert_p->cert); + else +#endif + { + char path[MAXPATHLEN]; + char *ca; + + if (iph1->rmconf->cacertfile != NULL) { + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, + iph1->rmconf->cacertfile); + ca = path; + } else { + ca = NULL; + } + + error = eay_check_x509cert(&iph1->cert_p->cert, + lcconf->pathinfo[LC_PATHTYPE_CERT], + ca, 0); + } + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "no supported certtype %d\n", certtype); + return ISAKMP_INTERNAL_ERROR; + } + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "the peer's certificate is not verified.\n"); + return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY; + } + } + + + plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n"); + + /* compute hash */ + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_base_r(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + if (my_hash == NULL) + return ISAKMP_INTERNAL_ERROR; + + + certtype = iph1->rmconf->certtype; +#ifdef ENABLE_HYBRID + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + certtype = iph1->cert_p->type; + break; + default: + break; + } +#endif + /* check signature */ + switch (certtype) { + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_DNS: + error = eay_check_x509sign(my_hash, + iph1->sig_p, + &iph1->cert_p->cert); + break; + case ISAKMP_CERT_PLAINRSA: + iph1->rsa_p = rsa_try_check_rsasign(my_hash, + iph1->sig_p, iph1->rsa_candidates); + error = iph1->rsa_p ? 0 : -1; + + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "no supported certtype %d\n", + certtype); + vfree(my_hash); + return ISAKMP_INTERNAL_ERROR; + } + + vfree(my_hash); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid SIG.\n"); + return ISAKMP_NTYPE_INVALID_SIGNATURE; + } + plog(LLV_DEBUG, LOCATION, NULL, "SIG authenticated\n"); + } + break; +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + { + if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, " + "hybrid auth is enabled, " + "but peer is no Xauth compliant\n"); + return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED; + break; + } + plog(LLV_INFO, LOCATION, NULL, "No SIG was passed, " + "but hybrid auth is enabled\n"); + + return 0; + break; + } +#endif +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + + if (my_hash == NULL) { + if (gssapi_more_tokens(iph1)) + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + else + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + gsshash = gssapi_unwraphash(iph1); + if (gsshash == NULL) { + vfree(my_hash); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + result = memcmp(my_hash->v, gsshash->v, my_hash->l); + vfree(my_hash); + vfree(gsshash); + + if (result) { + plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + plog(LLV_DEBUG, LOCATION, NULL, "hash compared OK\n"); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + if (iph1->id_p == NULL || iph1->pl_hash == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + plog(LLV_ERROR, LOCATION, iph1->remote, + "not supported authmethod type %s\n", + s_oakley_attr_method(iph1->approval->authmethod)); + return ISAKMP_INTERNAL_ERROR; + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid authmethod %d why ?\n", + iph1->approval->authmethod); + return ISAKMP_INTERNAL_ERROR; + } +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", __func__, + s_oakley_attr_method(iph1->approval->authmethod), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* get my certificate + * NOTE: include certificate type. + */ +int +oakley_getmycert(iph1) + struct ph1handle *iph1; +{ + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + if (iph1->cert) + return 0; + return get_cert_fromlocal(iph1, 1); + + case ISAKMP_CERT_PLAINRSA: + if (iph1->rsa) + return 0; + return get_plainrsa_fromlocal(iph1, 1); + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unknown certtype #%d\n", + iph1->rmconf->certtype); + return -1; + } + +} + +/* + * get a CERT from local file. + * IN: + * my != 0 my cert. + * my == 0 peer's cert. + */ +static int +get_cert_fromlocal(iph1, my) + struct ph1handle *iph1; + int my; +{ + char path[MAXPATHLEN]; + vchar_t *cert = NULL; + cert_t **certpl; + char *certfile; + int error = -1; + + if (my) { + certfile = iph1->rmconf->mycertfile; + certpl = &iph1->cert; + } else { + certfile = iph1->rmconf->peerscertfile; + certpl = &iph1->cert_p; + } + +#ifdef __APPLE__ + if (!certfile && iph1->rmconf->identity_in_keychain == 0) { +#else + if (!certfile) { +#endif + plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n"); + return 0; + } + + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: +#ifdef __APPLE__ + if (iph1->rmconf->identity_in_keychain) { + CFDataRef dataRef; + + if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) + goto end; + cert = crypto_cssm_get_x509cert(dataRef); + CFRelease(dataRef); + break; + } // else fall thru +#endif + case ISAKMP_CERT_DNS: + /* make public file name */ + getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile); + cert = eay_get_x509cert(path); + if (cert) { + char *p = NULL; + p = eay_get_x509text(cert); + plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); + racoon_free(p); + }; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported certtype %d\n", + iph1->rmconf->certtype); + goto end; + } + + if (!cert) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get %s CERT.\n", + my ? "my" : "peers"); + goto end; + } + + *certpl = oakley_newcert(); + if (!*certpl) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto end; + } + (*certpl)->pl = vmalloc(cert->l + 1); + if ((*certpl)->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer\n"); + oakley_delcert(*certpl); + *certpl = NULL; + goto end; + } + memcpy((*certpl)->pl->v + 1, cert->v, cert->l); + (*certpl)->pl->v[0] = iph1->rmconf->certtype; + (*certpl)->type = iph1->rmconf->certtype; + (*certpl)->cert.v = (*certpl)->pl->v + 1; + (*certpl)->cert.l = (*certpl)->pl->l - 1; + + plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n"); + plogdump(LLV_DEBUG, (*certpl)->pl->v, (*certpl)->pl->l); + + error = 0; + +end: + if (cert != NULL) + vfree(cert); + + return error; +} + +static int +get_plainrsa_fromlocal(iph1, my) + struct ph1handle *iph1; + int my; +{ + char path[MAXPATHLEN]; + vchar_t *cert = NULL; + char *certfile; + int error = -1; + + iph1->rsa_candidates = rsa_lookup_keys(iph1, my); + if (!iph1->rsa_candidates || rsa_list_count(iph1->rsa_candidates) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "%s RSA key not found for %s\n", + my ? "Private" : "Public", + saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); + goto end; + } + + if (my && rsa_list_count(iph1->rsa_candidates) > 1) { + plog(LLV_WARNING, LOCATION, NULL, + "More than one (=%lu) private PlainRSA key found for %s\n", + rsa_list_count(iph1->rsa_candidates), + saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); + plog(LLV_WARNING, LOCATION, NULL, + "This may have unpredictable results, i.e. wrong key could be used!\n"); + plog(LLV_WARNING, LOCATION, NULL, + "Consider using only one single private key for all peers...\n"); + } + if (my) { + iph1->rsa = ((struct rsa_key *)genlist_next(iph1->rsa_candidates, NULL))->rsa; + genlist_free(iph1->rsa_candidates, NULL); + iph1->rsa_candidates = NULL; + } + + error = 0; + +end: + return error; +} + +/* get signature */ +int +oakley_getsign(iph1) + struct ph1handle *iph1; +{ + char path[MAXPATHLEN]; + vchar_t *privkey = NULL; + int error = -1; + + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: +#ifdef __APPLE__ + // cert in keychain - use cssm to sign + if (iph1->rmconf->identity_in_keychain) { + CFDataRef dataRef; + + if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) + goto end; + iph1->sig = crypto_cssm_getsign(dataRef, iph1->hash); + CFRelease(dataRef); + break; + } // else fall thru +#endif + case ISAKMP_CERT_DNS: + if (iph1->rmconf->myprivfile == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n"); + goto end; + } + + /* make private file name */ + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, + iph1->rmconf->myprivfile); + privkey = privsep_eay_get_pkcs1privkey(path); + if (privkey == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get private key.\n"); + goto end; + } + plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n"); + plogdump(LLV_DEBUG2, privkey->v, privkey->l); + + iph1->sig = eay_get_x509sign(iph1->hash, privkey); + break; + case ISAKMP_CERT_PLAINRSA: + iph1->sig = eay_get_rsasign(iph1->hash, iph1->rsa); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unknown certtype #%d\n", + iph1->rmconf->certtype); + goto end; + } + + if (iph1->sig == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to sign.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SIGN computed:\n"); + plogdump(LLV_DEBUG, iph1->sig->v, iph1->sig->l); + + error = 0; + +end: + if (privkey != NULL) + vfree(privkey); + + return error; +} + +#ifdef __APPLE__ + +/* + * compare certificate name and ID value. + */ +static int +oakley_check_certid(iph1, which_id) + struct ph1handle *iph1; + int which_id; +{ + struct ipsecdoi_id_b *id_b; + int idlen; + u_int8_t doi_type = 255; + void *peers_id = NULL; + struct genlist_entry *gpb = NULL; + + if (which_id == CERT_CHECKID_FROM_PEER) { + /* use ID from peer */ + if (iph1->id_p == NULL || iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; + doi_type = id_b->type; + peers_id = id_b + 1; + idlen = iph1->id_p->l - sizeof(*id_b); + + return oakley_check_certid_1(iph1, doi_type, idlen, peers_id); + + } else { + /* use ID from remote configuration */ + /* check each ID in list */ + struct idspec *id_spec; + + for (id_spec = genlist_next (iph1->rmconf->idvl_p, &gpb); id_spec; id_spec = genlist_next (0, &gpb)) { + + if (id_spec->idtype == IDTYPE_ADDRESS) { + switch (((struct sockaddr *)(id_spec->id->v))->sa_family) { + case AF_INET: + doi_type = IPSECDOI_ID_IPV4_ADDR; + idlen = sizeof(struct in_addr); + peers_id = &(((struct sockaddr_in *)(id_spec->id->v))->sin_addr.s_addr); + break; + #ifdef INET6 + case AF_INET6: + doi_type = IPSECDOI_ID_IPV6_ADDR; + idlen = sizeof(struct in6_addr); + peers_id = &(((struct sockaddr_in6 *)(id_spec->id->v))->sin6_addr.s6_addr); + break; + #endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown address type for peers identifier.\n"); + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; + break; + } + + } else { + doi_type = idtype2doi(id_spec->idtype); + peers_id = id_spec->id->v; + idlen = id_spec->id->l; + } + if (oakley_check_certid_1(iph1, doi_type, idlen, peers_id) == 0) + return 0; + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } +} + +static int +oakley_check_certid_1(iph1, idtype, idlen, id) + struct ph1handle *iph1; + int idtype; + int idlen; + void *id; +{ + + vchar_t *name = NULL; + char *altname = NULL; + int type, len; + int error; + + switch (idtype) { + case IPSECDOI_ID_DER_ASN1_DN: + name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); + if (!name) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + if (idlen != name->l) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ID length in phase 1.\n"); + vfree(name); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id, name->v, idlen); + vfree(name); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + { + + /* + * Openssl returns the IPAddress as an ASN1 octet string (binary format) + * followed by a trailing NULL. 5 bytes for IPv4 and 17 bytes for IPv6 + */ + #define SUBJ_ALT_NAME_IPV4_ADDRESS_LEN 5 + #define SUBJ_ALT_NAME_IPV6_ADDRESS_LEN 17 + + int pos; + + if (idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr) + || idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid address length passed.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) !=0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + if (check_typeofcertname(idtype, type) != 0) { + /* wrong type - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + + if (len == SUBJ_ALT_NAME_IPV4_ADDRESS_LEN) { /* IPv4 */ + if (idtype != IPSECDOI_ID_IPV4_ADDR) { + /* wrong IP address type - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + } +#ifdef INET6 + else if (len == SUBJ_ALT_NAME_IPV6_ADDRESS_LEN) { /* IPv6 */ + if (idtype != IPSECDOI_ID_IPV6_ADDR) { + /* wrong IP address type - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + } +#endif + else { + /* invalid IP address length in certificate - bad or bogus certificate */ + plog(LLV_ERROR, LOCATION, NULL, + "invalid IP address in certificate.\n"); + racoon_free(altname); + altname = NULL; + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* compare the addresses */ + error = memcmp(id, altname, idlen); + racoon_free(altname); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + } + } + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + { + int pos; + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + if (check_typeofcertname(idtype, type) != 0) { + /* wrong general type - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + + if (idlen != strlen(altname)) { + /* wrong length - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + error = memcmp(id, altname, idlen); + racoon_free(altname); + if (error) { + plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + } + } + default: + plog(LLV_ERROR, LOCATION, NULL, + "Impropper ID type passed: %s.\n", + s_ipsecdoi_ident(idtype)); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + /*NOTREACHED*/ +} + +#else /* __APPLE__ */ + +/* + * compare certificate name and ID value. + */ +static int +oakley_check_certid(iph1) + struct ph1handle *iph1; +{ + struct ipsecdoi_id_b *id_b; + vchar_t *name = NULL; + char *altname = NULL; + int idlen, type; + int error; + + if (iph1->id_p == NULL || iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; + idlen = iph1->id_p->l - sizeof(*id_b); + + switch (id_b->type) { + case IPSECDOI_ID_DER_ASN1_DN: + name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); + if (!name) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + if (idlen != name->l) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ID length in phase 1.\n"); + vfree(name); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id_b + 1, name->v, idlen); + vfree(name); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + { + /* + * converting to binary from string because openssl return + * a string even if object is a binary. + * XXX fix it ! access by ASN.1 directly without. + */ + struct addrinfo hints, *res; + caddr_t a = NULL; + int pos; + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + &altname, &type, pos) !=0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + if (check_typeofcertname(id_b->type, type) == 0) + break; + + /* next name */ + racoon_free(altname); + altname = NULL; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_RAW; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(altname, NULL, &hints, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + switch (res->ai_family) { + case AF_INET: + a = (caddr_t)&((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr; + break; +#ifdef INET6 + case AF_INET6: + a = (caddr_t)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "family not supported: %d.\n", res->ai_family); + racoon_free(altname); + freeaddrinfo(res); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + error = memcmp(id_b + 1, a, idlen); + freeaddrinfo(res); + vfree(name); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + } + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + { + int pos; + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + &altname, &type, pos) != 0){ + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + if (check_typeofcertname(id_b->type, type) == 0) + break; + + /* next name */ + racoon_free(altname); + altname = NULL; + } + if (idlen != strlen(altname)) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ID length in phase 1.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + if (check_typeofcertname(id_b->type, type) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID type mismatched. ID: %s CERT: %s.\n", + s_ipsecdoi_ident(id_b->type), + s_ipsecdoi_ident(type)); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id_b + 1, altname, idlen); + if (error) { + plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + racoon_free(altname); + return 0; + } + default: + plog(LLV_ERROR, LOCATION, NULL, + "Impropper ID type passed: %s.\n", + s_ipsecdoi_ident(id_b->type)); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + /*NOTREACHED*/ +} + +#endif /* __APPLE__ */ + +static int +check_typeofcertname(doi, genid) + int doi, genid; +{ + switch (doi) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + if (genid != GENT_IPADD) + return -1; + return 0; + case IPSECDOI_ID_FQDN: + if (genid != GENT_DNS) + return -1; + return 0; + case IPSECDOI_ID_USER_FQDN: + if (genid != GENT_EMAIL) + return -1; + return 0; + case IPSECDOI_ID_DER_ASN1_DN: /* should not be passed to this function*/ + case IPSECDOI_ID_DER_ASN1_GN: + case IPSECDOI_ID_KEY_ID: + default: + return -1; + } + /*NOTREACHED*/ +} + +/* + * save certificate including certificate type. + */ +int +oakley_savecert(iph1, gen) + struct ph1handle *iph1; + struct isakmp_gen *gen; +{ + cert_t **c; + u_int8_t type; + STACK_OF(X509) *certs=NULL; + PKCS7 *p7; + + type = *(u_int8_t *)(gen + 1) & 0xff; + + switch (type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC. " + "ignore this CERT payload.\n"); + return 0; + case ISAKMP_CERT_PKCS7: + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + c = &iph1->cert_p; + break; + case ISAKMP_CERT_CRL: + c = &iph1->crl_p; + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + plog(LLV_ERROR, LOCATION, NULL, + "No supported such CERT type %d\n", type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid CERT type %d\n", type); + return -1; + } + + /* XXX choice the 1th cert, ignore after the cert. */ + /* XXX should be processed. */ + if (*c) { + plog(LLV_WARNING, LOCATION, NULL, + "ignore 2nd CERT payload.\n"); + return 0; + } + + if (type == ISAKMP_CERT_PKCS7) { + u_char *bp; + int i; + + /* Skip the header */ + bp = (u_char *)(gen + 1); + /* And the first byte is the certificate type, + * we know that already + */ + bp++; + p7 = d2i_PKCS7(NULL, (void *)&bp, + ntohs(gen->len) - sizeof(*gen) - 1); + + if (!p7) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to parse PKCS#7 CERT.\n"); + return -1; + } + + /* Copied this from the openssl pkcs7 application; + * there"s little by way of documentation for any of + * it. I can only presume it"s correct. + */ + + i = OBJ_obj2nid(p7->type); + switch (i) { + case NID_pkcs7_signed: + certs=p7->d.sign->cert; + break; + case NID_pkcs7_signedAndEnveloped: + certs=p7->d.signed_and_enveloped->cert; + break; + default: + break; + } + + if (!certs) { + plog(LLV_ERROR, LOCATION, NULL, + "CERT PKCS#7 bundle contains no certs.\n"); + PKCS7_free(p7); + return -1; + } + + for (i = 0; i < sk_X509_num(certs); i++) { + int len; + u_char *bp; + X509 *cert = sk_X509_value(certs,i); + + plog(LLV_DEBUG, LOCATION, NULL, + "Trying PKCS#7 cert %d.\n", i); + + /* We'll just try each cert in turn */ + *c = save_certx509(cert); + + if (!*c) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + continue; + } + + /* Ignore cert if it doesn't match identity + * XXX If verify cert is disabled, we still just take + * the first certificate.... + */ + if(iph1->rmconf->verify_cert && + oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) { + plog(LLV_DEBUG, LOCATION, NULL, + "Discarding CERT: does not match ID.\n"); + oakley_delcert((*c)); + *c = NULL; + continue; + } + + { + char *p = eay_get_x509text(&(*c)->cert); + plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plog(LLV_DEBUG, LOCATION, NULL, "%s", + p ? p : "\n"); + racoon_free(p); + } + break; + } + PKCS7_free(p7); + + } else { + *c = save_certbuf(gen); + if (!*c) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + return -1; + } + + switch ((*c)->type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC. " + "ignore it.\n"); + return 0; + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + /* Ignore cert if it doesn't match identity + * XXX If verify cert is disabled, we still just take + * the first certificate.... + */ + if(iph1->rmconf->verify_cert && + oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)){ + plog(LLV_DEBUG, LOCATION, NULL, + "Discarding CERT: does not match ID.\n"); + oakley_delcert((*c)); + *c = NULL; + return 0; + } + + { + char *p = eay_get_x509text(&(*c)->cert); + plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); + racoon_free(p); + } + break; + case ISAKMP_CERT_CRL: + plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + default: + /* XXX */ + oakley_delcert((*c)); + *c = NULL; + return 0; + } + } + + return 0; +} + +/* + * save certificate including certificate type. + */ +int +oakley_savecr(iph1, gen) + struct ph1handle *iph1; + struct isakmp_gen *gen; +{ + cert_t **c; + u_int8_t type; + + type = *(u_int8_t *)(gen + 1) & 0xff; + + switch (type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC\n"); + /*FALLTHRU*/ + case ISAKMP_CERT_PKCS7: + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + c = &iph1->cr_p; + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + plog(LLV_ERROR, LOCATION, NULL, + "No supported such CR type %d\n", type); + return -1; + case ISAKMP_CERT_CRL: + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid CR type %d\n", type); + return -1; + } + + *c = save_certbuf(gen); + if (!*c) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CR buffer.\n"); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + + return 0; +} + +static cert_t * +save_certbuf(gen) + struct isakmp_gen *gen; +{ + cert_t *new; + + new = oakley_newcert(); + if (!new) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + return NULL; + } + + new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen)); + if (new->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to copy CERT from packet.\n"); + oakley_delcert(new); + new = NULL; + return NULL; + } + memcpy(new->pl->v, gen + 1, new->pl->l); + new->type = new->pl->v[0] & 0xff; + new->cert.v = new->pl->v + 1; + new->cert.l = new->pl->l - 1; + + return new; +} + +static cert_t * +save_certx509(cert) + X509 *cert; +{ + cert_t *new; + int len; + u_char *bp; + + new = oakley_newcert(); + if (!new) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + return NULL; + } + + len = i2d_X509(cert, NULL); + new->pl = vmalloc(len); + if (new->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to copy CERT from packet.\n"); + oakley_delcert(new); + new = NULL; + return NULL; + } + bp = (u_char *) new->pl->v; + len = i2d_X509(cert, &bp); + new->type = ISAKMP_CERT_X509SIGN; + new->cert.v = new->pl->v; + new->cert.l = new->pl->l; + + return new; +} + +/* + * get my CR. + * NOTE: No Certificate Authority field is included to CR payload at the + * moment. Becuase any certificate authority are accepted without any check. + * The section 3.10 in RFC2408 says that this field SHOULD not be included, + * if there is no specific certificate authority requested. + */ +vchar_t * +oakley_getcr(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf; + + buf = vmalloc(1); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer\n"); + return NULL; + } + buf->v[0] = iph1->rmconf->certtype; + + plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n", + s_isakmp_certtype(iph1->rmconf->certtype)); + if (buf->l > 1) + plogdump(LLV_DEBUG, buf->v, buf->l); + + return buf; +} + +/* + * check peer's CR. + */ +int +oakley_checkcr(iph1) + struct ph1handle *iph1; +{ + if (iph1->cr_p == NULL) + return 0; + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "peer transmitted CR: %s\n", + s_isakmp_certtype(iph1->cr_p->type)); + + if (iph1->cr_p->type != iph1->rmconf->certtype) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "such a cert type isn't supported: %d\n", + (char)iph1->cr_p->type); + return -1; + } + + return 0; +} + +/* + * check to need CR payload. + */ +int +oakley_needcr(type) + int type; +{ + switch (type) { + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: +#endif + return 1; + default: + return 0; + } + /*NOTREACHED*/ +} + +/* + * compute SKEYID + * see seciton 5. Exchanges in RFC 2409 + * psk: SKEYID = prf(pre-shared-key, Ni_b | Nr_b) + * sig: SKEYID = prf(Ni_b | Nr_b, g^ir) + * enc: SKEYID = prf(H(Ni_b | Nr_b), CKY-I | CKY-R) + */ +int +oakley_skeyid(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL, *bp; + char *p; + int len; + int error = -1; + + /* SKEYID */ + switch(iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: +#ifdef __APPLE__ + if (iph1->rmconf->shared_secret) { + + switch (iph1->rmconf->secrettype) { + case SECRETTYPE_KEY: + /* in psk file - use KEY from remote configuration to locate it */ + iph1->authstr = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1); + break; + case SECRETTYPE_KEYCHAIN: + /* in the system keychain */ + iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL); + break; + case SECRETTYPE_KEYCHAIN_BY_ID: + /* in the system keychain - use peer id */ + iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, iph1->id_p); + break; + case SECRETTYPE_USE: + /* in the remote configuration */ + default: + iph1->authstr = vdup(iph1->rmconf->shared_secret); + } + + } + else +#endif + if (iph1->etype != ISAKMP_ETYPE_IDENT) { + iph1->authstr = getpskbyname(iph1->id_p); + if (iph1->authstr == NULL) { + if (iph1->rmconf->verify_identifier) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "couldn't find the pskey.\n"); + goto end; + } + plog(LLV_NOTIFY, LOCATION, iph1->remote, + "couldn't find the proper pskey, " + "try to get one by the peer's address.\n"); + } + } + if (iph1->authstr == NULL) { + /* + * If the exchange type is the main mode or if it's + * failed to get the psk by ID, racoon try to get + * the psk by remote IP address. + * It may be nonsense. + */ + iph1->authstr = getpskbyaddr(iph1->remote); + if (iph1->authstr == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "couldn't find the pskey for %s.\n", + saddrwop2str(iph1->remote)); + goto end; + } + } + plog(LLV_DEBUG, LOCATION, NULL, "the psk found.\n"); + /* should be secret PSK */ + plog(LLV_DEBUG2, LOCATION, NULL, "psk: "); + plogdump(LLV_DEBUG2, iph1->authstr->v, iph1->authstr->l); + + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + plog(LLV_DEBUG, LOCATION, NULL, "nonce 1: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + plog(LLV_DEBUG, LOCATION, NULL, "nonce 2: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(iph1->authstr, buf, iph1); + if (iph1->skeyid == NULL) + goto end; + break; + + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: +#endif +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: +#endif + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get nonce buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + plog(LLV_DEBUG, LOCATION, NULL, "nonce1: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + plog(LLV_DEBUG, LOCATION, NULL, "nonce2: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1); + if (iph1->skeyid == NULL) + goto end; + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_WARNING, LOCATION, NULL, + "not supported authentication method %s\n", + s_oakley_attr_method(iph1->approval->authmethod)); + goto end; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication method %d\n", + iph1->approval->authmethod); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid->v, iph1->skeyid->l); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + return error; +} + +/* + * compute SKEYID_[dae] + * see seciton 5. Exchanges in RFC 2409 + * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0) + * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1) + * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2) + */ +int +oakley_skeyid_dae(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL; + char *p; + int len; + int error = -1; + + if (iph1->skeyid == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + goto end; + } + + /* SKEYID D */ + /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ + len = iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 0; + iph1->skeyid_d = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_d == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_d computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid->l); + + /* SKEYID A */ + /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ + len = iph1->skeyid_d->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + memcpy(p, iph1->skeyid_d->v, iph1->skeyid_d->l); + p += iph1->skeyid_d->l; + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 1; + iph1->skeyid_a = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_a == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_a computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l); + + /* SKEYID E */ + /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ + len = iph1->skeyid_a->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + memcpy(p, iph1->skeyid_a->v, iph1->skeyid_a->l); + p += iph1->skeyid_a->l; + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 2; + iph1->skeyid_e = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_e == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_e computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + return error; +} + +/* + * compute final encryption key. + * see Appendix B. + */ +int +oakley_compute_enckey(iph1) + struct ph1handle *iph1; +{ + u_int keylen, prflen; + int error = -1; + + /* RFC2409 p39 */ + keylen = alg_oakley_encdef_keylen(iph1->approval->enctype, + iph1->approval->encklen); + if (keylen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoritym %d, " + "or invalid key length %d.\n", + iph1->approval->enctype, + iph1->approval->encklen); + goto end; + } + iph1->key = vmalloc(keylen >> 3); + if (iph1->key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get key buffer\n"); + goto end; + } + + /* set prf length */ + prflen = alg_oakley_hashdef_hashlen(iph1->approval->hashtype); + if (prflen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hash type %d.\n", iph1->approval->hashtype); + goto end; + } + + /* see isakmp-oakley-08 5.3. */ + if (iph1->key->l <= iph1->skeyid_e->l) { + /* + * if length(Ka) <= length(SKEYID_e) + * Ka = first length(K) bit of SKEYID_e + */ + memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l); + } else { + vchar_t *buf = NULL, *res = NULL; + u_char *p, *ep; + int cplen; + int subkey; + + /* + * otherwise, + * Ka = K1 | K2 | K3 + * where + * K1 = prf(SKEYID_e, 0) + * K2 = prf(SKEYID_e, K1) + * K3 = prf(SKEYID_e, K2) + */ + plog(LLV_DEBUG, LOCATION, NULL, + "len(SKEYID_e) < len(Ka) (%zu < %zu), " + "generating long key (Ka = K1 | K2 | ...)\n", + iph1->skeyid_e->l, iph1->key->l); + + if ((buf = vmalloc(prflen >> 3)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get key buffer\n"); + goto end; + } + p = (u_char *)iph1->key->v; + ep = p + iph1->key->l; + + subkey = 1; + while (p < ep) { + if (p == (u_char *)iph1->key->v) { + /* just for computing K1 */ + buf->v[0] = 0; + buf->l = 1; + } + res = oakley_prf(iph1->skeyid_e, buf, iph1); + if (res == NULL) { + vfree(buf); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "compute intermediate encryption key K%d\n", + subkey); + plogdump(LLV_DEBUG, buf->v, buf->l); + plogdump(LLV_DEBUG, res->v, res->l); + + cplen = (res->l < ep - p) ? res->l : ep - p; + memcpy(p, res->v, cplen); + p += cplen; + + buf->l = prflen >> 3; /* to cancel K1 speciality */ + if (res->l != buf->l) { + plog(LLV_ERROR, LOCATION, NULL, + "internal error: res->l=%zu buf->l=%zu\n", + res->l, buf->l); + vfree(res); + vfree(buf); + goto end; + } + memcpy(buf->v, res->v, res->l); + vfree(res); + subkey++; + } + + vfree(buf); + } + + /* + * don't check any weak key or not. + * draft-ietf-ipsec-ike-01.txt Appendix B. + * draft-ietf-ipsec-ciph-aes-cbc-00.txt Section 2.3. + */ +#if 0 + /* weakkey check */ + if (iph1->approval->enctype > ARRAYLEN(oakley_encdef) + || oakley_encdef[iph1->approval->enctype].weakkey == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "encryption algoritym %d isn't supported.\n", + iph1->approval->enctype); + goto end; + } + if ((oakley_encdef[iph1->approval->enctype].weakkey)(iph1->key)) { + plog(LLV_ERROR, LOCATION, NULL, + "weakkey was generated.\n"); + goto end; + } +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "final encryption key computed:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + error = 0; + +end: + return error; +} + +/* allocated new buffer for CERT */ +cert_t * +oakley_newcert() +{ + cert_t *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert's buffer\n"); + return NULL; + } + + new->pl = NULL; + + return new; +} + +/* delete buffer for CERT */ +void +oakley_delcert(cert) + cert_t *cert; +{ + if (!cert) + return; + if (cert->pl) + VPTRINIT(cert->pl); + racoon_free(cert); +} + +/* + * compute IV and set to ph1handle + * IV = hash(g^xi | g^xr) + * see 4.1 Phase 1 state in draft-ietf-ipsec-ike. + */ +int +oakley_newiv(iph1) + struct ph1handle *iph1; +{ + struct isakmp_ivm *newivm = NULL; + vchar_t *buf = NULL, *bp; + char *p; + int len; + + /* create buffer */ + len = iph1->dhpub->l + iph1->dhpub_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + return -1; + } + + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + /* allocate IVm */ + newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); + if (newivm == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + vfree(buf); + return -1; + } + + /* compute IV */ + newivm->iv = oakley_hash(buf, iph1); + if (newivm->iv == NULL) { + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + /* adjust length of iv */ + newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (newivm->iv->l == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + /* create buffer to save iv */ + if ((newivm->ive = vdup(newivm->iv)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "vdup (%s)\n", strerror(errno)); + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + vfree(buf); + + plog(LLV_DEBUG, LOCATION, NULL, "IV computed:\n"); + plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + + iph1->ivm = newivm; + + return 0; +} + +/* + * compute IV for the payload after phase 1. + * It's not limited for phase 2. + * if pahse 1 was encrypted. + * IV = hash(last CBC block of Phase 1 | M-ID) + * if phase 1 was not encrypted. + * IV = hash(phase 1 IV | M-ID) + * see 4.2 Phase 2 state in draft-ietf-ipsec-ike. + */ +struct isakmp_ivm * +oakley_newiv2(iph1, msgid) + struct ph1handle *iph1; + u_int32_t msgid; +{ + struct isakmp_ivm *newivm = NULL; + vchar_t *buf = NULL; + char *p; + int len; + int error = -1; + + /* create buffer */ + len = iph1->ivm->iv->l + sizeof(msgid_t); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + goto end; + } + + p = buf->v; + + memcpy(p, iph1->ivm->iv->v, iph1->ivm->iv->l); + p += iph1->ivm->iv->l; + + memcpy(p, &msgid, sizeof(msgid)); + + plog(LLV_DEBUG, LOCATION, NULL, "compute IV for phase2\n"); + plog(LLV_DEBUG, LOCATION, NULL, "phase1 last IV:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* allocate IVm */ + newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); + if (newivm == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + goto end; + } + + /* compute IV */ + if ((newivm->iv = oakley_hash(buf, iph1)) == NULL) + goto end; + + /* adjust length of iv */ + newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (newivm->iv->l == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + /* create buffer to save new iv */ + if ((newivm->ive = vdup(newivm->iv)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "vdup (%s)\n", strerror(errno)); + goto end; + } + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "phase2 IV computed:\n"); + plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + +end: + if (error && newivm != NULL){ + oakley_delivm(newivm); + newivm=NULL; + } + if (buf != NULL) + vfree(buf); + return newivm; +} + +void +oakley_delivm(ivm) + struct isakmp_ivm *ivm; +{ + if (ivm == NULL) + return; + + if (ivm->iv != NULL) + vfree(ivm->iv); + if (ivm->ive != NULL) + vfree(ivm->ive); + racoon_free(ivm); + + return; +} + +/* + * decrypt packet. + * save new iv and old iv. + */ +vchar_t * +oakley_do_decrypt(iph1, msg, ivdp, ivep) + struct ph1handle *iph1; + vchar_t *msg, *ivdp, *ivep; +{ + vchar_t *buf = NULL, *new = NULL; + char *pl; + int len; + u_int8_t padlen; + int blen; + int error = -1; + + plog(LLV_DEBUG, LOCATION, NULL, "begin decryption.\n"); + + blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (blen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + /* save IV for next, but not sync. */ + memset(ivep->v, 0, ivep->l); + memcpy(ivep->v, (caddr_t)&msg->v[msg->l - blen], blen); + + plog(LLV_DEBUG, LOCATION, NULL, + "IV was saved for next processing:\n"); + plogdump(LLV_DEBUG, ivep->v, ivep->l); + + pl = msg->v + sizeof(struct isakmp); + + len = msg->l - sizeof(struct isakmp); + + /* create buffer */ + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to decrypt.\n"); + goto end; + } + memcpy(buf->v, pl, len); + + /* do decrypt */ + new = alg_oakley_encdef_decrypt(iph1->approval->enctype, + buf, iph1->key, ivdp); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "decryption %d failed.\n", iph1->approval->enctype); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + vfree(buf); + buf = NULL; + if (new == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "decrypted payload by IV:\n"); + plogdump(LLV_DEBUG, ivdp->v, ivdp->l); + + plog(LLV_DEBUG, LOCATION, NULL, + "decrypted payload, but not trimed.\n"); + plogdump(LLV_DEBUG, new->v, new->l); + + /* get padding length */ + if (lcconf->pad_excltail) + padlen = new->v[new->l - 1] + 1; + else + padlen = new->v[new->l - 1]; + plog(LLV_DEBUG, LOCATION, NULL, "padding len=%u\n", padlen); + + /* trim padding */ + if (lcconf->pad_strict) { + if (padlen > new->l) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid padding len=%u, buflen=%zu.\n", + padlen, new->l); + plogdump(LLV_ERROR, new->v, new->l); + goto end; + } + new->l -= padlen; + plog(LLV_DEBUG, LOCATION, NULL, "trimmed padding\n"); + } else { + plog(LLV_DEBUG, LOCATION, NULL, "skip to trim padding.\n"); + } + + /* create new buffer */ + len = sizeof(struct isakmp) + new->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to decrypt.\n"); + goto end; + } + memcpy(buf->v, msg->v, sizeof(struct isakmp)); + memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); + ((struct isakmp *)buf->v)->len = htonl(buf->l); + + plog(LLV_DEBUG, LOCATION, NULL, "decrypted.\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph1->remote, iph1->local, 1); +#endif + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (new != NULL) + vfree(new); + + return buf; +} + +/* + * encrypt packet. + */ +vchar_t * +oakley_do_encrypt(iph1, msg, ivep, ivp) + struct ph1handle *iph1; + vchar_t *msg, *ivep, *ivp; +{ + vchar_t *buf = 0, *new = 0; + char *pl; + int len; + u_int padlen; + int blen; + int error = -1; + + plog(LLV_DEBUG, LOCATION, NULL, "begin encryption.\n"); + + /* set cbc block length */ + blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (blen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + pl = msg->v + sizeof(struct isakmp); + len = msg->l - sizeof(struct isakmp); + + /* add padding */ + padlen = oakley_padlen(len, blen); + plog(LLV_DEBUG, LOCATION, NULL, "pad length = %u\n", padlen); + + /* create buffer */ + buf = vmalloc(len + padlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to encrypt.\n"); + goto end; + } + if (padlen) { + int i; + char *p = &buf->v[len]; + if (lcconf->pad_random) { + for (i = 0; i < padlen; i++) + *p++ = eay_random() & 0xff; + } + } + memcpy(buf->v, pl, len); + + /* make pad into tail */ + if (lcconf->pad_excltail) + buf->v[len + padlen - 1] = padlen - 1; + else + buf->v[len + padlen - 1] = padlen; + + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* do encrypt */ + new = alg_oakley_encdef_encrypt(iph1->approval->enctype, + buf, iph1->key, ivep); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "encryption %d failed.\n", iph1->approval->enctype); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + vfree(buf); + buf = NULL; + if (new == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "encrypted payload by IV:\n"); + plogdump(LLV_DEBUG, ivep->v, ivep->l); + + /* save IV for next */ + memset(ivp->v, 0, ivp->l); + memcpy(ivp->v, (caddr_t)&new->v[new->l - blen], blen); + + plog(LLV_DEBUG, LOCATION, NULL, "save IV for next:\n"); + plogdump(LLV_DEBUG, ivp->v, ivp->l); + + /* create new buffer */ + len = sizeof(struct isakmp) + new->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to encrypt.\n"); + goto end; + } + memcpy(buf->v, msg->v, sizeof(struct isakmp)); + memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); + ((struct isakmp *)buf->v)->len = htonl(buf->l); + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "encrypted.\n"); + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (new != NULL) + vfree(new); + + return buf; +} + +/* culculate padding length */ +static int +oakley_padlen(len, base) + int len, base; +{ + int padlen; + + padlen = base - len % base; + + if (lcconf->pad_randomlen) + padlen += ((eay_random() % (lcconf->pad_maxsize + 1) + 1) * + base); + + return padlen; +} + +#ifdef __APPLE__ +/* ----------------------------------------------------------------------------- +The base-64 encoding packs three 8-bit bytes into four 7-bit ASCII +characters. If the number of bytes in the original data isn't divisable +by three, "=" characters are used to pad the encoded data. The complete +set of characters used in base-64 are: + 'A'..'Z' => 00..25 + 'a'..'z' => 26..51 + '0'..'9' => 52..61 + '+' => 62 + '/' => 63 + '=' => pad + +----------------------------------------------------------------------------- */ +static const signed char base64_DecodeTable[128] = { + /* 000 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* 010 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* 020 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* 030 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* ' ' */ -1, -1, -1, -1, -1, -1, -1, -1, + /* '(' */ -1, -1, -1, 62, -1, -1, -1, 63, + /* '0' */ 52, 53, 54, 55, 56, 57, 58, 59, + /* '8' */ 60, 61, -1, -1, -1, 0, -1, -1, + /* '@' */ -1, 0, 1, 2, 3, 4, 5, 6, + /* 'H' */ 7, 8, 9, 10, 11, 12, 13, 14, + /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22, + /* 'X' */ 23, 24, 25, -1, -1, -1, -1, -1, + /* '`' */ -1, 26, 27, 28, 29, 30, 31, 32, + /* 'h' */ 33, 34, 35, 36, 37, 38, 39, 40, + /* 'p' */ 41, 42, 43, 44, 45, 46, 47, 48, + /* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1 +}; + +static int base64toCFData(vchar_t *textin, CFDataRef *dataRef) +{ + uint8_t *tmpbuf; + uint8_t c; + int tmpbufpos = 0; + int numeq = 0; + int acc = 0; + int cntr = 0; + uint8_t *textcur = textin->v; + int len = textin->l; + int i; + + tmpbuf = malloc(len); // len of result will be less than encoded len + if (tmpbuf == NULL) { + yyerror("memory error - could not allocate buffer for certificate reference conversion from base-64."); + return -1; + } + + for (i = 0; i < len; i++) { + c = *(textcur++); + if (c == '=') + numeq++; + else if (!isspace(c)) + numeq = 0; + if (base64_DecodeTable[c] < 0) + continue; + cntr++; + acc <<= 6; + acc += base64_DecodeTable[c]; + if (0 == (cntr & 0x3)) { + tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff; + if (numeq < 2) + tmpbuf[tmpbufpos++] = (acc >> 8) & 0xff; + if (numeq < 1) + tmpbuf[tmpbufpos++] = acc & 0xff; + } + } + *dataRef = CFDataCreate(NULL, tmpbuf, tmpbufpos); + free(tmpbuf); + if (*dataRef) + return 0; + else + return -1; + +} +#endif diff --git a/ipsec-tools/racoon/oakley.h b/ipsec-tools/racoon/oakley.h new file mode 100644 index 0000000..66edfef --- /dev/null +++ b/ipsec-tools/racoon/oakley.h @@ -0,0 +1,218 @@ +/* $Id: oakley.h,v 1.9 2004/10/24 17:37:00 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _OAKLEY_H +#define _OAKLEY_H + +#include "vmbuf.h" + +/* refer to RFC 2409 */ + +/* Attribute Classes */ +#define OAKLEY_ATTR_ENC_ALG 1 /* B */ +#define OAKLEY_ATTR_ENC_ALG_DES 1 +#define OAKLEY_ATTR_ENC_ALG_IDEA 2 +#define OAKLEY_ATTR_ENC_ALG_BLOWFISH 3 +#define OAKLEY_ATTR_ENC_ALG_RC5 4 +#define OAKLEY_ATTR_ENC_ALG_3DES 5 +#define OAKLEY_ATTR_ENC_ALG_CAST 6 +#define OAKLEY_ATTR_ENC_ALG_AES 7 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_HASH_ALG 2 /* B */ +#define OAKLEY_ATTR_HASH_ALG_MD5 1 +#define OAKLEY_ATTR_HASH_ALG_SHA 2 +#define OAKLEY_ATTR_HASH_ALG_TIGER 3 +#if defined(WITH_SHA2) +#define OAKLEY_ATTR_HASH_ALG_SHA2_256 4 +#define OAKLEY_ATTR_HASH_ALG_SHA2_384 5 +#define OAKLEY_ATTR_HASH_ALG_SHA2_512 6 +#endif + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_AUTH_METHOD 3 /* B */ +#define OAKLEY_ATTR_AUTH_METHOD_PSKEY 1 +#define OAKLEY_ATTR_AUTH_METHOD_DSSSIG 2 +#define OAKLEY_ATTR_AUTH_METHOD_RSASIG 3 +#define OAKLEY_ATTR_AUTH_METHOD_RSAENC 4 +#define OAKLEY_ATTR_AUTH_METHOD_RSAREV 5 +#define OAKLEY_ATTR_AUTH_METHOD_EGENC 6 +#define OAKLEY_ATTR_AUTH_METHOD_EGREV 7 + /* Hybrid Auth */ +#ifdef ENABLE_HYBRID +#define OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I 64221 +#define OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R 64222 +#define OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I 64223 +#define OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R 64224 + + /* 65001 - 65535 Private Use */ + + /* Plain Xauth, Not implemented */ +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I 65001 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R 65002 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I 65003 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R 65004 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I 65005 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R 65006 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I 65007 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R 65008 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I 65009 +#define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R 65010 +#endif + + /* + * The following are valid when the Vendor ID is one of + * the following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + */ +#define OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB 65001 +#define OAKLEY_ATTR_GRP_DESC 4 /* B */ +#define OAKLEY_ATTR_GRP_DESC_MODP768 1 +#define OAKLEY_ATTR_GRP_DESC_MODP1024 2 +#define OAKLEY_ATTR_GRP_DESC_EC2N155 3 +#define OAKLEY_ATTR_GRP_DESC_EC2N185 4 +#define OAKLEY_ATTR_GRP_DESC_MODP1536 5 +#define OAKLEY_ATTR_GRP_DESC_MODP2048 14 +#define OAKLEY_ATTR_GRP_DESC_MODP3072 15 +#define OAKLEY_ATTR_GRP_DESC_MODP4096 16 +#define OAKLEY_ATTR_GRP_DESC_MODP6144 17 +#define OAKLEY_ATTR_GRP_DESC_MODP8192 18 + /* 32768 - 65535 Private Use */ +#define OAKLEY_ATTR_GRP_TYPE 5 /* B */ +#define OAKLEY_ATTR_GRP_TYPE_MODP 1 +#define OAKLEY_ATTR_GRP_TYPE_ECP 2 +#define OAKLEY_ATTR_GRP_TYPE_EC2N 3 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_GRP_PI 6 /* V */ +#define OAKLEY_ATTR_GRP_GEN_ONE 7 /* V */ +#define OAKLEY_ATTR_GRP_GEN_TWO 8 /* V */ +#define OAKLEY_ATTR_GRP_CURVE_A 9 /* V */ +#define OAKLEY_ATTR_GRP_CURVE_B 10 /* V */ +#define OAKLEY_ATTR_SA_LD_TYPE 11 /* B */ +#define OAKLEY_ATTR_SA_LD_TYPE_DEFAULT 1 +#define OAKLEY_ATTR_SA_LD_TYPE_SEC 1 +#define OAKLEY_ATTR_SA_LD_TYPE_KB 2 +#define OAKLEY_ATTR_SA_LD_TYPE_MAX 3 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_SA_LD 12 /* V */ +#define OAKLEY_ATTR_SA_LD_SEC_DEFAULT 28800 /* 8 hours */ +#define OAKLEY_ATTR_PRF 13 /* B */ +#define OAKLEY_ATTR_KEY_LEN 14 /* B */ +#define OAKLEY_ATTR_FIELD_SIZE 15 /* B */ +#define OAKLEY_ATTR_GRP_ORDER 16 /* V */ +#define OAKLEY_ATTR_BLOCK_SIZE 17 /* B */ + /* 16384 - 32767 Private Use */ + + /* + * The following are valid when the Vendor ID is one of + * the following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + */ +#define OAKLEY_ATTR_GSS_ID 16384 + +#define MAXPADLWORD 20 + +struct dhgroup { + int type; + vchar_t *prime; + int gen1; + int gen2; + vchar_t *curve_a; + vchar_t *curve_b; + vchar_t *order; +}; + +/* certificate holder */ +typedef struct cert_t_tag { + u_int8_t type; /* type of CERT, must be same to pl->v[0]*/ + vchar_t cert; /* pointer to the CERT */ + vchar_t *pl; /* CERT payload minus isakmp general header */ +} cert_t; + +struct ph1handle; +struct ph2handle; +struct isakmp_ivm; + +extern int oakley_get_defaultlifetime __P((void)); + +extern int oakley_dhinit __P((void)); +extern void oakley_dhgrp_free __P((struct dhgroup *)); +extern int oakley_dh_compute __P((const struct dhgroup *, + vchar_t *, vchar_t *, vchar_t *, vchar_t **)); +extern int oakley_dh_generate __P((const struct dhgroup *, + vchar_t **, vchar_t **)); +extern int oakley_setdhgroup __P((int, struct dhgroup **)); + +extern vchar_t *oakley_prf __P((vchar_t *, vchar_t *, struct ph1handle *)); +extern vchar_t *oakley_hash __P((vchar_t *, struct ph1handle *)); + +extern int oakley_compute_keymat __P((struct ph2handle *, int)); + +#if notyet +extern vchar_t *oakley_compute_hashx __P((void)); +#endif +extern vchar_t *oakley_compute_hash3 __P((struct ph1handle *, + u_int32_t, vchar_t *)); +extern vchar_t *oakley_compute_hash1 __P((struct ph1handle *, + u_int32_t, vchar_t *)); +extern vchar_t *oakley_ph1hash_common __P((struct ph1handle *, int)); +extern vchar_t *oakley_ph1hash_base_i __P((struct ph1handle *, int)); +extern vchar_t *oakley_ph1hash_base_r __P((struct ph1handle *, int)); + +extern int oakley_validate_auth __P((struct ph1handle *)); +extern int oakley_getmycert __P((struct ph1handle *)); +extern int oakley_getsign __P((struct ph1handle *)); +extern vchar_t *oakley_getcr __P((struct ph1handle *)); +extern int oakley_checkcr __P((struct ph1handle *)); +extern int oakley_needcr __P((int)); +struct isakmp_gen; +extern int oakley_savecert __P((struct ph1handle *, struct isakmp_gen *)); +extern int oakley_savecr __P((struct ph1handle *, struct isakmp_gen *)); + +extern int oakley_skeyid __P((struct ph1handle *)); +extern int oakley_skeyid_dae __P((struct ph1handle *)); + +extern int oakley_compute_enckey __P((struct ph1handle *)); +extern cert_t *oakley_newcert __P((void)); +extern void oakley_delcert __P((cert_t *)); +extern int oakley_newiv __P((struct ph1handle *)); +extern struct isakmp_ivm *oakley_newiv2 __P((struct ph1handle *, u_int32_t)); +extern void oakley_delivm __P((struct isakmp_ivm *)); +extern vchar_t *oakley_do_decrypt __P((struct ph1handle *, + vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *oakley_do_encrypt __P((struct ph1handle *, + vchar_t *, vchar_t *, vchar_t *)); + +#endif /* _OAKLEY_H */ diff --git a/ipsec-tools/racoon/open_dir.c b/ipsec-tools/racoon/open_dir.c new file mode 100644 index 0000000..952d0ce --- /dev/null +++ b/ipsec-tools/racoon/open_dir.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include + +#include +#include +#include +#include +#include + +#include "vmbuf.h" +#include "remoteconf.h" +#include "plog.h" +#include "misc.h" +#include "gcmalloc.h" +#include "open_dir.h" + +#define BUF_LEN 1024 + + +static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, + tDirNodeReference *searchNodeRef, unsigned long *count); +static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, + char *attr, tAttributeValueEntryPtr *attr_value); +static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, + char *group_name, char *user_name, char *userGID, int *authorized); + + +//---------------------------------------------------------------------- +// open_dir_authorize_id +//---------------------------------------------------------------------- +int open_dir_authorize_id(vchar_t *id, vchar_t *group) +{ + + tDirReference dirRef; + tDirStatus dsResult = eDSNoErr; + int authorized = 0; + tDirNodeReference searchNodeRef; + tAttributeValueEntryPtr groupID = NULL; + tAttributeValueEntryPtr recordName = NULL; + unsigned long searchNodeCount; + char* user_name = NULL; + char* group_name = NULL; + + if (id == 0 || id->l < 1) { + plog(LLV_ERROR, LOCATION, NULL, "invalid user name.\n"); + goto end; + } + user_name = racoon_malloc(id->l + 1); + if (user_name == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "out of memory - unable to allocate space for user name.\n"); + goto end; + } + bcopy(id->v, user_name, id->l); + *(user_name + id->l) = 0; + + if (group && group->l > 0) { + group_name = racoon_malloc(group->l + 1); + if (group_name == NULL) { + plog(LLV_NOTIFY, LOCATION, NULL, "out of memeory - unable to allocate space for group name.\n"); + goto end; + } + bcopy(group->v, group_name, group->l); + *(group_name + group->l) = 0; + } + + if ((dsResult = dsOpenDirService(&dirRef)) == eDSNoErr) { + // get the search node ref + if ((dsResult = open_dir_get_search_node_ref(dirRef, 1, &searchNodeRef, &searchNodeCount)) == eDSNoErr) { + // get the user's primary group ID + if (dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrRecordName, &recordName) == eDSNoErr) { + if (recordName != 0) { + if (group_name != 0) { + if ((dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDS1AttrPrimaryGroupID, &groupID)) == eDSNoErr) { + // check if user is member of the group + dsResult = open_dir_check_group_membership(dirRef, searchNodeRef, group_name, + recordName->fAttributeValueData.fBufferData, groupID->fAttributeValueData.fBufferData, &authorized); + } + } else + authorized = 1; // no group required - user record found + } + } + if (groupID) + dsDeallocAttributeValueEntry(dirRef, groupID); + if (recordName) + dsDeallocAttributeValueEntry(dirRef, recordName); + dsCloseDirNode(searchNodeRef); // close the search node + } + dsCloseDirService(dirRef); + } + +end: + if (authorized) + plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' authorized for access\n", user_name); + else + plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' not authorized for access\n", user_name); + if (user_name) + free(user_name); + if (group_name) + free(group_name); + return authorized; +} + + +//---------------------------------------------------------------------- +// open_dir_get_search_node_ref +//---------------------------------------------------------------------- +static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, + tDirNodeReference *searchNodeRef, unsigned long *count) +{ + tDirStatus dsResult = -1; + tDataBufferPtr searchNodeDataBufferPtr = 0; + tDataListPtr searchNodeNameDataListPtr = 0; + + unsigned long outNodeCount; + tContextData continueData = 0; + + *searchNodeRef = 0; + *count = 0; + + // allocate required buffers and data lists + if ((searchNodeDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); + goto cleanup; + } + if ((searchNodeNameDataListPtr = dsDataListAllocate(dirRef)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + + // find authentication search node(s) + if ((dsResult = dsFindDirNodes(dirRef, searchNodeDataBufferPtr, 0, eDSAuthenticationSearchNodeName, + &outNodeCount, &continueData)) == eDSNoErr) { + if (outNodeCount != 0) { + + // get the seach node name and open the node + if ((dsResult = dsGetDirNodeName(dirRef, searchNodeDataBufferPtr, index, + &searchNodeNameDataListPtr)) == eDSNoErr) { + if ((dsResult = dsOpenDirNode(dirRef, searchNodeNameDataListPtr, searchNodeRef)) == eDSNoErr) { + *count = outNodeCount; + } + } + } + if (continueData) + dsReleaseContinueData(dirRef, continueData); + } + +cleanup: + if (searchNodeDataBufferPtr) + dsDataBufferDeAllocate(dirRef, searchNodeDataBufferPtr); + if (searchNodeNameDataListPtr) + dsDataListDeallocate(dirRef, searchNodeNameDataListPtr); + + return dsResult; +} + +//---------------------------------------------------------------------- +// open_dir_get_user_attr +//---------------------------------------------------------------------- +static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, + char *attr, tAttributeValueEntryPtr *attr_value) +{ + + tDirStatus dsResult = -1; + + tDataBufferPtr userRcdDataBufferPtr = 0; + tDataListPtr recordNameDataListPtr = 0; + tDataListPtr recordTypeDataListPtr = 0; + tDataListPtr attrTypeDataListPtr = 0; + tContextData continueData = 0; + + unsigned long outRecordCount; + int userRcdFound = 0; + u_int32_t userRecordIndex, attrIndex; + + *attr_value = 0; + + if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); + goto cleanup; + } + if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, user_name, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSNAttrRecordName, kDS1AttrDistinguishedName, attr, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + + // find the user record(s), extracting the user name and requested attribute + do { + dsResult = dsGetRecordList(searchNodeRef, userRcdDataBufferPtr, recordNameDataListPtr, eDSExact, + recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData); + + // if buffer too small - allocate a larger one + if (dsResult == eDSBufferTooSmall) { + u_int32_t size = userRcdDataBufferPtr->fBufferSize * 2; + + dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr); + if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); + dsResult = -1; + goto cleanup; + } + } + } while (dsResult == eDSBufferTooSmall); + + if (dsResult == eDSNoErr) { + // for each user record + for (userRecordIndex = 1; (userRecordIndex <= outRecordCount) && (dsResult == eDSNoErr) + && (userRcdFound == 0); userRecordIndex++) { + + tAttributeListRef attrListRef; + tRecordEntryPtr userRcdEntryPtr; + + // get the user record entry from the data buffer + if ((dsResult = dsGetRecordEntry(searchNodeRef, userRcdDataBufferPtr, userRecordIndex, + &attrListRef, &userRcdEntryPtr)) == eDSNoErr) { + // for each attribute + for (attrIndex = 1; (attrIndex <= userRcdEntryPtr->fRecordAttributeCount) + && (dsResult == eDSNoErr); attrIndex++) { + + tAttributeValueListRef attrValueListRef; + tAttributeEntryPtr attrInfoPtr; + tAttributeValueEntryPtr attrValuePtr; + + if ((dsResult = dsGetAttributeEntry(searchNodeRef, userRcdDataBufferPtr, + attrListRef, attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) { + if ((dsResult = dsGetAttributeValue(searchNodeRef, userRcdDataBufferPtr, 1, + attrValueListRef, &attrValuePtr)) == eDSNoErr) { + + // check for user record name or attribute searching for + if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrRecordName)) { + if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) + userRcdFound = 1; + } + if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrDistinguishedName)) { + if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) + userRcdFound = 1; + } + if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, attr)) { + *attr_value = attrValuePtr; // return the attribute value + attrValuePtr = 0; // set to zero so we don't deallocate it + } + if (attrValuePtr) + dsDeallocAttributeValueEntry(dirRef, attrValuePtr); + } + dsCloseAttributeValueList(attrValueListRef); + dsDeallocAttributeEntry(dirRef, attrInfoPtr); + } + } + // make sure we've processed both attributes and we have a match on user name + if(userRcdFound == 0 || *attr_value == 0) { + userRcdFound = 0; + if (*attr_value) + dsDeallocAttributeValueEntry(dirRef, *attr_value); + *attr_value = 0; + } + dsCloseAttributeList(attrListRef); + dsDeallocRecordEntry(dirRef, userRcdEntryPtr); + } + } + } + +cleanup: + if (continueData) + dsReleaseContinueData(searchNodeRef, continueData); + if (userRcdDataBufferPtr) + dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr); + if (recordNameDataListPtr) + dsDataListDeallocate(dirRef, recordNameDataListPtr); + if (recordTypeDataListPtr) + dsDataListDeallocate(dirRef, recordTypeDataListPtr); + if (attrTypeDataListPtr) + dsDataListDeallocate(dirRef, attrTypeDataListPtr); + + return dsResult; + +} + + +//---------------------------------------------------------------------- +// open_dir_check_group_membership +//---------------------------------------------------------------------- +static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, + char *group_name, char *user_name, char *userGID, int *authorized) +{ + tDirStatus dsResult = -1; + + tDataBufferPtr groupRcdDataBufferPtr = 0; + tDataListPtr recordNameDataListPtr = 0; + tDataListPtr recordTypeDataListPtr = 0; + tDataListPtr attrTypeDataListPtr = 0; + tContextData continueData = 0; + + unsigned long outRecordCount; + u_int32_t attrIndex, valueIndex; + + *authorized = 0; + + if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); + goto cleanup; + } + if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, group_name, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeGroups, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDS1AttrPrimaryGroupID, kDSNAttrGroupMembership, 0)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); + goto cleanup; + } + + // find the group record, extracting the group ID and group membership attribute + do { + dsResult = dsGetRecordList(searchNodeRef, groupRcdDataBufferPtr, recordNameDataListPtr, eDSExact, + recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData); + // if buffer too small - allocate a larger one + if (dsResult == eDSBufferTooSmall) { + u_int32_t size = groupRcdDataBufferPtr->fBufferSize * 2; + + dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr); + if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); + dsResult = -1; + goto cleanup; + } + } + } while (dsResult == eDSBufferTooSmall); + + if (dsResult == eDSNoErr) { + + tAttributeListRef attrListRef; + tRecordEntryPtr groupRcdEntryPtr; + + // get the group record entry + if ((dsResult = dsGetRecordEntry(searchNodeRef, groupRcdDataBufferPtr, 1, &attrListRef, &groupRcdEntryPtr)) == eDSNoErr) { + + // for each attribute + for (attrIndex = 1; (attrIndex <= groupRcdEntryPtr->fRecordAttributeCount) && (dsResult == eDSNoErr) + && (*authorized == 0); attrIndex++) { + + tAttributeValueListRef attrValueListRef; + tAttributeEntryPtr attrInfoPtr; + tAttributeValueEntryPtr attrValuePtr; + + if ((dsResult = dsGetAttributeEntry(searchNodeRef, groupRcdDataBufferPtr, attrListRef, + attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) { + + // group ID attribute ? + if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrPrimaryGroupID)) { + if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, 1, + attrValueListRef, &attrValuePtr)) == eDSNoErr) { + + // check for match on primary group ID + if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, userGID)) + *authorized = 1; + dsDeallocAttributeValueEntry(dirRef, attrValuePtr); + } + } else if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrGroupMembership)) { + // for each value check for user's name in the group + for (valueIndex = 1; (valueIndex <= attrInfoPtr->fAttributeValueCount) + && (dsResult == eDSNoErr) && (*authorized == 0); valueIndex++) { + + if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, + valueIndex, attrValueListRef, &attrValuePtr)) == eDSNoErr) { + if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) + *authorized = 1; + dsDeallocAttributeValueEntry(dirRef, attrValuePtr); + } + } + } + dsCloseAttributeValueList(attrValueListRef); + dsDeallocAttributeEntry(dirRef, attrInfoPtr); + } + } + dsCloseAttributeList(attrListRef); + dsDeallocRecordEntry(dirRef, groupRcdEntryPtr); + } + } + +cleanup: + if (continueData) + dsReleaseContinueData(searchNodeRef, continueData); + if (groupRcdDataBufferPtr) + dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr); + if (recordNameDataListPtr) + dsDataListDeallocate(dirRef, recordNameDataListPtr); + if (recordTypeDataListPtr) + dsDataListDeallocate(dirRef, recordTypeDataListPtr); + if (attrTypeDataListPtr) + dsDataListDeallocate(dirRef, attrTypeDataListPtr); + + return dsResult; +} + diff --git a/ipsec-tools/racoon/open_dir.h b/ipsec-tools/racoon/open_dir.h new file mode 100644 index 0000000..89f1f2c --- /dev/null +++ b/ipsec-tools/racoon/open_dir.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __OPEN_DIR_H__ +#define __OPEN_DIR_H__ + +extern int open_dir_authorize_id(vchar_t *id, vchar_t *group); + + +#endif /* __OPEN_DIR_H__ */ + diff --git a/ipsec-tools/racoon/pfkey.h b/ipsec-tools/racoon/pfkey.h new file mode 100644 index 0000000..62aede2 --- /dev/null +++ b/ipsec-tools/racoon/pfkey.h @@ -0,0 +1,75 @@ +/* $Id: pfkey.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PFKEY_H +#define _PFKEY_H + +struct pfkey_satype { + u_int8_t ps_satype; + const char *ps_name; +}; + +extern const struct pfkey_satype pfkey_satypes[]; +extern const int pfkey_nsatypes; + +extern int pfkey_handler __P((void)); +extern vchar_t *pfkey_dump_sadb __P((int)); +extern void pfkey_flush_sadb __P((u_int)); +extern int pfkey_init __P((void)); + +extern struct pfkey_st *pfkey_getpst __P((caddr_t *, int, int)); + +extern int pk_checkalg __P((int, int, int)); + +struct ph2handle; +extern int pk_sendgetspi __P((struct ph2handle *)); +extern int pk_sendupdate __P((struct ph2handle *)); +extern int pk_sendadd __P((struct ph2handle *)); +extern int pk_sendeacquire __P((struct ph2handle *)); +extern int pk_sendspdupdate2 __P((struct ph2handle *)); +extern int pk_sendspdadd2 __P((struct ph2handle *)); +extern int pk_sendspddelete __P((struct ph2handle *)); + +extern void pfkey_timeover_stub __P((void *)); +extern void pfkey_timeover __P((struct ph2handle *)); + +extern u_int pfkey2ipsecdoi_proto __P((u_int)); +extern u_int ipsecdoi2pfkey_proto __P((u_int)); +extern u_int pfkey2ipsecdoi_mode __P((u_int)); +extern u_int ipsecdoi2pfkey_mode __P((u_int)); + +extern int pfkey_convertfromipsecdoi __P(( u_int, u_int, u_int, + u_int *, u_int *, u_int *, u_int *, u_int *)); +extern u_int32_t pk_getseq __P((void)); +extern const char *sadbsecas2str + __P((struct sockaddr *, struct sockaddr *, int, u_int32_t, int)); + +#endif /* _PFKEY_H */ diff --git a/ipsec-tools/racoon/pfkey_racoon.c b/ipsec-tools/racoon/pfkey_racoon.c new file mode 100644 index 0000000..7152a4e --- /dev/null +++ b/ipsec-tools/racoon/pfkey_racoon.c @@ -0,0 +1,3037 @@ +/* $Id: pfkey.c,v 1.31.2.10 2005/10/03 14:52:19 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#ifdef ENABLE_NATT +# ifdef __linux__ +# include +# endif +# if defined(__NetBSD__) || defined(__FreeBSD__) +# include +# endif +#endif + +#include +#include +#include +#include +#include + +#include +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_inf.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "pfkey.h" +#include "handler.h" +#include "policy.h" +#include "algorithm.h" +#include "sainfo.h" +#include "proposal.h" +#include "admin.h" +#include "privsep.h" +#include "strnames.h" +#include "backupsa.h" +#include "gcmalloc.h" +#include "nattraversal.h" +#include "crypto_openssl.h" +#include "grabmyaddr.h" +#include "vpn_control.h" +#include "vpn_control_var.h" + +#if defined(SADB_X_EALG_RIJNDAELCBC) && !defined(SADB_X_EALG_AESCBC) +#define SADB_X_EALG_AESCBC SADB_X_EALG_RIJNDAELCBC +#endif + +/* prototype */ +static u_int ipsecdoi2pfkey_aalg __P((u_int)); +static u_int ipsecdoi2pfkey_ealg __P((u_int)); +static u_int ipsecdoi2pfkey_calg __P((u_int)); +static u_int ipsecdoi2pfkey_alg __P((u_int, u_int)); +static u_int keylen_aalg __P((u_int)); +static u_int keylen_ealg __P((u_int, int)); + +static int pk_recvgetspi __P((caddr_t *)); +static int pk_recvupdate __P((caddr_t *)); +static int pk_recvadd __P((caddr_t *)); +static int pk_recvdelete __P((caddr_t *)); +static int pk_recvacquire __P((caddr_t *)); +static int pk_recvexpire __P((caddr_t *)); +static int pk_recvflush __P((caddr_t *)); +static int getsadbpolicy __P((caddr_t *, int *, int, struct ph2handle *)); +static int pk_recvspdupdate __P((caddr_t *)); +static int pk_recvspdadd __P((caddr_t *)); +static int pk_recvspddelete __P((caddr_t *)); +static int pk_recvspdexpire __P((caddr_t *)); +static int pk_recvspdget __P((caddr_t *)); +static int pk_recvspddump __P((caddr_t *)); +static int pk_recvspdflush __P((caddr_t *)); +static struct sadb_msg *pk_recv __P((int, int *)); + +static int (*pkrecvf[]) __P((caddr_t *)) = { +NULL, +pk_recvgetspi, +pk_recvupdate, +pk_recvadd, +pk_recvdelete, +NULL, /* SADB_GET */ +pk_recvacquire, +NULL, /* SABD_REGISTER */ +pk_recvexpire, +pk_recvflush, +NULL, /* SADB_DUMP */ +NULL, /* SADB_X_PROMISC */ +NULL, /* SADB_X_PCHANGE */ +pk_recvspdupdate, +pk_recvspdadd, +pk_recvspddelete, +pk_recvspdget, +NULL, /* SADB_X_SPDACQUIRE */ +pk_recvspddump, +pk_recvspdflush, +NULL, /* SADB_X_SPDSETIDX */ +pk_recvspdexpire, +NULL, /* SADB_X_SPDDELETE2 */ +NULL, /* SADB_X_NAT_T_NEW_MAPPING */ +NULL, /* SADB_X_MIGRATE */ +#if (SADB_MAX > 24) +#error "SADB extra message?" +#endif +}; + +static int addnewsp __P((caddr_t *)); + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +/* + * PF_KEY packet handler + * 0: success + * -1: fail + */ +int +pfkey_handler() +{ + struct sadb_msg *msg; + int len; + caddr_t mhp[SADB_EXT_MAX + 1]; + int error = -1; + + /* receive pfkey message. */ + len = 0; + msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len); + if (msg == NULL) { + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv from pfkey (%s)\n", + strerror(errno)); + goto end; + } else { + /* short message - msg not ready */ + return 0; + } + } + + plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n", + s_pfkey_type(msg->sadb_msg_type)); + plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3); + + /* validity check */ + if (msg->sadb_msg_errno) { + int pri; + + /* when SPD is empty, treat the state as no error. */ + if (msg->sadb_msg_type == SADB_X_SPDDUMP && + msg->sadb_msg_errno == ENOENT) + pri = LLV_DEBUG; + else + pri = LLV_ERROR; + + plog(pri, LOCATION, NULL, + "pfkey %s failed: %s\n", + s_pfkey_type(msg->sadb_msg_type), + strerror(msg->sadb_msg_errno)); + + goto end; + } + + /* check pfkey message. */ + if (pfkey_align(msg, mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey align (%s)\n", + ipsec_strerror()); + goto end; + } + if (pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey check (%s)\n", + ipsec_strerror()); + goto end; + } + msg = (struct sadb_msg *)mhp[0]; + + /* safety check */ + if (msg->sadb_msg_type >= ARRAYLEN(pkrecvf)) { + plog(LLV_ERROR, LOCATION, NULL, + "unknown PF_KEY message type=%u\n", + msg->sadb_msg_type); + goto end; + } + + if (pkrecvf[msg->sadb_msg_type] == NULL) { + plog(LLV_INFO, LOCATION, NULL, + "unsupported PF_KEY message %s\n", + s_pfkey_type(msg->sadb_msg_type)); + goto end; + } + + if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0) + goto end; + + error = 0; +end: + if (msg) + racoon_free(msg); + return(error); +} + +/* + * dump SADB + */ +vchar_t * +pfkey_dump_sadb(satype) + int satype; +{ + int s = -1; + vchar_t *buf = NULL; + pid_t pid = getpid(); + struct sadb_msg *msg = NULL; + size_t bl, ml; + int len; + + if ((s = privsep_pfkey_open()) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey open: %s\n", + ipsec_strerror()); + return NULL; + } + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n"); + if (pfkey_send_dump(s, satype) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed dump: %s\n", ipsec_strerror()); + goto fail; + } + + while (1) { + if (msg) + racoon_free(msg); + msg = pk_recv(s, &len); + if (msg == NULL) { + if (len < 0) + goto done; + else + continue; + } + + if (msg->sadb_msg_type != SADB_DUMP || msg->sadb_msg_pid != pid) + continue; + + ml = msg->sadb_msg_len << 3; + bl = buf ? buf->l : 0; + buf = vrealloc(buf, bl + ml); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to reallocate buffer to dump.\n"); + goto fail; + } + memcpy(buf->v + bl, msg, ml); + + if (msg->sadb_msg_seq == 0) + break; + } + goto done; + +fail: + if (buf) + vfree(buf); + buf = NULL; +done: + if (msg) + racoon_free(msg); + if (s >= 0) + privsep_pfkey_close(s); + return buf; +} + +#ifdef ENABLE_ADMINPORT +/* + * flush SADB + */ +void +pfkey_flush_sadb(proto) + u_int proto; +{ + int satype; + + /* convert to SADB_SATYPE */ + if ((satype = admin2pfkey_proto(proto)) < 0) + return; + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_flush\n"); + if (pfkey_send_flush(lcconf->sock_pfkey, satype) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send flush (%s)\n", ipsec_strerror()); + return; + } + + return; +} +#endif + +/* + * These are the SATYPEs that we manage. We register to get + * PF_KEY messages related to these SATYPEs, and we also use + * this list to determine which SATYPEs to delete SAs for when + * we receive an INITIAL-CONTACT. + */ +const struct pfkey_satype pfkey_satypes[] = { + { SADB_SATYPE_AH, "AH" }, + { SADB_SATYPE_ESP, "ESP" }, + { SADB_X_SATYPE_IPCOMP, "IPCOMP" }, +}; +const int pfkey_nsatypes = + sizeof(pfkey_satypes) / sizeof(pfkey_satypes[0]); + +/* + * PF_KEY initialization + */ +int +pfkey_init() +{ + int i, reg_fail; + + if ((lcconf->sock_pfkey = privsep_pfkey_open()) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey open (%s)\n", ipsec_strerror()); + return -1; + } + + for (i = 0, reg_fail = 0; i < pfkey_nsatypes; i++) { + plog(LLV_DEBUG, LOCATION, NULL, + "call pfkey_send_register for %s\n", + pfkey_satypes[i].ps_name); + if (pfkey_send_register(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype) < 0 || + pfkey_recv_register(lcconf->sock_pfkey) < 0) { + plog(LLV_WARNING, LOCATION, NULL, + "failed to register %s (%s)\n", + pfkey_satypes[i].ps_name, + ipsec_strerror()); + reg_fail++; + } + } + + if (reg_fail == pfkey_nsatypes) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to regist any protocol.\n"); + pfkey_close(lcconf->sock_pfkey); + return -1; + } + + initsp(); + + if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec sending spddump failed: %s\n", + ipsec_strerror()); + pfkey_close(lcconf->sock_pfkey); + return -1; + } +#if 0 + if (pfkey_promisc_toggle(1) < 0) { + pfkey_close(lcconf->sock_pfkey); + return -1; + } +#endif + return 0; +} + +/* %%% for conversion */ +/* IPSECDOI_ATTR_AUTH -> SADB_AALG */ +static u_int +ipsecdoi2pfkey_aalg(hashtype) + u_int hashtype; +{ + switch (hashtype) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + return SADB_AALG_MD5HMAC; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + return SADB_AALG_SHA1HMAC; + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256: +#if (defined SADB_X_AALG_SHA2_256) && !defined(SADB_X_AALG_SHA2_256HMAC) + return SADB_X_AALG_SHA2_256; +#else + return SADB_X_AALG_SHA2_256HMAC; +#endif + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384: +#if (defined SADB_X_AALG_SHA2_384) && !defined(SADB_X_AALG_SHA2_384HMAC) + return SADB_X_AALG_SHA2_384; +#else + return SADB_X_AALG_SHA2_384HMAC; +#endif + case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512: +#if (defined SADB_X_AALG_SHA2_512) && !defined(SADB_X_AALG_SHA2_512HMAC) + return SADB_X_AALG_SHA2_512; +#else + return SADB_X_AALG_SHA2_512HMAC; +#endif + case IPSECDOI_ATTR_AUTH_KPDK: /* need special care */ + return SADB_AALG_NONE; + + /* not supported */ + case IPSECDOI_ATTR_AUTH_DES_MAC: + plog(LLV_ERROR, LOCATION, NULL, + "Not supported hash type: %u\n", hashtype); + return ~0; + + case 0: /* reserved */ + default: + return SADB_AALG_NONE; + + plog(LLV_ERROR, LOCATION, NULL, + "Invalid hash type: %u\n", hashtype); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ESP -> SADB_EALG */ +static u_int +ipsecdoi2pfkey_ealg(t_id) + u_int t_id; +{ + switch (t_id) { + case IPSECDOI_ESP_DES_IV64: /* sa_flags |= SADB_X_EXT_OLD */ + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_DES: + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_3DES: + return SADB_EALG_3DESCBC; +#ifdef SADB_X_EALG_RC5CBC + case IPSECDOI_ESP_RC5: + return SADB_X_EALG_RC5CBC; +#endif + case IPSECDOI_ESP_CAST: + return SADB_X_EALG_CAST128CBC; + case IPSECDOI_ESP_BLOWFISH: + return SADB_X_EALG_BLOWFISHCBC; + case IPSECDOI_ESP_DES_IV32: /* flags |= (SADB_X_EXT_OLD| + SADB_X_EXT_IV4B)*/ + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_NULL: + return SADB_EALG_NULL; +#ifdef SADB_X_EALG_AESCBC + case IPSECDOI_ESP_AES: + return SADB_X_EALG_AESCBC; +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + case IPSECDOI_ESP_TWOFISH: + return SADB_X_EALG_TWOFISHCBC; +#endif + + /* not supported */ + case IPSECDOI_ESP_3IDEA: + case IPSECDOI_ESP_IDEA: + case IPSECDOI_ESP_RC4: + plog(LLV_ERROR, LOCATION, NULL, + "Not supported transform: %u\n", t_id); + return ~0; + + case 0: /* reserved */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid transform id: %u\n", t_id); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPCOMP -> SADB_CALG */ +static u_int +ipsecdoi2pfkey_calg(t_id) + u_int t_id; +{ + switch (t_id) { + case IPSECDOI_IPCOMP_OUI: + return SADB_X_CALG_OUI; + case IPSECDOI_IPCOMP_DEFLATE: + return SADB_X_CALG_DEFLATE; + case IPSECDOI_IPCOMP_LZS: + return SADB_X_CALG_LZS; + + case 0: /* reserved */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid transform id: %u\n", t_id); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_PROTO -> SADB_SATYPE */ +u_int +ipsecdoi2pfkey_proto(proto) + u_int proto; +{ + switch (proto) { + case IPSECDOI_PROTO_IPSEC_AH: + return SADB_SATYPE_AH; + case IPSECDOI_PROTO_IPSEC_ESP: + return SADB_SATYPE_ESP; + case IPSECDOI_PROTO_IPCOMP: + return SADB_X_SATYPE_IPCOMP; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ipsec_doi proto: %u\n", proto); + return ~0; + } + /*NOTREACHED*/ +} + +static u_int +ipsecdoi2pfkey_alg(algclass, type) + u_int algclass, type; +{ + switch (algclass) { + case IPSECDOI_ATTR_AUTH: + return ipsecdoi2pfkey_aalg(type); + case IPSECDOI_PROTO_IPSEC_ESP: + return ipsecdoi2pfkey_ealg(type); + case IPSECDOI_PROTO_IPCOMP: + return ipsecdoi2pfkey_calg(type); + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ipsec_doi algclass: %u\n", algclass); + return ~0; + } + /*NOTREACHED*/ +} + +/* SADB_SATYPE -> IPSECDOI_PROTO */ +u_int +pfkey2ipsecdoi_proto(satype) + u_int satype; +{ + switch (satype) { + case SADB_SATYPE_AH: + return IPSECDOI_PROTO_IPSEC_AH; + case SADB_SATYPE_ESP: + return IPSECDOI_PROTO_IPSEC_ESP; + case SADB_X_SATYPE_IPCOMP: + return IPSECDOI_PROTO_IPCOMP; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid pfkey proto: %u\n", satype); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ +u_int +ipsecdoi2pfkey_mode(mode) + u_int mode; +{ + switch (mode) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: +#ifdef ENABLE_NATT + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT: +#endif + return IPSEC_MODE_TUNNEL; + case IPSECDOI_ATTR_ENC_MODE_TRNS: +#ifdef ENABLE_NATT + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT: +#endif + return IPSEC_MODE_TRANSPORT; + default: + plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ +u_int +pfkey2ipsecdoi_mode(mode) + u_int mode; +{ + switch (mode) { + case IPSEC_MODE_TUNNEL: + return IPSECDOI_ATTR_ENC_MODE_TUNNEL; + case IPSEC_MODE_TRANSPORT: + return IPSECDOI_ATTR_ENC_MODE_TRNS; + case IPSEC_MODE_ANY: + return IPSECDOI_ATTR_ENC_MODE_ANY; + default: + plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); + return ~0; + } + /*NOTREACHED*/ +} + +/* default key length for encryption algorithm */ +static u_int +keylen_aalg(hashtype) + u_int hashtype; +{ + int res; + + if (hashtype == 0) + return SADB_AALG_NONE; + + res = alg_ipsec_hmacdef_hashlen(hashtype); + if (res == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hmac algorithm %u.\n", hashtype); + return ~0; + } + return res; +} + +/* default key length for encryption algorithm */ +static u_int +keylen_ealg(enctype, encklen) + u_int enctype; + int encklen; +{ + int res; + + res = alg_ipsec_encdef_keylen(enctype, encklen); + if (res == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algorithm %u.\n", enctype); + return ~0; + } + return res; +} + +int +pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, + e_type, e_keylen, a_type, a_keylen, flags) + u_int proto_id; + u_int t_id; + u_int hashtype; + u_int *e_type; + u_int *e_keylen; + u_int *a_type; + u_int *a_keylen; + u_int *flags; +{ + *flags = 0; + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + if ((*e_type = ipsecdoi2pfkey_ealg(t_id)) == ~0) + goto bad; + if ((*e_keylen = keylen_ealg(t_id, *e_keylen)) == ~0) + goto bad; + *e_keylen >>= 3; + + if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) + goto bad; + if ((*a_keylen = keylen_aalg(hashtype)) == ~0) + goto bad; + *a_keylen >>= 3; + + if (*e_type == SADB_EALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no ESP algorithm.\n"); + goto bad; + } + break; + + case IPSECDOI_PROTO_IPSEC_AH: + if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) + goto bad; + if ((*a_keylen = keylen_aalg(hashtype)) == ~0) + goto bad; + *a_keylen >>= 3; + + if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 + && hashtype == IPSECDOI_ATTR_AUTH_KPDK) { + /* AH_MD5 + Auth(KPDK) = RFC1826 keyed-MD5 */ + *a_type = SADB_X_AALG_MD5; + *flags |= SADB_X_EXT_OLD; + } + *e_type = SADB_EALG_NONE; + *e_keylen = 0; + if (*a_type == SADB_AALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no AH algorithm.\n"); + goto bad; + } + break; + + case IPSECDOI_PROTO_IPCOMP: + if ((*e_type = ipsecdoi2pfkey_calg(t_id)) == ~0) + goto bad; + *e_keylen = 0; + + *flags = SADB_X_EXT_RAWCPI; + + *a_type = SADB_AALG_NONE; + *a_keylen = 0; + if (*e_type == SADB_X_CALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no IPCOMP algorithm.\n"); + goto bad; + } + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, "unknown IPsec protocol.\n"); + goto bad; + } + + return 0; + + bad: + errno = EINVAL; + return -1; +} + +/* called from scheduler */ +void +pfkey_timeover_stub(p) + void *p; +{ + + pfkey_timeover((struct ph2handle *)p); +} + +void +pfkey_timeover(iph2) + struct ph2handle *iph2; +{ + plog(LLV_ERROR, LOCATION, NULL, + "%s give up to get IPsec-SA due to time up to wait.\n", + saddrwop2str(iph2->dst)); + SCHED_KILL(iph2->sce); + + /* If initiator side, send error to kernel by SADB_ACQUIRE. */ + if (iph2->side == INITIATOR) + pk_sendeacquire(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return; +} + +/*%%%*/ +/* send getspi message per ipsec protocol per remote address */ +/* + * the local address and remote address in ph1handle are dealed + * with destination address and source address respectively. + * Because SPI is decided by responder. + */ +int +pk_sendgetspi(iph2) + struct ph2handle *iph2; +{ + struct sockaddr *src = NULL, *dst = NULL; + u_int satype, mode; + struct saprop *pp; + struct saproto *pr; + u_int32_t minspi, maxspi; + int proxy = 0; + + if (iph2->side == INITIATOR) { + pp = iph2->proposal; + proxy = iph2->ph1->rmconf->support_proxy; + } else { + pp = iph2->approval; + if (iph2->sainfo && iph2->sainfo->id_i) + proxy = 1; + } + + /* for mobile IPv6 */ + if (proxy && iph2->src_id && iph2->dst_id && + ipsecdoi_transportmode(pp)) { + src = iph2->src_id; + dst = iph2->dst_id; + } else { + src = iph2->src; + dst = iph2->dst; + } + + for (pr = pp->head; pr != NULL; pr = pr->next) { + + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } + /* this works around a bug in Linux kernel where it allocates 4 byte + spi's for IPCOMP */ + else if (satype == SADB_X_SATYPE_IPCOMP) { + minspi = 0x100; + maxspi = 0xffff; + } + else { + minspi = 0; + maxspi = 0; + } + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n"); + if (pfkey_send_getspi( + lcconf->sock_pfkey, + satype, + mode, + dst, /* src of SA */ + src, /* dst of SA */ + minspi, maxspi, + pr->reqid_in, iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ipseclib failed send getspi (%s)\n", + ipsec_strerror()); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey GETSPI sent: %s\n", + sadbsecas2str(dst, src, satype, 0, mode)); + } + + return 0; +} + +/* + * receive GETSPI from kernel. + */ +static int +pk_recvgetspi(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct ph2handle *iph2; + struct sockaddr *dst; + int proto_id; + int allspiok, notfound; + struct saprop *pp; + struct saproto *pr; + + /* validity check */ + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb getspi message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */ + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + if (iph2->status != PHASE2ST_GETSPISENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch (db:%d msg:%d)\n", + iph2->status, PHASE2ST_GETSPISENT); + return -1; + } + + /* set SPI, and check to get all spi whether or not */ + allspiok = 1; + notfound = 1; + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + pp = iph2->side == INITIATOR ? iph2->proposal : iph2->approval; + + for (pr = pp->head; pr != NULL; pr = pr->next) { + if (pr->proto_id == proto_id && pr->spi == 0) { + pr->spi = sa->sadb_sa_spi; + notfound = 0; + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey GETSPI succeeded: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, + sa->sadb_sa_spi, + ipsecdoi2pfkey_mode(pr->encmode))); + } + if (pr->spi == 0) + allspiok = 0; /* not get all spi */ + } + + if (notfound) { + plog(LLV_ERROR, LOCATION, NULL, + "get spi for unknown address %s\n", + saddrwop2str(iph2->dst)); + return -1; + } + + if (allspiok) { + /* update status */ + iph2->status = PHASE2ST_GETSPIDONE; + if (isakmp_post_getspi(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to start post getspi.\n"); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + iph2 = NULL; + return -1; + } + } + + return 0; +} + +/* + * set inbound SA + */ +int +pk_sendupdate(iph2) + struct ph2handle *iph2; +{ + struct saproto *pr; + struct sockaddr *src = NULL, *dst = NULL; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int satype, mode; + u_int64_t lifebyte = 0; + u_int wsize = 4; /* XXX static size of window */ + int proxy = 0; + struct ph2natt natt; + + /* sanity check */ + if (iph2->approval == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no approvaled SAs found.\n"); + } + + if (iph2->side == INITIATOR) + proxy = iph2->ph1->rmconf->support_proxy; + else if (iph2->sainfo && iph2->sainfo->id_i) + proxy = 1; + + /* for mobile IPv6 */ + if (proxy && iph2->src_id && iph2->dst_id && + ipsecdoi_transportmode(iph2->approval)) { + src = iph2->src_id; + dst = iph2->dst_id; + } else { + src = iph2->src; + dst = iph2->dst; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } + else if (satype == SADB_X_SATYPE_IPCOMP) { + /* IPCOMP has no replay window */ + wsize = 0; + } +#ifdef ENABLE_SAMODE_UNSPECIFIED + mode = IPSEC_MODE_ANY; +#else + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } +#endif + + /* set algorithm type and key length */ + e_keylen = pr->head->encklen; + if (pfkey_convertfromipsecdoi( + pr->proto_id, + pr->head->trns_id, + pr->head->authtype, + &e_type, &e_keylen, + &a_type, &a_keylen, &flags) < 0) + return -1; + +#if 0 + lifebyte = iph2->approval->lifebyte * 1024, +#else + lifebyte = 0; +#endif + +#ifdef __APPLE__ +#ifdef ENABLE_NATT + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n"); + if (pr->udp_encap) { + memset (&natt, 0, sizeof (natt)); + natt.sport = extract_port (iph2->ph1->remote); + flags |= SADB_X_EXT_NATT; + if (iph2->ph1->natt_flags & NAT_DETECTED_ME) + flags |= SADB_X_EXT_NATT_KEEPALIVE; + else if (iph2->ph1->rmconf->natt_multiple_user == TRUE && + mode == IPSEC_MODE_TRANSPORT && + src->sa_family == AF_INET) + flags |= SADB_X_EXT_NATT_MULTIPLEUSERS; + } else { + memset (&natt, 0, sizeof (natt)); + } + + if (pfkey_send_update( + lcconf->sock_pfkey, + satype, + mode, + dst, + src, + pr->spi, + pr->reqid_in, + wsize, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq, natt.sport) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send update (%s)\n", + ipsec_strerror()); + return -1; + } +#else + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n"); + if (pfkey_send_update( + lcconf->sock_pfkey, + satype, + mode, + dst, + src, + pr->spi, + pr->reqid_in, + wsize, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send update (%s)\n", + ipsec_strerror()); + return -1; + } +#endif /* ENABLE_NATT */ +#else +#ifdef ENABLE_NATT + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update_nat\n"); + if (pr->udp_encap) { + memset (&natt, 0, sizeof (natt)); + natt.type = iph2->ph1->natt_options->encaps_type; + natt.sport = extract_port (iph2->ph1->remote); + natt.dport = extract_port (iph2->ph1->local); + natt.oa = NULL; // FIXME: Here comes OA!!! + natt.frag = iph2->ph1->rmconf->esp_frag; + } else { + memset (&natt, 0, sizeof (natt)); + } + + if (pfkey_send_update_nat( + lcconf->sock_pfkey, + satype, + mode, + dst, + src, + pr->spi, + pr->reqid_in, + wsize, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq, + natt.type, natt.sport, natt.dport, natt.oa, + natt.frag) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send update_nat (%s)\n", + ipsec_strerror()); + return -1; + } +#else + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n"); + if (pfkey_send_update( + lcconf->sock_pfkey, + satype, + mode, + dst, + src, + pr->spi, + pr->reqid_in, + wsize, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send update (%s)\n", + ipsec_strerror()); + return -1; + } +#endif /* ENABLE_NATT */ +#endif /* __APPLE__ */ + + if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) + continue; + + /* + * It maybe good idea to call backupsa_to_file() after + * racoon will receive the sadb_update messages. + * But it is impossible because there is not key in the + * information from the kernel. + */ + if (backupsa_to_file(satype, mode, dst, src, + pr->spi, pr->reqid_in, 4, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, iph2->approval->lifebyte * 1024, + iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "backuped SA failed: %s\n", + sadbsecas2str(dst, src, + satype, pr->spi, mode)); + } + plog(LLV_DEBUG, LOCATION, NULL, + "backuped SA: %s\n", + sadbsecas2str(dst, src, + satype, pr->spi, mode)); + } + + return 0; +} + +static int +pk_recvupdate(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int proto_id, encmode, sa_mode; + int incomplete = 0; + struct saproto *pr; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb update message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + if (iph2->status != PHASE2ST_ADDSA) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch (db:%d msg:%d)\n", + iph2->status, PHASE2ST_ADDSA); + return -1; + } + + /* check to complete all keys ? */ + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + encmode = pfkey2ipsecdoi_mode(sa_mode); + if (encmode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", sa_mode); + return -1; + } + + if (pr->proto_id == proto_id + && pr->spi == sa->sadb_sa_spi) { + pr->ok = 1; + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey UPDATE succeeded: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, + sa->sadb_sa_spi, + sa_mode)); + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA established: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, sa->sadb_sa_spi, + sa_mode)); + } + + if (pr->ok == 0) + incomplete = 1; + } + + if (incomplete) + return 0; + + /* turn off the timer for calling pfkey_timeover() */ + SCHED_KILL(iph2->sce); + + /* update status */ + iph2->status = PHASE2ST_ESTABLISHED; + +#ifdef ENABLE_STATS + gettimeofday(&iph2->end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", "quick", timedelta(&iph2->start, &iph2->end)); +#endif + + /* count up */ + iph2->ph1->ph2cnt++; + + /* turn off schedule */ + if (iph2->scr) + SCHED_KILL(iph2->scr); + + /* + * since we are going to reuse the phase2 handler, we need to + * remain it and refresh all the references between ph1 and ph2 to use. + */ + unbindph12(iph2); + + iph2->sce = sched_new(iph2->approval->lifetime, + isakmp_ph2expire_stub, iph2); + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + return 0; +} + +/* + * set outbound SA + */ +int +pk_sendadd(iph2) + struct ph2handle *iph2; +{ + struct saproto *pr; + struct sockaddr *src = NULL, *dst = NULL; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int satype, mode; + u_int64_t lifebyte = 0; + u_int wsize = 4; /* XXX static size of window */ + int proxy = 0; + struct ph2natt natt; + + /* sanity check */ + if (iph2->approval == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no approvaled SAs found.\n"); + } + + if (iph2->side == INITIATOR) + proxy = iph2->ph1->rmconf->support_proxy; + else if (iph2->sainfo && iph2->sainfo->id_i) + proxy = 1; + + /* for mobile IPv6 */ + if (proxy && iph2->src_id && iph2->dst_id && + ipsecdoi_transportmode(iph2->approval)) { + src = iph2->src_id; + dst = iph2->dst_id; + } else { + src = iph2->src; + dst = iph2->dst; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } + else if (satype == SADB_X_SATYPE_IPCOMP) { + /* no replay window for IPCOMP */ + wsize = 0; + } +#ifdef ENABLE_SAMODE_UNSPECIFIED + mode = IPSEC_MODE_ANY; +#else + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } +#endif + + /* set algorithm type and key length */ + e_keylen = pr->head->encklen; + if (pfkey_convertfromipsecdoi( + pr->proto_id, + pr->head->trns_id, + pr->head->authtype, + &e_type, &e_keylen, + &a_type, &a_keylen, &flags) < 0) + return -1; + +#if 0 + lifebyte = iph2->approval->lifebyte * 1024, +#else + lifebyte = 0; +#endif + +#ifdef __APPLE__ +#ifdef ENABLE_NATT + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n"); + + if (pr->udp_encap) { + memset (&natt, 0, sizeof (natt)); + natt.dport = extract_port (iph2->ph1->remote); + flags |= SADB_X_EXT_NATT; + if (iph2->ph1->natt_flags & NAT_DETECTED_ME) + flags |= SADB_X_EXT_NATT_KEEPALIVE; + else if (iph2->ph1->rmconf->natt_multiple_user == TRUE && + mode == IPSEC_MODE_TRANSPORT && + dst->sa_family == AF_INET) + flags |= SADB_X_EXT_NATT_MULTIPLEUSERS; + } else { + memset (&natt, 0, sizeof (natt)); + + /* Remove port information, that SA doesn't use it */ + //set_port(src, 0); + //set_port(dst, 0); + } + + if (pfkey_send_add( + lcconf->sock_pfkey, + satype, + mode, + src, + dst, + pr->spi_p, + pr->reqid_out, + wsize, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq,natt.dport) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send add (%s)\n", + ipsec_strerror()); + return -1; + } +#else + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n"); + + /* Remove port information, it is not used without NAT-T */ + //set_port(src, 0); + //set_port(dst, 0); + + if (pfkey_send_add( + lcconf->sock_pfkey, + satype, + mode, + src, + dst, + pr->spi_p, + pr->reqid_out, + wsize, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send add (%s)\n", + ipsec_strerror()); + return -1; + } +#endif /* ENABLE_NATT */ +#else /* __APPLE__ */ +#ifdef ENABLE_NATT + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add_nat\n"); + + if (pr->udp_encap) { + memset (&natt, 0, sizeof (natt)); + natt.type = UDP_ENCAP_ESPINUDP; + natt.sport = extract_port (iph2->ph1->local); + natt.dport = extract_port (iph2->ph1->remote); + natt.oa = NULL; // FIXME: Here comes OA!!! + natt.frag = iph2->ph1->rmconf->esp_frag; + } else { + memset (&natt, 0, sizeof (natt)); + + /* Remove port information, that SA doesn't use it */ + set_port(src, 0); + set_port(dst, 0); + } + + if (pfkey_send_add_nat( + lcconf->sock_pfkey, + satype, + mode, + src, + dst, + pr->spi_p, + pr->reqid_out, + wsize, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq, + natt.type, natt.sport, natt.dport, natt.oa, + natt.frag) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send add_nat (%s)\n", + ipsec_strerror()); + return -1; + } +#else + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n"); + + /* Remove port information, it is not used without NAT-T */ + set_port(src, 0); + set_port(dst, 0); + + if (pfkey_send_add( + lcconf->sock_pfkey, + satype, + mode, + src, + dst, + pr->spi_p, + pr->reqid_out, + wsize, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send add (%s)\n", + ipsec_strerror()); + return -1; + } +#endif /* ENABLE_NATT */ +#endif /* __APPLE__ */ + + if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) + continue; + + /* + * It maybe good idea to call backupsa_to_file() after + * racoon will receive the sadb_update messages. + * But it is impossible because there is not key in the + * information from the kernel. + */ + if (backupsa_to_file(satype, mode, src, dst, + pr->spi_p, pr->reqid_out, 4, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, iph2->approval->lifebyte * 1024, + iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "backuped SA failed: %s\n", + sadbsecas2str(src, dst, + satype, pr->spi_p, mode)); + } + plog(LLV_DEBUG, LOCATION, NULL, + "backuped SA: %s\n", + sadbsecas2str(src, dst, + satype, pr->spi_p, mode)); + } + + return 0; +} + +static int +pk_recvadd(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int sa_mode; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb add message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + /* + * NOTE don't update any status of phase2 handle + * because they must be updated by SADB_UPDATE message + */ + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA established: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); + +#ifdef ENABLE_VPNCONTROL_PORT + { + u_int32_t address; + + if (iph2->dst->sa_family == AF_INET) + address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr; + else + address = 0; + vpncontrol_notify_phase_change(0, FROM_LOCAL, NULL, iph2); + } +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + return 0; +} + +static int +pk_recvexpire(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int proto_id, sa_mode; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb expire message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA expired: %s\n", + sadbsecas2str(src, dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); + + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2 == NULL) { + /* + * Ignore it because two expire messages are come up. + * phase2 handler has been deleted already when 2nd message + * is received. + */ + plog(LLV_DEBUG, LOCATION, NULL, + "no such a SA found: %s\n", + sadbsecas2str(src, dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, + sa_mode)); + return 0; + } + if (iph2->status != PHASE2ST_ESTABLISHED) { + /* + * If the status is not equal to PHASE2ST_ESTABLISHED, + * racoon ignores this expire message. There are two reason. + * One is that the phase 2 probably starts because there is + * a potential that racoon receives the acquire message + * without receiving a expire message. Another is that racoon + * may receive the multiple expire messages from the kernel. + */ + plog(LLV_WARNING, LOCATION, NULL, + "the expire message is received " + "but the handler has not been established.\n"); + return 0; + } + + /* turn off the timer for calling isakmp_ph2expire() */ + SCHED_KILL(iph2->sce); + + iph2->status = PHASE2ST_EXPIRED; + + /* INITIATOR, begin phase 2 exchange. */ + /* allocate buffer for status management of pfkey message */ + if (iph2->side == INITIATOR) { + + initph2(iph2); + + /* update status for re-use */ + iph2->status = PHASE2ST_STATUS2; + + /* start isakmp initiation by using ident exchange */ + if (isakmp_post_acquire(iph2) < 0) { + plog(LLV_ERROR, LOCATION, iph2->dst, + "failed to begin ipsec sa " + "re-negotication.\n"); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + return -1; + } + + return 0; + /*NOTREACHED*/ + } + + /* If not received SADB_EXPIRE, INITIATOR delete ph2handle. */ + /* RESPONDER always delete ph2handle, keep silent. RESPONDER doesn't + * manage IPsec SA, so delete the list */ + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return 0; +} + +static int +pk_recvacquire(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_x_policy *xpl; + struct secpolicy *sp_out = NULL, *sp_in = NULL; +#define MAXNESTEDSA 5 /* XXX */ + struct ph2handle *iph2[MAXNESTEDSA]; + struct sockaddr *src, *dst; + int n; /* # of phase 2 handler */ + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb acquire message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + /* ignore if type is not IPSEC_POLICY_IPSEC */ + if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore ACQUIRE message. type is not IPsec.\n"); + return 0; + } + + /* ignore it if src is multicast address */ + { + struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if ((sa->sa_family == AF_INET + && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr))) +#ifdef INET6 + || (sa->sa_family == AF_INET6 + && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr)) +#endif + ) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore due to multicast address: %s.\n", + saddrwop2str(sa)); + return 0; + } + } + + /* ignore, if we do not listen on source address */ + { + /* reasons behind: + * - if we'll contact peer from address we do not listen - + * we will be unable to complete negotiation; + * - if we'll negotiate using address we're listening - + * remote peer will send packets to address different + * than one in the policy, so kernel will drop them; + * => therefore this acquire is not for us! --Aidas + */ + struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + struct myaddrs *p; + int do_listen = 0; + for (p = lcconf->myaddrs; p; p = p->next) { + if (!cmpsaddrwop(p->addr, sa)) { + do_listen = 1; + break; + } + } + + if (!do_listen) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore because do not listen on source address : %s.\n", + saddrwop2str(sa)); + return 0; + } + } + + /* + * If there is a phase 2 handler against the policy identifier in + * the acquire message, and if + * 1. its state is less than PHASE2ST_ESTABLISHED, then racoon + * should ignore such a acquire message because the phase 2 + * is just negotiating. + * 2. its state is equal to PHASE2ST_ESTABLISHED, then racoon + * has to prcesss such a acquire message because racoon may + * lost the expire message. + */ + iph2[0] = getph2byid(src, dst, xpl->sadb_x_policy_id); + if (iph2[0] != NULL) { + if (iph2[0]->status < PHASE2ST_ESTABLISHED) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore the acquire because ph2 found\n"); + return -1; + } + if (iph2[0]->status == PHASE2ST_EXPIRED) + iph2[0] = NULL; + /*FALLTHROUGH*/ + } + + /* search for proper policyindex */ + sp_out = getspbyspid(xpl->sadb_x_policy_id); + if (sp_out == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n", + xpl->sadb_x_policy_id); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx)); + + /* get inbound policy */ + { + struct policyindex spidx; + + spidx.dir = IPSEC_DIR_INBOUND; + memcpy(&spidx.src, &sp_out->spidx.dst, sizeof(spidx.src)); + memcpy(&spidx.dst, &sp_out->spidx.src, sizeof(spidx.dst)); + spidx.prefs = sp_out->spidx.prefd; + spidx.prefd = sp_out->spidx.prefs; + spidx.ul_proto = sp_out->spidx.ul_proto; + + sp_in = getsp(&spidx); + if (sp_in) { + plog(LLV_DEBUG, LOCATION, NULL, + "suitable inbound SP found: %s.\n", + spidx2str(&sp_in->spidx)); + } else { + plog(LLV_NOTIFY, LOCATION, NULL, + "no in-bound policy found: %s\n", + spidx2str(&spidx)); + } + } + + memset(iph2, 0, MAXNESTEDSA); + + n = 0; + + /* allocate a phase 2 */ + iph2[n] = newph2(); + if (iph2[n] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate phase2 entry.\n"); + return -1; + } + iph2[n]->side = INITIATOR; + iph2[n]->spid = xpl->sadb_x_policy_id; + iph2[n]->satype = msg->sadb_msg_satype; + iph2[n]->seq = msg->sadb_msg_seq; + iph2[n]->status = PHASE2ST_STATUS2; + + /* set end addresses of SA */ + iph2[n]->dst = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST])); + if (iph2[n]->dst == NULL) { + delph2(iph2[n]); + return -1; + } + iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC])); + if (iph2[n]->src == NULL) { + delph2(iph2[n]); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "new acquire %s\n", spidx2str(&sp_out->spidx)); + + /* get sainfo */ + { + vchar_t *idsrc, *iddst; + + idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src, + sp_out->spidx.prefs, sp_out->spidx.ul_proto); + if (idsrc == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp_out->spidx)); + delph2(iph2[n]); + return -1; + } + iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst, + sp_out->spidx.prefd, sp_out->spidx.ul_proto); + if (iddst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp_out->spidx)); + vfree(idsrc); + delph2(iph2[n]); + return -1; + } + iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL); + vfree(idsrc); + vfree(iddst); + if (iph2[n]->sainfo == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + delph2(iph2[n]); + return -1; + /* XXX should use the algorithm list from register message */ + } + } + + if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to create saprop.\n"); + delph2(iph2[n]); + return -1; + } + insph2(iph2[n]); + + /* start isakmp initiation by using ident exchange */ + /* XXX should be looped if there are multiple phase 2 handler. */ + if (isakmp_post_acquire(iph2[n]) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to begin ipsec sa negotication.\n"); + goto err; + } + + return 0; + +err: + while (n >= 0) { + unbindph12(iph2[n]); + remph2(iph2[n]); + delph2(iph2[n]); + iph2[n] = NULL; + n--; + } + return -1; +} + +static int +pk_recvdelete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2 = NULL; + u_int proto_id; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb delete message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid == getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because the message was originated by me.\n", + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2 == NULL) { + /* ignore */ + plog(LLV_ERROR, LOCATION, NULL, + "no iph2 found: %s\n", + sadbsecas2str(src, dst, msg->sadb_msg_satype, + sa->sadb_sa_spi, IPSEC_MODE_ANY)); + return 0; + } + + plog(LLV_ERROR, LOCATION, NULL, + "pfkey DELETE received: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, IPSEC_MODE_ANY)); + + /* send delete information */ + if (iph2->status == PHASE2ST_ESTABLISHED) + isakmp_info_send_d2(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return 0; +} + +static int +pk_recvflush(mhp) + caddr_t *mhp; +{ + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb flush message passed.\n"); + return -1; + } + + flushph2(); + + return 0; +} + +static int +getsadbpolicy(policy0, policylen0, type, iph2) + caddr_t *policy0; + int *policylen0, type; + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + struct sadb_x_policy *xpl; + struct sadb_x_ipsecrequest *xisr; + struct saproto *pr; + caddr_t policy, p; + int policylen; + int xisrlen; + u_int satype, mode; + + /* get policy buffer size */ + policylen = sizeof(struct sadb_x_policy); + if (type != SADB_X_SPDDELETE) { + for (pr = iph2->approval->head; pr; pr = pr->next) { + xisrlen = sizeof(*xisr); + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { + xisrlen += (sysdep_sa_len(iph2->src) + + sysdep_sa_len(iph2->dst)); + } + + policylen += PFKEY_ALIGN8(xisrlen); + } + } + + /* make policy structure */ + policy = racoon_malloc(policylen); + if (!policy) { + plog(LLV_ERROR, LOCATION, NULL, + "buffer allocation failed.\n"); + return -1; + } + + xpl = (struct sadb_x_policy *)policy; + xpl->sadb_x_policy_len = PFKEY_UNIT64(policylen); + xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC; + xpl->sadb_x_policy_dir = spidx->dir; + xpl->sadb_x_policy_id = 0; +#ifdef HAVE_PFKEY_POLICY_PRIORITY + xpl->sadb_x_policy_priority = PRIORITY_DEFAULT; +#endif + + /* no need to append policy information any more if type is SPDDELETE */ + if (type == SADB_X_SPDDELETE) + goto end; + + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + for (pr = iph2->approval->head; pr; pr = pr->next) { + + satype = doi2ipproto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + goto err; + } + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + goto err; + } + + /* + * the policy level cannot be unique because the policy + * is defined later than SA, so req_id cannot be bound to SA. + */ + xisr->sadb_x_ipsecrequest_proto = satype; + xisr->sadb_x_ipsecrequest_mode = mode; + xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; + xisr->sadb_x_ipsecrequest_reqid = 0; + p = (caddr_t)(xisr + 1); + + xisrlen = sizeof(*xisr); + + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { + int src_len, dst_len; + + src_len = sysdep_sa_len(iph2->src); + dst_len = sysdep_sa_len(iph2->dst); + xisrlen += src_len + dst_len; + + memcpy(p, iph2->src, src_len); + p += src_len; + + memcpy(p, iph2->dst, dst_len); + p += dst_len; + } + + xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen); + } + +end: + *policy0 = policy; + *policylen0 = policylen; + + return 0; + +err: + if (policy) + racoon_free(policy); + + return -1; +} + +int +pk_sendspdupdate2(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen = 0; + u_int64_t ltime, vtime; + + ltime = iph2->approval->lifetime; + vtime = 0; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDUPDATE, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spdupdate2( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + ltime, vtime, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spdupdate2 (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdupdate2\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspdupdate(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdupdate message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); +#endif + + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "such policy does not already exist: \"%s\"\n", + spidx2str(&spidx)); + } else { + remsp(sp); + delsp(sp); + } + + if (addnewsp(mhp) < 0) + return -1; + + return 0; +} + +/* + * this function has to be used by responder side. + */ +int +pk_sendspdadd2(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen = 0; + u_int64_t ltime, vtime; + + ltime = iph2->approval->lifetime; + vtime = 0; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDADD, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spdadd2( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + ltime, vtime, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spdadd2 (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdadd2\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspdadd(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdadd message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); +#endif + + sp = getsp(&spidx); + if (sp != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "such policy already exists. " + "anyway replace it: %s\n", + spidx2str(&spidx)); + remsp(sp); + delsp(sp); + } + + if (addnewsp(mhp) < 0) + return -1; + + return 0; +} + +/* + * this function has to be used by responder side. + */ +int +pk_sendspddelete(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDDELETE, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spddelete( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spddelete (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spddelete\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspddelete(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spddelete message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); +#endif + + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", + spidx2str(&spidx)); + return -1; + } + + remsp(sp); + delsp(sp); + + return 0; +} + +static int +pk_recvspdexpire(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdexpire message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); +#endif + + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", + spidx2str(&spidx)); + return -1; + } + + remsp(sp); + delsp(sp); + + return 0; +} + +static int +pk_recvspdget(mhp) + caddr_t *mhp; +{ + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdget message passed.\n"); + return -1; + } + + return 0; +} + +static int +pk_recvspddump(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spddump message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + if (saddr == NULL || daddr == NULL || xpl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spddump message passed.\n"); + return -1; + } + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); +#endif + + sp = getsp(&spidx); + if (sp != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "such policy already exists. " + "anyway replace it: %s\n", + spidx2str(&spidx)); + remsp(sp); + delsp(sp); + } + + if (addnewsp(mhp) < 0) + return -1; + + return 0; +} + +static int +pk_recvspdflush(mhp) + caddr_t *mhp; +{ + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdflush message passed.\n"); + return -1; + } + + flushsp(); + + return 0; +} + +/* + * send error against acquire message to kenrel. + */ +int +pk_sendeacquire(iph2) + struct ph2handle *iph2; +{ + struct sadb_msg *newmsg; + int len; + + len = sizeof(struct sadb_msg); + newmsg = racoon_calloc(1, len); + if (newmsg == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send acquire.\n"); + return -1; + } + + memset(newmsg, 0, len); + newmsg->sadb_msg_version = PF_KEY_V2; + newmsg->sadb_msg_type = SADB_ACQUIRE; + newmsg->sadb_msg_errno = ENOENT; /* XXX */ + newmsg->sadb_msg_satype = iph2->satype; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + newmsg->sadb_msg_reserved = 0; + newmsg->sadb_msg_seq = iph2->seq; + newmsg->sadb_msg_pid = (u_int32_t)getpid(); + + /* send message */ + len = pfkey_send(lcconf->sock_pfkey, newmsg, len); + + racoon_free(newmsg); + + return 0; +} + +/* + * check if the algorithm is supported or not. + * OUT 0: ok + * -1: ng + */ +int +pk_checkalg(class, calg, keylen) + int class, calg, keylen; +{ + int sup, error; + u_int alg; + struct sadb_alg alg0; + + switch (algclass2doi(class)) { + case IPSECDOI_PROTO_IPSEC_ESP: + sup = SADB_EXT_SUPPORTED_ENCRYPT; + break; + case IPSECDOI_ATTR_AUTH: + sup = SADB_EXT_SUPPORTED_AUTH; + break; + case IPSECDOI_PROTO_IPCOMP: + plog(LLV_DEBUG, LOCATION, NULL, + "compression algorithm can not be checked " + "because sadb message doesn't support it.\n"); + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid algorithm class.\n"); + return -1; + } + alg = ipsecdoi2pfkey_alg(algclass2doi(class), algtype2doi(class, calg)); + if (alg == ~0) + return -1; + + if (keylen == 0) { + if (ipsec_get_keylen(sup, alg, &alg0)) { + plog(LLV_ERROR, LOCATION, NULL, + "%s.\n", ipsec_strerror()); + return -1; + } + keylen = alg0.sadb_alg_minbits; + } + + error = ipsec_check_keylen(sup, alg, keylen); + if (error) + plog(LLV_ERROR, LOCATION, NULL, + "%s.\n", ipsec_strerror()); + + return error; +} + +/* + * differences with pfkey_recv() in libipsec/pfkey.c: + * - never performs busy wait loop. + * - returns NULL and set *lenp to negative on fatal failures + * - returns NULL and set *lenp to non-negative on non-fatal failures + * - returns non-NULL on success + */ +static struct sadb_msg * +pk_recv(so, lenp) + int so; + int *lenp; +{ + struct sadb_msg buf, *newmsg; + int reallen; + + *lenp = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK); + if (*lenp < 0) + return NULL; /*fatal*/ + else if (*lenp < sizeof(buf)) + return NULL; + + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = racoon_calloc(1, reallen)) == NULL) + return NULL; + + *lenp = recv(so, (caddr_t)newmsg, reallen, MSG_PEEK); + if (*lenp < 0) { + racoon_free(newmsg); + return NULL; /*fatal*/ + } else if (*lenp != reallen) { + racoon_free(newmsg); + return NULL; + } + + *lenp = recv(so, (caddr_t)newmsg, reallen, 0); + if (*lenp < 0) { + racoon_free(newmsg); + return NULL; /*fatal*/ + } else if (*lenp != reallen) { + racoon_free(newmsg); + return NULL; + } + + return newmsg; +} + +/* see handler.h */ +u_int32_t +pk_getseq() +{ + return eay_random(); +} + +static int +addnewsp(mhp) + caddr_t *mhp; +{ + struct secpolicy *new; + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + + /* sanity check */ + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spd management message passed.\n"); + return -1; + } + + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + +#ifdef __linux__ + /* bsd skips over per-socket policies because there will be no + * src and dst extensions in spddump messages. On Linux the only + * way to achieve the same is check for policy id. + */ + if (xpl->sadb_x_policy_id % 8 >= 3) return 0; +#endif + + new = newsp(); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer\n"); + return -1; + } + + new->spidx.dir = xpl->sadb_x_policy_dir; + new->id = xpl->sadb_x_policy_id; + new->policy = xpl->sadb_x_policy_type; + new->req = NULL; + + /* check policy */ + switch (xpl->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_GENERATE: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + break; + + case IPSEC_POLICY_IPSEC: + { + int tlen; + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest **p_isr = &new->req; + + /* validity check */ + if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid msg length.\n"); + return -1; + } + + tlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + + /* length check */ + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid msg length.\n"); + return -1; + } + + /* allocate request buffer */ + *p_isr = newipsecreq(); + if (*p_isr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get new ipsecreq.\n"); + return -1; + } + + /* set values */ + (*p_isr)->next = NULL; + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + case IPPROTO_IPCOMP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto type: %u\n", + xisr->sadb_x_ipsecrequest_proto); + return -1; + } + (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid mode: %u\n", + xisr->sadb_x_ipsecrequest_mode); + return -1; + } + (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; + + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + case IPSEC_LEVEL_USE: + case IPSEC_LEVEL_REQUIRE: + break; + case IPSEC_LEVEL_UNIQUE: + (*p_isr)->saidx.reqid = + xisr->sadb_x_ipsecrequest_reqid; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid level: %u\n", + xisr->sadb_x_ipsecrequest_level); + return -1; + } + (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; + + /* set IP addresses if there */ + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *paddr; + + paddr = (struct sockaddr *)(xisr + 1); + bcopy(paddr, &(*p_isr)->saidx.src, + sysdep_sa_len(paddr)); + + paddr = (struct sockaddr *)((caddr_t)paddr + + sysdep_sa_len(paddr)); + bcopy(paddr, &(*p_isr)->saidx.dst, + sysdep_sa_len(paddr)); + } + + (*p_isr)->sp = new; + + /* initialization for the next. */ + p_isr = &(*p_isr)->next; + tlen -= xisr->sadb_x_ipsecrequest_len; + + /* validity check */ + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "becoming tlen < 0\n"); + } + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid policy type.\n"); + return -1; + } + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + xpl->sadb_x_policy_priority, + &new->spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &new->spidx); +#endif + + inssp(new); + + return 0; +} + +/* proto/mode/src->dst spi */ +const char * +sadbsecas2str(src, dst, proto, spi, mode) + struct sockaddr *src, *dst; + int proto; + u_int32_t spi; + int mode; +{ + static char buf[256]; + u_int doi_proto, doi_mode = 0; + char *p; + int blen, i; + + doi_proto = pfkey2ipsecdoi_proto(proto); + if (doi_proto == ~0) + return NULL; + if (mode) { + doi_mode = pfkey2ipsecdoi_mode(mode); + if (doi_mode == ~0) + return NULL; + } + + blen = sizeof(buf) - 1; + p = buf; + + i = snprintf(p, blen, "%s%s%s ", + s_ipsecdoi_proto(doi_proto), + mode ? "/" : "", + mode ? s_ipsecdoi_encmode(doi_mode) : ""); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + i = snprintf(p, blen, "%s->", saddr2str(src)); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + i = snprintf(p, blen, "%s ", saddr2str(dst)); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + if (spi) { + snprintf(p, blen, "spi=%lu(0x%lx)", (unsigned long)ntohl(spi), + (unsigned long)ntohl(spi)); + } + + return buf; +} diff --git a/ipsec-tools/racoon/plainrsa-gen.8 b/ipsec-tools/racoon/plainrsa-gen.8 new file mode 100644 index 0000000..0f059f8 --- /dev/null +++ b/ipsec-tools/racoon/plainrsa-gen.8 @@ -0,0 +1,137 @@ +.\" $Id: plainrsa-gen.8,v 1.2.10.1 2005/04/18 11:10:55 manubsd Exp $ +.\" +.\" Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. +.\" Contributed by: Michal Ludvig , SUSE Labs +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 14, 2004 +.Dt PLAINRSA-GEN 8 +.Os +.\" +.Sh NAME +.Nm plainrsa-gen +.Nd generator for Plain RSA keys +.\" +.Sh SYNOPSIS +.Nm plainrsa-gen +.Bk -words +.Op Fl b Ar bits +.Op Fl e Ar pubexp +.Op Fl f Ar outfile +.Op Fl h +.Ek +.\" +.Sh DESCRIPTION +.Nm +can be used to generate +.Li Plain RSA keys +for authentication purposes. +Using +.Li Plain RSA keys +is optional. +Other possibilities are +.Li Pre-shared keys +or +.Li X.509 certificates . +.\" +.Bl -tag -width Ds +.It Fl b Ar bits +bit length of the key. +Default is +.Li 1024 , +recommended length is +.Li 2048 +or even +.Li 4096 +bits. +Note that generating longer keys takes more time. +.It Fl e Ar pubexp +value of the RSA public exponent. +Default is +.Li 0x3 . +Don't change this unless you really know what you are doing! +.It Fl f Ar outfile +write the resulting key to +.Ar outfile +instead of +.Li stdout . +If the file already exists it won't be overwritten. +You wouldn't like to lose your private key by accident, would you? +.El +.\" +.Sh OUTPUT FILE FORMAT +This is the secret +.Li private key +that should +.Ic never +leave your computer: +.Bd -literal +: RSA { + # RSA 1024 bits + # pubkey=0sAQOrWlcwbAIdNSMhDt... + Modulus: 0xab5a57306c021d3523... + PublicExponent: 0x03 + PrivateExponent: 0x723c3a2048... + Prime1: 0xd309b30e6adf9d85c01... + Prime2: 0xcfdc2a8aa5b2b3c90e3... + Exponent1: 0x8cb122099c9513ae... + Exponent2: 0x8a92c7071921cd30... + Coefficient: 0x722751305eafe9... + } +.Ed +.Pp +The line +.Li pubkey=0sAQOrW... +of the +.Li private key +contains a +.Li public key +that should be stored in the other peer's configuration in this format: +.Bd -literal +: PUB 0sAQOrWlcwbAIdNSMhDt... +.Ed +.\" +.Pp +You can also specify +.Li from +and +.Li to +addresses for which the key is valid: +.Bd -literal +0.0.0.0/0 10.20.30.0/24 : PUB 0sAQOrWlcwbAIdNSMhDt... +.Ed +.\" +.Sh SEE ALSO +.Xr racoon.conf 5 , +.Xr racoon 8 +.\" +.Sh HISTORY +.Nm +was written by +.An Michal Ludvig Aq michal@logix.cz +and first appeared in +.Ic ipsec-tools 0.4 . diff --git a/ipsec-tools/racoon/plainrsa-gen.c b/ipsec-tools/racoon/plainrsa-gen.c new file mode 100644 index 0000000..974f3cb --- /dev/null +++ b/ipsec-tools/racoon/plainrsa-gen.c @@ -0,0 +1,209 @@ +/* $Id: plainrsa-gen.c,v 1.4.8.2 2005/04/21 09:07:20 monas Exp $ */ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#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 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 \n"); + exit(1); +} + +/* + * See RFC 2065, section 3.5 for details about the output format. + */ +vchar_t * +mix_b64_pubkey(RSA *key) +{ + char *binbuf; + long binlen, ret; + vchar_t *res; + + binlen = 1 + BN_num_bytes(key->e) + BN_num_bytes(key->n); + binbuf = malloc(binlen); + memset(binbuf, 0, binlen); + binbuf[0] = BN_bn2bin(key->e, (unsigned char *) &binbuf[1]); + ret = BN_bn2bin(key->n, (unsigned char *) (&binbuf[binbuf[0] + 1])); + if (1 + binbuf[0] + ret != binlen) { + plog(LLV_ERROR, LOCATION, NULL, + "Pubkey generation failed. This is really strange...\n"); + return NULL; + } + + return base64_encode(binbuf, binlen); +} + +char * +lowercase(char *input) +{ + char *ptr = input; + while (*ptr) { + if (*ptr >= 'A' && *ptr <= 'F') + *ptr -= 'A' - 'a'; + *ptr++; + } + + return input; +} + +int +gen_rsa_key(FILE *fp, size_t bits, unsigned long exp) +{ + RSA *key; + vchar_t *pubkey64 = NULL; + + key = RSA_generate_key(bits, exp, NULL, NULL); + if (!key) { + fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror()); + return -1; + } + + pubkey64 = mix_b64_pubkey(key); + if (!pubkey64) { + fprintf(stderr, "mix_b64_pubkey(): %s\n", eay_strerror()); + return -1; + } + + fprintf(fp, "# : PUB 0s%s\n", pubkey64->v); + fprintf(fp, ": RSA\t{\n"); + fprintf(fp, "\t# RSA %zu bits\n", bits); + fprintf(fp, "\t# pubkey=0s%s\n", pubkey64->v); + fprintf(fp, "\tModulus: 0x%s\n", lowercase(BN_bn2hex(key->n))); + fprintf(fp, "\tPublicExponent: 0x%s\n", lowercase(BN_bn2hex(key->e))); + fprintf(fp, "\tPrivateExponent: 0x%s\n", lowercase(BN_bn2hex(key->d))); + fprintf(fp, "\tPrime1: 0x%s\n", lowercase(BN_bn2hex(key->p))); + fprintf(fp, "\tPrime2: 0x%s\n", lowercase(BN_bn2hex(key->q))); + fprintf(fp, "\tExponent1: 0x%s\n", lowercase(BN_bn2hex(key->dmp1))); + fprintf(fp, "\tExponent2: 0x%s\n", lowercase(BN_bn2hex(key->dmq1))); + fprintf(fp, "\tCoefficient: 0x%s\n", lowercase(BN_bn2hex(key->iqmp))); + fprintf(fp, " }\n"); + + vfree(pubkey64); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + FILE *fp = stdout; + size_t bits = 1024; + unsigned int pubexp = 0x3; + struct stat st; + extern char *optarg; + extern int optind; + int c; + char *fname = NULL; + + while ((c = getopt(argc, argv, "e:b:f:h")) != -1) + switch (c) { + case 'e': + if (strncmp(optarg, "0x", 2) == 0) + sscanf(optarg, "0x%x", &pubexp); + else + pubexp = atoi(optarg); + break; + case 'b': + bits = atoi(optarg); + break; + case 'f': + fname = optarg; + break; + case 'h': + default: + usage(argv[0]); + } + + if (fname) { + if (stat(fname, &st) >= 0) { + fprintf(stderr, "%s: file exists! Please use a different name.\n", fname); + exit(1); + } + + umask(0077); + fp = fopen(fname, "w"); + if (fp == NULL) { + fprintf(stderr, "%s: %s\n", fname, strerror(errno)); + exit(1); + } + } + + ploginit(); + eay_init(); + + gen_rsa_key(fp, bits, pubexp); + + fclose(fp); + + return 0; +} diff --git a/ipsec-tools/racoon/plog.c b/ipsec-tools/racoon/plog.c new file mode 100644 index 0000000..6b00980 --- /dev/null +++ b/ipsec-tools/racoon/plog.c @@ -0,0 +1,270 @@ +/* $Id: plog.c,v 1.6.10.1 2005/12/07 10:19:51 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#include + +#include "var.h" +#include "misc.h" +#include "plog.h" +#include "logger.h" +#include "debug.h" +#include "gcmalloc.h" + +#ifndef VA_COPY +# define VA_COPY(dst,src) memcpy(&(dst), &(src), sizeof(va_list)) +#endif + +extern int print_pid; + +char *pname = NULL; +u_int32_t loglevel = LLV_BASE; +int f_foreground = 0; + +int print_location = 0; + +static struct log *logp = NULL; +static char *logfile = NULL; + +static char *plog_common __P((int, const char *, const char *)); + +static struct plogtags { + char *name; + int priority; +} ptab[] = { + { "(not defined)", 0, }, + { "INFO", LOG_INFO, }, + { "NOTIFY", LOG_INFO, }, + { "WARNING", LOG_INFO, }, + { "ERROR", LOG_INFO, }, + { "ERROR", LOG_ERR, }, + { "DEBUG", LOG_DEBUG, }, + { "DEBUG2", LOG_DEBUG, }, +}; + +static char * +plog_common(pri, fmt, func) + int pri; + const char *fmt, *func; +{ + static char buf[800]; /* XXX shoule be allocated every time ? */ + char *p; + int reslen, len; + + p = buf; + reslen = sizeof(buf); + + if (logfile || f_foreground) { + time_t t; + struct tm *tm; + + t = time(0); + tm = localtime(&t); + len = strftime(p, reslen, "%Y-%m-%d %T: ", tm); + p += len; + reslen -= len; + } + + if (pri < ARRAYLEN(ptab)) { + if (print_pid) + len = snprintf(p, reslen, "[%d] %s: ", getpid(), ptab[pri].name); + else + len = snprintf(p, reslen, "%s: ", ptab[pri].name); + if (len >= 0 && len < reslen) { + p += len; + reslen -= len; + } else + *p = '\0'; + } + + if (print_location) + snprintf(p, reslen, "%s: %s", func, fmt); + else + snprintf(p, reslen, "%s", fmt); +#ifdef BROKEN_PRINTF + while ((p = strstr(buf,"%z")) != NULL) + p[1] = 'l'; +#endif + + return buf; +} + +void +plog(int pri, const char *func, struct sockaddr *sa, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + plogv(pri, func, sa, fmt, ap); + va_end(ap); +} + +void +plogv(int pri, const char *func, struct sockaddr *sa, + const char *fmt, va_list ap) +{ + char *newfmt; + va_list ap_bak; + + if (pri > loglevel) + return; + + newfmt = plog_common(pri, fmt, func); + + VA_COPY(ap_bak, ap); + + if (f_foreground) + vprintf(newfmt, ap); + + if (logfile) + log_vaprint(logp, newfmt, ap_bak); + else { + if (pri < ARRAYLEN(ptab)) + vsyslog(ptab[pri].priority, newfmt, ap_bak); + else + vsyslog(LOG_ALERT, newfmt, ap_bak); + } +} + +void +plogdump(pri, data, len) + int pri; + void *data; + size_t len; +{ + caddr_t buf; + size_t buflen; + int i, j; + + if (pri > loglevel) + return; + + /* + * 2 words a bytes + 1 space 4 bytes + 1 newline 32 bytes + * + 2 newline + '\0' + */ + buflen = (len * 2) + (len / 4) + (len / 32) + 3; + buf = racoon_malloc(buflen); + + i = 0; + j = 0; + while (j < len) { + if (j % 32 == 0) + buf[i++] = '\n'; + else + if (j % 4 == 0) + buf[i++] = ' '; + snprintf(&buf[i], buflen - i, "%02x", + ((unsigned char *)data)[j] & 0xff); + i += 2; + j++; + } + if (buflen - i >= 2) { + buf[i++] = '\n'; + buf[i] = '\0'; + } + plog(pri, LOCATION, NULL, "%s", buf); + + racoon_free(buf); +} + +void +ploginit() +{ + if (logfile) { + logp = log_open(250, logfile); + if (logp == NULL) + errx(1, "ERROR: failed to open log file %s.", logfile); + return; + } + + openlog(pname, LOG_NDELAY, LOG_DAEMON); +} + +void +plogset(file) + char *file; +{ + if (logfile != NULL) + racoon_free(logfile); + logfile = strdup(file); +} + +void +plogreset(file) + char *file; +{ + + /* if log paths equal - do nothing */ + if (logfile == NULL && file == NULL) + return; + if (logfile != NULL && file != NULL) + if (!strcmp(logfile, file)) + return; + + if (logfile == NULL) /* no logfile was specified - daemon was used */ + closelog(); /* close it */ + else { + log_close(logp); + logp = NULL; + racoon_free(logfile); + logfile = NULL; + } + + if (file) + plogset(file); + ploginit(); +} + diff --git a/ipsec-tools/racoon/plog.h b/ipsec-tools/racoon/plog.h new file mode 100644 index 0000000..d1448df --- /dev/null +++ b/ipsec-tools/racoon/plog.h @@ -0,0 +1,78 @@ +/* $Id: plog.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PLOG_H +#define _PLOG_H + +#include "config.h" + +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#include + +/* + * INFO: begin negotiation, SA establishment/deletion/expiration. + * NOTIFY: just notifiable. + * WARNING: not error strictly. + * ERROR: system call error. also invalid parameter/format. + * ERROR2: error causing exit - to be logged to syslog. + * DEBUG1: debugging informatioin. + * DEBUG2: too more verbose. e.g. parsing config. + */ +#define LLV_INFO 1 +#define LLV_NOTIFY 2 +#define LLV_WARNING 3 +#define LLV_ERROR 4 +#define LLV_ERROR2 5 +#define LLV_DEBUG 6 +#define LLV_DEBUG2 7 + +#define LLV_BASE 5 /* always logging less than or equal to this value. */ + +extern char *pname; +extern u_int32_t loglevel; +extern int f_foreground; +extern int print_location; + +struct sockaddr; +extern void plog __P((int, const char *, struct sockaddr *, const char *, ...)) + __attribute__ ((__format__ (__printf__, 4, 5))); +extern void plogv __P((int, const char *, struct sockaddr *, + const char *, va_list)); +extern void plogdump __P((int, void *, size_t)); +extern void ploginit __P((void)); +extern void plogset __P((char *)); +extern void plogreset __P((char *)); + +#endif /* _PLOG_H */ diff --git a/ipsec-tools/racoon/policy.c b/ipsec-tools/racoon/policy.c new file mode 100644 index 0000000..d553d26 --- /dev/null +++ b/ipsec-tools/racoon/policy.c @@ -0,0 +1,481 @@ +/* $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "policy.h" +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "strnames.h" +#include "gcmalloc.h" +#include "session.h" + +static TAILQ_HEAD(_sptree, secpolicy) sptree; + +/* perform exact match against security policy table. */ +struct secpolicy * +getsp(spidx) + struct policyindex *spidx; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidxstrict(spidx, &p->spidx)) + return p; + } + + return NULL; +} + +/* + * perform non-exact match against security policy table, only if this is + * transport mode SA negotiation. for example, 0.0.0.0/0 -> 0.0.0.0/0 + * entry in policy.txt can be returned when we're negotiating transport + * mode SA. this is how the kernel works. + */ +#if 1 +struct secpolicy * +getsp_r(spidx) + struct policyindex *spidx; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidxwild(spidx, &p->spidx)) + return p; + } + + return NULL; +} +#else +struct secpolicy * +getsp_r(spidx, iph2) + struct policyindex *spidx; + struct ph2handle *iph2; +{ + struct secpolicy *p; + u_int8_t prefixlen; + + plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n"); + + if (spidx->src.ss_family != spidx->dst.ss_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch, src:%d dst:%d\n", + spidx->src.ss_family, + spidx->dst.ss_family); + return NULL; + } + switch (spidx->src.ss_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", spidx->src.ss_family); + return NULL; + } + + /* is it transport mode SA negotiation? */ + plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n", + saddr2str(iph2->src)); + plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n", + saddr2str((struct sockaddr *)&spidx->src)); + if (cmpsaddrwop(iph2->src, (struct sockaddr *)&spidx->src) + || spidx->prefs != prefixlen) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n", + saddr2str(iph2->dst)); + plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n", + saddr2str((struct sockaddr *)&spidx->dst)); + if (cmpsaddrwop(iph2->dst, (struct sockaddr *)&spidx->dst) + || spidx->prefd != prefixlen) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n"); + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidx_wild(spidx, &p->spidx)) + return p; + } + + return NULL; +} +#endif + +struct secpolicy * +getspbyspid(spid) + u_int32_t spid; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (p->id == spid) + return p; + } + + return NULL; +} + +/* + * compare policyindex. + * a: subject b: db + * OUT: 0: equal + * 1: not equal + */ +int +cmpspidxstrict(a, b) + struct policyindex *a, *b; +{ + plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a)); + plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b)); + + /* XXX don't check direction now, but it's to be checked carefully. */ + if (a->dir != b->dir + || a->prefs != b->prefs + || a->prefd != b->prefd + || a->ul_proto != b->ul_proto) + return 1; + + if (cmpsaddrstrict((struct sockaddr *)&a->src, + (struct sockaddr *)&b->src)) + return 1; + if (cmpsaddrstrict((struct sockaddr *)&a->dst, + (struct sockaddr *)&b->dst)) + return 1; + + return 0; +} + +/* + * compare policyindex, with wildcard address/protocol match. + * a: subject b: db, can contain wildcard things. + * OUT: 0: equal + * 1: not equal + */ +int +cmpspidxwild(a, b) + struct policyindex *a, *b; +{ + struct sockaddr_storage sa1, sa2; + + plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a)); + plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b)); + + if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir)) + return 1; + + if (!(a->ul_proto == IPSEC_ULPROTO_ANY || + b->ul_proto == IPSEC_ULPROTO_ANY || + a->ul_proto == b->ul_proto)) + return 1; + + if (a->src.ss_family != b->src.ss_family) + return 1; + if (a->dst.ss_family != b->dst.ss_family) + return 1; + +#ifndef __linux__ + /* compare src address */ + if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) { + plog(LLV_ERROR, LOCATION, NULL, + "unexpected error: " + "src.ss_len:%d dst.ss_len:%d\n", + a->src.ss_len, b->src.ss_len); + return 1; + } +#endif + mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src, + b->prefs); + mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src, + b->prefs); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + a, b->prefs, saddr2str((struct sockaddr *)&sa1)); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + b, b->prefs, saddr2str((struct sockaddr *)&sa2)); + if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2)) + return 1; + +#ifndef __linux__ + /* compare dst address */ + if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) { + plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n"); + exit(1); + } +#endif + mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst, + b->prefd); + mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst, + b->prefd); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + a, b->prefd, saddr2str((struct sockaddr *)&sa1)); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + b, b->prefd, saddr2str((struct sockaddr *)&sa2)); + if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2)) + return 1; + + return 0; +} + +struct secpolicy * +newsp() +{ + struct secpolicy *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +void +delsp(sp) + struct secpolicy *sp; +{ + struct ipsecrequest *req = NULL, *next; + + for (req = sp->req; req; req = next) { + next = req->next; + racoon_free(req); + } + + racoon_free(sp); +} + +void +delsp_bothdir(spidx0) + struct policyindex *spidx0; +{ + struct policyindex spidx; + struct secpolicy *sp; + struct sockaddr_storage src, dst; + u_int8_t prefs, prefd; + + memcpy(&spidx, spidx0, sizeof(spidx)); + switch (spidx.dir) { + case IPSEC_DIR_INBOUND: +#ifdef HAVE_POLICY_FWD + case IPSEC_DIR_FWD: +#endif + src = spidx.src; + dst = spidx.dst; + prefs = spidx.prefs; + prefd = spidx.prefd; + break; + case IPSEC_DIR_OUTBOUND: + src = spidx.dst; + dst = spidx.src; + prefs = spidx.prefd; + prefd = spidx.prefs; + break; + default: + return; + } + + spidx.src = src; + spidx.dst = dst; + spidx.prefs = prefs; + spidx.prefd = prefd; + spidx.dir = IPSEC_DIR_INBOUND; + + sp = getsp(&spidx); + if (sp) { + remsp(sp); + delsp(sp); + } + +#ifdef HAVE_POLICY_FWD + spidx.dir = IPSEC_DIR_FWD; + + sp = getsp(&spidx); + if (sp) { + remsp(sp); + delsp(sp); + } +#endif + + spidx.src = dst; + spidx.dst = src; + spidx.prefs = prefd; + spidx.prefd = prefs; + spidx.dir = IPSEC_DIR_OUTBOUND; + + sp = getsp(&spidx); + if (sp) { + remsp(sp); + delsp(sp); + } +} + +void +inssp(new) + struct secpolicy *new; +{ +#ifdef HAVE_PFKEY_POLICY_PRIORITY + struct secpolicy *p; + + TAILQ_FOREACH(p, &sptree, chain) { + if (new->spidx.priority < p->spidx.priority) { + TAILQ_INSERT_BEFORE(p, new, chain); + return; + } + } + if (p == NULL) +#endif + TAILQ_INSERT_TAIL(&sptree, new, chain); + + check_auto_exit(); + return; +} + +void +remsp(sp) + struct secpolicy *sp; +{ + TAILQ_REMOVE(&sptree, sp, chain); + check_auto_exit(); +} + +void +flushsp() +{ + struct secpolicy *p, *next; + + for (p = TAILQ_FIRST(&sptree); p; p = next) { + next = TAILQ_NEXT(p, chain); + remsp(p); + delsp(p); + } +} + +int +policies_installed(void) +{ + if (TAILQ_EMPTY(&sptree)) + return 0; + else + return 1; +} + +void +initsp() +{ + TAILQ_INIT(&sptree); +} + +struct ipsecrequest * +newipsecreq() +{ + struct ipsecrequest *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +const char * +spidx2str(spidx) + const struct policyindex *spidx; +{ + /* addr/pref[port] addr/pref[port] ul dir act */ + static char buf[256]; + char *p, *a, *b; + int blen, i; + + blen = sizeof(buf) - 1; + p = buf; + + a = saddr2str((const struct sockaddr *)&spidx->src); + for (b = a; *b != '\0'; b++) + if (*b == '[') { + *b = '\0'; + b++; + break; + } + i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + a = saddr2str((const struct sockaddr *)&spidx->dst); + for (b = a; *b != '\0'; b++) + if (*b == '[') { + *b = '\0'; + b++; + break; + } + i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + snprintf(p, blen, "proto=%s dir=%s", + s_proto(spidx->ul_proto), s_direction(spidx->dir)); + + return buf; +} diff --git a/ipsec-tools/racoon/policy.h b/ipsec-tools/racoon/policy.h new file mode 100644 index 0000000..858b4b7 --- /dev/null +++ b/ipsec-tools/racoon/policy.h @@ -0,0 +1,136 @@ +/* $Id: policy.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _POLICY_H +#define _POLICY_H + +#include + +/* refs. ipsec.h */ +/* + * Security Policy Index + * NOTE: Ensure to be same address family and upper layer protocol. + * NOTE: ul_proto, port number, uid, gid: + * ANY: reserved for waldcard. + * 0 to (~0 - 1): is one of the number of each value. + */ +struct policyindex { + u_int8_t dir; /* direction of packet flow, see blow */ + struct sockaddr_storage src; /* IP src address for SP */ + struct sockaddr_storage dst; /* IP dst address for SP */ + u_int8_t prefs; /* prefix length in bits for src */ + u_int8_t prefd; /* prefix length in bits for dst */ + u_int16_t ul_proto; /* upper layer Protocol */ + u_int32_t priority; /* priority for the policy */ +}; + +/* Security Policy Data Base */ +struct secpolicy { + TAILQ_ENTRY(secpolicy) chain; + + struct policyindex spidx; /* selector */ + u_int32_t id; /* It's unique number on the system. */ + + u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */ + struct ipsecrequest *req; + /* pointer to the ipsec request tree, */ + /* if policy == IPSEC else this value == NULL.*/ +}; + +/* Security Assocciation Index */ +/* NOTE: Ensure to be same address family */ +struct secasindex { + struct sockaddr_storage src; /* srouce address for SA */ + struct sockaddr_storage dst; /* destination address for SA */ + u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */ + u_int8_t mode; /* mode of protocol, see ipsec.h */ + u_int32_t reqid; /* reqid id who owned this SA */ + /* see IPSEC_MANUAL_REQID_MAX. */ +}; + +/* Request for IPsec */ +struct ipsecrequest { + struct ipsecrequest *next; + /* pointer to next structure */ + /* If NULL, it means the end of chain. */ + + struct secasindex saidx;/* hint for search proper SA */ + /* if __ss_len == 0 then no address specified.*/ + u_int level; /* IPsec level defined below. */ + + struct secpolicy *sp; /* back pointer to SP */ +}; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _priority, idx) \ +do { \ + bzero((idx), sizeof(struct policyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + (idx)->priority = (_priority); \ + memcpy(&(idx)->src, (s), sysdep_sa_len((struct sockaddr *)(s))); \ + memcpy(&(idx)->dst, (d), sysdep_sa_len((struct sockaddr *)(d))); \ +} while (0) +#else +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) \ +do { \ + bzero((idx), sizeof(struct policyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + memcpy(&(idx)->src, (s), sysdep_sa_len((struct sockaddr *)(s))); \ + memcpy(&(idx)->dst, (d), sysdep_sa_len((struct sockaddr *)(d))); \ +} while (0) +#endif + +struct ph2handle; +struct policyindex; +extern struct secpolicy *getsp __P((struct policyindex *)); +extern struct secpolicy *getsp_r __P((struct policyindex *)); +struct secpolicy *getspbyspid __P((u_int32_t)); +extern int cmpspidxstrict __P((struct policyindex *, struct policyindex *)); +extern int cmpspidxwild __P((struct policyindex *, struct policyindex *)); +extern struct secpolicy *newsp __P((void)); +extern void delsp __P((struct secpolicy *)); +extern void delsp_bothdir __P((struct policyindex *)); +extern void inssp __P((struct secpolicy *)); +extern void remsp __P((struct secpolicy *)); +extern void flushsp __P((void)); +extern void initsp __P((void)); +extern struct ipsecrequest *newipsecreq __P((void)); +extern int policies_installed __P((void)); + +extern const char *spidx2str __P((const struct policyindex *)); + +#endif /* _POLICY_H */ diff --git a/ipsec-tools/racoon/privsep.c b/ipsec-tools/racoon/privsep.c new file mode 100644 index 0000000..8dc4fd1 --- /dev/null +++ b/ipsec-tools/racoon/privsep.c @@ -0,0 +1,1210 @@ +/* $Id: privsep.c,v 1.6.2.7 2005/08/08 11:25:01 vanhu Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#ifdef __NetBSD__ +#include /* for setproctitle */ +#endif +#include +#include +#include + +#include +#include + +#include "gcmalloc.h" +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "var.h" +#include "libpfkey.h" + +#include "crypto_openssl.h" +#include "isakmp_var.h" +#include "isakmp.h" +#ifdef ENABLE_HYBRID +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" +#endif +#include "localconf.h" +#include "remoteconf.h" +#include "admin.h" +#include "privsep.h" + +static int privsep_sock[2] = { -1, -1 }; + +static int privsep_recv(int, struct privsep_com_msg **, size_t *); +static int privsep_send(int, struct privsep_com_msg *, size_t); +static int safety_check(struct privsep_com_msg *, int i); +#ifdef HAVE_LIBPAM +static int port_check(int); +#endif +static int unsafe_env(char *const *); +static int unknown_name(int); +static int unknown_script(int); +static int unsafe_path(char *, int); +static char *script_name2path(int); + +static int +privsep_send(sock, buf, len) + int sock; + struct privsep_com_msg *buf; + size_t len; +{ + if (buf == NULL) + return 0; + + if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_send failed: %s\n", + strerror(errno)); + return -1; + } + + racoon_free((char *)buf); + + return 0; +} + + +static int +privsep_recv(sock, bufp, lenp) + int sock; + struct privsep_com_msg **bufp; + size_t *lenp; +{ + struct admin_com com; + struct admin_com *combuf; + size_t len; + + *bufp = NULL; + *lenp = 0; + + /* Get the header */ + while ((len = recvfrom(sock, (char *)&com, + sizeof(com), MSG_PEEK, NULL, NULL)) == -1) { + if (errno == EINTR) + continue; + + plog(LLV_ERROR, LOCATION, NULL, + "privsep_recv failed: %s\n", + strerror(errno)); + return -1; + } + + /* Check for short packets */ + if (len < sizeof(com)) { + plog(LLV_ERROR, LOCATION, NULL, + "corrupted privsep message (short header)\n"); + return -1; + } + + /* Allocate buffer for the whole message */ + if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate memory: %s\n", strerror(errno)); + return -1; + } + + /* Get the whole buffer */ + while ((len = recvfrom(sock, (char *)combuf, + com.ac_len, 0, NULL, NULL)) == -1) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv privsep command: %s\n", + strerror(errno)); + return -1; + } + + /* We expect len to match */ + if (len != com.ac_len) { + plog(LLV_ERROR, LOCATION, NULL, + "corrupted privsep message (short packet)\n"); + return -1; + } + + *bufp = (struct privsep_com_msg *)combuf; + *lenp = len; + + return 0; +} + +int +privsep_init(void) +{ + int i; + pid_t child_pid; + + /* If running as root, we don't use the privsep code path */ + if (lcconf->uid == 0) + return 0; + + /* + * When running privsep, certificate and script paths + * are mandatory, as they enable us to check path safety + * in the privilegied instance + */ + if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) || + (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) { + plog(LLV_ERROR, LOCATION, NULL, "privilege separation " + "require path cert and path script in the config file\n"); + return -1; + } + + if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate privsep_sock: %s\n", strerror(errno)); + return -1; + } + + switch (child_pid = fork()) { + case -1: + plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n", + strerror(errno)); + return -1; + break; + + case 0: /* Child: drop privileges */ + if (lcconf->chroot != NULL) { + if (chdir(lcconf->chroot) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot chdir(%s): %s\n", lcconf->chroot, + strerror(errno)); + return -1; + } + if (chroot(lcconf->chroot) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot chroot(%s): %s\n", lcconf->chroot, + strerror(errno)); + return -1; + } + } + + if (setgid(lcconf->gid) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot setgid(%d): %s\n", lcconf->gid, + strerror(errno)); + return -1; + } + + if (setegid(lcconf->gid) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot setegid(%d): %s\n", lcconf->gid, + strerror(errno)); + return -1; + } + + if (setuid(lcconf->uid) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot setuid(%d): %s\n", lcconf->uid, + strerror(errno)); + return -1; + } + + if (seteuid(lcconf->uid) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot seteuid(%d): %s\n", lcconf->uid, + strerror(errno)); + return -1; + } + + return 0; + break; + + default: /* Parent: privilegied process */ + break; + } + + /* + * Close everything except the socketpair, + * and stdout if running in the forground. + */ + for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) { + if (i == privsep_sock[0]) + continue; + if (i == privsep_sock[1]) + continue; + if ((f_foreground) && (i == 1)) + continue; + (void)close(i); + } + + /* Above trickery closed the log file, reopen it */ + ploginit(); + + plog(LLV_INFO, LOCATION, NULL, + "racoon privilegied process running with PID %d\n", getpid()); + +#ifdef __NetBSD__ + setproctitle("[priv]"); +#endif + + /* + * Don't catch any signal + * This duplicate session:signals[], which is static... + */ + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + while (1) { + size_t len; + struct privsep_com_msg *combuf; + struct privsep_com_msg *reply; + char *data; + size_t *buflen; + size_t totallen; + char *bufs[PRIVSEP_NBUF_MAX]; + int i; + + if (privsep_recv(privsep_sock[0], &combuf, &len) != 0) + goto out; + + /* Safety checks and gather the data */ + if (len < sizeof(*combuf)) { + plog(LLV_ERROR, LOCATION, NULL, + "corrupted privsep message (short buflen)\n"); + goto out; + } + + data = (char *)(combuf + 1); + totallen = sizeof(*combuf); + for (i = 0; i < PRIVSEP_NBUF_MAX; i++) { + bufs[i] = (char *)data; + data += combuf->bufs.buflen[i]; + totallen += combuf->bufs.buflen[i]; + } + + if (totallen > len) { + plog(LLV_ERROR, LOCATION, NULL, + "corrupted privsep message (bufs too big)\n"); + goto out; + } + + /* Prepare the reply buffer */ + if ((reply = racoon_malloc(sizeof(*reply))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate reply buffer: %s\n", + strerror(errno)); + goto out; + } + bzero(reply, sizeof(*reply)); + reply->hdr.ac_cmd = combuf->hdr.ac_cmd; + reply->hdr.ac_len = sizeof(*reply); + + switch(combuf->hdr.ac_cmd) { + /* + * XXX Improvement: instead of returning the key, + * stuff eay_get_pkcs1privkey and eay_get_x509sign + * together and sign the hash in the privilegied + * instance? + * pro: the key remains inaccessibleato + * con: a compromised unpriv racoon can still sign anything + */ + case PRIVSEP_EAY_GET_PKCS1PRIVKEY: { + vchar_t *privkey; + + /* Make sure the string is NULL terminated */ + if (safety_check(combuf, 0) != 0) + break; + bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; + + if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_eay_get_pkcs1privkey: " + "unsafe key \"%s\"\n", bufs[0]); + } + + if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){ + reply->hdr.ac_errno = errno; + break; + } + + reply->bufs.buflen[0] = privkey->l; + reply->hdr.ac_len = sizeof(*reply) + privkey->l; + reply = racoon_realloc(reply, reply->hdr.ac_len); + if (reply == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate reply buffer: %s\n", + strerror(errno)); + goto out; + } + + memcpy(reply + 1, privkey->v, privkey->l); + vfree(privkey); + break; + } + + case PRIVSEP_SCRIPT_EXEC: { + int script; + int name; + char **envp = NULL; + int envc = 0; + int count = 0; + int i; + + /* + * First count the bufs, and make sure strings + * are NULL terminated. + * + * We expect: script, name, envp[], void + */ + count++; /* script */ + count++; /* name */ + + for (; count < PRIVSEP_NBUF_MAX; count++) { + if (combuf->bufs.buflen[count] == 0) + break; + bufs[count] + [combuf->bufs.buflen[count] - 1] = '\0'; + envc++; + } + + /* count a void buf and perform safety check */ + count++; + if (count >= PRIVSEP_NBUF_MAX) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: too many args\n"); + goto out; + } + + + /* + * Allocate the arrays for envp + */ + envp = racoon_malloc((envc + 1) * sizeof(char *)); + if (envp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot allocate memory: %s\n", + strerror(errno)); + goto out; + } + bzero(envp, (envc + 1) * sizeof(char *)); + + + /* + * Populate script, name and envp + */ + count = 0; + + if (combuf->bufs.buflen[count] != sizeof(script)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: corrupted message\n"); + goto out; + } + memcpy((char *)&script, bufs[count++], sizeof(script)); + + if (combuf->bufs.buflen[count] != sizeof(name)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: corrupted message\n"); + goto out; + } + memcpy((char *)&name, bufs[count++], sizeof(name)); + + for (i = 0; combuf->bufs.buflen[count]; count++) + envp[i++] = bufs[count]; + + count++; /* void */ + + /* + * Check env for dangerous variables + * Check script path and name + * Perform fork and execve + */ + if ((unsafe_env(envp) == 0) && + (unknown_name(name) == 0) && + (unknown_script(script) == 0) && + (unsafe_path(script_name2path(script), + LC_PATHTYPE_SCRIPT) == 0)) + (void)script_exec(script, name, envp); + else + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: " + "unsafe script \"%s\"\n", + script_name2path(script)); + + racoon_free(envp); + break; + } + + case PRIVSEP_GETPSK: { + vchar_t *psk; + int keylen; + + /* Make sure the string is NULL terminated */ + if (safety_check(combuf, 0) != 0) + break; + bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; + + if (combuf->bufs.buflen[1] != sizeof(keylen)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_getpsk: corrupted message\n"); + goto out; + } + memcpy(&keylen, bufs[1], sizeof(keylen)); + if ((psk = getpsk(bufs[0], keylen)) == NULL) { + reply->hdr.ac_errno = errno; + break; + } + + reply->bufs.buflen[0] = psk->l; + reply->hdr.ac_len = sizeof(*reply) + psk->l; + reply = racoon_realloc(reply, reply->hdr.ac_len); + if (reply == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate reply buffer: %s\n", + strerror(errno)); + goto out; + } + + memcpy(reply + 1, psk->v, psk->l); + vfree(psk); + break; + } + +#ifdef ENABLE_HYBRID + case PRIVSEP_XAUTH_LOGIN_SYSTEM: { + if (safety_check(combuf, 0) != 0) + break; + bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; + + if (safety_check(combuf, 1) != 0) + break; + bufs[1][combuf->bufs.buflen[1] - 1] = '\0'; + + errno = 0; + if (xauth_login_system(bufs[0], bufs[1]) != 0) { + if (errno == 0) + reply->hdr.ac_errno = EINVAL; + else + reply->hdr.ac_errno = errno; + } + break; + } +#ifdef HAVE_LIBPAM + case PRIVSEP_ACCOUNTING_PAM: { + int port; + int inout; + + if (safety_check(combuf, 0) != 0) + break; + if (safety_check(combuf, 1) != 0) + break; + + memcpy(&port, bufs[0], sizeof(port)); + memcpy(&inout, bufs[1], sizeof(inout)); + + if (port_check(port) != 0) + break; + + errno = 0; + if (isakmp_cfg_accounting_pam(port, inout) != 0) { + if (errno == 0) + reply->hdr.ac_errno = EINVAL; + else + reply->hdr.ac_errno = errno; + } + break; + } + + case PRIVSEP_XAUTH_LOGIN_PAM: { + int port; + struct sockaddr *raddr; + + if (safety_check(combuf, 0) != 0) + break; + if (safety_check(combuf, 1) != 0) + break; + if (safety_check(combuf, 2) != 0) + break; + if (safety_check(combuf, 3) != 0) + break; + + memcpy(&port, bufs[0], sizeof(port)); + raddr = (struct sockaddr *)bufs[1]; + + bufs[2][combuf->bufs.buflen[2] - 1] = '\0'; + bufs[3][combuf->bufs.buflen[3] - 1] = '\0'; + + if (port_check(port) != 0) + break; + + errno = 0; + if (xauth_login_pam(port, + raddr, bufs[2], bufs[3]) != 0) { + if (errno == 0) + reply->hdr.ac_errno = EINVAL; + else + reply->hdr.ac_errno = errno; + } + break; + } + + case PRIVSEP_CLEANUP_PAM: { + int port; + + if (safety_check(combuf, 0) != 0) + break; + + memcpy(&port, bufs[0], sizeof(port)); + + if (port_check(port) != 0) + break; + + cleanup_pam(port); + reply->hdr.ac_errno = 0; + + break; + } +#endif /* HAVE_LIBPAM */ +#endif /* ENABLE_HYBRID */ + + default: + plog(LLV_ERROR, LOCATION, NULL, + "unexpected privsep command %d\n", + combuf->hdr.ac_cmd); + goto out; + break; + } + + /* This frees reply */ + if (privsep_send(privsep_sock[0], + reply, reply->hdr.ac_len) != 0) + goto out; + + racoon_free(combuf); + } + +out: + plog(LLV_INFO, LOCATION, NULL, "privsep exit\n"); + _exit(0); +} + + +vchar_t * +privsep_eay_get_pkcs1privkey(path) + char *path; +{ + vchar_t *privkey; + struct privsep_com_msg *msg; + size_t len; + + if (geteuid() == 0) + return eay_get_pkcs1privkey(path); + + len = sizeof(*msg) + strlen(path) + 1; + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return NULL; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY; + msg->hdr.ac_len = len; + msg->bufs.buflen[0] = len - sizeof(*msg); + memcpy(msg + 1, path, msg->bufs.buflen[0]); + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return NULL; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return NULL; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + if ((privkey = vmalloc(len - sizeof(*msg))) == NULL) + goto out; + + memcpy(privkey->v, msg + 1, privkey->l); + racoon_free(msg); + return privkey; + +out: + racoon_free(msg); + return NULL; +} + +/* + * No prigilege separation trick here, we just open PFKEY before + * dropping root privs and we remember it later. + */ +static int pfkey_socket = -1; +int +privsep_pfkey_open(void) +{ + int ps; + + if (pfkey_socket != -1) + return pfkey_socket; + + ps = pfkey_open(); + if (ps != -1) + pfkey_socket = ps; + + return ps; +} + +/* + * Consequence of the above trickery: don't + * really close PFKEY as we never re-open it. + */ +void +privsep_pfkey_close(ps) + int ps; +{ + return; +} + +int +privsep_script_exec(script, name, envp) + int script; + int name; + char *const envp[]; +{ + int count = 0; + char *const *c; + char *data; + size_t len; + struct privsep_com_msg *msg; + + if (geteuid() == 0) + return script_exec(script, name, envp); + + if ((msg = racoon_malloc(sizeof(*msg))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + + bzero(msg, sizeof(*msg)); + msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC; + msg->hdr.ac_len = sizeof(*msg); + + /* + * We send: + * script, name, envp[0], ... envp[N], void + */ + + /* + * Safety check on the counts: PRIVSEP_NBUF_MAX max + */ + count = 0; + count++; /* script */ + count++; /* name */ + for (c = envp; *c; c++) /* envp */ + count++; + count++; /* void */ + + if (count > PRIVSEP_NBUF_MAX) { + plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: " + "privsep_script_exec count > PRIVSEP_NBUF_MAX\n"); + racoon_free(msg); + return -1; + } + + + /* + * Compute the length + */ + count = 0; + msg->bufs.buflen[count] = sizeof(script); /* script */ + msg->hdr.ac_len += msg->bufs.buflen[count++]; + + msg->bufs.buflen[count] = sizeof(name); /* name */ + msg->hdr.ac_len += msg->bufs.buflen[count++]; + + for (c = envp; *c; c++) { /* envp */ + msg->bufs.buflen[count] = strlen(*c) + 1; + msg->hdr.ac_len += msg->bufs.buflen[count++]; + } + + msg->bufs.buflen[count] = 0; /* void */ + msg->hdr.ac_len += msg->bufs.buflen[count++]; + + if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + + /* + * Now copy the data + */ + data = (char *)(msg + 1); + count = 0; + + memcpy(data, (char *)&script, msg->bufs.buflen[count]); /* script */ + data += msg->bufs.buflen[count++]; + + memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */ + data += msg->bufs.buflen[count++]; + + for (c = envp; *c; c++) { /* envp */ + memcpy(data, *c, msg->bufs.buflen[count]); + data += msg->bufs.buflen[count++]; + } + + count++; /* void */ + + /* + * And send it! + */ + if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return -1; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + racoon_free(msg); + return -1; + } + + racoon_free(msg); + return 0; +} + +vchar_t * +privsep_getpsk(str, keylen) + const char *str; + int keylen; +{ + vchar_t *psk; + struct privsep_com_msg *msg; + size_t len; + int *keylenp; + char *data; + + if (geteuid() == 0) + return getpsk(str, keylen); + + len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen); + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return NULL; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_GETPSK; + msg->hdr.ac_len = len; + + data = (char *)(msg + 1); + msg->bufs.buflen[0] = strlen(str) + 1; + memcpy(data, str, msg->bufs.buflen[0]); + + data += msg->bufs.buflen[0]; + msg->bufs.buflen[1] = sizeof(keylen); + memcpy(data, &keylen, sizeof(keylen)); + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return NULL; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return NULL; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + if ((psk = vmalloc(len - sizeof(*msg))) == NULL) + goto out; + + memcpy(psk->v, msg + 1, psk->l); + racoon_free(msg); + return psk; + +out: + racoon_free(msg); + return NULL; +} + +#ifdef ENABLE_HYBRID +int +privsep_xauth_login_system(usr, pwd) + char *usr; + char *pwd; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + + if (geteuid() == 0) + return xauth_login_system(usr, pwd); + + len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1; + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM; + msg->hdr.ac_len = len; + + data = (char *)(msg + 1); + msg->bufs.buflen[0] = strlen(usr) + 1; + memcpy(data, usr, msg->bufs.buflen[0]); + data += msg->bufs.buflen[0]; + + msg->bufs.buflen[1] = strlen(pwd) + 1; + memcpy(data, pwd, msg->bufs.buflen[1]); + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return -1; + + if (msg->hdr.ac_errno != 0) { + racoon_free(msg); + return -1; + } + + racoon_free(msg); + return 0; +} +#endif /* ENABLE_HYBRID */ + +#ifdef HAVE_LIBPAM +static int +port_check(port) + int port; +{ + if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep: port %d outside of allowed range [0,%zu]\n", + port, isakmp_cfg_config.pool_size - 1); + return -1; + } + + return 0; +} +#endif + +static int +safety_check(msg, index) + struct privsep_com_msg *msg; + int index; +{ + if (index >= PRIVSEP_NBUF_MAX) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep: Corrupted message, too many buffers\n"); + return -1; + } + + if (msg->bufs.buflen[index] == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep: Corrupted message, unexpected void buffer\n"); + return -1; + } + + return 0; +} + +/* + * Filter unsafe environement variables + */ +static int +unsafe_env(envp) + char *const *envp; +{ + char *const *e; + char *const *be; + char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL }; + + for (e = envp; *e; e++) { + for (be = bad_env; *be; be++) { + if (strncmp(*e, *be, strlen(*be)) == 0) { + goto found; + } + } + } + + return 0; +found: + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: unsafe environement variable\n"); + return -1; +} + +/* + * Check path safety + */ +static int +unsafe_path(script, pathtype) + char *script; + int pathtype; +{ + char *path; + char rpath[MAXPATHLEN + 1]; + size_t len; + + if (script == NULL) + return -1; + + path = lcconf->pathinfo[pathtype]; + + /* No path was given for scripts: skip the check */ + if (path == NULL) + return 0; + + if (realpath(script, rpath) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "script path \"%s\" is invalid\n", script); + return -1; + } + + len = strlen(path); + if (strncmp(path, rpath, len) != 0) + return -1; + + return 0; +} + +static char * +script_name2path(name) + int name; +{ + vchar_t **sp; + + if (script_paths == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "script_name2path: script_paths was not initialized\n"); + return NULL; + } + + sp = (vchar_t **)(script_paths->v); + + return sp[name]->v; +} + +/* + * Check the script path index is correct + */ +static int +unknown_script(script) + int script; +{ + if (script_paths == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: script_paths was not initialized\n"); + return -1; + } + + if ((script < 0) || (script > (script_paths->l / sizeof(vchar_t *)))) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: unsafe script index\n"); + return -1; + } + + return 0; +} + +static int +unknown_name(name) + int name; +{ + if ((name < 0) || (name > SCRIPT_MAX)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_script_exec: unsafe name index\n"); + return -1; + } + + return 0; +} + +#ifdef HAVE_LIBPAM +int +privsep_accounting_pam(port, inout) + int port; + int inout; +{ + struct privsep_com_msg *msg; + size_t len; + int *port_data; + int *inout_data; + int result; + + if (geteuid() == 0) + return isakmp_cfg_accounting_pam(port, inout); + + len = sizeof(*msg) + sizeof(port) + sizeof(inout); + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM; + msg->hdr.ac_len = len; + msg->bufs.buflen[0] = sizeof(port); + msg->bufs.buflen[1] = sizeof(inout); + + port_data = (int *)(msg + 1); + inout_data = (int *)(port_data + 1); + + *port_data = port; + *inout_data = inout; + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return -1; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + racoon_free(msg); + return 0; + +out: + racoon_free(msg); + return -1; +} + +int +privsep_xauth_login_pam(port, raddr, usr, pwd) + int port; + struct sockaddr *raddr; + char *usr; + char *pwd; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + int result; + + if (geteuid() == 0) + return xauth_login_pam(port, raddr, usr, pwd); + + len = sizeof(*msg) + + sizeof(port) + + sysdep_sa_len(raddr) + + strlen(usr) + 1 + + strlen(pwd) + 1; + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM; + msg->hdr.ac_len = len; + msg->bufs.buflen[0] = sizeof(port); + msg->bufs.buflen[1] = sysdep_sa_len(raddr); + msg->bufs.buflen[2] = strlen(usr) + 1; + msg->bufs.buflen[3] = strlen(pwd) + 1; + + data = (char *)(msg + 1); + memcpy(data, &port, msg->bufs.buflen[0]); + + data += sizeof(msg->bufs.buflen[0]); + memcpy(data, raddr, msg->bufs.buflen[1]); + + data += msg->bufs.buflen[1]; + memcpy(data, usr, msg->bufs.buflen[2]); + + data += msg->bufs.buflen[2]; + memcpy(data, pwd, msg->bufs.buflen[3]); + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return -1; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + racoon_free(msg); + return 0; + +out: + racoon_free(msg); + return -1; +} + +void +privsep_cleanup_pam(port) + int port; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + int result; + + if (geteuid() == 0) + return cleanup_pam(port); + + len = sizeof(*msg) + sizeof(port); + if ((msg = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return; + } + bzero(msg, len); + msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM; + msg->hdr.ac_len = len; + msg->bufs.buflen[0] = sizeof(port); + + data = (char *)(msg + 1); + memcpy(data, &port, msg->bufs.buflen[0]); + + if (privsep_send(privsep_sock[1], msg, len) != 0) + return; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + return; + + if (msg->hdr.ac_errno != 0) + errno = msg->hdr.ac_errno; + + racoon_free(msg); + return; +} +#endif diff --git a/ipsec-tools/racoon/privsep.h b/ipsec-tools/racoon/privsep.h new file mode 100644 index 0000000..10e3aa2 --- /dev/null +++ b/ipsec-tools/racoon/privsep.h @@ -0,0 +1,69 @@ +/* $Id: privsep.h,v 1.3 2005/02/10 02:02:56 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PRIVSEP_H +#define _PRIVSEP_H + +#define PRIVSEP_EAY_GET_PKCS1PRIVKEY 0x0801 /* admin_com_bufs follows */ +#define PRIVSEP_SCRIPT_EXEC 0x0803 /* admin_com_bufs follows */ +#define PRIVSEP_GETPSK 0x0804 /* admin_com_bufs follows */ +#define PRIVSEP_XAUTH_LOGIN_SYSTEM 0x0805 /* admin_com_bufs follows */ +#define PRIVSEP_ACCOUNTING_PAM 0x0806 /* admin_com_bufs follows */ +#define PRIVSEP_XAUTH_LOGIN_PAM 0x0807 /* admin_com_bufs follows */ +#define PRIVSEP_CLEANUP_PAM 0x0808 /* admin_com_bufs follows */ + +#define PRIVSEP_NBUF_MAX 16 +#define PRIVSEP_BUFLEN_MAX 4096 +struct admin_com_bufs { + size_t buflen[PRIVSEP_NBUF_MAX]; + /* Followed by the buffers */ +}; + +struct privsep_com_msg { + struct admin_com hdr; + struct admin_com_bufs bufs; +}; + +int privsep_init __P((void)); + +vchar_t *privsep_eay_get_pkcs1privkey __P((char *)); +int privsep_pfkey_open __P((void)); +void privsep_pfkey_close __P((int)); +int privsep_script_exec __P((int, int, char * const *)); +vchar_t *privsep_getpsk __P((const char *, const int)); +int privsep_xauth_login_system __P((char *, char *)); +#ifdef HAVE_LIBPAM +int privsep_accounting_pam __P((int, int)); +int privsep_xauth_login_pam __P((int, struct sockaddr *, char *, char *)); +void privsep_cleanup_pam __P((int)); +#endif + +#endif /* _PRIVSEP_H */ diff --git a/ipsec-tools/racoon/proposal.c b/ipsec-tools/racoon/proposal.c new file mode 100644 index 0000000..a2f053a --- /dev/null +++ b/ipsec-tools/racoon/proposal.c @@ -0,0 +1,1189 @@ +/* $Id: proposal.c,v 1.13.8.5 2005/07/28 05:05:52 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "policy.h" +#include "pfkey.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "algorithm.h" +#include "proposal.h" +#include "sainfo.h" +#include "localconf.h" +#include "remoteconf.h" +#include "oakley.h" +#include "handler.h" +#include "strnames.h" +#include "gcmalloc.h" +#ifdef ENABLE_NATT +#include "nattraversal.h" +#endif + +/* %%% + * modules for ipsec sa spec + */ +struct saprop * +newsaprop() +{ + struct saprop *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +struct saproto * +newsaproto() +{ + struct saproto *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +/* set saprop to last part of the prop tree */ +void +inssaprop(head, new) + struct saprop **head; + struct saprop *new; +{ + struct saprop *p; + + if (*head == NULL) { + *head = new; + return; + } + + for (p = *head; p->next; p = p->next) + ; + p->next = new; + + return; +} + +/* set saproto to the end of the proto tree in saprop */ +void +inssaproto(pp, new) + struct saprop *pp; + struct saproto *new; +{ + struct saproto *p; + + for (p = pp->head; p && p->next; p = p->next) + ; + if (p == NULL) + pp->head = new; + else + p->next = new; + + return; +} + +/* set saproto to the top of the proto tree in saprop */ +void +inssaprotorev(pp, new) + struct saprop *pp; + struct saproto *new; +{ + new->next = pp->head; + pp->head = new; + + return; +} + +struct satrns * +newsatrns() +{ + struct satrns *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +/* set saproto to last part of the proto tree in saprop */ +void +inssatrns(pr, new) + struct saproto *pr; + struct satrns *new; +{ + struct satrns *tr; + + for (tr = pr->head; tr && tr->next; tr = tr->next) + ; + if (tr == NULL) + pr->head = new; + else + tr->next = new; + + return; +} + +/* + * take a single match between saprop. allocate a new proposal and return it + * for future use (like picking single proposal from a bundle). + * pp1: peer's proposal. + * pp2: my proposal. + * NOTE: In the case of initiator, must be ensured that there is no + * modification of the proposal by calling cmp_aproppair_i() before + * this function. + * XXX cannot understand the comment! + */ +struct saprop * +cmpsaprop_alloc(ph1, pp1, pp2, side) + struct ph1handle *ph1; + const struct saprop *pp1, *pp2; + int side; +{ + struct saprop *newpp = NULL; + struct saproto *pr1, *pr2, *newpr = NULL; + struct satrns *tr1, *tr2, *newtr; + const int ordermatters = 0; + int npr1, npr2; + int spisizematch; + + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + return NULL; + } + newpp->prop_no = pp1->prop_no; + + /* see proposal.h about lifetime/key length and PFS selection. */ + + /* check time/bytes lifetime and PFS */ + switch (ph1->rmconf->pcheck_level) { + case PROP_CHECK_OBEY: + newpp->lifetime = pp1->lifetime; + newpp->lifebyte = pp1->lifebyte; + newpp->pfs_group = pp1->pfs_group; + break; + + case PROP_CHECK_STRICT: + if (pp1->lifetime > pp2->lifetime) { + plog(LLV_ERROR, LOCATION, NULL, + "long lifetime proposed: " + "my:%d peer:%d\n", + (int)pp2->lifetime, (int)pp1->lifetime); + goto err; + } + if (pp1->lifebyte > pp2->lifebyte) { + plog(LLV_ERROR, LOCATION, NULL, + "long lifebyte proposed: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + goto err; + } + newpp->lifetime = pp1->lifetime; + newpp->lifebyte = pp1->lifebyte; + + prop_pfs_check: + if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs group mismatched: " + "my:%d peer:%d\n", + pp2->pfs_group, pp1->pfs_group); + goto err; + } + newpp->pfs_group = pp1->pfs_group; + break; + + case PROP_CHECK_CLAIM: + /* lifetime */ + if (pp1->lifetime <= pp2->lifetime) { + newpp->lifetime = pp1->lifetime; + } else { + newpp->lifetime = pp2->lifetime; + newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; + plog(LLV_NOTIFY, LOCATION, NULL, + "use own lifetime: " + "my:%d peer:%d\n", + (int)pp2->lifetime, (int)pp1->lifetime); + } + + /* lifebyte */ + if (pp1->lifebyte > pp2->lifebyte) { + newpp->lifebyte = pp2->lifebyte; + newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; + plog(LLV_NOTIFY, LOCATION, NULL, + "use own lifebyte: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + } + newpp->lifebyte = pp1->lifebyte; + + goto prop_pfs_check; + break; + + case PROP_CHECK_EXACT: + if (pp1->lifetime != pp2->lifetime) { + plog(LLV_ERROR, LOCATION, NULL, + "lifetime mismatched: " + "my:%d peer:%d\n", + (int)pp2->lifetime, (int)pp1->lifetime); + goto err; + } + + if (pp1->lifebyte != pp2->lifebyte) { + plog(LLV_ERROR, LOCATION, NULL, + "lifebyte mismatched: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + goto err; + } + if (pp1->pfs_group != pp2->pfs_group) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs group mismatched: " + "my:%d peer:%d\n", + pp2->pfs_group, pp1->pfs_group); + goto err; + } + newpp->lifetime = pp1->lifetime; + newpp->lifebyte = pp1->lifebyte; + newpp->pfs_group = pp1->pfs_group; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid pcheck_level why?.\n"); + goto err; + } + + npr1 = npr2 = 0; + for (pr1 = pp1->head; pr1; pr1 = pr1->next) + npr1++; + for (pr2 = pp2->head; pr2; pr2 = pr2->next) + npr2++; + if (npr1 != npr2) + goto err; + + /* check protocol order */ + pr1 = pp1->head; + pr2 = pp2->head; + + while (1) { + if (!ordermatters) { + /* + * XXX does not work if we have multiple proposals + * with the same proto_id + */ + switch (side) { + case RESPONDER: + if (!pr2) + break; + for (pr1 = pp1->head; pr1; pr1 = pr1->next) { + if (pr1->proto_id == pr2->proto_id) + break; + } + break; + case INITIATOR: + if (!pr1) + break; + for (pr2 = pp2->head; pr2; pr2 = pr2->next) { + if (pr2->proto_id == pr1->proto_id) + break; + } + break; + } + } + if (!pr1 || !pr2) + break; + + if (pr1->proto_id != pr2->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "proto_id mismatched: " + "my:%s peer:%s\n", + s_ipsecdoi_proto(pr2->proto_id), + s_ipsecdoi_proto(pr1->proto_id)); + goto err; + } + spisizematch = 0; + if (pr1->spisize == pr2->spisize) + spisizematch = 1; + else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) { + /* + * draft-shacham-ippcp-rfc2393bis-05.txt: + * need to accept 16bit and 32bit SPI (CPI) for IPComp. + */ + if (pr1->spisize == sizeof(u_int16_t) && + pr2->spisize == sizeof(u_int32_t)) { + spisizematch = 1; + } else if (pr2->spisize == sizeof(u_int16_t) && + pr1->spisize == sizeof(u_int32_t)) { + spisizematch = 1; + } + if (spisizematch) { + plog(LLV_ERROR, LOCATION, NULL, + "IPComp SPI size promoted " + "from 16bit to 32bit\n"); + } + } + if (!spisizematch) { + plog(LLV_ERROR, LOCATION, NULL, + "spisize mismatched: " + "my:%d peer:%d\n", + (int)pr2->spisize, (int)pr1->spisize); + goto err; + } + +#ifdef ENABLE_NATT + if ((ph1->natt_flags & NAT_DETECTED) && + natt_udp_encap (pr2->encmode)) + { + plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n", + s_ipsecdoi_encmode(pr2->encmode), + s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff)); + pr2->encmode -= ph1->natt_options->mode_udp_diff; + pr2->udp_encap = 1; + } + + if ((ph1->natt_flags & NAT_DETECTED) && + natt_udp_encap (pr1->encmode)) + { + plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n", + s_ipsecdoi_encmode(pr1->encmode), + pr1->encmode, + s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff), + pr1->encmode - ph1->natt_options->mode_udp_diff); + pr1->encmode -= ph1->natt_options->mode_udp_diff; + pr1->udp_encap = 1; + } +#endif + + if (pr1->encmode != pr2->encmode) { + plog(LLV_ERROR, LOCATION, NULL, + "encmode mismatched: " + "my:%s peer:%s\n", + s_ipsecdoi_encmode(pr2->encmode), + s_ipsecdoi_encmode(pr1->encmode)); + goto err; + } + + for (tr1 = pr1->head; tr1; tr1 = tr1->next) { + for (tr2 = pr2->head; tr2; tr2 = tr2->next) { + if (cmpsatrns(pr1->proto_id, tr1, tr2) == 0) + goto found; + } + } + + goto err; + + found: + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + newpr->proto_id = pr1->proto_id; + newpr->spisize = pr1->spisize; + newpr->encmode = pr1->encmode; + newpr->spi = pr2->spi; /* copy my SPI */ + newpr->spi_p = pr1->spi; /* copy peer's SPI */ + newpr->reqid_in = pr2->reqid_in; + newpr->reqid_out = pr2->reqid_out; +#ifdef ENABLE_NATT + newpr->udp_encap = pr1->udp_encap | pr2->udp_encap; +#endif + + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + newtr->trns_no = tr1->trns_no; + newtr->trns_id = tr1->trns_id; + newtr->encklen = tr1->encklen; + newtr->authtype = tr1->authtype; + + inssatrns(newpr, newtr); + inssaproto(newpp, newpr); + + pr1 = pr1->next; + pr2 = pr2->next; + } + + /* XXX should check if we have visited all items or not */ + if (!ordermatters) { + switch (side) { + case RESPONDER: + if (!pr2) + pr1 = NULL; + break; + case INITIATOR: + if (!pr1) + pr2 = NULL; + break; + } + } + + /* should be matched all protocols in a proposal */ + if (pr1 != NULL || pr2 != NULL) + goto err; + + return newpp; + +err: + flushsaprop(newpp); + return NULL; +} + +/* take a single match between saprop. returns 0 if pp1 equals to pp2. */ +int +cmpsaprop(pp1, pp2) + const struct saprop *pp1, *pp2; +{ + if (pp1->pfs_group != pp2->pfs_group) { + plog(LLV_WARNING, LOCATION, NULL, + "pfs_group mismatch. mine:%d peer:%d\n", + pp1->pfs_group, pp2->pfs_group); + /* FALLTHRU */ + } + + if (pp1->lifetime > pp2->lifetime) { + plog(LLV_WARNING, LOCATION, NULL, + "less lifetime proposed. mine:%d peer:%d\n", + (int)pp1->lifetime, (int)pp2->lifetime); + /* FALLTHRU */ + } + if (pp1->lifebyte > pp2->lifebyte) { + plog(LLV_WARNING, LOCATION, NULL, + "less lifebyte proposed. mine:%d peer:%d\n", + pp1->lifebyte, pp2->lifebyte); + /* FALLTHRU */ + } + + return 0; +} + +/* + * take a single match between satrns. returns 0 if tr1 equals to tr2. + * tr1: peer's satrns + * tr2: my satrns + */ +int +cmpsatrns(proto_id, tr1, tr2) + int proto_id; + const struct satrns *tr1, *tr2; +{ + if (tr1->trns_id != tr2->trns_id) { + plog(LLV_WARNING, LOCATION, NULL, + "trns_id mismatched: " + "my:%s peer:%s\n", + s_ipsecdoi_trns(proto_id, tr2->trns_id), + s_ipsecdoi_trns(proto_id, tr1->trns_id)); + return 1; + } + + if (tr1->authtype != tr2->authtype) { + plog(LLV_WARNING, LOCATION, NULL, + "authtype mismatched: " + "my:%s peer:%s\n", + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype), + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype)); + return 1; + } + + /* XXX + * At this moment for interoperability, the responder obey + * the initiator. It should be defined a notify message. + */ + if (tr1->encklen > tr2->encklen) { + plog(LLV_WARNING, LOCATION, NULL, + "less key length proposed, " + "mine:%d peer:%d. Use initiaotr's one.\n", + tr2->encklen, tr1->encklen); + /* FALLTHRU */ + } + + return 0; +} + +int +set_satrnsbysainfo(pr, sainfo) + struct saproto *pr; + struct sainfo *sainfo; +{ + struct sainfoalg *a, *b; + struct satrns *newtr; + int t; + + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + if (sainfo->algs[algclass_ipsec_auth] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no auth algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) { + + if (a->alg == IPSECDOI_ATTR_AUTH_NONE) + continue; + + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg); + newtr->authtype = a->alg; + + inssatrns(pr, newtr); + } + break; + case IPSECDOI_PROTO_IPSEC_ESP: + if (sainfo->algs[algclass_ipsec_enc] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no encryption algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) { + for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) { + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = a->alg; + newtr->encklen = a->encklen; + newtr->authtype = b->alg; + + inssatrns(pr, newtr); + } + } + break; + case IPSECDOI_PROTO_IPCOMP: + if (sainfo->algs[algclass_ipsec_comp] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no ipcomp algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) { + + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = a->alg; + newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/ + + inssatrns(pr, newtr); + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown proto_id (%d).\n", pr->proto_id); + goto err; + } + + /* no proposal found */ + if (pr->head == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n"); + return -1; + } + + return 0; + +err: + flushsatrns(pr->head); + return -1; +} + +struct saprop * +aproppair2saprop(p0) + struct prop_pair *p0; +{ + struct prop_pair *p, *t; + struct saprop *newpp; + struct saproto *newpr; + struct satrns *newtr; + u_int8_t *spi; + + if (p0 == NULL) + return NULL; + + /* allocate ipsec a sa proposal */ + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + return NULL; + } + newpp->prop_no = p0->prop->p_no; + /* lifetime & lifebyte must be updated later */ + + for (p = p0; p; p = p->next) { + + /* allocate ipsec sa protocol */ + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + + /* check spi size */ + /* XXX should be handled isakmp cookie */ + if (sizeof(newpr->spi) < p->prop->spi_size) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid spi size %d.\n", p->prop->spi_size); + goto err; + } + + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + newpr->proto_id = p->prop->proto_id; + newpr->spisize = p->prop->spi_size; + memset(&newpr->spi, 0, sizeof(newpr->spi)); + spi = (u_int8_t *)&newpr->spi; + spi += sizeof(newpr->spi); + spi -= p->prop->spi_size; + memcpy(spi, p->prop + 1, p->prop->spi_size); + newpr->reqid_in = 0; + newpr->reqid_out = 0; + + for (t = p; t; t = t->tnext) { + + plog(LLV_DEBUG, LOCATION, NULL, + "prop#=%d prot-id=%s spi-size=%d " + "#trns=%d trns#=%d trns-id=%s\n", + t->prop->p_no, + s_ipsecdoi_proto(t->prop->proto_id), + t->prop->spi_size, t->prop->num_t, + t->trns->t_no, + s_ipsecdoi_trns(t->prop->proto_id, + t->trns->t_id)); + + /* allocate ipsec sa transform */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + if (ipsecdoi_t2satrns(t->trns, newpp, newpr, newtr) < 0) { + flushsaprop(newpp); + return NULL; + } + + inssatrns(newpr, newtr); + } + + /* + * If the peer does not specify encryption mode, use + * transport mode by default. This is to conform to + * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies + * that unspecified == transport), as well as RFC2407 + * (unspecified == implementation dependent default). + */ + if (newpr->encmode == 0) + newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS; + + inssaproto(newpp, newpr); + } + + return newpp; + +err: + flushsaprop(newpp); + return NULL; +} + +void +flushsaprop(head) + struct saprop *head; +{ + struct saprop *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + flushsaproto(p->head); + racoon_free(p); + } + + return; +} + +void +flushsaproto(head) + struct saproto *head; +{ + struct saproto *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + flushsatrns(p->head); + vfree(p->keymat); + vfree(p->keymat_p); + racoon_free(p); + } + + return; +} + +void +flushsatrns(head) + struct satrns *head; +{ + struct satrns *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + racoon_free(p); + } + + return; +} + +/* + * print multiple proposals + */ +void +printsaprop(pri, pp) + const int pri; + const struct saprop *pp; +{ + const struct saprop *p; + + if (pp == NULL) { + plog(pri, LOCATION, NULL, "(null)"); + return; + } + + for (p = pp; p; p = p->next) { + printsaprop0(pri, p); + } + + return; +} + +/* + * print one proposal. + */ +void +printsaprop0(pri, pp) + int pri; + const struct saprop *pp; +{ + const struct saproto *p; + + if (pp == NULL) + return; + + for (p = pp->head; p; p = p->next) { + printsaproto(pri, p); + } + + return; +} + +void +printsaproto(pri, pr) + const int pri; + const struct saproto *pr; +{ + struct satrns *tr; + + if (pr == NULL) + return; + + plog(pri, LOCATION, NULL, + " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx " + "encmode=%s reqid=%d:%d)\n", + s_ipsecdoi_proto(pr->proto_id), + (int)pr->spisize, + (unsigned long)ntohl(pr->spi), + (unsigned long)ntohl(pr->spi_p), + s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode), + (int)pr->reqid_in, (int)pr->reqid_out); + + for (tr = pr->head; tr; tr = tr->next) { + printsatrns(pri, pr->proto_id, tr); + } + + return; +} + +void +printsatrns(pri, proto_id, tr) + const int pri; + const int proto_id; + const struct satrns *tr; +{ + if (tr == NULL) + return; + + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + plog(pri, LOCATION, NULL, + " (trns_id=%s authtype=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id), + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); + break; + case IPSECDOI_PROTO_IPSEC_ESP: + plog(pri, LOCATION, NULL, + " (trns_id=%s encklen=%d authtype=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id), + tr->encklen, + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); + break; + case IPSECDOI_PROTO_IPCOMP: + plog(pri, LOCATION, NULL, + " (trns_id=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id)); + break; + default: + plog(pri, LOCATION, NULL, + "(unknown proto_id %d)\n", proto_id); + } + + return; +} + +void +print_proppair0(pri, p, level) + int pri; + struct prop_pair *p; + int level; +{ + char spc[21]; + + memset(spc, ' ', sizeof(spc)); + spc[sizeof(spc) - 1] = '\0'; + if (level < 20) { + spc[level] = '\0'; + } + + plog(pri, LOCATION, NULL, + "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext); + if (p->next) + print_proppair0(pri, p->next, level + 1); + if (p->tnext) + print_proppair0(pri, p->tnext, level + 1); +} + +void +print_proppair(pri, p) + int pri; + struct prop_pair *p; +{ + print_proppair0(pri, p, 1); +} + +int +set_proposal_from_policy(iph2, sp_main, sp_sub) + struct ph2handle *iph2; + struct secpolicy *sp_main, *sp_sub; +{ + struct saprop *newpp; + struct ipsecrequest *req; + int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */ + + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + goto err; + } + newpp->prop_no = 1; + newpp->lifetime = iph2->sainfo->lifetime; + newpp->lifebyte = iph2->sainfo->lifebyte; + newpp->pfs_group = iph2->sainfo->pfs_group; + + if (lcconf->complex_bundle) + goto skip1; + + /* + * decide the encryption mode of this SA bundle. + * the mode becomes tunnel mode when there is even one policy + * of tunnel mode in the SPD. otherwise the mode becomes + * transport mode. + */ + encmodesv = IPSEC_MODE_TRANSPORT; + for (req = sp_main->req; req; req = req->next) { + if (req->saidx.mode == IPSEC_MODE_TUNNEL) { + encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode); +#ifdef ENABLE_NATT + if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED)) + encmodesv += iph2->ph1->natt_options->mode_udp_diff; +#endif + break; + } + } + + skip1: + for (req = sp_main->req; req; req = req->next) { + struct saproto *newpr; + caddr_t paddr = NULL; + + /* + * check if SA bundle ? + * nested SAs negotiation is NOT supported. + * me +--- SA1 ---+ peer1 + * me +--- SA2 --------------+ peer2 + */ +#ifdef __linux__ + if (req->saidx.src.ss_family && req->saidx.dst.ss_family) { +#else + if (req->saidx.src.ss_len && req->saidx.dst.ss_len) { +#endif + /* check the end of ip addresses of SA */ + if (iph2->side == INITIATOR) + paddr = (caddr_t)&req->saidx.dst; + else + paddr = (caddr_t)&req->saidx.src; + } + + /* allocate ipsec sa protocol */ + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + + newpr->proto_id = ipproto2doi(req->saidx.proto); + if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP) + newpr->spisize = 2; + else + newpr->spisize = 4; + if (lcconf->complex_bundle) { + newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode); +#ifdef ENABLE_NATT + if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED)) + newpr->encmode += iph2->ph1->natt_options->mode_udp_diff; +#endif + } + else + newpr->encmode = encmodesv; + + if (iph2->side == INITIATOR) + newpr->reqid_out = req->saidx.reqid; + else + newpr->reqid_in = req->saidx.reqid; + + if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get algorithms.\n"); + goto err; + } + + /* set new saproto */ + inssaprotorev(newpp, newpr); + } + + /* get reqid_in from inbound policy */ + if (sp_sub) { + struct saproto *pr; + + req = sp_sub->req; + pr = newpp->head; + while (req && pr) { + if (iph2->side == INITIATOR) + pr->reqid_in = req->saidx.reqid; + else + pr->reqid_out = req->saidx.reqid; + pr = pr->next; + req = req->next; + } + if (pr || req) { + plog(LLV_NOTIFY, LOCATION, NULL, + "There is a difference " + "between the in/out bound policies in SPD.\n"); + } + } + + iph2->proposal = newpp; + + printsaprop0(LLV_DEBUG, newpp); + + return 0; +err: + return -1; +} + +/* + * generate a policy from peer's proposal. + * this function unconditionally chooses the first proposal the in SA payload + * passed by peer. + */ +int +set_proposal_from_proposal(iph2) + struct ph2handle *iph2; +{ + struct saprop *newpp = NULL, *pp0, *pp_peer = NULL; + struct saproto *newpr = NULL, *pr; + struct prop_pair **pair; + int error = -1; + int i; + + /* get proposal pair */ + pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (pair == NULL) + goto end; + + /* + * make my proposal according as the client proposal. + * XXX assumed there is only one proposal even if it's the SA bundle. + */ + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + pp_peer = aproppair2saprop(pair[i]); + if (pp_peer == NULL) + goto end; + + pp0 = newsaprop(); + if (pp0 == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + goto end; + } + pp0->prop_no = 1; + pp0->lifetime = iph2->sainfo->lifetime; + pp0->lifebyte = iph2->sainfo->lifebyte; + pp0->pfs_group = iph2->sainfo->pfs_group; + + if (pp_peer->next != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "pp_peer is inconsistency, ignore it.\n"); + /*FALLTHROUGH*/ + } + + for (pr = pp_peer->head; pr; pr = pr->next) { + + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto end; + } + newpr->proto_id = pr->proto_id; + newpr->spisize = pr->spisize; + newpr->encmode = pr->encmode; + newpr->spi = 0; + newpr->spi_p = pr->spi; /* copy peer's SPI */ + newpr->reqid_in = 0; + newpr->reqid_out = 0; + } + + if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get algorithms.\n"); + goto end; + } + + inssaproto(pp0, newpr); + inssaprop(&newpp, pp0); + } + + plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n"); + printsaprop0(LLV_DEBUG, newpp); + + iph2->proposal = newpp; + + error = 0; + +end: + if (error && newpp) + flushsaprop(newpp); + + if (pp_peer) + flushsaprop(pp_peer); + free_proppair(pair); + return error; +} + +int +tunnel_mode_prop(p) + struct saprop *p; +{ + struct saproto *pr; + + for (pr = p->head; pr; pr = pr->next) + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) + return 1; + return 0; +} diff --git a/ipsec-tools/racoon/proposal.h b/ipsec-tools/racoon/proposal.h new file mode 100644 index 0000000..e95752b --- /dev/null +++ b/ipsec-tools/racoon/proposal.h @@ -0,0 +1,211 @@ +/* $Id: proposal.h,v 1.5.10.1 2005/05/12 19:34:10 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PROPOSAL_H +#define _PROPOSAL_H + +#include + +/* + * A. chained list of transform, only for single proto_id + * (this is same as set of transforms in single proposal payload) + * B. proposal. this will point to multiple (A) items (order is important + * here so pointer to (A) must be ordered array, or chained list). + * this covers multiple proposal on a packet if proposal # is the same. + * C. finally, (B) needs to be connected as chained list. + * + * head ---> prop[.......] ---> prop[...] ---> prop[...] ---> ... + * | | | | + * | | | +- proto4 <== must preserve order here + * | | +--- proto3 + * | +----- proto2 + * +------- proto1[trans1, trans2, trans3, ...] + * + * incoming packets needs to be parsed to construct the same structure + * (check "prop_pair" too). + */ +/* SA proposal specification */ +struct saprop { + int prop_no; + time_t lifetime; + int lifebyte; + int pfs_group; /* pfs group */ + int claim; /* flag to send RESPONDER-LIFETIME. */ + /* XXX assumed DOI values are 1 or 2. */ + + struct saproto *head; + struct saprop *next; +}; + +/* SA protocol specification */ +struct saproto { + int proto_id; + size_t spisize; /* spi size */ + int encmode; /* encryption mode */ + + int udp_encap; /* UDP encapsulation */ + + /* XXX should be vchar_t * */ + /* these are network byte order */ + u_int32_t spi; /* inbound. i.e. --SA-> me */ + u_int32_t spi_p; /* outbound. i.e. me -SA-> */ + + vchar_t *keymat; /* KEYMAT */ + vchar_t *keymat_p; /* peer's KEYMAT */ + + int reqid_out; /* request id (outbound) */ + int reqid_in; /* request id (inbound) */ + + int ok; /* if 1, success to set SA in kenrel */ + + struct satrns *head; /* header of transform */ + struct saproto *next; /* next protocol */ +}; + +/* SA algorithm specification */ +struct satrns { + int trns_no; + int trns_id; /* transform id */ + int encklen; /* key length of encryption algorithm */ + int authtype; /* authentication algorithm if ESP */ + + struct satrns *next; /* next transform */ +}; + +/* + * prop_pair: (proposal number, transform number) + * + * (SA (P1 (T1 T2)) (P1' (T1' T2')) (P2 (T1" T2"))) + * + * p[1] p[2] + * top (P1,T1) (P2",T1") + * | |tnext |tnext + * | v v + * | (P1, T2) (P2", T2") + * v next + * (P1', T1') + * |tnext + * v + * (P1', T2') + * + * when we convert it to saprop in prop2saprop(), it should become like: + * + * (next) + * saprop --------------------> saprop + * | (head) | (head) + * +-> saproto +-> saproto + * | | (head) | (head) + * | +-> satrns(P1 T1) +-> satrns(P2" T1") + * | | (next) | (next) + * | v v + * | satrns(P1, T2) satrns(P2", T2") + * v (next) + * saproto + * | (head) + * +-> satrns(P1' T1') + * | (next) + * v + * satrns(P1', T2') + */ +struct prop_pair { + struct isakmp_pl_p *prop; + struct isakmp_pl_t *trns; + struct prop_pair *next; /* next prop_pair with same proposal # */ + /* (bundle case) */ + struct prop_pair *tnext; /* next prop_pair in same proposal payload */ + /* (multiple tranform case) */ +}; +#define MAXPROPPAIRLEN 256 /* It's enough because field size is 1 octet. */ + +/* + * Lifetime length selection refered to the section 4.5.4 of RFC2407. It does + * not completely conform to the description of RFC. There are four types of + * the behavior. If the value of "proposal_check" in "remote" directive is; + * "obey" + * the responder obey the initiator anytime. + * "strict" + * If the responder's length is longer than the initiator's one, the + * responder uses the intitiator's one. Otherwise rejects the proposal. + * If PFS is not required by the responder, the responder obeys the + * proposal. If PFS is required by both sides and if the responder's + * group is not equal to the initiator's one, then the responder reject + * the proposal. + * "claim" + * If the responder's length is longer than the initiator's one, the + * responder use the intitiator's one. If the responder's length is + * shorter than the initiator's one, the responder uses own length + * AND send RESPONDER-LIFETIME notify message to a initiator in the + * case of lifetime. + * About PFS, this directive is same as "strict". + * "exact" + * If the initiator's length is not equal to the responder's one, the + * responder rejects the proposal. + * If PFS is required and if the responder's group is not equal to + * the initiator's one, then the responder reject the proposal. + * XXX should be defined the behavior of key length. + */ +#define PROP_CHECK_OBEY 1 +#define PROP_CHECK_STRICT 2 +#define PROP_CHECK_CLAIM 3 +#define PROP_CHECK_EXACT 4 + +struct sainfo; +struct ph1handle; +struct secpolicy; +extern struct saprop *newsaprop __P((void)); +extern struct saproto *newsaproto __P((void)); +extern void inssaprop __P((struct saprop **, struct saprop *)); +extern void inssaproto __P((struct saprop *, struct saproto *)); +extern void inssaprotorev __P((struct saprop *, struct saproto *)); +extern struct satrns *newsatrns __P((void)); +extern void inssatrns __P((struct saproto *, struct satrns *)); +extern struct saprop *cmpsaprop_alloc __P((struct ph1handle *, + const struct saprop *, const struct saprop *, int)); +extern int cmpsaprop __P((const struct saprop *, const struct saprop *)); +extern int cmpsatrns __P((int, const struct satrns *, const struct satrns *)); +extern int set_satrnsbysainfo __P((struct saproto *, struct sainfo *)); +extern struct saprop *aproppair2saprop __P((struct prop_pair *)); +extern void free_proppair __P((struct prop_pair **)); +extern void flushsaprop __P((struct saprop *)); +extern void flushsaproto __P((struct saproto *)); +extern void flushsatrns __P((struct satrns *)); +extern void printsaprop __P((const int, const struct saprop *)); +extern void printsaprop0 __P((const int, const struct saprop *)); +extern void printsaproto __P((const int, const struct saproto *)); +extern void printsatrns __P((const int, const int, const struct satrns *)); +extern void print_proppair0 __P((int, struct prop_pair *, int)); +extern void print_proppair __P((int, struct prop_pair *)); +extern int set_proposal_from_policy __P((struct ph2handle *, + struct secpolicy *, struct secpolicy *)); +extern int set_proposal_from_proposal __P((struct ph2handle *)); +extern int tunnel_mode_prop __P((struct saprop *p)); + +#endif /* _PROPOSAL_H */ diff --git a/ipsec-tools/racoon/prsa_par.y b/ipsec-tools/racoon/prsa_par.y new file mode 100644 index 0000000..b44eafc --- /dev/null +++ b/ipsec-tools/racoon/prsa_par.y @@ -0,0 +1,348 @@ +/* $Id: prsa_par.y,v 1.3 2004/11/08 12:04:23 ludvigm Exp $ */ + +%{ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include +#include +#include +#include + +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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 HEX +%type NUMBER +%type ADDR4 ADDR6 BASE64 + +%type rsa_statement +%type prefix +%type addr4 addr6 addr + +%% +statements: + statements statement + | statement + ; + +statement: + addr addr COLON rsa_statement + { + rsa_key_insert(prsa_cur_list, $1, $2, $4); + } + | addr COLON rsa_statement + { + rsa_key_insert(prsa_cur_list, NULL, $1, $3); + } + | COLON rsa_statement + { + rsa_key_insert(prsa_cur_list, NULL, NULL, $2); + } + ; + +rsa_statement: + TAG_RSA OBRACE params EBRACE + { + if (prsa_cur_type == RSA_TYPE_PUBLIC) { + prsawarning("Using private key for public key purpose.\n"); + if (!rsa_cur->n || !rsa_cur->e) { + prsaerror("Incomplete key. Mandatory parameters are missing!\n"); + YYABORT; + } + } + else { + if (!rsa_cur->n || !rsa_cur->e || !rsa_cur->d) { + prsaerror("Incomplete key. Mandatory parameters are missing!\n"); + YYABORT; + } + if (!rsa_cur->p || !rsa_cur->q || !rsa_cur->dmp1 + || !rsa_cur->dmq1 || !rsa_cur->iqmp) { + if (rsa_cur->p) BN_clear_free(rsa_cur->p); + if (rsa_cur->q) BN_clear_free(rsa_cur->q); + if (rsa_cur->dmp1) BN_clear_free(rsa_cur->dmp1); + if (rsa_cur->dmq1) BN_clear_free(rsa_cur->dmq1); + if (rsa_cur->iqmp) BN_clear_free(rsa_cur->iqmp); + + rsa_cur->p = NULL; + rsa_cur->q = NULL; + rsa_cur->dmp1 = NULL; + rsa_cur->dmq1 = NULL; + rsa_cur->iqmp = NULL; + } + } + $$ = rsa_cur; + rsa_cur = RSA_new(); + } + | TAG_PUB BASE64 + { + if (prsa_cur_type == RSA_TYPE_PRIVATE) { + prsaerror("Public key in private-key file!\n"); + YYABORT; + } + $$ = base64_pubkey2rsa($2); + } + | TAG_PUB HEX + { + if (prsa_cur_type == RSA_TYPE_PRIVATE) { + prsaerror("Public key in private-key file!\n"); + YYABORT; + } + $$ = bignum_pubkey2rsa($2); + } + ; + +addr: + addr4 + | addr6 + | ADDRANY + { + $$ = NULL; + } + ; + +addr4: + ADDR4 prefix + { + int err; + struct sockaddr_in *sap; + + if ($2 == -1) $2 = 32; + if ($2 < 0 || $2 > 32) { + prsaerror ("Invalid IPv4 prefix\n"); + YYABORT; + } + $$ = calloc (sizeof(struct netaddr), 1); + $$->prefix = $2; + sap = (struct sockaddr_in *)(&$$->sa); + sap->sin_family = AF_INET; + err = inet_pton(AF_INET, $1, (struct in_addr*)(&sap->sin_addr)); + if (err <= 0) { + prsaerror("inet_pton(%s): %s\n", $1, strerror(errno)); + YYABORT; + } + } + ; + +addr6: + ADDR6 prefix + { + int err; + struct sockaddr_in6 *sap; + + if ($2 == -1) $2 = 128; + if ($2 < 0 || $2 > 128) { + prsaerror ("Invalid IPv6 prefix\n"); + YYABORT; + } + $$ = calloc (sizeof(struct netaddr), 1); + $$->prefix = $2; + sap = (struct sockaddr_in6 *)(&$$->sa); + sap->sin6_family = AF_INET6; + err = inet_pton(AF_INET6, $1, (struct in6_addr*)(&sap->sin6_addr)); + if (err <= 0) { + prsaerror("inet_pton(%s): %s\n", $1, strerror(errno)); + YYABORT; + } + } + ; + +prefix: + /* nothing */ { $$ = -1; } + | SLASH NUMBER { $$ = $2; } + ; +params: + params param + | param + ; + +param: + MODULUS COLON HEX + { if (!rsa_cur->n) rsa_cur->n = $3; else { prsaerror ("Modulus already defined\n"); YYABORT; } } + | PUBLIC_EXPONENT COLON HEX + { if (!rsa_cur->e) rsa_cur->e = $3; else { prsaerror ("PublicExponent already defined\n"); YYABORT; } } + | PRIVATE_EXPONENT COLON HEX + { if (!rsa_cur->d) rsa_cur->d = $3; else { prsaerror ("PrivateExponent already defined\n"); YYABORT; } } + | PRIME1 COLON HEX + { if (!rsa_cur->p) rsa_cur->p = $3; else { prsaerror ("Prime1 already defined\n"); YYABORT; } } + | PRIME2 COLON HEX + { if (!rsa_cur->q) rsa_cur->q = $3; else { prsaerror ("Prime2 already defined\n"); YYABORT; } } + | EXPONENT1 COLON HEX + { if (!rsa_cur->dmp1) rsa_cur->dmp1 = $3; else { prsaerror ("Exponent1 already defined\n"); YYABORT; } } + | EXPONENT2 COLON HEX + { if (!rsa_cur->dmq1) rsa_cur->dmq1 = $3; else { prsaerror ("Exponent2 already defined\n"); YYABORT; } } + | COEFFICIENT COLON HEX + { if (!rsa_cur->iqmp) rsa_cur->iqmp = $3; else { prsaerror ("Coefficient already defined\n"); YYABORT; } } + ; +%% + +int prsaparse(void); + +int +prsa_parse_file(struct genlist *list, char *fname, enum rsa_key_type type) +{ + FILE *fp = NULL; + int ret; + + if (!fname) + return -1; + if (type == RSA_TYPE_PRIVATE) { + struct stat st; + if (stat(fname, &st) < 0) + return -1; + if (st.st_mode & (S_IRWXG | S_IRWXO)) { + plog(LLV_ERROR, LOCATION, NULL, + "Too slack permissions on private key '%s'\n", + fname); + plog(LLV_ERROR, LOCATION, NULL, + "Should be at most 0600, now is 0%o\n", + st.st_mode & 0777); + return -1; + } + } + fp = fopen(fname, "r"); + if (!fp) + return -1; + prsain = fp; + prsa_cur_lineno = 1; + prsa_cur_fname = fname; + prsa_cur_list = list; + prsa_cur_type = type; + rsa_cur = RSA_new(); + ret = prsaparse(); + if (rsa_cur) { + RSA_free(rsa_cur); + rsa_cur = NULL; + } + fclose (fp); + prsain = NULL; + return ret; +} diff --git a/ipsec-tools/racoon/prsa_tok.l b/ipsec-tools/racoon/prsa_tok.l new file mode 100644 index 0000000..be0d26c --- /dev/null +++ b/ipsec-tools/racoon/prsa_tok.l @@ -0,0 +1,91 @@ +/* $Id: prsa_tok.l,v 1.2 2004/07/12 20:43:51 ludvigm Exp $ */ + +%{ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include +#include +#ifdef __APPLE__ +#include "y.tab.h" +#else +#include "prsa_par.h" +#endif + +extern int prsalex (void); +extern int prsa_cur_lineno; + +%} + +comment \#.* +digit [0-9] +octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5]))) +addr4 {octet}\.{octet}\.{octet}\.{octet} +hex [0-9a-fA-F] +word6 {hex}{0,4} +base64 [A-Za-z0-9+/=] +addr6 (::({word6}|{addr4})?|({word6}:)+:?({word6}|{addr4})?) +%% +\{ { return OBRACE; } +\} { return EBRACE; } +: { return COLON; } +RSA { return TAG_RSA; } +PSK { return TAG_PSK; } +PUB { return TAG_PUB; } +0x[0-9a-fA-F]+ { + BIGNUM *bn = BN_new(); + BN_hex2bn(&bn, prsatext+2); + prsalval.bn = bn; + return HEX; + } +0s{base64}+ { + prsalval.chr = strdup(prsatext); + return BASE64; + } +Modulus { return MODULUS; } +PublicExponent { return PUBLIC_EXPONENT; } +PrivateExponent { return PRIVATE_EXPONENT; } +Prime1 { return PRIME1; } +Prime2 { return PRIME2; } +Exponent1 { return EXPONENT1; } +Exponent2 { return EXPONENT2; } +Coefficient { return COEFFICIENT; } +\/ { return SLASH; } +{digit}+ { prsalval.num = atol(prsatext); return NUMBER; } +any { return ADDRANY; } +{addr4} { prsalval.chr = strdup(prsatext); return ADDR4; } +{addr6} { prsalval.chr = strdup(prsatext); return ADDR6; } +[ \t]* ; +\n { prsa_cur_lineno++; } +\#.* ; +%% diff --git a/ipsec-tools/racoon/racoon.8 b/ipsec-tools/racoon/racoon.8 new file mode 100644 index 0000000..8e02322 --- /dev/null +++ b/ipsec-tools/racoon/racoon.8 @@ -0,0 +1,157 @@ +.\" $Id: racoon.8,v 1.3.10.1 2005/04/18 11:10:55 manubsd Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 20, 2000 +.Dt RACOON 8 +.Os +.\" +.Sh NAME +.Nm racoon +.Nd IKE (ISAKMP/Oakley) key management daemon +.\" +.Sh SYNOPSIS +.Nm racoon +.Bk -words +.Op Fl 46BdFLv +.Ek +.Bk -words +.Op Fl f Ar configfile +.Ek +.Bk -words +.Op Fl l Ar logfile +.Ek +.Bk -words +.Op Fl P Ar isakmp-natt-port +.Ek +.Bk -words +.Op Fl p Ar isakmp-port +.Ek +.\" +.Sh DESCRIPTION +.Nm +speaks the IKE +.Pq ISAKMP/Oakley +key management protocol, +to establish security associations with other hosts. +The SPD +.Pq Security Policy Database +in the kernel usually triggers +.Nm . +.Nm +usually sends all informational messages, warnings and error messages to +.Xr syslogd 8 +with the facility +.Dv LOG_DAEMON +and the priority +.Dv LOG_INFO . +Debugging messages are sent with the priority +.Dv LOG_DEBUG . +You should configure +.Xr syslog.conf 5 +appropriately to see these messages. +.Bl -tag -width Ds +.It Fl 4 +.It Fl 6 +Specify the default address family for the sockets. +.It Fl B +Install SA(s) from the file which is specified in +.Xr racoon.conf 5 . +.It Fl d +Increase the debug level. +Multiple +.Fl d +arguments will increase the debug level even more. +.It Fl F +Run +.Nm +in the foreground. +.It Fl f Ar configfile +Use +.Ar configfile +as the configuration file instead of the default. +.It Fl L +Include +.Ar file_name:line_number:function_name +in all messages. +.It Fl l Ar logfile +Use +.Ar logfile +as the logging file instead of +.Xr syslogd 8 . +.It Fl P Ar isakmp-natt-port +Use +.Ar isakmp-natt-port +for NAT-Traversal port-floating. +The default is 4500. +.It Fl p Ar isakmp-port +Listen to the ISAKMP key exchange on port +.Ar isakmp-port +instead of the default port number, 500. +.It Fl v +This flag causes the packet dump be more verbose, with higher +debugging level. +.El +.Pp +.Nm +assumes the presence of the kernel random number device +.Xr rnd 4 +at +.Pa /dev/urandom . +.\" +.Sh RETURN VALUES +The command exits with 0 on success, and non-zero on errors. +.\" +.Sh FILES +.Bl -tag -width /private/etc/racoon/remote/anonymous -compact +.It Pa /private/etc/racoon/racoon.conf +default configuration file. +.It Pa /private/etc/racoon/remote/anonymous +default anonymous configuration file. +.It Pa /private/etc/racoon/psk.txt +default pre-shared key file. +.El +.\" +.Sh SEE ALSO +.Xr ipsec 4 , +.Xr racoon.conf 5 , +.Xr syslog.conf 5 , +.Xr setkey 8 , +.Xr syslogd 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in the +.Dq YIPS +Yokogawa IPsec implementation. +.\" +.Sh SECURITY CONSIDERATIONS +The use of IKE phase 1 aggressive mode is not recommended, +as described in +.Pa http://www.kb.cert.org/vuls/id/886601 . diff --git a/ipsec-tools/racoon/racoon.conf.5 b/ipsec-tools/racoon/racoon.conf.5 new file mode 100644 index 0000000..1183e61 --- /dev/null +++ b/ipsec-tools/racoon/racoon.conf.5 @@ -0,0 +1,1158 @@ +.\" $Id: racoon.conf.5,v 1.27.2.12 2005/11/25 16:06:32 manubsd Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 23, 2004 +.Dt RACOON.CONF 5 +.Os +.\" +.Sh NAME +.Nm racoon.conf +.Nd configuration file for racoon +.\" +.\" .Sh SYNOPSIS +.\" +.Sh DESCRIPTION +.Nm +is the configuration file for the +.Xr racoon 8 +ISAKMP daemon. +.Xr racoon 8 +negotiates security associations for itself (ISAKMP SA, or phase 1 SA) +and for kernel IPsec (IPsec SA, or phase 2 SA). +The file consists of a sequence of directives and statements. +Each directive is composed by a tag and statements, enclosed by +.Ql { +and +.Ql } . +Lines beginning with +.Ql # +are comments. +.\" +.Ss Meta Syntax +Keywords and special characters that the parser expects exactly are +displayed using +.Ic this +font. +Parameters are specified with +.Ar this +font. +Square brackets +.Po +.Ql \&[ +and +.Ql \&] +.Pc +are used to show optional keywords and parameters. +Note that +you have to pay attention when this manual is describing +.Ar port +numbers. +The +.Ar port +number is always enclosed by +.Ql \&[ +and +.Ql \&] . +In this case, the port number is not an optional keyword. +If it is possible to omit the +.Ar port +number, +the expression becomes +.Bq Bq Ar port . +The vertical bar +.Pq Ql \&| +is used to indicate +a choice between optional parameters. +Parentheses +.Po +.Ql \&( +and +.Ql \&) +.Pc +are used to group keywords and parameters when necessary. +Major parameters are listed below. +.Pp +.Bl -tag -width addressx -compact +.It Ar number +means a hexadecimal or a decimal number. +The former must be prefixed with +.Ql Li 0x . +.It Ar string +.It Ar path +.It Ar file +means any string enclosed in +.Ql \&" +.Pq double quotes . +.It Ar address +means IPv6 and/or IPv4 address. +.It Ar port +means a TCP/UDP port number. +The port number is always enclosed by +.Ql \&[ +and +.Ql \&] . +.It Ar timeunit +is one of following: +.Ic sec , secs , second , seconds , +.Ic min , mins , minute , minutes , +.Ic hour , hours . +.El +.\" +.Ss Privilege separation +.Bl -tag -width Ds -compact +.It Ic privsep { Ar statements Ic } +specifies privilege separation parameters. +When enabled, these enable +.Xr racoon 8 +to operate with an unprivileged instance doing most of the work, while +a privileged instance takes care of performing the following operations +as root: reading PSK and private keys, launching hook scripts, and +validating passwords against system databases or against PAM. +.Pp +.Bl -tag -width Ds -compact +.It Ic user Ar user ; +The user to which the unprivileged instance of +.Xr racoon 8 , +should switch. +This can be a quoted user name or a numeric UID. +.It Ic group Ar group ; +The group to which the unprivileged instance of +.Xr racoon 8 , +should switch. +This can be a quoted group name or a numeric GID. +.It Ic chroot Ar path ; +A directory to which the unprivileged instance of +.Xr racoon 8 +should +.Xr chroot 2 . +This directory should hold a tree where the following files must be +reachable: +.Bl -tag -width Ds -compact +.It Pa /dev/random +.It Pa /dev/urandom +.It the certificates +.It the file containing the Xauth banner +.El +.Pp +The PSK file, the private keys, and the hook scripts are accessed through the +privileged instance of +.Xr racoon 8 +and do not need to be reachable in the +.Xr chroot 2 Ap ed +tree. +.El +.El +.Ss Path Specification +This section specify various paths used by racoon. +When running in privilege separation mode, +.Ic certificate +and +.Ic script +paths are mandatory. +.Bl -tag -width Ds -compact +.It Ic path include Ar path ; +specifies a path to include a file. +See +.Sx File Inclusion . +.It Ic path pre_shared_key Ar file ; +specifies a file containing pre-shared key(s) for various ID(s). +See +.Sx Pre-shared key File . +.It Ic path certificate Ar path ; +.Xr racoon 8 +will search this directory if a certificate or certificate request is received. +If you run with privilege separation, +.Xr racoon 8 +will refuse to use a certificate stored outside of this directory. +.It Ic path backupsa Ar file ; +specifies a file to which SA information which is negotiated by +racoon should be stored. +.Xr racoon 8 +will install SA(s) from the file when started with the +.Fl B +flag. +The file is growing because +.Xr racoon 8 +simply adds SAs to it. +You should maintain the file manually. +.It Ic path script Ar path ; +.Xr racoon 8 +will search this directory for scripts hooks. +If you run with privilege separation, +.Xr racoon 8 +will refuse to execute a script stored outside of this directory. +.It Ic path pidfile Ar file ; +specifies file where to store PID of process. +If path starts with +.Pa / +it is treated as +an absolute path, otherwise relative to VARRUN directory specified at +compilation time. +Default is +.Pa racoon.pid . +.It Ic path logfile Ar file ; +specifies log file path. +.El +.\" +.Ss File Inclusion +.Bl -tag -width Ds -compact +.It Ic include Ar file +other configuration files can be included. +.El +.\" +.Ss Identifier Specification +is obsolete. +It must be defined at each +.Ic remote +directive. +.\" +.Ss Timer Specification +.Bl -tag -width Ds -compact +.It Ic timer { Ar statements Ic } +specifies various timer values. +.Pp +.Bl -tag -width Ds -compact +.It Ic counter Ar number ; +the maximum number of retries to send. +The default is 5. +.It Ic interval Ar number Ar timeunit ; +the interval to resend, in seconds. +The default time is 10 seconds. +.It Ic persend Ar number ; +the number of packets per send. +The default is 1. +.It Ic phase1 Ar number Ar timeunit ; +the maximum time it should take to complete phase 1. +The default time is 15 seconds. +.It Ic phase2 Ar number Ar timeunit ; +the maximum time it should take to complete phase 2. +The default time is 10 seconds. +.It Ic natt_keepalive Ar number Ar timeunit ; +interval between sending NAT-Traversal keep-alive packets. +The default time is 20 seconds. +Set to 0s to disable keep-alive packets. +.El +.El +.\" +.Ss Listening Port Specification +.Bl -tag -width Ds -compact +.It Ic listen { Ar statements Ic } +If no +.Ar listen +directive is specified, +.Xr racoon 8 +will listen on all available interface addresses. +The following is the list of valid statements: +.Pp +.Bl -tag -width Ds -compact +.\" How do I express bold brackets; `[' and `]' . +.\" Answer: For bold brackets, do "Ic \&[ foo \&]". +.\" Is the "Bq Ic [ Ar port ] ;" buggy ? +.It Ic isakmp Ar address Bq Bq Ar port ; +If this is specified, +.Xr racoon 8 +will only listen on +.Ar address . +The default port is 500, which is specified by IANA. +You can provide more than one address definition. +.It Ic isakmp_natt Ar address Bq Ar port ; +Same as +.Ic isakmp +but also sets the socket options to accept UDP-encapsulated ESP traffic for +NAT-Traversal. +If you plan to use NAT-T, you should provide at least one address +with port 4500, which is specified by IANA. +There is no default. +.It Ic strict_address ; +require that all addresses for ISAKMP must be bound. +This statement will be ignored if you do not specify any address. +.El +The +.Ar listen +section can also be used to specify the admin socket mode and ownership, +if racoon was built with support for admin port. +.Bl -tag -width Ds -compact +.It Ic adminsock Ar path Op Ar owner\ group\ mode ; +.Ar path , +.Ar owner , +and +.Ar group +are the socket path, owner, and group; they must be quoted. +Defaults are +.Pa /var/racoon/racoon.sock , +UID 0, and GID 0. +.Ar mode +is the access mode in octal, default is 0600. +.It Ic adminsock disabled ; +This directive tells racoon to not listen on the admin socket. +.El +.El +.\" +.Ss Miscellaneous Global Parameters +.Bl -tag -width Ds -compact +.It Ic gss_id_enc Ar enctype ; +Older versions of +.Xr racoon 8 +used ISO-Latin-1 as the encoding of the GSS-API identifier attribute. +For interoperability with Microsoft Windows' GSS-API authentication +scheme, the default encoding has been changed to UTF-16LE. +The +.Ic gss_id_enc +parameter allows +.Xr racoon 8 +to be configured to use the old encoding for compatibility with existing +.Xr racoon 8 +installations. +The following are valid values for +.Ar enctype : +.Pp +.Bl -tag -width Ds -compact +.It Ic utf-16le +Use UTF-16LE to encode the GSS-API identifier attribute. +This is the default encoding. +This encoding is compatible with Microsoft Windows. +.It Ic latin1 +Use ISO-Latin-1 to encode the GSS-API identifier attribute. +This is the encoding used by older versions of +.Xr racoon 8 . +.El +.El +.\" +.Ss Remote Nodes Specifications +.Bl -tag -width Ds -compact +.It Xo +.Ic remote ( Ar address | Ic anonymous ) +.Bq Bq Ar port +.Bq Ic inherit Ar parent +.Ic { Ar statements Ic } +.Xc +specifies the parameters for IKE phase 1 for each remote node. +The default port is 500. +If +.Ic anonymous +is specified, the statements apply to all peers which do not match +any other +.Ic remote +directive. +.Pp +Sections with +.Ic inherit Ar parent +statements (where +.Ar parent +is either +.Ar address +or a keyword +.Ic anonymous ) +have all values predefined to those of a given +.Ar parent . +In these sections it is enough to redefine only the changed parameters. +.Pp +The following are valid statements. +.Pp +.Bl -tag -width Ds -compact +.\" +.It Ic exchange_mode ( main | aggressive | base ) ; +defines the exchange mode for phase 1 when racoon is the initiator. +It also means the acceptable exchange mode when racoon is responder. +More than one mode can be specified by separating them with a comma. +All of the modes are acceptable. +The first exchange mode is what racoon uses when it is the initiator. +.\" +.It Ic doi Ic ipsec_doi ; +means to use IPsec DOI as specified in RFC 2407. +You can omit this statement. +.\" +.It Ic situation Ic identity_only ; +means to use SIT_IDENTITY_ONLY as specified in RFC 2407. +You can omit this statement. +.\" +.It Ic identifier Ar idtype ; +is obsolete. +Instead, use +.Ic my_identifier . +.\" +.It Ic my_identifier Ar idtype ... ; +specifies the identifier sent to the remote host +and the type to use in the phase 1 negotiation. +.Ic address, fqdn , user_fqdn , keyid , +and +.Ic asn1dn +can be used as an +.Ar idtype . +Use them in the following way: +.Bl -tag -width Ds -compact +.It Ic my_identifier Ic address Bq Ar address ; +the type is the IP address. +This is the default type if you do not specify an identifier to use. +.It Ic my_identifier Ic user_fqdn Ar string ; +the type is a USER_FQDN (user fully-qualified domain name). +.It Ic my_identifier Ic fqdn Ar string ; +the type is a FQDN (fully-qualified domain name). +.It Ic my_identifier Ic keyid Ar file ; +the type is a KEY_ID. +.It Ic my_identifier Ic asn1dn Bq Ar string ; +the type is an ASN.1 distinguished name. +If +.Ar string +is omitted, +.Xr racoon 8 +will get the DN from the Subject field in the certificate. +.El +.\" +.It Ic xauth_login Bq Ar string ; +specifies the login to use in client-side Hybrid authentication. +It is available only if +.Xr racoon 8 +has been built with this option. +The associated password is looked up in the pre-shared key files, +using the login +.Ic string +as the key id. +.\" +.It Ic peers_identifier Ar idtype ... ; +specifies the peer's identifier to be received. +If it is not defined then +.Xr racoon 8 +will not verify the peer's identifier in ID payload transmitted from the peer. +If it is defined, the behavior of the verification depends on the flag of +.Ic verify_identifier . +The usage of +.Ar idtype +is the same as +.Ic my_identifier +except that the individual component values of an +.Ic asn1dn +identifier may specified as +.Ic * +to match any value (e.g. "C=XX, O=MyOrg, OU=*, CN=Mine"). +Alternative acceptable peer identifiers may be specified by repeating the +.Ic peers_identifier +statement. +.\" +.It Ic verify_identifier (on \(ba off) ; +If you want to verify the peer's identifier, +set this to on. +In this case, if the value defined by +.Ic peers_identifier +is not the same as the peer's identifier in the ID payload, +the negotiation will failed. +The default is off. +.\" +.It Ic certificate_type Ar certspec ; +specifies a certificate specification. +.Ar certspec +is one of followings: +.Bl -tag -width Ds -compact +.It Ic x509 Ar certfile Ar privkeyfile ; +.Ar certfile +means a file name of a certificate. +.Ar privkeyfile +means a file name of a secret key. +.El +.It Ic ca_type Ar cacertspec ; +specifies a root certificate authority specification. +.Ar cacertspec +is one of followings: +.Bl -tag -width Ds -compact +.It Ic x509 Ar cacertfile ; +.Ar cacertfile +means a file name of the root certificate authority. +Default is +.Pa /etc/openssl/cert.pem +.El +.\" +.It Ic mode_cfg (on \(ba off) ; +Gather network information through ISAKMP mode configuration. +Default is off. +.\" +.It Ic peers_certfile ( dnssec | Ar certfile ) ; +If +.Ic dnssec +is defined, +.Xr racoon 8 +will ignore the CERT payload from the peer, +and try to get the peer's certificate from DNS instead. +If +.Ar certfile +is defined, +.Xr racoon 8 +will ignore the CERT payload from the peer, +and will use this certificate as the peer's certificate. +.\" +.It Ic script Ar script Ic phase1_up +.It Ic script Ar script Ic phase1_down +Shell scripts that get executed when a phase 1 SA goes up or down. +Both scripts get either +.Ic phase1_up +or +.Ic phase1_down +as first argument, and the following +variables are set in their environment: +.Bl -tag -width Ds -compact +.It Ev LOCAL_ADDR +The local address of the phase 1 SA. +.It Ev LOCAL_PORT +The local port used for IKE for the phase 1 SA. +.It Ev REMOTE_ADDR +The remote address of the phase 1 SA. +.It Ev REMOTE_PORT +The remote port used for IKE for the phase 1 SA. +.El +The following variables are only set if +.Ic mode_cfg +was enabled: +.Bl -tag -width Ds -compact +.It INTERNAL_ADDR4 +An IPv4 internal address obtained by ISAKMP mode config. +.It INTERNAL_NETMASK4 +An IPv4 internal netmask obtained by ISAKMP mode config. +.It INTERNAL_DNS4 +Internal DNS server IPv4 address obtained by ISAKMP mode config. +.It INTERNAL_NBNS4 +Internal WINS server IPv4 address obtained by ISAKMP mode config. +.El +.\" +.\" +.It Ic send_cert (on \(ba off) ; +If you do not want to send a certificate for some reason, set this to off. +The default is on. +.\" +.It Ic send_cr (on \(ba off) ; +If you do not want to send a certificate request for some reason, set this to off. +The default is on. +.\" +.It Ic verify_cert (on \(ba off) ; +If you do not want to verify the peer's certificate for some reason, +set this to off. +The default is on. +.\" +.It Ic lifetime time Ar number Ar timeunit ; +Define a lifetime of a certain time +which will be proposed in the phase 1 negotiations. +Any proposal will be accepted, and the attribute(s) will be not proposed to +the peer if you do not specify it (them). +They can be individually specified in each proposal. +.\" +.It Ic ike_frag (on \(ba off) ; +Enable receiver-side IKE fragmentation, if +.Xr racoon 8 +has been built with this feature. +This extension is there to work around +broken firewalls that do not work with fragmented UDP packets. +IKE fragmentation is always enabled on the sender-side, and +it is used if the peer advertises itself as IKE fragmentation capable. +.\" +.It Ic esp_frag Ar fraglen ; +This option is only relevant if you use NAT traversal in tunnel mode. +Its purpose is to work around broken DSL routers that reject UDP +fragments, by fragmenting the IP packets before ESP encapsulation. +The result is ESP over UDP of fragmented packets instead of fragmented +ESP over UDP packets (i.e., IP:UDP:ESP:frag(IP) instead of +frag(IP:UDP:ESP:IP)). +.Ar fraglen +is the maximum size of the fragments. +552 should work anywhere, +but the higher +.Ar fraglen +is, the better is the performance. +.Pp +Note that because PMTU discovery is broken on many sites, you will +have to use MSS clamping if you want TCP to work correctly. +.\" +.It Ic initial_contact (on \(ba off) ; +enable this to send an INITIAL-CONTACT message. +The default value is +.Ic on . +This message is useful only when +the implementation of the responder chooses an old SA when there are multiple +SAs with different established time, and the initiator reboots. +If racoon did not send the message, +the responder would use an old SA even when a new SA was established. +The KAME stack has the switch in the system wide value +net.key.preferred_oldsa. +when the value is zero, the stack always uses a new SA. +.\" +.It Ic passive (on \(ba off) ; +If you do not want to initiate the negotiation, set this to on. +The default value is +.Ic off . +It is useful for a server. +.\" +.It Ic proposal_check Ar level ; +specifies the action of lifetime length and PFS of the phase 2 +selection on the responder side, and the action of lifetime check in +phase 1. +The default level is +.Ic strict . +If the +.Ar level +is: +.Bl -tag -width Ds -compact +.It Ic obey +the responder will obey the initiator anytime. +.It Ic strict +If the responder's length is longer than the initiator's one, the +responder uses the initiator's one. +Otherwise it rejects the proposal. +If PFS is not required by the responder, the responder will obey the proposal. +If PFS is required by both sides and if the responder's group is not equal to +the initiator's one, then the responder will reject the proposal. +.It Ic claim +If the responder's length is longer than the initiator's one, the +responder will use the initiator's one. +If the responder's length is +shorter than the initiator's one, the responder uses its own length +AND sends a RESPONDER-LIFETIME notify message to an initiator in the +case of lifetime (phase 2 only). +For PFS, this directive behaves the same as +.Ic strict . +.It Ic exact +If the initiator's length is not equal to the responder's one, the +responder will reject the proposal. +If PFS is required by both sides and if the responder's group is not equal to +the initiator's one, then the responder will reject the proposal. +.El +.\" +.It Ic support_proxy (on \(ba off) ; +If this value is set to on, then both values of ID payloads in the +phase 2 exchange are always used as the addresses of end-point of +IPsec-SAs. +The default is off. +.\" +.It Ic generate_policy (on \(ba off) ; +This directive is for the responder. +Therefore you should set +.Ic passive +to on in order that +.Xr racoon 8 +only becomes a responder. +If the responder does not have any policy in SPD during phase 2 +negotiation, and the directive is set to on, then +.Xr racoon 8 +will choose the first proposal in the +SA payload from the initiator, and generate policy entries from the proposal. +It is useful to negotiate with clients whose IP address is allocated +dynamically. +Note that an inappropriate policy might be installed into the responder's SPD +by the initiator, +so other communications might fail if such policies are installed +due to a policy mismatch between the initiator and the responder. +This directive is ignored in the initiator case. +The default value is +.Ic off . +.\" +.\" +.It Ic nat_traversal (on \(ba off \(ba force) ; +This directive enables use of the NAT-Traversal IPsec extension +(NAT-T). +NAT-T allows one or both peers to reside behind a NAT gateway (i.e., +doing address- or port-translation). +Presence of NAT gateways along the path +is discovered during phase 1 handshake and if found, NAT-T is negotiated. +When NAT-T is in charge, all ESP and AH packets of a given connection +are encapsulated into UDP datagrams (port 4500, by default). +Possible values are: +.Bl -tag -width Ds -compact +.It Ic on +NAT-T is used when a NAT gateway is detected between the peers. +.It Ic off +NAT-T is not proposed/accepted. +This is the default. +.It Ic force +NAT-T is used regardless if a NAT is detected between the peers or not. +.El +Please note that NAT-T support is a compile-time option. +Although it is enabled in the source distribution by default, it +may not be available in your particular build. +In that case you will get a +warning when using any NAT-T related config options. +.\" +.It Ic dpd_delay Ar delay ; +This option activates the DPD and sets the time (in seconds) allowed +between 2 proof of liveness requests. +The default value is +.Ic 0 , +which disables DPD monitoring, but still negotiates DPD support. +.\" +.It Ic dpd_retry Ar delay ; +If +.Ic dpd_delay +is set, this sets the delay (in seconds) to wait for a proof of +liveness before considering it as failed and send another request. +The default value is +.Ic 5 . +.\" +.It Ic dpd_maxfail Ar number ; +If +.Ic dpd_delay +is set, this sets the maximum number of proof of liveness to request +(without reply) before considering the peer is dead. +The default value is +.Ic 5 . +.\" +.It Ic nonce_size Ar number ; +define the byte size of nonce value. +Racoon can send any value although +RFC2409 specifies that the value MUST be between 8 and 256 bytes. +The default size is 16 bytes. +.\" +.It Xo +.Ic proposal { Ar sub-substatements Ic } +.Xc +.Bl -tag -width Ds -compact +.\" +.It Ic encryption_algorithm Ar algorithm ; +specify the encryption algorithm used for the phase 1 negotiation. +This directive must be defined. +.Ar algorithm +is one of following: +.Ic des , 3des , blowfish , cast128 , aes +.\".Ic rc5 , idea +for Oakley. +For other transforms, this statement should not be used. +.\" +.It Ic hash_algorithm Ar algorithm ; +define the hash algorithm used for the phase 1 negotiation. +This directive must be defined. +.Ar algorithm +is one of following: +.Ic md5, sha1, sha256, sha384, sha512 +for Oakley. +.\" +.It Ic authentication_method Ar type ; +defines the authentication method used for the phase 1 negotiation. +This directive must be defined. +.Ar type +is one of: +.Ic pre_shared_key , rsasig , gssapi_krb , hybrid_rsa_server , +or +.Ic hybrid_rsa_client . +.\" +.It Ic dh_group Ar group ; +define the group used for the Diffie-Hellman exponentiations. +This directive must be defined. +.Ar group +is one of following: +.Ic modp768 , modp1024 , modp1536 , +.Ic modp2048 , modp3072 , modp4096 , +.Ic modp6144 , modp8192 . +Or you can define 1, 2, 5, 14, 15, 16, 17, or 18 as the DH group number. +When you want to use aggressive mode, +you must define the same DH group in each proposal. +.It Ic lifetime time Ar number Ar timeunit ; +define lifetime of the phase 1 SA proposal. +Refer to the description of the +.Ic lifetime +directive defined in the +.Ic remote +directive. +.It Ic gss_id Ar string ; +define the GSS-API endpoint name, to be included as an attribute in the SA, +if the +.Ic gssapi_krb +authentication method is used. +If this is not defined, the default value of +.Ql host/hostname +is used, where hostname is the value returned by the +.Xr hostname 1 +command. +.El +.El +.El +.\" +.Ss Policy Specifications +The policy directive is obsolete, policies are now in the SPD. +.Xr racoon 8 +will obey the policy configured into the kernel by +.Xr setkey 8 , +and will construct phase 2 proposals by combining +.Ic sainfo +specifications in +.Nm , +and policies in the kernel. +.\" +.Ss Sainfo Specifications +.Bl -tag -width Ds -compact +.It Xo +.Ic sainfo ( Ar source_id destination_id | Ic anonymous ) [ from Ar idtype [ Ar string ] ] +.Ic { Ar statements Ic } +.Xc +defines the parameters of the IKE phase 2 (IPsec-SA establishment). +.Ar source_id +and +.Ar destination_id +are constructed like: +.Pp +.Ic address Ar address +.Bq Ic / Ar prefix +.Bq Ic [ Ar port ] +.Ar ul_proto +.Pp +or +.Pp +.Ic subnet Ar address +.Bq Ic / Ar prefix +.Bq Ic [ Ar port ] +.Ar ul_proto +.Pp +or +.Pp +.Ar idtype Ar string +.Pp +It means exactly the content of ID payload. +This is not like a filter rule. +For example, if you define 3ffe:501:4819::/48 as +.Ar source_id . +3ffe:501:4819:1000:/64 will not match. +.Pp +In case of longest prefix (selecting single host) +.Ar address +instructs to send ID type of ADDRESS, while +.Ar subnet +instructs to send ID type of SUBNET. +Otherwise these instructions are identical. +.Pp +.Bl -tag -width Ds -compact +.\" +.It Ic pfs_group Ar group ; +define the group of Diffie-Hellman exponentiations. +If you do not require PFS then you can omit this directive. +Any proposal will be accepted if you do not specify one. +.Ar group +is one of following: +.Ic modp768 , modp1024 , modp1536 , +.Ic modp2048 , modp3072 , modp4096 , +.Ic modp6144 , modp8192 . +Or you can define 1, 2, 5, 14, 15, 16, 17, or 18 as the DH group number. +.\" +.It Ic lifetime time Ar number Ar timeunit ; +define how long an IPsec-SA will be used, in timeunits. +Any proposal will be accepted, and no attribute(s) will be proposed to +the peer if you do not specify it(them). +See the +.Ic proposal_check +directive. +.\" +.It Ic my_identifier Ar idtype ... ; +is obsolete. +It does not make sense to specify an identifier in the phase 2. +.El +.\" +.Pp +.Xr racoon 8 +does not have a list of security protocols to be negotiated. +The list of security protocols are passed by SPD in the kernel. +Therefore you have to define all of the potential algorithms +in the phase 2 proposals even if there are algorithms which will not be used. +These algorithms are define by using the following three directives, +with a single comma as the separator. +For algorithms that can take variable-length keys, algorithm names +can be followed by a key length, like +.Dq Li blowfish 448 . +.Xr racoon 8 +will compute the actual phase 2 proposals by computing +the permutation of the specified algorithms, +and then combining them with the security protocol specified by the SPD. +For example, if +.Ic des , 3des , hmac_md5 , +and +.Ic hmac_sha1 +are specified as algorithms, we have four combinations for use with ESP, +and two for AH. +Then, based on the SPD settings, +.Xr racoon 8 +will construct the actual proposals. +If the SPD entry asks for ESP only, there will be 4 proposals. +If it asks for both AH and ESP, there will be 8 proposals. +Note that the kernel may not support the algorithm you have specified. +.\" +.Bl -tag -width Ds -compact +.It Ic encryption_algorithm Ar algorithms ; +.Ic des , 3des , des_iv64 , des_iv32 , +.Ic rc5 , rc4 , idea , 3idea , +.Ic cast128 , blowfish , null_enc , +.Ic twofish , rijndael , aes +.Pq used with ESP +.\" +.It Ic authentication_algorithm Ar algorithms ; +.Ic des , 3des , des_iv64 , des_iv32 , +.Ic hmac_md5 , hmac_sha1 , hmac_sha256, hmac_sha384, hmac_sha512, non_auth +.Pq used with ESP authentication and AH +.\" +.It Ic compression_algorithm Ar algorithms ; +.Ic deflate +.Pq used with IPComp +.El +.El +.\" +.Ss Logging level +.Bl -tag -width Ds -compact +.It Ic log Ar level ; +define logging level. +.Ar level +is one of following: +.Ic notify , debug , +and +.Ic debug2 . +The default is +.Ic notify . +If you set the logging level too high on slower machines, +IKE negotiation can fail due to timing constraint changes. +.El +.\" +.Ss Specifying the way to pad +.Bl -tag -width Ds -compact +.It Ic padding { Ar statements Ic } +specified padding format. +The following are valid statements: +.Bl -tag -width Ds -compact +.It Ic randomize (on \(ba off) ; +enable using a randomized value for padding. +The default is on. +.It Ic randomize_length (on \(ba off) ; +the pad length is random. +The default is off. +.It Ic maximum_length Ar number ; +define a maximum padding length. +If +.Ic randomize_length +is off, this is ignored. +The default is 20 bytes. +.It Ic exclusive_tail (on \(ba off) ; +means to put the number of pad bytes minus one into the last part +of the padding. +The default is on. +.It Ic strict_check (on \(ba off) ; +means to constrain the peer to set the number of pad bytes. +The default is off. +.El +.El +.Ss ISAKMP mode configuration settings +.Bl -tag -width Ds -compact +.It Ic mode_cfg { Ar statements Ic } +Defines the information to return for remote hosts' ISAKMP mode config +requests. +Also defines the authentication source for remote peers +authenticating through hybrid auth. +.Pp +The following are valid statements: +.Bl -tag -width Ds -compact +.It Ic auth_source (system \(ba radius \(ba pam) ; +Specify the source for authentication of users through hybrid auth. +.Ar system +means to use the Unix user database. +This is the default. +.Ar radius +means to use a RADIUS server. +It works only if +.Xr racoon 8 +was built with libradius support, and the configuration is done in +.Xr radius.conf 5 . +.Ar pam +means to use PAM. +It works only if +.Xr racoon 8 +was built with libpam support. +.It Ic conf_source (local \(ba radius) ; +Specify the source for IP addresses and netmask allocated through ISAKMP +mode config. +.Ar local +means to use the local IP pool defined by the +.Ic network4 +and +.Ic pool_size +keywords. +This is the default. +.Ar radius +means to use a RADIUS server. +It works only if +.Xr racoon 8 +was built with libradius support, and the configuration is done in +.Xr radius.conf 5 . +RADIUS configuration requires RADIUS authentication. +.It Ic accounting (none \(ba radius \(ba pam) ; +Enable or disable accounting for Xauth logins and logouts. +Default is +.Ar none , +which disable accounting. +.Ar radius +enable RADIUS accounting. +It works only if +.Xr racoon 8 +was built with libradius support, and the configuration is done in +.Xr radius.conf 5 . +RADIUS accounting require RADIUS authentication. +.Ar pam +enable PAM accounting. +It works only if +.Xr racoon 8 +was built with libpam support. +PAM accounting requires PAM authentication. +.It Ic pool_size Ar size +Specify the size of the IP address pool, either local or allocated +through RADIUS. +.Ic conf_source +selects the local pool or the RADIUS configuration, but in both +configurations, you cannot have more than +.Ar size +users connected at the same time. +The default is 255. +.It Ic network4 Ar address ; +.It Ic netmask4 Ar address ; +The local IP pool base address and network mask from which dynamically +allocated IPv4 addresses should be taken. +This is used if +.Ic conf_source +is set to +.Ar local +or if the RADIUS server returned +.Ar 255.255.255.254 . +Default is +.Ar 0.0.0.0/0.0.0.0 . +.It Ic dns4 Ar address ; +The IPv4 address for a DNS server. +.It Ic nbns4 Ar address ; +The IPv4 address for a WINS server. +.It Ic banner Ar path ; +The path of a file displayed on the client at connection time. +Default is +.Ar /etc/motd . +.It Ic auth_throttle Ar delay ; +On each failed Xauth authentication attempt, refuse new attempts for +.Ar delay +more seconds. +This is to avoid dictionary attacks on Xauth passwords. +Default is one second. +Set to zero to disable authentication delay. +.It Ic pfs_group Ar group ; +Sets the PFS group used in the client proposal (Cisco VPN client only). +Default is 0. +.It Ic save_passwd (on | off) ; +Allow the client to save the Xauth password (Cisco VPN client only). +Default is off. +.El +.El +.Ss Special directives +.Bl -tag -width Ds -compact +.It Ic complex_bundle (on \(ba off) ; +defines the interpretation of proposal in the case of SA bundle. +Normally +.Dq IP AH ESP IP payload +is proposed as +.Dq AH tunnel and ESP tunnel . +The interpretation is more common to other IKE implementations, however, +it allows very limited set of combinations for proposals. +With the option enabled, it will be proposed as +.Dq AH transport and ESP tunnel . +The default value is +.Ic off . +.El +.\" +.Ss Pre-shared key File +The pre-shared key file defines pairs of identifiers and corresponding +shared secret keys which are used in the pre-shared key authentication +method in phase 1. +The pair in each line is separated by some number of blanks and/or tab +characters like in the +.Xr hosts 5 +file. +Key can include blanks because everything after the first blanks +is interpreted as the secret key. +Lines starting with +.Ql # +are ignored. +Keys which start with +.Ql 0x +are interpreted as hexadecimal strings. +Note that the file must be owned by the user ID running +.Xr racoon 8 +.Pq usually the privileged user , +and must not be accessible by others. +.\" +.Sh EXAMPLES +The following shows how the remote directive should be configured. +.Bd -literal -offset +path pre_shared_key "/usr/local/v6/etc/psk.txt" ; +remote anonymous +{ + exchange_mode aggressive,main,base; + lifetime time 24 hour; + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key; + dh_group 2; + } +} + +sainfo anonymous +{ + pfs_group 2; + lifetime time 12 hour ; + encryption_algorithm 3des, blowfish 448, twofish, rijndael ; + authentication_algorithm hmac_sha1, hmac_md5 ; + compression_algorithm deflate ; +} +.Ed +.Pp +The following is a sample for the pre-shared key file. +.Bd -literal -offset +10.160.94.3 mekmitasdigoat +172.16.1.133 0x12345678 +194.100.55.1 whatcertificatereally +3ffe:501:410:ffff:200:86ff:fe05:80fa mekmitasdigoat +3ffe:501:410:ffff:210:4bff:fea2:8baa mekmitasdigoat +foo@kame.net mekmitasdigoat +foo.kame.net hoge +.Ed +.\" +.Sh SEE ALSO +.Xr racoon 8 , +.Xr racoonctl 8 , +.Xr setkey 8 +.\" +.Sh HISTORY +The +.Nm +configuration file first appeared in the +.Dq YIPS +Yokogawa IPsec implementation. +.\" +.Sh BUGS +Some statements may not be handled by +.Xr racoon 8 +yet. +.Pp +Diffie-Hellman computation can take a very long time, and may cause +unwanted timeouts, specifically when a large D-H group is used. +.\" +.Sh SECURITY CONSIDERATIONS +The use of IKE phase 1 aggressive mode is not recommended, +as described in +.Li http://www.kb.cert.org/vuls/id/886601 . diff --git a/ipsec-tools/racoon/racoonctl.8 b/ipsec-tools/racoon/racoonctl.8 new file mode 100644 index 0000000..cf292a5 --- /dev/null +++ b/ipsec-tools/racoon/racoonctl.8 @@ -0,0 +1,190 @@ +.\" $Id: racoonctl.8,v 1.2.4.2 2005/04/18 11:10:55 manubsd Exp $ +.\" +.\" Copyright (C) 2004 Emmanuel Dreyfus +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 16, 2004 +.Dt RACOONCTL 8 +.Os +.\" +.Sh NAME +.Nm racoonctl +.Nd racoon administrative control tool +.\" +.Sh SYNOPSIS +.Nm +reload-config +.Nm +show-schedule +.Nm +.Op Fl l Op Fl l +show-sa +.Op isakmp|esp|ah|ipsec +.Nm +flush-sa +.Op isakmp|esp|ah|ipsec +.Nm +delete-sa +.Ar saopts +.Nm +establish-sa +.Op Fl u Ar identity +.Ar saopts +.Nm +vpn-connect +.Op Fl u identity +.Ar vpn_gateway +.Nm +vpn-disconnect +.Ar vpn_gateway +.Nm +show-event +.Op Fl l +.\" +.Sh DESCRIPTION +.Nm +is used to control +.Xr racoon 8 +operation, if ipsec-tools was configured with adminport support. +Communication between +.Nm +and +.Xr racoon 8 +is done through a UNIX socket. +By changing the default mode and ownership +of the socket, you can allow non-root users to alter +.Xr racoon 8 +behavior, so do that with caution. +.Pp +The following commands are available: +.Bl -tag -width Ds +.It reload-config +This should cause +.Xr racoon 8 +to reload its configuration file. +This seems completely broken at the time this man page is written. +.It show-schedule +Unknown command. +.It show-sa Op isakmp|esp|ah|ipsec +Dump the SA: All the SAs if no SA class is provided, or either ISAKMP SAs, +IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs. +Use +.Fl l +to increase verbosity. +.It flush-sa Op isakmp|esp|ah|ipsec +is used to flush all SAs if no SA class is provided, or a class of SAs, +either ISAKMP SAs, IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs. +.It Xo establish-sa +.Oo Fl u Ar username +.Oc Ar saopts +.Xc +Establish an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA. +The optional +.Fl u Ar username +can be used when establishing an ISAKMP SA while hybrid auth is in use. +.Nm +will prompt you for the password associated with +.Ar username +and these credentials will be used in the Xauth exchange. +.Pp +.Ar saopts +has the following format: +.Bl -tag -width Bl +.It isakmp {inet|inet6} Ar src Ar dst +.It {esp|ah} {inet|inet6} Ar src/prefixlen/port Ar dst/prefixlen/port +{icmp|tcp|udp|any} +.El +.It Xo vpn-connect +.Oo Fl u Ar username +.Oc Ar vpn_gateway +.Xc +This is a particular case of the previous command. +It will establish an ISAKMP SA with +.Ar vpn_gateway . +.It delete-sa Ar saopts +Delete an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA. +.It vpn-disconnect Ar vpn_gateway +This is a particular case of the previous command. +It will kill all SAs associated with +.Ar vpn_gateway . +.It show-event Op Fl l +Dump all events reported by +.Xr racoon 8 , +then quit. +The +.Fl l +flag causes +.Nm +to not stop once all the events have been read, but rather to loop +awaiting and reporting new events. +.El +.Pp +Command shortcuts are available: +.Bl -tag -width XXX -compact -offset indent +.It rc +reload-config +.It ss +show-sa +.It sc +show-schedule +.It fs +flush-sa +.It ds +delete-sa +.It es +establish-sa +.It vc +vpn-connect +.It vd +vpn-disconnect +.It se +show-event +.El +.\" +.Sh RETURN VALUES +The command should exit with 0 on success, and non-zero on errors. +.\" +.Sh FILES +.Bl -tag -width 30n -compact +.It Pa /var/racoon/racoon.sock No or +.It Pa /var/run/racoon.sock +.Xr racoon 8 +control socket. +.El +.\" +.Sh SEE ALSO +.Xr ipsec 4 , +.Xr racoon 8 +.Sh HISTORY +Once was +.Ic kmpstat +in the KAME project. +It turned into +.Nm +but remained undocumented for a while. +.An Emmanuel Dreyfus Aq manu@NetBSD.org +wrote this man page. diff --git a/ipsec-tools/racoon/racoonctl.c b/ipsec-tools/racoon/racoonctl.c new file mode 100644 index 0000000..e59b1f9 --- /dev/null +++ b/ipsec-tools/racoon/racoonctl.c @@ -0,0 +1,1585 @@ +/* $Id: racoonctl.c,v 1.2.2.1 2005/04/21 09:07:20 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#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 \n" +" %s establish-sa [-u identity] \n" +" %s vpn-connect [-u identity] vpn_gateway\n" +" %s vpn-disconnect vpn_gateway\n" +"\n" +" : \"isakmp\", \"esp\" or \"ah\".\n" +" In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n" +"\n" +" : \"isakmp\" \n" +" : {\"esp\",\"ah\"} \n" +" \n" +" : \"inet\" or \"inet6\"\n" +" : \"icmp\", \"tcp\", \"udp\" or \"any\"\n", + pname, pname, pname, pname, pname, pname, pname); +} + +/* + * Check for proper racoonctl interface + */ +#if ((RACOONCTL_INTERFACE_MAJOR != 1) || (RACOONCTL_INTERFACE < 20041230)) +#error "Incompatible racoonctl interface" +#endif + +int +main(ac, av) + int ac; + char **av; +{ + vchar_t *combuf; + int c; + + pname = *av; + + /* + * Check for proper racoonctl interface + */ + if ((racoonctl_interface_major != RACOONCTL_INTERFACE_MAJOR) || + (racoonctl_interface < RACOONCTL_INTERFACE)) + errx(1, "Incompatible racoonctl interface"); + +#ifdef __linux__ + /* + * Disable GNU extensions that will prevent racoonct vc -u login + * from working (GNU getopt(3) does not like options after vc) + */ + setenv("POSIXLY_CORRECT", "1", 0); +#endif + while ((c = getopt(ac, av, "lds:")) != -1) { + switch(c) { + case 'l': + long_format++; + break; + + case 'd': + loglevel++; + break; + + case 's': + adminsock_path = optarg; + break; + + default: + usage(); + exit(0); + } + } + + ac -= optind; + av += optind; + + combuf = get_combuf(ac, av); + if (!combuf) + err(1, "kmpstat"); + + if (loglevel) + hexdump(combuf, ((struct admin_com *)combuf)->ac_len); + + com_init(); + + if (com_send(combuf) != 0) + goto bad; + + vfree(combuf); + + if (com_recv(&combuf) != 0) + goto bad; + if (handle_recv(combuf) != 0) + goto bad; + + vfree(combuf); + + if (evt_filter != EVTF_NONE) + if (evt_poll() != 0) + goto bad; + + exit(0); + + bad: + exit(1); +} + +int +evt_poll(void) { + struct timeval tv; + vchar_t *recvbuf; + vchar_t *sendbuf; + + if ((sendbuf = f_getevt(0, NULL)) == NULL) + errx(1, "Cannot make combuf"); + + while (evt_filter & (EVTF_LOOP|EVTF_PURGE)) { + com_init(); + if (com_send(sendbuf) != 0) + errx(1, "Cannot send combuf"); + + if (com_recv(&recvbuf) == 0) { + handle_recv(recvbuf); + vfree(recvbuf); + } + + tv.tv_sec = 0; + tv.tv_usec = 10; + (void)select(0, NULL, NULL, NULL, &tv); + } + + /* NOTREACHED */ + return 0; +} + +/* %%% */ +/* + * return command buffer. + */ +static vchar_t * +get_combuf(ac, av) + int ac; + char **av; +{ + struct cmd_tag *cp; + + if (ac == 0) { + usage(); + exit(0); + } + + /* checking the string of command. */ + for (cp = &cmdtab[0]; cp->str; cp++) { + if (strcmp(*av, cp->str) == 0) { + break; + } + } + if (!cp->str) { + printf("Invalid command [%s]\n", *av); + errno = EINVAL; + return NULL; + } + + ac--; + av++; + return (cp->func)(ac, av); +} + +static vchar_t * +f_reload(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_RELOAD_CONF; + head->ac_errno = 0; + head->ac_proto = 0; + + return buf; +} + +static vchar_t * +f_getevt(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + + /* + * There are 3 ways of getting here + * 1) racoonctl vc => evt_filter = (EVTF_LOOP|EVTF_CFG| ... ) + * 2) racoonctl es => evt_filter = EVTF_NONE + * 3) racoonctl es -l => evt_filter = EVTF_LOOP + * Catch the second case: show-event is here to purge all + */ + if (evt_filter == EVTF_NONE) + evt_filter = (EVTF_ALL|EVTF_PURGE); + + if ((ac >= 1) && (strcmp(av[0], "-l") == 0)) + evt_filter |= EVTF_LOOP; + + if (ac >= 2) + errx(1, "too many arguments"); + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_SHOW_EVT; + head->ac_errno = 0; + head->ac_proto = 0; + + return buf; +} + +static vchar_t * +f_getsched(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_SHOW_SCHED; + head->ac_errno = 0; + head->ac_proto = 0; + + return buf; +} + +static vchar_t * +f_getsa(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac != 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_SHOW_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static vchar_t * +f_flushsa(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac != 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_FLUSH_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static vchar_t * +f_deletesa(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (proto) { + case ADMIN_PROTO_ISAKMP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } + + buf = vmalloc(sizeof(*head) + index->l); + if (buf == NULL) + return NULL; + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l + index->l; + head->ac_cmd = ADMIN_DELETE_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + memcpy(buf->v+sizeof(*head), index->v, index->l); + + return buf; +} + +static vchar_t * +f_deleteallsadst(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (proto) { + case ADMIN_PROTO_ISAKMP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } + + buf = vmalloc(sizeof(*head) + index->l); + if (buf == NULL) + return NULL; + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l + index->l; + head->ac_cmd = ADMIN_DELETE_ALL_SA_DST; + head->ac_errno = 0; + head->ac_proto = proto; + + memcpy(buf->v+sizeof(*head), index->v, index->l); + + return buf; +} + +static vchar_t * +f_exchangesa(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com *head; + int proto; + int cmd = ADMIN_ESTABLISH_SA; + size_t com_len = 0; + char *id = NULL; + char *key = NULL; + struct admin_com_psk *acp; + + if (ac < 1) + errx(1, "insufficient arguments"); + + /* Optional -u identity */ + if (strcmp(av[0], "-u") == 0) { + if (ac < 2) + errx(1, "-u require an argument"); + + id = av[1]; + if ((key = getpass("Password: ")) == NULL) + errx(1, "getpass() failed: %s", strerror(errno)); + + com_len += sizeof(*acp) + strlen(id) + 1 + strlen(key) + 1; + cmd = ADMIN_ESTABLISH_SA_PSK; + + av += 2; + ac -= 2; + } + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + if ((proto = get_proto(*av)) == -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (proto) { + case ADMIN_PROTO_ISAKMP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } + + com_len += sizeof(*head) + index->l; + if ((buf = vmalloc(com_len)) == NULL) + errx(1, "Cannot allocate buffer"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = cmd; + head->ac_errno = 0; + head->ac_proto = proto; + + memcpy(buf->v+sizeof(*head), index->v, index->l); + + if (id && key) { + char *data; + acp = (struct admin_com_psk *) + (buf->v + sizeof(*head) + index->l); + + acp->id_type = IDTYPE_LOGIN; + acp->id_len = strlen(id) + 1; + acp->key_len = strlen(key) + 1; + + data = (char *)(acp + 1); + strcpy(data, id); + + data = (char *)(data + acp->id_len); + strcpy(data, key); + } + + return buf; +} + +static vchar_t * +f_vpnc(ac, av) + int ac; + char **av; +{ + char *nav[] = {NULL, NULL, NULL, NULL, NULL, NULL}; + int nac = 0; + char *isakmp = "isakmp"; + char *inet = "inet"; + char *srcaddr; + struct addrinfo hints, *res; + struct sockaddr *src; + char *idx; + + if (ac < 1) + errx(1, "insufficient arguments"); + + evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP); + time(&evt_start); + + /* Optional -u identity */ + if (strcmp(av[0], "-u") == 0) { + if (ac < 2) + errx(1, "-u require an argument"); + + nav[nac++] = av[0]; + nav[nac++] = av[1]; + + ac -= 2; + av += 2; + } + + if (ac < 1) + errx(1, "VPN gateway required"); + if (ac > 1) + warnx("Extra arguments"); + + /* + * Find the source address + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(av[0], "4500", &hints, &res) != 0) + errx(1, "Cannot resolve destination address"); + + if ((src = getlocaladdr(res->ai_addr)) == NULL) + errx(1, "cannot find source address"); + + if ((srcaddr = saddr2str(src)) == NULL) + errx(1, "cannot read source address"); + + /* We get "ip[port]" strip the port */ + if ((idx = index(srcaddr, '[')) == NULL) + errx(1, "unexpected source address format"); + *idx = '\0'; + + nav[nac++] = isakmp; + nav[nac++] = inet; + nav[nac++] = srcaddr; + nav[nac++] = av[0]; + + return f_exchangesa(nac, nav); +} + +static vchar_t * +f_vpnd(ac, av) + int ac; + char **av; +{ + char *nav[] = {NULL, NULL, NULL, NULL}; + int nac = 0; + char *isakmp = "isakmp"; + char *inet = "inet"; + char *anyaddr = "0.0.0.0"; + char *idx; + vchar_t *buf, *index; + + if (ac < 1) + errx(1, "VPN gateway required"); + if (ac > 1) + warnx("Extra arguments"); + + evt_filter = + (EVTF_PH1DOWN|EVTF_PH1DOWN_STOP|EVTF_LOOP|EVTF_ERR|EVTF_ERR_STOP); + + nav[nac++] = isakmp; + nav[nac++] = inet; + nav[nac++] = anyaddr; + nav[nac++] = av[0]; + + return f_deleteallsadst(nac, nav); +} + + +static int +get_proto(str) + char *str; +{ + struct proto_tag *cp; + + if (str == NULL) { + errno = EINVAL; + return -1; + } + + /* checking the string of command. */ + for (cp = &prototab[0]; cp->str; cp++) { + if (strcmp(str, cp->str) == 0) + return cp->proto; + } + + errno = EINVAL; + return -1; +} + +static vchar_t * +get_index(ac, av) + int ac; + char **av; +{ + int family; + + if (ac != 3 && ac != 4) { + errno = EINVAL; + return NULL; + } + + /* checking the string of family */ + family = get_family(*av); + if (family == -1) + return NULL; + av++; + ac--; + + return get_comindexes(family, ac, av); +} + +static int +get_family(str) + char *str; +{ + if (strcmp("inet", str) == 0) + return AF_INET; +#ifdef INET6 + else if (strcmp("inet6", str) == 0) + return AF_INET6; +#endif + errno = EAFNOSUPPORT; + return -1; +} + +static vchar_t * +get_comindexes(family, ac, av) + int family; + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com_indexes *ci; + char *p_name = NULL, *p_port = NULL; + char *p_prefs = NULL, *p_prefd = NULL; + struct sockaddr *src = NULL, *dst = NULL; + int ulproto; + + if (ac != 2 && ac != 3) { + errno = EINVAL; + return NULL; + } + + if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1) + goto bad; + src = get_sockaddr(family, p_name, p_port); + if (p_name) { + racoon_free(p_name); + p_name = NULL; + } + if (p_port) { + racoon_free(p_port); + p_port = NULL; + } + if (src == NULL) + goto bad; + av++; + ac--; + if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1) + goto bad; + dst = get_sockaddr(family, p_name, p_port); + if (p_name) { + racoon_free(p_name); + p_name = NULL; + } + if (p_port) { + racoon_free(p_port); + p_port = NULL; + } + if (dst == NULL) + goto bad; + + buf = vmalloc(sizeof(*ci)); + if (buf == NULL) + goto bad; + + av++; + ac--; + if(ac){ + ulproto = get_ulproto(*av); + if (ulproto == -1) + goto bad; + }else + ulproto=0; + + ci = (struct admin_com_indexes *)buf->v; + if(p_prefs) + ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */ + else + ci->prefs = 32; + if(p_prefd) + ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */ + else + ci->prefd = 32; + ci->ul_proto = ulproto; + memcpy(&ci->src, src, sysdep_sa_len(src)); + memcpy(&ci->dst, dst, sysdep_sa_len(dst)); + + if (p_name) + racoon_free(p_name); + + return buf; + + bad: + if (p_name) + racoon_free(p_name); + if (p_port) + racoon_free(p_port); + if (p_prefs) + racoon_free(p_prefs); + if (p_prefd) + racoon_free(p_prefd); + return NULL; +} + +static int +get_comindex(str, name, port, pref) + char *str, **name, **port, **pref; +{ + char *p; + + *name = *port = *pref = NULL; + + *name = strdup(str); + p = strpbrk(*name, "/["); + if (p != NULL) { + if (*(p + 1) == '\0') + goto bad; + if (*p == '/') { + *p = '\0'; + *pref = strdup(p + 1); + p = strchr(*pref, '['); + if (p != NULL) { + if (*(p + 1) == '\0') + goto bad; + *p = '\0'; + *port = strdup(p + 1); + p = strchr(*pref, ']'); + if (p == NULL) + goto bad; + *p = '\0'; + } + } else if (*p == '[') { + *p = '\0'; + *port = strdup(p + 1); + p = strchr(*pref, ']'); + if (p == NULL) + goto bad; + *p = '\0'; + } else { + /* XXX */ + } + } + + return 0; + + bad: + + if (*name) + racoon_free(*name); + if (*port) + racoon_free(*port); + if (*pref) + racoon_free(*pref); + *name = *port = *pref = NULL; + return -1; +} + +static int +get_ulproto(str) + char *str; +{ + struct ulproto_tag *cp; + + if(str == NULL){ + errno = EINVAL; + return -1; + } + + /* checking the string of upper layer protocol. */ + for (cp = &ulprototab[0]; cp->str; cp++) { + if (strcmp(str, cp->str) == 0) + return cp->ul_proto; + } + + errno = EINVAL; + return -1; +} + +/* %%% */ +void +dump_isakmp_sa(buf, len) + char *buf; + int len; +{ + struct ph1dump *pd; + struct tm *tm; + char tbuf[56]; + caddr_t p = NULL; + +/* isakmp status header */ +/* short header; + 1234567890123456789012 0000000000000000:0000000000000000 000000000000 +*/ +char *header1 = +"Destination Cookies Created"; + +/* semi long header; + 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000 +*/ +char *header2 = +"Destination Cookies ST S V E Created Phase2"; + +/* long header; + 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000 +*/ +char *header3 = +"Source Destination Cookies ST S V E Created Phase2"; + +/* phase status header */ +/* short format; + side stats source address destination address + xxx xxxxx 1234567890123456789012 1234567890123456789012 +*/ + + static char *estr[] = { "", "B", "M", "U", "A", "I", }; + + switch (long_format) { + case 0: + printf("%s\n", header1); + break; + case 1: + printf("%s\n", header2); + break; + case 2: + default: + printf("%s\n", header3); + break; + } + + if (len % sizeof(*pd)) + printf("invalid length %d\n", len); + len /= sizeof(*pd); + + pd = (struct ph1dump *)buf; + + while (len-- > 0) { + /* source address */ + if (long_format >= 2) { + GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_); + switch (long_format) { + case 0: + break; + case 1: + p = fixed_addr(_addr1_, _addr2_, 22); + break; + case 2: + default: + p = fixed_addr(_addr1_, _addr2_, 45); + break; + } + printf("%s ", p); + } + + /* destination address */ + GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_); + switch (long_format) { + case 0: + case 1: + p = fixed_addr(_addr1_, _addr2_, 22); + break; + case 2: + default: + p = fixed_addr(_addr1_, _addr2_, 45); + break; + } + printf("%s ", p); + + printf("%s ", pindex_isakmp(&pd->index)); + + /* statuc, side and version */ + if (long_format >= 1) { + printf("%2d %c %2x ", + pd->status, + pd->side == INITIATOR ? 'I' : 'R', + pd->version); + if (ARRAYLEN(estr) > pd->etype) + printf("%s ", estr[pd->etype]); + } + + /* created date */ + if (pd->created) { + tm = localtime(&pd->created); + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm); + } else + snprintf(tbuf, sizeof(tbuf), " "); + printf("%s ", tbuf); + + /* counter of phase 2 */ + if (long_format >= 1) + printf("%6d ", pd->ph2cnt); + + printf("\n"); + + pd++; + } + + return; +} + +/* %%% */ +void +dump_internal(buf, tlen) + char *buf; + int tlen; +{ + struct ph2handle *iph2; + struct sockaddr *addr; + +/* +short header; + source address destination address + 1234567890123456789012 1234567890123456789012 +*/ +char *short_h1 = +"Source Destination "; + +/* +long header; + source address destination address + 123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345 + 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 +*/ +char *long_h1 = +"Source Destination "; + + printf("%s\n", long_format ? long_h1 : short_h1); + + while (tlen > 0) { + iph2 = (struct ph2handle *)buf; + addr = (struct sockaddr *)(++iph2); + + GETNAMEINFO(addr, _addr1_, _addr2_); + printf("%s ", long_format ? + fixed_addr(_addr1_, _addr2_, 45) + : fixed_addr(_addr1_, _addr2_, 22)); + addr++; + tlen -= sysdep_sa_len(addr); + + GETNAMEINFO(addr, _addr1_, _addr2_); + printf("%s ", long_format ? + fixed_addr(_addr1_, _addr2_, 45) + : fixed_addr(_addr1_, _addr2_, 22)); + addr++; + tlen -= sysdep_sa_len(addr); + + printf("\n"); + } + + return; +} + +/* %%% */ +char * +pindex_isakmp(index) + isakmp_index *index; +{ + static char buf[64]; + u_char *p; + int i, j; + + memset(buf, 0, sizeof(buf)); + + /* copy index */ + p = (u_char *)index; + for (j = 0, i = 0; i < sizeof(isakmp_index); i++) { + snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]); + j += 2; + switch (i) { + case 7: +#if 0 + case 15: +#endif + buf[j++] = ':'; + } + } + + return buf; +} + +/* print schedule */ +char *str_sched_stat[] = { +"off", +"on", +"dead", +}; + +char *str_sched_id[] = { +"PH1resend", +"PH1lifetime", +"PH2resend", +"PSTacquire", +"PSTlifetime", +}; + +void +print_schedule(buf, len) + caddr_t buf; + int len; +{ + struct scheddump *sc = (struct scheddump *)buf; + struct tm *tm; + char tbuf[56]; + + if (len % sizeof(*sc)) + printf("invalid length %d\n", len); + len /= sizeof(*sc); + + /* 00000000 00000000 00000000 xxx........*/ + printf("index tick xtime created\n"); + + while (len-- > 0) { + tm = localtime(&sc->created); + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm); + + printf("%-8ld %-8ld %-8ld %s\n", + sc->id, + (long)sc->tick, + (long)sc->xtime, + tbuf); + sc++; + } + + return; +} + + +void +print_evt(buf, len) + caddr_t buf; + int len; +{ + struct evtdump *evtdump = (struct evtdump *)buf; + int i; + char *srcstr; + char *dststr; + + for (i = 0; evtmsg[i].msg; i++) + if (evtmsg[i].type == evtdump->type) + break; + + if (evtmsg[i].msg == NULL) + printf("Event %d: ", evtdump->type); + else + printf("%s : ", evtmsg[i].msg); + + if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL) + printf("unknown"); + else + printf("%s", srcstr); + printf(" -> "); + if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL) + printf("unknown"); + else + printf("%s", dststr); + printf("\n"); + + return; +} + +void +print_err(buf, len) + caddr_t buf; + int len; +{ + struct evtdump *evtdump = (struct evtdump *)buf; + int i; + + + for (i = 0; evtmsg[i].msg; i++) + if (evtmsg[i].type == evtdump->type) + break; + + if (evtmsg[i].level != ERROR) + return; + + if (evtmsg[i].msg == NULL) + printf("Error: Event %d\n", evtdump->type); + else + printf("Error: %s\n", evtmsg[i].msg); + + if (evt_filter & EVTF_ERR_STOP) + evt_filter &= ~EVTF_LOOP; + + return; +} + +/* + * Print a message when phase 1 SA goes down + */ +void +print_ph1down(buf, len) + caddr_t buf; + int len; +{ + struct evtdump *evtdump = (struct evtdump *)buf; + + if (evtdump->type != EVTT_PHASE1_DOWN) + return; + + printf("VPN connexion terminated\n"); + + if (evt_filter & EVTF_PH1DOWN_STOP) + evt_filter &= ~EVTF_LOOP; + + return; +} + +/* + * Print ISAKMP mode config info (IP and banner) + */ +void +print_cfg(buf, len) + caddr_t buf; + int len; +{ + struct evtdump *evtdump = (struct evtdump *)buf; + struct isakmp_data *attr; + char *banner = NULL; + struct in_addr addr4; + + memset(&addr4, 0, sizeof(addr4)); + + if (evtdump->type != EVTT_ISAKMP_CFG_DONE) + return; + + len -= sizeof(*evtdump); + attr = (struct isakmp_data *)(evtdump + 1); + + while (len > 0) { + if (len < sizeof(*attr)) { + printf("short attribute too short\n"); + break; + } + + if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) { + /* Short attribute, skip */ + len -= sizeof(*attr); + attr++; + } else { /* Long attribute */ + char *n; + + if (len < (sizeof(*attr) + ntohs(attr->lorv))) { + printf("long attribute too long\n"); + break; + } + + switch (ntohs(attr->type) & ~ISAKMP_GEN_MASK) { + case INTERNAL_IP4_ADDRESS: + if (ntohs(attr->lorv) < sizeof(addr4)) { + printf("addr4 attribute too short\n"); + break; + } + memcpy(&addr4, attr + 1, sizeof(addr4)); + break; + + case UNITY_BANNER: + banner = racoon_malloc(ntohs(attr->lorv) + 1); + if (banner == NULL) { + printf("malloc failed\n"); + break; + } + memcpy(banner, attr + 1, ntohs(attr->lorv)); + banner[ntohs(attr->lorv)] = '\0'; + break; + + default: + break; + } + + len -= (sizeof(*attr) + ntohs(attr->lorv)); + n = (char *)attr; + attr = (struct isakmp_data *) + (n + sizeof(*attr) + ntohs(attr->lorv)); + } + } + + printf("Bound to address %s\n", inet_ntoa(addr4)); + if (banner) { + struct winsize win; + int col = 0; + int i; + + if (ioctl(1, TIOCGWINSZ, &win) != 1) + col = win.ws_col; + + for (i = 0; i < col; i++) + printf("%c", '='); + printf("\n%s\n", banner); + for (i = 0; i < col; i++) + printf("%c", '='); + printf("\n"); + } + + if (evt_filter & EVTF_CFG_STOP) + evt_filter &= ~EVTF_LOOP; + + return; +} + + +char * +fixed_addr(addr, port, len) + char *addr, *port; + int len; +{ + static char _addr_buf_[BUFSIZ]; + char *p; + int plen, i; + + /* initialize */ + memset(_addr_buf_, ' ', sizeof(_addr_buf_)); + + plen = strlen(port); + if (len < plen + 1) + return NULL; + + p = _addr_buf_; + for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/) + *p++ = addr[i++]; + *p++ = '.'; + + for (i = 0; i < plen && port[i] != '\0'; /*noting*/) + *p++ = port[i++]; + + _addr_buf_[len] = '\0'; + + return _addr_buf_; +} + +static int +handle_recv(combuf) + vchar_t *combuf; +{ + struct admin_com h, *com; + caddr_t buf; + int len; + + com = (struct admin_com *)combuf->v; + len = com->ac_len - sizeof(*com); + buf = combuf->v + sizeof(*com); + + switch (com->ac_cmd) { + case ADMIN_SHOW_SCHED: + print_schedule(buf, len); + break; + + case ADMIN_SHOW_EVT: { + struct evtdump *evtdump; + + /* We got no event */ + if (len == 0) { + /* If we were purging the queue, it is now done */ + if (evt_filter & EVTF_PURGE) + evt_filter &= ~EVTF_PURGE; + break; + } + + if (len < sizeof(struct evtdump)) + errx(1, "Short buffer\n"); + + /* Toss outdated events */ + evtdump = (struct evtdump *)buf; + if (evtdump->timestamp < evt_start) + break; + + if (evt_filter & EVTF_ALL) + print_evt(buf, len); + if (evt_filter & EVTF_ERR) + print_err(buf, len); + if (evt_filter & EVTF_CFG) + print_cfg(buf, len); + if (evt_filter & EVTF_PH1DOWN) + print_ph1down(buf, len); + break; + } + + case ADMIN_SHOW_SA: + { + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + dump_isakmp_sa(buf, len); + break; + case ADMIN_PROTO_IPSEC: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + { + struct sadb_msg *msg = (struct sadb_msg *)buf; + + switch (msg->sadb_msg_errno) { + case ENOENT: + switch (msg->sadb_msg_type) { + case SADB_DELETE: + case SADB_GET: + printf("No entry.\n"); + break; + case SADB_DUMP: + printf("No SAD entries.\n"); + break; + } + break; + case 0: + while (1) { + pfkey_sadump(msg); + if (msg->sadb_msg_seq == 0) + break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + } + break; + default: + printf("%s.\n", strerror(msg->sadb_msg_errno)); + } + } + break; + case ADMIN_PROTO_INTERNAL: + dump_internal(buf, len); + break; + default: + printf("Invalid proto [%d]\n", com->ac_proto); + } + + } + break; + + default: + /* IGNORE */ + break; + } + + close(so); + return 0; + + bad: + close(so); + return -1; +} diff --git a/ipsec-tools/racoon/racoonctl.h b/ipsec-tools/racoon/racoonctl.h new file mode 100644 index 0000000..2b8b5a8 --- /dev/null +++ b/ipsec-tools/racoon/racoonctl.h @@ -0,0 +1,51 @@ +/* $Id: racoonctl.h,v 1.2 2004/12/30 11:08:32 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RACOONCTL_H +#define _RACOONCTL_H + +/* bumped on any change to the interface */ +#define RACOONCTL_INTERFACE 20041230 +extern u_int32_t racoonctl_interface; + +/* bumped when introducing changes that break backward compatibility */ +#define RACOONCTL_INTERFACE_MAJOR 1 +extern u_int32_t racoonctl_interface_major; + +extern u_int32_t loglevel; + +int com_init(void); +int com_send(vchar_t *); +int com_recv(vchar_t **); +struct sockaddr *get_sockaddr(int, char *, char *); + +#endif /* _RACOONCTL_H */ + diff --git a/ipsec-tools/racoon/remoteconf.c b/ipsec-tools/racoon/remoteconf.c new file mode 100644 index 0000000..0185db6 --- /dev/null +++ b/ipsec-tools/racoon/remoteconf.c @@ -0,0 +1,776 @@ +/* $Id: remoteconf.c,v 1.26.2.5 2005/11/06 17:18:26 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "genlist.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "grabmyaddr.h" +#include "proposal.h" +#include "vendorid.h" +#include "gcmalloc.h" +#include "strnames.h" +#include "algorithm.h" +#include "nattraversal.h" +#include "genlist.h" +#include "rsalist.h" + +static TAILQ_HEAD(_rmtree, remoteconf) rmtree; + +/* + * Script hook names and script hook paths + */ +char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" }; +vchar_t *script_paths = NULL; + +/*%%%*/ +/* + * search remote configuration. + * don't use port number to search if its value is either IPSEC_PORT_ANY. + * If matching anonymous entry, then new entry is copied from anonymous entry. + * If no anonymous entry found, then return NULL. + * OUT: NULL: NG + * Other: remote configuration entry. + */ +struct remoteconf * +getrmconf_strict(remote, allow_anon) + struct sockaddr *remote; + int allow_anon; +{ + struct remoteconf *p; + struct remoteconf *anon = NULL; + int withport; + char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + withport = 0; + +#ifndef ENABLE_NATT + /* + * We never have ports set in our remote configurations, but when + * NAT-T is enabled, the kernel can have policies with ports and + * send us an acquire message for a destination that has a port set. + * If we do this port check here, we don't find the remote config. + * + * In an ideal world, we would be able to have remote conf with + * port, and the port could be a wildcard. That test could be used. + */ + switch (remote->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)remote)->sin_port != IPSEC_PORT_ANY) + withport = 1; + break; +#ifdef INET6 + case AF_INET6: + if (((struct sockaddr_in6 *)remote)->sin6_port != IPSEC_PORT_ANY) + withport = 1; + break; +#endif + case AF_UNSPEC: + break; + + default: + plog(LLV_ERROR2, LOCATION, NULL, + "invalid ip address family: %d\n", remote->sa_family); + exit(1); + } +#endif /* ENABLE_NATT */ + + if (remote->sa_family == AF_UNSPEC) + snprintf (buf, sizeof(buf), "%s", "anonymous"); + else { + GETNAMEINFO(remote, addr, port); + snprintf(buf, sizeof(buf), "%s%s%s%s", addr, + withport ? "[" : "", + withport ? port : "", + withport ? "]" : ""); + } + + TAILQ_FOREACH(p, &rmtree, chain) { + if ((remote->sa_family == AF_UNSPEC + && remote->sa_family == p->remote->sa_family) + || (!withport && cmpsaddrwop(remote, p->remote) == 0) + || (withport && cmpsaddrstrict(remote, p->remote) == 0)) { + plog(LLV_DEBUG, LOCATION, NULL, + "configuration found for %s.\n", buf); + return p; + } + + /* save the pointer to the anonymous configuration */ + if (p->remote->sa_family == AF_UNSPEC) + anon = p; + } + + if (allow_anon && anon != NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "anonymous configuration selected for %s.\n", buf); + return anon; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "no remote configuration found.\n"); + + return NULL; +} + +struct remoteconf * +getrmconf(remote) + struct sockaddr *remote; +{ + return getrmconf_strict(remote, 1); +} + +struct remoteconf * +newrmconf() +{ + struct remoteconf *new; + int i; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + new->proposal = NULL; + + /* set default */ + new->doitype = IPSEC_DOI; + new->sittype = IPSECDOI_SIT_IDENTITY_ONLY; + new->idvtype = IDTYPE_UNDEFINED; + new->idvl_p = genlist_init(); + new->nonce_size = DEFAULT_NONCE_SIZE; + new->passive = FALSE; + new->ike_frag = FALSE; + new->esp_frag = IP_MAXPACKET; + new->ini_contact = TRUE; + new->mode_cfg = FALSE; + new->pcheck_level = PROP_CHECK_STRICT; + new->verify_identifier = FALSE; + new->verify_cert = TRUE; + new->getcert_method = ISAKMP_GETCERT_PAYLOAD; + new->getcacert_method = ISAKMP_GETCERT_LOCALFILE; + new->cacerttype = ISAKMP_CERT_X509SIGN; + new->cacertfile = NULL; + new->send_cert = TRUE; + new->send_cr = TRUE; + new->support_proxy = FALSE; + for (i = 0; i <= SCRIPT_MAX; i++) + new->script[i] = -1; + new->gen_policy = FALSE; + new->retry_counter = lcconf->retry_counter; + new->retry_interval = lcconf->retry_interval; +#ifdef __APPLE__ + new->nat_traversal = NATT_ON; + new->natt_multiple_user = FALSE; +#else + new->nat_traversal = NATT_OFF; +#endif + new->rsa_private = genlist_init(); + new->rsa_public = genlist_init(); + new->idv = NULL; + new->key = NULL; + + new->dpd = TRUE; /* Enable DPD support by default */ + new->dpd_interval = 0; /* Disable DPD checks by default */ + new->dpd_retry = 5; + new->dpd_maxfails = 5; + + return new; +} + +struct remoteconf * +copyrmconf(remote) + struct sockaddr *remote; +{ + struct remoteconf *new, *old; + + old = getrmconf_strict (remote, 0); + if (old == NULL) { + plog (LLV_ERROR, LOCATION, NULL, + "Remote configuration for '%s' not found!\n", + saddr2str (remote)); + return NULL; + } + + new = duprmconf (old); + + return new; +} + +void * +dupidvl(entry, arg) + void *entry; + void *arg; +{ + struct idspec *id; + struct idspec *old = (struct idspec *) entry; + id = newidspec(); + if (!id) return (void *) -1; + + if (set_identifier(&id->id, old->idtype, old->id) != 0) + return (void *) -1; + + id->idtype = old->idtype; + + genlist_append(arg, id); + return NULL; +} + +struct remoteconf * +duprmconf (rmconf) + struct remoteconf *rmconf; +{ + struct remoteconf *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + memcpy (new, rmconf, sizeof (*new)); + // FIXME: We should duplicate the proposal as well. + // This is now handled in the cfparse.y + // new->proposal = ...; + + /* duplicate dynamic structures */ + if (new->etypes) + new->etypes=dupetypes(new->etypes); + new->idvl_p = genlist_init(); + genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p); + + return new; +} + +static void +idspec_free(void *data) +{ + vfree (((struct idspec *)data)->id); + free (data); +} + +static void +proposalspec_free(struct proposalspec *head) +{ + + struct proposalspec* next_propsp = head; + + while (next_propsp) { + struct proposalspec* curr_propsp; + struct secprotospec* next_protosp; + + curr_propsp = next_propsp; + next_propsp = next_propsp->next; + next_protosp = curr_propsp->spspec; + while (next_protosp) { + struct secprotospec* curr_protosp; + + curr_protosp = next_protosp; + next_protosp = next_protosp->next; + + if (curr_protosp->gssid) + free(curr_protosp->gssid); + if (curr_protosp->remote) + free(curr_protosp->remote); + racoon_free(curr_protosp); + } + racoon_free(curr_propsp); + } +} + +void +delrmconf(rmconf) + struct remoteconf *rmconf; +{ + if (rmconf->remote) + racoon_free(rmconf->remote); + if (rmconf->etypes) + deletypes(rmconf->etypes); + if (rmconf->idv) + vfree(rmconf->idv); + if (rmconf->idvl_p) + genlist_free(rmconf->idvl_p, idspec_free); + if (rmconf->dhgrp) + oakley_dhgrp_free(rmconf->dhgrp); + if (rmconf->proposal) + delisakmpsa(rmconf->proposal); + if (rmconf->mycertfile) + racoon_free(rmconf->mycertfile); + if (rmconf->myprivfile) + racoon_free(rmconf->myprivfile); + if (rmconf->peerscertfile) + racoon_free(rmconf->peerscertfile); + if (rmconf->cacertfile) + racoon_free(rmconf->cacertfile); + if (rmconf->prhead) + proposalspec_free(rmconf->prhead); + if (rmconf->rsa_private) + genlist_free(rmconf->rsa_private, rsa_key_free); + if (rmconf->rsa_public) + genlist_free(rmconf->rsa_public, rsa_key_free); +#ifdef __APPLE__ + if (rmconf->shared_secret) + vfree(rmconf->shared_secret); + if (rmconf->keychainCertRef) + vfree(rmconf->keychainCertRef); + if (rmconf->open_dir_auth_group) + vfree(rmconf->open_dir_auth_group); +#endif + + racoon_free(rmconf); +} + +void +delisakmpsa(sa) + struct isakmpsa *sa; +{ + if (sa->dhgrp) + oakley_dhgrp_free(sa->dhgrp); + if (sa->next) + delisakmpsa(sa->next); +#ifdef HAVE_GSSAPI + if (sa->gssid) + vfree(sa->gssid); +#endif + racoon_free(sa); +} + +struct etypes * +dupetypes(orig) + struct etypes *orig; +{ + struct etypes *new; + + if (!orig) + return NULL; + + new = racoon_malloc(sizeof(struct etypes)); + if (new == NULL) + return NULL; + + new->type = orig->type; + new->next = NULL; + + if (orig->next) + new->next=dupetypes(orig->next); + + return new; +} + +void +deletypes(e) + struct etypes *e; +{ + if (e->next) + deletypes(e->next); + racoon_free(e); +} + +/* + * insert into head of list. + */ +void +insrmconf(new) + struct remoteconf *new; +{ + TAILQ_INSERT_HEAD(&rmtree, new, chain); +} + +void +remrmconf(rmconf) + struct remoteconf *rmconf; +{ + TAILQ_REMOVE(&rmtree, rmconf, chain); +} + +void +flushrmconf() +{ + struct remoteconf *p, *next; + + for (p = TAILQ_FIRST(&rmtree); p; p = next) { + next = TAILQ_NEXT(p, chain); + remrmconf(p); + delrmconf(p); + } +} + +void +initrmconf() +{ + TAILQ_INIT(&rmtree); +} + +/* check exchange type to be acceptable */ +struct etypes * +check_etypeok(rmconf, etype) + struct remoteconf *rmconf; + u_int8_t etype; +{ + struct etypes *e; + + for (e = rmconf->etypes; e != NULL; e = e->next) { + if (e->type == etype) + break; + } + + return e; +} + +/*%%%*/ +struct isakmpsa * +newisakmpsa() +{ + struct isakmpsa *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + /* + * Just for sanity, make sure this is initialized. This is + * filled in for real when the ISAKMP proposal is configured. + */ + new->vendorid = VENDORID_UNKNOWN; + + new->next = NULL; + new->rmconf = NULL; +#ifdef HAVE_GSSAPI + new->gssid = NULL; +#endif + + return new; +} + +/* + * insert into tail of list. + */ +void +insisakmpsa(new, rmconf) + struct isakmpsa *new; + struct remoteconf *rmconf; +{ + struct isakmpsa *p; + + new->rmconf = rmconf; + + if (rmconf->proposal == NULL) { + rmconf->proposal = new; + return; + } + + for (p = rmconf->proposal; p->next != NULL; p = p->next) + ; + p->next = new; + + return; +} + +struct remoteconf * +foreachrmconf(rmconf_func_t rmconf_func, void *data) +{ + struct remoteconf *p, *ret = NULL; + + TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) { + ret = (*rmconf_func)(p, data); + if (ret) + break; + } + + return ret; +} + +static void * +dump_peers_identifiers (void *entry, void *arg) +{ + struct idspec *id = (struct idspec*) entry; + char buf[1024], *pbuf; + pbuf = buf; + pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), "\tpeers_identifier %s", + s_idtype (id->idtype)); + if (id->id) + pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), " \"%s\"", id->id->v); + plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf); + return NULL; +} + +static struct remoteconf * +dump_rmconf_single (struct remoteconf *p, void *data) +{ + struct etypes *etype = p->etypes; + struct isakmpsa *prop = p->proposal; + char buf[1024], *pbuf; + + pbuf = buf; + pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "remote %s", saddr2str(p->remote)); + if (p->inherited_from) + pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), " inherit %s", + saddr2str(p->inherited_from->remote)); + plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf); + pbuf = buf; + pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "\texchange_type "); + while (etype) { + pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), "%s%s", s_etype(etype->type), + etype->next != NULL ? ", " : ";\n"); + etype = etype->next; + } + plog(LLV_INFO, LOCATION, NULL, "%s", buf); + plog(LLV_INFO, LOCATION, NULL, "\tdoi %s;\n", s_doi(p->doitype)); + pbuf = buf; + pbuf += snprintf(pbuf, sizeof(buf) - (pbuf - buf), "\tmy_identifier %s", s_idtype (p->idvtype)); + if (p->idvtype == IDTYPE_ASN1DN) { + plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf); + plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n", + p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*", + p->mycertfile, p->myprivfile); + switch (p->getcert_method) { + case 0: + break; + case ISAKMP_GETCERT_PAYLOAD: + plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n"); + break; + case ISAKMP_GETCERT_LOCALFILE: + plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile); + break; + case ISAKMP_GETCERT_DNS: + plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n"); + break; + default: + plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method); + } + } + else { + if (p->idv) + pbuf += snprintf (pbuf, sizeof(buf) - (pbuf - buf), " \"%s\"", p->idv->v); + plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf); + genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL); + } + + plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n", + s_switch (p->send_cert)); + plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n", + s_switch (p->send_cr)); + plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n", + s_switch (p->verify_cert)); + plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n", + s_switch (p->verify_identifier)); + plog(LLV_INFO, LOCATION, NULL, "\tnat_traversal %s;\n", + p->nat_traversal == NATT_FORCE ? + "force" : s_switch (p->nat_traversal)); +#ifdef __APPLE__ + plog(LLV_INFO, LOCATION, NULL, "\tnatt_multiple_user %s;\n", + s_switch (p->natt_multiple_user)); +#endif + plog(LLV_INFO, LOCATION, NULL, "\tnonce_size %d;\n", + p->nonce_size); + plog(LLV_INFO, LOCATION, NULL, "\tpassive %s;\n", + s_switch (p->passive)); + plog(LLV_INFO, LOCATION, NULL, "\tike_frag %s;\n", + s_switch (p->ike_frag)); + plog(LLV_INFO, LOCATION, NULL, "\tesp_frag %d;\n", p->esp_frag); + plog(LLV_INFO, LOCATION, NULL, "\tinitial_contact %s;\n", + s_switch (p->ini_contact)); + plog(LLV_INFO, LOCATION, NULL, "\tgenerate_policy %s;\n", + s_switch (p->gen_policy)); + plog(LLV_INFO, LOCATION, NULL, "\tsupport_proxy %s;\n", + s_switch (p->support_proxy)); + + while (prop) { + plog(LLV_INFO, LOCATION, NULL, "\n"); + plog(LLV_INFO, LOCATION, NULL, + "\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n", + prop->prop_no, prop->trns_no, + saddr2str(prop->rmconf->remote)); + plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n"); + plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n", + (long)prop->lifetime); + plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime bytes %zd;\n", + prop->lifebyte); + plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n", + alg_oakley_dhdef_name(prop->dh_group)); + plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n", + alg_oakley_encdef_name(prop->enctype)); + plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n", + alg_oakley_hashdef_name(prop->hashtype)); + plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n", + alg_oakley_authdef_name(prop->authmethod)); + plog(LLV_INFO, LOCATION, NULL, "\t}\n"); + prop = prop->next; + } + plog(LLV_INFO, LOCATION, NULL, "}\n"); + plog(LLV_INFO, LOCATION, NULL, "\n"); + + return NULL; +} + +void +dumprmconf() +{ + foreachrmconf (dump_rmconf_single, NULL); +} + +struct idspec * +newidspec() +{ + struct idspec *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + new->idtype = IDTYPE_ADDRESS; + + return new; +} + +int +script_path_add(path) + vchar_t *path; +{ + char *script_dir; + vchar_t *new_storage; + vchar_t *new_path; + vchar_t **sp; + size_t len; + size_t size; + + script_dir = lcconf->pathinfo[LC_PATHTYPE_SCRIPT]; + + /* Try to find the script in the script directory */ + if ((path->v[0] != '/') && (script_dir != NULL)) { + len = strlen(script_dir) + sizeof("/") + path->l + 1; + + if ((new_path = vmalloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + + new_path->v[0] = '\0'; + (void)strlcat(new_path->v, script_dir, len); + (void)strlcat(new_path->v, "/", len); + (void)strlcat(new_path->v, path->v, len); + + vfree(path); + path = new_path; + } + + /* First time, initialize */ + if (script_paths == NULL) + len = sizeof(vchar_t *); + else + len = script_paths->l; + + /* Add a slot for a new path */ + len += sizeof(vchar_t *); + if ((new_storage = vrealloc(script_paths, len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory: %s\n", strerror(errno)); + return -1; + } + script_paths = new_storage; + + size = len / sizeof(vchar_t *); + sp = (vchar_t **)script_paths->v; + sp[size - 1] = NULL; + sp[size - 2] = path; + + return (size - 2); +} + +struct isakmpsa * +dupisakmpsa(sa) + struct isakmpsa *sa; +{ + struct isakmpsa *res = NULL; + + if (sa == NULL) + return NULL; + + res = newisakmpsa(); + if(res == NULL) + return NULL; + + *res = *sa; +#ifdef HAVE_GSSAPI + /* + * XXX gssid + */ +#endif + res->next=NULL; + + if (sa->dhgrp != NULL) + oakley_setdhgroup(sa->dh_group, &(res->dhgrp)); + + return res; + +} + +void +rsa_key_free(void *entry) +{ + struct rsa_key *key = (struct rsa_key *)entry; + + if (key->src) + free(key->src); + if (key->dst) + free(key->dst); + if (key->rsa) + RSA_free(key->rsa); + free(key); +} diff --git a/ipsec-tools/racoon/remoteconf.h b/ipsec-tools/racoon/remoteconf.h new file mode 100644 index 0000000..0a9d485 --- /dev/null +++ b/ipsec-tools/racoon/remoteconf.h @@ -0,0 +1,224 @@ +/* $Id: remoteconf.h,v 1.19.2.1 2005/05/20 00:37:42 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _REMOTECONF_H +#define _REMOTECONF_H + +/* remote configuration */ + +#include +#include "genlist.h" +#ifdef __APPLE__ +#include +#endif +#include "algorithm.h" + +struct proposalspec { + time_t lifetime; /* for isakmp/ipsec */ + int lifebyte; /* for isakmp/ipsec */ + struct secprotospec *spspec; /* the head is always current spec. */ + struct proposalspec *next; /* the tail is the most prefered. */ + struct proposalspec *prev; +}; + +struct secprotospec { + int prop_no; + int trns_no; + int strength; /* for isakmp/ipsec */ + int encklen; /* for isakmp/ipsec */ + time_t lifetime; /* for isakmp */ + int lifebyte; /* for isakmp */ + int proto_id; /* for ipsec (isakmp?) */ + int ipsec_level; /* for ipsec */ + int encmode; /* for ipsec */ + int vendorid; /* for isakmp */ + char *gssid; + struct sockaddr *remote; + int algclass[MAXALGCLASS]; + + struct secprotospec *next; /* the tail is the most prefiered. */ + struct secprotospec *prev; + struct proposalspec *back; +}; + + +struct etypes { + int type; + struct etypes *next; +}; + +/* Script hooks */ +#define SCRIPT_PHASE1_UP 0 +#define SCRIPT_PHASE1_DOWN 1 +#define SCRIPT_MAX 1 +extern char *script_names[SCRIPT_MAX + 1]; +extern vchar_t *script_paths; + +struct remoteconf { + struct sockaddr *remote; /* remote IP address */ + /* if family is AF_UNSPEC, that is + * for anonymous configuration. */ + + struct etypes *etypes; /* exchange type list. the head + * is a type to be sent first. */ + int doitype; /* doi type */ + int sittype; /* situation type */ + + int idvtype; /* my identifier type */ + vchar_t *idv; /* my identifier */ + vchar_t *key; /* my pre-shared key */ + struct genlist *idvl_p; /* peer's identifiers list */ + +#ifdef __APPLE__ + int identity_in_keychain; /* cert and private key is in the keychain */ + vchar_t *keychainCertRef; /* peristant keychain ref for cert */ + int secrettype; /* type of secret [use, key, keychain] */ + vchar_t *shared_secret; /* shared secret */ + vchar_t *open_dir_auth_group; /* group to be used to authorize user */ +#endif + + int certtype; /* certificate type if need */ + char *mycertfile; /* file name of my certificate */ + char *myprivfile; /* file name of my private key file */ + char *peerscertfile; /* file name of peer's certifcate */ + int getcert_method; /* the way to get peer's certificate */ + int cacerttype; /* CA type is needed */ + char *cacertfile; /* file name of CA */ + int getcacert_method; /* the way to get the CA */ + int send_cert; /* send to CERT or not */ + int send_cr; /* send to CR or not */ + int verify_cert; /* verify a CERT strictly */ +#ifdef __APPLE__ + int cert_verification; /* openssl or security framework */ + int cert_verification_option; /* nothing, peers identifier, or open_dir */ +#endif + int verify_identifier; /* vefify the peer's identifier */ + int nonce_size; /* the number of bytes of nonce */ + int passive; /* never initiate */ + int ike_frag; /* IKE fragmentation */ + int esp_frag; /* ESP fragmentation */ + int mode_cfg; /* Gets config through mode config */ + int support_proxy; /* support mip6/proxy */ + int gen_policy; /* generate policy if no policy found */ + int ini_contact; /* initial contact */ + int pcheck_level; /* level of propocl checking */ + int nat_traversal; /* NAT-Traversal */ +#ifdef __APPLE__ + int natt_multiple_user; /* special handling of multiple users behind a nat - for VPN server */ +#endif + int script[SCRIPT_MAX + 1]; /* script hooks index in script_paths */ + int dh_group; /* use it when only aggressive mode */ + struct dhgroup *dhgrp; /* use it when only aggressive mode */ + /* above two can't be defined by user*/ + + int retry_counter; /* times to retry. */ + int retry_interval; /* interval each retry. */ + /* above 2 values are copied from localconf. */ + + int dpd; /* Negociate DPD support ? */ + int dpd_retry; /* in seconds */ + int dpd_interval; /* in seconds */ + int dpd_maxfails; + + struct isakmpsa *proposal; /* proposal list */ + struct remoteconf *inherited_from; /* the original rmconf + from which this one + was inherited */ + struct proposalspec *prhead; + + struct genlist *rsa_private, /* lists of PlainRSA keys to use */ + *rsa_public; + TAILQ_ENTRY(remoteconf) chain; /* next remote conf */ +}; + +struct dhgroup; + +/* ISAKMP SA specification */ +struct isakmpsa { + int prop_no; + int trns_no; + time_t lifetime; + size_t lifebyte; + int enctype; + int encklen; + int authmethod; + int hashtype; + int vendorid; +#ifdef HAVE_GSSAPI + vchar_t *gssid; +#endif + int dh_group; /* don't use it if aggressive mode */ + struct dhgroup *dhgrp; /* don't use it if aggressive mode */ + + struct isakmpsa *next; /* next transform */ + struct remoteconf *rmconf; /* backpointer to remoteconf */ +}; + +struct idspec { + int idtype; /* identifier type */ + vchar_t *id; /* identifier */ +}; + +typedef struct remoteconf * (rmconf_func_t)(struct remoteconf *rmconf, void *data); + +extern struct remoteconf *getrmconf __P((struct sockaddr *)); +extern struct remoteconf *getrmconf_strict + __P((struct sockaddr *remote, int allow_anon)); +extern struct remoteconf *copyrmconf __P((struct sockaddr *)); +extern struct remoteconf *newrmconf __P((void)); +extern struct remoteconf *duprmconf __P((struct remoteconf *)); +extern void delrmconf __P((struct remoteconf *)); +extern void delisakmpsa __P((struct isakmpsa *)); +extern void deletypes __P((struct etypes *)); +extern struct etypes * dupetypes __P((struct etypes *)); +extern void insrmconf __P((struct remoteconf *)); +extern void remrmconf __P((struct remoteconf *)); +extern void flushrmconf __P((void)); +extern void initrmconf __P((void)); +extern struct etypes *check_etypeok + __P((struct remoteconf *, u_int8_t)); +extern struct remoteconf *foreachrmconf __P((rmconf_func_t rmconf_func, + void *data)); + +extern struct isakmpsa *newisakmpsa __P((void)); +extern struct isakmpsa *dupisakmpsa __P((struct isakmpsa *)); + +extern void insisakmpsa __P((struct isakmpsa *, struct remoteconf *)); + +extern void dumprmconf __P((void)); + +extern struct idspec *newidspec __P((void)); + +extern int script_path_add __P((vchar_t *)); + +extern void rsa_key_free __P((void *entry)); + +#endif /* _REMOTECONF_H */ diff --git a/ipsec-tools/racoon/rsalist.c b/ipsec-tools/racoon/rsalist.c new file mode 100644 index 0000000..3db208d --- /dev/null +++ b/ipsec-tools/racoon/rsalist.c @@ -0,0 +1,214 @@ +/* $Id: rsalist.c,v 1.3 2004/11/08 12:04:23 ludvigm Exp $ */ + +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include + +#include +#include +#include +#include + +#include +#include + +#include "misc.h" +#include "plog.h" +#include "sockmisc.h" +#include "rsalist.h" +#include "genlist.h" +#include "remoteconf.h" +#include "crypto_openssl.h" + +#ifndef LIST_FIRST +#define LIST_FIRST(head) ((head)->lh_first) +#endif + +#ifndef LIST_NEXT +#define LIST_NEXT(elm, field) ((elm)->field.le_next) +#endif + +/* from prsa_tok.l */ +int prsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type); + +int +rsa_key_insert(struct genlist *list, struct netaddr *src, + struct netaddr *dst, RSA *rsa) +{ + struct rsa_key *rsa_key; + + rsa_key = calloc(sizeof(struct rsa_key), 1); + rsa_key->rsa = rsa; + + if (src) + rsa_key->src = src; + else + rsa_key->src = calloc(sizeof(*rsa_key->src), 1); + + if (dst) + rsa_key->dst = dst; + else + rsa_key->dst = calloc(sizeof(*rsa_key->dst), 1); + + genlist_append(list, rsa_key); + + return 0; +} + +static void * +rsa_key_dump_one(void *entry, void *arg) +{ + struct rsa_key *key = entry; + + plog(LLV_DEBUG, LOCATION, NULL, "Entry %s\n", + naddrwop2str_fromto("%s -> %s", key->src, + key->dst)); + if (loglevel > LLV_DEBUG) + RSA_print_fp(stdout, key->rsa, 4); + + return NULL; +} + +void +rsa_key_dump(struct genlist *list) +{ + genlist_foreach(list, rsa_key_dump_one, NULL); +} + +static void * +rsa_list_count_one(void *entry, void *arg) +{ + if (arg) + (*(unsigned long *)arg)++; + return NULL; +} + +unsigned long +rsa_list_count(struct genlist *list) +{ + unsigned long count = 0; + genlist_foreach(list, rsa_list_count_one, &count); + return count; +} + +struct lookup_result { + struct ph1handle *iph1; + int max_score; + struct genlist *winners; +}; + +static void * +rsa_lookup_key_one(void *entry, void *data) +{ + int local_score, remote_score; + struct lookup_result *req = data; + struct rsa_key *key = entry; + + local_score = naddr_score(key->src, req->iph1->local); + remote_score = naddr_score(key->dst, req->iph1->remote); + + plog(LLV_DEBUG, LOCATION, NULL, "Entry %s scored %d/%d\n", + naddrwop2str_fromto("%s -> %s", key->src, key->dst), + local_score, remote_score); + + if (local_score >= 0 && remote_score >= 0) { + if (local_score + remote_score > req->max_score) { + req->max_score = local_score + remote_score; +// genlist_free(req->winners, NULL); + } + + if (local_score + remote_score >= req->max_score) { + genlist_append(req->winners, key); + } + } + + /* Always traverse the whole list */ + return NULL; +} + +struct genlist * +rsa_lookup_keys(struct ph1handle *iph1, int my) +{ + struct genlist *list; + struct lookup_result r; + + plog(LLV_DEBUG, LOCATION, NULL, "Looking up RSA key for %s\n", + saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); + + r.iph1 = iph1; + r.max_score = -1; + r.winners = genlist_init(); + + if (my) + list = iph1->rmconf->rsa_private; + else + list = iph1->rmconf->rsa_public; + + genlist_foreach(list, rsa_lookup_key_one, &r); + + if (loglevel >= LLV_DEBUG) + rsa_key_dump(r.winners); + + return r.winners; +} + +int +rsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type) +{ + int ret; + + plog(LLV_DEBUG, LOCATION, NULL, "Parsing %s\n", fname); + ret = prsa_parse_file(list, fname, type); + if (loglevel >= LLV_DEBUG) + rsa_key_dump(list); + return ret; +} + +RSA * +rsa_try_check_rsasign(vchar_t *source, vchar_t *sig, struct genlist *list) +{ + struct rsa_key *key; + struct genlist_entry *gp; + + for(key = genlist_next(list, &gp); key; key = genlist_next(NULL, &gp)) { + plog(LLV_DEBUG, LOCATION, NULL, "Checking key %s...\n", + naddrwop2str_fromto("%s -> %s", key->src, key->dst)); + if (eay_check_rsasign(source, sig, key->rsa) == 0) { + plog(LLV_DEBUG, LOCATION, NULL, " ... YEAH!\n"); + return key->rsa; + } + plog(LLV_DEBUG, LOCATION, NULL, " ... nope.\n"); + } + return NULL; +} diff --git a/ipsec-tools/racoon/rsalist.h b/ipsec-tools/racoon/rsalist.h new file mode 100644 index 0000000..4ee4c4c --- /dev/null +++ b/ipsec-tools/racoon/rsalist.h @@ -0,0 +1,63 @@ +/* $Id: rsalist.h,v 1.2 2004/07/12 20:43:51 ludvigm Exp $ */ +/* + * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. + * Contributed by: Michal Ludvig , 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 +#include + +#include "handler.h" +#include "genlist.h" + +enum rsa_key_type { + RSA_TYPE_ANY = 0, + RSA_TYPE_PUBLIC, + RSA_TYPE_PRIVATE +}; + +struct rsa_key { + struct netaddr *src; + struct netaddr *dst; + RSA *rsa; +}; + +int rsa_key_insert(struct genlist *list, struct netaddr *src, struct netaddr *dst, RSA *rsa); +void rsa_key_dump(struct genlist *list); + +struct genlist *rsa_lookup_keys(struct ph1handle *iph1, int my); +RSA *rsa_try_check_rsasign(vchar_t *source, vchar_t *sig, struct genlist *list); + +unsigned long rsa_list_count(struct genlist *list); + +int rsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type); + +#endif /* _RSALIST_H */ diff --git a/ipsec-tools/racoon/safefile.c b/ipsec-tools/racoon/safefile.c new file mode 100644 index 0000000..b698fa7 --- /dev/null +++ b/ipsec-tools/racoon/safefile.c @@ -0,0 +1,91 @@ +/* $KAME: safefile.c,v 1.5 2001/03/05 19:54:06 thorpej Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "plog.h" +#include "debug.h" +#include "misc.h" +#include "safefile.h" + +int +safefile(path, secret) + const char *path; + int secret; +{ + struct stat s; + uid_t me; + + /* no setuid */ + if (getuid() != geteuid()) { + plog(LLV_ERROR, LOCATION, NULL, + "setuid'ed execution not allowed\n"); + return -1; + } + + if (stat(path, &s) != 0) + return -1; + + /* the file must be owned by the running uid */ + me = getuid(); + if (s.st_uid != me) { + plog(LLV_ERROR, LOCATION, NULL, + "%s has invalid owner uid\n", path); + return -1; + } + + switch (s.st_mode & S_IFMT) { + case S_IFREG: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "%s is an invalid file type 0x%x\n", path, + (s.st_mode & S_IFMT)); + return -1; + } + + /* secret file should not be read by others */ + if (secret) { + if ((s.st_mode & S_IRWXG) != 0 || (s.st_mode & S_IRWXO) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "%s has weak file permission\n", path); + return -1; + } + } + + return 0; +} diff --git a/ipsec-tools/racoon/safefile.h b/ipsec-tools/racoon/safefile.h new file mode 100644 index 0000000..2651e7e --- /dev/null +++ b/ipsec-tools/racoon/safefile.h @@ -0,0 +1,37 @@ +/* $Id: safefile.h,v 1.4 2004/07/12 18:32:12 ludvigm Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SAFEFILE_H +#define _SAFEFILE_H + +extern int safefile __P((const char *, int)); + +#endif /* _SAFEFILE_H */ diff --git a/ipsec-tools/racoon/sainfo.c b/ipsec-tools/racoon/sainfo.c new file mode 100644 index 0000000..2ad8797 --- /dev/null +++ b/ipsec-tools/racoon/sainfo.c @@ -0,0 +1,250 @@ +/* $KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "handler.h" +#include "algorithm.h" +#include "sainfo.h" +#include "gcmalloc.h" + +static LIST_HEAD(_sitree, sainfo) sitree; + +/* %%% + * modules for ipsec sa info + */ +/* + * return matching entry. + * no matching entry found and if there is anonymous entry, return it. + * else return NULL. + * XXX by each data type, should be changed to compare the buffer. + * First pass is for sainfo from a specified peer, second for others. + */ +struct sainfo * +getsainfo(src, dst, peer) + const vchar_t *src, *dst, *peer; +{ + struct sainfo *s = NULL; + struct sainfo *anonymous = NULL; + int pass = 1; + + if (peer == NULL) + pass = 2; + again: + LIST_FOREACH(s, &sitree, chain) { + if (s->id_i != NULL) { + if (pass == 2) + continue; + if (memcmp(peer->v, s->id_i->v, s->id_i->l) != 0) + continue; + } else if (pass == 1) + continue; + if (s->idsrc == NULL) { + anonymous = s; + continue; + } + + /* anonymous ? */ + if (src == NULL) { + if (anonymous != NULL) + break; + continue; + } + + if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0 + && memcmp(dst->v, s->iddst->v, s->iddst->l) == 0) + return s; + } + + if (anonymous) { + plog(LLV_DEBUG, LOCATION, NULL, + "anonymous sainfo selected.\n"); + } else if (pass == 1) { + pass = 2; + goto again; + } + + return anonymous; +} + +struct sainfo * +newsainfo() +{ + struct sainfo *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; + new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; + + return new; +} + +void +delsainfo(si) + struct sainfo *si; +{ + int i; + + for (i = 0; i < MAXALGCLASS; i++) + delsainfoalg(si->algs[i]); + + if (si->idsrc) + vfree(si->idsrc); + if (si->iddst) + vfree(si->iddst); + + racoon_free(si); +} + +void +inssainfo(new) + struct sainfo *new; +{ + LIST_INSERT_HEAD(&sitree, new, chain); +} + +void +remsainfo(si) + struct sainfo *si; +{ + LIST_REMOVE(si, chain); +} + +void +flushsainfo() +{ + struct sainfo *s, *next; + + for (s = LIST_FIRST(&sitree); s; s = next) { + next = LIST_NEXT(s, chain); + remsainfo(s); + delsainfo(s); + } +} + +void +initsainfo() +{ + LIST_INIT(&sitree); +} + +struct sainfoalg * +newsainfoalg() +{ + struct sainfoalg *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +void +delsainfoalg(alg) + struct sainfoalg *alg; +{ + struct sainfoalg *a, *next; + + for (a = alg; a; a = next) { + next = a->next; + racoon_free(a); + } +} + +void +inssainfoalg(head, new) + struct sainfoalg **head; + struct sainfoalg *new; +{ + struct sainfoalg *a; + + for (a = *head; a && a->next; a = a->next) + ; + if (a) + a->next = new; + else + *head = new; +} + +const char * +sainfo2str(si) + const struct sainfo *si; +{ + static char buf[256]; + + if (si->idsrc == NULL) + snprintf(buf, sizeof(buf), "anonymous"); + else { + snprintf(buf, sizeof(buf), "%s", ipsecdoi_id2str(si->idsrc)); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " %s", ipsecdoi_id2str(si->iddst)); + } + + if (si->id_i != NULL) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " from %s", ipsecdoi_id2str(si->id_i)); + + return buf; +} diff --git a/ipsec-tools/racoon/sainfo.h b/ipsec-tools/racoon/sainfo.h new file mode 100644 index 0000000..ec2a72f --- /dev/null +++ b/ipsec-tools/racoon/sainfo.h @@ -0,0 +1,76 @@ +/* $Id: sainfo.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SAINFO_H +#define _SAINFO_H + +#include + +/* SA info */ +struct sainfo { + vchar_t *idsrc; + vchar_t *iddst; + /* + * idsrc and iddst are constructed body of ID payload. + * that is (struct ipsecdoi_id_b) + ID value. + * If idsrc == NULL, that is anonymous entry. + */ + + time_t lifetime; + int lifebyte; + int pfs_group; /* only use when pfs is required. */ + vchar_t *id_i; /* identifier of the authorized initiator */ + struct sainfoalg *algs[MAXALGCLASS]; + + LIST_ENTRY(sainfo) chain; +}; + +/* algorithm type */ +struct sainfoalg { + int alg; + int encklen; /* key length if encryption algorithm */ + struct sainfoalg *next; +}; + +extern struct sainfo *getsainfo __P((const vchar_t *, + const vchar_t *, const vchar_t *)); +extern struct sainfo *newsainfo __P((void)); +extern void delsainfo __P((struct sainfo *)); +extern void inssainfo __P((struct sainfo *)); +extern void remsainfo __P((struct sainfo *)); +extern void flushsainfo __P((void)); +extern void initsainfo __P((void)); +extern struct sainfoalg *newsainfoalg __P((void)); +extern void delsainfoalg __P((struct sainfoalg *)); +extern void inssainfoalg __P((struct sainfoalg **, struct sainfoalg *)); +extern const char * sainfo2str __P((const struct sainfo *)); + +#endif /* _SAINFO_H */ diff --git a/ipsec-tools/racoon/schedule.c b/ipsec-tools/racoon/schedule.c new file mode 100644 index 0000000..705f4ce --- /dev/null +++ b/ipsec-tools/racoon/schedule.c @@ -0,0 +1,362 @@ +/* $KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +void +test(tick) + int *tick; +{ + printf("execute %d\n", *tick); + racoon_free(tick); +} + +void +getstdin() +{ + int *tick; + char buf[16]; + + read(0, buf, sizeof(buf)); + if (buf[0] == 'd') { + struct scheddump *scbuf, *p; + int len; + sched_dump((caddr_t *)&scbuf, &len); + if (buf == NULL) + return; + for (p = scbuf; len; p++) { + printf("xtime=%ld\n", p->xtime); + len -= sizeof(*p); + } + racoon_free(scbuf); + return; + } + + tick = (int *)racoon_malloc(sizeof(*tick)); + *tick = atoi(buf); + printf("new queue tick = %d\n", *tick); + sched_new(*tick, test, tick); +} + +int +main() +{ + static fd_set mask0; + int nfds = 0; + fd_set rfds; + struct timeval *timeout; + int error; + + FD_ZERO(&mask0); + FD_SET(0, &mask0); + nfds = 1; + + /* initialize */ + sched_init(); + + while (1) { + rfds = mask0; + + timeout = schedular(); + + error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); + if (error < 0) { + switch (errno) { + case EINTR: continue; + default: + err(1, "select"); + } + /*NOTREACHED*/ + } + + if (FD_ISSET(0, &rfds)) + getstdin(); + } +} +#endif diff --git a/ipsec-tools/racoon/schedule.h b/ipsec-tools/racoon/schedule.h new file mode 100644 index 0000000..bb2df2b --- /dev/null +++ b/ipsec-tools/racoon/schedule.h @@ -0,0 +1,81 @@ +/* $Id: schedule.h,v 1.4 2004/11/18 15:14:44 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SCHEDULE_H +#define _SCHEDULE_H + +#include +#include + +/* scheduling table */ +/* the head is the nearest event. */ +struct sched { + time_t xtime; /* event time which is as time(3). */ + /* + * if defined FIXY2038PROBLEM, this time + * is from the time when called sched_init(). + */ + void (*func) __P((void *)); /* call this function when timeout. */ + void *param; /* pointer to parameter */ + + int dead; /* dead or alive */ + long id; /* for debug */ + time_t created; /* for debug */ + time_t tick; /* for debug */ + + TAILQ_ENTRY(sched) chain; +}; + +/* cancel schedule */ +#define SCHED_KILL(s) \ +do { \ + sched_kill(s); \ + s = NULL; \ +} while(0) + +/* must be called after it's called from scheduler. */ +#define SCHED_INIT(s) (s) = NULL + +struct scheddump { + time_t xtime; + long id; + time_t created; + time_t tick; +}; + +struct timeval *schedular __P((void)); +struct sched *sched_new __P((time_t, void (*func) __P((void *)), void *)); +void sched_kill __P((struct sched *)); +int sched_dump __P((caddr_t *, int *)); +void sched_init __P((void)); +void sched_scrub_param __P((void *)); + +#endif /* _SCHEDULE_H */ diff --git a/ipsec-tools/racoon/session.c b/ipsec-tools/racoon/session.c new file mode 100644 index 0000000..1028290 --- /dev/null +++ b/ipsec-tools/racoon/session.c @@ -0,0 +1,659 @@ +/* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#if HAVE_SYS_WAIT_H +# include +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(s) ((unsigned)(s) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(s) (((s) & 255) == 0) +#endif + +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "schedule.h" +#include "session.h" +#include "grabmyaddr.h" +#include "evt.h" +#include "cfparse_proto.h" +#include "isakmp_var.h" +#include "admin_var.h" +#include "admin.h" +#include "privsep.h" +#include "oakley.h" +#include "pfkey.h" +#include "handler.h" +#include "localconf.h" +#include "remoteconf.h" +#include "backupsa.h" +#ifdef ENABLE_NATT +#include "nattraversal.h" +#endif +#include "vpn_control_var.h" +#include "policy.h" + +extern pid_t racoon_pid; +static void close_session __P((void)); +static void check_rtsock __P((void *)); +static void initfds __P((void)); +static void init_signal __P((void)); +static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int)))); +static void check_sigreq __P((void)); +static void check_flushsa_stub __P((void *)); +static void check_flushsa __P((void)); +static void auto_exit_do __P((void *)); +static int close_sockets __P((void)); + +static fd_set mask0; +static fd_set maskdying; +static int nfds = 0; +static volatile sig_atomic_t sigreq[NSIG + 1]; +static int dying = 0; +static struct sched *check_rtsock_sched = NULL; + +int +session(void) +{ + fd_set rfds; + struct timeval *timeout; + int error; + struct myaddrs *p; + char pid_file[MAXPATHLEN]; + FILE *fp; + int i, update_fds; + + /* initialize schedular */ + sched_init(); + + initmyaddr(); + + if (isakmp_init() < 0) { + plog(LLV_ERROR2, LOCATION, NULL, + "failed to initialize isakmp"); + exit(1); + } + +#ifdef ENABLE_ADMINPORT + if (admin_init() < 0) { + plog(LLV_ERROR2, LOCATION, NULL, + "failed to initialize admin port"); + exit(1); + } +#endif +#ifdef ENABLE_VPNCONTROL_PORT + if (vpncontrol_init() < 0) { + plog(LLV_ERROR2, LOCATION, NULL, + "failed to initialize vpn control port"); + exit(1); + } +#endif + + init_signal(); + initfds(); + +#ifndef __APPLE__ +#ifdef ENABLE_NATT + natt_keepalive_init (); +#endif +#endif + + if (privsep_init() != 0) { + plog(LLV_ERROR2, LOCATION, NULL, + "failed to initialize privsep"); + exit(1); + } + + for (i = 0; i <= NSIG; i++) + sigreq[i] = 0; + + /* write .pid file */ + if (!f_foreground) { + racoon_pid = getpid(); + if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) + strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN); + else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') + strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + else { + strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN); + strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + } + fp = fopen(pid_file, "w"); + if (fp) { + if (fchmod(fileno(fp), + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { + syslog(LOG_ERR, "%s", strerror(errno)); + fclose(fp); + exit(1); + } + fprintf(fp, "%ld\n", (long)racoon_pid); + fclose(fp); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "cannot open %s", pid_file); + } + } + + while (1) { + update_fds = 0; + /* + * asynchronous requests via signal. + * make sure to reset sigreq to 0. + */ + check_sigreq(); + + /* scheduling */ + timeout = schedular(); + + if (dying) + rfds = maskdying; + else + rfds = mask0; + error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); + if (error < 0) { + switch (errno) { + case EINTR: + continue; + default: + plog(LLV_ERROR2, LOCATION, NULL, + "failed select (%s)\n", + strerror(errno)); + exit(1); + } + /*NOTREACHED*/ + } + +#ifdef ENABLE_ADMINPORT + if ((lcconf->sock_admin != -1) && + (FD_ISSET(lcconf->sock_admin, &rfds))) + admin_handler(); +#endif +#ifdef ENABLE_VPNCONTROL_PORT + { + struct vpnctl_socket_elem *elem; + struct vpnctl_socket_elem *t_elem; + + if ((lcconf->sock_vpncontrol != -1) && + (FD_ISSET(lcconf->sock_vpncontrol, &rfds))) { + vpncontrol_handler(); + update_fds = 1; // in case new socket created - update mask + } + /* The handler may close and remove the list element + * so we can't rely on it being valid after calling + * the handler. + */ + LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) { + if ((elem->sock != -1) && + (FD_ISSET(elem->sock, &rfds))) + if (vpncontrol_comm_handler(elem)) + update_fds = 1; // socket closed by peer - update mask + } + } +#endif + + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + if (FD_ISSET(p->sock, &rfds)) + if ((error = isakmp_handler(p->sock)) == -2) + break; + } + if (error == -2) { + if (lcconf->autograbaddr) { + /* serious socket problem - close all listening sockets and re-open */ + isakmp_close(); + initfds(); + sched_new(5, check_rtsock, NULL); + continue; + } else { + isakmp_close_sockets(); + isakmp_open(); + initfds(); + continue; + } + } + + if (FD_ISSET(lcconf->sock_pfkey, &rfds)) + pfkey_handler(); + + if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) { + if (update_myaddrs() && lcconf->autograbaddr) + if (check_rtsock_sched == NULL) /* only schedule if not already done */ + check_rtsock_sched = sched_new(5, check_rtsock, NULL); + // initfds(); //%%% BUG FIX - not needed here + } + if (update_fds) { + initfds(); + update_fds = 0; + } + } +} + + +/* clear all status and exit program. */ +static void +close_session() +{ + flushph1(); + close_sockets(); + backupsa_clean(); + + plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); + exit(0); +} + +static void +check_rtsock(p) + void *p; +{ + + check_rtsock_sched = NULL; + grab_myaddrs(); + isakmp_close_unused(); + + autoconf_myaddrsport(); + isakmp_open(); + + /* initialize socket list again */ + initfds(); +} + +static void +initfds() +{ + struct myaddrs *p; + + nfds = 0; + + FD_ZERO(&mask0); + FD_ZERO(&maskdying); + +#ifdef ENABLE_ADMINPORT + if (lcconf->sock_admin != -1) { + if (lcconf->sock_admin >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - admin socket\n"); + exit(1); + } + FD_SET(lcconf->sock_admin, &mask0); + /* XXX should we listen on admin socket when dying ? + */ +#if 0 + FD_SET(lcconf->sock_admin, &maskdying); +#endif + nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin); + } +#endif +#ifdef ENABLE_VPNCONTROL_PORT + { + struct vpnctl_socket_elem *elem; + + if (lcconf->sock_vpncontrol != -1) { + if (lcconf->sock_vpncontrol >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - vpncontrol socket\n"); + exit(1); + } + FD_SET(lcconf->sock_vpncontrol, &mask0); + nfds = (nfds > lcconf->sock_vpncontrol ? nfds : lcconf->sock_vpncontrol); + } + + LIST_FOREACH(elem, &lcconf->vpnctl_comm_socks, chain) { + if (elem->sock != -1) { + if (elem->sock >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun vpnctl_comm socket\n"); + exit(1); + } + FD_SET(elem->sock, &mask0); + nfds = (nfds > elem->sock ? nfds : elem->sock); + } + } + } + +#endif + + if (lcconf->sock_pfkey >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - pfkey socket\n"); + exit(1); + } + FD_SET(lcconf->sock_pfkey, &mask0); + FD_SET(lcconf->sock_pfkey, &maskdying); + nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey); + if (lcconf->rtsock >= 0) { + if (lcconf->rtsock >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - rt socket\n"); + exit(1); + } + FD_SET(lcconf->rtsock, &mask0); + nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock); + } + + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + if (p->sock < 0) + continue; + if (p->sock >= FD_SETSIZE) { + plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - isakmp socket\n"); + exit(1); + } + FD_SET(p->sock, &mask0); + nfds = (nfds > p->sock ? nfds : p->sock); + } + nfds++; +} + +static int signals[] = { + SIGHUP, + SIGINT, + SIGTERM, + SIGUSR1, + SIGUSR2, + SIGCHLD, + SIGPIPE, + 0 +}; + +/* + * asynchronous requests will actually dispatched in the + * main loop in session(). + */ +RETSIGTYPE +signal_handler(sig) + int sig; +{ + /* Do not just set it to 1, because we may miss some signals by just setting + * values to 0/1 + */ + sigreq[sig]++; +} + +static void +check_sigreq() +{ + int sig; + + /* + * XXX We are not able to tell if we got + * several time the same signal. This is + * not a problem for the current code, + * but we shall remember this limitation. + */ + for (sig = 0; sig <= NSIG; sig++) { + if (sigreq[sig] == 0) + continue; + + sigreq[sig]--; + switch(sig) { + case 0: + return; + + /* Catch up childs, mainly scripts. + */ + case SIGCHLD: + { + pid_t pid; + int s; + + pid = wait(&s); + } + break; + +#ifdef DEBUG_RECORD_MALLOCATION + /* + * XXX This operation is signal handler unsafe and may lead to + * crashes and security breaches: See Henning Brauer talk at + * EuroBSDCon 2005. Do not run in production with this option + * enabled. + */ + case SIGUSR2: + DRM_dump(); + break; +#endif + + case SIGHUP: + /* Save old configuration, load new one... */ + isakmp_close(); + close(lcconf->rtsock); + if (cfreparse()) { + plog(LLV_ERROR2, LOCATION, NULL, + "configuration read failed\n"); + exit(1); + } + if (lcconf->logfile_param == NULL) + plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); + + initmyaddr(); + isakmp_cleanup(); + isakmp_init(); + initfds(); + break; + + case SIGINT: + case SIGTERM: + plog(LLV_INFO, LOCATION, NULL, + "caught signal %d\n", sig); + EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); + pfkey_send_flush(lcconf->sock_pfkey, + SADB_SATYPE_UNSPEC); + sched_new(1, check_flushsa_stub, NULL); + dying = 1; + break; + + default: + plog(LLV_INFO, LOCATION, NULL, + "caught signal %d\n", sig); + break; + } + } +} + +/* + * waiting the termination of processing until sending DELETE message + * for all inbound SA will complete. + */ +static void +check_flushsa_stub(p) + void *p; +{ + + check_flushsa(); +} + +static void +check_flushsa() +{ + vchar_t *buf; + struct sadb_msg *msg, *end, *next; + struct sadb_sa *sa; + caddr_t mhp[SADB_EXT_MAX + 1]; + int n; + + buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb: returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + /* counting SA except of dead one. */ + n = 0; + while (msg < end) { + if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + if (!sa) { + msg = next; + continue; + } + + if (sa->sadb_sa_state != SADB_SASTATE_DEAD) { + n++; + msg = next; + continue; + } + + msg = next; + } + + if (buf != NULL) + vfree(buf); + + if (n) { + sched_new(1, check_flushsa_stub, NULL); + return; + } + + close_session(); +} + +void +auto_exit_do(void *p) +{ + EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); + pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); + sched_new(1, check_flushsa_stub, NULL); + dying = 1; +} + +void +check_auto_exit(void) +{ + + if (lcconf->auto_exit_sched != NULL) { /* exit scheduled? */ + if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED + || vpn_control_connected() /* vpn control connected */ + || policies_installed()) /* policies installed in kernel */ + SCHED_KILL(lcconf->auto_exit_sched); + } else { /* exit not scheduled */ + if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED + && !vpn_control_connected() + && !policies_installed()) + if (lcconf->auto_exit_delay == 0) + auto_exit_do(NULL); /* immediate exit */ + else + lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); + } +} + + +static void +init_signal() +{ + int i; + + for (i = 0; signals[i] != 0; i++) + if (set_signal(signals[i], signal_handler) < 0) { + plog(LLV_ERROR2, LOCATION, NULL, + "failed to set_signal (%s)\n", + strerror(errno)); + exit(1); + } +} + +static int +set_signal(sig, func) + int sig; + RETSIGTYPE (*func) __P((int)); +{ + struct sigaction sa; + + memset((caddr_t)&sa, 0, sizeof(sa)); + sa.sa_handler = func; + sa.sa_flags = SA_RESTART; + + if (sigemptyset(&sa.sa_mask) < 0) + return -1; + + if (sigaction(sig, &sa, (struct sigaction *)0) < 0) + return(-1); + + return 0; +} + +static int +close_sockets() +{ + isakmp_close(); + pfkey_close(lcconf->sock_pfkey); +#ifdef ENABLE_ADMINPORT + (void)admin_close(); +#endif +#ifdef ENABLE_VPNCONTROL_PORT + vpncontrol_close(); +#endif + return 0; +} + diff --git a/ipsec-tools/racoon/session.h b/ipsec-tools/racoon/session.h new file mode 100644 index 0000000..6625b0b --- /dev/null +++ b/ipsec-tools/racoon/session.h @@ -0,0 +1,39 @@ +/* $Id: session.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SESSION_H +#define _SESSION_H + +extern int session __P((void)); +extern RETSIGTYPE signal_handler __P((int)); +extern void check_auto_exit __P((void)); + +#endif /* _SESSION_H */ diff --git a/ipsec-tools/racoon/sockmisc.c b/ipsec-tools/racoon/sockmisc.c new file mode 100644 index 0000000..14399cc --- /dev/null +++ b/ipsec-tools/racoon/sockmisc.c @@ -0,0 +1,1105 @@ +/* $Id: sockmisc.c,v 1.17.4.4 2005/10/04 09:54:27 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + +#if defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR) +#define IPV6_RECVDSTADDR IP_RECVDSTADDR +#endif + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#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" */ +#endif + +const int niflags = 0; + +/* + * compare two sockaddr without port number. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrwop(addr1, addr2) + const struct sockaddr *addr1; + const struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + +#ifdef __linux__ + if (addr1->sa_family != addr2->sa_family) + return 1; +#else + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + +#endif /* __linux__ */ + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* + * compare two sockaddr with port, taking care wildcard. + * addr1 is a subject address, addr2 is in a database entry. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrwild(addr1, addr2) + const struct sockaddr *addr1; + const struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + u_short port1, port2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + +#ifdef __linux__ + if (addr1->sa_family != addr2->sa_family) + return 1; +#else + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + +#endif /* __linux__ */ + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + port1 = ((struct sockaddr_in *)addr1)->sin_port; + port2 = ((struct sockaddr_in *)addr2)->sin_port; + if (!(port1 == IPSEC_PORT_ANY || + port2 == IPSEC_PORT_ANY || + port1 == port2)) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + port1 = ((struct sockaddr_in6 *)addr1)->sin6_port; + port2 = ((struct sockaddr_in6 *)addr2)->sin6_port; + if (!(port1 == IPSEC_PORT_ANY || + port2 == IPSEC_PORT_ANY || + port1 == port2)) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* + * compare two sockaddr with strict match on port. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrstrict(addr1, addr2) + const struct sockaddr *addr1; + const struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + u_short port1, port2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + +#ifdef __linux__ + if (addr1->sa_family != addr2->sa_family) + return 1; +#else + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + +#endif /* __linux__ */ + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + port1 = ((struct sockaddr_in *)addr1)->sin_port; + port2 = ((struct sockaddr_in *)addr2)->sin_port; + if (port1 != port2) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + port1 = ((struct sockaddr_in6 *)addr1)->sin6_port; + port2 = ((struct sockaddr_in6 *)addr2)->sin6_port; + if (port1 != port2) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* get local address against the destination. */ +struct sockaddr * +getlocaladdr(remote) + struct sockaddr *remote; +{ + struct sockaddr *local; + u_int local_len = sizeof(struct sockaddr_storage); + int s; /* for dummy connection */ + + /* allocate buffer */ + if ((local = racoon_calloc(1, local_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get address buffer.\n"); + goto err; + } + + /* get real interface received packet */ + if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket (%s)\n", strerror(errno)); + goto err; + } + + setsockopt_bypass(s, remote->sa_family); + + if (connect(s, remote, sysdep_sa_len(remote)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "connect (%s)\n", strerror(errno)); + close(s); + goto err; + } + + if (getsockname(s, local, &local_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + close(s); + return NULL; + } + + close(s); + return local; + + err: + if (local != NULL) + racoon_free(local); + return NULL; +} + +/* + * Receive packet, with src/dst information. It is assumed that necessary + * setsockopt() have already performed on socket. + */ +int +recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) + int s; + void *buf; + size_t buflen; + int flags; + struct sockaddr *from; + socklen_t *fromlen; + struct sockaddr *to; + u_int *tolen; +{ + int otolen; + u_int len; + struct sockaddr_storage ss; + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[2]; + u_char cmsgbuf[256]; +#if defined(INET6) && defined(INET6_ADVAPI) + struct in6_pktinfo *pi; +#endif /*INET6_ADVAPI*/ + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + len = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + return -1; + } + + m.msg_name = (caddr_t)from; + m.msg_namelen = *fromlen; + iov[0].iov_base = (caddr_t)buf; + iov[0].iov_len = buflen; + m.msg_iov = iov; + m.msg_iovlen = 1; + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + m.msg_controllen = sizeof(cmsgbuf); + if ((len = recvmsg(s, &m, flags)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "recvmsg (%s)\n", strerror(errno)); + return -1; + } + *fromlen = m.msg_namelen; + + otolen = *tolen; + *tolen = 0; + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); + m.msg_controllen != 0 && cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { +#if 0 + plog(LLV_ERROR, LOCATION, NULL, + "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);) +#endif +#if defined(INET6) && defined(INET6_ADVAPI) + if (ss.ss_family == AF_INET6 + && cm->cmsg_level == IPPROTO_IPV6 + && cm->cmsg_type == IPV6_PKTINFO + && otolen >= sizeof(*sin6)) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + *tolen = sizeof(*sin6); + sin6 = (struct sockaddr_in6 *)to; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; +#ifndef __linux__ + sin6->sin6_len = sizeof(*sin6); +#endif + memcpy(&sin6->sin6_addr, &pi->ipi6_addr, + sizeof(sin6->sin6_addr)); + /* XXX other cases, such as site-local? */ + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = pi->ipi6_ifindex; + else + sin6->sin6_scope_id = 0; + sin6->sin6_port = + ((struct sockaddr_in6 *)&ss)->sin6_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif +#ifdef __linux__ + if (ss.ss_family == AF_INET + && cm->cmsg_level == IPPROTO_IP + && cm->cmsg_type == IP_PKTINFO + && otolen >= sizeof(sin)) { + struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm)); + *tolen = sizeof(*sin); + sin = (struct sockaddr_in *)to; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, &pi->ipi_addr, + sizeof(sin->sin_addr)); + sin->sin_port = + ((struct sockaddr_in *)&ss)->sin_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif +#if defined(INET6) && defined(IPV6_RECVDSTADDR) + if (ss.ss_family == AF_INET6 + && cm->cmsg_level == IPPROTO_IPV6 + && cm->cmsg_type == IPV6_RECVDSTADDR + && otolen >= sizeof(*sin6)) { + *tolen = sizeof(*sin6); + sin6 = (struct sockaddr_in6 *)to; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + memcpy(&sin6->sin6_addr, CMSG_DATA(cm), + sizeof(sin6->sin6_addr)); + sin6->sin6_port = + ((struct sockaddr_in6 *)&ss)->sin6_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif +#ifndef __linux__ + if (ss.ss_family == AF_INET + && cm->cmsg_level == IPPROTO_IP + && cm->cmsg_type == IP_RECVDSTADDR + && otolen >= sizeof(*sin)) { + *tolen = sizeof(*sin); + sin = (struct sockaddr_in *)to; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + memcpy(&sin->sin_addr, CMSG_DATA(cm), + sizeof(sin->sin_addr)); + sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif + } + + return len; +} + +/* send packet, with fixing src/dst address pair. */ +int +sendfromto(s, buf, buflen, src, dst, cnt) + int s, cnt; + const void *buf; + size_t buflen; + struct sockaddr *src; + struct sockaddr *dst; +{ + struct sockaddr_storage ss; + u_int len; + int i; + + if (src->sa_family != dst->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch\n"); + return -1; + } + + len = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "sockname %s\n", saddr2str((struct sockaddr *)&ss)); + plog(LLV_DEBUG, LOCATION, NULL, + "send packet from %s\n", saddr2str(src)); + plog(LLV_DEBUG, LOCATION, NULL, + "send packet to %s\n", saddr2str(dst)); + + if (src->sa_family != ss.ss_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch\n"); + return -1; + } + + switch (src->sa_family) { +#if defined(INET6) && defined(INET6_ADVAPI) +// XXX: This block wasn't compiled on Linux - does it work? + case AF_INET6: + { + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[2]; + u_char cmsgbuf[256]; + struct in6_pktinfo *pi; + int ifindex; + struct sockaddr_in6 src6, dst6; + + memcpy(&src6, src, sizeof(src6)); + memcpy(&dst6, dst, sizeof(dst6)); + + /* XXX take care of other cases, such as site-local */ + ifindex = 0; + if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr) + || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) { + ifindex = src6.sin6_scope_id; /*???*/ + } + + /* XXX some sanity check on dst6.sin6_scope_id */ + + /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */ + src6.sin6_flowinfo = dst6.sin6_flowinfo = 0; + + memset(&m, 0, sizeof(m)); + m.msg_name = (caddr_t)&dst6; + m.msg_namelen = sizeof(dst6); + iov[0].iov_base = (char *)buf; + iov[0].iov_len = buflen; + m.msg_iov = iov; + m.msg_iovlen = 1; + + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr)); + pi->ipi6_ifindex = ifindex; + + plog(LLV_DEBUG, LOCATION, NULL, + "src6 %s %d\n", + saddr2str((struct sockaddr *)&src6), + src6.sin6_scope_id); + plog(LLV_DEBUG, LOCATION, NULL, + "dst6 %s %d\n", + saddr2str((struct sockaddr *)&dst6), + dst6.sin6_scope_id); + + for (i = 0; i < cnt; i++) { + len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "sendmsg (%s)\n", strerror(errno)); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d times of %d bytes message will be sent " + "to %s\n", + i + 1, len, saddr2str(dst)); + } + plogdump(LLV_DEBUG, (char *)buf, buflen); + + return len; + } +#endif +#ifdef __linux__ + case AF_INET: + { + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[2]; + u_char cmsgbuf[256]; + struct in_pktinfo *pi; + int ifindex = 0; + struct sockaddr_in src6, dst6; + + memcpy(&src6, src, sizeof(src6)); + memcpy(&dst6, dst, sizeof(dst6)); + + memset(&m, 0, sizeof(m)); + m.msg_name = (caddr_t)&dst6; + m.msg_namelen = sizeof(dst6); + iov[0].iov_base = (char *)buf; + iov[0].iov_len = buflen; + m.msg_iov = iov; + m.msg_iovlen = 1; + + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + + cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + cm->cmsg_level = IPPROTO_IP; + cm->cmsg_type = IP_PKTINFO; + pi = (struct in_pktinfo *)CMSG_DATA(cm); + memcpy(&pi->ipi_spec_dst, &src6.sin_addr, sizeof(src6.sin_addr)); + pi->ipi_ifindex = ifindex; + + plog(LLV_DEBUG, LOCATION, NULL, + "src4 %s\n", + saddr2str((struct sockaddr *)&src6)); + plog(LLV_DEBUG, LOCATION, NULL, + "dst4 %s\n", + saddr2str((struct sockaddr *)&dst6)); + + for (i = 0; i < cnt; i++) { + len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "sendmsg (%s)\n", strerror(errno)); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d times of %d bytes message will be sent " + "to %s\n", + i + 1, len, saddr2str(dst)); + } + plogdump(LLV_DEBUG, (char *)buf, buflen); + + return len; + } +#endif /* __linux__ */ + default: + { + int needclose = 0; + int sendsock; + + if (ss.ss_family == src->sa_family && memcmp(&ss, src, sysdep_sa_len(src)) == 0) { + sendsock = s; + needclose = 0; + } else { + int yes = 1; + /* + * Use newly opened socket for sending packets. + * NOTE: this is unsafe, because if the peer is quick enough + * the packet from the peer may be queued into sendsock. + * Better approach is to prepare bind'ed udp sockets for + * each of the interface addresses. + */ + sendsock = socket(src->sa_family, SOCK_DGRAM, 0); + if (sendsock < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket (%s)\n", strerror(errno)); + return -1; + } + if (setsockopt(sendsock, SOL_SOCKET, +#ifdef __linux__ + SO_REUSEADDR, +#else + SO_REUSEPORT, +#endif + (void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + close(sendsock); + return -1; + } +#ifdef IPV6_USE_MIN_MTU + if (src->sa_family == AF_INET6 && + setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + close(sendsock); + return -1; + } +#endif + if (setsockopt_bypass(sendsock, src->sa_family) < 0) { + close(sendsock); + return -1; + } + + if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind 1 (%s)\n", strerror(errno)); + close(sendsock); + return -1; + } + needclose = 1; + } + + for (i = 0; i < cnt; i++) { + len = sendto(sendsock, buf, buflen, 0, dst, sysdep_sa_len(dst)); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "sendto (%s)\n", strerror(errno)); + if (needclose) + close(sendsock); + return len; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d times of %d bytes message will be sent " + "to %s\n", + i + 1, len, saddr2str(dst)); + } + plogdump(LLV_DEBUG, (char *)buf, buflen); + + if (needclose) + close(sendsock); + + return len; + } + } +} + +int +setsockopt_bypass(so, family) + int so, family; +{ + int level; + char *buf; + char *policy; + + switch (family) { + case AF_INET: + level = IPPROTO_IP; + break; +#ifdef INET6 + case AF_INET6: + level = IPPROTO_IPV6; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported address family %d\n", family); + return -1; + } + + policy = "in bypass"; + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "ipsec_set_policy (%s)\n", + ipsec_strerror()); + return -1; + } + if (setsockopt(so, level, + (level == IPPROTO_IP ? + IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), + buf, ipsec_get_policylen(buf)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", + strerror(errno)); + return -1; + } + racoon_free(buf); + + policy = "out bypass"; + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "ipsec_set_policy (%s)\n", + ipsec_strerror()); + return -1; + } + if (setsockopt(so, level, + (level == IPPROTO_IP ? + IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), + buf, ipsec_get_policylen(buf)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", + strerror(errno)); + return -1; + } + racoon_free(buf); + + return 0; +} + +struct sockaddr * +newsaddr(len) + int len; +{ + struct sockaddr *new; + + new = racoon_calloc(1, len); + if (new == NULL) + plog(LLV_ERROR, LOCATION, NULL, + "%s\n", strerror(errno)); + +#ifdef __linux__ + if (len == sizeof (struct sockaddr_in6)) + new->sa_family = AF_INET6; + else + new->sa_family = AF_INET; +#else + /* initial */ + new->sa_len = len; +#endif + + return new; +} + +struct sockaddr * +dupsaddr(src) + struct sockaddr *src; +{ + struct sockaddr *dst; + + dst = racoon_calloc(1, sysdep_sa_len(src)); + if (dst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "%s\n", strerror(errno)); + return NULL; + } + + memcpy(dst, src, sysdep_sa_len(src)); + + return dst; +} + +char * +saddr2str(saddr) + const struct sockaddr *saddr; +{ + static char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + if (saddr == NULL) + return NULL; + + if (saddr->sa_family == AF_UNSPEC) + snprintf (buf, sizeof(buf), "%s", "anonymous"); + else { + GETNAMEINFO(saddr, addr, port); + snprintf(buf, sizeof(buf), "%s[%s]", addr, port); + } + + return buf; +} + +char * +saddrwop2str(saddr) + const struct sockaddr *saddr; +{ + static char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST]; + + if (saddr == NULL) + return NULL; + + GETNAMEINFO_NULL(saddr, addr); + snprintf(buf, sizeof(buf), "%s", addr); + + return buf; +} + +char * +naddrwop2str(const struct netaddr *naddr) +{ + static char buf[NI_MAXHOST + 10]; + static const struct sockaddr sa_any; /* this is initialized to all zeros */ + + if (naddr == NULL) + return NULL; + + if (memcmp(&naddr->sa, &sa_any, sizeof(sa_any)) == 0) + snprintf(buf, sizeof(buf), "%s", "any"); + else { + snprintf(buf, sizeof(buf), "%s", saddrwop2str(&naddr->sa.sa)); + snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "/%ld", naddr->prefix); + } + return buf; +} + +char * +naddrwop2str_fromto(const char *format, const struct netaddr *saddr, + const struct netaddr *daddr) +{ + static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100]; + char *src, *dst; + + src = strdup(naddrwop2str(saddr)); + dst = strdup(naddrwop2str(daddr)); + /* WARNING: Be careful about the format string! Don't + ever pass in something that a user can modify!!! */ + snprintf (buf, sizeof(buf), format, src, dst); + racoon_free (src); + racoon_free (dst); + + return buf; +} + +char * +saddr2str_fromto(format, saddr, daddr) + const char *format; + const struct sockaddr *saddr; + const struct sockaddr *daddr; +{ + static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100]; + char *src, *dst; + + src = strdup(saddr2str(saddr)); + dst = strdup(saddr2str(daddr)); + /* WARNING: Be careful about the format string! Don't + ever pass in something that a user can modify!!! */ + snprintf (buf, sizeof(buf), format, src, dst); + racoon_free (src); + racoon_free (dst); + + return buf; +} + +struct sockaddr * +str2saddr(host, port) + char *host; + char *port; +{ + struct addrinfo hints, *res; + struct sockaddr *saddr; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(host, port, &hints, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getaddrinfo(%s%s%s): %s\n", + host, port ? "," : "", port ? port : "", + gai_strerror(error)); + return NULL; + } + if (res->ai_next != NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "getaddrinfo(%s%s%s): " + "resolved to multiple address, " + "taking the first one\n", + host, port ? "," : "", port ? port : ""); + } + saddr = racoon_malloc(res->ai_addrlen); + if (saddr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + freeaddrinfo(res); + return NULL; + } + memcpy(saddr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + + return saddr; +} + +void +mask_sockaddr(a, b, l) + struct sockaddr *a; + const struct sockaddr *b; + size_t l; +{ + size_t i; + u_int8_t *p, alen; + + switch (b->sa_family) { + case AF_INET: + alen = sizeof(struct in_addr); + p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + alen = sizeof(struct in6_addr); + p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR2, LOCATION, NULL, + "invalid address family: %d\n", b->sa_family); + exit(1); + } + + if ((alen << 3) < l) { + plog(LLV_ERROR2, LOCATION, NULL, + "unexpected inconsistency: %d %zu\n", b->sa_family, l); + exit(1); + } + + memcpy(a, b, sysdep_sa_len(b)); + p[l / 8] &= (0xff00 >> (l % 8)) & 0xff; + for (i = l / 8 + 1; i < alen; i++) + p[i] = 0x00; +} + +/* Compute a score describing how "accurate" a netaddr is for a given sockaddr. + * Examples: + * Return values for address 10.20.30.40 [port 500] and given netaddresses... + * 10.10.0.0/16 => -1 ... doesn't match + * 0.0.0.0/0 => 0 ... matches, but only 0 bits. + * 10.20.0.0/16 => 16 ... 16 bits match + * 10.20.30.0/24 => 24 ... guess what ;-) + * 10.20.30.40/32 => 32 ... whole address match + * 10.20.30.40:500 => 33 ... both address and port match + * 10.20.30.40:501 => -1 ... port doesn't match and isn't 0 (=any) + */ +int +naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr) +{ + static const struct netaddr naddr_any; /* initialized to all-zeros */ + struct sockaddr sa; + uint16_t naddr_port, saddr_port; + int port_score; + + if (!naddr || !saddr) { + plog(LLV_ERROR, LOCATION, NULL, + "Call with null args: naddr=%p, saddr=%p\n", + naddr, saddr); + return -1; + } + + /* Wildcard address matches, but only 0 bits. */ + if (memcmp(naddr, &naddr_any, sizeof(naddr_any)) == 0) + return 0; + + /* If families don't match we really can't do much... */ + if (naddr->sa.sa.sa_family != saddr->sa_family) + return -1; + + /* If port check fail don't bother to check addresses. */ + naddr_port = extract_port(&naddr->sa.sa); + saddr_port = extract_port(saddr); + if (naddr_port == 0 || saddr_port == 0) /* wildcard match */ + port_score = 0; + else if (naddr_port == saddr_port) /* exact match */ + port_score = 1; + else /* mismatch :-) */ + return -1; + + /* Here it comes - compare network addresses. */ + mask_sockaddr(&sa, saddr, naddr->prefix); + if (loglevel >= LLV_DEBUG) { /* debug only */ + char *a1, *a2, *a3; + a1 = strdup(naddrwop2str(naddr)); + a2 = strdup(saddrwop2str(saddr)); + a3 = strdup(saddrwop2str(&sa)); + plog(LLV_DEBUG, LOCATION, NULL, + "naddr=%s, saddr=%s (masked=%s)\n", + a1, a2, a3); + free(a1); + free(a2); + free(a3); + } + if (cmpsaddrwop(&sa, &naddr->sa.sa) == 0) + return naddr->prefix + port_score; + + return -1; +} + +/* Some usefull functions for sockaddr port manipulations. */ +u_int16_t +extract_port (const struct sockaddr *addr) +{ + u_int16_t port = -1; + + if (!addr) + return port; + + switch (addr->sa_family) { + case AF_INET: + port = ((struct sockaddr_in *)addr)->sin_port; + break; + case AF_INET6: + port = ((struct sockaddr_in6 *)addr)->sin6_port; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family); + break; + } + + return ntohs(port); +} + +u_int16_t * +get_port_ptr (struct sockaddr *addr) +{ + u_int16_t *port_ptr; + + if (!addr) + return NULL; + + switch (addr->sa_family) { + case AF_INET: + port_ptr = &(((struct sockaddr_in *)addr)->sin_port); + break; + case AF_INET6: + port_ptr = &(((struct sockaddr_in6 *)addr)->sin6_port); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family); + return NULL; + break; + } + + return port_ptr; +} + +u_int16_t * +set_port (struct sockaddr *addr, u_int16_t new_port) +{ + u_int16_t *port_ptr; + + port_ptr = get_port_ptr (addr); + + if (port_ptr) + *port_ptr = htons(new_port); + + return port_ptr; +} diff --git a/ipsec-tools/racoon/sockmisc.h b/ipsec-tools/racoon/sockmisc.h new file mode 100644 index 0000000..828c0b4 --- /dev/null +++ b/ipsec-tools/racoon/sockmisc.h @@ -0,0 +1,87 @@ +/* $Id: sockmisc.h,v 1.5.10.4 2005/10/04 09:54:27 manubsd Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SOCKMISC_H +#define _SOCKMISC_H + +struct netaddr { + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + unsigned long prefix; +}; + +extern const int niflags; + +extern int cmpsaddrwop __P((const struct sockaddr *, const struct sockaddr *)); +extern int cmpsaddrwild __P((const struct sockaddr *, const struct sockaddr *)); +extern int cmpsaddrstrict __P((const struct sockaddr *, const struct sockaddr *)); + +#ifdef ENABLE_NATT +#define CMPSADDR(saddr1, saddr2) cmpsaddrstrict((saddr1), (saddr2)) +#else +#define CMPSADDR(saddr1, saddr2) cmpsaddrwop((saddr1), (saddr2)) +#endif + +extern struct sockaddr *getlocaladdr __P((struct sockaddr *)); + +extern int recvfromto __P((int, void *, size_t, int, + struct sockaddr *, socklen_t *, struct sockaddr *, unsigned int *)); +extern int sendfromto __P((int, const void *, size_t, + struct sockaddr *, struct sockaddr *, int)); + +extern int setsockopt_bypass __P((int, int)); + +extern struct sockaddr *newsaddr __P((int)); +extern struct sockaddr *dupsaddr __P((struct sockaddr *)); +extern char *saddr2str __P((const struct sockaddr *)); +extern char *saddrwop2str __P((const struct sockaddr *)); +extern char *saddr2str_fromto __P((const char *format, + const struct sockaddr *saddr, + const struct sockaddr *daddr)); +extern struct sockaddr *str2saddr __P((char *, char *)); +extern void mask_sockaddr __P((struct sockaddr *, const struct sockaddr *, + size_t)); + +/* struct netaddr functions */ +extern char *naddrwop2str __P((const struct netaddr *naddr)); +extern char *naddrwop2str_fromto __P((const char *format, const struct netaddr *saddr, + const struct netaddr *daddr)); +extern int naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr); + +/* Some usefull functions for sockaddr port manipulations. */ +extern u_int16_t extract_port __P((const struct sockaddr *addr)); +extern u_int16_t *set_port __P((struct sockaddr *addr, u_int16_t new_port)); +extern u_int16_t *get_port_ptr __P((struct sockaddr *addr)); + +#endif /* _SOCKMISC_H */ diff --git a/ipsec-tools/racoon/stats.pl b/ipsec-tools/racoon/stats.pl new file mode 100644 index 0000000..f509512 --- /dev/null +++ b/ipsec-tools/racoon/stats.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# usage: +# % cat /var/log/racoon-stats.log | perl stats.pl + +while() { + chomp; + ($a, $a, $a, $a, $a, $b) = split(/\s+/, $_, 6); + ($a, $c) = split(/:/, $b, 2); + $r{$a} += $c; + $t{$a}++; +} + +foreach (sort keys %t) { + printf "%s: total=%d avg=%8.6f\n", $_, $t{$_}, $r{$_}/$t{$_}; +} diff --git a/ipsec-tools/racoon/str2val.c b/ipsec-tools/racoon/str2val.c new file mode 100644 index 0000000..9a38ee3 --- /dev/null +++ b/ipsec-tools/racoon/str2val.c @@ -0,0 +1,124 @@ +/* $KAME: str2val.c,v 1.11 2001/08/16 14:37:29 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include "str2val.h" +#include "gcmalloc.h" + +/* + * exchange a value to a hex string. + * must free buffer allocated later. + */ +caddr_t +val2str(buf, mlen) + const char *buf; + size_t mlen; +{ + caddr_t new; + size_t len = (mlen * 2) + mlen / 8 + 10; + size_t i, j; + + if ((new = racoon_malloc(len)) == 0) return(0); + + for (i = 0, j = 0; i < mlen; i++) { + snprintf(&new[j], len - j, "%02x", (u_char)buf[i]); + j += 2; + if (i % 8 == 7) { + new[j++] = ' '; + new[j] = '\0'; + } + } + new[j] = '\0'; + + return(new); +} + +/* + * exchange a string based "base" to a value. + */ +char * +str2val(str, base, len) + const char *str; + int base; + size_t *len; +{ + int f; + size_t i; + char *dst; + char *rp; + const char *p; + char b[3]; + + i = 0; + for (p = str; *p != '\0'; p++) { + if (isxdigit((int)*p)) + i++; + else if (isspace((int)*p)) + ; + else + return NULL; + } + if (i == 0 || (i % 2) != 0) + return NULL; + i /= 2; + + if ((dst = racoon_malloc(i)) == NULL) + return NULL; + + i = 0; + f = 0; + for (rp = dst, p = str; *p != '\0'; p++) { + if (isxdigit((int)*p)) { + if (!f) { + b[0] = *p; + f = 1; + } else { + b[1] = *p; + b[2] = '\0'; + *rp++ = (char)strtol(b, NULL, base); + i++; + f = 0; + } + } + } + + *len = i; + + return(dst); +} diff --git a/ipsec-tools/racoon/str2val.h b/ipsec-tools/racoon/str2val.h new file mode 100644 index 0000000..4c286cc --- /dev/null +++ b/ipsec-tools/racoon/str2val.h @@ -0,0 +1,38 @@ +/* $Id: str2val.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STR2VAL_H +#define _STR2VAL_H + +extern caddr_t val2str __P((const char *, size_t)); +extern char *str2val __P((const char *, int, size_t *)); + +#endif /* _STR2VAL_H */ diff --git a/ipsec-tools/racoon/strnames.c b/ipsec-tools/racoon/strnames.c new file mode 100644 index 0000000..34562ee --- /dev/null +++ b/ipsec-tools/racoon/strnames.c @@ -0,0 +1,942 @@ +/* $KAME: strnames.c,v 1.25 2003/11/13 10:53:26 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include + +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif +#include + +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "handler.h" +#include "pfkey.h" +#include "strnames.h" +#include "algorithm.h" + +struct ksmap { + int key; + char *str; + char *(*f) __P((int)); +}; + +char * +num2str(n) + int n; +{ + static char buf[20]; + + snprintf(buf, sizeof(buf), "%d", n); + + return buf; +} + +/* isakmp.h */ +char * +s_isakmp_state(t, d, s) + int t, d, s; +{ + switch (t) { + case ISAKMP_ETYPE_AGG: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "agg I msg1"; + case PHASE1ST_ESTABLISHED: + return "agg I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "agg R msg1"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_BASE: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "base I msg1"; + case PHASE1ST_MSG2SENT: + return "base I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "base R msg1"; + case PHASE1ST_ESTABLISHED: + return "base R msg2"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_IDENT: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "ident I msg1"; + case PHASE1ST_MSG2SENT: + return "ident I msg2"; + case PHASE1ST_MSG3SENT: + return "ident I msg3"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "ident R msg1"; + case PHASE1ST_MSG2SENT: + return "ident R msg2"; + case PHASE1ST_ESTABLISHED: + return "ident R msg3"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_QUICK: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE2ST_MSG1SENT: + return "quick I msg1"; + case PHASE2ST_ADDSA: + return "quick I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE2ST_MSG1SENT: + return "quick R msg1"; + case PHASE2ST_COMMIT: + return "quick R msg2"; + default: + break; + } + } + break; + default: + case ISAKMP_ETYPE_NONE: + case ISAKMP_ETYPE_AUTH: + case ISAKMP_ETYPE_INFO: + case ISAKMP_ETYPE_NEWGRP: + case ISAKMP_ETYPE_ACKINFO: + break; + } + /*NOTREACHED*/ + + return "???"; +} + +static struct ksmap name_isakmp_certtype[] = { +{ ISAKMP_CERT_NONE, "NONE", NULL }, +{ ISAKMP_CERT_PKCS7, "PKCS #7 wrapped X.509 certificate", NULL }, +{ ISAKMP_CERT_PGP, "PGP Certificate", NULL }, +{ ISAKMP_CERT_DNS, "DNS Signed Key", NULL }, +{ ISAKMP_CERT_X509SIGN, "X.509 Certificate Signature", NULL }, +{ ISAKMP_CERT_X509KE, "X.509 Certificate Key Exchange", NULL }, +{ ISAKMP_CERT_KERBEROS, "Kerberos Tokens", NULL }, +{ ISAKMP_CERT_CRL, "Certificate Revocation List (CRL)", NULL }, +{ ISAKMP_CERT_ARL, "Authority Revocation List (ARL)", NULL }, +{ ISAKMP_CERT_SPKI, "SPKI Certificate", NULL }, +{ ISAKMP_CERT_X509ATTR, "X.509 Certificate Attribute", NULL }, +}; + +char * +s_isakmp_certtype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_certtype); i++) + if (name_isakmp_certtype[i].key == k) + return name_isakmp_certtype[i].str; + return num2str(k); +} + +static struct ksmap name_isakmp_etype[] = { +{ ISAKMP_ETYPE_NONE, "None", NULL }, +{ ISAKMP_ETYPE_BASE, "Base", NULL }, +{ ISAKMP_ETYPE_IDENT, "Identity Protection", NULL }, +{ ISAKMP_ETYPE_AUTH, "Authentication Only", NULL }, +{ ISAKMP_ETYPE_AGG, "Aggressive", NULL }, +{ ISAKMP_ETYPE_INFO, "Informational", NULL }, +{ ISAKMP_ETYPE_QUICK, "Quick", NULL }, +{ ISAKMP_ETYPE_NEWGRP, "New Group", NULL }, +{ ISAKMP_ETYPE_ACKINFO, "Acknowledged Informational", NULL }, +}; + +char * +s_isakmp_etype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_etype); i++) + if (name_isakmp_etype[i].key == k) + return name_isakmp_etype[i].str; + return num2str(k); +} + +static struct ksmap name_isakmp_notify_msg[] = { +{ ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, "INVALID-PAYLOAD-TYPE", NULL }, +{ ISAKMP_NTYPE_DOI_NOT_SUPPORTED, "DOI-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED, "SITUATION-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_INVALID_COOKIE, "INVALID-COOKIE", NULL }, +{ ISAKMP_NTYPE_INVALID_MAJOR_VERSION, "INVALID-MAJOR-VERSION", NULL }, +{ ISAKMP_NTYPE_INVALID_MINOR_VERSION, "INVALID-MINOR-VERSION", NULL }, +{ ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, "INVALID-EXCHANGE-TYPE", NULL }, +{ ISAKMP_NTYPE_INVALID_FLAGS, "INVALID-FLAGS", NULL }, +{ ISAKMP_NTYPE_INVALID_MESSAGE_ID, "INVALID-MESSAGE-ID", NULL }, +{ ISAKMP_NTYPE_INVALID_PROTOCOL_ID, "INVALID-PROTOCOL-ID", NULL }, +{ ISAKMP_NTYPE_INVALID_SPI, "INVALID-SPI", NULL }, +{ ISAKMP_NTYPE_INVALID_TRANSFORM_ID, "INVALID-TRANSFORM-ID", NULL }, +{ ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN, "NO-PROPOSAL-CHOSEN", NULL }, +{ ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX, "BAD-PROPOSAL-SYNTAX", NULL }, +{ ISAKMP_NTYPE_PAYLOAD_MALFORMED, "PAYLOAD-MALFORMED", NULL }, +{ ISAKMP_NTYPE_INVALID_KEY_INFORMATION, "INVALID-KEY-INFORMATION", NULL }, +{ ISAKMP_NTYPE_INVALID_ID_INFORMATION, "INVALID-ID-INFORMATION", NULL }, +{ ISAKMP_NTYPE_INVALID_CERT_ENCODING, "INVALID-CERT-ENCODING", NULL }, +{ ISAKMP_NTYPE_INVALID_CERTIFICATE, "INVALID-CERTIFICATE", NULL }, +{ ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX, "BAD-CERT-REQUEST-SYNTAX", NULL }, +{ ISAKMP_NTYPE_INVALID_CERT_AUTHORITY, "INVALID-CERT-AUTHORITY", NULL }, +{ ISAKMP_NTYPE_INVALID_HASH_INFORMATION, "INVALID-HASH-INFORMATION", NULL }, +{ ISAKMP_NTYPE_AUTHENTICATION_FAILED, "AUTHENTICATION-FAILED", NULL }, +{ ISAKMP_NTYPE_INVALID_SIGNATURE, "INVALID-SIGNATURE", NULL }, +{ ISAKMP_NTYPE_ADDRESS_NOTIFICATION, "ADDRESS-NOTIFICATION", NULL }, +{ ISAKMP_NTYPE_NOTIFY_SA_LIFETIME, "NOTIFY-SA-LIFETIME", NULL }, +{ ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE, "CERTIFICATE-UNAVAILABLE", NULL }, +{ ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED-EXCHANGE-TYPE", NULL }, +{ ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL-PAYLOAD-LENGTHS", NULL }, +{ ISAKMP_NTYPE_CONNECTED, "CONNECTED", NULL }, +{ ISAKMP_NTYPE_RESPONDER_LIFETIME, "RESPONDER-LIFETIME", NULL }, +{ ISAKMP_NTYPE_REPLAY_STATUS, "REPLAY-STATUS", NULL }, +{ ISAKMP_NTYPE_INITIAL_CONTACT, "INITIAL-CONTACT", NULL }, +{ ISAKMP_LOG_RETRY_LIMIT_REACHED, "RETRY-LIMIT-REACHED", NULL }, +}; + +char * +s_isakmp_notify_msg(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_notify_msg); i++) + if (name_isakmp_notify_msg[i].key == k) + return name_isakmp_notify_msg[i].str; + + return num2str(k); +} + +static struct ksmap name_isakmp_nptype[] = { +{ ISAKMP_NPTYPE_NONE, "none", NULL }, +{ ISAKMP_NPTYPE_SA, "sa", NULL }, +{ ISAKMP_NPTYPE_P, "prop", NULL }, +{ ISAKMP_NPTYPE_T, "trns", NULL }, +{ ISAKMP_NPTYPE_KE, "ke", NULL }, +{ ISAKMP_NPTYPE_ID, "id", NULL }, +{ ISAKMP_NPTYPE_CERT, "cert", NULL }, +{ ISAKMP_NPTYPE_CR, "cr", NULL }, +{ ISAKMP_NPTYPE_HASH, "hash", NULL }, +{ ISAKMP_NPTYPE_SIG, "sig", NULL }, +{ ISAKMP_NPTYPE_NONCE, "nonce", NULL }, +{ ISAKMP_NPTYPE_N, "notify", NULL }, +{ ISAKMP_NPTYPE_D, "delete", NULL }, +{ ISAKMP_NPTYPE_VID, "vid", NULL }, +{ ISAKMP_NPTYPE_GSS, "gss id", NULL }, +{ ISAKMP_NPTYPE_NATD_RFC, "nat-d", NULL }, +{ ISAKMP_NPTYPE_NATOA_RFC, "nat-oa", NULL }, +{ ISAKMP_NPTYPE_NATD_DRAFT, "nat-d", NULL }, +{ ISAKMP_NPTYPE_NATOA_DRAFT, "nat-oa", NULL }, +{ ISAKMP_NPTYPE_NATD_BADDRAFT, "nat-d", NULL }, +{ ISAKMP_NPTYPE_NATOA_BADDRAFT, "nat-oa", NULL } +}; + +char * +s_isakmp_nptype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_nptype); i++) + if (name_isakmp_nptype[i].key == k) + return name_isakmp_nptype[i].str; + return num2str(k); +} + +/* ipsec_doi.h */ +static struct ksmap name_ipsecdoi_proto[] = { +{ IPSECDOI_PROTO_ISAKMP, "ISAKMP", s_ipsecdoi_trns_isakmp }, +{ IPSECDOI_PROTO_IPSEC_AH, "AH", s_ipsecdoi_trns_ah }, +{ IPSECDOI_PROTO_IPSEC_ESP, "ESP", s_ipsecdoi_trns_esp }, +{ IPSECDOI_PROTO_IPCOMP, "IPCOMP", s_ipsecdoi_trns_ipcomp }, +}; + +char * +s_ipsecdoi_proto(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++) + if (name_ipsecdoi_proto[i].key == k) + return name_ipsecdoi_proto[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_isakmp[] = { +{ IPSECDOI_KEY_IKE, "IKE", NULL }, +}; + +char * +s_ipsecdoi_trns_isakmp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_isakmp); i++) + if (name_ipsecdoi_trns_isakmp[i].key == k) + return name_ipsecdoi_trns_isakmp[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_ah[] = { +{ IPSECDOI_AH_MD5, "MD5", NULL }, +{ IPSECDOI_AH_SHA, "SHA", NULL }, +{ IPSECDOI_AH_DES, "DES", NULL }, +{ IPSECDOI_AH_SHA256, "SHA256", NULL }, +{ IPSECDOI_AH_SHA384, "SHA384", NULL }, +{ IPSECDOI_AH_SHA512, "SHA512", NULL }, +}; + +char * +s_ipsecdoi_trns_ah(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ah); i++) + if (name_ipsecdoi_trns_ah[i].key == k) + return name_ipsecdoi_trns_ah[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_esp[] = { +{ IPSECDOI_ESP_DES_IV64, "DES_IV64", NULL }, +{ IPSECDOI_ESP_DES, "DES", NULL }, +{ IPSECDOI_ESP_3DES, "3DES", NULL }, +{ IPSECDOI_ESP_RC5, "RC5", NULL }, +{ IPSECDOI_ESP_IDEA, "IDEA", NULL }, +{ IPSECDOI_ESP_CAST, "CAST", NULL }, +{ IPSECDOI_ESP_BLOWFISH, "BLOWFISH", NULL }, +{ IPSECDOI_ESP_3IDEA, "3IDEA", NULL }, +{ IPSECDOI_ESP_DES_IV32, "DES_IV32", NULL }, +{ IPSECDOI_ESP_RC4, "RC4", NULL }, +{ IPSECDOI_ESP_NULL, "NULL", NULL }, +{ IPSECDOI_ESP_AES, "AES", NULL }, +{ IPSECDOI_ESP_TWOFISH, "TWOFISH", NULL }, +}; + +char * +s_ipsecdoi_trns_esp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_esp); i++) + if (name_ipsecdoi_trns_esp[i].key == k) + return name_ipsecdoi_trns_esp[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_ipcomp[] = { +{ IPSECDOI_IPCOMP_OUI, "OUI", NULL}, +{ IPSECDOI_IPCOMP_DEFLATE, "DEFLATE", NULL}, +{ IPSECDOI_IPCOMP_LZS, "LZS", NULL}, +}; + +char * +s_ipsecdoi_trns_ipcomp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ipcomp); i++) + if (name_ipsecdoi_trns_ipcomp[i].key == k) + return name_ipsecdoi_trns_ipcomp[i].str; + return num2str(k); +} + +char * +s_ipsecdoi_trns(proto, trns) + int proto, trns; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++) + if (name_ipsecdoi_proto[i].key == proto + && name_ipsecdoi_proto[i].f) + return (name_ipsecdoi_proto[i].f)(trns); + return num2str(trns); +} + +static struct ksmap name_attr_ipsec[] = { +{ IPSECDOI_ATTR_SA_LD_TYPE, "SA Life Type", s_ipsecdoi_ltype }, +{ IPSECDOI_ATTR_SA_LD, "SA Life Duration", NULL }, +{ IPSECDOI_ATTR_GRP_DESC, "Group Description", NULL }, +{ IPSECDOI_ATTR_ENC_MODE, "Encryption Mode", s_ipsecdoi_encmode }, +{ IPSECDOI_ATTR_AUTH, "Authentication Algorithm", s_ipsecdoi_auth }, +{ IPSECDOI_ATTR_KEY_LENGTH, "Key Length", NULL }, +{ IPSECDOI_ATTR_KEY_ROUNDS, "Key Rounds", NULL }, +{ IPSECDOI_ATTR_COMP_DICT_SIZE, "Compression Dictionary Size", NULL }, +{ IPSECDOI_ATTR_COMP_PRIVALG, "Compression Private Algorithm", NULL }, +}; + +char * +s_ipsecdoi_attr(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec); i++) + if (name_attr_ipsec[i].key == k) + return name_attr_ipsec[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_ltype[] = { +{ IPSECDOI_ATTR_SA_LD_TYPE_SEC, "seconds", NULL }, +{ IPSECDOI_ATTR_SA_LD_TYPE_KB, "kilobytes", NULL }, +}; + +char * +s_ipsecdoi_ltype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_ltype); i++) + if (name_attr_ipsec_ltype[i].key == k) + return name_attr_ipsec_ltype[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_encmode[] = { +{ IPSECDOI_ATTR_ENC_MODE_ANY, "Any", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_TUNNEL, "Tunnel", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_TRNS, "Transport", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC, "UDP-Tunnel", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC, "UDP-Transport", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT, "UDP-Tunnel", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT, "UDP-Transport", NULL }, +}; + +char * +s_ipsecdoi_encmode(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_encmode); i++) + if (name_attr_ipsec_encmode[i].key == k) + return name_attr_ipsec_encmode[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_auth[] = { +{ IPSECDOI_ATTR_AUTH_HMAC_MD5, "hmac-md5", NULL }, +{ IPSECDOI_ATTR_AUTH_HMAC_SHA1, "hmac-sha", NULL }, +{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_256, "hmac-sha256", NULL }, +{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_384, "hmac-sha384", NULL }, +{ IPSECDOI_ATTR_AUTH_HMAC_SHA2_512, "hmac-sha512", NULL }, +{ IPSECDOI_ATTR_AUTH_DES_MAC, "des-mac", NULL }, +{ IPSECDOI_ATTR_AUTH_KPDK, "kpdk", NULL }, +}; + +char * +s_ipsecdoi_auth(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_auth); i++) + if (name_attr_ipsec_auth[i].key == k) + return name_attr_ipsec_auth[i].str; + return num2str(k); +} + +char * +s_ipsecdoi_attr_v(type, val) + int type, val; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec); i++) + if (name_attr_ipsec[i].key == type + && name_attr_ipsec[i].f) + return (name_attr_ipsec[i].f)(val); + return num2str(val); +} + +static struct ksmap name_ipsecdoi_ident[] = { +{ IPSECDOI_ID_IPV4_ADDR, "IPv4_address", NULL }, +{ IPSECDOI_ID_FQDN, "FQDN", NULL }, +{ IPSECDOI_ID_USER_FQDN, "User_FQDN", NULL }, +{ IPSECDOI_ID_IPV4_ADDR_SUBNET, "IPv4_subnet", NULL }, +{ IPSECDOI_ID_IPV6_ADDR, "IPv6_address", NULL }, +{ IPSECDOI_ID_IPV6_ADDR_SUBNET, "IPv6_subnet", NULL }, +{ IPSECDOI_ID_IPV4_ADDR_RANGE, "IPv4_address_range", NULL }, +{ IPSECDOI_ID_IPV6_ADDR_RANGE, "IPv6_address_range", NULL }, +{ IPSECDOI_ID_DER_ASN1_DN, "DER_ASN1_DN", NULL }, +{ IPSECDOI_ID_DER_ASN1_GN, "DER_ASN1_GN", NULL }, +{ IPSECDOI_ID_KEY_ID, "KEY_ID", NULL }, +}; + +char * +s_ipsecdoi_ident(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_ident); i++) + if (name_ipsecdoi_ident[i].key == k) + return name_ipsecdoi_ident[i].str; + return num2str(k); +} + +/* oakley.h */ +static struct ksmap name_oakley_attr[] = { +{ OAKLEY_ATTR_ENC_ALG, "Encryption Algorithm", s_attr_isakmp_enc }, +{ OAKLEY_ATTR_HASH_ALG, "Hash Algorithm", s_attr_isakmp_hash }, +{ OAKLEY_ATTR_AUTH_METHOD, "Authentication Method", s_oakley_attr_method }, +{ OAKLEY_ATTR_GRP_DESC, "Group Description", s_attr_isakmp_desc }, +{ OAKLEY_ATTR_GRP_TYPE, "Group Type", s_attr_isakmp_group }, +{ OAKLEY_ATTR_GRP_PI, "Group Prime/Irreducible Polynomial", NULL }, +{ OAKLEY_ATTR_GRP_GEN_ONE, "Group Generator One", NULL }, +{ OAKLEY_ATTR_GRP_GEN_TWO, "Group Generator Two", NULL }, +{ OAKLEY_ATTR_GRP_CURVE_A, "Group Curve A", NULL }, +{ OAKLEY_ATTR_GRP_CURVE_B, "Group Curve B", NULL }, +{ OAKLEY_ATTR_SA_LD_TYPE, "Life Type", s_attr_isakmp_ltype }, +{ OAKLEY_ATTR_SA_LD, "Life Duration", NULL }, +{ OAKLEY_ATTR_PRF, "PRF", NULL }, +{ OAKLEY_ATTR_KEY_LEN, "Key Length", NULL }, +{ OAKLEY_ATTR_FIELD_SIZE, "Field Size", NULL }, +{ OAKLEY_ATTR_GRP_ORDER, "Group Order", NULL }, +{ OAKLEY_ATTR_BLOCK_SIZE, "Block Size", NULL }, +{ OAKLEY_ATTR_GSS_ID, "GSS-API endpoint name",NULL }, +}; + +char * +s_oakley_attr(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_oakley_attr); i++) + if (name_oakley_attr[i].key == k) + return name_oakley_attr[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_enc[] = { +{ OAKLEY_ATTR_ENC_ALG_DES, "DES-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_IDEA, "IDEA-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_BLOWFISH, "Blowfish-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_RC5, "RC5-R16-B64-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_3DES, "3DES-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_CAST, "CAST-CBC", NULL }, +}; + +char * +s_attr_isakmp_enc(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_enc); i++) + if (name_attr_isakmp_enc[i].key == k) + return name_attr_isakmp_enc[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_hash[] = { +{ OAKLEY_ATTR_HASH_ALG_MD5, "MD5", NULL }, +{ OAKLEY_ATTR_HASH_ALG_SHA, "SHA", NULL }, +{ OAKLEY_ATTR_HASH_ALG_TIGER, "Tiger", NULL }, +{ OAKLEY_ATTR_HASH_ALG_SHA2_256,"SHA256", NULL }, +{ OAKLEY_ATTR_HASH_ALG_SHA2_384,"SHA384", NULL }, +{ OAKLEY_ATTR_HASH_ALG_SHA2_512,"SHA512", NULL }, +}; + +char * +s_attr_isakmp_hash(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_hash); i++) + if (name_attr_isakmp_hash[i].key == k) + return name_attr_isakmp_hash[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_method[] = { +{ OAKLEY_ATTR_AUTH_METHOD_PSKEY, "pre-shared key", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_DSSSIG, "DSS signatures", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSASIG, "RSA signatures", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSAENC, "Encryption with RSA", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSAREV, "Revised encryption with RSA", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_EGENC, "Encryption with El-Gamal", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_EGREV, "Revised encryption with El-Gamal", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, "GSS-API on Kerberos 5", NULL }, +#ifdef ENABLE_HYBRID +{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I, "Hybrid DSS server", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I, "Hybrid RSA server", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R, "Hybrid DSS client", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R, "Hybrid RSA client", NULL }, +#endif +}; + +char * +s_oakley_attr_method(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_method); i++) + if (name_attr_isakmp_method[i].key == k) + return name_attr_isakmp_method[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_desc[] = { +{ OAKLEY_ATTR_GRP_DESC_MODP768, "768-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP1024, "1024-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_EC2N155, "EC2N group on GP[2^155]", NULL }, +{ OAKLEY_ATTR_GRP_DESC_EC2N185, "EC2N group on GP[2^185]", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP1536, "1536-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP2048, "2048-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP3072, "3072-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP4096, "4096-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP6144, "6144-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP8192, "8192-bit MODP group", NULL }, +}; + +char * +s_attr_isakmp_desc(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_desc); i++) + if (name_attr_isakmp_desc[i].key == k) + return name_attr_isakmp_desc[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_group[] = { +{ OAKLEY_ATTR_GRP_TYPE_MODP, "MODP", NULL }, +{ OAKLEY_ATTR_GRP_TYPE_ECP, "ECP", NULL }, +{ OAKLEY_ATTR_GRP_TYPE_EC2N, "EC2N", NULL }, +}; + +char * +s_attr_isakmp_group(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_group); i++) + if (name_attr_isakmp_group[i].key == k) + return name_attr_isakmp_group[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_ltype[] = { +{ OAKLEY_ATTR_SA_LD_TYPE_SEC, "seconds", NULL }, +{ OAKLEY_ATTR_SA_LD_TYPE_KB, "kilobytes", NULL }, +}; + +char * +s_attr_isakmp_ltype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_ltype); i++) + if (name_attr_isakmp_ltype[i].key == k) + return name_attr_isakmp_ltype[i].str; + return num2str(k); +} + +char * +s_oakley_attr_v(type, val) + int type, val; +{ + int i; + for (i = 0; i < ARRAYLEN(name_oakley_attr); i++) + if (name_oakley_attr[i].key == type + && name_oakley_attr[i].f) + return (name_oakley_attr[i].f)(val); + return num2str(val); +} + +/* netinet6/ipsec.h */ +static struct ksmap name_ipsec_level[] = { +{ IPSEC_LEVEL_USE, "use", NULL }, +{ IPSEC_LEVEL_REQUIRE, "require", NULL }, +{ IPSEC_LEVEL_UNIQUE, "unique", NULL }, +}; + +char * +s_ipsec_level(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsec_level); i++) + if (name_ipsec_level[i].key == k) + return name_ipsec_level[i].str; + return num2str(k); +} + +static struct ksmap name_algclass[] = { +{ algclass_ipsec_enc, "ipsec enc", s_ipsecdoi_trns_esp }, +{ algclass_ipsec_auth, "ipsec auth", s_ipsecdoi_trns_ah }, +{ algclass_ipsec_comp, "ipsec comp", s_ipsecdoi_trns_ipcomp }, +{ algclass_isakmp_enc, "isakmp enc", s_attr_isakmp_enc }, +{ algclass_isakmp_hash, "isakmp hash", s_attr_isakmp_hash }, +{ algclass_isakmp_dh, "isakmp dh", s_attr_isakmp_desc }, +{ algclass_isakmp_ameth, "isakmp auth method", s_oakley_attr_method }, +}; + +char * +s_algclass(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_algclass); i++) + if (name_algclass[i].key == k) + return name_algclass[i].str; + return num2str(k); +} + +char * +s_algtype(class, n) + int class, n; +{ + int i; + for (i = 0; i < ARRAYLEN(name_algclass); i++) + if (name_algclass[i].key == class + && name_algclass[i].f) + return (name_algclass[i].f)(n); + return num2str(n); +} + +/* pfkey.h */ +static struct ksmap name_pfkey_type[] = { +{ SADB_GETSPI, "GETSPI", NULL }, +{ SADB_UPDATE, "UPDATE", NULL }, +{ SADB_ADD, "ADD", NULL }, +{ SADB_DELETE, "DELETE", NULL }, +{ SADB_GET, "GET", NULL }, +{ SADB_ACQUIRE, "ACQUIRE", NULL }, +{ SADB_REGISTER, "REGISTER", NULL }, +{ SADB_EXPIRE, "EXPIRE", NULL }, +{ SADB_FLUSH, "FLUSH", NULL }, +{ SADB_DUMP, "DUMP", NULL }, +{ SADB_X_PROMISC, "X_PRIMISC", NULL }, +{ SADB_X_PCHANGE, "X_PCHANGE", NULL }, +{ SADB_X_SPDUPDATE, "X_SPDUPDATE", NULL }, +{ SADB_X_SPDADD, "X_SPDADD", NULL }, +{ SADB_X_SPDDELETE, "X_SPDDELETE", NULL }, +{ SADB_X_SPDGET, "X_SPDGET", NULL }, +{ SADB_X_SPDACQUIRE, "X_SPDACQUIRE", NULL }, +{ SADB_X_SPDDUMP, "X_SPDDUMP", NULL }, +{ SADB_X_SPDFLUSH, "X_SPDFLUSH", NULL }, +{ SADB_X_SPDSETIDX, "X_SPDSETIDX", NULL }, +{ SADB_X_SPDEXPIRE, "X_SPDEXPIRE", NULL }, +{ SADB_X_SPDDELETE2, "X_SPDDELETE2", NULL }, +#ifndef __APPLE__ +#ifdef ENABLE_NATT +{ SADB_X_NAT_T_NEW_MAPPING, "X_NAT_T_NEW_MAPPING", NULL }, +#endif +#endif +}; + +char * +s_pfkey_type(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_pfkey_type); i++) + if (name_pfkey_type[i].key == k) + return name_pfkey_type[i].str; + return num2str(k); +} + +static struct ksmap name_pfkey_satype[] = { +{ SADB_SATYPE_UNSPEC, "UNSPEC", NULL }, +{ SADB_SATYPE_AH, "AH", NULL }, +{ SADB_SATYPE_ESP, "ESP", NULL }, +{ SADB_SATYPE_RSVP, "RSVP", NULL }, +{ SADB_SATYPE_OSPFV2, "OSPFV2", NULL }, +{ SADB_SATYPE_RIPV2, "RIPV2", NULL }, +{ SADB_SATYPE_MIP, "MIP", NULL }, +{ SADB_X_SATYPE_IPCOMP, "IPCOMP", NULL }, +}; + +char * +s_pfkey_satype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_pfkey_satype); i++) + if (name_pfkey_satype[i].key == k) + return name_pfkey_satype[i].str; + return num2str(k); +} + +static struct ksmap name_direction[] = { +{ IPSEC_DIR_INBOUND, "in", NULL }, +{ IPSEC_DIR_OUTBOUND, "out", NULL }, +#ifdef HAVE_POLICY_FWD +{ IPSEC_DIR_FWD, "fwd", NULL }, +#endif +}; + +char * +s_direction(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_direction); i++) + if (name_direction[i].key == k) + return name_direction[i].str; + return num2str(k); +} + +char * +s_proto(k) + int k; +{ + switch (k) { + case IPPROTO_ICMP: + return "icmp"; + case IPPROTO_TCP: + return "tcp"; + case IPPROTO_UDP: + return "udp"; + case IPPROTO_ICMPV6: + return "icmpv6"; + case IPSEC_ULPROTO_ANY: + return "any"; + } + + return num2str(k); +} + +char * +s_doi(int k) +{ + switch (k) { + case IPSEC_DOI: + return "ipsec_doi"; + default: + return num2str(k); + } +} + +char * +s_etype (int k) +{ + switch (k) { + case ISAKMP_ETYPE_NONE: + return "_none"; + case ISAKMP_ETYPE_BASE: + return "base"; + case ISAKMP_ETYPE_IDENT: + return "main"; + case ISAKMP_ETYPE_AUTH: + return "_auth"; + case ISAKMP_ETYPE_AGG: + return "aggressive"; + case ISAKMP_ETYPE_INFO: + return "_info"; + case ISAKMP_ETYPE_QUICK: + return "_quick"; + case ISAKMP_ETYPE_NEWGRP: + return "_newgrp"; + case ISAKMP_ETYPE_ACKINFO: + return "_ackinfo"; + default: + return num2str(k); + } +} + +char * +s_idtype (int k) +{ + switch (k) { + case IDTYPE_FQDN: + return "fqdn"; + case IDTYPE_USERFQDN: + return "user_fqdn"; + case IDTYPE_KEYID: + return "keyid"; + case IDTYPE_ADDRESS: + return "address"; + case IDTYPE_ASN1DN: + return "asn1dn"; + default: + return num2str(k); + } +} + +char * +s_switch (int k) +{ + switch (k) { + case FALSE: + return "off"; + case TRUE: + return "on"; + default: + return num2str(k); + } +} diff --git a/ipsec-tools/racoon/strnames.h b/ipsec-tools/racoon/strnames.h new file mode 100644 index 0000000..ed60551 --- /dev/null +++ b/ipsec-tools/racoon/strnames.h @@ -0,0 +1,74 @@ +/* $Id: strnames.h,v 1.5 2004/07/12 20:37:13 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STRNAMES_H +#define _STRNAMES_H + +extern char *num2str __P((int n)); + +extern char *s_isakmp_state __P((int, int, int)); +extern char *s_isakmp_certtype __P((int)); +extern char *s_isakmp_etype __P((int)); +extern char *s_isakmp_notify_msg __P((int)); +extern char *s_isakmp_nptype __P((int)); +extern char *s_ipsecdoi_proto __P((int)); +extern char *s_ipsecdoi_trns_isakmp __P((int)); +extern char *s_ipsecdoi_trns_ah __P((int)); +extern char *s_ipsecdoi_trns_esp __P((int)); +extern char *s_ipsecdoi_trns_ipcomp __P((int)); +extern char *s_ipsecdoi_trns __P((int, int)); +extern char *s_ipsecdoi_attr __P((int)); +extern char *s_ipsecdoi_ltype __P((int)); +extern char *s_ipsecdoi_encmode __P((int)); +extern char *s_ipsecdoi_auth __P((int)); +extern char *s_ipsecdoi_attr_v __P((int, int)); +extern char *s_ipsecdoi_ident __P((int)); +extern char *s_oakley_attr __P((int)); +extern char *s_attr_isakmp_enc __P((int)); +extern char *s_attr_isakmp_hash __P((int)); +extern char *s_oakley_attr_method __P((int)); +extern char *s_attr_isakmp_desc __P((int)); +extern char *s_attr_isakmp_group __P((int)); +extern char *s_attr_isakmp_ltype __P((int)); +extern char *s_oakley_attr_v __P((int, int)); +extern char *s_ipsec_level __P((int)); +extern char *s_algclass __P((int)); +extern char *s_algtype __P((int, int)); +extern char *s_pfkey_type __P((int)); +extern char *s_pfkey_satype __P((int)); +extern char *s_direction __P((int)); +extern char *s_proto __P((int)); +extern char *s_doi __P((int)); +extern char *s_etype __P((int)); +extern char *s_idtype __P((int)); +extern char *s_switch __P((int)); + +#endif /* _STRNAMES_H */ diff --git a/ipsec-tools/racoon/throttle.c b/ipsec-tools/racoon/throttle.c new file mode 100644 index 0000000..73f6b92 --- /dev/null +++ b/ipsec-tools/racoon/throttle.c @@ -0,0 +1,154 @@ +/* $Id: throttle.c,v 1.2 2004/11/30 07:40:13 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#include +#include + +#include + +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "throttle.h" +#include "sockmisc.h" +#include "libpfkey.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" +#include "gcmalloc.h" + +struct throttle_list throttle_list = TAILQ_HEAD_INITIALIZER(throttle_list); + + +struct throttle_entry * +throttle_add(addr) + struct sockaddr *addr; +{ + struct throttle_entry *te; + size_t len; + + len = sizeof(*te) + - sizeof(struct sockaddr_storage) + + sysdep_sa_len(addr); + + if ((te = racoon_malloc(len)) == NULL) + return NULL; + + te->penalty = time(NULL) + isakmp_cfg_config.auth_throttle; + memcpy(&te->host, addr, sysdep_sa_len(addr)); + TAILQ_INSERT_HEAD(&throttle_list, te, next); + + return te; +} + +int +throttle_host(addr, authfail) + struct sockaddr *addr; + int authfail; +{ + struct throttle_entry *te; + int found = 0; + time_t now; + + if (isakmp_cfg_config.auth_throttle == 0) + return 0; + + now = time(NULL); + + TAILQ_FOREACH_REVERSE(te, &throttle_list, throttle_list, next) { + /* + * Remove outdated entries + */ + if (te->penalty < now) { + TAILQ_REMOVE(&throttle_list, te, next); + racoon_free(te); + continue; + } + + if (cmpsaddrwop(addr, (struct sockaddr *)&te->host) == 0) { + found = 1; + break; + } + } + + /* + * No match, if auth failed, allocate a new throttle entry + * give no penalty even on error: this is the first time + * and we are indulgent. + */ + if (!found) { + if (authfail) { + if ((te = throttle_add(addr)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Throttle insertion failed\n"); + return (time(NULL) + + isakmp_cfg_config.auth_throttle); + } + } + return 0; + } else { + /* + * We had a match and auth failed, increase penalty. + */ + if (authfail) { + time_t remaining; + time_t new; + + remaining = te->penalty - now; + new = remaining + isakmp_cfg_config.auth_throttle; + + if (new > THROTTLE_PENALTY_MAX) + new = THROTTLE_PENALTY_MAX; + + te->penalty = now + new; + } + } + + return te->penalty; +} + diff --git a/ipsec-tools/racoon/throttle.h b/ipsec-tools/racoon/throttle.h new file mode 100644 index 0000000..4de4970 --- /dev/null +++ b/ipsec-tools/racoon/throttle.h @@ -0,0 +1,49 @@ +/* $Id: throttle.h,v 1.1 2004/11/30 00:46:09 manubsd Exp $ */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _THROTTLE_H +#define _THROTTLE_H + +struct throttle_entry { + int penalty; + TAILQ_ENTRY(throttle_entry) next; + struct sockaddr_storage host; +}; + +TAILQ_HEAD(throttle_list, throttle_entry); + +#define THROTTLE_PENALTY 1 +#define THROTTLE_PENALTY_MAX 10 + +struct throttle_entry *throttle_add(struct sockaddr *); +int throttle_host(struct sockaddr *, int); + +#endif /* _THROTTLE_H */ diff --git a/ipsec-tools/racoon/var.h b/ipsec-tools/racoon/var.h new file mode 100644 index 0000000..e2cb36f --- /dev/null +++ b/ipsec-tools/racoon/var.h @@ -0,0 +1,105 @@ +/* $Id: var.h,v 1.6 2004/11/20 16:16:59 monas Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VAR_H +#define _VAR_H + +#if !defined(_VAR_H_) +#define _VAR_H_ + +#define MAX3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c)) + +#define ISSET(exp, bit) (((exp) & (bit)) == (bit)) + +#define LALIGN(a) \ + ((a) > 0 ? ((a) &~ (sizeof(long) - 1)) : sizeof(long)) + +#define RNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +#define ARRAYLEN(a) (sizeof(a)/sizeof(a[0])) + +#define BUFSIZE 5120 + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifdef ENABLE_STATS +#include +#endif +#include + +/* + * 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 +#include + +/* 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 +#ifndef LIST_FOREACH +#define LIST_FOREACH(elm, head, field) \ + for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field)) +#endif + +#include "gcmalloc.h" + +#endif /*!defined(_VAR_H_)*/ + +#endif /* _VAR_H */ diff --git a/ipsec-tools/racoon/vendorid.c b/ipsec-tools/racoon/vendorid.c new file mode 100644 index 0000000..7a12f5f --- /dev/null +++ b/ipsec-tools/racoon/vendorid.c @@ -0,0 +1,270 @@ +/* $Id: vendorid.c,v 1.7 2005/01/29 16:34:25 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "vendorid.h" +#include "crypto_openssl.h" + +static struct vendor_id all_vendor_ids[] = { +{ VENDORID_KAME , "KAME/racoon" }, +{ VENDORID_GSSAPI_LONG, "A GSS-API Authentication Method for IKE" }, +{ VENDORID_GSSAPI , "GSSAPI" }, +{ VENDORID_MS_NT5 , "MS NT5 ISAKMPOAKLEY" }, +{ VENDORID_NATT_00 , "draft-ietf-ipsec-nat-t-ike-00" }, +{ VENDORID_NATT_01 , "draft-ietf-ipsec-nat-t-ike-01" }, +{ VENDORID_NATT_02 , "draft-ietf-ipsec-nat-t-ike-02" }, +{ VENDORID_NATT_02_N , "draft-ietf-ipsec-nat-t-ike-02\n" }, +{ VENDORID_NATT_03 , "draft-ietf-ipsec-nat-t-ike-03" }, +{ VENDORID_NATT_04 , "draft-ietf-ipsec-nat-t-ike-04" }, +{ VENDORID_NATT_05 , "draft-ietf-ipsec-nat-t-ike-05" }, +{ VENDORID_NATT_06 , "draft-ietf-ipsec-nat-t-ike-06" }, +{ VENDORID_NATT_07 , "draft-ietf-ipsec-nat-t-ike-07" }, +{ VENDORID_NATT_08 , "draft-ietf-ipsec-nat-t-ike-08" }, +#ifdef __APPLE__ +{ VENDORID_NATT_APPLE , "draft-ietf-ipsec-nat-t-ike" }, +#endif +{ VENDORID_NATT_RFC , "RFC 3947" }, +{ VENDORID_XAUTH , "draft-ietf-ipsra-isakmp-xauth-06.txt" }, +{ VENDORID_UNITY , "CISCO-UNITY" }, +{ VENDORID_FRAG , "FRAGMENTATION" }, +/* Just a readable string for DPD ... */ +{ VENDORID_DPD , "DPD" }, +}; + +#define NUMVENDORIDS (sizeof(all_vendor_ids)/sizeof(all_vendor_ids[0])) + +#define DPD_MAJOR_VERSION 0x01 +#define DPD_MINOR_VERSION 0x00 + +const char vendorid_dpd_hash[] = { + 0xAF, 0xCA, 0xD7, 0x13, + 0x68, 0xA1, 0xF1, 0xC9, + 0x6B, 0x86, 0x96, 0xFC, + 0x77, 0x57, DPD_MAJOR_VERSION, DPD_MINOR_VERSION +}; + + +static vchar_t *vendorid_fixup(int, vchar_t *t); + +static struct vendor_id * +lookup_vendor_id_by_id (int id) +{ + int i; + + for (i = 0; i < NUMVENDORIDS; i++) + if (all_vendor_ids[i].id == id) + return &all_vendor_ids[i]; + + return NULL; +} + +const char * +vid_string_by_id (int id) +{ + struct vendor_id *current; + + if (id == VENDORID_DPD) + return vendorid_dpd_hash; + + current = lookup_vendor_id_by_id(id); + + return current ? current->string : NULL; +} + +static struct vendor_id * +lookup_vendor_id_by_hash (const char *hash) +{ + int i; + unsigned char *h = (unsigned char *)hash; + + for (i = 0; i < NUMVENDORIDS; i++) + if (strncmp(all_vendor_ids[i].hash->v, hash, + all_vendor_ids[i].hash->l) == 0) + return &all_vendor_ids[i]; + + return NULL; +} + +void +compute_vendorids (void) +{ + int i; + vchar_t vid; + + for (i = 0; i < NUMVENDORIDS; i++) { + /* VENDORID_DPD is not a MD5 sum... */ + if(i == VENDORID_DPD){ + all_vendor_ids[i].hash = vmalloc(sizeof(vendorid_dpd_hash)); + if (all_vendor_ids[i].hash == NULL) { + plog(LLV_ERROR2, LOCATION, NULL, + "unable to get memory for VID hash\n"); + exit(1); /* this really shouldn't happen */ + } + memcpy(all_vendor_ids[i].hash->v, vendorid_dpd_hash, + sizeof(vendorid_dpd_hash)); + continue; + } + + vid.v = (char *) all_vendor_ids[i].string; + vid.l = strlen(vid.v); + + all_vendor_ids[i].hash = eay_md5_one(&vid); + if (all_vendor_ids[i].hash == NULL) + plog(LLV_ERROR, LOCATION, NULL, + "unable to hash vendor ID string\n"); + + /* Special cases */ + all_vendor_ids[i].hash = + vendorid_fixup(all_vendor_ids[i].id, + all_vendor_ids[i].hash); + } +} + +/* + * set hashed vendor id. + * hash function is always MD5. + */ +vchar_t * +set_vendorid(int vendorid) +{ + struct vendor_id *current; + vchar_t vid, *new; + + if (vendorid == VENDORID_UNKNOWN) { + /* + * The default unknown ID gets translated to + * KAME/racoon. + */ + vendorid = VENDORID_KAME; + } + + current = lookup_vendor_id_by_id(vendorid); + if (current == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid vendor ID index: %d\n", vendorid); + return (NULL); + } + + /* The rest of racoon expects a private copy + * of the VID that could be free'd after use. + * That's why we don't return the original pointer. */ + return vdup(current->hash); +} + +/* + * Check the vendor ID payload -- return the vendor ID index + * if we find a recognized one, or UNKNOWN if we don't. + * + * gen ... points to Vendor ID payload. + */ +int +check_vendorid(struct isakmp_gen *gen) +{ + vchar_t vid, *vidhash; + int i, vidlen; + struct vendor_id *current; + + if (gen == NULL) + return (VENDORID_UNKNOWN); + + vidlen = ntohs(gen->len) - sizeof(*gen); + + current = lookup_vendor_id_by_hash((char *)(gen + 1)); + if (!current) + goto unknown; + + if (current->hash->l < vidlen) + plog(LLV_INFO, LOCATION, NULL, + "received broken Microsoft ID: %s\n", + current->string); + else + plog(LLV_INFO, LOCATION, NULL, + "received Vendor ID: %s\n", + current->string); + + return current->id; + +unknown: + plog(LLV_DEBUG, LOCATION, NULL, "received unknown Vendor ID\n"); + return (VENDORID_UNKNOWN); +} + +static vchar_t * +vendorid_fixup(vendorid, vidhash) + int vendorid; + vchar_t *vidhash; +{ + switch(vendorid) { + case VENDORID_XAUTH: { /* The vendor Id is truncated */ + vchar_t *tmp; + + if ((tmp = vmalloc(8)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to hash vendor ID string\n"); + return NULL; + } + + memcpy(tmp->v, vidhash->v, 8); + vfree(vidhash); + vidhash = tmp; + + break; + } + case VENDORID_UNITY: /* Two bytes tweak */ + vidhash->v[14] = 0x01; + vidhash->v[15] = 0x00; + break; + + default: + break; + } + + return vidhash; +} diff --git a/ipsec-tools/racoon/vendorid.h b/ipsec-tools/racoon/vendorid.h new file mode 100644 index 0000000..d3ecf67 --- /dev/null +++ b/ipsec-tools/racoon/vendorid.h @@ -0,0 +1,104 @@ +/* $Id: vendorid.h,v 1.10 2005/01/29 16:34:25 vanhu Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VENDORID_H +#define _VENDORID_H + +/* The unknown vendor ID. */ +#define VENDORID_UNKNOWN -1 + +/* Our default vendor ID. */ +#define VENDORID_KAME 0 + +/* + * Refer to draft-ietf-ipsec-isakmp-gss-auth-06.txt. + */ +#define VENDORID_GSSAPI_LONG 1 +#define VENDORID_GSSAPI 2 +#define VENDORID_MS_NT5 3 +#define VENDOR_SUPPORTS_GSSAPI(x) \ + ((x) == VENDORID_GSSAPI_LONG || \ + (x) == VENDORID_GSSAPI || \ + (x) == VENDORID_MS_NT5) + +/* NAT-T support */ +#define VENDORID_NATT_00 4 +#define VENDORID_NATT_01 5 +#define VENDORID_NATT_02 6 +#define VENDORID_NATT_02_N 7 +#define VENDORID_NATT_03 8 +#define VENDORID_NATT_04 9 +#define VENDORID_NATT_05 10 +#define VENDORID_NATT_06 11 +#define VENDORID_NATT_07 12 +#define VENDORID_NATT_08 13 + +#ifdef __APPLE__ +#define VENDORID_NATT_APPLE 14 +#define VENDORID_NATT_RFC 15 +/* Hybrid auth */ +#define VENDORID_XAUTH 16 +#define VENDORID_UNITY 17 +/* IKE fragmentation */ +#define VENDORID_FRAG 18 +/* Dead Peer Detection */ +#define VENDORID_DPD 19 +#else /* __APPLE__ */ +#define VENDORID_NATT_RFC 14 +/* Hybrid auth */ +#define VENDORID_XAUTH 15 +#define VENDORID_UNITY 16 +/* IKE fragmentation */ +#define VENDORID_FRAG 17 +/* Dead Peer Detection */ +#define VENDORID_DPD 18 +#endif /* __APPLE__ */ + +#define VENDORID_NATT_FIRST VENDORID_NATT_00 +#define VENDORID_NATT_LAST VENDORID_NATT_RFC + + +#define MAX_NATT_VID_COUNT (VENDORID_NATT_LAST - VENDORID_NATT_FIRST + 1 ) + + +struct vendor_id { + int id; + const char *string; + vchar_t *hash; +}; + +vchar_t *set_vendorid __P((int)); +int check_vendorid __P((struct isakmp_gen *)); + +void compute_vendorids __P((void)); +const char *vid_string_by_id __P((int id)); + +#endif /* _VENDORID_H */ diff --git a/ipsec-tools/racoon/vmbuf.c b/ipsec-tools/racoon/vmbuf.c new file mode 100644 index 0000000..e0204b6 --- /dev/null +++ b/ipsec-tools/racoon/vmbuf.c @@ -0,0 +1,129 @@ +/* $KAME: vmbuf.c,v 1.11 2001/11/26 16:54:29 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#define NONEED_DRM + +#include +#include + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "debug.h" +#include "gcmalloc.h" + +vchar_t * +vmalloc(size) + size_t size; +{ + vchar_t *var; + + if ((var = (vchar_t *)racoon_malloc(sizeof(*var))) == NULL) + return NULL; + + var->l = size; + if (size == 0) { + var->v = NULL; + } else { + var->v = (caddr_t)racoon_calloc(1, size); + if (var->v == NULL) { + (void)racoon_free(var); + return NULL; + } + } + + return var; +} + +vchar_t * +vrealloc(ptr, size) + vchar_t *ptr; + size_t size; +{ + caddr_t v; + + if (ptr != NULL) { + if (ptr->l == 0) { + (void)vfree(ptr); + return vmalloc(size); /* zero-fill it? */ + } + + if ((v = (caddr_t)racoon_realloc(ptr->v, size)) == NULL) { + (void)vfree(ptr); + return NULL; + } + + if ( size > ptr->l) + memset(v + ptr->l, 0, size - ptr->l); + ptr->v = v; + ptr->l = size; + } else { + if ((ptr = vmalloc(size)) == NULL) + return NULL; + } + + return ptr; +} + +void +vfree(var) + vchar_t *var; +{ + if (var == NULL) + return; + + if (var->v) + (void)racoon_free(var->v); + + (void)racoon_free(var); + + return; +} + +vchar_t * +vdup(src) + vchar_t *src; +{ + vchar_t *new; + + if ((new = vmalloc(src->l)) == NULL) + return NULL; + + memcpy(new->v, src->v, src->l); + + return new; +} diff --git a/ipsec-tools/racoon/vmbuf.h b/ipsec-tools/racoon/vmbuf.h new file mode 100644 index 0000000..5191be9 --- /dev/null +++ b/ipsec-tools/racoon/vmbuf.h @@ -0,0 +1,68 @@ +/* $Id: vmbuf.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VMBUF_H +#define _VMBUF_H + +#include + +/* + * bp v + * v v + * ........................ + * <--------------> l + * <----------------------> bl + */ +typedef struct _vchar_t_ { +#if notyet + u_int32_t t; /* type of the value */ + vchar_t *n; /* next vchar_t buffer */ + size_t bl; /* length of the buffer */ + caddr_t bp; /* pointer to the buffer */ +#endif + size_t l; /* length of the value */ + caddr_t v; /* place holder to the pointer to the value */ +} vchar_t; + +#define VPTRINIT(p) \ +do { \ + if (p) { \ + vfree(p); \ + (p) = NULL; \ + } \ +} while(0); + +extern vchar_t *vmalloc __P((size_t)); +extern vchar_t *vrealloc __P((vchar_t *, size_t)); +extern void vfree __P((vchar_t *)); +extern vchar_t *vdup __P((vchar_t *)); + +#endif /* _VMBUF_H */ diff --git a/ipsec-tools/racoon/vpn_control.c b/ipsec-tools/racoon/vpn_control.c new file mode 100644 index 0000000..f3217a0 --- /dev/null +++ b/ipsec-tools/racoon/vpn_control.c @@ -0,0 +1,516 @@ +/* $Id: vpn_control.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */ + +/* + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#ifndef HAVE_NETINET6_IPSEC +#include +#else +#include +#endif + + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "localconf.h" +#include "remoteconf.h" +#include "grabmyaddr.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "evt.h" +#include "pfkey.h" +#include "ipsec_doi.h" +#include "vpn_control.h" +#include "vpn_control_var.h" +#include "isakmp_inf.h" +#include "session.h" +#include "gcmalloc.h" + +#ifdef ENABLE_VPNCONTROL_PORT +char *vpncontrolsock_path = VPNCONTROLSOCK_PATH; +uid_t vpncontrolsock_owner = 0; +gid_t vpncontrolsock_group = 0; +mode_t vpncontrolsock_mode = 0600; + +static struct sockaddr_un sunaddr; +static int vpncontrol_process(struct vpnctl_socket_elem *, char *); +static int vpncontrol_reply(int, char *); +static void vpncontrol_close_comm(struct vpnctl_socket_elem *); + +int +vpncontrol_handler() +{ + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + + struct vpnctl_socket_elem *sock_elem; + + sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem)); + if (sock_elem == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "memory error: %s\n", strerror(errno)); + return -1; + } + LIST_INIT(&sock_elem->bound_addresses); + + sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen); + if (sock_elem->sock < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to accept vpn_control command: %s\n", strerror(errno)); + racoon_free(sock_elem); + return -1; + } + LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain); + plog(LLV_NOTIFY, LOCATION, NULL, + "accepted connection on vpn control socket.\n"); + + check_auto_exit(); + + return 0; +} + +int +vpncontrol_comm_handler(struct vpnctl_socket_elem *elem) +{ + struct vpnctl_hdr hdr; + char *combuf = NULL; + int len; + + /* get buffer length */ + while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv vpn_control command: %s\n", strerror(errno)); + goto end; + } + if (len == 0) { + plog(LLV_NOTIFY, LOCATION, NULL, + "vpn_control socket closed by peer.\n"); + vpncontrol_close_comm(elem); + return -1; + } + + /* sanity check */ + if (len < sizeof(hdr)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid header length of vpn_control command - len=%d - expected %d\n", len, sizeof(hdr)); + goto end; + } + + /* get buffer to receive */ + if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to alloc buffer for vpn_control command\n"); + goto end; + } + + /* get real data */ + while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv vpn_control command: %s\n", + strerror(errno)); + goto end; + } + + (void)vpncontrol_process(elem, combuf); + +end: + if (combuf) + racoon_free(combuf); + return 0; // return -1 only if a socket is closed +} + +static int +vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf) +{ + u_int16_t error = 0; + struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf; + + switch (ntohs(hdr->msg_type)) { + + case VPNCTL_CMD_BIND: + { + struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf; + struct bound_addr *addr; + + plog(LLV_DEBUG, LOCATION, NULL, + "received bind command on vpn control socket.\n"); + addr = racoon_malloc(sizeof(struct bound_addr)); + if (addr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "memory error: %s\n", strerror(errno)); + error = -1; + break; + } + addr->address = pkt->address; + LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain); + lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; /* client side */ + } + break; + + case VPNCTL_CMD_UNBIND: + { + struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf; + struct bound_addr *addr; + struct bound_addr *t_addr; + + plog(LLV_DEBUG, LOCATION, NULL, + "received unbind command on vpn control socket.\n"); + LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) { + if (pkt->address == 0xFFFFFFFF || + pkt->address == addr->address) { + LIST_REMOVE(addr, chain); + racoon_free(addr); + } + } + } + break; + + case VPNCTL_CMD_REDIRECT: + { + struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf; + struct redirect *raddr; + struct redirect *t_raddr; + int found = 0; + + plog(LLV_DEBUG, LOCATION, NULL, + "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address)); + + LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) { + if (raddr->cluster_address == redirect_msg->address) { + if (redirect_msg->redirect_address == 0) { + LIST_REMOVE(raddr, chain); + racoon_free(raddr); + } else { + raddr->redirect_address = redirect_msg->redirect_address; + raddr->force = ntohs(redirect_msg->force); + } + found = 1; + break; + } + } + if (!found) { + raddr = racoon_malloc(sizeof(struct redirect)); + if (raddr == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "cannot allcoate memory for redirect address.\n"); + error = -1; + break; + } + raddr->cluster_address = redirect_msg->address; + raddr->redirect_address = redirect_msg->redirect_address; + raddr->force = ntohs(redirect_msg->force); + LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain); + + } + } + break; + + case VPNCTL_CMD_PING: + break; // just reply for now + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid command: %d\n", ntohs(hdr->msg_type)); + error = -1; // for now + break; + } + + hdr->len = 0; + hdr->result = htons(error); + if (vpncontrol_reply(elem->sock, combuf) < 0) + return -1; + + return 0; + +} + +static int +vpncontrol_reply(int so, char *combuf) +{ + size_t tlen; + + tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0); + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to send vpn_control message: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +int +vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t address, u_int16_t data_len, u_int8_t *data) +{ + struct vpnctl_status_failed *msg; + struct vpnctl_socket_elem *sock_elem; + struct bound_addr *bound_addr; + size_t tlen, len; + + len = sizeof(struct vpnctl_status_failed) + data_len; + + msg = (struct vpnctl_status_failed *)racoon_malloc(len); + if (msg == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "unable to allcate memory for vpn control status message.\n"); + return -1; + } + + msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED); + msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0; + msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr)); + msg->address = address; + msg->ike_code = htons(notify_code); + msg->from = htons(from); + if (data_len > 0) + memcpy(msg->data, data, data_len); + plog(LLV_DEBUG, LOCATION, NULL, + "sending vpn_control ike notify failed message - code=%d from=%s.\n", notify_code, + (from == FROM_LOCAL ? "local" : "remote")); + + LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) { + LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) { + if (bound_addr->address == 0xFFFFFFFF || + bound_addr->address == address) { + tlen = send(sock_elem->sock, msg, len, 0); + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to send vpn_control ike notify failed: %s\n", strerror(errno)); + } + break; + } + } + } + return 0; +} + + +int +vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1, struct ph2handle *iph2) +{ + struct vpnctl_status_phase_change msg; + struct vpnctl_socket_elem *sock_elem; + struct bound_addr *bound_addr; + size_t tlen; + u_int32_t address; + + if (iph1) { + if (iph1->remote->sa_family == AF_INET) + address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr; + else + return 0; // for now + msg.hdr.msg_type = htons(start ? + (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER) + : VPNCTL_STATUS_PH1_ESTABLISHED); + } else { + if (iph2->dst->sa_family == AF_INET) + address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr; + else + return 0; // for now + msg.hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED); + } + msg.hdr.flags = msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0; + msg.hdr.len = htons(sizeof(struct vpnctl_status_phase_change) - sizeof(struct vpnctl_hdr)); + msg.address = address; + + LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) { + LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) { + if (bound_addr->address == 0xFFFFFFFF || + bound_addr->address == address) { + tlen = send(sock_elem->sock, &msg, sizeof(struct vpnctl_status_phase_change), 0); + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to send vpn_control phase change status: %s\n", strerror(errno)); + } + break; + } + } + } + + return 0; +} + + +int +vpncontrol_init() +{ + if (vpncontrolsock_path == NULL) { + lcconf->sock_vpncontrol = -1; + return 0; + } + + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), + "%s", vpncontrolsock_path); + + lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0); + if (lcconf->sock_vpncontrol == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "socket: %s\n", strerror(errno)); + return -1; + } + + unlink(sunaddr.sun_path); + if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_vpncontrol); + return -1; + } + + if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "chown(%s, %d, %d): %s\n", + sunaddr.sun_path, vpncontrolsock_owner, + vpncontrolsock_group, strerror(errno)); + (void)close(lcconf->sock_vpncontrol); + return -1; + } + + if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "chmod(%s, 0%03o): %s\n", + sunaddr.sun_path, vpncontrolsock_mode, strerror(errno)); + (void)close(lcconf->sock_vpncontrol); + return -1; + } + + if (listen(lcconf->sock_vpncontrol, 5) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "listen(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_vpncontrol); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "opened %s as racoon management.\n", sunaddr.sun_path); + + return 0; +} + + +void +vpncontrol_close() +{ + struct vpnctl_socket_elem *elem; + struct vpnctl_socket_elem *t_elem; + + if (lcconf->sock_vpncontrol != -1) { + close(lcconf->sock_vpncontrol); + lcconf->sock_vpncontrol = -1; + } + LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) + vpncontrol_close_comm(elem); +} + +static void +vpncontrol_close_comm(struct vpnctl_socket_elem *elem) +{ + struct bound_addr *addr; + struct bound_addr *t_addr; + + LIST_REMOVE(elem, chain); + if (elem->sock != -1) + close(elem->sock); + LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) { + LIST_REMOVE(addr, chain); + racoon_free(addr); + } + racoon_free(elem); + check_auto_exit(); +} + +int +vpn_control_connected(void) +{ + if (LIST_EMPTY(&lcconf->vpnctl_comm_socks)) + return 0; + else + return 1; +} + +#endif diff --git a/ipsec-tools/racoon/vpn_control.h b/ipsec-tools/racoon/vpn_control.h new file mode 100644 index 0000000..cabbb16 --- /dev/null +++ b/ipsec-tools/racoon/vpn_control.h @@ -0,0 +1,172 @@ +/* $Id: vpn_control.h,v 1.10 2004/12/30 13:45:49 manubsd Exp $ */ + +/* + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VPN_CONTROL_H +#define _VPN_CONTROL_H + +#define VPNCONTROLSOCK_PATH ADMINPORTDIR "/vpncontrol.sock" + +#define FROM_LOCAL 0 +#define FROM_REMOTE 1 + +extern char *vpncontrolsock_path; +extern uid_t vpncontrolsock_owner; +extern gid_t vpncontrolsock_group; +extern mode_t vpncontrolsock_mode; + + +/* + * message types + */ +#define VPNCTL_CMD_BIND 0x0001 +#define VPNCTL_CMD_UNBIND 0x0002 +#define VPNCTL_CMD_REDIRECT 0x0003 +#define VPNCTL_CMD_PING 0x0004 +#define VPNCTL_STATUS_IKE_FAILED 0x8001 +#define VPNCTL_STATUS_PH1_START_US 0x8011 +#define VPNCTL_STATUS_PH1_START_PEER 0x8012 +#define VPNCTL_STATUS_PH1_ESTABLISHED 0x8013 +#define VPNCTL_STATUS_PH2_START 0x8021 +#define VPNCTL_STATUS_PH2_ESTABLISHED 0x8022 + + +/* commands and status for vpn control. */ +/* network byte order. */ + +/* Packet header */ +struct vpnctl_hdr { + u_int16_t msg_type; + u_int16_t flags; + u_int32_t cookie; + u_int32_t reserved; + u_int16_t result; + u_int16_t len; /* payload length */ +}; + +/* Packet formats for commands */ + +/* bind to receive status for specified address */ +struct vpnctl_cmd_bind { + struct vpnctl_hdr hdr; + u_int32_t address; /* 0xFFFFFFFF = all */ +}; + +/* unbind to stop receiving status for specified address */ +struct vpnctl_cmd_unbind { + struct vpnctl_hdr hdr; + u_int32_t address; /* 0xFFFFFFFF = all */ +}; + +/* redirect client to specified address */ +struct vpnctl_cmd_redirect { + struct vpnctl_hdr hdr; + u_int32_t address; + u_int32_t redirect_address; + u_int16_t force; +}; + + +/* + * IKE Notify codes - mirrors codes in isakmp.h + */ +#define VPNCTL_NTYPE_INVALID_PAYLOAD_TYPE 1 +#define VPNCTL_NTYPE_DOI_NOT_SUPPORTED 2 +#define VPNCTL_NTYPE_SITUATION_NOT_SUPPORTED 3 +#define VPNCTL_NTYPE_INVALID_COOKIE 4 +#define VPNCTL_NTYPE_INVALID_MAJOR_VERSION 5 +#define VPNCTL_NTYPE_INVALID_MINOR_VERSION 6 +#define VPNCTL_NTYPE_INVALID_EXCHANGE_TYPE 7 +#define VPNCTL_NTYPE_INVALID_FLAGS 8 +#define VPNCTL_NTYPE_INVALID_MESSAGE_ID 9 +#define VPNCTL_NTYPE_INVALID_PROTOCOL_ID 10 +#define VPNCTL_NTYPE_INVALID_SPI 11 +#define VPNCTL_NTYPE_INVALID_TRANSFORM_ID 12 +#define VPNCTL_NTYPE_ATTRIBUTES_NOT_SUPPORTED 13 +#define VPNCTL_NTYPE_NO_PROPOSAL_CHOSEN 14 +#define VPNCTL_NTYPE_BAD_PROPOSAL_SYNTAX 15 +#define VPNCTL_NTYPE_PAYLOAD_MALFORMED 16 +#define VPNCTL_NTYPE_INVALID_KEY_INFORMATION 17 +#define VPNCTL_NTYPE_INVALID_ID_INFORMATION 18 +#define VPNCTL_NTYPE_INVALID_CERT_ENCODING 19 +#define VPNCTL_NTYPE_INVALID_CERTIFICATE 20 +#define VPNCTL_NTYPE_BAD_CERT_REQUEST_SYNTAX 21 +#define VPNCTL_NTYPE_INVALID_CERT_AUTHORITY 22 +#define VPNCTL_NTYPE_INVALID_HASH_INFORMATION 23 +#define VPNCTL_NTYPE_AUTHENTICATION_FAILED 24 +#define VPNCTL_NTYPE_INVALID_SIGNATURE 25 +#define VPNCTL_NTYPE_ADDRESS_NOTIFICATION 26 +#define VPNCTL_NTYPE_NOTIFY_SA_LIFETIME 27 +#define VPNCTL_NTYPE_CERTIFICATE_UNAVAILABLE 28 +#define VPNCTL_NTYPE_UNSUPPORTED_EXCHANGE_TYPE 29 +#define VPNCTL_NTYPE_UNEQUAL_PAYLOAD_LENGTHS 30 +#define VPNCTL_NTYPE_LOAD_BALANCE 40501 +#define VPNCTL_NTYPE_INTERNAL_ERROR -1 + + +/* packet format for phase change status */ +struct vpnctl_status_phase_change { + struct vpnctl_hdr hdr; + u_int32_t address; +}; + +/* Packet formats for failed status */ +struct vpnctl_status_failed { + struct vpnctl_hdr hdr; + u_int32_t address; + u_int16_t ike_code; + u_int16_t from; + u_int8_t data[0]; +}; + + +#endif /* _VPN_CONTROL_H */ diff --git a/ipsec-tools/racoon/vpn_control_var.h b/ipsec-tools/racoon/vpn_control_var.h new file mode 100644 index 0000000..59ad69e --- /dev/null +++ b/ipsec-tools/racoon/vpn_control_var.h @@ -0,0 +1,65 @@ +/* $Id: vpn_control_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp $ */ + +/* + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VPN_CONTROL_VAR_H +#define _VPN_CONTROL_VAR_H + +extern int vpncontrol_handler __P((void)); +extern int vpncontrol_comm_handler __P((struct vpnctl_socket_elem *)); +extern int vpncontrol_notify_ike_failed __P((u_int16_t, u_int16_t, u_int32_t, u_int16_t, u_int8_t*)); +extern int vpncontrol_notify_phase_change __P((int, u_int16_t, struct ph1handle*, struct ph2handle*)); +extern int vpncontrol_init __P((void)); +extern void vpncontrol_close __P((void)); +extern int vpn_control_connected __P((void)); + +#endif /* _VPN_CONTROL_VAR_H */ diff --git a/ipsec-tools/setkey/Sample/sample-policy01.cf b/ipsec-tools/setkey/Sample/sample-policy01.cf new file mode 100644 index 0000000..42c16b2 --- /dev/null +++ b/ipsec-tools/setkey/Sample/sample-policy01.cf @@ -0,0 +1,20 @@ +# +# This is for basic policy test on loopback. +# + +spdflush; +spdadd 127.0.0.1 127.0.0.1 icmp + -P out ipsec + esp/transport//require ; +spdadd ::1 ::1 icmp6 + -P out ipsec + esp/transport//require ; + +flush; +add 127.0.0.1 127.0.0.1 esp 0x1000 + -m transport + -E des-cbc "kamekame"; +add ::1 ::1 esp 0x1001 + -m transport + -E des-cbc "hagehage"; +flush; diff --git a/ipsec-tools/setkey/Sample/sample-policy02.cf b/ipsec-tools/setkey/Sample/sample-policy02.cf new file mode 100644 index 0000000..8c5134a --- /dev/null +++ b/ipsec-tools/setkey/Sample/sample-policy02.cf @@ -0,0 +1,43 @@ +# +# this is test configuration for unique policy on loopback. +# + +spdflush; +# connection to 9999 encrypted, reverse no encrypted. +spdadd ::1 ::1[9999] tcp + -P out ipsec + esp/transport//unique:2 ; + +# Session encrypted. Inbound policy check takes place non-strictly. +spdadd ::1 ::1[9998] tcp + -P out ipsec + esp/transport//unique:1 ; +spdadd ::1[9998] ::1 tcp + -P in ipsec + esp/transport//unique:2 ; +spdadd ::1[9998] ::1 tcp + -P out ipsec + esp/transport//unique:1 ; + +# Cause new SA to be acquired. +spdadd ::1 ::1[9997] tcp + -P out ipsec + esp/transport//unique ; + +# Used proper SA. +spdadd ::1 ::1[9996] tcp + -P out ipsec + esp/transport//require ; + +# reqid will be updated by kernel. +spdadd ::1 ::1[9995] tcp + -P out ipsec + esp/transport//unique:28000 ; + +flush; +add ::1 ::1 esp 0x1001 + -u 1 + -E des-cbc "kamekame"; +add ::1 ::1 esp 0x1002 + -u 2 + -E des-cbc "hogehoge"; diff --git a/ipsec-tools/setkey/Sample/sample.cf b/ipsec-tools/setkey/Sample/sample.cf new file mode 100644 index 0000000..c64fd36 --- /dev/null +++ b/ipsec-tools/setkey/Sample/sample.cf @@ -0,0 +1,217 @@ +# Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# There are sample scripts for IPsec configuration by manual keying. +# A security association is uniquely identified by a triple consisting +# of a Security Parameter Index (SPI), an IP Destination Address, and a +# security protocol (AH or ESP) identifier. You must take care of these +# parameters when you configure by manual keying. + +# ESP transport mode is recommended for TCP port number 110 between +# Host-A and Host-B. Encryption algorithm is blowfish-cbc whose key +# is "kamekame", and authentication algorithm is hmac-sha1 whose key +# is "this is the test key". +# +# ============ ESP ============ +# | | +# Host-A Host-B +# fec0::10 -------------------- fec0::11 +# +# At Host-A and Host-B, +spdadd fec0::10[any] fec0::11[110] tcp -P out ipsec + esp/transport//use ; +spdadd fec0::11[110] fec0::10[any] tcp -P in ipsec + esp/transport//use ; +add fec0::10 fec0::11 esp 0x10001 + -m transport + -E blowfish-cbc "kamekame" + -A hmac-sha1 "this is the test key" ; +add fec0::11 fec0::10 esp 0x10002 + -m transport + -E blowfish-cbc "kamekame" + -A hmac-sha1 "this is the test key" ; + +# "[any]" is wildcard of port number. Note that "[0]" is the number of +# zero in port number. + +# Security protocol is old AH tunnel mode, i.e. RFC1826, with keyed-md5 +# whose key is "this is the test" as authentication algorithm. +# That protocol takes place between Gateway-A and Gateway-B. +# +# ======= AH ======= +# | | +# Network-A Gateway-A Gateway-B Network-B +# 10.0.1.0/24 ---- 172.16.0.1 ----- 172.16.0.2 ---- 10.0.2.0/24 +# +# At Gateway-A: +spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec + ah/tunnel/172.16.0.1-172.16.0.2/require ; +spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec + ah/tunnel/172.16.0.2-172.16.0.1/require ; +add 172.16.0.1 172.16.0.2 ah-old 0x10003 + -m any + -A keyed-md5 "this is the test" ; +add 172.16.0.2 172.16.0.1 ah-old 0x10004 + -m any + -A keyed-md5 "this is the test" ; + +# If port number field is omitted such above then "[any]" is employed. +# -m specifies the mode of SA to be used. "-m any" means wildcard of +# mode of security protocol. You can use this SAs for both tunnel and +# transport mode. + +# At Gateway-B. Attention to the selector and peer's IP address for tunnel. +spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec + ah/tunnel/172.16.0.2-172.16.0.1/require ; +spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec + ah/tunnel/172.16.0.1-172.16.0.2/require ; +add 172.16.0.1 172.16.0.2 ah-old 0x10003 + -m tunnel + -A keyed-md5 "this is the test" ; +add 172.16.0.2 172.16.0.1 ah-old 0x10004 + -m tunnel + -A keyed-md5 "this is the test" ; + +# AH transport mode followed by ESP tunnel mode is required between +# Gateway-A and Gateway-B. +# Encryption algorithm is 3des-cbc, and authentication algorithm for ESP +# is hmac-sha1. Authentication algorithm for AH is hmac-md5. +# +# ========== AH ========= +# | ======= ESP ===== | +# | | | | +# Network-A Gateway-A Gateway-B Network-B +# fec0:0:0:1::/64 --- fec0:0:0:1::1 ---- fec0:0:0:2::1 --- fec0:0:0:2::/64 +# +# At Gateway-A: +spdadd fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out ipsec + esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require + ah/transport//require ; +spdadd fec0:0:0:2::/64 fec0:0:0:1::/64 any -P in ipsec + esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require + ah/transport//require ; +add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10001 + -m tunnel + -E 3des-cbc "kamekame12341234kame1234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:1::1 fec0:0:0:2::1 ah 0x10001 + -m transport + -A hmac-md5 "this is the test" ; +add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10001 + -m tunnel + -E 3des-cbc "kamekame12341234kame1234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:2::1 fec0:0:0:1::1 ah 0x10001 + -m transport + -A hmac-md5 "this is the test" ; + +# ESP tunnel mode is required between Host-A and Gateway-A. +# Encryption algorithm is cast128-cbc, and authentication algorithm +# for ESP is hmac-sha1. +# ESP transport mode is recommended between Host-A and Host-B. +# Encryption algorithm is rc5-cbc, and authentication algorithm +# for ESP is hmac-md5. +# +# ================== ESP ================= +# | ======= ESP ======= | +# | | | | +# Host-A Gateway-A Host-B +# fec0:0:0:1::1 ---- fec0:0:0:2::1 ---- fec0:0:0:2::2 +# +# At Host-A: +spdadd fec0:0:0:1::1[any] fec0:0:0:2::2[80] tcp -P out ipsec + esp/transport//use + esp/tunnel/fec0:0:0:1::1-fec0:0:0:2::1/require ; +spdadd fec0:0:0:2::1[80] fec0:0:0:1::1[any] tcp -P in ipsec + esp/transport//use + esp/tunnel/fec0:0:0:2::1-fec0:0:0:1::1/require ; +add fec0:0:0:1::1 fec0:0:0:2::2 esp 0x10001 + -m transport + -E cast128-cbc "12341234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:1::1 fec0:0:0:2::1 esp 0x10002 + -E rc5-cbc "kamekame" + -A hmac-md5 "this is the test" ; +add fec0:0:0:2::2 fec0:0:0:1::1 esp 0x10003 + -m transport + -E cast128-cbc "12341234" + -A hmac-sha1 "this is the test key" ; +add fec0:0:0:2::1 fec0:0:0:1::1 esp 0x10004 + -E rc5-cbc "kamekame" + -A hmac-md5 "this is the test" ; + +# By "get" command, you can get a entry of either SP or SA. +get fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ; + +# Also delete command, you can delete a entry of either SP or SA. +spddelete fec0:0:0:1::/64 fec0:0:0:2::/64 any -P out; +delete fec0:0:0:1::1 fec0:0:0:2::2 ah 0x10004 ; + +# By dump command, you can dump all entry of either SP or SA. +dump ; +spddump ; +dump esp ; +flush esp ; + +# By flush command, you can flush all entry of either SP or SA. +flush ; +spdflush ; + +# "flush" and "dump" commands can specify a security protocol. +dump esp ; +flush ah ; + +# XXX +add ::1 ::1 esp 10001 -m transport -E null ; +add ::1 ::1 esp 10002 -m transport -E des-deriv "12341234" ; +add ::1 ::1 esp-old 10003 -m transport -E des-32iv "12341234" ; +add ::1 ::1 esp 10004 -m transport -E null -A null ; +add ::1 ::1 esp 10005 -m transport -E null -A hmac-md5 "1234123412341234" ; +add ::1 ::1 esp 10006 -m tunnel -E null -A hmac-sha1 "12341234123412341234" ; +add ::1 ::1 esp 10007 -m transport -E null -A keyed-md5 "1234123412341234" ; +add ::1 ::1 esp 10008 -m any -E null -A keyed-sha1 "12341234123412341234" ; +add ::1 ::1 esp 10009 -m transport -E des-cbc "testtest" ; +add ::1 ::1 esp 10010 -m transport -E 3des-cbc "testtest12341234testtest" ; +add ::1 ::1 esp 10011 -m tunnel -E cast128-cbc "testtest1234" ; +add ::1 ::1 esp 10012 -m tunnel -E blowfish-cbc "testtest1234" ; +add ::1 ::1 esp 10013 -m tunnel -E rc5-cbc "testtest1234" ; +add ::1 ::1 esp 10014 -m any -E rc5-cbc "testtest1234" ; +add ::1 ::1 esp 10015 -m transport -f zero-pad -E null ; +add ::1 ::1 esp 10016 -m tunnel -f random-pad -r 8 -lh 100 -ls 80 -E null ; +add ::1 ::1 esp 10017 -m transport -f seq-pad -f nocyclic-seq -E null ; +add ::1 ::1 esp 10018 -m transport -E null ; +#add ::1 ::1 ah 20000 -m transport -A null ; +add ::1 ::1 ah 20001 -m any -A hmac-md5 "1234123412341234"; +add ::1 ::1 ah 20002 -m tunnel -A hmac-sha1 "12341234123412341234"; +add ::1 ::1 ah 20003 -m transport -A keyed-md5 "1234123412341234"; +add ::1 ::1 ah-old 20004 -m transport -A keyed-md5 "1234123412341234"; +add ::1 ::1 ah 20005 -m transport -A keyed-sha1 "12341234123412341234"; +#add ::1 ::1 ipcomp 30000 -C oui ; +add ::1 ::1 ipcomp 30001 -C deflate ; +#add ::1 ::1 ipcomp 30002 -C lzs ; + +# enjoy. diff --git a/ipsec-tools/setkey/extern.h b/ipsec-tools/setkey/extern.h new file mode 100644 index 0000000..3a8a751 --- /dev/null +++ b/ipsec-tools/setkey/extern.h @@ -0,0 +1,28 @@ + + +void parse_init __P((void)); +int parse __P((FILE **)); +int parse_string __P((char *)); + +int setkeymsg __P((char *, size_t *)); +int sendkeymsg __P((char *, size_t)); + +int yylex __P((void)); +int yyparse __P((void)); +void yyfatal __P((const char *)); +void yyerror __P((const char *)); + +extern int f_rfcmode; +extern int lineno; +extern int last_msg_type; +extern u_int32_t last_priority; +extern int exit_now; + +extern u_char m_buf[BUFSIZ]; +extern u_int m_len; +extern int f_debug; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY +extern int last_msg_type; +extern u_int32_t last_priority; +#endif diff --git a/ipsec-tools/setkey/parse.y b/ipsec-tools/setkey/parse.y new file mode 100644 index 0000000..6b99dea --- /dev/null +++ b/ipsec-tools/setkey/parse.y @@ -0,0 +1,1539 @@ +/* $KAME: parse.y,v 1.81 2003/07/01 04:01:48 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +%{ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 prefix protocol_spec upper_spec +%type ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD ALG_ENC_NOKEY +%type ALG_AUTH ALG_AUTH_NOKEY +%type ALG_COMP +%type PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP +%type EXTENSION MODE +%type DECSTRING +%type PL_REQUESTS portstr key_string +%type policy_requests +%type QUOTEDSTRING HEXSTRING STRING +%type F_AIFLAGS +%type upper_misc_spec policy_spec +%type ipaddr ipandport + +%% +commands + : /*NOTHING*/ + | commands command + { + free_buffer(); + parse_init(); + } + ; + +command + : add_command + | get_command + | delete_command + | deleteall_command + | flush_command + | dump_command + | exit_command + | spdadd_command + | spddelete_command + | spddump_command + | spdflush_command + ; + /* commands concerned with management, there is in tail of this file. */ + + /* add command */ +add_command + : ADD ipaddropts ipandport ipandport protocol_spec spi extension_spec algorithm_spec EOT + { + int status; + + status = setkeymsg_add(SADB_ADD, $5, $3, $4); + if (status < 0) + return -1; + } + ; + + /* delete */ +delete_command + : DELETE ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT + { + int status; + + if ($3->ai_next || $4->ai_next) { + yyerror("multiple address specified"); + return -1; + } + if (p_mode != IPSEC_MODE_ANY) + yyerror("WARNING: mode is obsolete"); + + status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 0); + if (status < 0) + return -1; + } + ; + + /* deleteall command */ +deleteall_command + : DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT + { + int status; + + status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1); + if (status < 0) + return -1; + } + ; + + /* get command */ +get_command + : GET ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT + { + int status; + + if (p_mode != IPSEC_MODE_ANY) + yyerror("WARNING: mode is obsolete"); + + status = setkeymsg_addr(SADB_GET, $5, $3, $4, 0); + if (status < 0) + return -1; + } + ; + + /* flush */ +flush_command + : FLUSH protocol_spec EOT + { + struct sadb_msg msg; + setkeymsg0(&msg, SADB_FLUSH, $2, sizeof(msg)); + sendkeymsg((char *)&msg, sizeof(msg)); + } + ; + + /* dump */ +dump_command + : DUMP protocol_spec EOT + { + struct sadb_msg msg; + setkeymsg0(&msg, SADB_DUMP, $2, sizeof(msg)); + sendkeymsg((char *)&msg, sizeof(msg)); + } + ; + +protocol_spec + : /*NOTHING*/ + { + $$ = SADB_SATYPE_UNSPEC; + } + | PR_ESP + { + $$ = SADB_SATYPE_ESP; + if ($1 == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_AH + { + $$ = SADB_SATYPE_AH; + if ($1 == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_IPCOMP + { + $$ = SADB_X_SATYPE_IPCOMP; + } + | PR_ESPUDP + { + $$ = SADB_SATYPE_ESP; + p_ext &= ~SADB_X_EXT_OLD; + p_natt_oa = 0; + p_natt_type = UDP_ENCAP_ESPINUDP; + } + | PR_ESPUDP ipaddr + { + $$ = SADB_SATYPE_ESP; + p_ext &= ~SADB_X_EXT_OLD; + p_natt_oa = $2; + p_natt_type = UDP_ENCAP_ESPINUDP; + } + | PR_TCP + { +#ifdef SADB_X_SATYPE_TCPSIGNATURE + $$ = SADB_X_SATYPE_TCPSIGNATURE; +#endif + } + ; + +spi + : DECSTRING { p_spi = $1; } + | HEXSTRING + { + char *ep; + unsigned long v; + + ep = NULL; + v = strtoul($1.buf, &ep, 16); + if (!ep || *ep) { + yyerror("invalid SPI"); + return -1; + } + if (v & ~0xffffffff) { + yyerror("SPI too big."); + return -1; + } + + p_spi = v; + } + ; + +algorithm_spec + : esp_spec + | ah_spec + | ipcomp_spec + ; + +esp_spec + : F_ENC enc_alg F_AUTH auth_alg + | F_ENC enc_alg + ; + +ah_spec + : F_AUTH auth_alg + ; + +ipcomp_spec + : F_COMP ALG_COMP + { + if ($2 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $2; + } + | F_COMP ALG_COMP F_RAWCPI + { + if ($2 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $2; + p_ext |= SADB_X_EXT_RAWCPI; + } + ; + +enc_alg + : ALG_ENC_NOKEY { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $1; + + p_key_enc_len = 0; + p_key_enc = ""; + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + | ALG_ENC key_string { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $1; + + p_key_enc_len = $2.len; + p_key_enc = $2.buf; + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + | ALG_ENC_OLD { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + yyerror("WARNING: obsolete algorithm"); + p_alg_enc = $1; + + p_key_enc_len = 0; + p_key_enc = ""; + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + | ALG_ENC_DESDERIV key_string + { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $1; + if (p_ext & SADB_X_EXT_OLD) { + yyerror("algorithm mismatched"); + return -1; + } + p_ext |= SADB_X_EXT_DERIV; + + p_key_enc_len = $2.len; + p_key_enc = $2.buf; + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + | ALG_ENC_DES32IV key_string + { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_enc = $1; + if (!(p_ext & SADB_X_EXT_OLD)) { + yyerror("algorithm mismatched"); + return -1; + } + p_ext |= SADB_X_EXT_IV4B; + + p_key_enc_len = $2.len; + p_key_enc = $2.buf; + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + ; + +auth_alg + : ALG_AUTH key_string { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_auth = $1; + + p_key_auth_len = $2.len; + p_key_auth = $2.buf; +#ifdef SADB_X_AALG_TCP_MD5 + if (p_alg_auth == SADB_X_AALG_TCP_MD5) { + if ((p_key_auth_len < 1) || + (p_key_auth_len > 80)) + return -1; + } else +#endif + { + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH, + p_alg_auth, + PFKEY_UNUNIT64(p_key_auth_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + } + | ALG_AUTH_NOKEY { + if ($1 < 0) { + yyerror("unsupported algorithm"); + return -1; + } + p_alg_auth = $1; + + p_key_auth_len = 0; + p_key_auth = NULL; + } + ; + +key_string + : QUOTEDSTRING + { + $$ = $1; + } + | HEXSTRING + { + caddr_t pp_key; + caddr_t bp; + caddr_t yp = $1.buf; + int l; + + l = strlen(yp) % 2 + strlen(yp) / 2; + if ((pp_key = malloc(l)) == 0) { + yyerror("not enough core"); + return -1; + } + memset(pp_key, 0, l); + + bp = pp_key; + if (strlen(yp) % 2) { + *bp = ATOX(yp[0]); + yp++, bp++; + } + while (*yp) { + *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); + yp += 2, bp++; + } + + $$.len = l; + $$.buf = pp_key; + } + ; + +extension_spec + : /*NOTHING*/ + | extension_spec extension + ; + +extension + : F_EXT EXTENSION { p_ext |= $2; } + | F_EXT NOCYCLICSEQ { p_ext &= ~SADB_X_EXT_CYCSEQ; } + | F_MODE MODE { p_mode = $2; } + | F_MODE ANY { p_mode = IPSEC_MODE_ANY; } + | F_REQID DECSTRING { p_reqid = $2; } + | F_REPLAY DECSTRING + { + if ((p_ext & SADB_X_EXT_OLD) != 0) { + yyerror("replay prevention cannot be used with " + "ah/esp-old"); + return -1; + } + p_replay = $2; + } + | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2; } + | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2; } + | F_LIFEBYTE_HARD DECSTRING { p_lb_hard = $2; } + | F_LIFEBYTE_SOFT DECSTRING { p_lb_soft = $2; } + ; + + /* definition about command for SPD management */ + /* spdadd */ +spdadd_command + : SPDADD ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT + { + int status; + struct addrinfo *src, *dst; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + last_msg_type = SADB_X_SPDADD; +#endif + + /* fixed port fields if ulp is icmpv6 */ + if ($10.buf != NULL) { + if ($9 != IPPROTO_ICMPV6) + return -1; + free($5.buf); + free($8.buf); + if (fix_portstr(&$10, &$5, &$8)) + return -1; + } + + src = parse_addr($3.buf, $5.buf); + dst = parse_addr($6.buf, $8.buf); + if (!src || !dst) { + /* yyerror is already called */ + return -1; + } + if (src->ai_next || dst->ai_next) { + yyerror("multiple address specified"); + freeaddrinfo(src); + freeaddrinfo(dst); + return -1; + } + + status = setkeymsg_spdaddr(SADB_X_SPDADD, $9, &$11, + src, $4, dst, $7); + freeaddrinfo(src); + freeaddrinfo(dst); + if (status < 0) + return -1; + } + | SPDADD TAGGED QUOTEDSTRING policy_spec EOT + { + int status; + + status = setkeymsg_spdaddr_tag(SADB_X_SPDADD, + $3.buf, &$4); + if (status < 0) + return -1; + } + ; + +spddelete_command + : SPDDELETE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT + { + int status; + struct addrinfo *src, *dst; + + /* fixed port fields if ulp is icmpv6 */ + if ($10.buf != NULL) { + if ($9 != IPPROTO_ICMPV6) + return -1; + free($5.buf); + free($8.buf); + if (fix_portstr(&$10, &$5, &$8)) + return -1; + } + + src = parse_addr($3.buf, $5.buf); + dst = parse_addr($6.buf, $8.buf); + if (!src || !dst) { + /* yyerror is already called */ + return -1; + } + if (src->ai_next || dst->ai_next) { + yyerror("multiple address specified"); + freeaddrinfo(src); + freeaddrinfo(dst); + return -1; + } + + status = setkeymsg_spdaddr(SADB_X_SPDDELETE, $9, &$11, + src, $4, dst, $7); + freeaddrinfo(src); + freeaddrinfo(dst); + if (status < 0) + return -1; + } + ; + +spddump_command: + SPDDUMP EOT + { + struct sadb_msg msg; + setkeymsg0(&msg, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC, + sizeof(msg)); + sendkeymsg((char *)&msg, sizeof(msg)); + } + ; + +spdflush_command + : + SPDFLUSH EOT + { + struct sadb_msg msg; + setkeymsg0(&msg, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC, + sizeof(msg)); + sendkeymsg((char *)&msg, sizeof(msg)); + } + ; + +ipaddropts + : /* nothing */ + | ipaddropts ipaddropt + ; + +ipaddropt + : F_AIFLAGS + { + char *p; + + for (p = $1.buf + 1; *p; p++) + switch (*p) { + case '4': + p_aifamily = AF_INET; + break; +#ifdef INET6 + case '6': + p_aifamily = AF_INET6; + break; +#endif + case 'n': + p_aiflags = AI_NUMERICHOST; + break; + default: + yyerror("invalid flag"); + return -1; + } + } + ; + +ipaddr + : STRING + { + $$ = parse_addr($1.buf, NULL); + if ($$ == NULL) { + /* yyerror already called by parse_addr */ + return -1; + } + } + ; + +ipandport + : STRING + { + $$ = parse_addr($1.buf, NULL); + if ($$ == NULL) { + /* yyerror already called by parse_addr */ + return -1; + } + } + | STRING portstr + { + $$ = parse_addr($1.buf, $2.buf); + if ($$ == NULL) { + /* yyerror already called by parse_addr */ + return -1; + } + } + ; + +prefix + : /*NOTHING*/ { $$ = -1; } + | SLASH DECSTRING { $$ = $2; } + ; + +portstr + : /*NOTHING*/ + { + $$.buf = strdup("0"); + if (!$$.buf) { + yyerror("insufficient memory"); + return -1; + } + $$.len = strlen($$.buf); + } + | BLCL ANY ELCL + { + $$.buf = strdup("0"); + if (!$$.buf) { + yyerror("insufficient memory"); + return -1; + } + $$.len = strlen($$.buf); + } + | BLCL DECSTRING ELCL + { + char buf[20]; + snprintf(buf, sizeof(buf), "%lu", $2); + $$.buf = strdup(buf); + if (!$$.buf) { + yyerror("insufficient memory"); + return -1; + } + $$.len = strlen($$.buf); + } + | BLCL STRING ELCL + { + $$ = $2; + } + ; + +upper_spec + : DECSTRING { $$ = $1; } + | ANY { $$ = IPSEC_ULPROTO_ANY; } + | PR_TCP { + $$ = IPPROTO_TCP; + } + | STRING + { + struct protoent *ent; + + ent = getprotobyname($1.buf); + if (ent) + $$ = ent->p_proto; + else { + if (strcmp("icmp6", $1.buf) == 0) { + $$ = IPPROTO_ICMPV6; + } else if(strcmp("ip4", $1.buf) == 0) { + $$ = IPPROTO_IPV4; + } else { + yyerror("invalid upper layer protocol"); + return -1; + } + } + endprotoent(); + } + ; + +upper_misc_spec + : /*NOTHING*/ + { + $$.buf = NULL; + $$.len = 0; + } + | STRING + { + $$.buf = strdup($1.buf); + if (!$$.buf) { + yyerror("insufficient memory"); + return -1; + } + $$.len = strlen($$.buf); + } + ; + +policy_spec + : F_POLICY policy_requests + { + char *policy; +#ifdef HAVE_PFKEY_POLICY_PRIORITY + struct sadb_x_policy *xpl; +#endif + + policy = ipsec_set_policy($2.buf, $2.len); + if (policy == NULL) { + yyerror(ipsec_strerror()); + return -1; + } + + $$.buf = policy; + $$.len = ipsec_get_policylen(policy); + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + xpl = (struct sadb_x_policy *) $$.buf; + last_priority = xpl->sadb_x_policy_priority; +#endif + } + ; + +policy_requests + : PL_REQUESTS { $$ = $1; } + ; + + /* exit */ +exit_command + : EXIT EOT + { + exit_now = 1; + YYACCEPT; + } + ; +%% + +int +setkeymsg0(msg, type, satype, l) + struct sadb_msg *msg; + unsigned int type; + unsigned int satype; + size_t l; +{ + + msg->sadb_msg_version = PF_KEY_V2; + msg->sadb_msg_type = type; + msg->sadb_msg_errno = 0; + msg->sadb_msg_satype = satype; + msg->sadb_msg_reserved = 0; + msg->sadb_msg_seq = 0; + msg->sadb_msg_pid = getpid(); + msg->sadb_msg_len = PFKEY_UNIT64(l); + return 0; +} + +/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ +static int +setkeymsg_spdaddr(type, upper, policy, srcs, splen, dsts, dplen) + unsigned int type; + unsigned int upper; + vchar_t *policy; + struct addrinfo *srcs; + int splen; + struct addrinfo *dsts; + int dplen; +{ + struct sadb_msg *msg; + char buf[BUFSIZ]; + int l, l0; + struct sadb_address m_addr; + struct addrinfo *s, *d; + int n; + int plen; + struct sockaddr *sa; + int salen; + struct sadb_x_policy *sp; +#ifdef HAVE_POLICY_FWD + struct sadb_x_ipsecrequest *ps = NULL; + int saved_level, saved_id = 0; +#endif + + msg = (struct sadb_msg *)buf; + + if (!srcs || !dsts) + return -1; + + /* fix up length afterwards */ + setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0); + l = sizeof(struct sadb_msg); + + sp = (struct sadb_x_policy*) (buf + l); + memcpy(buf + l, policy->buf, policy->len); + l += policy->len; + + l0 = l; + n = 0; + + /* do it for all src/dst pairs */ + for (s = srcs; s; s = s->ai_next) { + for (d = dsts; d; d = d->ai_next) { + /* rewind pointer */ + l = l0; + + if (s->ai_addr->sa_family != d->ai_addr->sa_family) + continue; + switch (s->ai_addr->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + continue; + } + + /* set src */ + sa = s->ai_addr; + salen = sysdep_sa_len(s->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = upper; + m_addr.sadb_address_prefixlen = + (splen >= 0 ? splen : plen); + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), (caddr_t)sa, salen); + + /* set dst */ + sa = d->ai_addr; + salen = sysdep_sa_len(d->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = upper; + m_addr.sadb_address_prefixlen = + (dplen >= 0 ? dplen : plen); + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + + msg->sadb_msg_len = PFKEY_UNIT64(l); + + sendkeymsg(buf, l); + +#ifdef HAVE_POLICY_FWD + /* create extra call for FWD policy */ + if (f_rfcmode && sp->sadb_x_policy_dir == IPSEC_DIR_INBOUND) { + sp->sadb_x_policy_dir = IPSEC_DIR_FWD; + ps = (struct sadb_x_ipsecrequest*) (sp+1); + + /* if request level is unique, change it to + * require for fwd policy */ + /* XXX: currently, only first policy is updated + * only. Update following too... */ + saved_level = ps->sadb_x_ipsecrequest_level; + if (saved_level == IPSEC_LEVEL_UNIQUE) { + saved_id = ps->sadb_x_ipsecrequest_reqid; + ps->sadb_x_ipsecrequest_reqid=0; + ps->sadb_x_ipsecrequest_level=IPSEC_LEVEL_REQUIRE; + } + + sendkeymsg(buf, l); + /* restoring for next message */ + sp->sadb_x_policy_dir = IPSEC_DIR_INBOUND; + if (saved_level == IPSEC_LEVEL_UNIQUE) { + ps->sadb_x_ipsecrequest_reqid = saved_id; + ps->sadb_x_ipsecrequest_level = saved_level; + } + } +#endif + + n++; + } + } + + if (n == 0) + return -1; + else + return 0; +} + +static int +setkeymsg_spdaddr_tag(type, tag, policy) + unsigned int type; + char *tag; + vchar_t *policy; +{ + struct sadb_msg *msg; + char buf[BUFSIZ]; + int l, l0; +#ifdef SADB_X_EXT_TAG + struct sadb_x_tag m_tag; +#endif + int n; + + msg = (struct sadb_msg *)buf; + + /* fix up length afterwards */ + setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0); + l = sizeof(struct sadb_msg); + + memcpy(buf + l, policy->buf, policy->len); + l += policy->len; + + l0 = l; + n = 0; + +#ifdef SADB_X_EXT_TAG + memset(&m_tag, 0, sizeof(m_tag)); + m_tag.sadb_x_tag_len = PFKEY_UNIT64(sizeof(m_tag)); + m_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG; + if (strlcpy(m_tag.sadb_x_tag_name, tag, + sizeof(m_tag.sadb_x_tag_name)) >= sizeof(m_tag.sadb_x_tag_name)) + return -1; + memcpy(buf + l, &m_tag, sizeof(m_tag)); + l += sizeof(m_tag); +#endif + + msg->sadb_msg_len = PFKEY_UNIT64(l); + + sendkeymsg(buf, l); + + return 0; +} + +/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ +static int +setkeymsg_addr(type, satype, srcs, dsts, no_spi) + unsigned int type; + unsigned int satype; + struct addrinfo *srcs; + struct addrinfo *dsts; + int no_spi; +{ + struct sadb_msg *msg; + char buf[BUFSIZ]; + int l, l0, len; + struct sadb_sa m_sa; + struct sadb_x_sa2 m_sa2; + struct sadb_address m_addr; + struct addrinfo *s, *d; + int n; + int plen; + struct sockaddr *sa; + int salen; + + msg = (struct sadb_msg *)buf; + + if (!srcs || !dsts) + return -1; + + /* fix up length afterwards */ + setkeymsg0(msg, type, satype, 0); + l = sizeof(struct sadb_msg); + + if (!no_spi) { + len = sizeof(struct sadb_sa); + m_sa.sadb_sa_len = PFKEY_UNIT64(len); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(p_spi); + m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = p_alg_auth; + m_sa.sadb_sa_encrypt = p_alg_enc; + m_sa.sadb_sa_flags = p_ext; + + memcpy(buf + l, &m_sa, len); + l += len; + + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; + + memcpy(buf + l, &m_sa2, len); + l += len; + } + + l0 = l; + n = 0; + + /* do it for all src/dst pairs */ + for (s = srcs; s; s = s->ai_next) { + for (d = dsts; d; d = d->ai_next) { + /* rewind pointer */ + l = l0; + + if (s->ai_addr->sa_family != d->ai_addr->sa_family) + continue; + switch (s->ai_addr->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + continue; + } + + /* set src */ + sa = s->ai_addr; + salen = sysdep_sa_len(s->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + + /* set dst */ + sa = d->ai_addr; + salen = sysdep_sa_len(d->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + + msg->sadb_msg_len = PFKEY_UNIT64(l); + + sendkeymsg(buf, l); + + n++; + } + } + + if (n == 0) + return -1; + else + return 0; +} + +#ifdef SADB_X_EXT_NAT_T_TYPE +static u_int16_t get_port (struct addrinfo *addr) +{ + struct sockaddr *s = addr->ai_addr; + u_int16_t port = 0; + + switch (s->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin4 = (struct sockaddr_in *)s; + port = ntohs(sin4->sin_port); + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)s; + port = ntohs(sin6->sin6_port); + break; + } + } + + if (port == 0) + port = DEFAULT_NATT_PORT; + + return port; +} +#endif + +/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ +static int +setkeymsg_add(type, satype, srcs, dsts) + unsigned int type; + unsigned int satype; + struct addrinfo *srcs; + struct addrinfo *dsts; +{ + struct sadb_msg *msg; + char buf[BUFSIZ]; + int l, l0, len; + struct sadb_sa m_sa; + struct sadb_x_sa2 m_sa2; + struct sadb_address m_addr; + struct addrinfo *s, *d; + int n; + int plen; + struct sockaddr *sa; + int salen; + + msg = (struct sadb_msg *)buf; + + if (!srcs || !dsts) + return -1; + + /* fix up length afterwards */ + setkeymsg0(msg, type, satype, 0); + l = sizeof(struct sadb_msg); + + /* set encryption algorithm, if present. */ + if (satype != SADB_X_SATYPE_IPCOMP && p_key_enc) { + union { + struct sadb_key key; + struct sadb_ext ext; + } m; + + m.key.sadb_key_len = + PFKEY_UNIT64(sizeof(m.key) + + PFKEY_ALIGN8(p_key_enc_len)); + m.key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + m.key.sadb_key_bits = p_key_enc_len * 8; + m.key.sadb_key_reserved = 0; + + setvarbuf(buf, &l, &m.ext, sizeof(m.key), + p_key_enc, p_key_enc_len); + } + + /* set authentication algorithm, if present. */ + if (p_key_auth) { + union { + struct sadb_key key; + struct sadb_ext ext; + } m; + + m.key.sadb_key_len = + PFKEY_UNIT64(sizeof(m.key) + + PFKEY_ALIGN8(p_key_auth_len)); + m.key.sadb_key_exttype = SADB_EXT_KEY_AUTH; + m.key.sadb_key_bits = p_key_auth_len * 8; + m.key.sadb_key_reserved = 0; + + setvarbuf(buf, &l, &m.ext, sizeof(m.key), + p_key_auth, p_key_auth_len); + } + + /* set lifetime for HARD */ + if (p_lt_hard != 0 || p_lb_hard != 0) { + struct sadb_lifetime m_lt; + u_int slen = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = p_lb_hard; + m_lt.sadb_lifetime_addtime = p_lt_hard; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(buf + l, &m_lt, slen); + l += slen; + } + + /* set lifetime for SOFT */ + if (p_lt_soft != 0 || p_lb_soft != 0) { + struct sadb_lifetime m_lt; + u_int slen = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = p_lb_soft; + m_lt.sadb_lifetime_addtime = p_lt_soft; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(buf + l, &m_lt, slen); + l += slen; + } + + len = sizeof(struct sadb_sa); + m_sa.sadb_sa_len = PFKEY_UNIT64(len); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(p_spi); + m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = p_alg_auth; + m_sa.sadb_sa_encrypt = p_alg_enc; + m_sa.sadb_sa_flags = p_ext; + + memcpy(buf + l, &m_sa, len); + l += len; + + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; + + memcpy(buf + l, &m_sa2, len); + l += len; + +#ifdef SADB_X_EXT_NAT_T_TYPE + if (p_natt_type) { + struct sadb_x_nat_t_type natt_type; + + len = sizeof(struct sadb_x_nat_t_type); + memset(&natt_type, 0, len); + natt_type.sadb_x_nat_t_type_len = PFKEY_UNIT64(len); + natt_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; + natt_type.sadb_x_nat_t_type_type = p_natt_type; + + memcpy(buf + l, &natt_type, len); + l += len; + + if (p_natt_oa) { + sa = p_natt_oa->ai_addr; + switch (sa->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + return -1; + } + salen = sysdep_sa_len(sa); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_X_EXT_NAT_T_OA; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + } + } +#endif + + l0 = l; + n = 0; + + /* do it for all src/dst pairs */ + for (s = srcs; s; s = s->ai_next) { + for (d = dsts; d; d = d->ai_next) { + /* rewind pointer */ + l = l0; + + if (s->ai_addr->sa_family != d->ai_addr->sa_family) + continue; + switch (s->ai_addr->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + continue; + } + + /* set src */ + sa = s->ai_addr; + salen = sysdep_sa_len(s->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + + /* set dst */ + sa = d->ai_addr; + salen = sysdep_sa_len(d->ai_addr); + m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(salen)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, + sizeof(m_addr), sa, salen); + +#ifdef SADB_X_EXT_NAT_T_TYPE + if (p_natt_type) { + struct sadb_x_nat_t_port natt_port; + + /* NATT_SPORT */ + len = sizeof(struct sadb_x_nat_t_port); + memset(&natt_port, 0, len); + natt_port.sadb_x_nat_t_port_len = PFKEY_UNIT64(len); + natt_port.sadb_x_nat_t_port_exttype = + SADB_X_EXT_NAT_T_SPORT; + natt_port.sadb_x_nat_t_port_port = htons(get_port(s)); + + memcpy(buf + l, &natt_port, len); + l += len; + + /* NATT_DPORT */ + natt_port.sadb_x_nat_t_port_exttype = + SADB_X_EXT_NAT_T_DPORT; + natt_port.sadb_x_nat_t_port_port = htons(get_port(d)); + + memcpy(buf + l, &natt_port, len); + l += len; + } +#endif + msg->sadb_msg_len = PFKEY_UNIT64(l); + + sendkeymsg(buf, l); + + n++; + } + } + + if (n == 0) + return -1; + else + return 0; +} + +static struct addrinfo * +parse_addr(host, port) + char *host; + char *port; +{ + struct addrinfo hints, *res = NULL; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = p_aifamily; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_protocol = IPPROTO_UDP; /*dummy*/ + hints.ai_flags = p_aiflags; + error = getaddrinfo(host, port, &hints, &res); + if (error != 0) { + yyerror(gai_strerror(error)); + return NULL; + } + return res; +} + +static int +fix_portstr(spec, sport, dport) + vchar_t *spec, *sport, *dport; +{ + const char *p, *p2 = "0"; + char *q; + u_int l; + + l = 0; + for (q = spec->buf; *q != ',' && *q != '\0' && l < spec->len; q++, l++) + ; + if (*q != '\0') { + if (*q == ',') { + *q = '\0'; + p2 = ++q; + } + for (p = p2; *p != '\0' && l < spec->len; p++, l++) + ; + if (*p != '\0' || *p2 == '\0') { + yyerror("invalid an upper layer protocol spec"); + return -1; + } + } + + sport->buf = strdup(spec->buf); + if (!sport->buf) { + yyerror("insufficient memory"); + return -1; + } + sport->len = strlen(sport->buf); + dport->buf = strdup(p2); + if (!dport->buf) { + yyerror("insufficient memory"); + return -1; + } + dport->len = strlen(dport->buf); + + return 0; +} + +static int +setvarbuf(buf, off, ebuf, elen, vbuf, vlen) + char *buf; + int *off; + struct sadb_ext *ebuf; + int elen; + const void *vbuf; + int vlen; +{ + memset(buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len)); + memcpy(buf + *off, (caddr_t)ebuf, elen); + memcpy(buf + *off + elen, vbuf, vlen); + (*off) += PFKEY_ALIGN8(elen + vlen); + + return 0; +} + +void +parse_init() +{ + p_spi = 0; + + p_ext = SADB_X_EXT_CYCSEQ; + p_alg_enc = SADB_EALG_NONE; + p_alg_auth = SADB_AALG_NONE; + p_mode = IPSEC_MODE_ANY; + p_reqid = 0; + p_replay = 0; + p_key_enc_len = p_key_auth_len = 0; + p_key_enc = p_key_auth = 0; + p_lt_hard = p_lt_soft = 0; + p_lb_hard = p_lb_soft = 0; + + p_aiflags = 0; + p_aifamily = PF_UNSPEC; + + /* Clear out any natt OA information */ + if (p_natt_oa) + freeaddrinfo (p_natt_oa); + p_natt_oa = NULL; + p_natt_type = 0; + + return; +} + +void +free_buffer() +{ + /* we got tons of memory leaks in the parser anyways, leave them */ + + return; +} diff --git a/ipsec-tools/setkey/scriptdump.pl b/ipsec-tools/setkey/scriptdump.pl new file mode 100644 index 0000000..f5b9f25 --- /dev/null +++ b/ipsec-tools/setkey/scriptdump.pl @@ -0,0 +1,55 @@ +#! @LOCALPREFIX@/bin/perl + +if ($< != 0) { + print STDERR "must be root to invoke this\n"; + exit 1; +} + +$mode = 'add'; +while ($i = shift @ARGV) { + if ($i eq '-d') { + $mode = 'delete'; + } else { + print STDERR "usage: scriptdump [-d]\n"; + exit 1; + } +} + +open(IN, "setkey -D |") || die; +foreach $_ () { + if (/^[^\t]/) { + ($src, $dst) = split(/\s+/, $_); + } elsif (/^\t(esp|ah) mode=(\S+) spi=(\d+).*reqid=(\d+)/) { + ($proto, $ipsecmode, $spi, $reqid) = ($1, $2, $3, $4); + } elsif (/^\tE: (\S+) (.*)/) { + $ealgo = $1; + $ekey = $2; + $ekey =~ s/\s//g; + $ekey =~ s/^/0x/g; + } elsif (/^\tA: (\S+) (.*)/) { + $aalgo = $1; + $akey = $2; + $akey =~ s/\s//g; + $akey =~ s/^/0x/g; + } elsif (/^\tseq=(0x\d+) replay=(\d+) flags=(0x\d+) state=/) { + print "$mode $src $dst $proto $spi"; + $replay = $2; + print " -u $reqid" if $reqid; + if ($mode eq 'add') { + print " -m $ipsecmode -r $replay" if $replay; + if ($proto eq 'esp') { + print " -E $ealgo $ekey" if $ealgo; + print " -A $aalgo $akey" if $aalgo; + } elsif ($proto eq 'ah') { + print " -A $aalgo $akey" if $aalgo; + } + } + print ";\n"; + + $src = $dst = $upper = $proxy = ''; + $ealgo = $ekey = $aalgo = $akey = ''; + } +} +close(IN); + +exit 0; diff --git a/ipsec-tools/setkey/setkey.8 b/ipsec-tools/setkey/setkey.8 new file mode 100644 index 0000000..3a87ac1 --- /dev/null +++ b/ipsec-tools/setkey/setkey.8 @@ -0,0 +1,828 @@ +.\" $NetBSD: setkey.8,v 1.17 2005/09/15 08:42:09 wiz Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 19, 2004 +.Dt SETKEY 8 +.Os +.\" +.Sh NAME +.Nm setkey +.Nd manually manipulate the IPsec SA/SP database +.\" +.Sh SYNOPSIS +.Nm setkey +.Op Fl knrv +.Ar file ... +.Nm setkey +.Op Fl knrv +.Fl c +.Nm setkey +.Op Fl krv +.Fl f Ar filename +.Nm setkey +.Op Fl aklPrv +.Fl D +.Nm setkey +.Op Fl Pvp +.Fl F +.Nm setkey +.Op Fl H +.Fl x +.Nm setkey +.Op Fl ?V +.\" +.Sh DESCRIPTION +.Nm +adds, updates, dumps, or flushes +Security Association Database (SAD) entries +as well as Security Policy Database (SPD) entries in the kernel. +.Pp +.Nm +takes a series of operations from standard input +.Po +if invoked with +.Fl c +.Pc +or the file named +.Ar filename +.Po +if invoked with +.Fl f Ar filename +.Pc . +.Bl -tag -width Ds +.It (no flag) +Dump the SAD entries or SPD entries contained in the specified +.Ar file . +.It Fl ? +Print short help. +.It Fl a +.Nm +usually does not display dead SAD entries with +.Fl D . +If +.Fl a +is also specified, the dead SAD entries will be displayed as well. +A dead SAD entry is one that has expired but remains in the +system because it is referenced by some SPD entries. +.It Fl D +Dump the SAD entries. +If +.Fl P +is also specified, the SPD entries are dumped. +If +.Fl p +is specified, the ports are displayed. +.It Fl F +Flush the SAD entries. +If +.Fl P +is also specified, the SPD entries are flushed. +.It Fl H +Add hexadecimal dump in +.Fl x +mode. +.It Fl h +On +.Nx , +synonym for +.Fl H . +On other systems, synonym for +.Fl ? . +.It Fl k +Use semantics used in kernel. +Available only in Linux. +See also +.Fl r . +.It Fl l +Loop forever with short output on +.Fl D . +.It Fl n +No action. +The program will check validity of the input, but no changes to +the SPD will be made. +.It Fl r +Use semantics described in IPsec RFCs. +This mode is default. +For details see section +.Sx RFC vs Linux kernel semantics . +Available only in Linux. +See also +.Fl k . +.It Fl x +Loop forever and dump all the messages transmitted to the +.Dv PF_KEY +socket. +.Fl xx +prints the unformatted timestamps. +.It Fl V +Print version string. +.It Fl v +Be verbose. +The program will dump messages exchanged on the +.Dv PF_KEY +socket, including messages sent from other processes to the kernel. +.El +.Ss Configuration syntax +With +.Fl c +or +.Fl f +on the command line, +.Nm +accepts the following configuration syntax. +Lines starting with hash signs +.Pq Sq # +are treated as comment lines. +.Bl -tag -width Ds +.It Xo +.Li add +.Op Fl 46n +.Ar src Ar dst Ar protocol Ar spi +.Op Ar extensions +.Ar algorithm ... +.Li ; +.Xc +Add an SAD entry. +.Li add +can fail for multiple reasons, including when the key length does +not match the specified algorithm. +.\" +.It Xo +.Li get +.Op Fl 46n +.Ar src Ar dst Ar protocol Ar spi +.Li ; +.Xc +Show an SAD entry. +.\" +.It Xo +.Li delete +.Op Fl 46n +.Ar src Ar dst Ar protocol Ar spi +.Li ; +.Xc +Remove an SAD entry. +.\" +.It Xo +.Li deleteall +.Op Fl 46n +.Ar src Ar dst Ar protocol +.Li ; +.Xc +Remove all SAD entries that match the specification. +.\" +.It Xo +.Li flush +.Op Ar protocol +.Li ; +.Xc +Clear all SAD entries matched by the options. +.Fl F +on the command line achieves the same functionality. +.\" +.It Xo +.Li dump +.Op Ar protocol +.Li ; +.Xc +Dumps all SAD entries matched by the options. +.Fl D +on the command line achieves the same functionality. +.\" +.It Xo +.Li spdadd +.Op Fl 46n +.Ar src_range Ar dst_range Ar upperspec Ar policy +.Li ; +.Xc +Add an SPD entry. +.\" +.It Xo +.Li spdadd tagged +.Ar tag Ar policy +.Li ; +.Xc +Add an SPD entry based on a PF tag. +.Ar tag +must be a string surrounded by double quotes. +.\" +.It Xo +.Li spddelete +.Op Fl 46n +.Ar src_range Ar dst_range Ar upperspec Fl P Ar direction +.Li ; +.Xc +Delete an SPD entry. +.\" +.It Xo +.Li spdflush +.Li ; +.Xc +Clear all SPD entries. +.Fl FP +on the command line achieves the same functionality. +.\" +.It Xo +.Li spddump +.Li ; +.Xc +Dumps all SPD entries. +.Fl DP +on the command line achieves the same functionality. +.El +.\" +.Pp +Meta-arguments are as follows: +.Pp +.Bl -tag -compact -width Ds +.It Ar src +.It Ar dst +Source/destination of the secure communication is specified as +an IPv4/v6 address, and an optional port number between square +brackets. +.Nm +can resolve a FQDN into numeric addresses. +If the FQDN resolves into multiple addresses, +.Nm +will install multiple SAD/SPD entries into the kernel +by trying all possible combinations. +.Fl 4 , +.Fl 6 , +and +.Fl n +restrict the address resolution of FQDN in certain ways. +.Fl 4 +and +.Fl 6 +restrict results into IPv4/v6 addresses only, respectively. +.Fl n +avoids FQDN resolution and requires addresses to be numeric addresses. +.\" +.Pp +.It Ar protocol +.Ar protocol +is one of following: +.Bl -tag -width Fl -compact +.It Li esp +ESP based on rfc2406 +.It Li esp-old +ESP based on rfc1827 +.It Li ah +AH based on rfc2402 +.It Li ah-old +AH based on rfc1826 +.It Li ipcomp +IPComp +.It Li tcp +TCP-MD5 based on rfc2385 +.El +.\" +.Pp +.It Ar spi +Security Parameter Index +.Pq SPI +for the SAD and the SPD. +.Ar spi +must be a decimal number, or a hexadecimal number with a +.Dq Li 0x +prefix. +SPI values between 0 and 255 are reserved for future use by IANA +and cannot be used. +TCP-MD5 associations must use 0x1000 and therefore only have per-host +granularity at this time. +.\" +.Pp +.It Ar extensions +take some of the following: +.Bl -tag -width Fl -compact +.\" +.It Fl m Ar mode +Specify a security protocol mode for use. +.Ar mode +is one of following: +.Li transport , tunnel , +or +.Li any . +The default value is +.Li any . +.\" +.It Fl r Ar size +Specify window size of bytes for replay prevention. +.Ar size +must be decimal number in 32-bit word. +If +.Ar size +is zero or not specified, replay checks don't take place. +.\" +.It Fl u Ar id +Specify the identifier of the policy entry in the SPD. +See +.Ar policy . +.\" +.It Fl f Ar pad_option +defines the content of the ESP padding. +.Ar pad_option +is one of following: +.Bl -tag -width random-pad -compact +.It Li zero-pad +All the paddings are zero. +.It Li random-pad +A series of randomized values are used. +.It Li seq-pad +A series of sequential increasing numbers started from 1 are used. +.El +.\" +.It Fl f Li nocyclic-seq +Don't allow cyclic sequence numbers. +.\" +.It Fl lh Ar time +.It Fl ls Ar time +Specify hard/soft life time duration of the SA measured in seconds. +.\" +.It Fl bh Ar bytes +.It Fl bs Ar bytes +Specify hard/soft life time duration of the SA measured in bytes transported. +.El +.\" +.Pp +.It Ar algorithm +.Bl -tag -width Fl -compact +.It Fl E Ar ealgo Ar key +Specify an encryption algorithm +.Ar ealgo +for ESP. +.It Xo +.Fl E Ar ealgo Ar key +.Fl A Ar aalgo Ar key +.Xc +Specify an encryption algorithm +.Ar ealgo , +as well as a payload authentication algorithm +.Ar aalgo , +for ESP. +.It Fl A Ar aalgo Ar key +Specify an authentication algorithm for AH. +.It Fl C Ar calgo Op Fl R +Specify a compression algorithm for IPComp. +If +.Fl R +is specified, the +.Ar spi +field value will be used as the IPComp CPI +.Pq compression parameter index +on wire as-is. +If +.Fl R +is not specified, +the kernel will use well-known CPI on wire, and +.Ar spi +field will be used only as an index for kernel internal usage. +.El +.Pp +.Ar key +must be a double-quoted character string, or a series of hexadecimal +digits preceded by +.Dq Li 0x . +.Pp +Possible values for +.Ar ealgo , +.Ar aalgo , +and +.Ar calgo +are specified in the +.Sx Algorithms +sections. +.\" +.Pp +.It Ar src_range +.It Ar dst_range +These select the communications that should be secured by IPsec. +They can be an IPv4/v6 address or an IPv4/v6 address range, and +may be accompanied by a TCP/UDP port specification. +This takes the following form: +.Bd -literal -offset +.Ar address +.Ar address/prefixlen +.Ar address[port] +.Ar address/prefixlen[port] +.Ed +.Pp +.Ar prefixlen +and +.Ar port +must be decimal numbers. +The square brackets around +.Ar port +are really necessary, +they are not man page meta-characters. +For FQDN resolution, the rules applicable to +.Ar src +and +.Ar dst +apply here as well. +.\" +.Pp +.It Ar upperspec +Upper-layer protocol to be used. +You can use one of the words in +.Pa /etc/protocols +as +.Ar upperspec , +or +.Li icmp6 , +.Li ip4 , +or +.Li any . +.Li any +stands for +.Dq any protocol . +You can also use the protocol number. +You can specify a type and/or a code of ICMPv6 when the +upper-layer protocol is ICMPv6. +The specification can be placed after +.Li icmp6 . +A type is separated from a code by single comma. +A code must always be specified. +When a zero is specified, the kernel deals with it as a wildcard. +Note that the kernel can not distinguish a wildcard from an ICPMv6 +type of zero. +For example, the following means that the policy doesn't require IPsec +for any inbound Neighbor Solicitation. +.Dl spdadd ::/0 ::/0 icmp6 135,0 -P in none ; +.Pp +.Em Note : +.Ar upperspec +does not work against forwarding case at this moment, +as it requires extra reassembly at the forwarding node +.Pq not implemented at this moment . +There are many protocols in +.Pa /etc/protocols , +but all protocols except of TCP, UDP, and ICMP may not be suitable +to use with IPsec. +You have to consider carefully what to use. +.\" +.Pp +.It Ar policy +.Ar policy +is in one of the following three formats: +.Bd -literal -offset indent +.It Fl P Ar direction [priority specification] Li discard +.It Fl P Ar direction [priority specification] Li none +.It Xo Fl P Ar direction [priority specification] Li ipsec +.Ar protocol/mode/src-dst/level Op ... +.Xc +.Ed +.Pp +You must specify the direction of its policy as +.Ar direction . +Either +.Ar out , +.Ar in , +or +.Ar fwd +can be used. +.Pp +.Ar priority specification +is used to control the placement of the policy within the SPD. +Policy position is determined by +a signed integer where higher priorities indicate the policy is placed +closer to the beginning of the list and lower priorities indicate the +policy is placed closer to the end of the list. +Policies with equal priorities are added at the end of groups +of such policies. +.Pp +Priority can only +be specified when setkey has been compiled against kernel headers that +support policy priorities (Linux \*[Gt]= 2.6.6). +If the kernel does not support priorities, a warning message will +be printed the first time a priority specification is used. +Policy priority takes one of the following formats: +.Bl -tag -width "discard" +.It Xo +.Ar {priority,prio} offset +.Xc +.Ar offset +is an integer in the range from \-2147483647 to 214783648. +.It Xo +.Ar {priority,prio} base {+,\-} offset +.Xc +.Ar base +is either +.Li low (\-1073741824) , +.Li def (0) , +or +.Li high (1073741824) +.Pp +.Ar offset +is an unsigned integer. +It can be up to 1073741824 for +positive offsets, and up to 1073741823 for negative offsets. +.El +.Pp +.Li discard +means the packet matching indexes will be discarded. +.Li none +means that IPsec operation will not take place onto the packet. +.Li ipsec +means that IPsec operation will take place onto the packet. +.Pp +The +.Ar protocol/mode/src-dst/level +part specifies the rule how to process the packet. +Either +.Li ah , +.Li esp , +or +.Li ipcomp +must be used as +.Ar protocol . +.Ar mode +is either +.Li transport +or +.Li tunnel . +If +.Ar mode +is +.Li tunnel , +you must specify the end-point addresses of the SA as +.Ar src +and +.Ar dst +with +.Sq - +between these addresses, which is used to specify the SA to use. +If +.Ar mode +is +.Li transport , +both +.Ar src +and +.Ar dst +can be omitted. +.Ar level +is to be one of the following: +.Li default , use , require , +or +.Li unique . +If the SA is not available in every level, the kernel will +ask the key exchange daemon to establish a suitable SA. +.Li default +means the kernel consults the system wide default for the protocol +you specified, e.g. the +.Li esp_trans_deflev +sysctl variable, when the kernel processes the packet. +.Li use +means that the kernel uses an SA if it's available, +otherwise the kernel keeps normal operation. +.Li require +means SA is required whenever the kernel sends a packet matched +with the policy. +.Li unique +is the same as +.Li require ; +in addition, it allows the policy to match the unique out-bound SA. +You just specify the policy level +.Li unique , +.Xr racoon 8 +will configure the SA for the policy. +If you configure the SA by manual keying for that policy, +you can put a decimal number as the policy identifier after +.Li unique +separated by a colon +.Sq \&: +like: +.Li unique:number +in order to bind this policy to the SA. +.Li number +must be between 1 and 32767. +It corresponds to +.Ar extensions Fl u +of the manual SA configuration. +When you want to use SA bundle, you can define multiple rules. +For example, if an IP header was followed by an AH header followed +by an ESP header followed by an upper layer protocol header, the +rule would be: +.Dl esp/transport//require ah/transport//require ; +The rule order is very important. +.Pp +When NAT-T is enabled in the kernel, policy matching for ESP over +UDP packets may be done on endpoint addresses and port +(this depends on the system. +System that do not perform the port check cannot support +multiple endpoints behind the same NAT). +When using ESP over UDP, you can specify port numbers in the endpoint +addresses to get the correct matching. +Here is an example: +.Bd -literal -offset +spdadd 10.0.11.0/24[any] 10.0.11.33/32[any] any -P out ipsec + esp/tunnel/192.168.0.1[4500]-192.168.1.2[30000]/require ; + +.Ed +These ports must be left unspecified (which defaults to 0) for +anything other than ESP over UDP. +They can be displayed in SPD dump using +.Nm +.Fl DPp . +.Pp +Note that +.Dq Li discard +and +.Dq Li none +are not in the syntax described in +.Xr ipsec_set_policy 3 . +There are a few differences in the syntax. +See +.Xr ipsec_set_policy 3 +for detail. +.El +.\" +.Ss Algorithms +The following list shows the supported algorithms. +.Sy protocol +and +.Sy algorithm +are almost orthogonal. +These authentication algorithms can be used as +.Ar aalgo +in +.Fl A Ar aalgo +of the +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) +hmac-md5 128 ah: rfc2403 + 128 ah-old: rfc2085 +hmac-sha1 160 ah: rfc2404 + 160 ah-old: 128bit ICV (no document) +keyed-md5 128 ah: 96bit ICV (no document) + 128 ah-old: rfc1828 +keyed-sha1 160 ah: 96bit ICV (no document) + 160 ah-old: 128bit ICV (no document) +null 0 to 2048 for debugging +hmac-sha256 256 ah: 96bit ICV + (draft-ietf-ipsec-ciph-sha-256-00) + 256 ah-old: 128bit ICV (no document) +hmac-sha384 384 ah: 96bit ICV (no document) + 384 ah-old: 128bit ICV (no document) +hmac-sha512 512 ah: 96bit ICV (no document) + 512 ah-old: 128bit ICV (no document) +hmac-ripemd160 160 ah: 96bit ICV (RFC2857) + ah-old: 128bit ICV (no document) +aes-xcbc-mac 128 ah: 96bit ICV (RFC3566) + 128 ah-old: 128bit ICV (no document) +tcp-md5 8 to 640 tcp: rfc2385 +.Ed +.Pp +These encryption algorithms can be used as +.Ar ealgo +in +.Fl E Ar ealgo +of the +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) +des-cbc 64 esp-old: rfc1829, esp: rfc2405 +3des-cbc 192 rfc2451 +null 0 to 2048 rfc2410 +blowfish-cbc 40 to 448 rfc2451 +cast128-cbc 40 to 128 rfc2451 +des-deriv 64 ipsec-ciph-des-derived-01 +3des-deriv 192 no document +rijndael-cbc 128/192/256 rfc3602 +twofish-cbc 0 to 256 draft-ietf-ipsec-ciph-aes-cbc-01 +aes-ctr 160/224/288 draft-ietf-ipsec-ciph-aes-ctr-03 +.Ed +.Pp +Note that the first 128 bits of a key for +.Li aes-ctr +will be used as AES key, and the remaining 32 bits will be used as nonce. +.Pp +These compression algorithms can be used as +.Ar calgo +in +.Fl C Ar calgo +of the +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm +deflate rfc2394 +.Ed +.\" +.Ss RFC vs Linux kernel semantics +The Linux kernel uses the +.Ar fwd +policy instead of the +.Ar in +policy for packets what are forwarded through that particular box. +.Pp +In +.Ar kernel +mode, +.Nm +manages and shows policies and SAs exactly as they are stored in the kernel. +.Pp +In +.Ar RFC +mode, +.Nm +.Bl -item +.It +creates +.Ar fwd +policies for every +.Ar in +policy inserted +.It +(not implemented yet) filters out all +.Ar fwd +policies +.El +.Sh RETURN VALUES +The command exits with 0 on success, and non-zero on errors. +.\" +.Sh EXAMPLES +.Bd -literal -offset +add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457 + -E des-cbc 0x3ffe05014819ffff ; + +add -6 myhost.example.com yourhost.example.com ah 123456 + -A hmac-sha1 "AH SA configuration!" ; + +add 10.0.11.41 10.0.11.33 esp 0x10001 + -E des-cbc 0x3ffe05014819ffff + -A hmac-md5 "authentication!!" ; + +get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ; + +flush ; + +dump esp ; + +spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any + -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ; + +add 10.1.10.34 10.1.10.36 tcp 0x1000 -A tcp-md5 "TCP-MD5 BGP secret" ; +.Ed +.\" +.Sh SEE ALSO +.Xr ipsec_set_policy 3 , +.Xr racoon 8 , +.Xr sysctl 8 +.Rs +.%T "Changed manual key configuration for IPsec" +.%O "http://www.kame.net/newsletter/19991007/" +.%D "October 1999" +.Re +.\" +.Sh HISTORY +The +.Nm +command first appeared in the WIDE Hydrangea IPv6 protocol stack +kit. +The command was completely re-designed in June 1998. +.\" +.Sh BUGS +.Nm +should report and handle syntax errors better. +.Pp +For IPsec gateway configuration, +.Ar src_range +and +.Ar dst_range +with TCP/UDP port numbers does not work, as the gateway does not +reassemble packets +.Pq it cannot inspect upper-layer headers . diff --git a/ipsec-tools/setkey/setkey.c b/ipsec-tools/setkey/setkey.c new file mode 100644 index 0000000..1c9445f --- /dev/null +++ b/ipsec-tools/setkey/setkey.c @@ -0,0 +1,908 @@ +/* $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_READLINE +#include +#include +#endif + +#include "config.h" +#include "libpfkey.h" +//#include "package_version.h" +#define extern /* so that variables in extern.h are not extern... */ +#include "extern.h" + +#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0') + +void usage __P((/*int*/)); +int main __P((int, char **)); +int get_supported __P((void)); +void sendkeyshort __P((u_int)); +void promisc __P((void)); +int postproc __P((struct sadb_msg *, int)); +int verifypriority __P((struct sadb_msg *m)); +int fileproc __P((const char *)); +const char *numstr __P((int)); +void shortdump_hdr __P((void)); +void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); +void stdin_loop __P((void)); + +#define MODE_SCRIPT 1 +#define MODE_CMDDUMP 2 +#define MODE_CMDFLUSH 3 +#define MODE_PROMISC 4 +#define MODE_STDIN 5 + +int so; + +int f_forever = 0; +int f_all = 0; +int f_verbose = 0; +int f_mode = 0; +int f_cmddump = 0; +int f_policy = 0; +int f_hexdump = 0; +int f_tflag = 0; +int f_notreally = 0; +int f_withports = 0; +#ifdef HAVE_POLICY_FWD +int f_rfcmode = 1; +#define RK_OPTS "rk" +#else +int f_rkwarn = 0; +#define RK_OPTS "" +static void rkwarn(void); +static void +rkwarn(void) +{ + if (!f_rkwarn) { + f_rkwarn = 1; + printf("warning: -r and -k options are not supported in this environment\n"); + } +} + +#endif +static time_t thiszone; + +void +usage(/*int only_version*/) +{ + //printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL); + //if (! only_version) { + printf("usage: setkey [-v" RK_OPTS "] file ...\n"); + printf(" setkey [-nv" RK_OPTS "] -c\n"); + printf(" setkey [-nv" RK_OPTS "] -f filename\n"); + printf(" setkey [-Palpv" RK_OPTS "] -D\n"); + printf(" setkey [-Pv] -F\n"); + printf(" setkey [-H] -x\n"); + printf(" setkey [-V] [-h]\n"); + //} + exit(1); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + FILE *fp = stdin; + int c; + + if (argc == 1) { + usage(0); + /* NOTREACHED */ + } + + thiszone = gmt2local(0); + + while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) { + switch (c) { + case 'c': + f_mode = MODE_STDIN; +#ifdef HAVE_READLINE + /* disable filename completion */ + rl_bind_key('\t', rl_insert); +#endif + break; + case 'f': + f_mode = MODE_SCRIPT; + if ((fp = fopen(optarg, "r")) == NULL) { + err(1, "fopen"); + /*NOTREACHED*/ + } + break; + case 'D': + f_mode = MODE_CMDDUMP; + break; + case 'F': + f_mode = MODE_CMDFLUSH; + break; + case 'a': + f_all = 1; + break; + case 'l': + f_forever = 1; + break; + case 'n': + f_notreally = 1; + break; +#ifdef __NetBSD__ + case 'h': +#endif + case 'H': + f_hexdump = 1; + break; + case 'x': + f_mode = MODE_PROMISC; + f_tflag++; + break; + case 'P': + f_policy = 1; + break; + case 'p': + f_withports = 1; + break; + case 'v': + f_verbose = 1; + break; + case 'r': +#ifdef HAVE_POLICY_FWD + f_rfcmode = 1; +#else + rkwarn(); +#endif + break; + case 'k': +#ifdef HAVE_POLICY_FWD + f_rfcmode = 0; +#else + rkwarn(); +#endif + break; + case 'V': + usage(1); + break; + /*NOTREACHED*/ +#ifndef __NetBSD__ + case 'h': +#endif + case '?': + default: + usage(0); + /*NOTREACHED*/ + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + while (argc--) + if (fileproc(*argv++) < 0) { + err(1, "%s", argv[-1]); + /*NOTREACHED*/ + } + exit(0); + } + + so = pfkey_open(); + if (so < 0) { + perror("pfkey_open"); + exit(1); + } + + switch (f_mode) { + case MODE_CMDDUMP: + sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP); + break; + case MODE_CMDFLUSH: + sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); + break; + case MODE_SCRIPT: + if (get_supported() < 0) { + errx(1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + if (parse(&fp)) + exit (1); + break; + case MODE_STDIN: + if (get_supported() < 0) { + errx(1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + stdin_loop(); + break; + case MODE_PROMISC: + promisc(); + /*NOTREACHED*/ + default: + usage(0); + /*NOTREACHED*/ + } + + exit(0); +} + +int +get_supported() +{ + + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) + return -1; + + if (pfkey_recv_register(so) < 0) + return -1; + + return (0); +} + +void +stdin_loop() +{ + char line[1024], *semicolon, *comment; + size_t linelen = 0; + + memset (line, 0, sizeof(line)); + + parse_init(); + while (1) { +#ifdef HAVE_READLINE + char *rbuf; + rbuf = readline (""); + if (! rbuf) + break; +#else + char rbuf[1024]; + rbuf[0] = '\0'; + fgets (rbuf, sizeof(rbuf), stdin); + if (!rbuf[0]) + break; + if (rbuf[strlen(rbuf)-1] == '\n') + rbuf[strlen(rbuf)-1] = '\0'; +#endif + comment = strchr(rbuf, '#'); + if (comment) + *comment = '\0'; + + if (!rbuf[0]) + continue; + + linelen += snprintf (&line[linelen], sizeof(line) - linelen, + "%s%s", linelen > 0 ? " " : "", rbuf); + + semicolon = strchr(line, ';'); + while (semicolon) { + char saved_char = *++semicolon; + *semicolon = '\0'; +#ifdef HAVE_READLINE + add_history (line); +#endif + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + last_msg_type = -1; /* invalid message type */ +#endif + + parse_string (line); + if (exit_now) + return; + if (saved_char) { + *semicolon = saved_char; + linelen = strlen (semicolon); + memmove (line, semicolon, linelen + 1); + semicolon = strchr(line, ';'); + } + else { + semicolon = NULL; + linelen = 0; + } + } + } +} + +void +sendkeyshort(type) + u_int type; +{ + struct sadb_msg msg; + + msg.sadb_msg_version = PF_KEY_V2; + msg.sadb_msg_type = type; + msg.sadb_msg_errno = 0; + msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); + msg.sadb_msg_reserved = 0; + msg.sadb_msg_seq = 0; + msg.sadb_msg_pid = getpid(); + + sendkeymsg((char *)&msg, sizeof(msg)); + + return; +} + +void +promisc() +{ + struct sadb_msg msg; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + ssize_t l; + + msg.sadb_msg_version = PF_KEY_V2; + msg.sadb_msg_type = SADB_X_PROMISC; + msg.sadb_msg_errno = 0; + msg.sadb_msg_satype = 1; + msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); + msg.sadb_msg_reserved = 0; + msg.sadb_msg_seq = 0; + msg.sadb_msg_pid = getpid(); + + if ((l = send(so, &msg, sizeof(msg), 0)) < 0) { + err(1, "send"); + /*NOTREACHED*/ + } + + while (1) { + struct sadb_msg *base; + + if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + + if (l != sizeof(*base)) + continue; + + base = (struct sadb_msg *)rbuf; + if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), + 0)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + printdate(); + if (f_hexdump) { + int i; + for (i = 0; i < l; i++) { + if (i % 16 == 0) + printf("%08x: ", i); + printf("%02x ", rbuf[i] & 0xff); + if (i % 16 == 15) + printf("\n"); + } + if (l % 16) + printf("\n"); + } + /* adjust base pointer for promisc mode */ + if (base->sadb_msg_type == SADB_X_PROMISC) { + if ((ssize_t)sizeof(*base) < l) + base++; + else + base = NULL; + } + if (base) { + kdebug_sadb(base); + printf("\n"); + fflush(stdout); + } + } +} + +int +sendkeymsg(buf, len) + char *buf; + size_t len; +{ + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + ssize_t l; + struct sadb_msg *msg; + + if (f_notreally) { + goto end; + } + + { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); + goto end; + } + } + + if (f_forever) + shortdump_hdr(); +again: + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)buf); + printf("\n"); + } + if (f_hexdump) { + int i; + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("%08x: ", i); + printf("%02x ", buf[i] & 0xff); + if (i % 16 == 15) + printf("\n"); + } + if (len % 16) + printf("\n"); + } + + if ((l = send(so, buf, len, 0)) < 0) { + perror("send"); + goto end; + } + + msg = (struct sadb_msg *)rbuf; + do { + if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { + perror("recv"); + goto end; + } + + if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) { + warnx("invalid keymsg length"); + break; + } + + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)rbuf); + printf("\n"); + } + if (postproc(msg, l) < 0) + break; + } while (msg->sadb_msg_errno || msg->sadb_msg_seq); + + if (f_forever) { + fflush(stdout); + sleep(1); + goto again; + } + +end: + return (0); +} + +int +postproc(msg, len) + struct sadb_msg *msg; + int len; +{ +#ifdef HAVE_PFKEY_POLICY_PRIORITY + static int priority_support_check = 0; +#endif + + if (msg->sadb_msg_errno != 0) { + char inf[80]; + const char *errmsg = NULL; + + if (f_mode == MODE_SCRIPT) + snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); + else + inf[0] = '\0'; + + switch (msg->sadb_msg_errno) { + case ENOENT: + switch (msg->sadb_msg_type) { + case SADB_DELETE: + case SADB_GET: + case SADB_X_SPDDELETE: + errmsg = "No entry"; + break; + case SADB_DUMP: + errmsg = "No SAD entries"; + break; + case SADB_X_SPDDUMP: + errmsg = "No SPD entries"; + break; + } + break; + default: + errmsg = strerror(msg->sadb_msg_errno); + } + printf("%s%s.\n", inf, errmsg); + return (-1); + } + + switch (msg->sadb_msg_type) { + case SADB_GET: + if (f_withports) + pfkey_sadump_withports(msg); + else + pfkey_sadump(msg); + break; + + case SADB_DUMP: + /* filter out DEAD SAs */ + if (!f_all) { + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *sa; + pfkey_align(msg, mhp); + pfkey_check(mhp); + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + if (sa->sadb_sa_state == SADB_SASTATE_DEAD) + break; + } + } + if (f_forever) { + /* TODO: f_withports */ + shortdump(msg); + } else { + if (f_withports) + pfkey_sadump_withports(msg); + else + pfkey_sadump(msg); + } + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + break; + + case SADB_X_SPDGET: + if (f_withports) + pfkey_spdump_withports(msg); + else + pfkey_spdump(msg); + break; + + case SADB_X_SPDDUMP: + if (f_withports) + pfkey_spdump_withports(msg); + else + pfkey_spdump(msg); + if (msg->sadb_msg_seq == 0) break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + break; +#ifdef HAVE_PFKEY_POLICY_PRIORITY + case SADB_X_SPDADD: + if (last_msg_type == SADB_X_SPDADD && last_priority != 0 && + msg->sadb_msg_pid == getpid() && !priority_support_check) { + priority_support_check = 1; + if (!verifypriority(msg)) + printf ("WARNING: Kernel does not support policy priorities\n"); + } + break; +#endif + } + + return (0); +} + +#ifdef HAVE_PFKEY_POLICY_PRIORITY +int +verifypriority(m) + struct sadb_msg *m; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_x_policy *xpl; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("(%s\n", ipsec_strerror()); + return 0; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return 0; + } + + xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY]; + + if (xpl == NULL) { + printf("no X_POLICY extension.\n"); + return 0; + } + + /* now make sure they match */ + if (last_priority != xpl->sadb_x_policy_priority) + return 0; + + return 1; +} +#endif + +int +fileproc(filename) + const char *filename; +{ + int fd; + ssize_t len, l; + u_char *p, *ep; + struct sadb_msg *msg; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + l = 0; + while (1) { + len = read(fd, rbuf + l, sizeof(rbuf) - l); + if (len < 0) { + close(fd); + return -1; + } else if (len == 0) + break; + l += len; + } + + if (l < sizeof(struct sadb_msg)) { + close(fd); + errno = EINVAL; + return -1; + } + close(fd); + + p = rbuf; + ep = rbuf + l; + + while (p < ep) { + msg = (struct sadb_msg *)p; + len = PFKEY_UNUNIT64(msg->sadb_msg_len); + postproc(msg, len); + p += len; + } + + return (0); +} + + +/*------------------------------------------------------------*/ +static const char *satype[] = { + NULL, NULL, "ah", "esp" +}; +static const char *sastate[] = { + "L", "M", "D", "d" +}; +static const char *ipproto[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + NULL, "tcp", NULL, "egp", NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "udp", NULL, NULL, +/*20*/ NULL, NULL, "idp", NULL, NULL, + NULL, NULL, NULL, NULL, "tp", +/*30*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, +/*40*/ NULL, "ip6", NULL, "rt6", "frag6", + NULL, "rsvp", "gre", NULL, NULL, +/*50*/ "esp", "ah", NULL, NULL, NULL, + NULL, NULL, NULL, "icmp6", "none", +/*60*/ "dst6", +}; + +#define STR_OR_ID(x, tab) \ + (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) + +const char * +numstr(x) + int x; +{ + static char buf[20]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +shortdump_hdr() +{ + printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", + "time", "p", "s", "spi", "ltime", "src", "dst"); +} + +void +shortdump(msg) + struct sadb_msg *msg; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + char buf[NI_MAXHOST], pbuf[NI_MAXSERV]; + struct sadb_sa *sa; + struct sadb_address *saddr; + struct sadb_lifetime *lts, *lth, *ltc; + struct sockaddr *s; + u_int t; + time_t cur = time(0); + + pfkey_align(msg, mhp); + pfkey_check(mhp); + + printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); + + printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); + + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); + printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); + } else + printf("%-1s %-8s", "?", "?"); + + lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + if (lts && lth && ltc) { + if (ltc->sadb_lifetime_addtime == 0) + t = (u_long)0; + else + t = (u_long)(cur - ltc->sadb_lifetime_addtime); + if (t >= 1000) + strlcpy(buf, " big/", sizeof(buf)); + else + snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); + printf("%s", buf); + + t = (u_long)lth->sadb_lifetime_addtime; + if (t >= 1000) + strlcpy(buf, "big", sizeof(buf)); + else + snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); + printf("%s", buf); + } else + printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ + + printf(" "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf(" -> "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf("\n"); +} + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} diff --git a/ipsec-tools/setkey/test-pfkey.c b/ipsec-tools/setkey/test-pfkey.c new file mode 100644 index 0000000..fb80000 --- /dev/null +++ b/ipsec-tools/setkey/test-pfkey.c @@ -0,0 +1,571 @@ +/* $KAME: test-pfkey.c,v 1.4 2000/06/07 00:29:14 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +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 + 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: + /**/ + 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(); + /**/ + break; + + case SADB_ADD: + /* */ + 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(); + /* */ + break; + + case SADB_DELETE: + /* */ + 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"); + /* */ + break; + + case SADB_GET: + /* */ + 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"); + /* */ + break; + + case SADB_ACQUIRE: + /* */ + 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(); + /* */ + break; + + case SADB_REGISTER: + /* */ + /* */ + break; + + case SADB_EXPIRE: + case SADB_FLUSH: + break; + + case SADB_DUMP: + break; + + case SADB_X_PROMISC: + /* */ + /* */ + break; + + case SADB_X_PCHANGE: + break; + + /* for SPD management */ + case SADB_X_SPDFLUSH: + case SADB_X_SPDDUMP: + break; + + case SADB_X_SPDADD: +#if 0 + { + struct sadb_x_policy m_policy; + + m_policy.sadb_x_policy_len = PFKEY_UNIT64(sizeof(m_policy)); + m_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + m_policy.sadb_x_policy_type = SADB_X_PL_IPSEC; + m_policy.sadb_x_policy_esp_trans = 1; + m_policy.sadb_x_policy_ah_trans = 2; + m_policy.sadb_x_policy_esp_network = 3; + m_policy.sadb_x_policy_ah_network = 4; + m_policy.sadb_x_policy_reserved = 0; + + memcpy(m_buf + m_len, &m_policy, sizeof(struct sadb_x_policy)); + m_len += sizeof(struct sadb_x_policy); + } +#endif + + case SADB_X_SPDDELETE: + key_setsadbaddr(SADB_EXT_ADDRESS_SRC, AF_INET, "192.168.1.1"); + key_setsadbaddr(SADB_EXT_ADDRESS_DST, AF_INET, "10.0.3.4"); + break; + } + + ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len); + + return; +} + +void +key_setsadbsens() +{ + struct sadb_sens m_sens; + u_char buf[64]; + u_int s, i, slen, ilen, len; + + /* make sens & integ */ + s = htonl(0x01234567); + i = htonl(0x89abcdef); + slen = sizeof(s); + ilen = sizeof(i); + memcpy(buf, &s, slen); + memcpy(buf + slen, &i, ilen); + + len = sizeof(m_sens) + PFKEY_ALIGN8(slen) + PFKEY_ALIGN8(ilen); + m_sens.sadb_sens_len = PFKEY_UNIT64(len); + m_sens.sadb_sens_exttype = SADB_EXT_SENSITIVITY; + m_sens.sadb_sens_dpd = 1; + m_sens.sadb_sens_sens_level = 2; + m_sens.sadb_sens_sens_len = PFKEY_ALIGN8(slen); + m_sens.sadb_sens_integ_level = 3; + m_sens.sadb_sens_integ_len = PFKEY_ALIGN8(ilen); + m_sens.sadb_sens_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_sens, sizeof(struct sadb_sens), + buf, slen + ilen); + m_len += len; + + return; +} + +void +key_setsadbprop() +{ + struct sadb_prop m_prop; + struct sadb_comb *m_comb; + u_char buf[256]; +#if defined(SADB_X_EALG_AESCBC) && defined(SADB_X_AALG_SHA2_256) + u_int len = sizeof(m_prop) + sizeof(m_comb) * 3; +#else + u_int len = sizeof(m_prop) + sizeof(m_comb) * 2; +#endif + + /* make prop & comb */ + m_prop.sadb_prop_len = PFKEY_UNIT64(len); + m_prop.sadb_prop_exttype = SADB_EXT_PROPOSAL; + m_prop.sadb_prop_replay = 0; + m_prop.sadb_prop_reserved[0] = 0; + m_prop.sadb_prop_reserved[1] = 0; + m_prop.sadb_prop_reserved[2] = 0; + + /* the 1st is ESP DES-CBC HMAC-MD5 */ + m_comb = (struct sadb_comb *)buf; + m_comb->sadb_comb_auth = SADB_AALG_MD5HMAC; + m_comb->sadb_comb_encrypt = SADB_EALG_DESCBC; + m_comb->sadb_comb_flags = 0; + m_comb->sadb_comb_auth_minbits = 8; + m_comb->sadb_comb_auth_maxbits = 96; + m_comb->sadb_comb_encrypt_minbits = 64; + m_comb->sadb_comb_encrypt_maxbits = 64; + m_comb->sadb_comb_reserved = 0; + m_comb->sadb_comb_soft_allocations = 0; + m_comb->sadb_comb_hard_allocations = 0; + m_comb->sadb_comb_soft_bytes = 0; + m_comb->sadb_comb_hard_bytes = 0; + m_comb->sadb_comb_soft_addtime = 0; + m_comb->sadb_comb_hard_addtime = 0; + m_comb->sadb_comb_soft_usetime = 0; + m_comb->sadb_comb_hard_usetime = 0; + + /* the 2st is ESP 3DES-CBC and AH HMAC-SHA1 */ + m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb)); + m_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; + m_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC; + m_comb->sadb_comb_flags = 0; + m_comb->sadb_comb_auth_minbits = 8; + m_comb->sadb_comb_auth_maxbits = 96; + m_comb->sadb_comb_encrypt_minbits = 64; + m_comb->sadb_comb_encrypt_maxbits = 64; + m_comb->sadb_comb_reserved = 0; + m_comb->sadb_comb_soft_allocations = 0; + m_comb->sadb_comb_hard_allocations = 0; + m_comb->sadb_comb_soft_bytes = 0; + m_comb->sadb_comb_hard_bytes = 0; + m_comb->sadb_comb_soft_addtime = 0; + m_comb->sadb_comb_hard_addtime = 0; + m_comb->sadb_comb_soft_usetime = 0; + m_comb->sadb_comb_hard_usetime = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_prop, sizeof(struct sadb_prop), + buf, sizeof(*m_comb) * 2); + m_len += len; + + #if defined(SADB_X_EALG_AESCBC) && defined(SADB_X_AALG_SHA2_256) + /* the 3rd is ESP AES-CBC and AH HMAC-SHA256 */ + m_comb = (struct sadb_comb *)(buf + sizeof(*m_comb)); + m_comb->sadb_comb_auth = SADB_X_AALG_SHA2_256; + m_comb->sadb_comb_encrypt = SADB_X_EALG_AESCBC; + m_comb->sadb_comb_flags = 0; + m_comb->sadb_comb_auth_minbits = 8; + m_comb->sadb_comb_auth_maxbits = 96; + m_comb->sadb_comb_encrypt_minbits = 128; + m_comb->sadb_comb_encrypt_maxbits = 128; + m_comb->sadb_comb_reserved = 0; + m_comb->sadb_comb_soft_allocations = 0; + m_comb->sadb_comb_hard_allocations = 0; + m_comb->sadb_comb_soft_bytes = 0; + m_comb->sadb_comb_hard_bytes = 0; + m_comb->sadb_comb_soft_addtime = 0; + m_comb->sadb_comb_hard_addtime = 0; + m_comb->sadb_comb_soft_usetime = 0; + m_comb->sadb_comb_hard_usetime = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_prop, sizeof(struct sadb_prop), + buf, sizeof(*m_comb) * 3); + m_len += len; +#else + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_prop, sizeof(struct sadb_prop), + buf, sizeof(*m_comb) * 2); + m_len += len; +#endif + return; +} + +void +key_setsadbid(ext, str) + u_int ext; + caddr_t str; +{ + struct sadb_ident m_id; + u_int idlen = strlen(str), len; + + len = sizeof(m_id) + PFKEY_ALIGN8(idlen); + m_id.sadb_ident_len = PFKEY_UNIT64(len); + m_id.sadb_ident_exttype = ext; + m_id.sadb_ident_type = SADB_IDENTTYPE_USERFQDN; + m_id.sadb_ident_reserved = 0; + m_id.sadb_ident_id = getpid(); + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_id, sizeof(struct sadb_ident), + str, idlen); + m_len += len; + + return; +} + +void +key_setsadblft(ext, time) + u_int ext, time; +{ + struct sadb_lifetime m_lft; + + m_lft.sadb_lifetime_len = PFKEY_UNIT64(sizeof(m_lft)); + m_lft.sadb_lifetime_exttype = ext; + m_lft.sadb_lifetime_allocations = 0x2; + m_lft.sadb_lifetime_bytes = 0x1000; + m_lft.sadb_lifetime_addtime = time; + m_lft.sadb_lifetime_usetime = 0x0020; + + memcpy(m_buf + m_len, &m_lft, sizeof(struct sadb_lifetime)); + m_len += sizeof(struct sadb_lifetime); + + return; +} + +void +key_setspirange() +{ + struct sadb_spirange m_spi; + + m_spi.sadb_spirange_len = PFKEY_UNIT64(sizeof(m_spi)); + m_spi.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + m_spi.sadb_spirange_min = 0x00001000; + m_spi.sadb_spirange_max = 0x00002000; + m_spi.sadb_spirange_reserved = 0; + + memcpy(m_buf + m_len, &m_spi, sizeof(struct sadb_spirange)); + m_len += sizeof(struct sadb_spirange); + + return; +} + +void +key_setsadbkey(ext, str) + u_int ext; + caddr_t str; +{ + struct sadb_key m_key; + u_int keylen = strlen(str); + u_int len; + + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + m_key.sadb_key_len = PFKEY_UNIT64(len); + m_key.sadb_key_exttype = ext; + m_key.sadb_key_bits = keylen * 8; + m_key.sadb_key_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_key, sizeof(struct sadb_key), + str, keylen); + m_len += len; + + return; +} + +void +key_setsadbsa() +{ + struct sadb_sa m_sa; + + m_sa.sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(0x12345678); + m_sa.sadb_sa_replay = 4; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = SADB_AALG_MD5HMAC; + m_sa.sadb_sa_encrypt = SADB_EALG_DESCBC; + m_sa.sadb_sa_flags = 0; + + memcpy(m_buf + m_len, &m_sa, sizeof(struct sadb_sa)); + m_len += sizeof(struct sadb_sa); + + return; +} + +void +key_setsadbaddr(ext, af, str) + u_int ext, af; + caddr_t str; +{ + struct sadb_address m_addr; + u_int len; + struct addrinfo hints, *res; + const char *serv; + int plen; + + switch (af) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + /* XXX bark */ + exit(1); + } + + /* make sockaddr buffer */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + serv = (ext == SADB_EXT_ADDRESS_PROXY ? "0" : "4660"); /*0x1234*/ + if (getaddrinfo(str, serv, &hints, &res) != 0 || res->ai_next) { + /* XXX bark */ + exit(1); + } + + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(res->ai_addrlen); + m_addr.sadb_address_len = PFKEY_UNIT64(len); + m_addr.sadb_address_exttype = ext; + m_addr.sadb_address_proto = + (ext == SADB_EXT_ADDRESS_PROXY ? 0 : IPPROTO_TCP); + m_addr.sadb_address_prefixlen = plen; + m_addr.sadb_address_reserved = 0; + + key_setsadbextbuf(m_buf, m_len, + (caddr_t)&m_addr, sizeof(struct sadb_address), + (caddr_t)res->ai_addr, res->ai_addrlen); + m_len += len; + + freeaddrinfo(res); + + return; +} + +void +key_setsadbextbuf(dst, off, ebuf, elen, vbuf, vlen) + caddr_t dst, ebuf, vbuf; + int off, elen, vlen; +{ + memset(dst + off, 0, elen + vlen); + memcpy(dst + off, (caddr_t)ebuf, elen); + memcpy(dst + off + elen, vbuf, vlen); + + return; +} + diff --git a/ipsec-tools/setkey/token.l b/ipsec-tools/setkey/token.l new file mode 100644 index 0000000..a890d95 --- /dev/null +++ b/ipsec-tools/setkey/token.l @@ -0,0 +1,353 @@ +/* $KAME: token.l,v 1.44 2003/10/21 07:20:58 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +%option noyywrap +%{ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include +#ifdef HAVE_NETINET6_IPSEC +# include +#else +# include +#endif + +#include +#include +#include +#include +#include +#include + +#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); } +[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); + } +{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); } +hmac-md5 { yylval.num = SADB_AALG_MD5HMAC; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha1 { yylval.num = SADB_AALG_SHA1HMAC; BEGIN INITIAL; return(ALG_AUTH); } +keyed-md5 { yylval.num = SADB_X_AALG_MD5; BEGIN INITIAL; return(ALG_AUTH); } +keyed-sha1 { yylval.num = SADB_X_AALG_SHA; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha2-256 { yylval.num = SADB_X_AALG_SHA2_256; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha256 { yylval.num = SADB_X_AALG_SHA2_256; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha2-384 { yylval.num = SADB_X_AALG_SHA2_384; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha384 { yylval.num = SADB_X_AALG_SHA2_384; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha2-512 { yylval.num = SADB_X_AALG_SHA2_512; BEGIN INITIAL; return(ALG_AUTH); } +hmac-sha512 { yylval.num = SADB_X_AALG_SHA2_512; BEGIN INITIAL; return(ALG_AUTH); } +hmac-ripemd160 { yylval.num = SADB_X_AALG_RIPEMD160HMAC; BEGIN INITIAL; return(ALG_AUTH); } +aes-xcbc-mac { yylval.num = SADB_X_AALG_AES_XCBC_MAC; BEGIN INITIAL; return(ALG_AUTH); } +tcp-md5 { +#ifdef SADB_X_AALG_TCP_MD5 + yylval.num = SADB_X_AALG_TCP_MD5; + BEGIN INITIAL; + return(ALG_AUTH); +#endif + } +null { yylval.num = SADB_X_AALG_NULL; BEGIN INITIAL; return(ALG_AUTH_NOKEY); } + + /* encryption alogorithm */ +{hyphen}E { BEGIN S_ENCALG; return(F_ENC); } +des-cbc { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC); } +3des-cbc { yylval.num = SADB_EALG_3DESCBC; BEGIN INITIAL; return(ALG_ENC); } +null { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_NOKEY); } +simple { yylval.num = SADB_EALG_NULL; BEGIN INITIAL; return(ALG_ENC_OLD); } +blowfish-cbc { yylval.num = SADB_X_EALG_BLOWFISHCBC; BEGIN INITIAL; return(ALG_ENC); } +cast128-cbc { yylval.num = SADB_X_EALG_CAST128CBC; BEGIN INITIAL; return(ALG_ENC); } +des-deriv { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DESDERIV); } +des-32iv { yylval.num = SADB_EALG_DESCBC; BEGIN INITIAL; return(ALG_ENC_DES32IV); } +twofish-cbc { yylval.num = SADB_X_EALG_TWOFISHCBC; BEGIN INITIAL; return(ALG_ENC); } +aes-cbc { +#ifdef SADB_X_EALG_AESCBC + yylval.num = SADB_X_EALG_AESCBC; BEGIN INITIAL; return(ALG_ENC); +#endif +} +rijndael-cbc { +#ifdef SADB_X_EALG_AESCBC + yylval.num = SADB_X_EALG_AESCBC; BEGIN INITIAL; return(ALG_ENC); +#endif +} +aes-ctr { yylval.num = SADB_X_EALG_AESCTR; BEGIN INITIAL; return(ALG_ENC); } + + /* compression algorithms */ +{hyphen}C { return(F_COMP); } +oui { yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); } +deflate { yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); } +lzs { yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); } +{hyphen}R { return(F_RAWCPI); } + + /* extension */ +{hyphen}m { return(F_MODE); } +transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); } +tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } +{hyphen}u { return(F_REQID); } +{hyphen}f { return(F_EXT); } +random-pad { yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); } +seq-pad { yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); } +zero-pad { yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); } +nocyclic-seq { return(NOCYCLICSEQ); } +{hyphen}r { return(F_REPLAY); } +{hyphen}lh { return(F_LIFETIME_HARD); } +{hyphen}ls { return(F_LIFETIME_SOFT); } +{hyphen}bh { return(F_LIFEBYTE_HARD); } +{hyphen}bs { return(F_LIFEBYTE_SOFT); } + + /* ... */ +any { return(ANY); } +{ws} { } +{nl} { lineno++; } +{comment} +{semi} { return(EOT); } + + /* for address parameters: /prefix, [port] */ +{slash} { return SLASH; } +{blcl} { return BLCL; } +{elcl} { return ELCL; } + + /* parameter */ +{decstring} { + char *bp; + + yylval.ulnum = strtoul(yytext, &bp, 10); + return(DECSTRING); + } + +{hexstring} { + yylval.val.buf = strdup(yytext + 2); + if (!yylval.val.buf) + yyfatal("insufficient memory"); + yylval.val.len = strlen(yylval.val.buf); + + return(HEXSTRING); + } + +{quotedstring} { + char *p = yytext; + while (*++p != '"') ; + *p = '\0'; + yytext++; + yylval.val.len = yyleng - 2; + yylval.val.buf = strdup(yytext); + if (!yylval.val.buf) + yyfatal("insufficient memory"); + + return(QUOTEDSTRING); + } + +[A-Za-z0-9:][A-Za-z0-9:%\.-]* { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + if (!yylval.val.buf) + yyfatal("insufficient memory"); + return(STRING); + } + +[0-9,]+ { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + if (!yylval.val.buf) + yyfatal("insufficient memory"); + return(STRING); + } + +. { + yyfatal("Syntax error"); + /*NOTREACHED*/ + } + +%% + +void +yyfatal(s) + const char *s; +{ + yyerror(s); + exit(1); +} + +void +yyerror(s) + const char *s; +{ + printf("line %d: %s at [%s]\n", lineno, s, yytext); +} + +int +parse(fp) + FILE **fp; +{ + yyin = *fp; + + lineno = 1; + parse_init(); + + if (yyparse()) { + printf("parse failed, line %d.\n", lineno); + return(-1); + } + + return(0); +} + +int +parse_string (char *src) +{ + int result; + YY_BUFFER_STATE buf_state; + + buf_state = yy_scan_string(src); + result = yyparse(); + yy_delete_buffer(buf_state); + return result; +} + diff --git a/ipsec-tools/setkey/vchar.h b/ipsec-tools/setkey/vchar.h new file mode 100644 index 0000000..1031e42 --- /dev/null +++ b/ipsec-tools/setkey/vchar.h @@ -0,0 +1,40 @@ +/* $Id: vchar.h,v 1.2 2004/06/07 09:18:47 ludvigm Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VCHAR_H +#define _VCHAR_H + +typedef struct { + u_int len; + caddr_t buf; +} vchar_t; + +#endif /* _VCHAR_H */ diff --git a/ipsec.xcodeproj/project.pbxproj b/ipsec.xcodeproj/project.pbxproj new file mode 100644 index 0000000..964f919 --- /dev/null +++ b/ipsec.xcodeproj/project.pbxproj @@ -0,0 +1,2505 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + 23B20D2F0871D62A00A3B0FC /* IPSec (Aggregate) */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 25D3DAB8098952B20025F703 /* Build configuration list for PBXAggregateTarget "IPSec (Aggregate)" */; + buildPhases = ( + ); + dependencies = ( + 25D3DDE30989AFDE0025F703 /* PBXTargetDependency */, + 25D3DDE50989AFE50025F703 /* PBXTargetDependency */, + 25D3DDE70989AFE90025F703 /* PBXTargetDependency */, + 254347D109DCBAF8007943DE /* PBXTargetDependency */, + 25DE3DB609EC27B900147420 /* PBXTargetDependency */, + ); + name = "IPSec (Aggregate)"; + productName = "IPSec (Aggregate)"; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 25078AE509D37570005F3F63 /* nattraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F00988657000D15623 /* nattraversal.c */; }; + 2537A1B109E4867100D0ECDA /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 25D9499F09A6AAD700CA0F24 /* config.h */; }; + 2537A1B509E4867700D0ECDA /* ipsec_dump_policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9520989B4EE00E5B678 /* ipsec_dump_policy.c */; }; + 2537A1B609E4867700D0ECDA /* ipsec_get_policylen.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9530989B4EE00E5B678 /* ipsec_get_policylen.c */; }; + 2537A1B709E4867800D0ECDA /* ipsec_strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9560989B4EE00E5B678 /* ipsec_strerror.c */; }; + 2537A1B809E4867900D0ECDA /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 252DF9570989B4EE00E5B678 /* ipsec_strerror.h */; }; + 2537A1B909E4867900D0ECDA /* policy_parse.y in Sources */ = {isa = PBXBuildFile; fileRef = 252DF95E0989B4EE00E5B678 /* policy_parse.y */; }; + 2537A1BA09E4867A00D0ECDA /* policy_token.l in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9600989B4EE00E5B678 /* policy_token.l */; }; + 2537A1C109E494B300D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 2537A1C709E49D0600D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 2537A1CB09E49D5600D0ECDA /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 2543473209DCAE27007943DE /* racoonctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2590C0988657000D15623 /* racoonctl.c */; }; + 2543474E09DCAEF8007943DE /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; }; + 2543475109DCB063007943DE /* kmpstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E80988657000D15623 /* kmpstat.c */; }; + 2543475509DCB0D9007943DE /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; }; + 2543475609DCB0DB007943DE /* sockmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591A0988657000D15623 /* sockmisc.c */; }; + 2543475709DCB0E6007943DE /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; }; + 2543476409DCB396007943DE /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; }; + 2543476709DCB400007943DE /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; }; + 2543476909DCB420007943DE /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 2543477109DCB492007943DE /* plainrsa-gen.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FC0988657000D15623 /* plainrsa-gen.c */; }; + 2543478A09DCB49C007943DE /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; }; + 2543478C09DCB4A6007943DE /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; }; + 254347A909DCB6C8007943DE /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; }; + 254347AB09DCB6D6007943DE /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; }; + 254347B809DCB84D007943DE /* test-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 252DF9610989B4EE00E5B678 /* test-policy.c */; }; + 254347C809DCBA1B007943DE /* test-pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 254347C709DCBA1B007943DE /* test-pfkey.c */; }; + 258CF2CB0A19197400166B38 /* setkey.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F258890988648C00D15623 /* setkey.8 */; }; + 258CF2CD0A1919A800166B38 /* ipsec_set_policy.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 252DF9540989B4EE00E5B678 /* ipsec_set_policy.3 */; }; + 258CF2CE0A1919AF00166B38 /* ipsec_strerror.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 252DF9550989B4EE00E5B678 /* ipsec_strerror.3 */; }; + 258CF2D20A191A0600166B38 /* racoonctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2590B0988657000D15623 /* racoonctl.8 */; }; + 258CF2D40A191A5000166B38 /* plainrsa-gen.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F258FB0988657000D15623 /* plainrsa-gen.8 */; }; + 258CF2E10A191A9200166B38 /* racoon.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F259090988657000D15623 /* racoon.8 */; }; + 258CF2E40A191AD500166B38 /* racoon.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2590A0988657000D15623 /* racoon.conf.5 */; }; + 258CF2E60A191B1800166B38 /* racoon.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F2589A098864D700D15623 /* racoon.conf */; }; + 258CF2FB0A191B4F00166B38 /* anonymous.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F25898098864D700D15623 /* anonymous.conf */; }; + 258CF2FC0A191B5400166B38 /* psk.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 25F25899098864D700D15623 /* psk.txt */; }; + 25BC48740A0BC7B000A181A0 /* eaytest.c in Sources */ = {isa = PBXBuildFile; fileRef = 25BC48730A0BC7B000A181A0 /* eaytest.c */; }; + 25BE7E0109E5D3F4009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 25BE7E1209E5D550009B6B84 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; }; + 25BE7E1309E5D555009B6B84 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; }; + 25BE7E1B09E5D5D9009B6B84 /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; }; + 25BE7E2E09E5D709009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 25BE7E3809E5D80E009B6B84 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; }; + 25BE7E3E09E5D906009B6B84 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; }; + 25BE7E4009E5D92C009B6B84 /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; }; + 25BE7E5709E5DC4D009B6B84 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; }; + 25BE7E5A09E5DCBD009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 25BE7E5E09E5DCF5009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 25BE7E6009E5DD04009B6B84 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; }; + 25BE7E6309E5DD38009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 25BE7E7609E5DDBA009B6B84 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; }; + 25BE7E7709E5DDBE009B6B84 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; }; + 25BE7E7F09E5DE4C009B6B84 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; }; + 25BE7E8209E5DE8D009B6B84 /* libipsec.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2537A1A809E4864800D0ECDA /* libipsec.A.dylib */; }; + 25BE7E8809E5E499009B6B84 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 25BE7E8A09E5E4A6009B6B84 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; }; + 25BE7E8E09E5E5BE009B6B84 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; }; + 25BE7E9009E5E61F009B6B84 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; }; + 25BE7E9209E5E635009B6B84 /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; }; + 25DC9EC909DB0FBB00C89F86 /* rsalist.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259100988657000D15623 /* rsalist.c */; }; + 25DC9ED409DB16F300C89F86 /* isakmp_cfg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D50988657000D15623 /* isakmp_cfg.c */; }; + 25DC9ED509DB16F800C89F86 /* isakmp_unity.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E10988657000D15623 /* isakmp_unity.c */; }; + 25DC9ED609DB16FA00C89F86 /* isakmp_xauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E40988657000D15623 /* isakmp_xauth.c */; }; + 25DC9ED709DB170800C89F86 /* rsaparse.o in Frameworks */ = {isa = PBXBuildFile; fileRef = 25E08C9A09D9E64A001A11CF /* rsaparse.o */; }; + 25DE2DE90A8BD40E0010A46D /* vpn_control.c in Sources */ = {isa = PBXBuildFile; fileRef = 25DE2DE60A8BD40E0010A46D /* vpn_control.c */; }; + 25E08C9E09D9E681001A11CF /* prsa_par.y in Sources */ = {isa = PBXBuildFile; fileRef = 2589CBA809D8B727002DC960 /* prsa_par.y */; }; + 25E08C9F09D9E682001A11CF /* prsa_tok.l in Sources */ = {isa = PBXBuildFile; fileRef = 2589CBAA09D8B727002DC960 /* prsa_tok.l */; }; + 25EAE83209D875790042CC7F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE83109D875790042CC7F /* Security.framework */; }; + 25EAE83809D875BF0042CC7F /* DirectoryService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE83709D875BF0042CC7F /* DirectoryService.framework */; }; + 25EAE84809D879700042CC7F /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84709D879700042CC7F /* libssl.dylib */; }; + 25EAE84B09D879DE0042CC7F /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */; }; + 25EAE87209D87A160042CC7F /* libgssapi_krb5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */; }; + 25EAE87409D87A390042CC7F /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87309D87A390042CC7F /* libpam.dylib */; }; + 25EAE87709D87A770042CC7F /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE87609D87A770042CC7F /* libiconv.dylib */; }; + 25EAE8C109D87B080042CC7F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EAE8C009D87B080042CC7F /* CoreFoundation.framework */; }; + 25EAE8C609D87B990042CC7F /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 25ECCDA209AD479A00883CA3 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25D949A209A6AAD700CA0F24 /* pfkey.c */; }; + 25ECCDB509AD489200883CA3 /* key_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777B909ABE3E100C99783 /* key_debug.c */; }; + 25ECCDB709AD48A300883CA3 /* pfkey_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F777ED09ABE58400C99783 /* pfkey_dump.c */; }; + 25F258900988648C00D15623 /* parse.y in Sources */ = {isa = PBXBuildFile; fileRef = 25F258870988648C00D15623 /* parse.y */; }; + 25F258910988648C00D15623 /* setkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2588A0988648C00D15623 /* setkey.c */; }; + 25F258940988648C00D15623 /* token.l in Sources */ = {isa = PBXBuildFile; fileRef = 25F2588D0988648C00D15623 /* token.l */; }; + 25F258A80988651000D15623 /* rijndael-alg-fst.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258A10988651000D15623 /* rijndael-alg-fst.c */; }; + 25F258A90988651000D15623 /* rijndael-api-fst.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258A30988651000D15623 /* rijndael-api-fst.c */; }; + 25F259280988657000D15623 /* admin.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258AC0988657000D15623 /* admin.c */; }; + 25F259290988657000D15623 /* algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258AE0988657000D15623 /* algorithm.c */; }; + 25F2592A0988657000D15623 /* backupsa.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B10988657000D15623 /* backupsa.c */; }; + 25F2592B0988657000D15623 /* cfparse.y in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B40988657000D15623 /* cfparse.y */; }; + 25F2592C0988657000D15623 /* cftoken.l in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B60988657000D15623 /* cftoken.l */; }; + 25F2592D0988657000D15623 /* crypto_cssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B70988657000D15623 /* crypto_cssm.c */; }; + 25F2592E0988657000D15623 /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258B90988657000D15623 /* crypto_openssl.c */; }; + 25F2592F0988657000D15623 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258BE0988657000D15623 /* dnssec.c */; }; + 25F259310988657000D15623 /* evt.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C20988657000D15623 /* evt.c */; }; + 25F259320988657000D15623 /* genlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C50988657000D15623 /* genlist.c */; }; + 25F259330988657000D15623 /* getcertsbyname.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C70988657000D15623 /* getcertsbyname.c */; }; + 25F259340988657000D15623 /* grabmyaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258C90988657000D15623 /* grabmyaddr.c */; }; + 25F259350988657000D15623 /* gssapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CB0988657000D15623 /* gssapi.c */; }; + 25F259360988657000D15623 /* handler.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CD0988657000D15623 /* handler.c */; }; + 25F259370988657000D15623 /* ipsec_doi.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258CF0988657000D15623 /* ipsec_doi.c */; }; + 25F259380988657000D15623 /* isakmp_agg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D10988657000D15623 /* isakmp_agg.c */; }; + 25F259390988657000D15623 /* isakmp_base.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D30988657000D15623 /* isakmp_base.c */; }; + 25F2593C0988657000D15623 /* isakmp_ident.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258D90988657000D15623 /* isakmp_ident.c */; }; + 25F2593D0988657000D15623 /* isakmp_inf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DB0988657000D15623 /* isakmp_inf.c */; }; + 25F2593E0988657000D15623 /* isakmp_newg.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DD0988657000D15623 /* isakmp_newg.c */; }; + 25F2593F0988657000D15623 /* isakmp_quick.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258DF0988657000D15623 /* isakmp_quick.c */; }; + 25F259420988657000D15623 /* isakmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E60988657000D15623 /* isakmp.c */; }; + 25F259440988657000D15623 /* localconf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258E90988657000D15623 /* localconf.c */; }; + 25F259450988657000D15623 /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EB0988657000D15623 /* logger.c */; }; + 25F259460988657000D15623 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258ED0988657000D15623 /* main.c */; }; + 25F259470988657000D15623 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258EE0988657000D15623 /* misc.c */; }; + 25F259490988657000D15623 /* oakley.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F30988657000D15623 /* oakley.c */; }; + 25F2594A0988657000D15623 /* open_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F50988657000D15623 /* open_dir.c */; }; + 25F2594C0988657000D15623 /* pfkey_racoon.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258F80988657000D15623 /* pfkey_racoon.c */; }; + 25F2594F0988657000D15623 /* plog.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FD0988657000D15623 /* plog.c */; }; + 25F259500988657000D15623 /* policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F258FF0988657000D15623 /* policy.c */; }; + 25F259510988657000D15623 /* privsep.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259010988657000D15623 /* privsep.c */; }; + 25F259520988657000D15623 /* proposal.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259030988657000D15623 /* proposal.c */; }; + 25F259580988657000D15623 /* remoteconf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2590E0988657000D15623 /* remoteconf.c */; }; + 25F2595A0988657000D15623 /* safefile.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259120988657000D15623 /* safefile.c */; }; + 25F2595B0988657000D15623 /* sainfo.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259140988657000D15623 /* sainfo.c */; }; + 25F2595C0988657000D15623 /* schedule.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259160988657000D15623 /* schedule.c */; }; + 25F2595D0988657000D15623 /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259180988657000D15623 /* session.c */; }; + 25F2595E0988657000D15623 /* sockmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591A0988657000D15623 /* sockmisc.c */; }; + 25F2595F0988657000D15623 /* str2val.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591D0988657000D15623 /* str2val.c */; }; + 25F259600988657000D15623 /* strnames.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F2591F0988657000D15623 /* strnames.c */; }; + 25F259610988657000D15623 /* throttle.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259210988657000D15623 /* throttle.c */; }; + 25F259620988657000D15623 /* vendorid.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259240988657000D15623 /* vendorid.c */; }; + 25F259630988657000D15623 /* vmbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 25F259260988657000D15623 /* vmbuf.c */; }; + 81EDB0690B5D8D9600840BC7 /* ipsec_get_policylen.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 81EDB0680B5D8D8900840BC7 /* ipsec_get_policylen.3 */; }; + 81EDB06A0B5D8D9A00840BC7 /* ipsec_dump_policy.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 81EDB0670B5D8D7000840BC7 /* ipsec_dump_policy.3 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 2537A1C209E494D300D0ECDA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 2537A1C809E49D1400D0ECDA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 2537A1CC09E49D5C00D0ECDA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 254347D009DCBAF8007943DE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2543476E09DCB477007943DE; + remoteInfo = "plainrsa-gen"; + }; + 25BE7E0309E5D3FE009B6B84 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 25BE7E2F09E5D710009B6B84 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 25BE7E5B09E5DCC5009B6B84 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 25BE7E7B09E5DE28009B6B84 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 25D3DDE20989AFDE0025F703 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25F258040987FBFA00D15623; + remoteInfo = racoon; + }; + 25D3DDE40989AFE50025F703 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25F258090987FC1500D15623; + remoteInfo = setkey; + }; + 25D3DDE60989AFE90025F703 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25F2580E0987FC3400D15623; + remoteInfo = racoonctl; + }; + 25DE3DB509EC27B900147420 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2537A1A709E4864800D0ECDA; + remoteInfo = libipsec; + }; + 25E08CE909D9F0A2001A11CF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23D2D790087071FC00C51098 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E08C9909D9E64A001A11CF; + remoteInfo = rsaparse; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 258CF2CF0A1919CD00166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man3; + dstSubfolderSpec = 0; + files = ( + 258CF2CD0A1919A800166B38 /* ipsec_set_policy.3 in CopyFiles */, + 258CF2CE0A1919AF00166B38 /* ipsec_strerror.3 in CopyFiles */, + 81EDB0690B5D8D9600840BC7 /* ipsec_get_policylen.3 in CopyFiles */, + 81EDB06A0B5D8D9A00840BC7 /* ipsec_dump_policy.3 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2D00A1919CD00166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 258CF2CB0A19197400166B38 /* setkey.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2D50A191A6E00166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 258CF2D20A191A0600166B38 /* racoonctl.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2D60A191A6E00166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 258CF2D40A191A5000166B38 /* plainrsa-gen.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2E20A191AB000166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 258CF2E10A191A9200166B38 /* racoon.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2F80A191B3900166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man5; + dstSubfolderSpec = 0; + files = ( + 258CF2E40A191AD500166B38 /* racoon.conf.5 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2F90A191B3900166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /private/etc/racoon; + dstSubfolderSpec = 0; + files = ( + 258CF2FC0A191B5400166B38 /* psk.txt in CopyFiles */, + 258CF2E60A191B1800166B38 /* racoon.conf in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 258CF2FA0A191B3900166B38 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /private/etc/racoon/remote; + dstSubfolderSpec = 0; + files = ( + 258CF2FB0A191B4F00166B38 /* anonymous.conf in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 252DF9520989B4EE00E5B678 /* ipsec_dump_policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipsec_dump_policy.c; path = libipsec/ipsec_dump_policy.c; sourceTree = ""; }; + 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 = ""; }; + 252DF9540989B4EE00E5B678 /* ipsec_set_policy.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_set_policy.3; path = libipsec/ipsec_set_policy.3; sourceTree = ""; }; + 252DF9550989B4EE00E5B678 /* ipsec_strerror.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_strerror.3; path = libipsec/ipsec_strerror.3; sourceTree = ""; }; + 252DF9560989B4EE00E5B678 /* ipsec_strerror.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipsec_strerror.c; path = libipsec/ipsec_strerror.c; sourceTree = ""; }; + 252DF9570989B4EE00E5B678 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ipsec_strerror.h; path = libipsec/ipsec_strerror.h; sourceTree = ""; }; + 252DF95E0989B4EE00E5B678 /* policy_parse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; name = policy_parse.y; path = libipsec/policy_parse.y; sourceTree = ""; }; + 252DF9600989B4EE00E5B678 /* policy_token.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; name = policy_token.l; path = libipsec/policy_token.l; sourceTree = ""; }; + 252DF9610989B4EE00E5B678 /* test-policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = "test-policy.c"; path = "libipsec/test-policy.c"; sourceTree = ""; }; + 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 = ""; }; + 2589CBA809D8B727002DC960 /* prsa_par.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = prsa_par.y; sourceTree = ""; }; + 2589CBAA09D8B727002DC960 /* prsa_tok.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = prsa_tok.l; sourceTree = ""; }; + 25BC48730A0BC7B000A181A0 /* eaytest.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = eaytest.c; sourceTree = ""; }; + 25D9499F09A6AAD700CA0F24 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = Common/config.h; sourceTree = ""; }; + 25D949A109A6AAD700CA0F24 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = libpfkey.h; path = Common/libpfkey.h; sourceTree = ""; }; + 25D949A209A6AAD700CA0F24 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pfkey.c; path = Common/pfkey.c; sourceTree = ""; }; + 25DE2DE50A8BD40E0010A46D /* vpn_control_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vpn_control_var.h; sourceTree = ""; }; + 25DE2DE60A8BD40E0010A46D /* vpn_control.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vpn_control.c; sourceTree = ""; }; + 25DE2DE70A8BD40E0010A46D /* vpn_control.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vpn_control.h; sourceTree = ""; }; + 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 = ""; }; + 25EAE83709D875BF0042CC7F /* DirectoryService.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DirectoryService.framework; path = /System/Library/Frameworks/DirectoryService.framework; sourceTree = ""; }; + 25EAE84709D879700042CC7F /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = /usr/lib/libssl.dylib; sourceTree = ""; }; + 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = /usr/lib/libcrypto.dylib; sourceTree = ""; }; + 25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgssapi_krb5.dylib; path = /usr/lib/libgssapi_krb5.dylib; sourceTree = ""; }; + 25EAE87309D87A390042CC7F /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = ""; }; + 25EAE87609D87A770042CC7F /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = ""; }; + 25EAE8C009D87B080042CC7F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; + 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 = ""; }; + 25F258870988648C00D15623 /* parse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = parse.y; sourceTree = ""; }; + 25F258880988648C00D15623 /* scriptdump.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = scriptdump.pl; sourceTree = ""; }; + 25F258890988648C00D15623 /* setkey.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = setkey.8; sourceTree = ""; }; + 25F2588A0988648C00D15623 /* setkey.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = setkey.c; sourceTree = ""; }; + 25F2588D0988648C00D15623 /* token.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = token.l; sourceTree = ""; }; + 25F2588E0988648C00D15623 /* vchar.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vchar.h; sourceTree = ""; }; + 25F25895098864AB00D15623 /* sample-policy01.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "sample-policy01.cf"; sourceTree = ""; }; + 25F25896098864AB00D15623 /* sample-policy02.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "sample-policy02.cf"; sourceTree = ""; }; + 25F25897098864AB00D15623 /* sample.cf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = sample.cf; sourceTree = ""; }; + 25F25898098864D700D15623 /* anonymous.conf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = anonymous.conf; sourceTree = ""; }; + 25F25899098864D700D15623 /* psk.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = psk.txt; sourceTree = ""; }; + 25F2589A098864D700D15623 /* racoon.conf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.conf; sourceTree = ""; }; + 25F2589B098864F500D15623 /* FAQ */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = FAQ; sourceTree = ""; }; + 25F2589C098864F500D15623 /* README.certificate */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.certificate; sourceTree = ""; }; + 25F2589D098864F500D15623 /* README.gssapi */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.gssapi; sourceTree = ""; }; + 25F2589E098864F500D15623 /* TODO */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO; sourceTree = ""; }; + 25F2589F0988651000D15623 /* boxes-fst.dat */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "boxes-fst.dat"; sourceTree = ""; }; + 25F258A00988651000D15623 /* rijndael_local.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rijndael_local.h; sourceTree = ""; }; + 25F258A10988651000D15623 /* rijndael-alg-fst.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "rijndael-alg-fst.c"; sourceTree = ""; }; + 25F258A20988651000D15623 /* rijndael-alg-fst.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "rijndael-alg-fst.h"; sourceTree = ""; }; + 25F258A30988651000D15623 /* rijndael-api-fst.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "rijndael-api-fst.c"; sourceTree = ""; }; + 25F258A40988651000D15623 /* rijndael-api-fst.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "rijndael-api-fst.h"; sourceTree = ""; }; + 25F258A50988651000D15623 /* rijndael.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rijndael.h; sourceTree = ""; }; + 25F258AB0988657000D15623 /* admin_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = admin_var.h; sourceTree = ""; }; + 25F258AC0988657000D15623 /* admin.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = admin.c; sourceTree = ""; }; + 25F258AD0988657000D15623 /* admin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = admin.h; sourceTree = ""; }; + 25F258AE0988657000D15623 /* algorithm.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = algorithm.c; sourceTree = ""; }; + 25F258AF0988657000D15623 /* algorithm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = algorithm.h; sourceTree = ""; }; + 25F258B00988657000D15623 /* arc4random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = arc4random.h; sourceTree = ""; }; + 25F258B10988657000D15623 /* backupsa.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = backupsa.c; sourceTree = ""; }; + 25F258B20988657000D15623 /* backupsa.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = backupsa.h; sourceTree = ""; }; + 25F258B30988657000D15623 /* cfparse_proto.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfparse_proto.h; sourceTree = ""; }; + 25F258B40988657000D15623 /* cfparse.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = cfparse.y; sourceTree = ""; }; + 25F258B50988657000D15623 /* cftoken_proto.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cftoken_proto.h; sourceTree = ""; }; + 25F258B60988657000D15623 /* cftoken.l */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.lex; path = cftoken.l; sourceTree = ""; }; + 25F258B70988657000D15623 /* crypto_cssm.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = crypto_cssm.c; sourceTree = ""; }; + 25F258B80988657000D15623 /* crypto_cssm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crypto_cssm.h; sourceTree = ""; }; + 25F258B90988657000D15623 /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = crypto_openssl.c; sourceTree = ""; }; + 25F258BA0988657000D15623 /* crypto_openssl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crypto_openssl.h; sourceTree = ""; }; + 25F258BB0988657000D15623 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; + 25F258BC0988657000D15623 /* debugrm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = debugrm.h; sourceTree = ""; }; + 25F258BD0988657000D15623 /* dhgroup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dhgroup.h; sourceTree = ""; }; + 25F258BE0988657000D15623 /* dnssec.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = dnssec.c; sourceTree = ""; }; + 25F258BF0988657000D15623 /* dnssec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dnssec.h; sourceTree = ""; }; + 25F258C00988657000D15623 /* dump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dump.h; sourceTree = ""; }; + 25F258C20988657000D15623 /* evt.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = evt.c; sourceTree = ""; }; + 25F258C30988657000D15623 /* evt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = evt.h; sourceTree = ""; }; + 25F258C40988657000D15623 /* gcmalloc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gcmalloc.h; sourceTree = ""; }; + 25F258C50988657000D15623 /* genlist.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = genlist.c; sourceTree = ""; }; + 25F258C60988657000D15623 /* genlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = genlist.h; sourceTree = ""; }; + 25F258C70988657000D15623 /* getcertsbyname.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = getcertsbyname.c; sourceTree = ""; }; + 25F258C80988657000D15623 /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = ""; }; + 25F258C90988657000D15623 /* grabmyaddr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = grabmyaddr.c; sourceTree = ""; }; + 25F258CA0988657000D15623 /* grabmyaddr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = grabmyaddr.h; sourceTree = ""; }; + 25F258CB0988657000D15623 /* gssapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gssapi.c; sourceTree = ""; }; + 25F258CC0988657000D15623 /* gssapi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gssapi.h; sourceTree = ""; }; + 25F258CD0988657000D15623 /* handler.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = handler.c; sourceTree = ""; }; + 25F258CE0988657000D15623 /* handler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = handler.h; sourceTree = ""; }; + 25F258CF0988657000D15623 /* ipsec_doi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ipsec_doi.c; sourceTree = ""; }; + 25F258D00988657000D15623 /* ipsec_doi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ipsec_doi.h; sourceTree = ""; }; + 25F258D10988657000D15623 /* isakmp_agg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_agg.c; sourceTree = ""; }; + 25F258D20988657000D15623 /* isakmp_agg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_agg.h; sourceTree = ""; }; + 25F258D30988657000D15623 /* isakmp_base.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_base.c; sourceTree = ""; }; + 25F258D40988657000D15623 /* isakmp_base.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_base.h; sourceTree = ""; }; + 25F258D50988657000D15623 /* isakmp_cfg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_cfg.c; sourceTree = ""; }; + 25F258D60988657000D15623 /* isakmp_cfg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_cfg.h; sourceTree = ""; }; + 25F258D70988657000D15623 /* isakmp_frag.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_frag.c; sourceTree = ""; }; + 25F258D80988657000D15623 /* isakmp_frag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_frag.h; sourceTree = ""; }; + 25F258D90988657000D15623 /* isakmp_ident.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_ident.c; sourceTree = ""; }; + 25F258DA0988657000D15623 /* isakmp_ident.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_ident.h; sourceTree = ""; }; + 25F258DB0988657000D15623 /* isakmp_inf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_inf.c; sourceTree = ""; }; + 25F258DC0988657000D15623 /* isakmp_inf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_inf.h; sourceTree = ""; }; + 25F258DD0988657000D15623 /* isakmp_newg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_newg.c; sourceTree = ""; }; + 25F258DE0988657000D15623 /* isakmp_newg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_newg.h; sourceTree = ""; }; + 25F258DF0988657000D15623 /* isakmp_quick.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_quick.c; sourceTree = ""; }; + 25F258E00988657000D15623 /* isakmp_quick.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_quick.h; sourceTree = ""; }; + 25F258E10988657000D15623 /* isakmp_unity.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_unity.c; sourceTree = ""; }; + 25F258E20988657000D15623 /* isakmp_unity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_unity.h; sourceTree = ""; }; + 25F258E30988657000D15623 /* isakmp_var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_var.h; sourceTree = ""; }; + 25F258E40988657000D15623 /* isakmp_xauth.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp_xauth.c; sourceTree = ""; }; + 25F258E50988657000D15623 /* isakmp_xauth.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp_xauth.h; sourceTree = ""; }; + 25F258E60988657000D15623 /* isakmp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = isakmp.c; sourceTree = ""; }; + 25F258E70988657000D15623 /* isakmp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = isakmp.h; sourceTree = ""; }; + 25F258E80988657000D15623 /* kmpstat.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kmpstat.c; sourceTree = ""; }; + 25F258E90988657000D15623 /* localconf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = localconf.c; sourceTree = ""; }; + 25F258EA0988657000D15623 /* localconf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = localconf.h; sourceTree = ""; }; + 25F258EB0988657000D15623 /* logger.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = logger.c; sourceTree = ""; }; + 25F258EC0988657000D15623 /* logger.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = logger.h; sourceTree = ""; }; + 25F258ED0988657000D15623 /* main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 25F258EE0988657000D15623 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = ""; }; + 25F258EF0988657000D15623 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = ""; }; + 25F258F00988657000D15623 /* nattraversal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = nattraversal.c; sourceTree = ""; }; + 25F258F10988657000D15623 /* nattraversal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = nattraversal.h; sourceTree = ""; }; + 25F258F20988657000D15623 /* netdb_dnssec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = netdb_dnssec.h; sourceTree = ""; }; + 25F258F30988657000D15623 /* oakley.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = oakley.c; sourceTree = ""; }; + 25F258F40988657000D15623 /* oakley.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oakley.h; sourceTree = ""; }; + 25F258F50988657000D15623 /* open_dir.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = open_dir.c; sourceTree = ""; }; + 25F258F60988657000D15623 /* open_dir.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = open_dir.h; sourceTree = ""; }; + 25F258F80988657000D15623 /* pfkey_racoon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = pfkey_racoon.c; sourceTree = ""; }; + 25F258F90988657000D15623 /* pfkey.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pfkey.h; sourceTree = ""; }; + 25F258FB0988657000D15623 /* plainrsa-gen.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "plainrsa-gen.8"; sourceTree = ""; }; + 25F258FC0988657000D15623 /* plainrsa-gen.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "plainrsa-gen.c"; sourceTree = ""; }; + 25F258FD0988657000D15623 /* plog.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = plog.c; sourceTree = ""; }; + 25F258FE0988657000D15623 /* plog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = plog.h; sourceTree = ""; }; + 25F258FF0988657000D15623 /* policy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = policy.c; sourceTree = ""; }; + 25F259000988657000D15623 /* policy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = policy.h; sourceTree = ""; }; + 25F259010988657000D15623 /* privsep.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = privsep.c; sourceTree = ""; }; + 25F259020988657000D15623 /* privsep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = privsep.h; sourceTree = ""; }; + 25F259030988657000D15623 /* proposal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = proposal.c; sourceTree = ""; }; + 25F259040988657000D15623 /* proposal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = proposal.h; sourceTree = ""; }; + 25F259090988657000D15623 /* racoon.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.8; sourceTree = ""; }; + 25F2590A0988657000D15623 /* racoon.conf.5 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoon.conf.5; sourceTree = ""; }; + 25F2590B0988657000D15623 /* racoonctl.8 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = racoonctl.8; sourceTree = ""; }; + 25F2590C0988657000D15623 /* racoonctl.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = racoonctl.c; sourceTree = ""; }; + 25F2590D0988657000D15623 /* racoonctl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = racoonctl.h; sourceTree = ""; }; + 25F2590E0988657000D15623 /* remoteconf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = remoteconf.c; sourceTree = ""; }; + 25F2590F0988657000D15623 /* remoteconf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = remoteconf.h; sourceTree = ""; }; + 25F259100988657000D15623 /* rsalist.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rsalist.c; sourceTree = ""; }; + 25F259110988657000D15623 /* rsalist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rsalist.h; sourceTree = ""; }; + 25F259120988657000D15623 /* safefile.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = safefile.c; sourceTree = ""; }; + 25F259130988657000D15623 /* safefile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = safefile.h; sourceTree = ""; }; + 25F259140988657000D15623 /* sainfo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = sainfo.c; sourceTree = ""; }; + 25F259150988657000D15623 /* sainfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sainfo.h; sourceTree = ""; }; + 25F259160988657000D15623 /* schedule.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = schedule.c; sourceTree = ""; }; + 25F259170988657000D15623 /* schedule.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = schedule.h; sourceTree = ""; }; + 25F259180988657000D15623 /* session.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = session.c; sourceTree = ""; }; + 25F259190988657000D15623 /* session.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = ""; }; + 25F2591A0988657000D15623 /* sockmisc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = sockmisc.c; sourceTree = ""; }; + 25F2591B0988657000D15623 /* sockmisc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sockmisc.h; sourceTree = ""; }; + 25F2591C0988657000D15623 /* stats.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = stats.pl; sourceTree = ""; }; + 25F2591D0988657000D15623 /* str2val.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = str2val.c; sourceTree = ""; }; + 25F2591E0988657000D15623 /* str2val.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = str2val.h; sourceTree = ""; }; + 25F2591F0988657000D15623 /* strnames.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = strnames.c; sourceTree = ""; }; + 25F259200988657000D15623 /* strnames.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = strnames.h; sourceTree = ""; }; + 25F259210988657000D15623 /* throttle.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = throttle.c; sourceTree = ""; }; + 25F259220988657000D15623 /* throttle.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = throttle.h; sourceTree = ""; }; + 25F259230988657000D15623 /* var.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = var.h; sourceTree = ""; }; + 25F259240988657000D15623 /* vendorid.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vendorid.c; sourceTree = ""; }; + 25F259250988657000D15623 /* vendorid.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vendorid.h; sourceTree = ""; }; + 25F259260988657000D15623 /* vmbuf.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vmbuf.c; sourceTree = ""; }; + 25F259270988657000D15623 /* vmbuf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vmbuf.h; sourceTree = ""; }; + 25F777B909ABE3E100C99783 /* key_debug.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = key_debug.c; path = Common/key_debug.c; sourceTree = ""; }; + 25F777ED09ABE58400C99783 /* pfkey_dump.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pfkey_dump.c; path = Common/pfkey_dump.c; sourceTree = ""; }; + 81EDB0670B5D8D7000840BC7 /* ipsec_dump_policy.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_dump_policy.3; path = libipsec/ipsec_dump_policy.3; sourceTree = ""; }; + 81EDB0680B5D8D8900840BC7 /* ipsec_get_policylen.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = ipsec_get_policylen.3; path = libipsec/ipsec_get_policylen.3; sourceTree = ""; }; +/* 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 = ""; + }; + 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 = ""; + }; + 2589CB5409D8AE95002DC960 /* Libraries */ = { + isa = PBXGroup; + children = ( + 25EAE87609D87A770042CC7F /* libiconv.dylib */, + 25EAE87309D87A390042CC7F /* libpam.dylib */, + 25EAE87109D87A160042CC7F /* libgssapi_krb5.dylib */, + 25EAE84A09D879DE0042CC7F /* libcrypto.dylib */, + 25EAE84709D879700042CC7F /* libssl.dylib */, + ); + name = Libraries; + sourceTree = ""; + }; + 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 = ""; + }; + 25D3DB4C098998230025F703 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 25EAE83109D875790042CC7F /* Security.framework */, + 25EAE83709D875BF0042CC7F /* DirectoryService.framework */, + 25EAE8C009D87B080042CC7F /* CoreFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 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 = ""; + }; + 25E5E82D0981A61900F2834C /* ipsec-tools */ = { + isa = PBXGroup; + children = ( + 25D9497C09A6AA7600CA0F24 /* Common */, + 25D3DB1B098996310025F703 /* libipsec */, + 25F258000987FB1600D15623 /* racoon */, + 25F257FF0987FB0E00D15623 /* setkey */, + ); + path = "ipsec-tools"; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 25F2584B098861D900D15623 /* Sample */ = { + isa = PBXGroup; + children = ( + 25F25895098864AB00D15623 /* sample-policy01.cf */, + 25F25896098864AB00D15623 /* sample-policy02.cf */, + 25F25897098864AB00D15623 /* sample.cf */, + ); + path = Sample; + sourceTree = ""; + }; + 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 = ""; + }; + 25F2584D098861F500D15623 /* Documents */ = { + isa = PBXGroup; + children = ( + 25F2589B098864F500D15623 /* FAQ */, + 25F2589C098864F500D15623 /* README.certificate */, + 25F2589D098864F500D15623 /* README.gssapi */, + 25F2589E098864F500D15623 /* TODO */, + ); + path = Documents; + sourceTree = ""; + }; + 25F2584E0988620300D15623 /* Sample */ = { + isa = PBXGroup; + children = ( + 25F25898098864D700D15623 /* anonymous.conf */, + 25F25899098864D700D15623 /* psk.txt */, + 25F2589A098864D700D15623 /* racoon.conf */, + ); + path = Sample; + sourceTree = ""; + }; +/* 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 */; +} -- 2.45.2