diff options
author | Chia-chi Yeh <chiachi@android.com> | 2011-07-04 17:21:23 -0700 |
---|---|---|
committer | Chia-chi Yeh <chiachi@android.com> | 2011-07-07 00:16:04 -0700 |
commit | f8a6a7636d53a5730c58ae041e4e09ae12e1657c (patch) | |
tree | 2d0059f37c93a41af4c58c7d2f7c588b21339b99 | |
parent | c9ac7d2fae3a233f928fd3f643ffa20b6ea602d3 (diff) | |
download | ipsec-tools-f8a6a7636d53a5730c58ae041e4e09ae12e1657c.tar.gz |
ipsec-tools: Update to 0.8.0.
This change updates ipsec-tools to 0.8.0. However, a quick test reveals
a regression in IPSec PSK sessions. The server rejects the first packet
of phase 2 negotiation with INVALID-ID-INFORMATION error. After testing
files one by one, it turns out that using the old ipsec_doi.c fixes the
problem. Then the next error shows that identity check is failed. This
can be fixed by marking few lines in isakmp_quick.c just like 0.7.3.
This change adds ipsec_doi-0.7.3.c as a temporary fix. I will come back
and see if I can find the real problem. IPSec RSA sessions will be
covered in the next change.
Change-Id: I48f0026c3be07f506b3901b59202081bf88f41c9
110 files changed, 17276 insertions, 7834 deletions
@@ -21,6 +21,10 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ + src/racoon/algorithm.c \ + src/racoon/crypto_openssl.c \ + src/racoon/genlist.c \ + src/racoon/handler.c \ src/racoon/isakmp.c \ src/racoon/isakmp_agg.c \ src/racoon/isakmp_base.c \ @@ -29,22 +33,19 @@ LOCAL_SRC_FILES := \ src/racoon/isakmp_inf.c \ src/racoon/isakmp_newg.c \ src/racoon/isakmp_quick.c \ - src/racoon/handler.c \ - src/racoon/pfkey.c \ - src/racoon/ipsec_doi.c \ + src/racoon/ipsec_doi-0.7.3.c \ + src/racoon/nattraversal.c \ src/racoon/oakley.c \ - src/racoon/vendorid.c \ + src/racoon/pfkey.c \ src/racoon/policy.c \ - src/racoon/crypto_openssl.c \ - src/racoon/algorithm.c \ src/racoon/proposal.c \ - src/racoon/strnames.c \ + src/racoon/remoteconf.c \ src/racoon/schedule.c \ + src/racoon/sockmisc.c \ src/racoon/str2val.c \ - src/racoon/genlist.c \ + src/racoon/strnames.c \ + src/racoon/vendorid.c \ src/racoon/vmbuf.c \ - src/racoon/sockmisc.c \ - src/racoon/nattraversal.c \ main.c \ setup.c @@ -1,46 +1,574 @@ -2009-08-13 tag ipsec-tools-0_7_3 +2011-03-17 Yvan Vanhullebus <vanhu@netasq.com> -2009-08-13 Yvan Vanhullebus <vanhu@netasq.com> + * src/racoon/oakley.c: fixed a memory leak in + oakley_append_rmconf_cr() while generating plist. patch by Roman + Hoog Antink <rha@open.ch> + + * src/racoon/oakley.c: free name later, to avoid a memory use after + free in oakley_check_certid(). also give iph1->remote to some plog() + calls. patch by Roman Hoog Antink <rha@open.ch> + + * src/racoon/oakley.c: fixed a memory leak in + oakley_check_certid(). patch by Roman Hoog Antink <rha@open.ch> + +2011-03-15 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: isakmp.c, isakmp_inf.c, pfkey.c: directly call + isakmp_ph1delete() instead of scheduling isakmp_ph1delete_stub(), as + it is useless an can lead to memory access after free + +2011-03-14 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: grabmyaddr.c, handler.c, isakmp.c, isakmp_inf.c, + isakmp_quick.c, nattraversal.c, pfkey.c, policy.c, sockmisc.c, + sockmisc.h, throttle.c: Explicitly compare return value of + cmpsaddr() against a return value define to make it more obvious + what is the intended action. One more return value is also added, to + fix comparison of security policy descriptors. Namely, getsp() + should not allow wildcard matching (as the comment says, it does + exact matching) - otherwise we get problems when kernel has generic + policy with no ports, and a second similar policy with ports. + +2011-03-14 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: cfparse.y, isakmp_xauth.c, isakmp_xauth.h, + remoteconf.c, remoteconf.h, rsalist.c, rsalist.h: avoid some + memory leaks / free memory access when reloading conf and have + inherited config. patch from Roman Hoog Antink <rha@open.ch> + + * src/racoon/handler.c: removed an useless comment + + * src/racoon/handler.c: check if we got RMCONF_ERR_MULTIPLE from + getrmconf_by_ph1() in revalidate_ph1tree_rmconf() + +2011-03-11 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: handler.c, isakmp.c: directly delete a ph1 in + remove_ph1-) instead of scheduling it, to avoid (completely ?) a + race condition when reloading configuration + +2011-03-06 Timo Teras <timo.teras@iki.fi> + + * src/racoon/privsep.c: Quiet a gcc warning when strict-aliasing + checks are enabled. Reported by Stephen Clark. + +2011-03-02 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/session.c: flush sainfo list when closing session. + patch by Roman Hoog Antink <rha@open.ch> + + * src/racoon/: remoteconf.c, rsalist.c, rsalist.h: free rsa + structures when deleting a struct rmconf. patch by Roman Hoog Antink + <rha@open.ch> + + * src/racoon/: cfparse.y, remoteconf.c, remoteconf.h: free spspec + when deleting a rmconf struct. patch by Roman Hoog Antink + <rha@open.ch> + + * src/racoon/: remoteconf.c, session.c: fixed some memory leaks in + remoteconf. patch by Roman Hoog Antink <rha@open.ch> + + * src/racoon/: cfparse.y, prsa_par.y: fixed some memory leaks + during configuration parsing. patch by Roman Hoog Antink + <rha@open.ch> + +2011-03-01 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: isakmp.c, pfkey.c: plog text fixes, patch from M E + Andersson <debian@gisladisker.se> + + * src/racoon/cfparse.y: reset yyerrorcount before doing parse + stuff. patch by Roman Hoog Antink <rha@open.ch> + +2011-02-20 Timo Teras <timo.teras@iki.fi> + + * src/racoon/oakley.c: From Roman Hoog Antink <rha@open.ch>: Fix + memory leak when using plain RSA key authentication. + +2011-02-11 Timo Teras <timo.teras@iki.fi> + + * src/racoon/plainrsa-gen.c: From Mats E Andersson + <debian@gisladisker.se>: Fix fprintf format specifier usage from + previous patch. + +2011-02-10 Timo Teras <timo.teras@iki.fi> + + * src/racoon/plainrsa-gen.c: From Mats Erik Andersson + <debian@gisladisker.se>: Implement importing of RSA keys from PEM + files. + + * src/racoon/prsa_par.y: From M E Andersson + <debian@gisladisker.se>: Fix parsing of restricted RSA key + addresses. + +2011-02-02 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: cftoken.l, isakmp.c, remoteconf.h, sainfo.c, + sainfo.h: store ph1id in an u_int32_t instead of a (signed)int. + Patch from Christophe Carre + +2011-01-28 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: sainfo.c, sainfo.h, session.c: From Roman Hoog + Antink <rha@open.ch>: Clean up sainfo reloading: rename the + functions, and remove unneeded global variable. + + * src/racoon/: remoteconf.c, remoteconf.h, session.c: From Roman + Hoog Antink <rha@open.ch>: Clean up rmconf reloading: rename the + functions, and remove unneeded global variable. + + * src/racoon/plog.c: From Roman Hoog Antink <rha@open.ch>: Log + remote IP address if available (slightly modified by tteras) + +2011-01-22 Timo Teras <timo.teras@iki.fi> + + * src/racoon/isakmp_inf.c: From Roman Hoog Antink <rha@open.ch>: + Fixes a null pointer dereference that might occur after removing + peers from the config and then reloading. + +2011-01-20 Yvan Vanhullebus <vanhu@netasq.com> + + * src/libipsec/pfkey.c: fixed a typo, it will now compile when + KMADDRESS is defined. reported by Roman Hoog Antink (rha (at) + open.ch) + +2010-12-28 Timo Teras <timo.teras@iki.fi> + + * src/racoon/handler.c: From Roman Hoog Antink <rha@open.ch>: Fix + config reload to not delete too many phase 2 handles, because wrong + chain field is used when enumerating the handles. + +2010-12-16 gdt + + * src/racoon/oakley.c: When encountering a certificate where "ID + mismatched with ASN1 SubjectName", and verify_identifier is off, + don't raise an error. This makes the behavior match the man page. + + Patch sent for review long ago: + http://mail-index.netbsd.org/tech-security/2006/03/24/0000.html + with no negative feedback received to date. + +2010-12-14 Timo Teras <timo.teras@iki.fi> + + * src/racoon/ipsec_doi.c: From Roman Hoog Antink <rha@open.ch>: Fix + possible null derefence. + +2010-12-08 Timo Teras <timo.teras@iki.fi> + + * src/racoon/admin.c: Use separate SA addresses for phase2's + created by admin command. The phase2 startup overwrites src/dst with + ISAKMP ports if they are zero and we don't want that to happen for + the SA ports. + +2010-12-08 joerg + + * src/libipsec/pfkey.c: ANSIfy + +2010-12-07 Timo Teras <timo.teras@iki.fi> + + * src/racoon/isakmp_quick.c: Fix spacing and improve wording in + some log messages. + +2010-12-03 Timo Teras <timo.teras@iki.fi> + + * src/libipsec/ipsec_dump_policy.c: Recognize direction for Linux + per-socket policies. + + * src/: libipsec/libpfkey.h, libipsec/pfkey_dump.c, setkey/parse.y, + setkey/setkey.8: Support GRE key as upper layer protocol + specifier (will be supported in Linux kernel 2.6.38). + + * src/racoon/grabmyaddr.c: Netlink deletion notification does not + guarentee actual address deletion: it might still exist on some + other interface. Make sure we do not unbind unless the address is + really gone. + +2010-11-17 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: handler.c, handler.h, isakmp.c, isakmp_inf.c: Fix my + previous patch to not call purge_remote() twice. Change the place + where purge_remote() is called. This fixes also a possible crash + from the same patch since ph1->remote can be NULL (when we are + responder and config is not yet selected). + +2010-11-12 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: admin.c, isakmp.c, isakmp_var.h, pfkey.c: + isakmp_post_acquire is now called from admin commands too, add a + flag so admin commands can be used to establish even passive links + on demand. + + * src/racoon/isakmp.c: Purge all IPsec-SA's if the last main + ISAKMP-SA for the node is deleted by remote request and the phase1 + rekeying is enabled (this will also trigger the new phase1_dead + script hook). + + * src/racoon/: handler.h, isakmp_inf.c: Improve DPD sequence checks + to allow any reply within valid sequence window to be proof of + livelyness. This can improves things if there's random packet + delays, or if racoon is not getting enough CPU time. + + * src/racoon/: admin.c, admin.h, kmpstat.c, racoonctl.c: Extern + admin protocol to allow reply packets to exceed 64kb. E.g SA dumps + with many established SAs can be easily over the limit. + +2010-10-22 Timo Teras <timo.teras@iki.fi> + + * src/racoon/grabmyaddr.c: Change Linux Netlink address monitoring + to monitor local route changes. This works around a kernel bug, and + slightly improves behaviour on some special cases. + +2010-10-21 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: admin.c, evt.c, grabmyaddr.c, isakmp.c, pfkey.c, + session.c, session.h: Introduce priorities for file descriptor + polling mechanism and give priority to admin port. If admin port is + used by ISAKMP-SA hook scripts they should be preferred, other wise + heavy traffic can delay admin port requests considerably. This in + turn may cause renegotiation loop for ISAKMP-SA. This is mostly + useful for OpenNHRP setup, but can benefit other setups too. + + * src/racoon/: admin.c, handler.c, handler.h: Remove + initial-contact entry when all ISAKMP-SA are purged via adminport. + This will avoid stale security associations if some of the delete + notifications happens to get lost. + +2010-10-20 Timo Teras <timo.teras@iki.fi> + + * src/racoon/crypto_openssl.c: Use high-level openssl EVP and HMAC + functions when possible: this allows openssl to perform hardware + acceleration if available. + + * src/racoon/: isakmp.c, isakmp_quick.c: Various improvements to + error log messages and a few additional error log messages to + improve diagnosing an error condition. + + * src/racoon/grabmyaddr.c: Fix address comparison so we actually + close sockets which were bound to IP-address that got deconfigured. + +2010-10-11 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/ipsec_doi.c: report a higher encryption key length in + approval for OBEY / CLAIM / STRICT modes + +2010-09-27 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/isakmp_xauth.c: fixed some typos in logs (reported by + fazaeli (at) sepehrs.com) + +2010-09-24 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/cftoken.l: fixed a fd leak, patch by getlaser (at) + gmail.com + +2010-09-22 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/admin.c: get the correct length of username when + processing ADMIN_LOGOUT_USER, patch by rweikusat (at) mssgmbh.com + + * src/racoon/nattraversal.h: fixed a typo in macros, reported by + marisp (at) mt.lv + +2010-09-21 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/isakmp_cfg.c: moved from utmp.h to utmpx.h (patch + provided by marcin.cieslak (at) gmail.com) + +2010-09-08 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/remoteconf.c: fixed remoteconf selection when no ID + specified in configuration, and added some debug to remoteconf + selection + +2010-08-26 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/remoteconf.c: fix by Sergio.Gelato (at) astro.su.se: + duplicate some dynamic values in duprmconf() + +2010-08-04 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/isakmp_cfg.c: fixed answer for IP4_SUBNET request + +2010-07-30 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/doc/FAQ: updated link to NetBSD's documentation + +2010-06-22 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Bump date for previous. + +2010-06-22 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/: cfparse.y, cftoken.l, isakmp.c, isakmp_inf.c, + racoon.conf.5, remoteconf.c, remoteconf.h: added a specific + script hook when a dead peer is detected + +2010-06-04 Thomas Klausner <wiz@netbsd.org> + + * src/setkey/setkey.8: New sentence, new line. Bump date for + previous. + +2010-06-04 Yvan Vanhullebus <vanhu@netasq.com> + + * src/setkey/: parse.y, setkey.8, token.l: Added support for + spdupdate command in setkey + +2010-04-07 Yvan Vanhullebus <vanhu@netasq.com> + + * src/libipsec/ipsec_strerror.c: by Eric Preston: fixed a typo + +2010-04-02 Christos Zoulas <christos@netbsd.org> + + * src/: libipsec/pfkey_dump.c, racoon/backupsa.c: handle ctime + returning NULL. + +2010-03-11 Christos Zoulas <christos@netbsd.org> + + * src/racoon/handler.c: PR/42363: Yasuoka Masahiko: Second part of + the patch: iterate only on the phase2 handles that are bound by the + given phase1 handle. + +2010-03-05 Timo Teras <timo.teras@iki.fi> + + * src/: libipsec/ipsec_set_policy.3, racoon/privsep.c, + racoon/doc/FAQ, setkey/setkey.8: From Stefan Bauer: Fix multiple + typoes and manpage formatting errors. - * NEWS, configure.ac: 0.7.3 release +2010-03-04 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/session.c: From Pierre POMES: fixed admin port + initialization + +2010-02-28 snj + + * src/racoon/: sockmisc.c, sockmisc.h: Fight the ever-increasing + size of src checkouts by spelling "useful" without an extra l. + +2010-02-09 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/: pfkey.c, proposal.h: Fix typo in comment. + +2010-01-17 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/sainfo.c: Free strdeupped string after using it. Found + by cppcheck. + + * src/racoon/: eaytest.c, ipsec_doi.c: Close file handles after + using them. Found by cppcheck. + +2010-01-15 joerg + + * src/setkey/setkey.8: Use .%U instead of .%O for URLs. + +2009-12-11 Timo Teras <timo.teras@iki.fi> + + * src/racoon/Makefile.am: From Paul Wernau: vmbuf.h was defined + twice in the headers. Remove the redundant entry so new install tool + does not complain about overwriting just installed file. + +2009-11-22 Christos Zoulas <christos@netbsd.org> + + * src/racoon/handler.c: PR/42363: Yasuoka Masahiko: + + racoon uses a wrong IPsec-SA handle that is for other peer in case + it receives a ISAKMP message for IPsec-SA that has the same + message-id as the message-id that is received before. + + racoon uses message-id to find the handle of IPsec-SA. The + message-id is a unique number for each peer, but different peers may + use the same value. + + Different Windows Vista or Windows 7 peers seem to use the same + message-id. racoon can handle the first Windows's Phase-2, but it + cannot handle the second Windows. Because racoon misunderstands the + message for the second Windows as the message for the first Windows. + + >Category: bin >Synopsis: racoon uses a wrong IPsec-SA + that is for different peer >Confidential: no >Severity: + serious >Priority: medium >Responsible: bin-bug-people + >State: open >Class: sw-bug >Submitter-Id: net + >Arrival-Date: Sun Nov 22 18:25:00 +0000 2009 >Originator: + yasuoka@iij.ad.jp + +2009-10-29 Christos Zoulas <christos@netbsd.org> + + * src/setkey/token.l: use %option noinput nounput + +2009-10-28 Christos Zoulas <christos@netbsd.org> + + * src/setkey/token.l: no unput + +2009-10-14 joerg + + * src/libipsec/ipsec_set_policy.3: Do not use .Xo/.Xc to workaround + ancient groff limits. + + * src/setkey/setkey.8: Do not use .Xo/.Xc to work around ancient + groff limits. Fix markup. + + * src/racoon/racoon.conf.5: Don't use .Xo/.Xc to work around + ancient groff limits. Set only one list type. + +2009-09-18 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: isakmp_agg.c, isakmp_ident.c: From Tomas Mraz: Fix + gssapi error checking. + +2009-09-03 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: admin.c, handler.c, handler.h, isakmp.c, + isakmp_var.h, pfkey.c: When rekeying phase2 use phase1 used to + negotiate phase2 as a hint to select the phase1 for rekeying the new + phase2. + +2009-09-01 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: nattraversal.c, racoon.conf.5, vendorid.c: Check + nat_traversal configuration from remote configuration candidates + when acting as responder. Enable NAT-T if any of the remote + candidates have NAT-T enabled. + + * src/racoon/remoteconf.c: Change remote conf matching level to + matching score. This way one can override anonymous certificate + block config with more exact "inhereted" IP specific block. + + * src/racoon/: isakmp.c, racoon.conf.5: From Maik Broemme: export + ISAKMP SA identity as REMOTE_ID for phase1 up script (trac #313). + +2009-08-24 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/oakley.c: fixed typo: algoriym -> algorithm + +2009-08-19 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/remoteconf.c: fixed address check in + rmconf_match_type(), just check address with wildcard port + +2009-08-19 Timo Teras <timo.teras@iki.fi> + + * src/racoon/remoteconf.c: Have an enum for rmconf_match_type() + return values to make the code a bit more readable. + +2009-08-18 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/oakley.c: typo: algoritym -> algorithm + +2009-08-17 Yvan Vanhullebus <vanhu@netasq.com> + + * src/libipsec/libpfkey.h: do not use SADB_X_NAT_T_NEW_MAPPING to + check system support for NAT-T, as at least FreeBSD doesn't have + this define anymore + + * src/racoon/schedule.h: include stddef.h so we have a chance to + get the system offsetof if present + + * src/racoon/crypto_openssl.h: removed a self include + +2009-08-13 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/oakley.c: fixed a potential DoS in oakley_do_decrypt(), reported by Orange Labs +2009-08-10 Timo Teras <timo.teras@iki.fi> + + * src/racoon/pfkey.c: Don't print EAGAIN error from + pfkey_handler(), it can occur normally under some code paths and is + not a hard error in any case. + 2009-08-06 Timo Teras <timo.teras@iki.fi> * src/setkey/setkey.c: From Paul Wenau: Check fgets return value in setkey to make gcc happy. -2009-06-19 Timo Teras <timo.teras@iki.fi> +2009-08-05 Timo Teras <timo.teras@iki.fi> + + * src/racoon/pfkey.c: From Paul Wernau: Fix transport mode per-port + security associations that got broke during NAT-T fixes. + +2009-07-07 Timo Teras <timo.teras@iki.fi> + + * src/racoon/sockmisc.c: From Arnaud Ebalard: Fix possible usage of + uninitialized local variable (not sure if any code path triggers + this, but this makes compiler happy). + +2009-07-03 Timo Teras <timo.teras@iki.fi> - * src/racoon/ipsec_doi.c: Backport S.P.Zeidler's fix to IPv6 - address related stack smashing in ipsecdoi_id2str() from CVS HEAD. + * src/racoon/: admin.c, grabmyaddr.c, handler.c, handler.h, + isakmp.c, isakmp_cfg.c, isakmp_inf.c, isakmp_quick.c, + nattraversal.c, pfkey.c, policy.c, remoteconf.c, remoteconf.h, + sockmisc.c, sockmisc.h, throttle.c: Get rid of the evil CMPSADDR + macro. Trac #295. + + * src/: libipsec/libpfkey.h, libipsec/pfkey.c, racoon/isakmp.c, + racoon/isakmp_inf.c, racoon/pfkey.c, racoon/pfkey.h: From Yvan + Vanhullebus: Use SADB_X_EXT_NAT_T_* consistently for passing the + NAT-T port information. This might break compatibility with some + kernels, but as discussed this is the proper way to pass NAT-T ports + and the broken kernels need to be fixed. + +2009-06-24 Timo Teras <timo.teras@iki.fi> + + * src/racoon/session.c: Fix a call to null pointer: in some cases, + the unmonitor_fd can be called from another fd's callback. That + could lead to still have callback pending after unmonitoring the fd + resulting in a call to null pointer. This is fixed by making + unmonitor_fd now clear the pending fd_set too. Bug was introduced + by my commit in 2008-12-23. + +2009-05-20 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/isakmp.h: typo + +2009-05-19 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: ipsec_doi.c, isakmp.c: From Jukka Salmi: Fix couple + of typos from previous commit. 2009-05-18 Timo Teras <timo.teras@iki.fi> + * src/racoon/: ipsec_doi.c, isakmp.c, sockmisc.c, sockmisc.h: From + Tomas Mraz: Introduce union sockaddr_any and use it to make code + more readable. Related to trac #293. + * src/racoon/isakmp_inf.c: From Tomas Mraz: Remove variable that is not really used; only referenced while uninitialized causing valgrind error. * src/racoon/nattraversal.c: From Tomas Mraz: Fix natt_flags check. +2009-05-04 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Remove superfluous spaces around + parentheses. + 2009-04-29 Timo Teras <timo.teras@iki.fi> * src/racoon/crypto_openssl.c: From Ross Meng: Fix a memory leak in X509 certificate validation. -2009-04-22 tag ipsec-tools-0_7_2 +2009-04-28 Timo Teras <timo.teras@iki.fi> -2009-04-22 Timo Teras <timo.teras@iki.fi> + * src/racoon/handler.c: Reset nat_oa variables too when reusing + phase two handler. Otherwise phase2 rekeying might fail in some + scenarios. - * NEWS, configure.ac: Updates for 0.7.2 release +2009-04-22 Timo Teras <timo.teras@iki.fi> * src/racoon/isakmp_frag.c: From Neil Kettle: Fix a possible null pointer dereference in fragmentation code. +2009-04-21 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: grabmyaddr.c, grabmyaddr.h, session.c: Fix + strict_address to work again. The lists needs to be initialized + before configuration is read, which happens before my_addr_init() + call. + 2009-04-20 Timo Teras <timo.teras@iki.fi> + * src/racoon/: isakmp.c, isakmp.h, isakmp_var.h: Fix a memory leak + in certificate request generation. + * src/racoon/: isakmp_inf.c, isakmp_xauth.c, plog.c: Orignally from Bin Li: Fix possible memory corruption in binsanitize(). @@ -56,25 +584,257 @@ * src/racoon/handler.c: From Paul Moore: Phase2 message id's should be unique wrt phase1, not globally. +2009-03-13 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: pfkey.c, remoteconf.h: From Arnaud Ebalard: Fix + couple of problems with previous commit. + +2009-03-12 he + + * src/racoon/: isakmp.c, remoteconf.c: When casting to/from a + pointer to an integral type (a bad practice, if you ask me), you + need to cast via intptr_t for portability. + +2009-03-12 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: New sentence, new line. Avoid marking + up punctuation. + + * src/racoon/racoonctl.8: Bump date for previous. Sort options to + establish-sa. Stop using Xo/Xc. + +2009-03-12 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: admin.c, cfparse.y, cftoken.l, crypto_openssl.c, + crypto_openssl.h, dnssec.c, dnssec.h, handler.c, handler.h, + ipsec_doi.c, ipsec_doi.h, isakmp.c, isakmp.h, isakmp_agg.c, + isakmp_base.c, isakmp_ident.c, isakmp_inf.c, isakmp_quick.c, + isakmp_var.h, nattraversal.c, oakley.c, oakley.h, racoon.conf.5, + racoonctl.8, racoonctl.c, remoteconf.c, remoteconf.h, sockmisc.c, + vendorid.c: Support multiple anonymous remotes and decide + remoteconf based on identity, received certificates and other + information. General code clean up. + +2009-03-06 Timo Teras <timo.teras@iki.fi> + + * src/setkey/: extern.h, parse.y, setkey.c: setkey: fix deleteall + in Linux + + Linux requires SADB_DELETE message to have SPI. So send a + SADB_DELETE message for each matching SA. Trac #284. + + From: Gabriel Somlo <somlo@cmu.edu> + 2009-02-16 Timo Teras <timo.teras@iki.fi> * src/libipsec/policy_parse.y: From Paul Moore: Fix a heap corruption bug (yacc return non-null terminated buffer and sprintf writes over bounds). -2009-01-20 Timo Teras <timo.teras@iki.fi> +2009-02-11 Yvan Vanhullebus <vanhu@netasq.com> - * configure.ac: Fix a CPPLAGS typo to CPPFLAGS which was intended + * src/racoon/: isakmp.c, sockmisc.c, sockmisc.h: trac#301: fixed + IPsec SAs flush in purge_remote() when NAT-T enabled but no NAT-T on + tunnel + +2009-02-03 Timo Teras <timo.teras@iki.fi> + + * src/racoon/isakmp.c: From: Phil Sutter. Fix script environment + variables with IPv6 addresses. + +2009-01-26 Timo Teras <timo.teras@iki.fi> + + * src/racoon/main.c: Argument parsing needs lcconf initialized. + +2009-01-24 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoonctl.c: Sort options in usage. + + * src/racoon/racoonctl.8: Sort options. New sentence, new line. + + * src/racoon/racoon.8: Sort options. + +2009-01-23 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: racoonctl.8, racoonctl.c: Update usage and manpage + for racoonctl. + + * src/racoon/: main.c, racoon.8: Racoon -v to print version and + compilation information. Update usage message. - * misc/cvs2cl.pl, misc/cvsusermap, Makefile.am: Autogenerate + * NEWS: Update NEWS with major changes since 0.7 release. + + * src/racoon/schedule.c: Fix monotonic scheduler change, to not + refresh 'now' before exit. Otherwise we can return negative timeout + after spending time handling other events. + + * src/racoon/: handler.c, pfkey.c: From Arnaud Ebalard: Handle + reception of MIGRATE message during Phase 1 and Phase 2 negotiation. + Also corrects some debugging statements. + + * src/racoon/pfkey.c: From Arnaud Ebalard: On the responder (for + instance), there is a need to not only migrate local and remote + addresses of Phase 1 that match previous addresses but also the + local and remote addresses of a Phase 1 *associated* with a migrated + Phase 2. For instance, we have that need when receiving the first + MIGRATE/KMADDRESS message because the old addresses are still the + HoA and the address of the HA (while the peer has contacted us using + the CoA and we have negotiated this address as src attribute in + Phase 2). The patch fixes that by having migrate_ph1_ike_addresses() + called from migrate_ph2_ike_addresses() callback. + + * src/racoon/isakmp_quick.c: From Arnaud Ebalard: Set phase2 spid + when acting as responder. + + * configure.ac, src/racoon/handler.c, src/racoon/handler.h, + src/racoon/isakmp_inf.c, src/racoon/isakmp_xauth.c, + src/racoon/schedule.c, src/racoon/schedule.h, + src/racoon/throttle.c, src/racoon/throttle.h: Detect if monotonic + system clock is available, and use it for relative time measurements + to avoid complite hang if time jumps backwards. + + * src/racoon/: cfparse.y, ipsec_doi.c, isakmp.c, isakmp_agg.c, + isakmp_base.c, isakmp_cfg.c, isakmp_ident.c, isakmp_xauth.c, + oakley.c, oakley.h: Fix authentication method ambiguity by + internally using unique ID and setting/interpreting the wire format + based on received vendor ID:s. Fixes trac #280. + + * src/racoon/: handler.h, isakmp_agg.c, isakmp_base.c, + isakmp_ident.c, vendorid.c, vendorid.h: Introduce vendorid + bitmask that can be used otherwhere to detect peer capabilities. + + * configure.ac, src/racoon/admin.c, src/racoon/evt.c, + src/racoon/grabmyaddr.c, src/racoon/isakmp.c, src/racoon/pfkey.c, + src/racoon/session.c, src/racoon/session.h: Remove "fastquit" + configure option and make it the default behaviour. The previous + normal behaviour is buggy, as after flush kernel can immediately + create larval SA:s which would prevent exit. + +2009-01-20 Timo Teras <timo.teras@iki.fi> + + * Makefile.am, misc/cvs2cl.pl, misc/cvsusermap: Autogenerate ChangeLog from NetBSD CVS. Put sourceforge.net changes to ChangeLog.old. - * misc/cvs2cl.pl: file cvs2cl.pl was added on branch - ipsec-tools-0_7-branch on 2009-01-20 14:36:32 +0000 +2009-01-10 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Make ready for HTML output. Use proper + escape for backslash ('\e'). + +2009-01-10 Timo Teras <timo.teras@iki.fi> - * misc/cvsusermap: file cvsusermap was added on branch - ipsec-tools-0_7-branch on 2009-01-20 14:36:32 +0000 + * src/racoon/: crypto_openssl.c, racoon.conf.5: From Cyrus Rahman: + Accept RFC2253 compliant escaped special characters for asn1dn + identifier. + +2009-01-09 Timo Teras <timo.teras@iki.fi> + + * configure.ac: Fix a CPPLAGS typo to CPPFLAGS which was intended + +2009-01-05 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: cfparse.y, cftoken.l, racoon.conf.5: Remove obsolete + configuration options, fix radius configuration block and add GRE as + recognized protocol. + + * src/racoon/session.c: Do not use counting in signal handling as + it was unsafe by not using atomic functions (post increment is not + necessarily atomic). Instead reap all children on SIGCHLD as that + was the only signal needing signal counting. + +2008-12-30 Timo Teras <timo.teras@iki.fi> + + * src/racoon/session.c: schedular() call can now modify fd mask so + make the working copy just before calling select(); otherwise it can + contain bad file descriptors + +2008-12-29 Michael van Elst <mlelstv@netbsd.org> + + * src/setkey/parse.y: support icmp codes. Fixes PR 39056. + +2008-12-24 Christos Zoulas <christos@netbsd.org> + + * src/racoon/grabmyaddr.c: remove sin{6,}_len linux does not have + it. From Timo Teras. + + * src/racoon/grabmyaddr.c: I was wrong. addr is actually set. + + * src/racoon/grabmyaddr.c: + - make this compile by zeroing out the whole structure not just + bogus fields. + - set length field of sockets appropriately. + - mark bogus no-op code (I don't understand what the author intended + here). + +2008-12-23 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Bump date for identity configuration + option removal. + +2008-12-23 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: cfparse.y, cftoken.l, ipsec_doi.c, localconf.c, + localconf.h, racoon.conf.5: Remove the obsoleted global identity + configuration option. + + * src/racoon/: admin.c, admin_var.h, cfparse.y, debug.h, evt.c, + evt.h, grabmyaddr.c, grabmyaddr.h, handler.c, isakmp.c, + isakmp_inf.c, isakmp_var.h, localconf.c, localconf.h, main.c, + nattraversal.c, pfkey.c, pfkey.h, privsep.c, session.c, + session.h: rewrite local address detection make some functions + static that arr not needed globally rework how fd_set is + construction for the main loop select() + +2008-12-18 Timo Teras <timo.teras@iki.fi> + + * src/racoon/pfkey.c: From Arnaud Ebalard: Delete larval ph2handles + when expire with hard lifetime received + +2008-12-16 Timo Teras <timo.teras@iki.fi> + + * README: Update README + + * src/racoon/pfkey.c: Fix transport mode address selection in + acquire handling. Some earlier fixes got lost on 2008-12-05 commit. + +2008-12-11 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/grabmyaddr.c: Fixed compilation on FreeBSD (RTM_IFINFO + and RTM_OIFINFO stuff) + + * src/racoon/isakmp.c: Fixed compilation when DPD support is + disabled + +2008-12-08 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: pfkey.c, privsep.c, privsep.h: Do not cache pfkey + sockets: it might cause to not handle some pfkey events when + select() has marked pfkey socket readable, but a timer callback + first calls pfkey_dump_sadb(). + +2008-12-05 Timo Teras <timo.teras@iki.fi> + + * src/: libipsec/key_debug.c, libipsec/libpfkey.h, + libipsec/pfkey.c, racoon/handler.c, racoon/handler.h, + racoon/ipsec_doi.c, racoon/isakmp.c, racoon/isakmp_quick.c, + racoon/pfkey.c, racoon/policy.c, racoon/policy.h: From Arnaud + Ebalard: Improved Mobile IPv6 support per + draft-ebalard-mext-pfkey-enhanced-migrate. + +2008-12-04 Christoph Badura <bad@netbsd.org> + + * src/racoon/privsep.c: Fix typo in previous and use SIG_IGN as I + intended. + +2008-12-02 Timo Teras <timo.teras@iki.fi> + + * src/racoon/session.c: Explicitly ignore SIGPIPE. Default action + on Linux is terminate. + +2008-11-28 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Remove empty line. Fix typo. New + sentence, new line. 2008-11-27 Yvan Vanhullebus <vanhu@netasq.com> @@ -83,26 +843,181 @@ * src/racoon/isakmp_cfg.c: Fixed pool resizing +2008-11-27 Timo Teras <timo.teras@iki.fi> + + * src/racoon/pfkey.c: From Arnaud Ebalard: Remove MAXNESTEDSA + weirdness. It's probably meant for bundle support which is not done. + When someone actually writes bundle support, the nested SA stuff + would probably be reworked too anyway. + + * src/: libipsec/libpfkey.h, libipsec/pfkey.c, racoon/cfparse.y, + racoon/cftoken.l, racoon/localconf.c, racoon/localconf.h, + racoon/pfkey.c, racoon/racoon.conf.5: From: Matthew Krenzer + Ability to set pfkey socket buffer size via configuration file + directive. (Indentation and minor fixes by me.) + +2008-11-25 Christoph Badura <bad@netbsd.org> + + * src/racoon/: evt.c, privsep.c, session.c: Avoid using + MSG_NOSIGNAL as it is not available everywhere. Ignore SIGPIPE + instead. + + * src/racoon/grabmyaddr.c: Ignore unspecified and looback + addresses. Ignoring unspecified addresses prevents racoon from + trying to bind to the wildcard address and specific addresses + simultaneously after e.g. dhclient has changed an interface's + address to 0.0.0.0. + + * src/racoon/grabmyaddr.c: RTM_DELETE and RTM_IFINFO don't carry + info for added or deleted addresses. Ignore them silently. + + * src/racoon/grabmyaddr.c: Ignoring an unsuitable address is not an + error. Therefore log it as informational. Make it clear from the + log message that a route message is not interesting. + + * src/racoon/grabmyaddr.c: Use insmyaddr() instead of open coding + it. + + * src/racoon/isakmp.c: Do not return erroneously from isakmp_open() + when setting IPV6_USE_MIN_MTU fails. + + * src/racoon/: grabmyaddr.c, isakmp.c: Keep myaddr.sock at -1 when + no socket is opened. + +2008-11-08 Christoph Badura <bad@netbsd.org> + + * src/racoon/samples/roadwarrior/client/: phase1-down.sh, + phase1-up.sh: Preserve owner and permissions of original + /etc/resolv.conf. Ensure that new /etc/resolv.conf isn't group or + world writable. + + * src/racoon/samples/roadwarrior/client/: phase1-down.sh, + phase1-up.sh: Print and check INTERNAL_NETMASK4. + + * src/racoon/samples/roadwarrior/client/: phase1-down.sh, + phase1-up.sh: Make the handling of NAT-T SPD entries automatic. + + * src/racoon/samples/roadwarrior/client/: phase1-down.sh, + phase1-up.sh: Ensure that the determination of the default + gateway and the corresponding interface don't get confused by + multiple, possibly non-IPv4 default routes. Bring the NetBSD case + of deleting the VPN routes and address in line with the Linux case + and delete the address after deleting the VPN routes. + +2008-11-06 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/sainfo.c: fixed delsainfo() to avoid a crash when + iddst's value is SAINFO_CLIENTADDR + +2008-10-29 S.P.Zeidler <spz@netbsd.org> + + * src/racoon/ipsec_doi.c: Changes to ipsecdoi_id2str(): + + struct sockaddr -> struct sockaddr_storage fixes a stack overflow + + For non-linklocal addresses the value in 'scope' is garbage and gets + set to zero instead. + +2008-10-27 Timo Teras <timo.teras@iki.fi> + + * src/racoon/pfkey.c: From Arnaud Ebalard: Add missing return to + error path + + * src/racoon/grabmyaddr.c: From Francis Dupont (sent by Arnaud + Ebalard): recognize RTM_IFANNOUNCE + + * src/racoon/grabmyaddr.c: From Arnaud Ebalard: Fix indentation + issues for readability + + * src/racoon/session.c: From Arnaud Ebalard: initfds() needs to be + called only if monitored file descriptor numbers have changed + + * src/racoon/isakmp_var.h: From Arnaud Ebalard: Remove duplicate + declaration + +2008-10-23 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: privsep.c, session.c, session.h: From Krzysztof + Piotr Oledzki <olel@ans.pl>: Revert parts of 2008-08-06 commit; the + problem those changes address are already handled in a sensible way + by Cyrus Rahman's patch from 2008-03-06. + +2008-10-09 Timo Teras <timo.teras@iki.fi> + + * src/racoon/isakmp_quick.c: From Arnaud Ebalard: remove + unnecessary unbindph12() call which is now done in remph2() + 2008-09-25 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/isakmp.c: Fixed resending mechanism to have non-ESP marker for retransmitted packets +2008-09-19 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: New sentence, new line. + +2008-09-19 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: admin.c, cfparse.y, cftoken.l, handler.c, handler.h, + isakmp.c, isakmp_cfg.c, isakmp_inf.c, isakmp_quick.c, + isakmp_var.h, isakmp_xauth.c, pfkey.c, proposal.c, racoon.conf.5, + remoteconf.c, remoteconf.h: Implement ISAKMP SA rekeying + configurable with rekey {on|off|force} option in remote conf. + + * src/racoon/: handler.c, handler.h, isakmp.c, isakmp_inf.c, + isakmp_quick.c, isakmp_var.h, isakmp_xauth.c, isakmp_xauth.h, + nattraversal.c, pfkey.c, pfkey.h, schedule.c, schedule.h, + session.c: Change struct sched to be allocated be the caller to + avoid some memory allocations. Optimize scheduling algorithm to not + scan all entries in the main loop. + 2008-09-17 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/isakmp_inf.c: Fixed port match in purge_ipsec_spi() when NAT-T enabled and trying to purge non NAT-T SAs +2008-09-09 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/pfkey.c: Some calls to set_port() were not correctly + updated in the previous commit + +2008-09-03 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/pfkey.c: From Tomas Mraz: Duplicate addresses in + pk_sendxxx functions, as they may be altered for NAT-T stuff. + +2008-09-03 Timo Teras <timo.teras@iki.fi> + + * src/: libipsec/pfkey.c, racoon/pfkey.c, racoon/sockmisc.c: + - Fix reloading of SPD (Linux satype check, handling of SPD dump + responses) + - Remove some spurious error log message from extract_port() + +2008-08-29 Gregory McGarry <gmcgarry@netbsd.org> + + * src/racoon/isakmp.c: Eliminate gcc-specific feature of empty + structures. + + * src/racoon/evt.h: Eliminate superfluous semicolon. + + * src/racoon/: admin.c, admin.h: Eliminate gcc-specific feature of + unnamed structures added recently. + 2008-08-12 Yvan Vanhullebus <vanhu@netasq.com> - * src/racoon/isakmp.c: From Krzysztof Oledzki: Remove ph1handler if - we received an invalid first exchange from initiator. + * src/racoon/isakmp.c: From Krzysztof Piotr Oledzki: Remove + ph1handler if we received an invalid first exchange from initiator. -2008-07-23 tag ipsec-tools-0_7_1 +2008-08-06 Timo Teras <timo.teras@iki.fi> -2008-07-23 Yvan Vanhullebus <vanhu@netasq.com> + * src/racoon/: privsep.c, session.c, session.h: From Krzysztof + Piotr Oledzki: Make privileged process exit if unprivileged process + is terminated and some spelling fixes. - * NEWS: NEWS for 0.7.1 release +2008-07-23 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: cfparse.y, session.c: Add some missing ifdefs + required for non-radius enabled builds. 2008-07-23 Timo Teras <timo.teras@iki.fi> @@ -114,16 +1029,30 @@ 2008-07-22 Yvan Vanhullebus <vanhu@netasq.com> - * configure.ac: 0.7.1 coming ! - * src/racoon/proposal.c: From Kohki Ohhira: fix some memory leaks, when malloc fails or when peer sends invalid proposal. -2008-07-21 Timo Teras <timo.teras@iki.fi> +2008-07-22 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: cfparse.y, cftoken.l, isakmp_cfg.c, isakmp_xauth.c, + isakmp_xauth.h, main.c, racoon.conf.5, session.c: Add an optional + radius configuration section to the racoon.conf file. This is + similar to the the LDAP configuration section and overrides settings + in the system radius configuration file. + +2008-07-21 Matthias Scheler <tron@netbsd.org> * src/racoon/cfparse.y: Correct typo to fix the build. - * src/racoon/cfparse.y: Do not set default gss id if xauth is used. +2008-07-21 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: isakmp_agg.c, isakmp_base.c, isakmp_ident.c, + vendorid.c, vendorid.h: Separate generic vendor id handling to a + new function and use it. + + * src/racoon/cfparse.y: Do not set default gss id if xauth is used, + otherwise gss-id attribute might be sent even if it was not + requested. 2008-07-15 Matthew Grooms <mgrooms@shrew.net> @@ -134,6 +1063,17 @@ racoonctl.c: Fix a conflict with the FreeBSD 8 system hexdump function. +2008-07-14 Timo Teras <timo.teras@iki.fi> + + * src/racoon/: handler.h, ipsec_doi.c, ipsec_doi.h, isakmp_quick.c, + pfkey.c: Handle RESPONDER-LIFETIME notification in quick mode. + + * src/racoon/: handler.h, isakmp.c, isakmp_agg.c, isakmp_ident.c, + isakmp_inf.c, isakmp_inf.h, isakmp_quick.c, strnames.c: Clean up + notification payload handling. Handle INITIAL-CONTACT notification + in last main mode exchange (delayed) and during quick mode + exchanges. + 2008-07-11 Timo Teras <timo.teras@iki.fi> * src/racoon/: isakmp.c, isakmp_inf.c: Original patch from Atis @@ -147,48 +1087,125 @@ 2008-07-02 Yvan Vanhullebus <vanhu@netasq.com> - * src/racoon/isakmp_inf.c: From Timo Teras: fixed some %d to %zu - (size_t values). + * src/racoon/isakmp_inf.c: From Timo Teras: fix some %d to %zu + (size_t values) + +2008-06-18 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoonctl.8: Bump date for previous. 2008-06-18 Matthew Grooms <mgrooms@shrew.net> - * src/racoon/: grabmyaddr.c, admin.c, ipsec_doi.c, isakmp.c, - isakmp_cfg.c, isakmp_inf.c, remoteconf.c: Use utility functions - to evaluate and manipulate network port values. No functional - changes. Submitted by Timo Teras. + * src/racoon/: admin.c, admin.h, racoonctl.8, racoonctl.c: Add an + admin port command to retrieve the peer certificate. Submitted by + Timo Teras. + + * src/racoon/: admin.c, grabmyaddr.c, isakmp.c, misc.c, misc.h: Set + sockets to be closed on exec to avoid potential file descriptor + inheritance issues. Submitted by Timo Teras. + + * src/racoon/: admin.c, grabmyaddr.c, ipsec_doi.c, isakmp.c, + isakmp_cfg.c, isakmp_inf.c, privsep.c, remoteconf.c: Use utility + functions to evaluate and manipulate network port values. No + functional changes. Submitted by Timo Teras. + + * src/racoon/: admin.c, racoonctl.c: Admin port code cleanup. No + functional changes. Submitted by Timo Teras. + + * src/racoon/pfkey.c: Correct a phase2 status event. Submitted by + Timo Teras. + +2008-05-24 Christos Zoulas <christos@netbsd.org> + + * src/racoon/privsep.c: Coverity CID 5018: Fix double frees. + +2008-05-08 Emmanuel Dreyfus <manu@netbsd.org> + + * configure.ac: From Christian Hohnstaedt: allow out of tree + building + +2008-04-30 Martin Husemann <martin@netbsd.org> + + * netbsd-import.sh: Convert TNF licenses to new 2 clause variant 2008-04-25 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/isakmp_inf.c: From Timo Teras: extract port numbers from SADB_X_EXT_NAT_T[SD]PORT if present in purge_ipsec_spi(). +2008-04-13 Christos Zoulas <christos@netbsd.org> + + * src/racoon/privsep.c: for symmetry set controllen the same way we + set it on the receiving side. + +2008-04-02 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/: Makefile.am, sockmisc.c, sockmisc.h: fix Linux build + +2008-03-28 Christos Zoulas <christos@netbsd.org> + + * src/racoon/privsep.c: properly fix the variable stack allocation + code. + +2008-03-28 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/privsep.c: Still from Cyrus Rahman: fix file + descriptor leak introduced by previous commit. + + * src/racoon/: Makefile.am, isakmp.c, isakmp_inf.c, privsep.c, + privsep.h, sockmisc.c, doc/README.privsep: From Cyrus Rahman: + Allow interface reconfiguration when running in privilege separation + mode, document privilege separation + 2008-03-06 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/oakley.c: Generates a log if cert validation has been disabled by configuration +2008-03-06 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/: privsep.c, session.c: From Cyrus Rahman + <crahman@gmail.com> privilegied instance exit when unprivilegied one + terminates. Save PID in real root, not in chroot + +2008-03-06 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: admin.c, isakmp.c, isakmp_var.h, pfkey.c, + racoonctl.8, racoonctl.c: Add the ability to initiate IPsec SA + negotiations using the admin socket. Submitted by Timo Teras. + + * src/racoon/: admin.c, admin.h, evt.c, evt.h, handler.c, + handler.h, isakmp.c, isakmp_agg.c, isakmp_base.c, isakmp_cfg.c, + isakmp_ident.c, isakmp_inf.c, isakmp_var.h, isakmp_xauth.c, + racoonctl.8, racoonctl.c, session.c: Refactor admin socket event + protocol to be less error prone. Backwards compatibility is + provided. Submitted by Timo Teras. + 2008-03-05 Matthew Grooms <mgrooms@shrew.net> * src/racoon/cfparse.y: Properly initialize the unity network struct to prevent erroneous protocol and port info from being transmitted. - * src/racoon/pfkey.c: Provide better handling for pfkey socket read + * src/racoon/: pfkey.c, pfkey.h, session.c: Reload SPD on SIGHUP or + adminport reload. Also provide better handling for pfkey socket read errors. Submitted by Timo Teras. 2008-02-25 Emmanuel Dreyfus <manu@netbsd.org> - * src/racoon/ipsec_doi.c: From Brian Haley <brian.haley@hp.com>: + * src/racoon/ipsec_doi.c: From Brian Haley <brian.haley@hp.com> There's a cut/paste error in cmp_aproppair_i(), it's supposed to be checking spi_size but it's not. I'm not sure this patch is correct, but what's there isn't either. - Add fogotten entry in ChangeLog - 2008-02-22 Emmanuel Dreyfus <manu@netbsd.org> - * src/racoon/isakmp.c: Fix bad address length computation, from - Brian Haley. + * src/racoon/isakmp.c: Fix address length, from Brian Haley + +2008-02-10 S.P.Zeidler <spz@netbsd.org> + + * src/racoon/ipsec_doi.c: closes PR bin/37644 did not meet violent + opposition ( :) ) on ipsec-tools-devel 2008-01-11 Yvan Vanhullebus <vanhu@netasq.com> @@ -208,12 +1225,58 @@ * src/racoon/: handler.c, handler.h: added an 'established' arg to getph1byaddr() +2007-12-31 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: policy.c, racoonctl.8, racoonctl.c: Add GRE protocol + number to racoonctl. Correct id wildcard matching for transport + mode. Submitted by Timo Teras. + +2007-12-12 Matthew Grooms <mgrooms@shrew.net> + + * NEWS, src/racoon/isakmp_quick.c: Add corrections submitted in a + follow up patch for the nat-t oa support. + + * src/racoon/: handler.c, handler.h, isakmp_quick.c, pfkey.c: Add + support for nat-t oa payload handling. Submitted by Timo Teras. + +2007-12-04 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: ipsec_doi.c, ipsec_doi.h, isakmp_quick.c: Modify + ipsecdoi_sockaddr2id() to obtain an id without specifying the exact + prefix length. Correct a memory leak in phase2. Both submitted by + Timo Teras. + +2007-12-01 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Fix typos. New sentence, new line. + 2007-11-29 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/Makefile.am: From Natanael Copa: fixed a race condition when building yacc stuff. -2007-11-06 Yvan Vanhullebus <vanhu@netasq.com> +2007-11-09 Yvan Vanhullebus <vanhu@netasq.com> + + * src/racoon/pfkey.c: From Arnaud Ebalard: Some sanity checking in + pk_recv() + + * src/racoon/policy.c: From Arnaud Ebalard: Better matching of SPD + entries in getsp_r(). + + * src/racoon/isakmp_quick.c: From Arnaud Ebalard: Added some debug + in get_proposal_r(). + +2007-10-19 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/: isakmp_cfg.c, isakmp_unity.c, isakmp_unity.h, + racoon.conf.5: Add SPLITNET_{INCLUDR_LOCAL}_CIDR to hook scripts + +2007-10-15 Yvan Vanhullebus <vanhu@netasq.com> + + * src/libipsec/pfkey.c: Try to increase the buffer size of the + pfkey socket, this may help things when we have a huge SPD + +2007-10-02 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/crypto_openssl.c: From Scott Lamb: include plog.h to work with the new plog macro. @@ -223,34 +1286,53 @@ * src/racoon/: plog.c, plog.h: From Scott Lamb: new plog macro. -2007-10-15 Yvan Vanhullebus <vanhu@netasq.com> +2007-09-19 Matthew Grooms <mgrooms@shrew.net> - * src/libipsec/pfkey.c: Try to increase the buffer size of the - pfkey socket, this may help things when we have a huge SPD + * src/racoon/isakmp.c: Set REUSE option on sockets to prevent + failures associated with closing and immediately re-opening. + Submitted by Gabriel Somlo. -2007-09-19 Matthew Grooms <mgrooms@shrew.net> + * src/racoon/isakmp_unity.c: Prevent duplicate entries in splitnet + list. Submitted by Gabriel Somlo. + +2007-09-13 Matthew Grooms <mgrooms@shrew.net> * configure.ac: Fix autoconf check for selinux support. Submitted by Joy Latten. +2007-09-12 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/: cfparse.y, cftoken.l, handler.c, isakmp_quick.c, + pfkey.c, racoon.conf.5, sainfo.c, sainfo.h: Implement clientaddr + sainfo remote id option and refine the sainfo man page syntax. + +2007-09-05 Matthew Grooms <mgrooms@shrew.net> + + * src/racoon/sainfo.c: Sort sainfo sections on insert and improve + matching logic. + 2007-09-03 Matthew Grooms <mgrooms@shrew.net> * src/racoon/: cftoken.l, racoon.conf.5: Correct the syntax for wins4 in the man page and add nbns4 as an alias. Pointed out by Claas Langbehn. -2007-08-09 tag ipsec-tools-0_7 +2007-08-07 Emmanuel Dreyfus <manu@netbsd.org> -2007-08-09 Matthew Grooms <mgrooms@shrew.net> + * src/racoon/isakmp_xauth.c: src/racoon/isakmp_xauth.c: Don't mix + up RADIUS authentication and authorization ports. Allow + interoperability with freeradius - * NEWS, configure.ac: Prepare for 0.7 release tag. +2007-07-24 Matthew Grooms <mgrooms@shrew.net> -2007-08-07 Emmanuel Dreyfus <manu@netbsd.org> + * NEWS: Update NEWS file with additional 0.7 improvements. - * src/racoon/isakmp_xauth.c: Don't mix up RADIUS authentication and - authorization ports. Allow interoperability with freeradius +2007-07-18 Matthew Grooms <mgrooms@shrew.net> -2007-08-01 Yvan Vanhullebus <vanhu@netasq.com> + * src/racoon/racoon.conf.5: Various racoon configuration manpage + updates. + +2007-07-18 Yvan Vanhullebus <vanhu@netasq.com> * configure.ac, src/libipsec/ipsec_dump_policy.c, src/libipsec/ipsec_get_policylen.c, @@ -269,58 +1351,50 @@ src/setkey/token.l: use a single PATH_IPSEC_H to fix some path_to_ipsec.h issues -2007-07-24 Matthew Grooms <mgrooms@shrew.net> - - * NEWS: Update NEWS file with additional 0.7 improvements. - -2007-07-18 Matthew Grooms <mgrooms@shrew.net> - - * src/racoon/racoon.conf.5: Various racoon configuration manpage - updates. - 2007-07-16 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/grabmyaddr.c: fixed a socket leak -2007-06-12 tag ipsec-tools-0_7-RC1 - -2007-06-12 tag ipsec-tools-0_7-rc1 - -2007-06-12 Emmanuel Dreyfus <manu@netbsd.org> - - * configure.ac: ipsec-tools used to use tags in lower case - -2007-06-12 Yvan Vanhullebus <vanhu@netasq.com> - - * configure.ac: 0.7-RC1 + * src/racoon/proposal.c: indentation 2007-06-07 Emmanuel Dreyfus <manu@netbsd.org> - * src/racoon/: main.c, policy.h, security.c: From Joy Latten - <latten@austin.ibm.com> Fix file descriptor shortage when using - labeled IPsec. - * src/racoon/isakmp_cfg.c: From Paul Winder - <Paul.Winder@tadpole.com> Fix ignored INTERNAL_DNS4_LIST + <Paul.Winder@tadpole.com>: Fix ignored INTERNAL_DNS4_LIST 2007-06-06 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/: eaytest.c, var.h: From Rong-En Fan: fix compilation with gcc 4.2 -2007-06-06 Emmanuel Dreyfus <manu@netbsd.org> - - * src/racoon/kmpstat.c: From Jianli Liu <jlliu@nortel.com>: Use the - specified socket path instead of the default location - -2007-06-06 Yvan Vanhullebus <vanhu@netasq.com> - * src/racoon/session.c: From Jianli Liu: speed up interfaces update when they change. * src/racoon/handler.c: ignore obsolete lifebyte when validating reloaded configuration +2007-05-31 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/: main.c, policy.h, security.c: From Joy Latten + <latten@austin.ibm.com> Fix file descriptor shortage when using + labeled IPsec. + +2007-05-30 Emmanuel Dreyfus <manu@netbsd.org> + + * src/racoon/kmpstat.c: From Jianli Liu <jlliu@nortel.com>: In + racoonctl, use the specified socket path instead of the default + location + +2007-05-16 Christos Zoulas <christos@netbsd.org> + + * src/racoon/cfparse.y: coverity CID 4168: yyerror() does not + return, so we proceed to de-reference NULL. Make it return -1 + instead like in other places. + + * src/racoon/cfparse.y: coverity CID 4170: yyerror() does not + return, so we proceed to de-reference NULL. Make it return -1 + instead like in other places. + 2007-05-04 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/handler.c: search a ph1 by address if iph2->ph1 is @@ -345,18 +1419,17 @@ * src/racoon/oakley.c: dumps peer's ID and peer's certificate subject /subjectaltname if they don't match -2007-03-29 tag ipsec-tools-0_7-beta3 - -2007-03-29 Emmanuel Dreyfus <manu@netbsd.org> - - * configure.ac: Bump to 0.7beta3 - 2007-03-26 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/isakmp_inf.c: Store the DPD main scheduler in ph1 handler, to be able to cancel it when removing the handler, and some minor cleanups in DPD code +2007-03-24 Christos Zoulas <christos@netbsd.org> + + * src/racoon/isakmp_xauth.c: PR/36069: Huang Yushuo: racoon can't + work with pam_group Set RUSER. + 2007-03-23 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/: ipsec_doi.c, security.c: From Joy Latten: fix a @@ -389,13 +1462,7 @@ * src/racoon/isakmp.c: Consider a negociation timeout when retry_counter is <=0 instead of < 0 -2007-03-06 tag ipsec-tools-0_7-beta2 - -2007-03-06 Emmanuel Dreyfus <manu@netbsd.org> - - * configure.ac: Bump to 0.7beta2 - -2007-03-01 Matthew Grooms <mgrooms@shrew.net> +2007-02-28 Matthew Grooms <mgrooms@shrew.net> * src/racoon/ipsec_doi.c: Add logic to allow ip address ids to be matched to ip subnet ids when appropriate. @@ -423,12 +1490,6 @@ * src/racoon/isakmp.c: Removed a debug printf.... -2007-02-16 tag ipsec-tools-0_7-beta1 - -2007-02-16 Emmanuel Dreyfus <manu@netbsd.org> - - * configure.ac: Bump to 0.7beta1 - 2007-02-16 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/ipsec_doi.c: From Olivier Warin: Fix a %zu in a @@ -436,7 +1497,7 @@ 2007-02-15 Emmanuel Dreyfus <manu@netbsd.org> - * src/racoon/security.c: Missing file for SELinux + * src/racoon/security.c: Missing SELinux file * configure.ac: Missing stuff for SELinux @@ -460,6 +1521,20 @@ deleted from payload instead of just deleting the ISAKMP SA used to protect the informational exchange. +2006-12-26 Arnaud Lacombe <alc@netbsd.org> + + * src/racoon/ipsec_doi.c: CID-4167: check for 'iph1->approval != + NULL' + +2006-12-23 Thomas Klausner <wiz@netbsd.org> + + * src/racoon/racoon.conf.5: Use even more macros. + + * src/racoon/racoon.conf.5: Use more macros. + + * src/racoon/racoon.conf.5: Serial comma, and bump date for + previous. + 2006-12-18 Yvan Vanhullebus <vanhu@netasq.com> * src/racoon/crypto_openssl.c: From Joy Latten: fix a memory leak @@ -3,6 +3,10 @@ all: -Isrc/racoon -Isrc/racoon/missing -DHAVE_CONFIG_H -lcrypto \ src/libipsec/pfkey.c \ src/libipsec/ipsec_strerror.c \ + src/racoon/algorithm.c \ + src/racoon/crypto_openssl.c \ + src/racoon/genlist.c \ + src/racoon/handler.c \ src/racoon/isakmp.c \ src/racoon/isakmp_agg.c \ src/racoon/isakmp_base.c \ @@ -11,21 +15,18 @@ all: src/racoon/isakmp_inf.c \ src/racoon/isakmp_newg.c \ src/racoon/isakmp_quick.c \ - src/racoon/handler.c \ - src/racoon/pfkey.c \ - src/racoon/ipsec_doi.c \ + src/racoon/ipsec_doi-0.7.3.c \ + src/racoon/nattraversal.c \ src/racoon/oakley.c \ - src/racoon/vendorid.c \ + src/racoon/pfkey.c \ src/racoon/policy.c \ - src/racoon/crypto_openssl.c \ - src/racoon/algorithm.c \ src/racoon/proposal.c \ - src/racoon/strnames.c \ + src/racoon/remoteconf.c \ src/racoon/schedule.c \ + src/racoon/sockmisc.c \ src/racoon/str2val.c \ - src/racoon/genlist.c \ + src/racoon/strnames.c \ + src/racoon/vendorid.c \ src/racoon/vmbuf.c \ - src/racoon/sockmisc.c \ - src/racoon/nattraversal.c \ main.c \ setup.c @@ -1,36 +1,38 @@ Version history: ---------------- - -0.7.3 - 23 August 2009 - o Fix a remote crash and a memory leak - o Fixed a NAT-T flag check - o Some code cleanups/compilation fixes with recent gcc - -0.7.2 - 22 April 2009 - o Fix a remote crash in fragmentation code - o Phase2 message identities are phase1 specific (Vista compatibility= - o Autogenerate ChangeLog from cvs metadata - o Fix mode config pool resizing - o NAT-T fixes related to purging of IPsec SA:s and retransmission - o Remove phase1 handler immediately if first exchange is bad - o A bunch of memory leak and possible memory corruptions (triggerable - by bad configuration or startup parameters) - -0.7.1 - 23 July 2008 +0.8 - 18 March 2011 + o Fix authentication method ambiguity with kerberos and xauth + o RFC2253 compliant escaping of asn1dn identifiers (Cyrus Rahman) + o Local address code rewrite to speed things up + o Improved MIPv6 support (Arnaud Ebalard) + o ISAKMP SA (phase1) rekeying + o Improved scheduler (faster algorithm, support monotonic clock) + o Handle RESPONDER-LIFETIME in quick mode + o Handle INITIAL-CONTACT in from main mode too + o Rewritten event handling framework for admin port + o Ability to initiate IPsec SA through admin port + o NAT-T Original Address handling (transport mode NAT-T support) + o clean NAT-T - PFkey support + o support for multiple anonymous remoteconfs + o Remove various obsolete configuration options + o A lot of other bug fixes, performance improvements and clean ups + +0.7.1 - 23 July 2008 o Fixes a memory leak when invalid proposal received o Some fixes in DPD o do not set default gss id if xauth is used o fixed hybrid enabled builds o fixed compilation on FreeBSD8 o cleanup in network port value manipulation - o gets ports from SADB_X_EXT_NAT_T_[SD]PORT if present in purge_ipsec_spi() - o Generates a log if cert validation has been disabled by configuration + o Gets ports from SADB_X_EXT_NAT_T_[SD]PORT if present in + purge_ipsec_spi() + o Generates a log if cert validation has been disabled by + configuration o better handling for pfkey socket read errors o Fixes in yacc / bison stuff o new plog() macro (reduced CPU usage when logging is disabled) - o Try to works better with huge SPD/SAD + o Try to work better with huge SPD/SAD o Corrected modecfg option syntax - o Many other various fixes... 0.7 - 09 August 2007 o Xauth with pre-shared key PSK @@ -63,7 +65,7 @@ Version history: o ESP fragmentation in tunnel mode can be tunned (NetBSD only) o racoon admin interface is exported (header and library) to help building control programs for racoon (think GUI) - o Fixed single DES support; single DES users MUST UPGRADE. + o Fixed single DES support; single DES users MUST UPGRADE. 0.5 - 10 April 2005 o Rewritten buildsystem. Now completely autoconfed, automaked, @@ -91,7 +93,7 @@ Version history: o All source files now have 3-clause BSD license. 0.3 - 14 April 2004 - o Fixed setkey to handle multiline commands again. + o Fixed setkey to handle multiline commands again. o Added command 'exit' to setkey. o Fixed racoon to only Warn if no CRL was found. o Improved testsuite. @@ -11,20 +11,27 @@ in the Linux 2.6+ kernel. It works as well on NetBSD and FreeBSD. IPsec-tools were ported to Linux from the KAME project (http://www.kame.net) by Derek Atkins <derek@ihtfp.com>. -Currently the package is actively maintained and developed -by Michal Ludvig <mludvig@suse.cz>, Aidas Kasparas <a.kasparas@gmc.lt> -Emmanuel Dreyfus <manu@netbsd.org>, VANHULLEBUS Yvan <vanhu@zeninc.net>, -and Fred Senault <fred.letter@lacave.net>. +Currently the package is actively maintained and developed by: + Emmanuel Dreyfus <manu@netbsd.org> + VANHULLEBUS Yvan <vanhu@free.fr> + Matthew Grooms <mgrooms@shrew.net> + Timo Teräs <timo.teras@iki.fi> Sources can be found at the IPsec-Tools home page at: http://ipsec-tools.sourceforge.net/ +And CVS repository is hosted at NetBSD tree: + cvs -danoncvs@anoncvs.netbsd.org:/cvsroot co ipsec-tools + +Bug reports and project wiki is located at: + https://trac.ipsec-tools.net/ + Please report any problems to the mailing list: ipsec-tools-devel@lists.sourceforge.net ipsec-tools-users@lists.sourceforge.net You can also browse the list archive: - http://sourceforge.net/mailarchive/forum.php?forum_id=32000 + http://sf.net/mailarchive/forum.php?forum_name=ipsec-tools-devel Credits: IHTFP Consulting, see http://www.ihtfp.com/ diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop index 6ec7936..9af3ed7 100644 --- a/ThirdPartyProject.prop +++ b/ThirdPartyProject.prop @@ -1,7 +1,7 @@ -# Copyright 2010 Google Inc. All Rights Reserved. -#Fri Jul 16 10:03:09 PDT 2010 -currentVersion=0.7.3 -version=0.7.3 (unreleased) +# Copyright 2011 Google Inc. All Rights Reserved. +#Tue Jul 5 19:05:36 PDT 2011 +currentVersion=0.8.0 +version=0.8.0 isNative=true name=ipsec-tools keywords=ipsec-tools @@ -21,4 +21,6 @@ #define HAVE_SYS_TIME_H 1 #define HAVE_UNISTD_H +#define RETSIGTYPE void + #define ANDROID_PATCHED @@ -16,56 +16,40 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <stdarg.h> #include <signal.h> +#include <poll.h> + +#ifdef ANDROID_CHANGES #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> -#include <sys/select.h> - -#ifdef ANDROID_CHANGES -#include <sys/ioctl.h> -#include <linux/if.h> #include <android/log.h> #include <cutils/sockets.h> #include <private/android_filesystem_config.h> -#include "keystore_get.h" #endif #include "config.h" -#include "libpfkey.h" #include "gcmalloc.h" -#include "vmbuf.h" -#include "crypto_openssl.h" -#include "oakley.h" -#include "pfkey.h" +#include "session.h" #include "schedule.h" -#include "isakmp_var.h" -#include "nattraversal.h" -#include "localconf.h" -#include "sockmisc.h" -#include "grabmyaddr.h" #include "plog.h" -#include "admin.h" -#include "privsep.h" -#include "misc.h" #ifdef ANDROID_CHANGES -static int get_control_and_arguments(int *argc, char ***argv) +static void android_get_arguments(int *argc, char ***argv) { static char *args[32]; int control; int i; if ((i = android_get_control_socket("racoon")) == -1) { - return -1; + return; } do_plog(LLV_DEBUG, "Waiting for control socket"); if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) { do_plog(LLV_ERROR, "Cannot get control socket"); - exit(-1); + exit(1); } close(i); @@ -75,7 +59,7 @@ static int get_control_and_arguments(int *argc, char ***argv) if (recv(control, &bytes[0], 1, 0) != 1 || recv(control, &bytes[1], 1, 0) != 1) { do_plog(LLV_ERROR, "Cannot get argument length"); - exit(-1); + exit(1); } else { int length = bytes[0] << 8 | bytes[1]; int offset = 0; @@ -90,7 +74,7 @@ static int get_control_and_arguments(int *argc, char ***argv) offset += n; } else { do_plog(LLV_ERROR, "Cannot get argument value"); - exit(-1); + exit(1); } } args[i][length] = 0; @@ -100,38 +84,19 @@ static int get_control_and_arguments(int *argc, char ***argv) *argc = i; *argv = args; - return control; -} - -static void bind_interface() -{ - struct ifreq ifreqs[64]; - struct ifconf ifconf = {.ifc_len = sizeof(ifreqs), .ifc_req = ifreqs}; - struct myaddrs *p = lcconf->myaddrs; - - if (ioctl(p->sock, SIOCGIFCONF, &ifconf) == -1) { - do_plog(LLV_WARNING, "Cannot list interfaces"); - return; - } - - while (p) { - int i = ifconf.ifc_len / sizeof(struct ifreq) - 1; - while (i >= 0 && cmpsaddrwop(p->addr, &ifreqs[i].ifr_addr)) { - --i; - } - if (i < 0 || setsockopt(p->sock, SOL_SOCKET, SO_BINDTODEVICE, - ifreqs[i].ifr_name, IFNAMSIZ) == -1) { - do_plog(LLV_WARNING, "Cannot bind socket %d to proper interface", - p->sock); - } - p = p->next; - } + close(control); } #endif extern void setup(int argc, char **argv); -int f_local = 0; + +static int monitor_count; +static struct { + int (*callback)(void *ctx, int fd); + void *ctx; +} monitors[10]; +static struct pollfd pollfds[10]; static void terminate(int signal) { @@ -145,69 +110,60 @@ static void terminated() int main(int argc, char **argv) { - fd_set fdset; - int fdset_size; - struct myaddrs *p; -#ifdef ANDROID_CHANGES - int control = get_control_and_arguments(&argc, &argv); -#endif + do_plog(LLV_INFO, "ipsec-tools 0.8.0 (http://ipsec-tools.sf.net)\n"); signal(SIGHUP, terminate); signal(SIGINT, terminate); signal(SIGTERM, terminate); signal(SIGPIPE, SIG_IGN); - setup(argc, argv); - - do_plog(LLV_INFO, "ipsec-tools 0.7.3 (http://ipsec-tools.sf.net)\n"); atexit(terminated); - eay_init(); - oakley_dhinit(); - compute_vendorids(); - sched_init(); - - if (pfkey_init() < 0 || isakmp_init() < 0) { - exit(1); - } - -#ifdef ENABLE_NATT - natt_keepalive_init(); -#endif - #ifdef ANDROID_CHANGES - bind_interface(); - setuid(AID_VPN); +/* setuid(AID_VPN); */ + android_get_arguments(&argc, &argv); #endif - - FD_ZERO(&fdset); - FD_SET(lcconf->sock_pfkey, &fdset); - fdset_size = lcconf->sock_pfkey; - for (p = lcconf->myaddrs; p; p = p->next) { - FD_SET(p->sock, &fdset); - if (fdset_size < p->sock) { - fdset_size = p->sock; - } - } - ++fdset_size; + setup(argc, argv); while (1) { - fd_set readset = fdset; - struct timeval *timeout = schedular(); - if (select(fdset_size, &readset, NULL, NULL, timeout) < 0) { - exit(1); - } - if (FD_ISSET(lcconf->sock_pfkey, &readset)) { - pfkey_handler(); - } - for (p = lcconf->myaddrs; p; p = p->next) { - if (FD_ISSET(p->sock, &readset)) { - isakmp_handler(p->sock); + struct timeval *tv = schedular(); + int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1; + + if (poll(pollfds, monitor_count, timeout) > 0) { + int i; + for (i = 0; i < monitor_count; ++i) { + if (pollfds[i].revents & POLLHUP) { + do_plog(LLV_ERROR, "fd %d is closed\n", pollfds[i].fd); + exit(1); + } + if (pollfds[i].revents & POLLIN) { + monitors[i].callback(monitors[i].ctx, pollfds[i].fd); + } } } } return 0; } +/* session.h */ + +void monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority) +{ + if (fd < 0 || monitor_count == 10) { + do_plog(LLV_ERROR, "Cannot monitor fd"); + exit(1); + } + monitors[monitor_count].callback = callback; + monitors[monitor_count].ctx = ctx; + pollfds[monitor_count].fd = fd; + pollfds[monitor_count].events = POLLIN; + ++monitor_count; +} + +void unmonitor_fd(int fd) +{ + exit(1); +} + /* plog.h */ void do_plog(int level, char *format, ...) @@ -245,54 +201,3 @@ char *binsanitize(char *data, size_t length) } return output; } - -/* privsep.h */ - -int privsep_pfkey_open() -{ - return pfkey_open(); -} - -void privsep_pfkey_close(int key) -{ - pfkey_close(key); -} - -vchar_t *privsep_eay_get_pkcs1privkey(char *file) -{ - return eay_get_pkcs1privkey(file); -} - -vchar_t *privsep_getpsk(const char *key, int size) -{ - vchar_t *p = NULL; - if (key && (p = vmalloc(size)) != NULL) { - memcpy(p->v, key, p->l); - } - return p; -} - -int privsep_script_exec(char *script, int name, char * const *environ) -{ - return 0; -} - -/* grabmyaddr.h */ - -int getsockmyaddr(struct sockaddr *addr) -{ - struct myaddrs *p; - for (p = lcconf->myaddrs; p; p = p->next) { - if (cmpsaddrstrict(addr, p->addr) == 0) { - return p->sock; - } - } - return -1; -} - -/* misc.h */ - -int racoon_hexdump(void *data, size_t length) -{ - return 0; -} @@ -17,22 +17,29 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netdb.h> +#include <fcntl.h> #include "config.h" +#include "gcmalloc.h" #include "libpfkey.h" #include "var.h" #include "isakmp_var.h" #include "isakmp.h" #include "vmbuf.h" +#include "crypto_openssl.h" #include "oakley.h" #include "ipsec_doi.h" #include "algorithm.h" #include "vendorid.h" +#include "schedule.h" +#include "pfkey.h" +#include "nattraversal.h" #include "proposal.h" #include "sainfo.h" #include "localconf.h" @@ -42,71 +49,43 @@ #include "plog.h" #include "admin.h" #include "privsep.h" +#include "misc.h" -static struct myaddrs myaddrs[2]; -static struct etypes main_mode = { .type = ISAKMP_ETYPE_IDENT }; static struct localconf localconf; -static struct remoteconf remoteconf; static struct sainfo sainfo; static char *pre_shared_key; -static struct sockaddr target; + +static char *interface; +static struct sockaddr *target; +static struct { + struct sockaddr *addr; + int fd; +} myaddrs[2]; struct localconf *lcconf = &localconf; char *script_names[SCRIPT_MAX + 1]; +int f_local = 0; + +/*****************************************************************************/ -static void set_default() +static void add_sainfo_algorithm(int class, int algorithm, int length) { - localconf.myaddrs = &myaddrs[0]; - localconf.port_isakmp = PORT_ISAKMP; - localconf.port_isakmp_natt = PORT_ISAKMP_NATT; - localconf.default_af = AF_INET; - localconf.pad_random = LC_DEFAULT_PAD_RANDOM; - localconf.pad_randomlen = LC_DEFAULT_PAD_RANDOM; - localconf.pad_strict = LC_DEFAULT_PAD_STRICT; - localconf.pad_excltail = LC_DEFAULT_PAD_EXCLTAIL; - localconf.retry_counter = 10; - localconf.retry_interval = 3; - localconf.count_persend = LC_DEFAULT_COUNT_PERSEND; - localconf.secret_size = LC_DEFAULT_SECRETSIZE; - localconf.retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1; - localconf.wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE; - localconf.natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL; - localconf.pathinfo[LC_PATHTYPE_CERT] = "/"; - - remoteconf.etypes = &main_mode; - remoteconf.doitype = IPSEC_DOI; - remoteconf.sittype = IPSECDOI_SIT_IDENTITY_ONLY; - remoteconf.idvtype = IDTYPE_ADDRESS; - remoteconf.nonce_size = DEFAULT_NONCE_SIZE; - - remoteconf.ike_frag = TRUE; - remoteconf.esp_frag = IP_MAXPACKET; - remoteconf.ini_contact = TRUE; - remoteconf.pcheck_level = PROP_CHECK_OBEY; - remoteconf.verify_identifier = FALSE; - remoteconf.verify_cert = TRUE; - remoteconf.getcert_method = ISAKMP_GETCERT_PAYLOAD; - remoteconf.certtype = ISAKMP_CERT_X509SIGN; - remoteconf.getcacert_method = ISAKMP_GETCERT_LOCALFILE; - remoteconf.cacerttype = ISAKMP_CERT_X509SIGN; - remoteconf.send_cert = TRUE; - remoteconf.send_cr = TRUE; - remoteconf.gen_policy = TRUE; - remoteconf.retry_counter = LC_DEFAULT_RETRY_COUNTER; - remoteconf.retry_interval = LC_DEFAULT_RETRY_INTERVAL; - remoteconf.nat_traversal = TRUE; - remoteconf.rsa_private = genlist_init(); - remoteconf.rsa_public = genlist_init(); - remoteconf.dpd = TRUE; - remoteconf.dpd_interval = 0; - remoteconf.dpd_retry = 5; - remoteconf.dpd_maxfails = 5; + struct sainfoalg *p = calloc(1, sizeof(struct sainfoalg)); + p->alg = algorithm; + p->encklen = length; - sainfo.lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; - sainfo.lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; + if (!sainfo.algs[class]) { + sainfo.algs[class] = p; + } else { + struct sainfoalg *q = sainfo.algs[class]; + while (q->next) { + q = q->next; + } + q->next = p; + } } -static void set_address(char *server, char *port) +static void set_globals(char *interfaze, char *server) { struct addrinfo hints = { .ai_flags = AI_NUMERICSERV, @@ -117,73 +96,60 @@ static void set_address(char *server, char *port) #endif .ai_socktype = SOCK_DGRAM, }; - struct addrinfo *r; + struct addrinfo *info; - if (getaddrinfo(server, port, &hints, &r) != 0) { - do_plog(LLV_ERROR, "Cannot resolve server address\n"); + if (getaddrinfo(server, "80", &hints, &info) != 0) { + do_plog(LLV_ERROR, "Cannot resolve address: %s\n", server); exit(1); } - if (r->ai_next) { - do_plog(LLV_WARNING, "Multiple server address found\n"); + if (info->ai_next) { + do_plog(LLV_WARNING, "Found multiple addresses. Use the first one.\n"); } - remoteconf.remote = dupsaddr(r->ai_addr); - freeaddrinfo(r); + target = dupsaddr(info->ai_addr); + freeaddrinfo(info); - myaddrs[0].addr = getlocaladdr(remoteconf.remote); + interface = interfaze; + myaddrs[0].addr = getlocaladdr(target); if (!myaddrs[0].addr) { do_plog(LLV_ERROR, "Cannot get local address\n"); exit(1); } -} + set_port(target, 0); + set_port(myaddrs[0].addr, 0); + myaddrs[0].fd = -1; + myaddrs[1].addr = dupsaddr(myaddrs[0].addr); + myaddrs[1].fd = -1; -static void add_proposal(int auth, int hash, int encryption, int length) -{ - struct isakmpsa *p = calloc(1, sizeof(struct isakmpsa)); - p->prop_no = 1; - p->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT; - p->enctype = encryption; - p->encklen = length; - p->authmethod = auth; - p->hashtype = hash; - p->dh_group = OAKLEY_ATTR_GRP_DESC_MODP1024; - p->vendorid = VENDORID_UNKNOWN; - p->rmconf = &remoteconf; + localconf.port_isakmp = PORT_ISAKMP; + localconf.port_isakmp_natt = PORT_ISAKMP_NATT; + localconf.default_af = AF_INET; + localconf.pad_random = LC_DEFAULT_PAD_RANDOM; + localconf.pad_randomlen = LC_DEFAULT_PAD_RANDOM; + localconf.pad_strict = LC_DEFAULT_PAD_STRICT; + localconf.pad_excltail = LC_DEFAULT_PAD_EXCLTAIL; + localconf.retry_counter = 10; + localconf.retry_interval = 3; + localconf.count_persend = LC_DEFAULT_COUNT_PERSEND; + localconf.secret_size = LC_DEFAULT_SECRETSIZE; + localconf.retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1; + localconf.wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE; + localconf.natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL; - if (!remoteconf.proposal) { - p->trns_no = 1; - remoteconf.proposal = p; - } else { - struct isakmpsa *q = remoteconf.proposal; - while (q->next) { - q = q->next; - } - p->trns_no = q->trns_no + 1; - q->next = p; - } + sainfo.lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; + sainfo.lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; + add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_SHA1, 0); + add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_MD5, 0); + add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_3DES, 0); + add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_DES, 0); + add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_AES, 128); } -static void add_sainfo_algorithm(int class, int algorithm, int length) -{ - struct sainfoalg *p = calloc(1, sizeof(struct sainfoalg)); - p->alg = algorithm; - p->encklen = length; - - if (!sainfo.algs[class]) { - sainfo.algs[class] = p; - } else { - struct sainfoalg *q = sainfo.algs[class]; - while (q->next) { - q = q->next; - } - q->next = p; - } -} +/*****************************************************************************/ -static int match(struct sadb_address *address) +static int policy_match(struct sadb_address *address) { if (address) { - struct sockaddr *source = PFKEY_ADDR_SADDR(address); - return !cmpsaddrwop(source, &target); + return cmpsaddr(PFKEY_ADDR_SADDR(address), target) < CMPSADDR_MISMATCH; } return 0; } @@ -213,8 +179,8 @@ static void flush() if (p->sadb_msg_errno || pfkey_align(p, q) || pfkey_check(q)) { continue; } - if (match((struct sadb_address *)q[SADB_EXT_ADDRESS_SRC]) || - match((struct sadb_address *)q[SADB_EXT_ADDRESS_DST])) { + if (policy_match((struct sadb_address *)q[SADB_EXT_ADDRESS_SRC]) || + policy_match((struct sadb_address *)q[SADB_EXT_ADDRESS_DST])) { p->sadb_msg_type = (p->sadb_msg_type == SADB_DUMP) ? SADB_DELETE : SADB_X_SPDDELETE; p->sadb_msg_reserved = 0; @@ -227,34 +193,68 @@ static void flush() } /* flush; spdflush; - * spdadd local remote udp -P out ipsec esp/transport//require; */ -static void spdadd(struct sockaddr *local, struct sockaddr *remote) + * spdadd src dst protocol -P out ipsec esp/transport//require; OR + * spdadd src any protocol -P out ipsec esp/tunnel/local-remote/require; */ +static void spdadd(struct sockaddr *src, struct sockaddr *dst, + int protocol, struct sockaddr *local, struct sockaddr *remote) { struct __attribute__((packed)) { struct sadb_x_policy p; struct sadb_x_ipsecrequest q; + char addresses[sizeof(struct sockaddr_storage) * 2]; } policy; - int prefix = (local->sa_family == AF_INET) ? sizeof(struct in_addr) * 8 : - sizeof(struct in6_addr) * 8; - int key = pfkey_open(); + struct sockaddr_storage any = { +#ifndef __linux__ + .ss_len = src->sa_len, +#endif + .ss_family = src->sa_family, + }; + + int src_prefix = (src->sa_family == AF_INET) ? 32 : 128; + int dst_prefix = src_prefix; + int length = 0; + int key; + + /* Fill default values. */ memset(&policy, 0, sizeof(policy)); - policy.p.sadb_x_policy_len = PFKEY_UNIT64(sizeof(policy)); policy.p.sadb_x_policy_exttype = SADB_X_EXT_POLICY; policy.p.sadb_x_policy_type = IPSEC_POLICY_IPSEC; policy.p.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; #ifdef HAVE_PFKEY_POLICY_PRIORITY policy.p.sadb_x_policy_priority = PRIORITY_DEFAULT; #endif - policy.q.sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest); policy.q.sadb_x_ipsecrequest_proto = IPPROTO_ESP; policy.q.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; policy.q.sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; - target = *remote; + /* Deal with tunnel mode. */ + if (!dst) { + policy.q.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; + dst = (struct sockaddr *)&any; + dst_prefix = 0; + + length = sysdep_sa_len(local); + memcpy(policy.addresses, local, length); + memcpy(&policy.addresses[length], remote, length); + length += length; + + /* Use the source address to flush policies. */ + racoon_free(target); + target = dupsaddr(src); + } + + /* Fix lengths. */ + length += sizeof(policy.q); + policy.q.sadb_x_ipsecrequest_len = length; + length += sizeof(policy.p); + policy.p.sadb_x_policy_len = PFKEY_UNIT64(length); + + /* Always do a flush before adding the new policy. */ flush(); - if (pfkey_send_spdadd(key, local, prefix, remote, prefix, IPPROTO_UDP, - (caddr_t)&policy, sizeof(policy), 0) <= 0) { + key = pfkey_open(); + if (pfkey_send_spdadd(key, src, src_prefix, dst, dst_prefix, protocol, + (caddr_t)&policy, length, 0) <= 0) { do_plog(LLV_ERROR, "Cannot initialize SAD and SPD\n"); exit(1); } @@ -262,66 +262,135 @@ static void spdadd(struct sockaddr *local, struct sockaddr *remote) atexit(flush); } -void setup(int argc, char **argv) +/*****************************************************************************/ + +static void add_proposal(struct remoteconf *remoteconf, + int auth, int hash, int encryption, int length) { - int auth; - if (argc != 4 && argc != 6) { - printf("Usage: %s server port pre-shared-key\n" - " %s server port my-private-key my-cert ca-cert\n", - argv[0], argv[0]); - exit(0); - } - set_default(); + struct isakmpsa *p = racoon_calloc(1, sizeof(struct isakmpsa)); + p->prop_no = 1; + p->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT; + p->enctype = encryption; + p->encklen = length; + p->authmethod = auth; + p->hashtype = hash; + p->dh_group = OAKLEY_ATTR_GRP_DESC_MODP1024; + p->vendorid = VENDORID_UNKNOWN; - /* Set local address and remote address. */ - set_address(argv[1], argv[2]); + if (!remoteconf->proposal) { + p->trns_no = 1; + remoteconf->proposal = p; + } else { + struct isakmpsa *q = remoteconf->proposal; + while (q->next) { + q = q->next; + } + p->trns_no = q->trns_no + 1; + q->next = p; + } +} - /* Initialize SAD and SPD. */ - spdadd(myaddrs[0].addr, remoteconf.remote); +void setup(int argc, char **argv) +{ + struct remoteconf *remoteconf; + int auth; - /* Set local port and remote port. */ - set_port(myaddrs[0].addr, localconf.port_isakmp); - set_port(remoteconf.remote, localconf.port_isakmp); + if (argc > 2) { + set_globals(argv[1], argv[2]); + + /* Initialize everything else. */ + eay_init(); + initrmconf(); + oakley_dhinit(); + compute_vendorids(); + sched_init(); + if (pfkey_init() < 0 || isakmp_init() < 0) { + exit(1); + } #ifdef ENABLE_NATT - myaddrs[0].next = &myaddrs[1]; - myaddrs[1].addr = dupsaddr(myaddrs[0].addr); - set_port(myaddrs[1].addr, localconf.port_isakmp_natt); - myaddrs[1].udp_encap = 1; + natt_keepalive_init(); #endif - /* Set authentication method. */ - if (argc == 4) { - pre_shared_key = argv[3]; + /* Create remote configuration. */ + remoteconf = newrmconf(); + remoteconf->etypes = racoon_calloc(1, sizeof(struct etypes)); + remoteconf->etypes->type = ISAKMP_ETYPE_IDENT; + remoteconf->ike_frag = TRUE; + remoteconf->pcheck_level = PROP_CHECK_OBEY; + remoteconf->gen_policy = TRUE; + remoteconf->nat_traversal = TRUE; + remoteconf->remote = dupsaddr(target); + set_port(remoteconf->remote, localconf.port_isakmp); + } + + /* Set authentication method and credentials. */ + if (argc == 6 && !strcmp(argv[3], "udppsk")) { + set_port(target, atoi(argv[4])); + spdadd(myaddrs[0].addr, target, IPPROTO_UDP, NULL, NULL); + pre_shared_key = argv[5]; + remoteconf->idvtype = IDTYPE_ADDRESS; auth = OAKLEY_ATTR_AUTH_METHOD_PSKEY; - } else { - remoteconf.idvtype = IDTYPE_ASN1DN; - remoteconf.myprivfile = argv[3]; - remoteconf.mycertfile = argv[4]; - remoteconf.cacertfile = argv[5]; + } else if (argc == 8 && !strcmp(argv[3], "udprsa")) { + set_port(target, atoi(argv[4])); + spdadd(myaddrs[0].addr, target, IPPROTO_UDP, NULL, NULL); + remoteconf->myprivfile = argv[5]; + remoteconf->mycertfile = argv[6]; + remoteconf->cacertfile = argv[7]; + remoteconf->idvtype = IDTYPE_ASN1DN; auth = OAKLEY_ATTR_AUTH_METHOD_RSASIG; + } else { + printf("Usage: %s <interface> <server> [...],\n" + " where [...] can be:\n" + " udppsk <port> <pre-shared-key>\n" + " udprsa <port> <my-private-key> <my-cert> <ca-cert>\n", + argv[0]); + exit(0); } - /* Create proposals. */ - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_3DES, 0); - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_3DES, 0); - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_DES, 0); - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_DES, 0); - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_AES, 128); - add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_AES, 128); - - /* Create sainfo algorithms. */ - add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_SHA1, 0); - add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_MD5, 0); - add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_3DES, 0); - add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_DES, 0); - add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_AES, 128); + /* Add proposals. */ + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_3DES, 0); + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_3DES, 0); + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_DES, 0); + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_DES, 0); + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_AES, 128); + add_proposal(remoteconf, auth, + OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_AES, 128); + + /* Install remote configuration. */ + insrmconf(remoteconf); + + /* Create ISAKMP sockets. */ + set_port(myaddrs[0].addr, localconf.port_isakmp); + myaddrs[0].fd = isakmp_open(myaddrs[0].addr, FALSE); + if (myaddrs[0].fd == -1) { + do_plog(LLV_ERROR, "Cannot create ISAKMP socket"); + exit(1); + } +#ifdef ENABLE_NATT + set_port(myaddrs[1].addr, localconf.port_isakmp_natt); + myaddrs[1].fd = isakmp_open(myaddrs[1].addr, TRUE); + if (myaddrs[1].fd == -1) { + do_plog(LLV_WARNING, "Cannot create ISAKMP socket for NAT-T"); + } +#endif } +/*****************************************************************************/ + /* localconf.h */ vchar_t *getpskbyaddr(struct sockaddr *addr) { - return privsep_getpsk(pre_shared_key, strlen(pre_shared_key)); + vchar_t *p = NULL; + if (pre_shared_key && (p = vmalloc(strlen(pre_shared_key)))) { + memcpy(p->v, pre_shared_key, p->l); + } + return p; } vchar_t *getpskbyname(vchar_t *name) @@ -334,61 +403,75 @@ void getpathname(char *path, int length, int type, const char *name) strncpy(path, name, length); } -/* remoteconf.h */ +/* sainfo.h */ -struct remoteconf *getrmconf(struct sockaddr *addr) +struct sainfo *getsainfo(const vchar_t *src, const vchar_t *dst, + const vchar_t *peer, const vchar_t *client, uint32_t remoteid) { - return cmpsaddrwop(addr, remoteconf.remote) ? NULL : &remoteconf; + return &sainfo; } -struct isakmpsa *dupisakmpsa(struct isakmpsa *sa) +const char *sainfo2str(const struct sainfo *si) { - struct isakmpsa *p = NULL; - if (sa && (p = malloc(sizeof(struct isakmpsa)))) { - *p = *sa; - p->next = NULL; - if (sa->dhgrp) { - oakley_setdhgroup(sa->dh_group, &p->dhgrp); - } - } - return p; + return "*"; } -void delisakmpsa(struct isakmpsa *sa) +/* privsep.h */ + +int privsep_socket(int domain, int type, int protocol) { - while (sa) { - struct isakmpsa *p = sa->next; - if (sa->dhgrp) { - oakley_dhgrp_free(sa->dhgrp); - } - free(sa); - sa = p; + int fd = socket(domain, type, protocol); + if ((domain == AF_INET || domain == AF_INET6) && setsockopt( + fd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface))) { + do_plog(LLV_WARNING, "Cannot bind socket to %s", interface); } + return fd; } -struct etypes *check_etypeok(struct remoteconf *rmconf, uint8_t etype) +int privsep_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { - struct etypes *p = rmconf->etypes; - while (p && etype != p->type) { - p = p->next; - } - return p; + return bind(fd, addr, addrlen); } -struct remoteconf *foreachrmconf(rmconf_func_t function, void *data) +vchar_t *privsep_eay_get_pkcs1privkey(char *file) { - return (*function)(&remoteconf, data); + return eay_get_pkcs1privkey(file); } -/* sainfo.h */ +int privsep_script_exec(char *script, int name, char * const *environ) +{ + return 0; +} -struct sainfo *getsainfo(const vchar_t *src, const vchar_t *dst, - const vchar_t *peer, int remoteid) +/* grabmyaddr.h */ + +int myaddr_getsport(struct sockaddr *addr) { - return &sainfo; + return 0; } -const char *sainfo2str(const struct sainfo *si) +int myaddr_getfd(struct sockaddr *addr) { - return "*"; +#ifdef ENABLE_NATT + if (myaddrs[1].fd != -1 && + cmpsaddr(addr, myaddrs[1].addr) == CMPSADDR_MATCH) { + return myaddrs[1].fd; + } +#endif + if (cmpsaddr(addr, myaddrs[0].addr) < CMPSADDR_MISMATCH) { + return myaddrs[0].fd; + } + return -1; +} + +/* misc.h */ + +int racoon_hexdump(void *data, size_t length) +{ + return 0; +} + +void close_on_exec(int fd) +{ + fcntl(fd, F_SETFD, FD_CLOEXEC); } diff --git a/src/include-glibc/Makefile.in b/src/include-glibc/Makefile.in index 842728e..d92fdf6 100644 --- a/src/include-glibc/Makefile.in +++ b/src/include-glibc/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -15,8 +16,9 @@ @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -41,6 +43,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -58,23 +61,18 @@ CONFIGURE_AMFLAGS = @CONFIGURE_AMFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOBJS = @CRYPTOBJS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CRYPTO = @EXTRA_CRYPTO@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ FRAG_OBJS = @FRAG_OBJS@ GLIBC_BUGS = @GLIBC_BUGS@ GREP = @GREP@ @@ -88,6 +86,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KERNEL_INCLUDE = @KERNEL_INCLUDE@ KRB5_CONFIG = @KRB5_CONFIG@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ @@ -95,18 +94,24 @@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NATT_OBJS = @NATT_OBJS@ +NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ @@ -124,8 +129,7 @@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -157,6 +161,7 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -169,6 +174,7 @@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ @@ -185,14 +191,14 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/include-glibc/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/include-glibc/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/include-glibc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/include-glibc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -210,6 +216,7 @@ $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo @@ -239,13 +246,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -273,6 +284,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @@ -292,6 +304,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -300,18 +314,28 @@ install-data-am: install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -351,6 +375,7 @@ uninstall-am: touch .includes all: .includes + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in index 748877a..cd0993b 100644 --- a/src/libipsec/Makefile.in +++ b/src/libipsec/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -17,8 +18,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -45,15 +47,30 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \ "$(DESTDIR)$(libipsecdir)" -libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libipsec_la_DEPENDENCIES = $(am__DEPENDENCIES_1) @@ -67,6 +84,7 @@ libipsec_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -88,7 +106,6 @@ DIST_SOURCES = $(libipsec_la_SOURCES) man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man3_MANS) -libipsecHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(libipsec_HEADERS) $(noinst_HEADERS) ETAGS = etags CTAGS = ctags @@ -107,23 +124,18 @@ CONFIGURE_AMFLAGS = @CONFIGURE_AMFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOBJS = @CRYPTOBJS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CRYPTO = @EXTRA_CRYPTO@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ FRAG_OBJS = @FRAG_OBJS@ GLIBC_BUGS = @GLIBC_BUGS@ GREP = @GREP@ @@ -137,6 +149,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KERNEL_INCLUDE = @KERNEL_INCLUDE@ KRB5_CONFIG = @KRB5_CONFIG@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ @@ -144,18 +157,24 @@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NATT_OBJS = @NATT_OBJS@ +NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ @@ -173,8 +192,7 @@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -206,6 +224,7 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -218,6 +237,7 @@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @@ -262,14 +282,14 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libipsec/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/libipsec/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libipsec/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/libipsec/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -287,23 +307,28 @@ $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + list2="$$list2 $$p"; \ else :; fi; \ - done + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: @@ -339,21 +364,21 @@ distclean-compile: .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< @@ -369,82 +394,74 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-man3: $(man3_MANS) $(man_MANS) +install-man3: $(man3_MANS) @$(NORMAL_INSTALL) test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)" - @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.3*) list="$$list $$i" ;; \ - esac; \ + @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ done; \ - for i in $$list; do \ - if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ - else file=$$i; fi; \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 3*) ;; \ - *) ext='3' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ - done + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + uninstall-man3: @$(NORMAL_UNINSTALL) - @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.3*) list="$$list $$i" ;; \ - esac; \ - done; \ - for i in $$list; do \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 3*) ;; \ - *) ext='3' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ - rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ - done + @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man3dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man3dir)" && rm -f $$files; } install-libipsecHEADERS: $(libipsec_HEADERS) @$(NORMAL_INSTALL) test -z "$(libipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(libipsecdir)" - @list='$(libipsec_HEADERS)'; for p in $$list; do \ + @list='$(libipsec_HEADERS)'; test -n "$(libipsecdir)" || list=; \ + for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(libipsecHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libipsecdir)/$$f'"; \ - $(libipsecHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libipsecdir)/$$f"; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libipsecdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libipsecdir)" || exit $$?; \ done uninstall-libipsecHEADERS: @$(NORMAL_UNINSTALL) - @list='$(libipsec_HEADERS)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(libipsecdir)/$$f'"; \ - rm -f "$(DESTDIR)$(libipsecdir)/$$f"; \ - done + @list='$(libipsec_HEADERS)'; test -n "$(libipsecdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libipsecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libipsecdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -452,34 +469,52 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -495,13 +530,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -534,6 +573,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -559,6 +599,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -567,18 +609,28 @@ install-data-am: install-libipsecHEADERS install-man install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-libLTLIBRARIES install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-man3 install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -604,7 +656,7 @@ uninstall-am: uninstall-libLTLIBRARIES uninstall-libipsecHEADERS \ uninstall-man: uninstall-man3 -.MAKE: install-am install-strip +.MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ @@ -622,6 +674,7 @@ uninstall-man: uninstall-man3 uninstall-am uninstall-libLTLIBRARIES \ uninstall-libipsecHEADERS uninstall-man uninstall-man3 + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/libipsec/ipsec_dump_policy.c b/src/libipsec/ipsec_dump_policy.c index bdadb47..4d0eb77 100644 --- a/src/libipsec/ipsec_dump_policy.c +++ b/src/libipsec/ipsec_dump_policy.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_dump_policy.c,v 1.7.6.1 2007/08/01 11:52:17 vanhu Exp $ */ +/* $NetBSD: ipsec_dump_policy.c,v 1.9 2010/12/03 15:01:11 tteras Exp $ */ /* Id: ipsec_dump_policy.c,v 1.10 2005/06/29 09:12:37 manubsd Exp */ @@ -53,7 +53,10 @@ #include "libpfkey.h" static const char *ipsp_dir_strs[] = { - "any", "in", "out", "fwd" + "any", "in", "out", "fwd", +#ifdef __linux__ + "in(socket)", "out(socket)" +#endif }; static const char *ipsp_policy_strs[] = { @@ -165,6 +168,8 @@ ipsec_dump_policy1(policy, delimiter, withports) case IPSEC_DIR_OUTBOUND: #ifdef HAVE_POLICY_FWD case IPSEC_DIR_FWD: + case IPSEC_DIR_FWD + 1: + case IPSEC_DIR_FWD + 2: #endif break; default: diff --git a/src/libipsec/ipsec_get_policylen.c b/src/libipsec/ipsec_get_policylen.c index 2f4f6e9..5a49778 100644 --- a/src/libipsec/ipsec_get_policylen.c +++ b/src/libipsec/ipsec_get_policylen.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_get_policylen.c,v 1.6.6.1 2007/08/01 11:52:17 vanhu Exp $ */ +/* $NetBSD: ipsec_get_policylen.c,v 1.7 2007/07/18 12:07:50 vanhu Exp $ */ /* $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $ */ diff --git a/src/libipsec/ipsec_set_policy.3 b/src/libipsec/ipsec_set_policy.3 index 643b582..f3832b5 100644 --- a/src/libipsec/ipsec_set_policy.3 +++ b/src/libipsec/ipsec_set_policy.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipsec_set_policy.3,v 1.13 2006/09/09 16:22:09 manu Exp $ +.\" $NetBSD: ipsec_set_policy.3,v 1.15 2010/03/05 06:47:58 tteras Exp $ .\" .\" $KAME: ipsec_set_policy.3,v 1.16 2003/01/06 21:59:03 sumikawa Exp $ .\" @@ -124,14 +124,10 @@ 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 +.It Ar {priority,prio} offset .Ar offset -is an integer in the range -2147483647..214783648. -.It Xo -.Ar {priority,prio} base {+,-} offset -.Xc +is an integer in the range \-2147483647..214783648. +.It Ar {priority,prio} base {+,-} offset .Ar base is either .Li low (-1073741824) , @@ -162,12 +158,7 @@ means to consult the SPD defined by 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 +.It Ar direction Bo Ar priority specification Bc Li ipsec Ar request ... .Li ipsec means that the matching packets are subject to IPsec processing. .Li ipsec @@ -175,16 +166,7 @@ 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 +.It Ar protocol Li / Ar mode Li / Ar src Li - Ar dst Op Ar /level .Ar protocol is either .Li ah , diff --git a/src/libipsec/ipsec_strerror.c b/src/libipsec/ipsec_strerror.c index ad1ab2a..ca26d0e 100644 --- a/src/libipsec/ipsec_strerror.c +++ b/src/libipsec/ipsec_strerror.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_strerror.c,v 1.4.6.1 2007/08/01 11:52:17 vanhu Exp $ */ +/* $NetBSD: ipsec_strerror.c,v 1.6 2010/04/07 14:53:52 vanhu Exp $ */ /* $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $ */ @@ -63,7 +63,7 @@ static const char *ipsec_errlist[] = { "Invalid key length", /*EIPSEC_INVAL_KEYLEN*/ "Invalid address family", /*EIPSEC_INVAL_FAMILY*/ "Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/ -"Invalid direciton", /*EIPSEC_INVAL_DIR*/ +"Invalid direction", /*EIPSEC_INVAL_DIR*/ "SPI range violation", /*EIPSEC_INVAL_SPI*/ "No protocol specified", /*EIPSEC_NO_PROTO*/ "No algorithm specified", /*EIPSEC_NO_ALGS*/ diff --git a/src/libipsec/key_debug.c b/src/libipsec/key_debug.c index 60f1602..e381a98 100644 --- a/src/libipsec/key_debug.c +++ b/src/libipsec/key_debug.c @@ -1,4 +1,4 @@ -/* $NetBSD: key_debug.c,v 1.7.6.1 2007/08/01 11:52:18 vanhu Exp $ */ +/* $NetBSD: key_debug.c,v 1.9 2008/12/05 06:02:20 tteras Exp $ */ /* $KAME: key_debug.c,v 1.29 2001/08/16 14:25:41 itojun Exp $ */ @@ -91,6 +91,10 @@ static void kdebug_sadb_x_nat_t_port __P((struct sadb_ext *ext)); static void kdebug_sadb_x_packet __P((struct sadb_ext *)); #endif +#ifdef SADB_X_EXT_KMADDRESS +static void kdebug_sadb_x_kmaddress __P((struct sadb_ext *)); +#endif + #ifdef _KERNEL static void kdebug_secreplay __P((struct secreplay *)); #endif @@ -194,6 +198,11 @@ kdebug_sadb(base) kdebug_sadb_x_packet(ext); break; #endif +#ifdef SADB_X_EXT_KMADDRESS + case SADB_X_EXT_KMADDRESS: + kdebug_sadb_x_kmaddress(ext); + break; +#endif default: printf("kdebug_sadb: invalid ext_type %u was passed.\n", ext->sadb_ext_type); @@ -556,6 +565,48 @@ kdebug_sadb_x_packet(ext) } #endif +#ifdef SADB_X_EXT_KMADDRESS +static void +kdebug_sadb_x_kmaddress(ext) + struct sadb_ext *ext; +{ + struct sadb_x_kmaddress *kma = (struct sadb_x_kmaddress *)ext; + struct sockaddr * sa; + sa_family_t family; + int len, sa_len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_kmaddress: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(kma->sadb_x_kmaddress_len) - sizeof(*kma)); + + printf("sadb_x_kmaddress{ reserved=0x%02x%02x%02x%02x }\n", + ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[0], + ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[1], + ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[2], + ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[3]); + + sa = (struct sockaddr *)(kma + 1); + if (len < sizeof(struct sockaddr) || (sa_len = sysdep_sa_len(sa)) > len) + panic("kdebug_sadb_x_kmaddress: not enough data to read" + " first sockaddr.\n"); + kdebug_sockaddr((void *)sa); /* local address */ + family = sa->sa_family; + + len -= sa_len; + sa = (struct sockaddr *)((char *)sa + sa_len); + if (len < sizeof(struct sockaddr) || sysdep_sa_len(sa) > len) + panic("kdebug_sadb_x_kmaddress: not enough data to read" + " second sockaddr.\n"); + kdebug_sockaddr((void *)sa); /* remote address */ + + if (family != sa->sa_family) + printf("kdebug_sadb_x_kmaddress: !!!! Please, note the " + "unexpected mismatch in address family.\n"); +} +#endif + #ifdef _KERNEL /* %%%: about SPD and SAD */ diff --git a/src/libipsec/libpfkey.h b/src/libipsec/libpfkey.h index b312015..ff4c603 100644 --- a/src/libipsec/libpfkey.h +++ b/src/libipsec/libpfkey.h @@ -1,4 +1,4 @@ -/* $NetBSD: libpfkey.h,v 1.12.4.1 2007/08/01 11:52:18 vanhu Exp $ */ +/* $NetBSD: libpfkey.h,v 1.18 2010/12/03 14:32:52 tteras Exp $ */ /* Id: libpfkey.h,v 1.13 2005/12/04 20:26:43 manubsd Exp */ @@ -121,6 +121,10 @@ 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)); +int pfkey_send_getspi_nat __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int8_t, u_int16_t, u_int16_t, + u_int32_t, u_int32_t, u_int32_t, u_int32_t)); + int pfkey_send_update2 __P((struct pfkey_send_sa_args *)); int pfkey_send_add2 __P((struct pfkey_send_sa_args *)); int pfkey_send_delete __P((int, u_int, u_int, @@ -154,12 +158,22 @@ int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, int pfkey_send_spdflush __P((int)); int pfkey_send_spddump __P((int)); #ifdef SADB_X_MIGRATE -int pfkey_send_migrate __P((int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_migrate __P((int, struct sockaddr *, struct sockaddr *, + struct sockaddr *, u_int, struct sockaddr *, u_int, u_int, + caddr_t, int, u_int32_t)); +#endif + +/* XXX should be somewhere else !!! + */ +#ifdef SADB_X_EXT_NAT_T_TYPE +#define PFKEY_ADDR_X_PORT(ext) (ntohs(((struct sadb_x_nat_t_port *)ext)->sadb_x_nat_t_port_port)) +#define PFKEY_ADDR_X_NATTYPE(ext) ( ext != NULL && ((struct sadb_x_nat_t_type *)ext)->sadb_x_nat_t_type_type ) #endif + int pfkey_open __P((void)); void pfkey_close __P((int)); +int pfkey_set_buffer_size __P((int, 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 *)); @@ -200,6 +214,10 @@ int pfkey_send_add_nat __P((int, u_int, u_int, struct sockaddr *, #define IPPROTO_IPCOMP IPPROTO_COMP #endif +#ifndef IPPROTO_MH +#define IPPROTO_MH 135 +#endif + static __inline u_int8_t sysdep_sa_len (const struct sockaddr *sa) { diff --git a/src/libipsec/pfkey.c b/src/libipsec/pfkey.c index fae0415..e64cf36 100644 --- a/src/libipsec/pfkey.c +++ b/src/libipsec/pfkey.c @@ -1,4 +1,4 @@ -/* $NetBSD: pfkey.c,v 1.13.4.2 2007/10/15 16:05:22 vanhu Exp $ */ +/* $NetBSD: pfkey.c,v 1.21 2011/01/20 16:08:35 vanhu Exp $ */ /* $KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $ */ @@ -71,6 +71,12 @@ static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, u_int, u_int, u_int32_t)); static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, struct sockaddr *, u_int, u_int)); + +#ifdef SADB_X_EXT_KMADDRESS +static caddr_t pfkey_setsadbkmaddr __P((caddr_t, caddr_t, struct sockaddr *, + struct sockaddr *)); +#endif + 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)); @@ -374,11 +380,10 @@ pfkey_get_softrate(type) * -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; +pfkey_send_getspi_nat(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int8_t natt_type, u_int16_t sport, + u_int16_t dport, u_int32_t min, u_int32_t max, u_int32_t reqid, + u_int32_t seq) { struct sadb_msg *newmsg; caddr_t ep; @@ -425,6 +430,14 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) len += sizeof(struct sadb_spirange); } +#ifdef SADB_X_EXT_NAT_T_TYPE + if(natt_type||sport||dport){ + len += sizeof(struct sadb_x_nat_t_type); + len += sizeof(struct sadb_x_nat_t_port); + len += sizeof(struct sadb_x_nat_t_port); + } +#endif + if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; @@ -460,6 +473,32 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) return -1; } +#ifdef SADB_X_EXT_NAT_T_TYPE + /* Add nat-t messages */ + if (natt_type) { + p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE, + natt_type); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT, + sport); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT, + dport); + if (!p) { + free(newmsg); + return -1; + } + } +#endif + /* proccessing spi range */ if (need_spirange) { struct sadb_spirange spirange; @@ -495,6 +534,15 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) return len; } +int +pfkey_send_getspi(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t min, u_int32_t max, u_int32_t reqid, + u_int32_t seq) +{ + return pfkey_send_getspi_nat(so, satype, mode, src, dst, 0, 0, 0, + min, max, reqid, seq); +} + /* * sending SADB_UPDATE message to the kernel. * The length of key material is a_keylen + e_keylen. @@ -503,12 +551,10 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) * -1 : error occured, and set errno. */ int -pfkey_send_update2(sa_parms) - struct pfkey_send_sa_args *sa_parms; +pfkey_send_update2(struct pfkey_send_sa_args *sa_parms) { int len; - sa_parms->type = SADB_UPDATE; if ((len = pfkey_send_x1(sa_parms)) < 0) return -1; @@ -524,8 +570,7 @@ pfkey_send_update2(sa_parms) * -1 : error occured, and set errno. */ int -pfkey_send_add2(sa_parms) - struct pfkey_send_sa_args *sa_parms; +pfkey_send_add2(struct pfkey_send_sa_args *sa_parms) { int len; @@ -543,11 +588,8 @@ pfkey_send_add2(sa_parms) * -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; +pfkey_send_delete(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi) { int len; if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) @@ -567,10 +609,8 @@ pfkey_send_delete(so, satype, mode, src, dst, spi) */ /*ARGSUSED*/ int -pfkey_send_delete_all(so, satype, mode, src, dst) - int so; - u_int satype, mode; - struct sockaddr *src, *dst; +pfkey_send_delete_all(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst) { struct sadb_msg *newmsg; int len; @@ -649,11 +689,8 @@ pfkey_send_delete_all(so, satype, mode, src, dst) * -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; +pfkey_send_get(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi) { int len; if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) @@ -669,9 +706,7 @@ pfkey_send_get(so, satype, mode, src, dst, spi) * -1 : error occured, and set errno. */ int -pfkey_send_register(so, satype) - int so; - u_int satype; +pfkey_send_register(int so, u_int satype) { int len, algno; @@ -711,8 +746,7 @@ pfkey_send_register(so, satype) * -1: error occured, and set errno. */ int -pfkey_recv_register(so) - int so; +pfkey_recv_register(int so) { pid_t pid = getpid(); struct sadb_msg *newmsg; @@ -751,9 +785,7 @@ pfkey_recv_register(so) * -1: error occured, and set errno. */ int -pfkey_set_supported(msg, tlen) - struct sadb_msg *msg; - int tlen; +pfkey_set_supported(struct sadb_msg *msg, int tlen) { struct sadb_supported *sup; caddr_t p; @@ -815,9 +847,7 @@ pfkey_set_supported(msg, tlen) * -1 : error occured, and set errno. */ int -pfkey_send_flush(so, satype) - int so; - u_int satype; +pfkey_send_flush(int so, u_int satype) { int len; @@ -834,9 +864,7 @@ pfkey_send_flush(so, satype) * -1 : error occured, and set errno. */ int -pfkey_send_dump(so, satype) - int so; - u_int satype; +pfkey_send_dump(int so, u_int satype) { int len; @@ -859,9 +887,7 @@ pfkey_send_dump(so, satype) * algorithms is. */ int -pfkey_send_promisc_toggle(so, flag) - int so; - int flag; +pfkey_send_promisc_toggle(int so, int flag) { int len; @@ -879,13 +905,9 @@ pfkey_send_promisc_toggle(so, flag) * -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; +pfkey_send_spdadd(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; @@ -905,15 +927,9 @@ pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) * -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; +pfkey_send_spdadd2(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq) { int len; @@ -933,13 +949,9 @@ pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, * -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; +pfkey_send_spdupdate(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; @@ -959,15 +971,9 @@ pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) * -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; +pfkey_send_spdupdate2(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq) { int len; @@ -987,13 +993,9 @@ pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, * -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; +pfkey_send_spddelete(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; @@ -1018,9 +1020,7 @@ pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) * -1 : error occured, and set errno. */ int -pfkey_send_spddelete2(so, spid) - int so; - u_int32_t spid; +pfkey_send_spddelete2(int so, u_int32_t spid) { int len; @@ -1037,9 +1037,7 @@ pfkey_send_spddelete2(so, spid) * -1 : error occured, and set errno. */ int -pfkey_send_spdget(so, spid) - int so; - u_int32_t spid; +pfkey_send_spdget(int so, u_int32_t spid) { int len; @@ -1056,13 +1054,9 @@ pfkey_send_spdget(so, spid) * -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; +pfkey_send_spdsetidx(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; @@ -1087,8 +1081,7 @@ pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) * -1 : error occured, and set errno. */ int -pfkey_send_spdflush(so) - int so; +pfkey_send_spdflush(int so) { int len; @@ -1105,8 +1098,7 @@ pfkey_send_spdflush(so) * -1 : error occured, and set errno. */ int -pfkey_send_spddump(so) - int so; +pfkey_send_spddump(int so) { int len; @@ -1125,13 +1117,9 @@ pfkey_send_spddump(so) * -1 : error occured, and set errno. */ int -pfkey_send_migrate(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; +pfkey_send_migrate(int so, struct sockaddr *local, struct sockaddr *remote, + struct sockaddr *src, u_int prefs, struct sockaddr *dst, u_int prefd, + u_int proto, caddr_t policy, int policylen, u_int32_t seq) { struct sadb_msg *newmsg; int len; @@ -1149,6 +1137,17 @@ pfkey_send_migrate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) return -1; } + if (local == NULL || remote == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } +#ifdef SADB_X_EXT_KMADDRESS + if (local->sa_family != remote->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } +#endif + switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; @@ -1167,6 +1166,10 @@ pfkey_send_migrate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) +#ifdef SADB_X_EXT_KMADDRESS + + sizeof(struct sadb_x_kmaddress) + + PFKEY_ALIGN8(2*sysdep_sa_len(local)) +#endif + sizeof(struct sadb_address) + PFKEY_ALIGN8(sysdep_sa_len(src)) + sizeof(struct sadb_address) @@ -1185,6 +1188,13 @@ pfkey_send_migrate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) free(newmsg); return -1; } +#ifdef SADB_X_EXT_KMADDRESS + p = pfkey_setsadbkmaddr(p, ep, local, remote); + if (!p) { + free(newmsg); + return -1; + } +#endif p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); if (!p) { free(newmsg); @@ -1212,8 +1222,7 @@ pfkey_send_migrate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) /* sending SADB_ADD or SADB_UPDATE message to the kernel */ static int -pfkey_send_x1(sa_parms) - struct pfkey_send_sa_args *sa_parms; +pfkey_send_x1(struct pfkey_send_sa_args *sa_parms) { struct sadb_msg *newmsg; int len; @@ -1486,11 +1495,8 @@ pfkey_send_x1(sa_parms) /* 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; +pfkey_send_x2(int so, u_int type, u_int satype, u_int mode, + struct sockaddr *src, struct sockaddr *dst, u_int32_t spi) { struct sadb_msg *newmsg; int len; @@ -1573,9 +1579,7 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) * to the kernel */ static int -pfkey_send_x3(so, type, satype) - int so; - u_int type, satype; +pfkey_send_x3(int so, u_int type, u_int satype) { struct sadb_msg *newmsg; int len; @@ -1635,15 +1639,9 @@ pfkey_send_x3(so, type, satype) /* 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; +pfkey_send_x4(int so, u_int type, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, char *policy, int policylen, u_int32_t seq) { struct sadb_msg *newmsg; int len; @@ -1729,10 +1727,7 @@ pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, /* 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; +pfkey_send_x5(int so, u_int type, u_int32_t spid) { struct sadb_msg *newmsg; struct sadb_x_policy xpl; @@ -1785,7 +1780,7 @@ pfkey_send_x5(so, type, spid) * others : success and return value of socket. */ int -pfkey_open() +pfkey_open(void) { int so; int bufsiz = 128 * 1024; /*is 128K enough?*/ @@ -1811,6 +1806,42 @@ pfkey_open() return so; } +int +pfkey_set_buffer_size(int so, int size) +{ + int newsize; + int actual_bufsiz; + socklen_t sizebufsiz; + int desired_bufsiz; + + /* + * on linux you may need to allow the kernel to allocate + * more buffer space by increasing: + * /proc/sys/net/core/rmem_max and wmem_max + */ + if (size > 0) { + actual_bufsiz = 0; + sizebufsiz = sizeof(actual_bufsiz); + desired_bufsiz = size * 1024; + if ((getsockopt(so, SOL_SOCKET, SO_RCVBUF, + &actual_bufsiz, &sizebufsiz) < 0) + || (actual_bufsiz < desired_bufsiz)) { + if (setsockopt(so, SOL_SOCKET, SO_RCVBUF, + &desired_bufsiz, sizeof(desired_bufsiz)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + } + } + + /* return actual buffer size */ + actual_bufsiz = 0; + sizebufsiz = sizeof(actual_bufsiz); + getsockopt(so, SOL_SOCKET, SO_RCVBUF, + &actual_bufsiz, &sizebufsiz); + return actual_bufsiz / 1024; +} + /* * close a socket. * OUT: @@ -1818,8 +1849,7 @@ pfkey_open() * -1: fail. */ void -pfkey_close(so) - int so; +pfkey_close(int so) { (void)close(so); @@ -1837,8 +1867,7 @@ pfkey_close(so) * XXX should be rewritten to pass length explicitly */ struct sadb_msg * -pfkey_recv(so) - int so; +pfkey_recv(int so) { struct sadb_msg buf, *newmsg; int len, reallen; @@ -1895,10 +1924,7 @@ pfkey_recv(so) * -1 : fail. */ int -pfkey_send(so, msg, len) - int so; - struct sadb_msg *msg; - int len; +pfkey_send(int so, struct sadb_msg *msg, int len) { if ((len = send(so, (void *)msg, (socklen_t)len, 0)) < 0) { __ipsec_set_strerror(strerror(errno)); @@ -1924,9 +1950,7 @@ pfkey_send(so, msg, len) * XXX should be rewritten to obtain length explicitly */ int -pfkey_align(msg, mhp) - struct sadb_msg *msg; - caddr_t *mhp; +pfkey_align(struct sadb_msg *msg, caddr_t *mhp) { struct sadb_ext *ext; int i; @@ -2001,6 +2025,9 @@ pfkey_align(msg, mhp) #ifdef SADB_X_EXT_PACKET case SADB_X_EXT_PACKET: #endif +#ifdef SADB_X_EXT_KMADDRESS + case SADB_X_EXT_KMADDRESS: +#endif #ifdef SADB_X_EXT_SEC_CTX case SADB_X_EXT_SEC_CTX: #endif @@ -2035,8 +2062,7 @@ pfkey_align(msg, mhp) * 0: valid. */ int -pfkey_check(mhp) - caddr_t *mhp; +pfkey_check(caddr_t *mhp) { struct sadb_msg *msg; @@ -2112,6 +2138,12 @@ pfkey_check(mhp) break; /*FALLTHROUGH*/ default: +#ifdef __linux__ + /* Linux kernel seems to be buggy and return + * uninitialized satype for spd flush message */ + if (msg->sadb_msg_type == SADB_X_SPDFLUSH) + break; +#endif __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } @@ -2159,13 +2191,8 @@ pfkey_check(mhp) * `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; +pfkey_setsadbmsg(caddr_t buf, caddr_t lim, u_int type, u_int tlen, + u_int satype, u_int32_t seq, pid_t pid) { struct sadb_msg *p; u_int len; @@ -2194,11 +2221,8 @@ pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) * `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; +pfkey_setsadbsa(caddr_t buf, caddr_t lim, u_int32_t spi, u_int wsize, + u_int auth, u_int enc, u_int32_t flags) { struct sadb_sa *p; u_int len; @@ -2228,13 +2252,8 @@ pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) * 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; +pfkey_setsadbaddr(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; @@ -2257,16 +2276,50 @@ pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) return(buf + len); } +#ifdef SADB_X_EXT_KMADDRESS +/* + * set data into sadb_x_kmaddress. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbkmaddr(caddr_t buf, caddr_t lim, struct sockaddr *local, + struct sockaddr *remote) +{ + struct sadb_x_kmaddress *p; + struct sockaddr *sa; + u_int salen = sysdep_sa_len(local); + u_int len; + + /* sanity check */ + if (local->sa_family != remote->sa_family) + return NULL; + + p = (void *)buf; + len = sizeof(struct sadb_x_kmaddress) + PFKEY_ALIGN8(2*salen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_kmaddress_len = PFKEY_UNIT64(len); + p->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS; + p->sadb_x_kmaddress_reserved = 0; + sa = (struct sockaddr *)(p + 1); + memcpy(sa, local, salen); + sa = (struct sockaddr *)((char *)sa + salen); + memcpy(sa, remote, salen); + + return(buf + len); +} +#endif + /* * 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; +pfkey_setsadbkey(caddr_t buf, caddr_t lim, u_int type, caddr_t key, + u_int keylen) { struct sadb_key *p; u_int len; @@ -2293,11 +2346,8 @@ pfkey_setsadbkey(buf, lim, type, key, keylen) * 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; +pfkey_setsadblifetime(caddr_t buf, caddr_t lim, u_int type, u_int32_t l_alloc, + u_int32_t l_bytes, u_int32_t l_addtime, u_int32_t l_usetime) { struct sadb_lifetime *p; u_int len; @@ -2339,11 +2389,7 @@ pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) * `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; +pfkey_setsadbxsa2(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; @@ -2366,11 +2412,7 @@ pfkey_setsadbxsa2(buf, lim, mode0, reqid) #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; +pfkey_set_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; @@ -2390,11 +2432,7 @@ pfkey_set_natt_type(buf, lim, type, l_natt_type) } 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; +pfkey_set_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; @@ -2416,11 +2454,8 @@ pfkey_set_natt_port(buf, lim, type, l_natt_port) #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; +pfkey_set_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; @@ -2442,13 +2477,8 @@ pfkey_set_natt_frag(buf, lim, type, l_natt_frag) #ifdef SADB_X_EXT_SEC_CTX static caddr_t -pfkey_setsecctx(buf, lim, type, ctx_doi, ctx_alg, sec_ctx, sec_ctxlen) - caddr_t buf; - caddr_t lim; - u_int type; - u_int8_t ctx_doi, ctx_alg; - caddr_t sec_ctx; - u_int16_t sec_ctxlen; +pfkey_setsecctx(caddr_t buf, caddr_t lim, u_int type, u_int8_t ctx_doi, + u_int8_t ctx_alg, caddr_t sec_ctx, u_int16_t sec_ctxlen) { struct sadb_x_sec_ctx *p; u_int len; @@ -2477,18 +2507,11 @@ pfkey_setsecctx(buf, lim, type, ctx_doi, ctx_alg, sec_ctx, sec_ctxlen) * libipsec users. Please use pfkey_send_update2 and pfkey_send_add2 instead */ 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; +pfkey_send_update(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, + u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, + u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq) { struct pfkey_send_sa_args psaa; @@ -2518,24 +2541,13 @@ pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, } 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; +pfkey_send_update_nat(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, + u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, + u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq, + u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport, + struct sockaddr *l_natt_oa, u_int16_t l_natt_frag) { struct pfkey_send_sa_args psaa; @@ -2570,18 +2582,11 @@ pfkey_send_update_nat(so, satype, mode, src, dst, spi, reqid, wsize, } 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; +pfkey_send_add(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, + u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, + u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq) { struct pfkey_send_sa_args psaa; @@ -2611,24 +2616,13 @@ pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, } 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; +pfkey_send_add_nat(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, + u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, + u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq, + u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport, + struct sockaddr *l_natt_oa, u_int16_t l_natt_frag) { struct pfkey_send_sa_args psaa; diff --git a/src/libipsec/pfkey_dump.c b/src/libipsec/pfkey_dump.c index 8fa4084..4627ebc 100644 --- a/src/libipsec/pfkey_dump.c +++ b/src/libipsec/pfkey_dump.c @@ -1,4 +1,4 @@ -/* $NetBSD: pfkey_dump.c,v 1.15.6.1 2007/08/01 11:52:18 vanhu Exp $ */ +/* $NetBSD: pfkey_dump.c,v 1.18 2010/12/03 14:32:52 tteras Exp $ */ /* $KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $ */ @@ -716,13 +716,19 @@ str_prefport(family, pref, port, ulp) else snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); - if (ulp == IPPROTO_ICMPV6) + switch (ulp) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + case IPPROTO_MH: + case IPPROTO_GRE: memset(portbuf, 0, sizeof(portbuf)); - else { + break; + default: if (port == IPSEC_PORT_ANY) - snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + strcpy(portbuf, "[any]"); else snprintf(portbuf, sizeof(portbuf), "[%u]", port); + break; } snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); @@ -734,29 +740,26 @@ 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; + 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); + ent = getprotobynumber((int)ulp); + if (ent) + printf("%s", ent->p_name); + else + printf("%u", ulp); - endprotoent(); - break; - } + if (p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY) + return; + + switch (ulp) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + case IPPROTO_MH: + printf(" %u,%u", p1, p2); + break; + case IPPROTO_GRE: + printf(" %u", (p1 << 16) + p2); + break; } } @@ -774,8 +777,10 @@ str_time(t) for (;i < 20;) buf[i++] = ' '; } else { char *t0; - t0 = ctime(&t); - memcpy(buf, t0 + 4, 20); + if ((t0 = ctime(&t)) == NULL) + memset(buf, '?', 20); + else + memcpy(buf, t0 + 4, 20); } buf[20] = '\0'; diff --git a/src/libipsec/policy_parse.h b/src/libipsec/policy_parse.h index a4c1d0b..dc629dd 100644 --- a/src/libipsec/policy_parse.h +++ b/src/libipsec/policy_parse.h @@ -1,24 +1,23 @@ -/* A Bison parser, made by GNU Bison 2.3. */ -/* Skeleton interface for Bison's Yacc-like parsers in C +/* A Bison parser, made by GNU Bison 2.4.1. */ - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,10 +28,11 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ + /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -80,22 +80,28 @@ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 129 "policy_parse.y" { + +/* Line 1676 of yacc.c */ +#line 129 "policy_parse.y" + u_int num; u_int32_t num32; struct _val { int len; char *buf; } val; -} -/* Line 1489 of yacc.c. */ -#line 94 "policy_parse.h" - YYSTYPE; + + + +/* Line 1676 of yacc.c */ +#line 99 "policy_parse.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE __libipseclval; + diff --git a/src/libipsec/policy_parse.y b/src/libipsec/policy_parse.y index a13dc12..321f4f0 100644 --- a/src/libipsec/policy_parse.y +++ b/src/libipsec/policy_parse.y @@ -1,4 +1,4 @@ -/* $NetBSD: policy_parse.y,v 1.9.6.2 2009/02/16 18:38:26 tteras Exp $ */ +/* $NetBSD: policy_parse.y,v 1.11 2009/02/16 18:36:21 tteras Exp $ */ /* $KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 itojun Exp $ */ diff --git a/src/libipsec/policy_token.l b/src/libipsec/policy_token.l index 0833c20..243b678 100644 --- a/src/libipsec/policy_token.l +++ b/src/libipsec/policy_token.l @@ -1,4 +1,4 @@ -/* $NetBSD: policy_token.l,v 1.6.6.1 2007/08/01 11:52:19 vanhu Exp $ */ +/* $NetBSD: policy_token.l,v 1.7 2007/07/18 12:07:50 vanhu Exp $ */ /* Id: policy_token.l,v 1.12 2005/05/05 12:32:18 manubsd Exp */ diff --git a/src/racoon/Makefile.am b/src/racoon/Makefile.am index 202a18e..dbaded9 100644 --- a/src/racoon/Makefile.am +++ b/src/racoon/Makefile.am @@ -3,7 +3,7 @@ sbin_PROGRAMS = racoon racoonctl plainrsa-gen noinst_PROGRAMS = eaytest include_racoon_HEADERS = racoonctl.h var.h vmbuf.h misc.h gcmalloc.h admin.h \ - schedule.h sockmisc.h vmbuf.h isakmp_var.h isakmp.h isakmp_xauth.h \ + schedule.h sockmisc.h isakmp_var.h isakmp.h isakmp_xauth.h \ isakmp_cfg.h isakmp_unity.h ipsec_doi.h evt.h lib_LTLIBRARIES = libracoon.la @@ -48,6 +48,7 @@ racoonctl_SOURCES = racoonctl.c str2val.c racoonctl_LDADD = libracoon.la ../libipsec/libipsec.la libracoon_la_SOURCES = kmpstat.c vmbuf.c sockmisc.c misc.c +libracoon_la_CFLAGS = -DNOUSE_PRIVSEP $(AM_CFLAGS) plainrsa_gen_SOURCES = plainrsa-gen.c plog.c \ crypto_openssl.c logger.c @@ -88,6 +89,7 @@ EXTRA_DIST = \ ${man5_MANS} ${man8_MANS} \ missing/crypto/rijndael/boxes-fst.dat \ doc/FAQ doc/README.certificate doc/README.gssapi doc/README.plainrsa \ + doc/README.privsep \ contrib/sp.pl stats.pl \ samples/psk.txt.sample samples/racoon.conf.sample \ samples/psk.txt.in samples/racoon.conf.in \ diff --git a/src/racoon/Makefile.in b/src/racoon/Makefile.in index 47e997b..4b4e635 100644 --- a/src/racoon/Makefile.in +++ b/src/racoon/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -20,8 +21,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -52,21 +54,40 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" \ "$(DESTDIR)$(include_racoondir)" -libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) libracoon_la_LIBADD = -am_libracoon_la_OBJECTS = kmpstat.lo vmbuf.lo sockmisc.lo misc.lo +am_libracoon_la_OBJECTS = libracoon_la-kmpstat.lo \ + libracoon_la-vmbuf.lo libracoon_la-sockmisc.lo \ + libracoon_la-misc.lo libracoon_la_OBJECTS = $(am_libracoon_la_OBJECTS) -sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +libracoon_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libracoon_la_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS) am_eaytest_OBJECTS = eaytest.$(OBJEXT) plog.$(OBJEXT) logger.$(OBJEXT) eaytest_OBJECTS = $(am_eaytest_OBJECTS) @@ -96,6 +117,7 @@ racoonctl_DEPENDENCIES = libracoon.la ../libipsec/libipsec.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -124,10 +146,11 @@ man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man5_MANS) $(man8_MANS) -include_racoonHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(include_racoon_HEADERS) $(noinst_HEADERS) ETAGS = etags CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -143,23 +166,18 @@ CONFIGURE_AMFLAGS = @CONFIGURE_AMFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOBJS = @CRYPTOBJS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CRYPTO = @EXTRA_CRYPTO@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ FRAG_OBJS = @FRAG_OBJS@ GLIBC_BUGS = @GLIBC_BUGS@ GREP = @GREP@ @@ -173,6 +191,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KERNEL_INCLUDE = @KERNEL_INCLUDE@ KRB5_CONFIG = @KRB5_CONFIG@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ @@ -180,18 +199,24 @@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NATT_OBJS = @NATT_OBJS@ +NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ @@ -209,8 +234,7 @@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -242,6 +266,7 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -254,10 +279,11 @@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ include_racoon_HEADERS = racoonctl.h var.h vmbuf.h misc.h gcmalloc.h admin.h \ - schedule.h sockmisc.h vmbuf.h isakmp_var.h isakmp.h isakmp_xauth.h \ + schedule.h sockmisc.h isakmp_var.h isakmp.h isakmp_xauth.h \ isakmp_cfg.h isakmp_unity.h ipsec_doi.h evt.h lib_LTLIBRARIES = libracoon.la @@ -302,6 +328,7 @@ racoon_DEPENDENCIES = \ racoonctl_SOURCES = racoonctl.c str2val.c racoonctl_LDADD = libracoon.la ../libipsec/libipsec.la libracoon_la_SOURCES = kmpstat.c vmbuf.c sockmisc.c misc.c +libracoon_la_CFLAGS = -DNOUSE_PRIVSEP $(AM_CFLAGS) plainrsa_gen_SOURCES = plainrsa-gen.c plog.c \ crypto_openssl.c logger.c @@ -341,6 +368,7 @@ EXTRA_DIST = \ ${man5_MANS} ${man8_MANS} \ missing/crypto/rijndael/boxes-fst.dat \ doc/FAQ doc/README.certificate doc/README.gssapi doc/README.plainrsa \ + doc/README.privsep \ contrib/sp.pl stats.pl \ samples/psk.txt.sample samples/racoon.conf.sample \ samples/psk.txt.in samples/racoon.conf.in \ @@ -362,14 +390,14 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/racoon/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/racoon/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/racoon/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/racoon/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -387,23 +415,28 @@ $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + list2="$$list2 $$p"; \ else :; fi; \ - done + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: @@ -415,42 +448,59 @@ clean-libLTLIBRARIES: rm -f "$${dir}/so_locations"; \ done libracoon.la: $(libracoon_la_OBJECTS) $(libracoon_la_DEPENDENCIES) - $(LINK) -rpath $(libdir) $(libracoon_la_OBJECTS) $(libracoon_la_LIBADD) $(LIBS) + $(libracoon_la_LINK) -rpath $(libdir) $(libracoon_la_OBJECTS) $(libracoon_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: - @list='$(noinst_PROGRAMS)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f $$p $$f"; \ - rm -f $$p $$f ; \ - done + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" - @list='$(sbin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - || test -f $$p1 \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ - else :; fi; \ - done + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) - @list='$(sbin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ - rm -f "$(DESTDIR)$(sbindir)/$$f"; \ - done + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: - @list='$(sbin_PROGRAMS)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f $$p $$f"; \ - rm -f $$p $$f ; \ - done + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list eaytest$(EXEEXT): $(eaytest_OBJECTS) $(eaytest_DEPENDENCIES) @rm -f eaytest$(EXEEXT) $(LINK) $(eaytest_OBJECTS) $(eaytest_LDADD) $(LIBS) @@ -506,11 +556,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_quick.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_unity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_xauth.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmpstat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-kmpstat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-sockmisc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-vmbuf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localconf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nattraversal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oakley.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey.Po@am__quote@ @@ -532,51 +584,77 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/security.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockmisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str2val.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnames.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/throttle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendorid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmbuf.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< +libracoon_la-kmpstat.lo: kmpstat.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-kmpstat.lo -MD -MP -MF $(DEPDIR)/libracoon_la-kmpstat.Tpo -c -o libracoon_la-kmpstat.lo `test -f 'kmpstat.c' || echo '$(srcdir)/'`kmpstat.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libracoon_la-kmpstat.Tpo $(DEPDIR)/libracoon_la-kmpstat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kmpstat.c' object='libracoon_la-kmpstat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-kmpstat.lo `test -f 'kmpstat.c' || echo '$(srcdir)/'`kmpstat.c + +libracoon_la-vmbuf.lo: vmbuf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-vmbuf.lo -MD -MP -MF $(DEPDIR)/libracoon_la-vmbuf.Tpo -c -o libracoon_la-vmbuf.lo `test -f 'vmbuf.c' || echo '$(srcdir)/'`vmbuf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libracoon_la-vmbuf.Tpo $(DEPDIR)/libracoon_la-vmbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vmbuf.c' object='libracoon_la-vmbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-vmbuf.lo `test -f 'vmbuf.c' || echo '$(srcdir)/'`vmbuf.c + +libracoon_la-sockmisc.lo: sockmisc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-sockmisc.lo -MD -MP -MF $(DEPDIR)/libracoon_la-sockmisc.Tpo -c -o libracoon_la-sockmisc.lo `test -f 'sockmisc.c' || echo '$(srcdir)/'`sockmisc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libracoon_la-sockmisc.Tpo $(DEPDIR)/libracoon_la-sockmisc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sockmisc.c' object='libracoon_la-sockmisc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-sockmisc.lo `test -f 'sockmisc.c' || echo '$(srcdir)/'`sockmisc.c + +libracoon_la-misc.lo: misc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-misc.lo -MD -MP -MF $(DEPDIR)/libracoon_la-misc.Tpo -c -o libracoon_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libracoon_la-misc.Tpo $(DEPDIR)/libracoon_la-misc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc.c' object='libracoon_la-misc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c + sha2.obj: missing/crypto/sha2/sha2.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha2.obj -MD -MP -MF $(DEPDIR)/sha2.Tpo -c -o sha2.obj `if test -f 'missing/crypto/sha2/sha2.c'; then $(CYGPATH_W) 'missing/crypto/sha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/sha2/sha2.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/sha2.Tpo $(DEPDIR)/sha2.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/sha2.Tpo $(DEPDIR)/sha2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='missing/crypto/sha2/sha2.c' object='sha2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha2.obj `if test -f 'missing/crypto/sha2/sha2.c'; then $(CYGPATH_W) 'missing/crypto/sha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/sha2/sha2.c'; fi` rijndael-api-fst.obj: missing/crypto/rijndael/rijndael-api-fst.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rijndael-api-fst.obj -MD -MP -MF $(DEPDIR)/rijndael-api-fst.Tpo -c -o rijndael-api-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-api-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-api-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-api-fst.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/rijndael-api-fst.Tpo $(DEPDIR)/rijndael-api-fst.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rijndael-api-fst.Tpo $(DEPDIR)/rijndael-api-fst.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='missing/crypto/rijndael/rijndael-api-fst.c' object='rijndael-api-fst.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rijndael-api-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-api-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-api-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-api-fst.c'; fi` rijndael-alg-fst.obj: missing/crypto/rijndael/rijndael-alg-fst.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rijndael-alg-fst.obj -MD -MP -MF $(DEPDIR)/rijndael-alg-fst.Tpo -c -o rijndael-alg-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-alg-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-alg-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-alg-fst.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/rijndael-alg-fst.Tpo $(DEPDIR)/rijndael-alg-fst.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rijndael-alg-fst.Tpo $(DEPDIR)/rijndael-alg-fst.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='missing/crypto/rijndael/rijndael-alg-fst.c' object='rijndael-alg-fst.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rijndael-alg-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-alg-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-alg-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-alg-fst.c'; fi` @@ -592,127 +670,108 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-man5: $(man5_MANS) $(man_MANS) +install-man5: $(man5_MANS) @$(NORMAL_INSTALL) test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" - @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.5*) list="$$list $$i" ;; \ - esac; \ + @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ + fi; \ done; \ - for i in $$list; do \ - if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ - else file=$$i; fi; \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 5*) ;; \ - *) ext='5' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ - done + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ + done; } + uninstall-man5: @$(NORMAL_UNINSTALL) - @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.5*) list="$$list $$i" ;; \ - esac; \ - done; \ - for i in $$list; do \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 5*) ;; \ - *) ext='5' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ - rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ - done -install-man8: $(man8_MANS) $(man_MANS) + @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man5dir)" && rm -f $$files; } +install-man8: $(man8_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" - @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.8*) list="$$list $$i" ;; \ - esac; \ + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ done; \ - for i in $$list; do \ - if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ - else file=$$i; fi; \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 8*) ;; \ - *) ext='8' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ - done + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + uninstall-man8: @$(NORMAL_UNINSTALL) - @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.8*) list="$$list $$i" ;; \ - esac; \ - done; \ - for i in $$list; do \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 8*) ;; \ - *) ext='8' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ - rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ - done + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } install-include_racoonHEADERS: $(include_racoon_HEADERS) @$(NORMAL_INSTALL) test -z "$(include_racoondir)" || $(MKDIR_P) "$(DESTDIR)$(include_racoondir)" - @list='$(include_racoon_HEADERS)'; for p in $$list; do \ + @list='$(include_racoon_HEADERS)'; test -n "$(include_racoondir)" || list=; \ + for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(include_racoonHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_racoondir)/$$f'"; \ - $(include_racoonHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_racoondir)/$$f"; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_racoondir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_racoondir)" || exit $$?; \ done uninstall-include_racoonHEADERS: @$(NORMAL_UNINSTALL) - @list='$(include_racoon_HEADERS)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(include_racoondir)/$$f'"; \ - rm -f "$(DESTDIR)$(include_racoondir)/$$f"; \ - done + @list='$(include_racoon_HEADERS)'; test -n "$(include_racoondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(include_racoondir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(include_racoondir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -720,37 +779,43 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) - @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[ ]'; \ + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ + $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ @@ -759,49 +824,63 @@ check-TESTS: $(TESTS) if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ - *$$ws$$tst$$ws*) \ + *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ - echo "XPASS: $$tst"; \ + col=$$red; res=XPASS; \ ;; \ *) \ - echo "PASS: $$tst"; \ + col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ - *$$ws$$tst$$ws*) \ + *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ - echo "XFAIL: $$tst"; \ + col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ - echo "FAIL: $$tst"; \ + col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ - echo "SKIP: $$tst"; \ + col=$$blu; res=SKIP; \ fi; \ + echo "$${col}$$res$${std}: $$tst"; \ done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ - banner="All $$all tests passed"; \ + banner="$$All$$all $$tests passed"; \ else \ - banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ - banner="$$failed of $$all tests failed"; \ + banner="$$failed of $$all $$tests failed"; \ else \ - banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ - skipped="($$skip tests were not run)"; \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ @@ -812,15 +891,32 @@ check-TESTS: $(TESTS) dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ - echo "$$dashes"; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ - echo "$$dashes"; \ + echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -836,13 +932,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -876,6 +976,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -904,6 +1005,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -912,19 +1015,29 @@ install-data-am: install-include_racoonHEADERS install-man install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-exec-local install-libLTLIBRARIES \ install-sbinPROGRAMS install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-man5 install-man8 install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -950,7 +1063,7 @@ uninstall-am: uninstall-include_racoonHEADERS uninstall-libLTLIBRARIES \ uninstall-man: uninstall-man5 uninstall-man8 -.MAKE: install-am install-strip +.MAKE: all check check-am install install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool \ @@ -995,6 +1108,7 @@ rijndael-alg-fst.o: $(srcdir)/missing/crypto/rijndael/rijndael-alg-fst.c $(COMPILE) -c $(srcdir)/missing/crypto/rijndael/$*.c sha2.o: $(srcdir)/missing/crypto/sha2/sha2.c $(COMPILE) -c $(srcdir)/missing/crypto/sha2/$*.c + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/racoon/admin.c b/src/racoon/admin.c index b56dd2c..b0aad88 100644 --- a/src/racoon/admin.c +++ b/src/racoon/admin.c @@ -1,11 +1,11 @@ -/* $NetBSD: admin.c,v 1.17.6.3 2009/04/20 13:32:57 tteras Exp $ */ +/* $NetBSD: admin.c,v 1.38 2010/12/08 07:38:35 tteras Exp $ */ /* Id: admin.c,v 1.25 2006/04/06 14:31:04 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -76,6 +76,7 @@ #include "evt.h" #include "pfkey.h" #include "ipsec_doi.h" +#include "policy.h" #include "admin.h" #include "admin_var.h" #include "isakmp_inf.h" @@ -93,10 +94,12 @@ 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 *)); +static int admin_reply __P((int, struct admin_com *, int, vchar_t *)); -int -admin_handler() +static int +admin_handler(ctx, fd) + void *ctx; + int fd; { int so2; struct sockaddr_storage from; @@ -112,6 +115,7 @@ admin_handler() strerror(errno)); return -1; } + close_on_exec(so2); /* get buffer length */ while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { @@ -147,22 +151,30 @@ admin_handler() 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); +end: + if (error == -2) { + plog(LLV_DEBUG, LOCATION, NULL, + "[%d] admin connection established\n", so2); + } else { + (void)close(so2); + } + if (combuf) racoon_free(combuf); return error; } +static int admin_ph1_delete_sa(struct ph1handle *iph1, void *arg) +{ + if (iph1->status >= PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(iph1); + purge_remote(iph1); + return 0; +} + /* * main child's process. */ @@ -176,131 +188,140 @@ admin_process(so2, combuf) vchar_t *id = NULL; vchar_t *key = NULL; int idtype = 0; - int error = -1; + int error = 0, l_ac_errno = 0; + struct evt_listener_list *event_list = NULL; - com->ac_errno = 0; + if (com->ac_cmd & ADMIN_FLAG_VERSION) + com->ac_cmd &= ~ADMIN_FLAG_VERSION; + else + com->ac_version = 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 out; + signal_handler(SIGHUP); + break; - case ADMIN_SHOW_SCHED: - { + case ADMIN_SHOW_SCHED: { caddr_t p = NULL; int len; - com->ac_errno = -1; - - if (sched_dump(&p, &len) == -1) - goto out2; - - if ((buf = vmalloc(len)) == NULL) - goto out2; - - memcpy(buf->v, p, len); - - com->ac_errno = 0; -out2: - racoon_free(p); + if (sched_dump(&p, &len) != -1) { + buf = vmalloc(len); + if (buf != NULL) + memcpy(buf->v, p, len); + else + l_ac_errno = ENOMEM; + racoon_free(p); + } else + l_ac_errno = ENOMEM; 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; + if (com->ac_version == 0) { + buf = evt_dump(); + l_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; - } + buf = dumpph1(); + if (buf == NULL) + l_ac_errno = ENOMEM; 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 out; + case ADMIN_PROTO_ESP: { + u_int p; + p = admin2pfkey_proto(com->ac_proto); + if (p != -1) { buf = pfkey_dump_sadb(p); if (buf == NULL) - com->ac_errno = -1; - } - break; - case ADMIN_FLUSH_SA: - pfkey_flush_sadb(com->ac_proto); - break; - } + l_ac_errno = ENOMEM; + } else + l_ac_errno = EINVAL; 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; - } + default: + l_ac_errno = ENOTSUP; + break; + } + break; + + case ADMIN_GET_SA_CERT: { + struct admin_com_indexes *ndx; + struct sockaddr *src, *dst; + struct ph1handle *iph1; + + ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); + src = (struct sockaddr *) &ndx->src; + dst = (struct sockaddr *) &ndx->dst; + + if (com->ac_proto != ADMIN_PROTO_ISAKMP) { + l_ac_errno = ENOTSUP; break; + } + + iph1 = getph1byaddr(src, dst, 0); + if (iph1 == NULL) { + l_ac_errno = ENOENT; + break; + } + if (iph1->cert_p != NULL) { + vchar_t tmp; + tmp.v = iph1->cert_p->v + 1; + tmp.l = iph1->cert_p->l - 1; + buf = vdup(&tmp); + } + break; + } + + case ADMIN_FLUSH_SA: + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + flushph1(); + break; + case ADMIN_PROTO_IPSEC: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + pfkey_flush_sadb(com->ac_proto); + break; + case ADMIN_PROTO_INTERNAL: + /*XXX flushph2();*/ default: - /* ignore */ - com->ac_errno = -1; + l_ac_errno = ENOTSUP; + break; } - } break; case ADMIN_DELETE_SA: { - struct ph1handle *iph1; - struct sockaddr *dst; - struct sockaddr *src; char *loc, *rem; + struct ph1selector sel; - src = (struct sockaddr *) + memset(&sel, 0, sizeof(sel)); + sel.local = (struct sockaddr *) &((struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)))->src; - dst = (struct sockaddr *) + sel.remote = (struct sockaddr *) &((struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)))->dst; - loc = racoon_strdup(saddrwop2str(src)); - rem = racoon_strdup(saddrwop2str(dst)); + loc = racoon_strdup(saddr2str(sel.local)); + rem = racoon_strdup(saddr2str(sel.remote)); STRDUP_FATAL(loc); STRDUP_FATAL(rem); - 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); - } + plog(LLV_INFO, LOCATION, NULL, + "admin delete-sa %s %s\n", loc, rem); + enumph1(&sel, admin_ph1_delete_sa, NULL); + remcontacted(sel.remote); racoon_free(loc); racoon_free(rem); - break; } @@ -308,7 +329,7 @@ out2: case ADMIN_LOGOUT_USER: { struct ph1handle *iph1; char user[LOGINLEN+1]; - int found = 0, len = com->ac_len - sizeof(com); + int found = 0, len = com->ac_len - sizeof(*com); if (len > LOGINLEN) { plog(LLV_ERROR, LOCATION, NULL, @@ -320,7 +341,7 @@ out2: user[len] = 0; found = purgeph1bylogin(user); - plog(LLV_INFO, LOCATION, NULL, + plog(LLV_INFO, LOCATION, NULL, "deleted %d SA for user \"%s\"\n", found, user); break; @@ -339,22 +360,21 @@ out2: rem = racoon_strdup(saddrwop2str(dst)); STRDUP_FATAL(rem); - plog(LLV_INFO, LOCATION, NULL, + plog(LLV_INFO, LOCATION, NULL, "Flushing all SAs for peer %s\n", rem); - while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { + while ((iph1 = getph1bydstaddr(dst)) != NULL) { loc = racoon_strdup(saddrwop2str(iph1->local)); STRDUP_FATAL(loc); - if (iph1->status == PHASE1ST_ESTABLISHED) + if (iph1->status >= PHASE1ST_ESTABLISHED) isakmp_info_send_d1(iph1); purge_remote(iph1); racoon_free(loc); } - - racoon_free(rem); + racoon_free(rem); break; } @@ -362,17 +382,15 @@ out2: struct admin_com_psk *acp; char *data; - com->ac_cmd = ADMIN_ESTABLISH_SA; - acp = (struct admin_com_psk *) - ((char *)com + sizeof(*com) + + ((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", + "cannot allocate memory: %s\n", strerror(errno)); break; } @@ -381,7 +399,7 @@ out2: if ((key = vmalloc(acp->key_len)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "cannot allocate memory: %s\n", + "cannot allocate memory: %s\n", strerror(errno)); vfree(id); id = NULL; @@ -391,56 +409,57 @@ out2: memcpy(key->v, data, key->l); } /* FALLTHROUGH */ - case ADMIN_ESTABLISH_SA: - { + case ADMIN_ESTABLISH_SA: { + struct admin_com_indexes *ndx; 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; + char *name = NULL; + + ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); + src = (struct sockaddr *) &ndx->src; + dst = (struct sockaddr *) &ndx->dst; + + if (com->ac_cmd == ADMIN_ESTABLISH_SA && + com->ac_len > sizeof(*com) + sizeof(*ndx)) + name = (char *) ((caddr_t) ndx + sizeof(*ndx)); switch (com->ac_proto) { case ADMIN_PROTO_ISAKMP: { + struct ph1handle *ph1; struct remoteconf *rmconf; - struct sockaddr *remote = NULL; - struct sockaddr *local = NULL; u_int16_t port; - com->ac_errno = -1; + l_ac_errno = -1; + + /* connected already? */ + ph1 = getph1byaddr(src, dst, 0); + if (ph1 != NULL) { + event_list = &ph1->evt_listeners; + if (ph1->status == PHASE1ST_ESTABLISHED) + l_ac_errno = EEXIST; + else + l_ac_errno = 0; + break; + } /* search appropreate configuration */ - rmconf = getrmconf(dst); + if (name == NULL) + rmconf = getrmconf(dst, 0); + else + rmconf = getrmconf_by_name(name); if (rmconf == NULL) { plog(LLV_ERROR, LOCATION, NULL, "no configuration found " "for %s\n", saddrwop2str(dst)); - goto out1; + break; } - /* get remote IP address and port number. */ - if ((remote = dupsaddr(dst)) == NULL) - goto out1; - - port = extract_port(rmconf->remote); - if (set_port(remote, port) == NULL) - goto out1; - - /* get local address */ - if ((local = dupsaddr(src)) == NULL) - goto out1; - - port = getmyaddrsport(local); - if (set_port(local, port) == NULL) - goto out1; - #ifdef ENABLE_HYBRID + /* XXX This overwrites rmconf information globally. */ /* Set the id and key */ if (id && key) { if (xauth_rmconf_used(&rmconf->xauth) == -1) - goto out1; + break; if (rmconf->xauth->login != NULL) { vfree(rmconf->xauth->login); @@ -455,43 +474,145 @@ out2: rmconf->xauth->pass = key; } #endif - + plog(LLV_INFO, LOCATION, NULL, "accept a request to establish IKE-SA: " - "%s\n", saddrwop2str(remote)); + "%s\n", saddrwop2str(dst)); /* begin ident mode */ - if (isakmp_ph1begin_i(rmconf, remote, local) < 0) - goto out1; - - com->ac_errno = 0; -out1: - if (local != NULL) - racoon_free(local); - if (remote != NULL) - racoon_free(remote); + ph1 = isakmp_ph1begin_i(rmconf, dst, src); + if (ph1 == NULL) + break; + + event_list = &ph1->evt_listeners; + l_ac_errno = 0; break; } case ADMIN_PROTO_AH: - case ADMIN_PROTO_ESP: + case ADMIN_PROTO_ESP: { + struct ph2handle *iph2; + struct secpolicy *sp_out = NULL, *sp_in = NULL; + struct policyindex spidx; + + l_ac_errno = -1; + + /* got outbound policy */ + memset(&spidx, 0, sizeof(spidx)); + spidx.dir = IPSEC_DIR_OUTBOUND; + memcpy(&spidx.src, src, sizeof(spidx.src)); + memcpy(&spidx.dst, dst, sizeof(spidx.dst)); + spidx.prefs = ndx->prefs; + spidx.prefd = ndx->prefd; + spidx.ul_proto = ndx->ul_proto; + + sp_out = getsp_r(&spidx); + if (sp_out) { + plog(LLV_DEBUG, LOCATION, NULL, + "suitable outbound SP found: %s.\n", + spidx2str(&sp_out->spidx)); + } else { + l_ac_errno = ENOENT; + plog(LLV_NOTIFY, LOCATION, NULL, + "no outbound policy found: %s\n", + spidx2str(&spidx)); + break; + } + + iph2 = getph2byid(src, dst, sp_out->id); + if (iph2 != NULL) { + event_list = &iph2->evt_listeners; + if (iph2->status == PHASE2ST_ESTABLISHED) + l_ac_errno = EEXIST; + else + l_ac_errno = 0; + break; + } + + /* get inbound policy */ + memset(&spidx, 0, sizeof(spidx)); + spidx.dir = IPSEC_DIR_INBOUND; + memcpy(&spidx.src, dst, sizeof(spidx.src)); + memcpy(&spidx.dst, src, sizeof(spidx.dst)); + spidx.prefs = ndx->prefd; + spidx.prefd = ndx->prefs; + spidx.ul_proto = ndx->ul_proto; + + sp_in = getsp_r(&spidx); + if (sp_in) { + plog(LLV_DEBUG, LOCATION, NULL, + "suitable inbound SP found: %s.\n", + spidx2str(&sp_in->spidx)); + } else { + l_ac_errno = ENOENT; + plog(LLV_NOTIFY, LOCATION, NULL, + "no inbound policy found: %s\n", + spidx2str(&spidx)); + break; + } + + /* allocate a phase 2 */ + iph2 = newph2(); + if (iph2 == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate phase2 entry.\n"); + break; + } + iph2->side = INITIATOR; + iph2->satype = admin2pfkey_proto(com->ac_proto); + iph2->spid = sp_out->id; + iph2->seq = pk_getseq(); + iph2->status = PHASE2ST_STATUS2; + + /* set end addresses of SA */ + iph2->sa_dst = dupsaddr(dst); + iph2->sa_src = dupsaddr(src); + iph2->dst = dupsaddr(dst); + iph2->src = dupsaddr(src); + if (iph2->sa_src == NULL || iph2->sa_dst == NULL || + iph2->dst == NULL || iph2->src == NULL) { + delph2(iph2); + break; + } + set_port(iph2->dst, 0); + set_port(iph2->src, 0); + + if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) { + delph2(iph2); + break; + } + + insph2(iph2); + if (isakmp_post_acquire(iph2, NULL, FALSE) < 0) { + remph2(iph2); + delph2(iph2); + break; + } + + event_list = &iph2->evt_listeners; + l_ac_errno = 0; break; + } default: /* ignore */ - com->ac_errno = -1; + l_ac_errno = ENOTSUP; } - } break; + } default: plog(LLV_ERROR, LOCATION, NULL, "invalid command: %d\n", com->ac_cmd); - com->ac_errno = -1; + l_ac_errno = ENOTSUP; } - if ((error = admin_reply(so2, com, buf)) != 0) + if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0) goto out; - error = 0; + /* start pushing events if so requested */ + if ((l_ac_errno == 0) && + (com->ac_version >= 1) && + (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL)) + error = evt_subscribe(event_list, so2); out: if (buf != NULL) vfree(buf); @@ -500,12 +621,13 @@ out: } static int -admin_reply(so, combuf, buf) - int so; - struct admin_com *combuf; +admin_reply(so, req, l_ac_errno, buf) + int so, l_ac_errno; + struct admin_com *req; vchar_t *buf; { int tlen; + struct admin_com *combuf; char *retbuf = NULL; if (buf != NULL) @@ -520,8 +642,17 @@ admin_reply(so, combuf, buf) return -1; } - memcpy(retbuf, combuf, sizeof(*combuf)); - ((struct admin_com *)retbuf)->ac_len = tlen; + combuf = (struct admin_com *) retbuf; + combuf->ac_len = (u_int16_t) tlen; + combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION; + if (tlen != (u_int32_t) combuf->ac_len && + l_ac_errno == 0) { + combuf->ac_len_high = tlen >> 16; + combuf->ac_cmd |= ADMIN_FLAG_LONG_REPLY; + } else { + combuf->ac_errno = l_ac_errno; + } + combuf->ac_proto = req->ac_proto; if (buf != NULL) memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); @@ -577,6 +708,7 @@ admin_init() "socket: %s\n", strerror(errno)); return -1; } + close_on_exec(lcconf->sock_admin); unlink(sunaddr.sun_path); if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, @@ -589,17 +721,17 @@ admin_init() } 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, + 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", + 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; @@ -612,8 +744,10 @@ admin_init() (void)close(lcconf->sock_admin); return -1; } + + monitor_fd(lcconf->sock_admin, admin_handler, NULL, 0); plog(LLV_DEBUG, LOCATION, NULL, - "open %s as racoon management.\n", sunaddr.sun_path); + "open %s as racoon management.\n", sunaddr.sun_path); return 0; } @@ -621,8 +755,9 @@ admin_init() int admin_close() { + unmonitor_fd(lcconf->sock_admin); close(lcconf->sock_admin); return 0; } -#endif +#endif diff --git a/src/racoon/admin.h b/src/racoon/admin.h index cbc19e8..8cb9382 100644 --- a/src/racoon/admin.h +++ b/src/racoon/admin.h @@ -1,4 +1,4 @@ -/* $NetBSD: admin.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: admin.h,v 1.8 2010/11/12 09:08:26 tteras Exp $ */ /* Id: admin.h,v 1.11 2005/06/19 22:37:47 manubsd Exp */ @@ -46,9 +46,22 @@ extern mode_t adminsock_mode; struct admin_com { u_int16_t ac_len; /* total packet length including data */ u_int16_t ac_cmd; - int16_t ac_errno; + union { + int16_t ac_un_errno; + uint16_t ac_un_version; + uint16_t ac_un_len_high; + } u; u_int16_t ac_proto; }; +#define ac_errno u.ac_un_errno +#define ac_version u.ac_un_version +#define ac_len_high u.ac_un_len_high + +/* + * Version field in request is valid. + */ +#define ADMIN_FLAG_VERSION 0x8000 +#define ADMIN_FLAG_LONG_REPLY 0x8000 /* * No data follows as the data. @@ -72,6 +85,8 @@ struct admin_com { #define ADMIN_ESTABLISH_SA 0x0202 #define ADMIN_DELETE_ALL_SA_DST 0x0204 /* All SA for a given peer */ +#define ADMIN_GET_SA_CERT 0x0206 + /* * The admin_com_indexes and admin_com_psk follow, see below. */ diff --git a/src/racoon/admin_var.h b/src/racoon/admin_var.h index 6d7ba81..f4471a3 100644 --- a/src/racoon/admin_var.h +++ b/src/racoon/admin_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: admin_var.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: admin_var.h,v 1.5 2008/12/23 14:03:12 tteras Exp $ */ /* Id: admin_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp */ @@ -34,7 +34,6 @@ #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)); diff --git a/src/racoon/backupsa.c b/src/racoon/backupsa.c index 9496000..82d74ca 100644 --- a/src/racoon/backupsa.c +++ b/src/racoon/backupsa.c @@ -1,4 +1,4 @@ -/* $NetBSD: backupsa.c,v 1.8.4.1 2007/08/01 11:52:19 vanhu Exp $ */ +/* $NetBSD: backupsa.c,v 1.10 2010/04/02 15:15:00 christos Exp $ */ /* $KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $ */ @@ -452,7 +452,7 @@ main() struct tm tm; time_t t; char *buf = "Nov 24 18:22:48 1986 "; - char *p; + const char *p; memset(&tm, 0, sizeof(tm)); p = str2tmx(buf, &tm); @@ -460,7 +460,8 @@ main() t = mktime(&tm); if (t == -1) printf("mktime failed."); - p = ctime(&t); + if ((p = ctime(&t)) == NULL) + p = "?"; printf("[%s]\n", p); exit(0); diff --git a/src/racoon/cfparse.h b/src/racoon/cfparse.h index 2946b3e..bbf678a 100644 --- a/src/racoon/cfparse.h +++ b/src/racoon/cfparse.h @@ -1,24 +1,23 @@ -/* A Bison parser, made by GNU Bison 2.3. */ -/* Skeleton interface for Bison's Yacc-like parsers in C +/* A Bison parser, made by GNU Bison 2.4.1. */ - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,10 +28,11 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ + /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -46,161 +46,170 @@ PATH = 262, PATHTYPE = 263, INCLUDE = 264, - IDENTIFIER = 265, - VENDORID = 266, - LOGGING = 267, - LOGLEV = 268, - PADDING = 269, - PAD_RANDOMIZE = 270, - PAD_RANDOMIZELEN = 271, - PAD_MAXLEN = 272, - PAD_STRICT = 273, - PAD_EXCLTAIL = 274, - LISTEN = 275, - X_ISAKMP = 276, - X_ISAKMP_NATT = 277, - X_ADMIN = 278, - STRICT_ADDRESS = 279, - ADMINSOCK = 280, - DISABLED = 281, - LDAPCFG = 282, - LDAP_HOST = 283, - LDAP_PORT = 284, - LDAP_PVER = 285, - LDAP_BASE = 286, - LDAP_BIND_DN = 287, - LDAP_BIND_PW = 288, - LDAP_SUBTREE = 289, - LDAP_ATTR_USER = 290, - LDAP_ATTR_ADDR = 291, - LDAP_ATTR_MASK = 292, - LDAP_ATTR_GROUP = 293, - LDAP_ATTR_MEMBER = 294, - MODECFG = 295, - CFG_NET4 = 296, - CFG_MASK4 = 297, - CFG_DNS4 = 298, - CFG_NBNS4 = 299, - CFG_DEFAULT_DOMAIN = 300, - CFG_AUTH_SOURCE = 301, - CFG_AUTH_GROUPS = 302, - CFG_SYSTEM = 303, - CFG_RADIUS = 304, - CFG_PAM = 305, - CFG_LDAP = 306, - CFG_LOCAL = 307, - CFG_NONE = 308, - CFG_GROUP_SOURCE = 309, - CFG_ACCOUNTING = 310, - CFG_CONF_SOURCE = 311, - CFG_MOTD = 312, - CFG_POOL_SIZE = 313, - CFG_AUTH_THROTTLE = 314, - CFG_SPLIT_NETWORK = 315, - CFG_SPLIT_LOCAL = 316, - CFG_SPLIT_INCLUDE = 317, - CFG_SPLIT_DNS = 318, - CFG_PFS_GROUP = 319, - CFG_SAVE_PASSWD = 320, - RETRY = 321, - RETRY_COUNTER = 322, - RETRY_INTERVAL = 323, - RETRY_PERSEND = 324, - RETRY_PHASE1 = 325, - RETRY_PHASE2 = 326, - NATT_KA = 327, - ALGORITHM_CLASS = 328, - ALGORITHMTYPE = 329, - STRENGTHTYPE = 330, - SAINFO = 331, - FROM = 332, - REMOTE = 333, - ANONYMOUS = 334, - INHERIT = 335, - EXCHANGE_MODE = 336, - EXCHANGETYPE = 337, - DOI = 338, - DOITYPE = 339, - SITUATION = 340, - SITUATIONTYPE = 341, - CERTIFICATE_TYPE = 342, - CERTTYPE = 343, - PEERS_CERTFILE = 344, - CA_TYPE = 345, - VERIFY_CERT = 346, - SEND_CERT = 347, - SEND_CR = 348, - IDENTIFIERTYPE = 349, - IDENTIFIERQUAL = 350, - MY_IDENTIFIER = 351, - PEERS_IDENTIFIER = 352, - VERIFY_IDENTIFIER = 353, - DNSSEC = 354, - CERT_X509 = 355, - CERT_PLAINRSA = 356, - NONCE_SIZE = 357, - DH_GROUP = 358, - KEEPALIVE = 359, - PASSIVE = 360, - INITIAL_CONTACT = 361, - NAT_TRAVERSAL = 362, - REMOTE_FORCE_LEVEL = 363, - PROPOSAL_CHECK = 364, - PROPOSAL_CHECK_LEVEL = 365, - GENERATE_POLICY = 366, - GENERATE_LEVEL = 367, - SUPPORT_PROXY = 368, - PROPOSAL = 369, - EXEC_PATH = 370, - EXEC_COMMAND = 371, - EXEC_SUCCESS = 372, - EXEC_FAILURE = 373, - GSS_ID = 374, - GSS_ID_ENC = 375, - GSS_ID_ENCTYPE = 376, - COMPLEX_BUNDLE = 377, - DPD = 378, - DPD_DELAY = 379, - DPD_RETRY = 380, - DPD_MAXFAIL = 381, - PH1ID = 382, - XAUTH_LOGIN = 383, - WEAK_PHASE1_CHECK = 384, - PREFIX = 385, - PORT = 386, - PORTANY = 387, - UL_PROTO = 388, - ANY = 389, - IKE_FRAG = 390, - ESP_FRAG = 391, - MODE_CFG = 392, - PFS_GROUP = 393, - LIFETIME = 394, - LIFETYPE_TIME = 395, - LIFETYPE_BYTE = 396, - STRENGTH = 397, - REMOTEID = 398, - SCRIPT = 399, - PHASE1_UP = 400, - PHASE1_DOWN = 401, - NUMBER = 402, - SWITCH = 403, - BOOLEAN = 404, - HEXSTRING = 405, - QUOTEDSTRING = 406, - ADDRSTRING = 407, - ADDRRANGE = 408, - UNITTYPE_BYTE = 409, - UNITTYPE_KBYTES = 410, - UNITTYPE_MBYTES = 411, - UNITTYPE_TBYTES = 412, - UNITTYPE_SEC = 413, - UNITTYPE_MIN = 414, - UNITTYPE_HOUR = 415, - EOS = 416, - BOC = 417, - EOC = 418, - COMMA = 419 + PFKEY_BUFFER = 265, + LOGGING = 266, + LOGLEV = 267, + PADDING = 268, + PAD_RANDOMIZE = 269, + PAD_RANDOMIZELEN = 270, + PAD_MAXLEN = 271, + PAD_STRICT = 272, + PAD_EXCLTAIL = 273, + LISTEN = 274, + X_ISAKMP = 275, + X_ISAKMP_NATT = 276, + X_ADMIN = 277, + STRICT_ADDRESS = 278, + ADMINSOCK = 279, + DISABLED = 280, + LDAPCFG = 281, + LDAP_HOST = 282, + LDAP_PORT = 283, + LDAP_PVER = 284, + LDAP_BASE = 285, + LDAP_BIND_DN = 286, + LDAP_BIND_PW = 287, + LDAP_SUBTREE = 288, + LDAP_ATTR_USER = 289, + LDAP_ATTR_ADDR = 290, + LDAP_ATTR_MASK = 291, + LDAP_ATTR_GROUP = 292, + LDAP_ATTR_MEMBER = 293, + RADCFG = 294, + RAD_AUTH = 295, + RAD_ACCT = 296, + RAD_TIMEOUT = 297, + RAD_RETRIES = 298, + MODECFG = 299, + CFG_NET4 = 300, + CFG_MASK4 = 301, + CFG_DNS4 = 302, + CFG_NBNS4 = 303, + CFG_DEFAULT_DOMAIN = 304, + CFG_AUTH_SOURCE = 305, + CFG_AUTH_GROUPS = 306, + CFG_SYSTEM = 307, + CFG_RADIUS = 308, + CFG_PAM = 309, + CFG_LDAP = 310, + CFG_LOCAL = 311, + CFG_NONE = 312, + CFG_GROUP_SOURCE = 313, + CFG_ACCOUNTING = 314, + CFG_CONF_SOURCE = 315, + CFG_MOTD = 316, + CFG_POOL_SIZE = 317, + CFG_AUTH_THROTTLE = 318, + CFG_SPLIT_NETWORK = 319, + CFG_SPLIT_LOCAL = 320, + CFG_SPLIT_INCLUDE = 321, + CFG_SPLIT_DNS = 322, + CFG_PFS_GROUP = 323, + CFG_SAVE_PASSWD = 324, + RETRY = 325, + RETRY_COUNTER = 326, + RETRY_INTERVAL = 327, + RETRY_PERSEND = 328, + RETRY_PHASE1 = 329, + RETRY_PHASE2 = 330, + NATT_KA = 331, + ALGORITHM_CLASS = 332, + ALGORITHMTYPE = 333, + STRENGTHTYPE = 334, + SAINFO = 335, + FROM = 336, + REMOTE = 337, + ANONYMOUS = 338, + CLIENTADDR = 339, + INHERIT = 340, + REMOTE_ADDRESS = 341, + EXCHANGE_MODE = 342, + EXCHANGETYPE = 343, + DOI = 344, + DOITYPE = 345, + SITUATION = 346, + SITUATIONTYPE = 347, + CERTIFICATE_TYPE = 348, + CERTTYPE = 349, + PEERS_CERTFILE = 350, + CA_TYPE = 351, + VERIFY_CERT = 352, + SEND_CERT = 353, + SEND_CR = 354, + MATCH_EMPTY_CR = 355, + IDENTIFIERTYPE = 356, + IDENTIFIERQUAL = 357, + MY_IDENTIFIER = 358, + PEERS_IDENTIFIER = 359, + VERIFY_IDENTIFIER = 360, + DNSSEC = 361, + CERT_X509 = 362, + CERT_PLAINRSA = 363, + NONCE_SIZE = 364, + DH_GROUP = 365, + KEEPALIVE = 366, + PASSIVE = 367, + INITIAL_CONTACT = 368, + NAT_TRAVERSAL = 369, + REMOTE_FORCE_LEVEL = 370, + PROPOSAL_CHECK = 371, + PROPOSAL_CHECK_LEVEL = 372, + GENERATE_POLICY = 373, + GENERATE_LEVEL = 374, + SUPPORT_PROXY = 375, + PROPOSAL = 376, + EXEC_PATH = 377, + EXEC_COMMAND = 378, + EXEC_SUCCESS = 379, + EXEC_FAILURE = 380, + GSS_ID = 381, + GSS_ID_ENC = 382, + GSS_ID_ENCTYPE = 383, + COMPLEX_BUNDLE = 384, + DPD = 385, + DPD_DELAY = 386, + DPD_RETRY = 387, + DPD_MAXFAIL = 388, + PH1ID = 389, + XAUTH_LOGIN = 390, + WEAK_PHASE1_CHECK = 391, + REKEY = 392, + PREFIX = 393, + PORT = 394, + PORTANY = 395, + UL_PROTO = 396, + ANY = 397, + IKE_FRAG = 398, + ESP_FRAG = 399, + MODE_CFG = 400, + PFS_GROUP = 401, + LIFETIME = 402, + LIFETYPE_TIME = 403, + LIFETYPE_BYTE = 404, + STRENGTH = 405, + REMOTEID = 406, + SCRIPT = 407, + PHASE1_UP = 408, + PHASE1_DOWN = 409, + PHASE1_DEAD = 410, + NUMBER = 411, + SWITCH = 412, + BOOLEAN = 413, + HEXSTRING = 414, + QUOTEDSTRING = 415, + ADDRSTRING = 416, + ADDRRANGE = 417, + UNITTYPE_BYTE = 418, + UNITTYPE_KBYTES = 419, + UNITTYPE_MBYTES = 420, + UNITTYPE_TBYTES = 421, + UNITTYPE_SEC = 422, + UNITTYPE_MIN = 423, + UNITTYPE_HOUR = 424, + EOS = 425, + BOC = 426, + EOC = 427, + COMMA = 428 }; #endif /* Tokens. */ @@ -211,182 +220,197 @@ #define PATH 262 #define PATHTYPE 263 #define INCLUDE 264 -#define IDENTIFIER 265 -#define VENDORID 266 -#define LOGGING 267 -#define LOGLEV 268 -#define PADDING 269 -#define PAD_RANDOMIZE 270 -#define PAD_RANDOMIZELEN 271 -#define PAD_MAXLEN 272 -#define PAD_STRICT 273 -#define PAD_EXCLTAIL 274 -#define LISTEN 275 -#define X_ISAKMP 276 -#define X_ISAKMP_NATT 277 -#define X_ADMIN 278 -#define STRICT_ADDRESS 279 -#define ADMINSOCK 280 -#define DISABLED 281 -#define LDAPCFG 282 -#define LDAP_HOST 283 -#define LDAP_PORT 284 -#define LDAP_PVER 285 -#define LDAP_BASE 286 -#define LDAP_BIND_DN 287 -#define LDAP_BIND_PW 288 -#define LDAP_SUBTREE 289 -#define LDAP_ATTR_USER 290 -#define LDAP_ATTR_ADDR 291 -#define LDAP_ATTR_MASK 292 -#define LDAP_ATTR_GROUP 293 -#define LDAP_ATTR_MEMBER 294 -#define MODECFG 295 -#define CFG_NET4 296 -#define CFG_MASK4 297 -#define CFG_DNS4 298 -#define CFG_NBNS4 299 -#define CFG_DEFAULT_DOMAIN 300 -#define CFG_AUTH_SOURCE 301 -#define CFG_AUTH_GROUPS 302 -#define CFG_SYSTEM 303 -#define CFG_RADIUS 304 -#define CFG_PAM 305 -#define CFG_LDAP 306 -#define CFG_LOCAL 307 -#define CFG_NONE 308 -#define CFG_GROUP_SOURCE 309 -#define CFG_ACCOUNTING 310 -#define CFG_CONF_SOURCE 311 -#define CFG_MOTD 312 -#define CFG_POOL_SIZE 313 -#define CFG_AUTH_THROTTLE 314 -#define CFG_SPLIT_NETWORK 315 -#define CFG_SPLIT_LOCAL 316 -#define CFG_SPLIT_INCLUDE 317 -#define CFG_SPLIT_DNS 318 -#define CFG_PFS_GROUP 319 -#define CFG_SAVE_PASSWD 320 -#define RETRY 321 -#define RETRY_COUNTER 322 -#define RETRY_INTERVAL 323 -#define RETRY_PERSEND 324 -#define RETRY_PHASE1 325 -#define RETRY_PHASE2 326 -#define NATT_KA 327 -#define ALGORITHM_CLASS 328 -#define ALGORITHMTYPE 329 -#define STRENGTHTYPE 330 -#define SAINFO 331 -#define FROM 332 -#define REMOTE 333 -#define ANONYMOUS 334 -#define INHERIT 335 -#define EXCHANGE_MODE 336 -#define EXCHANGETYPE 337 -#define DOI 338 -#define DOITYPE 339 -#define SITUATION 340 -#define SITUATIONTYPE 341 -#define CERTIFICATE_TYPE 342 -#define CERTTYPE 343 -#define PEERS_CERTFILE 344 -#define CA_TYPE 345 -#define VERIFY_CERT 346 -#define SEND_CERT 347 -#define SEND_CR 348 -#define IDENTIFIERTYPE 349 -#define IDENTIFIERQUAL 350 -#define MY_IDENTIFIER 351 -#define PEERS_IDENTIFIER 352 -#define VERIFY_IDENTIFIER 353 -#define DNSSEC 354 -#define CERT_X509 355 -#define CERT_PLAINRSA 356 -#define NONCE_SIZE 357 -#define DH_GROUP 358 -#define KEEPALIVE 359 -#define PASSIVE 360 -#define INITIAL_CONTACT 361 -#define NAT_TRAVERSAL 362 -#define REMOTE_FORCE_LEVEL 363 -#define PROPOSAL_CHECK 364 -#define PROPOSAL_CHECK_LEVEL 365 -#define GENERATE_POLICY 366 -#define GENERATE_LEVEL 367 -#define SUPPORT_PROXY 368 -#define PROPOSAL 369 -#define EXEC_PATH 370 -#define EXEC_COMMAND 371 -#define EXEC_SUCCESS 372 -#define EXEC_FAILURE 373 -#define GSS_ID 374 -#define GSS_ID_ENC 375 -#define GSS_ID_ENCTYPE 376 -#define COMPLEX_BUNDLE 377 -#define DPD 378 -#define DPD_DELAY 379 -#define DPD_RETRY 380 -#define DPD_MAXFAIL 381 -#define PH1ID 382 -#define XAUTH_LOGIN 383 -#define WEAK_PHASE1_CHECK 384 -#define PREFIX 385 -#define PORT 386 -#define PORTANY 387 -#define UL_PROTO 388 -#define ANY 389 -#define IKE_FRAG 390 -#define ESP_FRAG 391 -#define MODE_CFG 392 -#define PFS_GROUP 393 -#define LIFETIME 394 -#define LIFETYPE_TIME 395 -#define LIFETYPE_BYTE 396 -#define STRENGTH 397 -#define REMOTEID 398 -#define SCRIPT 399 -#define PHASE1_UP 400 -#define PHASE1_DOWN 401 -#define NUMBER 402 -#define SWITCH 403 -#define BOOLEAN 404 -#define HEXSTRING 405 -#define QUOTEDSTRING 406 -#define ADDRSTRING 407 -#define ADDRRANGE 408 -#define UNITTYPE_BYTE 409 -#define UNITTYPE_KBYTES 410 -#define UNITTYPE_MBYTES 411 -#define UNITTYPE_TBYTES 412 -#define UNITTYPE_SEC 413 -#define UNITTYPE_MIN 414 -#define UNITTYPE_HOUR 415 -#define EOS 416 -#define BOC 417 -#define EOC 418 -#define COMMA 419 +#define PFKEY_BUFFER 265 +#define LOGGING 266 +#define LOGLEV 267 +#define PADDING 268 +#define PAD_RANDOMIZE 269 +#define PAD_RANDOMIZELEN 270 +#define PAD_MAXLEN 271 +#define PAD_STRICT 272 +#define PAD_EXCLTAIL 273 +#define LISTEN 274 +#define X_ISAKMP 275 +#define X_ISAKMP_NATT 276 +#define X_ADMIN 277 +#define STRICT_ADDRESS 278 +#define ADMINSOCK 279 +#define DISABLED 280 +#define LDAPCFG 281 +#define LDAP_HOST 282 +#define LDAP_PORT 283 +#define LDAP_PVER 284 +#define LDAP_BASE 285 +#define LDAP_BIND_DN 286 +#define LDAP_BIND_PW 287 +#define LDAP_SUBTREE 288 +#define LDAP_ATTR_USER 289 +#define LDAP_ATTR_ADDR 290 +#define LDAP_ATTR_MASK 291 +#define LDAP_ATTR_GROUP 292 +#define LDAP_ATTR_MEMBER 293 +#define RADCFG 294 +#define RAD_AUTH 295 +#define RAD_ACCT 296 +#define RAD_TIMEOUT 297 +#define RAD_RETRIES 298 +#define MODECFG 299 +#define CFG_NET4 300 +#define CFG_MASK4 301 +#define CFG_DNS4 302 +#define CFG_NBNS4 303 +#define CFG_DEFAULT_DOMAIN 304 +#define CFG_AUTH_SOURCE 305 +#define CFG_AUTH_GROUPS 306 +#define CFG_SYSTEM 307 +#define CFG_RADIUS 308 +#define CFG_PAM 309 +#define CFG_LDAP 310 +#define CFG_LOCAL 311 +#define CFG_NONE 312 +#define CFG_GROUP_SOURCE 313 +#define CFG_ACCOUNTING 314 +#define CFG_CONF_SOURCE 315 +#define CFG_MOTD 316 +#define CFG_POOL_SIZE 317 +#define CFG_AUTH_THROTTLE 318 +#define CFG_SPLIT_NETWORK 319 +#define CFG_SPLIT_LOCAL 320 +#define CFG_SPLIT_INCLUDE 321 +#define CFG_SPLIT_DNS 322 +#define CFG_PFS_GROUP 323 +#define CFG_SAVE_PASSWD 324 +#define RETRY 325 +#define RETRY_COUNTER 326 +#define RETRY_INTERVAL 327 +#define RETRY_PERSEND 328 +#define RETRY_PHASE1 329 +#define RETRY_PHASE2 330 +#define NATT_KA 331 +#define ALGORITHM_CLASS 332 +#define ALGORITHMTYPE 333 +#define STRENGTHTYPE 334 +#define SAINFO 335 +#define FROM 336 +#define REMOTE 337 +#define ANONYMOUS 338 +#define CLIENTADDR 339 +#define INHERIT 340 +#define REMOTE_ADDRESS 341 +#define EXCHANGE_MODE 342 +#define EXCHANGETYPE 343 +#define DOI 344 +#define DOITYPE 345 +#define SITUATION 346 +#define SITUATIONTYPE 347 +#define CERTIFICATE_TYPE 348 +#define CERTTYPE 349 +#define PEERS_CERTFILE 350 +#define CA_TYPE 351 +#define VERIFY_CERT 352 +#define SEND_CERT 353 +#define SEND_CR 354 +#define MATCH_EMPTY_CR 355 +#define IDENTIFIERTYPE 356 +#define IDENTIFIERQUAL 357 +#define MY_IDENTIFIER 358 +#define PEERS_IDENTIFIER 359 +#define VERIFY_IDENTIFIER 360 +#define DNSSEC 361 +#define CERT_X509 362 +#define CERT_PLAINRSA 363 +#define NONCE_SIZE 364 +#define DH_GROUP 365 +#define KEEPALIVE 366 +#define PASSIVE 367 +#define INITIAL_CONTACT 368 +#define NAT_TRAVERSAL 369 +#define REMOTE_FORCE_LEVEL 370 +#define PROPOSAL_CHECK 371 +#define PROPOSAL_CHECK_LEVEL 372 +#define GENERATE_POLICY 373 +#define GENERATE_LEVEL 374 +#define SUPPORT_PROXY 375 +#define PROPOSAL 376 +#define EXEC_PATH 377 +#define EXEC_COMMAND 378 +#define EXEC_SUCCESS 379 +#define EXEC_FAILURE 380 +#define GSS_ID 381 +#define GSS_ID_ENC 382 +#define GSS_ID_ENCTYPE 383 +#define COMPLEX_BUNDLE 384 +#define DPD 385 +#define DPD_DELAY 386 +#define DPD_RETRY 387 +#define DPD_MAXFAIL 388 +#define PH1ID 389 +#define XAUTH_LOGIN 390 +#define WEAK_PHASE1_CHECK 391 +#define REKEY 392 +#define PREFIX 393 +#define PORT 394 +#define PORTANY 395 +#define UL_PROTO 396 +#define ANY 397 +#define IKE_FRAG 398 +#define ESP_FRAG 399 +#define MODE_CFG 400 +#define PFS_GROUP 401 +#define LIFETIME 402 +#define LIFETYPE_TIME 403 +#define LIFETYPE_BYTE 404 +#define STRENGTH 405 +#define REMOTEID 406 +#define SCRIPT 407 +#define PHASE1_UP 408 +#define PHASE1_DOWN 409 +#define PHASE1_DEAD 410 +#define NUMBER 411 +#define SWITCH 412 +#define BOOLEAN 413 +#define HEXSTRING 414 +#define QUOTEDSTRING 415 +#define ADDRSTRING 416 +#define ADDRRANGE 417 +#define UNITTYPE_BYTE 418 +#define UNITTYPE_KBYTES 419 +#define UNITTYPE_MBYTES 420 +#define UNITTYPE_TBYTES 421 +#define UNITTYPE_SEC 422 +#define UNITTYPE_MIN 423 +#define UNITTYPE_HOUR 424 +#define EOS 425 +#define BOC 426 +#define EOC 427 +#define COMMA 428 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 174 "cfparse.y" { + +/* Line 1676 of yacc.c */ +#line 177 "cfparse.y" + unsigned long num; vchar_t *val; struct remoteconf *rmconf; struct sockaddr *saddr; struct sainfoalg *alg; -} -/* Line 1489 of yacc.c. */ -#line 385 "cfparse.h" - YYSTYPE; + + + +/* Line 1676 of yacc.c */ +#line 408 "cfparse.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; + diff --git a/src/racoon/cfparse.y b/src/racoon/cfparse.y index 540c400..12920d8 100644 --- a/src/racoon/cfparse.y +++ b/src/racoon/cfparse.y @@ -1,4 +1,4 @@ -/* $NetBSD: cfparse.y,v 1.18.4.7 2008/07/21 20:45:32 tteras Exp $ */ +/* $NetBSD: cfparse.y,v 1.42 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: cfparse.y,v 1.66 2006/08/22 18:17:17 manubsd Exp */ @@ -94,14 +94,7 @@ #endif #include "vendorid.h" #include "rsalist.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; -}; +#include "crypto_openssl.h" struct secprotospec { int prop_no; @@ -120,7 +113,6 @@ struct secprotospec { struct secprotospec *next; /* the tail is the most prefiered. */ struct secprotospec *prev; - struct proposalspec *back; }; static int num2dhgroup[] = { @@ -151,24 +143,35 @@ static struct sainfo *cur_sainfo; static int cur_algclass; static int oldloglevel = LLV_BASE; -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 insspspec __P((struct remoteconf *, struct secprotospec *)); +void dupspspec_list __P((struct remoteconf *dst, struct remoteconf *src)); +void flushspspec __P((struct remoteconf *)); static void adminsock_conf __P((vchar_t *, vchar_t *, vchar_t *, int)); -static int set_isakmp_proposal - __P((struct remoteconf *, struct proposalspec *)); +static int set_isakmp_proposal __P((struct remoteconf *)); 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 +static int load_x509(const char *file, char **filenameptr, + vchar_t **certptr) +{ + char path[PATH_MAX]; + + getpathname(path, sizeof(path), LC_PATHTYPE_CERT, file); + *certptr = eay_get_x509cert(path); + if (*certptr == NULL) + return -1; + + *filenameptr = racoon_strdup(file); + STRDUP_FATAL(*filenameptr); + + return 0; +} + %} %union { @@ -185,8 +188,8 @@ static int fix_lifebyte __P((u_long)); %token PATH PATHTYPE /* include */ %token INCLUDE - /* self information */ -%token IDENTIFIER VENDORID + /* PFKEY_BUFFER */ +%token PFKEY_BUFFER /* logging */ %token LOGGING LOGLEV /* padding */ @@ -196,6 +199,8 @@ static int fix_lifebyte __P((u_long)); /* ldap config */ %token LDAPCFG LDAP_HOST LDAP_PORT LDAP_PVER LDAP_BASE LDAP_BIND_DN LDAP_BIND_PW LDAP_SUBTREE %token LDAP_ATTR_USER LDAP_ATTR_ADDR LDAP_ATTR_MASK LDAP_ATTR_GROUP LDAP_ATTR_MEMBER + /* radius config */ +%token RADCFG RAD_AUTH RAD_ACCT RAD_TIMEOUT RAD_RETRIES /* modecfg */ %token MODECFG CFG_NET4 CFG_MASK4 CFG_DNS4 CFG_NBNS4 CFG_DEFAULT_DOMAIN %token CFG_AUTH_SOURCE CFG_AUTH_GROUPS CFG_SYSTEM CFG_RADIUS CFG_PAM CFG_LDAP CFG_LOCAL CFG_NONE @@ -211,10 +216,10 @@ static int fix_lifebyte __P((u_long)); /* sainfo */ %token SAINFO FROM /* remote */ -%token REMOTE ANONYMOUS INHERIT +%token REMOTE ANONYMOUS CLIENTADDR INHERIT REMOTE_ADDRESS %token EXCHANGE_MODE EXCHANGETYPE DOI DOITYPE SITUATION SITUATIONTYPE %token CERTIFICATE_TYPE CERTTYPE PEERS_CERTFILE CA_TYPE -%token VERIFY_CERT SEND_CERT SEND_CR +%token VERIFY_CERT SEND_CERT SEND_CR MATCH_EMPTY_CR %token IDENTIFIERTYPE IDENTIFIERQUAL MY_IDENTIFIER %token PEERS_IDENTIFIER VERIFY_IDENTIFIER %token DNSSEC CERT_X509 CERT_PLAINRSA @@ -229,11 +234,12 @@ static int fix_lifebyte __P((u_long)); %token DPD DPD_DELAY DPD_RETRY DPD_MAXFAIL %token PH1ID %token XAUTH_LOGIN WEAK_PHASE1_CHECK +%token REKEY %token PREFIX PORT PORTANY UL_PROTO ANY IKE_FRAG ESP_FRAG MODE_CFG %token PFS_GROUP LIFETIME LIFETYPE_TIME LIFETYPE_BYTE STRENGTH REMOTEID -%token SCRIPT PHASE1_UP PHASE1_DOWN +%token SCRIPT PHASE1_UP PHASE1_DOWN PHASE1_DEAD %token NUMBER SWITCH BOOLEAN %token HEXSTRING QUOTEDSTRING ADDRSTRING ADDRRANGE @@ -265,12 +271,13 @@ statement : privsep_statement | path_statement | include_statement + | pfkey_statement | gssenc_statement - | identifier_statement | logging_statement | padding_statement | listen_statement | ldapcfg_statement + | radcfg_statement | modecfg_statement | timer_statement | sainfo_statement @@ -354,6 +361,13 @@ include_statement } ; + /* pfkey_buffer */ +pfkey_statement + : PFKEY_BUFFER NUMBER EOS + { + lcconf->pfkey_buffer_size = $2; + } + ; /* gss_id_enc */ gssenc_statement : GSS_ID_ENC GSS_ID_ENCTYPE EOS @@ -366,45 +380,12 @@ gssenc_statement } ; - /* self information */ -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 + : LOGLEV { /* * set the loglevel to the value specified @@ -443,23 +424,21 @@ listen_stmts listen_stmt : X_ISAKMP ike_addrinfo_port { - listen_addr ($2, 0); + myaddr_listen($2, FALSE); + racoon_free($2); } EOS | X_ISAKMP_NATT ike_addrinfo_port { #ifdef ENABLE_NATT - listen_addr ($2, 1); + myaddr_listen($2, TRUE); + racoon_free($2); #else + racoon_free($2); 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 @@ -506,6 +485,122 @@ ike_port | PORT { $$ = $1; } ; + /* radius configuration */ +radcfg_statement + : RADCFG { +#ifndef ENABLE_HYBRID + yyerror("racoon not configured with --enable-hybrid"); + return -1; +#endif +#ifndef HAVE_LIBRADIUS + yyerror("racoon not configured with --with-libradius"); + return -1; +#endif +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + xauth_rad_config.timeout = 3; + xauth_rad_config.retries = 3; +#endif +#endif + } BOC radcfg_stmts EOC + ; +radcfg_stmts + : /* nothing */ + | radcfg_stmts radcfg_stmt + ; +radcfg_stmt + : RAD_AUTH QUOTEDSTRING QUOTEDSTRING + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + int i = xauth_rad_config.auth_server_count; + if (i == RADIUS_MAX_SERVERS) { + yyerror("maximum radius auth servers exceeded"); + return -1; + } + + xauth_rad_config.auth_server_list[i].host = vdup($2); + xauth_rad_config.auth_server_list[i].secret = vdup($3); + xauth_rad_config.auth_server_list[i].port = 0; // default port + xauth_rad_config.auth_server_count++; +#endif +#endif + } + EOS + | RAD_AUTH QUOTEDSTRING NUMBER QUOTEDSTRING + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + int i = xauth_rad_config.auth_server_count; + if (i == RADIUS_MAX_SERVERS) { + yyerror("maximum radius auth servers exceeded"); + return -1; + } + + xauth_rad_config.auth_server_list[i].host = vdup($2); + xauth_rad_config.auth_server_list[i].secret = vdup($4); + xauth_rad_config.auth_server_list[i].port = $3; + xauth_rad_config.auth_server_count++; +#endif +#endif + } + EOS + | RAD_ACCT QUOTEDSTRING QUOTEDSTRING + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + int i = xauth_rad_config.acct_server_count; + if (i == RADIUS_MAX_SERVERS) { + yyerror("maximum radius account servers exceeded"); + return -1; + } + + xauth_rad_config.acct_server_list[i].host = vdup($2); + xauth_rad_config.acct_server_list[i].secret = vdup($3); + xauth_rad_config.acct_server_list[i].port = 0; // default port + xauth_rad_config.acct_server_count++; +#endif +#endif + } + EOS + | RAD_ACCT QUOTEDSTRING NUMBER QUOTEDSTRING + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + int i = xauth_rad_config.acct_server_count; + if (i == RADIUS_MAX_SERVERS) { + yyerror("maximum radius account servers exceeded"); + return -1; + } + + xauth_rad_config.acct_server_list[i].host = vdup($2); + xauth_rad_config.acct_server_list[i].secret = vdup($4); + xauth_rad_config.acct_server_list[i].port = $3; + xauth_rad_config.acct_server_count++; +#endif +#endif + } + EOS + | RAD_TIMEOUT NUMBER + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + xauth_rad_config.timeout = $2; +#endif +#endif + } + EOS + | RAD_RETRIES NUMBER + { +#ifdef ENABLE_HYBRID +#ifdef HAVE_LIBRADIUS + xauth_rad_config.retries = $2; +#endif +#endif + } + EOS + ; + /* ldap configuration */ ldapcfg_statement : LDAPCFG { @@ -1015,12 +1110,16 @@ authgroup grouplist = racoon_realloc(icc->grouplist, sizeof(char**)*(icc->groupcount+1)); - if (grouplist == NULL) + if (grouplist == NULL) { yyerror("unable to allocate auth group list"); + return -1; + } groupname = racoon_malloc($1->l+1); - if (groupname == NULL) + if (groupname == NULL) { yyerror("unable to allocate auth group name"); + return -1; + } memcpy(groupname,$1->v,$1->l); groupname[$1->l]=0; @@ -1048,8 +1147,10 @@ splitdns if (!icc->splitdns_len) { icc->splitdns_list = racoon_malloc($1->l); - if(icc->splitdns_list == NULL) + if(icc->splitdns_list == NULL) { yyerror("error allocating splitdns list buffer"); + return -1; + } memcpy(icc->splitdns_list,$1->v,$1->l); icc->splitdns_len = $1->l; } @@ -1057,8 +1158,10 @@ splitdns { int len = icc->splitdns_len + $1->l + 1; icc->splitdns_list = racoon_realloc(icc->splitdns_list,len); - if(icc->splitdns_list == NULL) + if(icc->splitdns_list == NULL) { yyerror("error allocating splitdns list buffer"); + return -1; + } icc->splitdns_list[icc->splitdns_len] = ','; memcpy(icc->splitdns_list + icc->splitdns_len + 1, $1->v, $1->l); icc->splitdns_len = len; @@ -1154,12 +1257,16 @@ sainfo_statement check = getsainfo(cur_sainfo->idsrc, cur_sainfo->iddst, cur_sainfo->id_i, + NULL, cur_sainfo->remoteid); - if (check && (!check->idsrc && !cur_sainfo->idsrc)) { + + if (check && ((check->idsrc != SAINFO_ANONYMOUS) && + (cur_sainfo->idsrc != SAINFO_ANONYMOUS))) { yyerror("duplicated sainfo: %s", sainfo2str(cur_sainfo)); return -1; } + inssainfo(cur_sainfo); } EOC @@ -1167,18 +1274,28 @@ sainfo_statement sainfo_name : ANONYMOUS { - cur_sainfo->idsrc = NULL; - cur_sainfo->iddst = NULL; + cur_sainfo->idsrc = SAINFO_ANONYMOUS; + cur_sainfo->iddst = SAINFO_ANONYMOUS; + } + | ANONYMOUS CLIENTADDR + { + cur_sainfo->idsrc = SAINFO_ANONYMOUS; + cur_sainfo->iddst = SAINFO_CLIENTADDR; } | ANONYMOUS sainfo_id { - cur_sainfo->idsrc = NULL; + cur_sainfo->idsrc = SAINFO_ANONYMOUS; cur_sainfo->iddst = $2; } | sainfo_id ANONYMOUS { cur_sainfo->idsrc = $1; - cur_sainfo->iddst = NULL; + cur_sainfo->iddst = SAINFO_ANONYMOUS; + } + | sainfo_id CLIENTADDR + { + cur_sainfo->idsrc = $1; + cur_sainfo->iddst = SAINFO_CLIENTADDR; } | sainfo_id sainfo_id { @@ -1407,16 +1524,6 @@ sainfo_spec 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 @@ -1507,51 +1614,91 @@ keylength /* remote */ remote_statement - : REMOTE remote_index INHERIT remote_index + : REMOTE QUOTEDSTRING INHERIT QUOTEDSTRING { - struct remoteconf *new; - struct proposalspec *prspec; + struct remoteconf *from, *new; - new = copyrmconf($4); + if (getrmconf_by_name($2->v) != NULL) { + yyerror("named remoteconf \"%s\" already exists."); + return -1; + } + + from = getrmconf_by_name($4->v); + if (from == NULL) { + yyerror("named parent remoteconf \"%s\" does not exist.", + $4->v); + return -1; + } + + new = duprmconf_shallow(from); if (new == NULL) { - yyerror("failed to get remoteconf for %s.", saddr2str ($4)); + yyerror("failed to duplicate remoteconf from \"%s\".", + $4->v); return -1; } - new->remote = $2; - new->inherited_from = getrmconf_strict($4, 1); - new->proposal = NULL; - new->prhead = NULL; + new->name = racoon_strdup($2->v); 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); + vfree($2); + vfree($4); } remote_specs_block - | REMOTE remote_index + | REMOTE QUOTEDSTRING { struct remoteconf *new; - struct proposalspec *prspec; + + if (getrmconf_by_name($2->v) != NULL) { + yyerror("Named remoteconf \"%s\" already exists."); + return -1; + } new = newrmconf(); if (new == NULL) { yyerror("failed to get new remoteconf."); return -1; } + new->name = racoon_strdup($2->v); + cur_rmconf = new; + + vfree($2); + } + remote_specs_block + | REMOTE remote_index INHERIT remote_index + { + struct remoteconf *from, *new; + + from = getrmconf($4, GETRMCONF_F_NO_ANONYMOUS); + if (from == NULL) { + yyerror("failed to get remoteconf for %s.", + saddr2str($4)); + return -1; + } + new = duprmconf_shallow(from); + if (new == NULL) { + yyerror("failed to duplicate remoteconf from %s.", + saddr2str($4)); + return -1; + } + + racoon_free($4); new->remote = $2; cur_rmconf = new; + } + remote_specs_block + | REMOTE remote_index + { + struct remoteconf *new; - prspec = newprspec(); - if (prspec == NULL) + new = newrmconf(); + if (new == NULL) { + yyerror("failed to get new remoteconf."); return -1; - prspec->lifetime = oakley_get_defaultlifetime(); - insprspec(prspec, &cur_rmconf->prhead); + } + + new->remote = $2; + cur_rmconf = new; } remote_specs_block ; @@ -1568,7 +1715,6 @@ remote_specs_block if (cur_rmconf->idvtype == IDTYPE_UNDEFINED) cur_rmconf->idvtype = IDTYPE_ADDRESS; - if (cur_rmconf->idvtype == IDTYPE_ASN1DN) { if (cur_rmconf->mycertfile) { if (cur_rmconf->idv) @@ -1583,17 +1729,24 @@ remote_specs_block return -1; } } - - 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 (duprmconf_finish(cur_rmconf)) + return -1; + +#if 0 + /* this pointer copy will never happen, because duprmconf_shallow + * already copied all pointers. + */ + if (cur_rmconf->spspec == NULL && + cur_rmconf->inherited_from != NULL) { + cur_rmconf->spspec = cur_rmconf->inherited_from->spspec; } - if (set_isakmp_proposal(cur_rmconf, cur_rmconf->prhead) != 0) +#endif + if (set_isakmp_proposal(cur_rmconf) != 0) return -1; /* DH group settting if aggressive mode is there. */ - if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) { + if (check_etypeok(cur_rmconf, (void*) ISAKMP_ETYPE_AGG)) { struct isakmpsa *p; int b = 0; @@ -1648,7 +1801,16 @@ remote_specs | remote_specs remote_spec ; remote_spec - : EXCHANGE_MODE + : REMOTE_ADDRESS ike_addrinfo_port + { + if (cur_rmconf->remote != NULL) { + yyerror("remote_address already specified"); + return -1; + } + cur_rmconf->remote = $2; + } + EOS + | EXCHANGE_MODE { cur_rmconf->etypes = NULL; } @@ -1660,33 +1822,36 @@ remote_spec { 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; - if (cur_rmconf->peerscertfile != NULL) - racoon_free(cur_rmconf->peerscertfile); - cur_rmconf->peerscertfile = racoon_strdup($2->v); - STRDUP_FATAL(cur_rmconf->peerscertfile); + if (cur_rmconf->peerscert != NULL) { + yyerror("peers_certfile already defined\n"); + return -1; + } + + if (load_x509($2->v, &cur_rmconf->peerscertfile, + &cur_rmconf->peerscert)) { + yyerror("failed to load certificate \"%s\"\n", + $2->v); + return -1; + } + vfree($2); } EOS - | CA_TYPE CERT_X509 QUOTEDSTRING - { - cur_rmconf->cacerttype = $2; - cur_rmconf->getcacert_method = ISAKMP_GETCERT_LOCALFILE; - if (cur_rmconf->cacertfile != NULL) - racoon_free(cur_rmconf->cacertfile); - cur_rmconf->cacertfile = racoon_strdup($3->v); - STRDUP_FATAL(cur_rmconf->cacertfile); - vfree($3); - } - EOS | PEERS_CERTFILE CERT_X509 QUOTEDSTRING { - cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; - if (cur_rmconf->peerscertfile != NULL) - racoon_free(cur_rmconf->peerscertfile); - cur_rmconf->peerscertfile = racoon_strdup($3->v); - STRDUP_FATAL(cur_rmconf->peerscertfile); + if (cur_rmconf->peerscert != NULL) { + yyerror("peers_certfile already defined\n"); + return -1; + } + + if (load_x509($3->v, &cur_rmconf->peerscertfile, + &cur_rmconf->peerscert)) { + yyerror("failed to load certificate \"%s\"\n", + $3->v); + return -1; + } + vfree($3); } EOS @@ -1695,37 +1860,66 @@ remote_spec char path[MAXPATHLEN]; int ret = 0; - getpathname(path, sizeof(path), - LC_PATHTYPE_CERT, $3->v); - vfree($3); + if (cur_rmconf->peerscert != NULL) { + yyerror("peers_certfile already defined\n"); + return -1; + } - if (cur_rmconf->getcert_method == ISAKMP_GETCERT_DNS) { - yyerror("Different peers_certfile method " - "already defined: %d!\n", - cur_rmconf->getcert_method); + cur_rmconf->peerscert = vmalloc(1); + if (cur_rmconf->peerscert == NULL) { + yyerror("failed to allocate peerscert"); return -1; } - cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; - if (rsa_parse_file(cur_rmconf->rsa_public, path, RSA_TYPE_PUBLIC)) { + cur_rmconf->peerscert->v[0] = ISAKMP_CERT_PLAINRSA; + + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, $3->v); + 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); + plog(LLV_DEBUG, LOCATION, NULL, + "Public PlainRSA keyfile parsed: %s\n", path); + + vfree($3); } EOS | PEERS_CERTFILE DNSSEC { - if (cur_rmconf->getcert_method) { - yyerror("Different peers_certfile method already defined!\n"); + if (cur_rmconf->peerscert != NULL) { + yyerror("peers_certfile already defined\n"); return -1; } - cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS; - cur_rmconf->peerscertfile = NULL; + cur_rmconf->peerscert = vmalloc(1); + if (cur_rmconf->peerscert == NULL) { + yyerror("failed to allocate peerscert"); + return -1; + } + cur_rmconf->peerscert->v[0] = ISAKMP_CERT_DNS; + } + EOS + | CA_TYPE CERT_X509 QUOTEDSTRING + { + if (cur_rmconf->cacert != NULL) { + yyerror("ca_type already defined\n"); + return -1; + } + + if (load_x509($3->v, &cur_rmconf->cacertfile, + &cur_rmconf->cacert)) { + yyerror("failed to load certificate \"%s\"\n", + $3->v); + return -1; + } + + vfree($3); } 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 + | MATCH_EMPTY_CR SWITCH { cur_rmconf->match_empty_cr = $2; } EOS | MY_IDENTIFIER IDENTIFIERTYPE identifierstring { if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) { @@ -1830,6 +2024,13 @@ remote_spec cur_rmconf->script[SCRIPT_PHASE1_DOWN] = script_path_add(vdup($2)); } EOS + | SCRIPT QUOTEDSTRING PHASE1_DEAD { + if (cur_rmconf->script[SCRIPT_PHASE1_DEAD] != NULL) + vfree(cur_rmconf->script[SCRIPT_PHASE1_DEAD]); + + cur_rmconf->script[SCRIPT_PHASE1_DEAD] = + script_path_add(vdup($2)); + } EOS | MODE_CFG SWITCH { cur_rmconf->mode_cfg = $2; } EOS | WEAK_PHASE1_CHECK SWITCH { cur_rmconf->weak_phase1_check = $2; @@ -1895,6 +2096,8 @@ remote_spec #endif } EOS + | REKEY SWITCH { cur_rmconf->rekey = $2; } EOS + | REKEY REMOTE_FORCE_LEVEL { cur_rmconf->rekey = REKEY_FORCE; } EOS | PH1ID NUMBER { cur_rmconf->ph1id = $2; @@ -1902,7 +2105,7 @@ remote_spec EOS | LIFETIME LIFETYPE_TIME NUMBER unittype_time { - cur_rmconf->prhead->lifetime = $3 * $4; + cur_rmconf->lifetime = $3 * $4; } EOS | PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS @@ -1914,8 +2117,8 @@ remote_spec #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) + cur_rmconf->lifebyte = fix_lifebyte($3 * $4); + if (cur_rmconf->lifebyte == 0) return -1; #endif } @@ -1927,7 +2130,7 @@ remote_spec spspec = newspspec(); if (spspec == NULL) return -1; - insspspec(spspec, &cur_rmconf->prhead); + insspspec(cur_rmconf, spspec); } BOC isakmpproposal_specs EOC ; @@ -1958,16 +2161,22 @@ exchange_types cert_spec : CERT_X509 QUOTEDSTRING QUOTEDSTRING { - cur_rmconf->certtype = $1; - if (cur_rmconf->mycertfile != NULL) - racoon_free(cur_rmconf->mycertfile); - cur_rmconf->mycertfile = racoon_strdup($2->v); - STRDUP_FATAL(cur_rmconf->mycertfile); - vfree($2); - if (cur_rmconf->myprivfile != NULL) - racoon_free(cur_rmconf->myprivfile); + if (cur_rmconf->mycert != NULL) { + yyerror("certificate_type already defined\n"); + return -1; + } + + if (load_x509($2->v, &cur_rmconf->mycertfile, + &cur_rmconf->mycert)) { + yyerror("failed to load certificate \"%s\"\n", + $2->v); + return -1; + } + cur_rmconf->myprivfile = racoon_strdup($3->v); STRDUP_FATAL(cur_rmconf->myprivfile); + + vfree($2); vfree($3); } EOS @@ -1976,19 +2185,31 @@ cert_spec char path[MAXPATHLEN]; int ret = 0; - getpathname(path, sizeof(path), - LC_PATHTYPE_CERT, $2->v); - vfree($2); + if (cur_rmconf->mycert != NULL) { + yyerror("certificate_type already defined\n"); + return -1; + } + + cur_rmconf->mycert = vmalloc(1); + if (cur_rmconf->mycert == NULL) { + yyerror("failed to allocate mycert"); + return -1; + } + cur_rmconf->mycert->v[0] = ISAKMP_CERT_PLAINRSA; - cur_rmconf->certtype = $1; + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, $2->v); 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)) { + 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); + plog(LLV_DEBUG, LOCATION, NULL, + "Private PlainRSA keyfile parsed: %s\n", path); + vfree($2); } EOS ; @@ -2022,13 +2243,9 @@ isakmpproposal_specs | isakmpproposal_specs isakmpproposal_spec ; isakmpproposal_spec - : STRENGTH + : LIFETIME LIFETYPE_TIME NUMBER unittype_time { - yyerror("strength directive is obsoleted."); - } STRENGTHTYPE EOS - | LIFETIME LIFETYPE_TIME NUMBER unittype_time - { - cur_rmconf->prhead->spspec->lifetime = $3 * $4; + cur_rmconf->spspec->lifetime = $3 * $4; } EOS | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte @@ -2037,28 +2254,28 @@ isakmpproposal_spec 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) + cur_rmconf->spspec->lifebyte = fix_lifebyte($3 * $4); + if (cur_rmconf->spspec->lifebyte == 0) return -1; #endif } EOS | DH_GROUP dh_group_num { - cur_rmconf->prhead->spspec->algclass[algclass_isakmp_dh] = $2; + cur_rmconf->spspec->algclass[algclass_isakmp_dh] = $2; } EOS | GSS_ID QUOTEDSTRING { - if (cur_rmconf->prhead->spspec->vendorid != VENDORID_GSSAPI) { + if (cur_rmconf->spspec->vendorid != VENDORID_GSSAPI) { yyerror("wrong Vendor ID for gssapi_id"); return -1; } - if (cur_rmconf->prhead->spspec->gssid != NULL) - racoon_free(cur_rmconf->prhead->spspec->gssid); - cur_rmconf->prhead->spspec->gssid = + if (cur_rmconf->spspec->gssid != NULL) + racoon_free(cur_rmconf->spspec->gssid); + cur_rmconf->spspec->gssid = racoon_strdup($2->v); - STRDUP_FATAL(cur_rmconf->prhead->spspec->gssid); + STRDUP_FATAL(cur_rmconf->spspec->gssid); } EOS | ALGORITHM_CLASS ALGORITHMTYPE keylength @@ -2090,7 +2307,7 @@ isakmpproposal_spec } #endif - cur_rmconf->prhead->spspec->algclass[algclass_isakmp_enc] = doi; + cur_rmconf->spspec->algclass[algclass_isakmp_enc] = doi; defklen = default_keylen($1, $2); if (defklen == 0) { if ($3) { @@ -2104,22 +2321,22 @@ isakmpproposal_spec } } if ($3) - cur_rmconf->prhead->spspec->encklen = $3; + cur_rmconf->spspec->encklen = $3; else - cur_rmconf->prhead->spspec->encklen = defklen; + cur_rmconf->spspec->encklen = defklen; break; case algclass_isakmp_hash: - cur_rmconf->prhead->spspec->algclass[algclass_isakmp_hash] = doi; + cur_rmconf->spspec->algclass[algclass_isakmp_hash] = doi; break; case algclass_isakmp_ameth: - cur_rmconf->prhead->spspec->algclass[algclass_isakmp_ameth] = doi; + cur_rmconf->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 != + if (cur_rmconf->spspec->vendorid != VENDORID_UNKNOWN) { yyerror("Vendor ID mismatch " "for auth method"); @@ -2129,19 +2346,19 @@ isakmpproposal_spec * For interoperability with Win2k, * we set the Vendor ID to "GSSAPI". */ - cur_rmconf->prhead->spspec->vendorid = + cur_rmconf->spspec->vendorid = VENDORID_GSSAPI; break; case algtype_rsasig: - if (cur_rmconf->certtype == ISAKMP_CERT_PLAINRSA) { + if (oakley_get_certtype(cur_rmconf->peerscert) == ISAKMP_CERT_PLAINRSA) { if (rsa_list_count(cur_rmconf->rsa_private) == 0) { yyerror ("Private PlainRSA key not set. " - "Use directive 'certificate_type plainrsa ...'\n"); + "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"); + "Use directive 'peers_certfile plainrsa ...'\n"); return -1; } } @@ -2171,32 +2388,6 @@ unittype_byte ; %% -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() { @@ -2224,44 +2415,113 @@ newspspec() * insert into head of list. */ static void -insspspec(spspec, head) +insspspec(rmconf, spspec) + struct remoteconf *rmconf; + struct secprotospec *spspec; +{ + if (rmconf->spspec != NULL) + rmconf->spspec->prev = spspec; + spspec->next = rmconf->spspec; + rmconf->spspec = spspec; +} + +static struct secprotospec * +dupspspec(spspec) struct secprotospec *spspec; - struct proposalspec **head; { - spspec->back = *head; + struct secprotospec *new; + + new = newspspec(); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "dupspspec: malloc failed\n"); + return NULL; + } + memcpy(new, spspec, sizeof(*new)); + + if (spspec->gssid) { + new->gssid = racoon_strdup(spspec->gssid); + STRDUP_FATAL(new->gssid); + } + if (spspec->remote) { + new->remote = racoon_malloc(sizeof(*new->remote)); + if (new->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "dupspspec: malloc failed (remote)\n"); + return NULL; + } + memcpy(new->remote, spspec->remote, sizeof(*new->remote)); + } - if ((*head)->spspec != NULL) - (*head)->spspec->prev = spspec; - spspec->next = (*head)->spspec; - (*head)->spspec = spspec; + return new; +} + +/* + * copy the whole list + */ +void +dupspspec_list(dst, src) + struct remoteconf *dst, *src; +{ + struct secprotospec *p, *new, *last; + + for(p = src->spspec, last = NULL; p; p = p->next, last = new) { + new = dupspspec(p); + if (new == NULL) + exit(1); + + new->prev = last; + new->next = NULL; /* not necessary but clean */ + + if (last) + last->next = new; + else /* first element */ + dst->spspec = new; + + } +} + +/* + * delete the whole list + */ +void +flushspspec(rmconf) + struct remoteconf *rmconf; +{ + struct secprotospec *p; + + while(rmconf->spspec != NULL) { + p = rmconf->spspec; + rmconf->spspec = p->next; + if (p->next != NULL) + p->next->prev = NULL; /* not necessary but clean */ + + if (p->gssid) + racoon_free(p->gssid); + if (p->remote) + racoon_free(p->remote); + racoon_free(p); + } + rmconf->spspec = NULL; } /* set final acceptable proposal */ static int -set_isakmp_proposal(rmconf, prspec) +set_isakmp_proposal(rmconf) 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) { + if (rmconf->spspec == NULL) { yyerror("no remote specification found: %s.\n", saddr2str(rmconf->remote)); return -1; } - for (s = p->spspec; s != NULL; s = s->next) { + for (s = rmconf->spspec; s != NULL; s = s->next) { /* XXX need more to check */ if (s->algclass[algclass_isakmp_enc] == 0) { yyerror("encryption algorithm required."); @@ -2282,16 +2542,16 @@ set_isakmp_proposal(rmconf, prspec) } /* skip to last part */ - for (s = p->spspec; s->next != NULL; s = s->next) + for (s = rmconf->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)); + (s->lifetime ? s->lifetime : rmconf->lifetime)); plog(LLV_DEBUG2, LOCATION, NULL, "lifebyte = %d\n", - s->lifebyte ? s->lifebyte : p->lifebyte); + s->lifebyte ? s->lifebyte : rmconf->lifebyte); plog(LLV_DEBUG2, LOCATION, NULL, "encklen=%d\n", s->encklen); @@ -2306,8 +2566,8 @@ set_isakmp_proposal(rmconf, prspec) 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->lifetime ? s->lifetime : rmconf->lifetime, + s->lifebyte ? s->lifebyte : rmconf->lifebyte, s->encklen, s->vendorid, s->gssid, rmconf); if (trns_no == -1) { @@ -2412,11 +2672,7 @@ expand_isakmpspec(prop_no, trns_no, types, } memcpy(new->gssid->v, gssid, new->gssid->l); racoon_free(gssid); -#ifdef ENABLE_HYBRID - } else if (rmconf->xauth == NULL) { -#else } else { -#endif /* * Allocate the default ID so that it gets put * into a GSS ID attribute during the Phase 1 @@ -2431,30 +2687,6 @@ expand_isakmpspec(prop_no, trns_no, types, 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; - - insmyaddr(p, &lcconf->myaddrs); - - lcconf->autograbaddr = 0; - return 0; -} - #if 0 /* * fix lifebyte. @@ -2479,6 +2711,7 @@ cfparse() { int error; + yyerrorcount = 0; yycf_init_buffer(); if (yycf_switch_buffer(lcconf->racoon_conf) != 0) { diff --git a/src/racoon/cftoken.l b/src/racoon/cftoken.l index 9950d49..3042796 100644 --- a/src/racoon/cftoken.l +++ b/src/racoon/cftoken.l @@ -1,4 +1,4 @@ -/* $NetBSD: cftoken.l,v 1.11.4.2 2007/09/03 18:07:29 mgrooms Exp $ */ +/* $NetBSD: cftoken.l,v 1.23 2011/02/02 15:21:34 vanhu Exp $ */ /* Id: cftoken.l,v 1.53 2006/08/22 18:17:17 manubsd Exp */ @@ -132,7 +132,7 @@ 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_LDAP +%s S_INI S_PRIV S_PTH S_LOG S_PAD S_LST S_RTRY S_CFG S_LDAP S_RAD %s S_ALGST S_ALGCL %s S_SAINF S_SAINFS %s S_RMT S_RMTS S_RMTP @@ -174,9 +174,8 @@ hexstring 0x{hexdigit}+ /* include */ <S_INI>include { YYDB; return(INCLUDE); } - /* self information */ -<S_INI>identifier { BEGIN S_INF; YYDB; yywarn("it is obsoleted. use \"my_identifier\" in each remote directives."); return(IDENTIFIER); } -<S_INF>{semi} { BEGIN S_INI; return(EOS); } + /* pfkey_buffer */ +<S_INI>pfkey_buffer { YYDB; return(PFKEY_BUFFER); } /* special */ <S_INI>complex_bundle { YYDB; return(COMPLEX_BUNDLE); } @@ -189,8 +188,6 @@ hexstring 0x{hexdigit}+ <S_LOG>info { YYD; yylval.num = LLV_INFO; return(LOGLEV); } <S_LOG>debug { YYD; yylval.num = LLV_DEBUG; return(LOGLEV); } <S_LOG>debug2 { YYD; yylval.num = LLV_DEBUG2; return(LOGLEV); } -<S_LOG>debug3 { YYD; yywarn("it is obsoleted. use \"debug2\""); yylval.num = LLV_DEBUG2; return(LOGLEV); } -<S_LOG>debug4 { YYD; yywarn("it is obsoleted. use \"debug2\""); yylval.num = LLV_DEBUG2; return(LOGLEV); } <S_LOG>{semi} { BEGIN S_INI; return(EOS); } /* padding */ @@ -214,6 +211,15 @@ hexstring 0x{hexdigit}+ <S_LST>strict_address { YYD; return(STRICT_ADDRESS); } <S_LST>{ecl} { BEGIN S_INI; return(EOC); } + /* radius config */ +<S_INI>radiuscfg { BEGIN S_RAD; YYDB; return(RADCFG); } +<S_RAD>{bcl} { return(BOC); } +<S_RAD>auth { YYD; return(RAD_AUTH); } +<S_RAD>acct { YYD; return(RAD_ACCT); } +<S_RAD>timeout { YYD; return(RAD_TIMEOUT); } +<S_RAD>retries { YYD; return(RAD_RETRIES); } +<S_RAD>{ecl} { BEGIN S_INI; return(EOC); } + /* ldap config */ <S_INI>ldapcfg { BEGIN S_LDAP; YYDB; return(LDAPCFG); } <S_LDAP>{bcl} { return(BOC); } @@ -277,6 +283,7 @@ hexstring 0x{hexdigit}+ /* sainfo */ <S_INI>sainfo { BEGIN S_SAINF; YYDB; return(SAINFO); } <S_SAINF>anonymous { YYD; return(ANONYMOUS); } +<S_SAINF>clientaddr { YYD; return(CLIENTADDR); } <S_SAINF>{blcl}any{elcl} { YYD; return(PORTANY); } <S_SAINF>any { YYD; return(ANY); } <S_SAINF>from { YYD; return(FROM); } @@ -287,7 +294,6 @@ hexstring 0x{hexdigit}+ <S_SAINFS>{ecl} { BEGIN S_INI; return(EOC); } <S_SAINFS>pfs_group { YYD; return(PFS_GROUP); } <S_SAINFS>remoteid { YYD; return(REMOTEID); } -<S_SAINFS>identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } <S_SAINFS>my_identifier { YYD; return(MY_IDENTIFIER); } <S_SAINFS>lifetime { YYD; return(LIFETIME); } <S_SAINFS>time { YYD; return(LIFETYPE_TIME); } @@ -304,6 +310,7 @@ hexstring 0x{hexdigit}+ /* remote spec */ <S_RMT>{bcl} { BEGIN S_RMTS; return(BOC); } <S_RMTS>{ecl} { BEGIN S_INI; return(EOC); } +<S_RMTS>remote_address { YYD; return(REMOTE_ADDRESS); } <S_RMTS>exchange_mode { YYD; return(EXCHANGE_MODE); } <S_RMTS>{comma} { YYD; /* XXX ignored, but to be handled. */ ; } <S_RMTS>base { YYD; yylval.num = ISAKMP_ETYPE_BASE; return(EXCHANGETYPE); } @@ -315,7 +322,6 @@ hexstring 0x{hexdigit}+ <S_RMTS>identity_only { YYD; yylval.num = IPSECDOI_SIT_IDENTITY_ONLY; return(SITUATIONTYPE); } <S_RMTS>secrecy { YYD; yylval.num = IPSECDOI_SIT_SECRECY; return(SITUATIONTYPE); } <S_RMTS>integrity { YYD; yylval.num = IPSECDOI_SIT_INTEGRITY; return(SITUATIONTYPE); } -<S_RMTS>identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } <S_RMTS>my_identifier { YYD; return(MY_IDENTIFIER); } <S_RMTS>xauth_login { YYD; return(XAUTH_LOGIN); /* formerly identifier type login */ } <S_RMTS>peers_identifier { YYD; return(PEERS_IDENTIFIER); } @@ -329,12 +335,12 @@ hexstring 0x{hexdigit}+ <S_RMTS>verify_cert { YYD; return(VERIFY_CERT); } <S_RMTS>send_cert { YYD; return(SEND_CERT); } <S_RMTS>send_cr { YYD; return(SEND_CR); } +<S_RMTS>match_empty_cr { YYD; return(MATCH_EMPTY_CR); } <S_RMTS>dh_group { YYD; return(DH_GROUP); } <S_RMTS>nonce_size { YYD; return(NONCE_SIZE); } <S_RMTS>generate_policy { YYD; return(GENERATE_POLICY); } <S_RMTS>unique { YYD; yylval.num = GENERATE_POLICY_UNIQUE; return(GENERATE_LEVEL); } <S_RMTS>require { YYD; yylval.num = GENERATE_POLICY_REQUIRE; return(GENERATE_LEVEL); } -<S_RMTS>support_mip6 { YYD; yywarn("it is obsoleted. use \"support_proxy\"."); return(SUPPORT_PROXY); } <S_RMTS>support_proxy { YYD; return(SUPPORT_PROXY); } <S_RMTS>initial_contact { YYD; return(INITIAL_CONTACT); } <S_RMTS>nat_traversal { YYD; return(NAT_TRAVERSAL); } @@ -359,8 +365,10 @@ hexstring 0x{hexdigit}+ <S_RMTS>script { YYD; return(SCRIPT); } <S_RMTS>phase1_up { YYD; return(PHASE1_UP); } <S_RMTS>phase1_down { YYD; return(PHASE1_DOWN); } +<S_RMTS>phase1_dead { YYD; return(PHASE1_DEAD); } <S_RMTS>mode_cfg { YYD; return(MODE_CFG); } <S_RMTS>weak_phase1_check { YYD; return(WEAK_PHASE1_CHECK); } +<S_RMTS>rekey { YYD; return(REKEY); } /* remote proposal */ <S_RMTS>proposal { BEGIN S_RMTP; YYDB; return(PROPOSAL); } <S_RMTP>{bcl} { return(BOC); } @@ -427,6 +435,7 @@ 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); } +gre { YYD; yylval.num = IPPROTO_GRE; return(UL_PROTO); } /* algorithm type */ des_iv64 { YYD; yylval.num = algtype_des_iv64; return(ALGORITHMTYPE); } @@ -543,14 +552,12 @@ xauth_rsa_client { /* 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); } 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); } /* identifier qualifier */ tag { YYD; yylval.num = IDQUAL_TAG; return(IDENTIFIERQUAL); } @@ -573,7 +580,7 @@ no { YYD; yylval.num = FALSE; return(BOOLEAN); } char *bp; YYD; - yylval.num = strtol(yytext, &bp, 10); + yylval.num = strtoul(yytext, &bp, 10); return(NUMBER); } @@ -631,6 +638,10 @@ no { YYD; yylval.num = FALSE; return(BOOLEAN); } <<EOF>> { yy_delete_buffer(YY_CURRENT_BUFFER); + fclose (incstack[incstackp].fp); + incstack[incstackp].fp = NULL; + racoon_free(incstack[incstackp].path); + incstack[incstackp].path = NULL; incstackp--; nextfile: if (incstack[incstackp].matchon < diff --git a/src/racoon/crypto_openssl.c b/src/racoon/crypto_openssl.c index b6e4c0d..f8a4db9 100644 --- a/src/racoon/crypto_openssl.c +++ b/src/racoon/crypto_openssl.c @@ -1,4 +1,4 @@ -/* $NetBSD: crypto_openssl.c,v 1.11.6.6 2009/04/29 10:50:25 tteras Exp $ */ +/* $NetBSD: crypto_openssl.c,v 1.20 2010/10/20 13:40:02 tteras Exp $ */ /* Id: crypto_openssl.c,v 1.47 2006/05/06 20:42:09 manubsd Exp */ @@ -113,6 +113,7 @@ typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; #include "crypto_openssl.h" #include "debug.h" #include "gcmalloc.h" +#include "isakmp.h" /* * I hate to cast every parameter to des_xx into void *, but it is @@ -136,9 +137,9 @@ eay_str2asn1dn(str, len) int len; { X509_NAME *name; - char *buf; + char *buf, *dst; char *field, *value; - int i, j; + int i; vchar_t *ret = NULL; caddr_t p; @@ -154,15 +155,38 @@ eay_str2asn1dn(str, len) name = X509_NAME_new(); - field = &buf[0]; + dst = field = &buf[0]; value = NULL; for (i = 0; i < len; i++) { + if (buf[i] == '\\') { + /* Escape characters specified in RFC 2253 */ + if (i < len - 1 && + strchr("\\,=+<>#;", buf[i+1]) != NULL) { + *dst++ = buf[++i]; + continue; + } else if (i < len - 2) { + /* RFC 2253 hexpair character escape */ + long u; + char esc_str[3]; + char *endptr; + + esc_str[0] = buf[++i]; + esc_str[1] = buf[++i]; + esc_str[2] = '\0'; + u = strtol(esc_str, &endptr, 16); + if (*endptr != '\0' || u < 0 || u > 255) + goto err; + *dst++ = u; + continue; + } else + goto err; + } if (!value && buf[i] == '=') { - buf[i] = '\0'; - value = &buf[i + 1]; + *dst = '\0'; + dst = value = &buf[i + 1]; continue; } else if (buf[i] == ',' || buf[i] == '/') { - buf[i] = '\0'; + *dst = '\0'; plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n", field, value); @@ -179,16 +203,16 @@ eay_str2asn1dn(str, len) "%s\n", eay_strerror()); goto err; } - for (j = i + 1; j < len; j++) { - if (buf[j] != ' ') - break; - } - field = &buf[j]; + + while (i + 1 < len && buf[i + 1] == ' ') i++; + dst = field = &buf[i + 1]; value = NULL; continue; + } else { + *dst++ = buf[i]; } } - buf[len] = '\0'; + *dst = '\0'; plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n", field, value); @@ -638,7 +662,7 @@ cb_check_cert_remote(ok, ctx) } /* - * get a subjectAltName from X509 certificate. + * get a subjectName from X509 certificate. */ vchar_t * eay_get_x509asn1subjectname(cert) @@ -649,8 +673,6 @@ eay_get_x509asn1subjectname(cert) vchar_t *name = NULL; int len; - bp = (unsigned char *) cert->v; - x509 = mem2x509(cert); if (x509 == NULL) goto error; @@ -784,6 +806,46 @@ end: return error; } +/* + * get a issuerName from X509 certificate. + */ +vchar_t * +eay_get_x509asn1issuername(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + u_char *bp; + vchar_t *name = NULL; + int len; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto error; + + /* get the length of the name */ + len = i2d_X509_NAME(x509->cert_info->issuer, NULL); + name = vmalloc(len); + if (name == NULL) + goto error; + + /* get the name */ + bp = (unsigned char *) name->v; + len = i2d_X509_NAME(x509->cert_info->issuer, &bp); + + X509_free(x509); + + return name; + +error: + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); + + if (name != NULL) + vfree(name); + if (x509 != NULL) + X509_free(x509); + + return NULL; +} /* * decode a X509 certificate and make a readable text terminated '\n'. @@ -850,9 +912,9 @@ mem2x509(cert) { u_char *bp; - bp = (unsigned char *) cert->v; + bp = (unsigned char *) cert->v + 1; - x509 = d2i_X509(NULL, (void *)&bp, cert->l); + x509 = d2i_X509(NULL, (void *)&bp, cert->l - 1); } #else { @@ -862,7 +924,7 @@ mem2x509(cert) bio = BIO_new(BIO_s_mem()); if (bio == NULL) return NULL; - len = BIO_write(bio, cert->v, cert->l); + len = BIO_write(bio, cert->v + 1, cert->l - 1); if (len == -1) return NULL; x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); @@ -912,12 +974,13 @@ eay_get_x509cert(path) return NULL; len = i2d_X509(x509, NULL); - cert = vmalloc(len); + cert = vmalloc(len + 1); if (cert == NULL) { X509_free(x509); return NULL; } - bp = (unsigned char *) cert->v; + cert->v[0] = ISAKMP_CERT_X509SIGN; + bp = (unsigned char *) &cert->v[1]; error = i2d_X509(x509, &bp); X509_free(x509); @@ -943,17 +1006,12 @@ eay_check_x509sign(source, sig, cert) 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()); + x509 = mem2x509(cert); + if (x509 == NULL) return -1; - } evp = X509_get_pubkey(x509); if (! evp) { @@ -1807,6 +1865,42 @@ eay_hmac_init(key, md) return (caddr_t)c; } +static vchar_t *eay_hmac_one(key, data, type) + vchar_t *key, *data; + const EVP_MD *type; +{ + vchar_t *res; + + if ((res = vmalloc(EVP_MD_size(type))) == 0) + return NULL; + + if (!HMAC(type, (void *) key->v, key->l, + (void *) data->v, data->l, (void *) res->v, NULL)) { + vfree(res); + return NULL; + } + + return res; +} + +static vchar_t *eay_digest_one(data, type) + vchar_t *data; + const EVP_MD *type; +{ + vchar_t *res; + + if ((res = vmalloc(EVP_MD_size(type))) == 0) + return NULL; + + if (!EVP_Digest((void *) data->v, data->l, + (void *) res->v, NULL, type, NULL)) { + vfree(res); + return NULL; + } + + return res; +} + #ifdef WITH_SHA2 /* * HMAC SHA2-512 @@ -1815,14 +1909,7 @@ 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); + return eay_hmac_one(key, data, EVP_sha2_512()); } caddr_t @@ -1872,14 +1959,7 @@ 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); + return eay_hmac_one(key, data, EVP_sha2_384()); } caddr_t @@ -1929,14 +2009,7 @@ 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); + return eay_hmac_one(key, data, EVP_sha2_256()); } caddr_t @@ -1987,14 +2060,7 @@ 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); + return eay_hmac_one(key, data, EVP_sha1()); } caddr_t @@ -2044,14 +2110,7 @@ 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); + return eay_hmac_one(key, data, EVP_md5()); } caddr_t @@ -2137,14 +2196,7 @@ 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); + return eay_digest_one(data, EVP_sha512()); } int @@ -2197,14 +2249,7 @@ 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); + return eay_digest_one(data, EVP_sha2_384()); } int @@ -2257,14 +2302,7 @@ 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); + return eay_digest_one(data, EVP_sha2_256()); } int @@ -2316,14 +2354,7 @@ 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); + return eay_digest_one(data, EVP_sha1()); } int @@ -2374,14 +2405,7 @@ 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); + return eay_digest_one(data, EVP_md5()); } int diff --git a/src/racoon/crypto_openssl.h b/src/racoon/crypto_openssl.h index 9a17de8..66fac73 100644 --- a/src/racoon/crypto_openssl.h +++ b/src/racoon/crypto_openssl.h @@ -1,4 +1,4 @@ -/* $NetBSD: crypto_openssl.h,v 1.5 2006/10/06 12:02:27 manu Exp $ */ +/* $NetBSD: crypto_openssl.h,v 1.7 2009/08/17 11:59:10 vanhu Exp $ */ /* Id: crypto_openssl.h,v 1.11 2004/11/13 11:28:01 manubsd Exp */ @@ -34,8 +34,6 @@ #ifndef _CRYPTO_OPENSSL_H #define _CRYPTO_OPENSSL_H -#include "crypto_openssl.h" - #include <openssl/x509v3.h> #include <openssl/rsa.h> @@ -55,6 +53,7 @@ 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 *)); extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int)); +extern vchar_t * eay_get_x509asn1issuername __P((vchar_t *)); 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 *)); diff --git a/src/racoon/debug.h b/src/racoon/debug.h index 47c2641..4270b6a 100644 --- a/src/racoon/debug.h +++ b/src/racoon/debug.h @@ -1,4 +1,4 @@ -/* $NetBSD: debug.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: debug.h,v 1.5 2008/12/23 14:03:12 tteras Exp $ */ /* Id: debug.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp */ @@ -37,5 +37,6 @@ /* define by main.c */ extern int f_local; extern int vflag; +extern int dump_config; #endif /* _DEBUG_H */ diff --git a/src/racoon/dnssec.c b/src/racoon/dnssec.c index 1fc0bd1..d52a243 100644 --- a/src/racoon/dnssec.c +++ b/src/racoon/dnssec.c @@ -1,4 +1,4 @@ -/* $NetBSD: dnssec.c,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: dnssec.c,v 1.5 2009/03/12 10:57:26 tteras Exp $ */ /* $KAME: dnssec.c,v 1.2 2001/08/05 18:46:07 itojun Exp $ */ @@ -55,11 +55,11 @@ extern int h_errno; -cert_t * +vchar_t * dnssec_getcert(id) vchar_t *id; { - cert_t *cert = NULL; + vchar_t *cert = NULL; struct certinfo *res = NULL; struct ipsecdoi_id_b *id_b; int type; @@ -116,39 +116,22 @@ dnssec_getcert(id) } /* create cert holder */ - cert = oakley_newcert(); + cert = vmalloc(res->ci_certlen + 1); 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; + cert->v[0] = type; + memcpy(&cert->v[1], res->ci_cert, res->ci_certlen); 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; + plogdump(LLV_DEBUG, cert->v, cert->l); err: if (name) racoon_free(name); - if (cert) { - oakley_delcert(cert); - cert = NULL; - } - - goto end; + if (res) + freecertinfo(res); + return cert; } diff --git a/src/racoon/dnssec.h b/src/racoon/dnssec.h index fb1c931..1a03d77 100644 --- a/src/racoon/dnssec.h +++ b/src/racoon/dnssec.h @@ -1,4 +1,4 @@ -/* $NetBSD: dnssec.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: dnssec.h,v 1.5 2009/03/12 10:57:26 tteras Exp $ */ /* Id: dnssec.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp */ @@ -34,6 +34,6 @@ #ifndef _DNSSEC_H #define _DNSSEC_H -extern cert_t *dnssec_getcert __P((vchar_t *)); +extern vchar_t *dnssec_getcert __P((vchar_t *)); #endif /* _DNSSEC_H */ diff --git a/src/racoon/doc/FAQ b/src/racoon/doc/FAQ index 0ab49f0..cf9c394 100644 --- a/src/racoon/doc/FAQ +++ b/src/racoon/doc/FAQ @@ -18,7 +18,7 @@ Q: How can I make racoon interoperate with <IKE/IPsec implementation>? A: Configure both ends exactly the same. With just a tiny little - differnce, you will be in trouble. + difference, you will be in trouble. Q: How to build racoon on my platform? @@ -109,6 +109,6 @@ A: Q: Other documents to look at? A: - http://www.netbsd.org/Documentation/network/ipsec/ + http://www.NetBSD.org/docs/network/ipsec/ http://www.kame.net/ http://www.kame.net/newsletter/ diff --git a/src/racoon/doc/README.privsep b/src/racoon/doc/README.privsep new file mode 100644 index 0000000..e01c820 --- /dev/null +++ b/src/racoon/doc/README.privsep @@ -0,0 +1,152 @@ + Using Racoon with Privilege Separation + Tue Mar 25 16:37:09 MDT 2008 + + +Racoon can run in a chroot'd environment. When so instructed, it runs as two +processes, one of which handles a small number of simple requests and runs as +root in the full native filesystem, and another which runs as a less +privileged user in a chroot'd environment and which handles all the other and +very complex business of racoon. + +Because racoon does many complex things there are many opportunities for +coding errors to lead to compromises and so this separation is important. If +someone breaks into your system using racoon and you have enabled privilege +separation, they will find themselves in a very limited environment and unable +to do much damage. They may be able to alter the host's security associations +or obtain the private keys stored on that system using file descriptors +available to the unprivileged instance of racoon, and from there they will be +able to alter security associations on other hosts in disruptive or dangerous +ways if you have generate_policy enabled on those hosts. But that's because +in its current form generate_policy is itself dangerous and requires that you +trust anyone with the credentials to use it. + +They will also be able to execute any scripts you have placed in the scripts +directory, although racoon will prevent them from mis-using the traditional +environment variables PATH, LD_LIBRARY_PATH, and IFS. But if you have +introduced vulnerabilities into your scripts you may want to re-visit them. +The thing to watch for is blindly trusting the environment variables passed +in by racoon - assume they could be set to anything by a malicious entity and +check them for suitability before using them. + +All these possibilities are present when privilege separation is not enabled, +and they are greatly reduced when it is enabled because the resources +available to the attacker are less. + +***** + +The basic concept with racoon's privilege separation is that a minimal +environment containing all the files racoon needs to operate - with the +exception of private keys, scripts, and system-wide authentication services - +is placed in a stripped-down copy of the original environment. The private +keys and scripts are left in the original environment where only the +privileged instance of racoon will have access to them. + +Here are basic instructions for setting up racoon to run with privilege +separation: + + +First, create a user/group for racoon to run under. For example, user:group +ike:ike. The account should not have a usable password or real home +directory, so copy the general format of another system-services type account +such as 'daemon'. + +You already have files in, e.g. /usr/local/etc/racoon - perhaps racoon.conf, a +certs directory containing certificates, a scripts directory, and other +miscellaneous files such as welcome messages. Perform the following steps: + +cd /usr/local/etc/racoon +mkdir root +mv certs root +mkdir certs +mv root/certs/*.key certs + +If you want to be able to switch back and forth between using and not using +privsep, do this too: + +cd /usr/local/etc/racoon/certs +for i in ../root/certs/* +do + ln -s $i . +done + +Now root/certs contains certificates and certs contains the keys. The idea is +that the public certificates are in the chroot'd area +(/usr/local/etc/racoon/root) and the keys are available only to the privileged +instance of racoon. + +Move any other racoon configuration data into /usr/local/etc/racoon/root, +with the exception of the scripts directory and racoon.conf. + +All the files in /usr/local/etc/racoon/root should be owned by root and the +ike:ike user you created should not have write access to any directories or +files (unless you are using something like 'path backupsa', but you get the +idea). + +Create the device nodes: + +mkdir root/dev + +Do whatever your OS requires to populate the new dev directory with a +minimal set of devices, e.g. mknod, MAKEDEV, or mount devfs... In freebsd +this is done by adding a line to /etc/fstab: + +devfs /usr/local/etc/racoon/root/dev devfs rw 0 0 + +and then adding a line like this to /etc/rc.conf: + +devfs_set_rulesets="/usr/local/etc/racoon/root/dev=devfsrules_basic" + +and then adding the following lines to /etc/devfs.rules: + +[devfsrules_basic=10] +add include $devfsrules_hide_all +add include $devfsrules_unhide_basic + +and then either rebooting or entering "mount -a && /etc/rc.d/devfs start". + +When done with that: + +mkdir -p root/usr/local/etc +ln -s ../../../ root/usr/local/etc/racoon + +This dummy hierarchy keeps the config file consistent between both copies of +racoon. Of course, you could actually put the certs directory and any other +configuration data down in the hierarchy but I prefer to leave it at the root +and link to it as shown. You may end up with something like this: + +root# ls -FC /usr/local/etc/racoon/root +certs/ dev/ usr/ + +root# ls -l /usr/local/etc/racoon/root/usr/local/etc +lrwxr-xr-x 1 root wheel 9 Mar 7 22:13 racoon -> ../../../ + +root# ls -FC /usr/local/etc/racoon/root/usr/local/etc/racoon/ +certs/ dev/ usr/ + +Presumably your racoon.conf already contains something like: + +path certificate "/usr/local/etc/racoon/certs"; +path script "/usr/local/etc/racoon/scripts"; + +If so, great. If not, add them. Then, finally, add the privsep section: + +privsep { + user "ike"; + group "ike"; + chroot "/usr/local/etc/racoon/root"; +} + +Apply the patches posted to the list and rebuild racoon (the patches will be +incorporated into the release subsequent to the date of this memo, so if you +use that or a later release you can skip this step). + +Restart racoon and hopefully things will work. As of the date of this memo, +re-loading the configuration file with racoonctl will not work with privsep +enabled. However, the problem is not insurmountable and if you figure it out +let us know. + +I have not tested privsep with many of racoon's features such as XAUTH or +scripts, so if you have trouble with them and work anything out please reply +to the list so that your discoveries may be incorporated into this document. + +Last modified: $Date: 2008/03/28 04:18:52 $ diff --git a/src/racoon/eaytest.c b/src/racoon/eaytest.c index 323ecef..1474bdc 100644 --- a/src/racoon/eaytest.c +++ b/src/racoon/eaytest.c @@ -1,4 +1,4 @@ -/* $NetBSD: eaytest.c,v 1.7.6.2 2008/07/15 00:55:48 mgrooms Exp $ */ +/* $NetBSD: eaytest.c,v 1.10 2010/01/17 23:02:48 wiz Exp $ */ /* Id: eaytest.c,v 1.22 2005/06/19 18:02:54 manubsd Exp */ @@ -572,6 +572,7 @@ getcerts(path) n++; } + closedir(dirp); p = (char **)realloc(certs, (n + 1) * sizeof(certs)); if (p == NULL) diff --git a/src/racoon/evt.c b/src/racoon/evt.c index fc65b20..11d9695 100644 --- a/src/racoon/evt.c +++ b/src/racoon/evt.c @@ -1,9 +1,10 @@ -/* $NetBSD: evt.c,v 1.5 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: evt.c,v 1.10 2010/10/21 06:15:28 tteras Exp $ */ /* Id: evt.c,v 1.5 2006/06/22 20:11:35 manubsd Exp */ /* * Copyright (C) 2004 Emmanuel Dreyfus + * Copyright (C) 2008 Timo Teras * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,14 +47,55 @@ #include "plog.h" #include "misc.h" #include "admin.h" +#include "handler.h" +#include "session.h" #include "gcmalloc.h" #include "evt.h" +#include "var.h" #ifdef ENABLE_ADMINPORT -struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); -int evtlist_len = 0; -void +static EVT_LISTENER_LIST(evt_listeners); + +struct evt_message { + struct admin_com adm; + struct evt_async evt; +}; + +struct evt { + struct evtdump *dump; + TAILQ_ENTRY(evt) next; +}; + +TAILQ_HEAD(evtlist, evt); + +#define EVTLIST_MAX 32 + +static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); +static int evtlist_len = 0; +static int evtlist_inuse = 0; + +static struct { + int newtype, oldtype; +} evttype_map[] = { + { EVT_RACOON_QUIT, EVTT_RACOON_QUIT }, + { EVT_PHASE1_UP, EVTT_PHASE1_UP }, + { EVT_PHASE1_DOWN, EVTT_PHASE1_DOWN }, + { EVT_PHASE1_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, + { EVT_PHASE1_NO_PROPOSAL, EVTT_PEERPH1_NOPROP }, + { EVT_PHASE1_AUTH_FAILED, EVTT_PEERPH1AUTH_FAILED }, + { EVT_PHASE1_DPD_TIMEOUT, EVTT_DPD_TIMEOUT }, + { EVT_PHASE1_PEER_DELETED, EVTT_PEER_DELETE }, + { EVT_PHASE1_MODE_CFG, EVTT_ISAKMP_CFG_DONE }, + { EVT_PHASE1_XAUTH_SUCCESS, EVTT_XAUTH_SUCCESS }, + { EVT_PHASE1_XAUTH_FAILED, EVTT_XAUTH_FAILED }, + { EVT_PHASE2_NO_PHASE1, -1 }, + { EVT_PHASE2_UP, EVTT_PHASE2_UP }, + { EVT_PHASE2_DOWN, EVTT_PHASE2_DOWN }, + { EVT_PHASE2_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, +}; + +static void evt_push(src, dst, type, optdata) struct sockaddr *src; struct sockaddr *dst; @@ -63,9 +105,21 @@ evt_push(src, dst, type, optdata) struct evtdump *evtdump; struct evt *evt; size_t len; + int i; /* If admin socket is disabled, silently discard anything */ - if (adminsock_path == NULL) + if (adminsock_path == NULL || !evtlist_inuse) + return; + + /* Map the event type to old */ + for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++) + if (evttype_map[i].newtype == type) + break; + if (i >= sizeof(evttype_map) / sizeof(evttype_map[0])) + return; + + type = evttype_map[i].oldtype; + if (type < 0) return; /* If we are above the limit, don't record anything */ @@ -121,7 +175,7 @@ evt_push(src, dst, type, optdata) return; } -struct evtdump * +static struct evtdump * evt_pop(void) { struct evtdump *evtdump; struct evt *evt; @@ -142,6 +196,12 @@ evt_dump(void) { struct evtdump *evtdump; vchar_t *buf = NULL; + if (!evtlist_inuse) { + evtlist_inuse = 1; + plog(LLV_ERROR, LOCATION, NULL, + "evt_dump: deprecated event polling used\n"); + } + if ((evtdump = evt_pop()) != NULL) { if ((buf = vmalloc(evtdump->len)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, @@ -155,4 +215,185 @@ evt_dump(void) { return buf; } +static struct evt_message * +evtmsg_create(type, optdata) + int type; + vchar_t *optdata; +{ + struct evt_message *e; + size_t len; + + len = sizeof(struct evt_message); + if (optdata != NULL) + len += optdata->l; + + if ((e = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n", + strerror(errno)); + return NULL; + } + + memset(e, 0, sizeof(struct evt_message)); + e->adm.ac_len = len; + e->adm.ac_cmd = ADMIN_SHOW_EVT; + e->adm.ac_errno = 0; + e->adm.ac_proto = 0; + e->evt.ec_type = type; + time(&e->evt.ec_timestamp); + if (optdata != NULL) + memcpy(e + 1, optdata->v, optdata->l); + + return e; +} + +static void +evt_unsubscribe(l) + struct evt_listener *l; +{ + plog(LLV_DEBUG, LOCATION, NULL, + "[%d] admin connection released\n", l->fd); + + LIST_REMOVE(l, ll_chain); + unmonitor_fd(l->fd); + close(l->fd); + racoon_free(l); +} + +static int +evt_unsubscribe_cb(ctx, fd) + void *ctx; + int fd; +{ + evt_unsubscribe((struct evt_listener *) ctx); + return 0; +} + +static void +evtmsg_broadcast(ll, e) + const struct evt_listener_list *ll; + struct evt_message *e; +{ + struct evt_listener *l, *nl; + + for (l = LIST_FIRST(ll); l != NULL; l = nl) { + nl = LIST_NEXT(l, ll_chain); + + if (send(l->fd, e, e->adm.ac_len, MSG_DONTWAIT) < 0) { + plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n", + strerror(errno)); + evt_unsubscribe(l); + } + } +} + +void +evt_generic(type, optdata) + int type; + vchar_t *optdata; +{ + struct evt_message *e; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +void +evt_phase1(ph1, type, optdata) + const struct ph1handle *ph1; + int type; + vchar_t *optdata; +{ + struct evt_message *e; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + if (ph1->local) + memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); + if (ph1->remote) + memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); + + evtmsg_broadcast(&ph1->evt_listeners, e); + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +void +evt_phase2(ph2, type, optdata) + const struct ph2handle *ph2; + int type; + vchar_t *optdata; +{ + struct evt_message *e; + struct ph1handle *ph1 = ph2->ph1; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + if (ph1) { + if (ph1->local) + memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); + if (ph1->remote) + memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); + } + e->evt.ec_ph2msgid = ph2->msgid; + + evtmsg_broadcast(&ph2->evt_listeners, e); + if (ph1) + evtmsg_broadcast(&ph1->evt_listeners, e); + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +int +evt_subscribe(list, fd) + struct evt_listener_list *list; + int fd; +{ + struct evt_listener *l; + + if ((l = racoon_malloc(sizeof(*l))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate event listener: %s\n", + strerror(errno)); + return errno; + } + + if (list == NULL) + list = &evt_listeners; + + LIST_INSERT_HEAD(list, l, ll_chain); + l->fd = fd; + monitor_fd(l->fd, evt_unsubscribe_cb, l, 0); + + plog(LLV_DEBUG, LOCATION, NULL, + "[%d] admin connection is polling events\n", fd); + + return -2; +} + +void +evt_list_init(list) + struct evt_listener_list *list; +{ + LIST_INIT(list); +} + +void +evt_list_cleanup(list) + struct evt_listener_list *list; +{ + while (!LIST_EMPTY(list)) + evt_unsubscribe(LIST_FIRST(list)); +} + #endif /* ENABLE_ADMINPORT */ diff --git a/src/racoon/evt.h b/src/racoon/evt.h index 88ee366..42e14d7 100644 --- a/src/racoon/evt.h +++ b/src/racoon/evt.h @@ -1,9 +1,10 @@ -/* $NetBSD: evt.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: evt.h,v 1.7 2008/12/23 14:03:12 tteras Exp $ */ /* Id: evt.h,v 1.5 2006/01/19 10:24:09 fredsen Exp */ /* * Copyright (C) 2004 Emmanuel Dreyfus + * Copyright (C) 2008 Timo Teras * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +35,10 @@ #ifndef _EVT_H #define _EVT_H +/* + * Old style (deprecated) events which are polled. + */ + struct evtdump { size_t len; struct sockaddr_storage src; @@ -64,25 +69,78 @@ struct evtdump { #define EVTT_PEERPH1_NOPROP 14 /* NO_PROPOSAL_CHOSEN & friends */ #define EVTT_NO_ISAKMP_CFG 15 /* no need to wait for mode_cfg */ -struct evt { - struct evtdump *dump; - TAILQ_ENTRY(evt) next; +/* + * New style, asynchronous events. + */ + +struct evt_async { + uint32_t ec_type; + time_t ec_timestamp; + + struct sockaddr_storage ec_ph1src; + struct sockaddr_storage ec_ph1dst; + u_int32_t ec_ph2msgid; + + /* + * Optionnal list of struct isakmp_data + * for type EVTT_ISAKMP_CFG_DONE + */ }; -TAILQ_HEAD(evtlist, evt); +/* type */ +#define EVT_RACOON_QUIT 0x0001 + +#define EVT_PHASE1_UP 0x0100 +#define EVT_PHASE1_DOWN 0x0101 +#define EVT_PHASE1_NO_RESPONSE 0x0102 +#define EVT_PHASE1_NO_PROPOSAL 0x0103 +#define EVT_PHASE1_AUTH_FAILED 0x0104 +#define EVT_PHASE1_DPD_TIMEOUT 0x0105 +#define EVT_PHASE1_PEER_DELETED 0x0106 +#define EVT_PHASE1_MODE_CFG 0x0107 +#define EVT_PHASE1_XAUTH_SUCCESS 0x0108 +#define EVT_PHASE1_XAUTH_FAILED 0x0109 -#define EVTLIST_MAX 32 +#define EVT_PHASE2_NO_PHASE1 0x0200 +#define EVT_PHASE2_UP 0x0201 +#define EVT_PHASE2_DOWN 0x0202 +#define EVT_PHASE2_NO_RESPONSE 0x0203 #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); +struct ph1handle; +struct ph2handle; + +struct evt_listener { + LIST_ENTRY(evt_listener) ll_chain; + int fd; +}; +LIST_HEAD(evt_listener_list, evt_listener); +#define EVT_LISTENER_LIST(x) struct evt_listener_list x + +void evt_generic __P((int type, vchar_t *optdata)); +void evt_phase1 __P((const struct ph1handle *ph1, int type, vchar_t *optdata)); +void evt_phase2 __P((const struct ph2handle *ph2, int type, vchar_t *optdata)); +vchar_t *evt_dump __P((void)); + +int evt_subscribe __P((struct evt_listener_list *list, int fd)); +void evt_list_init __P((struct evt_listener_list *list)); +void evt_list_cleanup __P((struct evt_listener_list *list)); + #else -#define EVT_PUSH(src, dst, type, optdata) ; -#endif + +#define EVT_LISTENER_LIST(x) + +#define evt_generic(type, optdata) ; +#define evt_phase1(ph1, type, optdata) ; +#define evt_phase2(ph2, type, optdata) ; + +#define evt_subscribe(eventlist, fd) ; +#define evt_list_init(eventlist) ; +#define evt_list_cleanup(eventlist) ; +#define evt_get_fdmask(nfds, fdset) nfds +#define evt_handle_fdmask(fdset) ; + +#endif /* ENABLE_ADMINPORT */ #endif /* _EVT_H */ diff --git a/src/racoon/grabmyaddr.c b/src/racoon/grabmyaddr.c index 8155001..29b913c 100644 --- a/src/racoon/grabmyaddr.c +++ b/src/racoon/grabmyaddr.c @@ -1,9 +1,7 @@ -/* $NetBSD: grabmyaddr.c,v 1.4.6.3 2008/06/18 07:30:18 mgrooms Exp $ */ - -/* Id: grabmyaddr.c,v 1.27 2006/04/06 16:27:05 manubsd Exp */ - +/* $NetBSD: grabmyaddr.c,v 1.28 2011/03/14 17:18:12 tteras Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,40 +31,32 @@ #include "config.h" +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> #include <sys/types.h> -#include <sys/param.h> +#include <sys/queue.h> #include <sys/socket.h> -#include <sys/ioctl.h> -#include <net/if.h> -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include <net/if_var.h> -#endif -#if defined(__NetBSD__) || defined(__FreeBSD__) || \ - (defined(__APPLE__) && defined(__MACH__)) -#include <netinet/in.h> -#include <netinet6/in6_var.h> -#endif +#ifdef __linux__ +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#define USE_NETLINK +#else #include <net/route.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <netdb.h> -#ifdef HAVE_GETIFADDRS -#include <ifaddrs.h> #include <net/if.h> -#endif +#include <net/if_dl.h> +#include <sys/sysctl.h> +#define USE_ROUTE +#endif #include "var.h" #include "misc.h" #include "vmbuf.h" #include "plog.h" #include "sockmisc.h" +#include "session.h" #include "debug.h" #include "localconf.h" @@ -77,841 +67,803 @@ #include "gcmalloc.h" #include "nattraversal.h" -#ifdef __linux__ -#include <linux/types.h> -#include <linux/rtnetlink.h> -#ifndef HAVE_GETIFADDRS -#define HAVE_GETIFADDRS -#define NEED_LINUX_GETIFADDRS -#endif -#endif - -#ifndef HAVE_GETIFADDRS -static unsigned int if_maxindex __P((void)); -#endif -static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *)); -static int suitable_ifaddr __P((const char *, const struct sockaddr *)); -#ifdef INET6 -static int suitable_ifaddr6 __P((const char *, const struct sockaddr *)); -#endif +static int kernel_receive __P((void *ctx, int fd)); +static int kernel_open_socket __P((void)); +static void kernel_sync __P((void)); -#ifdef NEED_LINUX_GETIFADDRS +struct myaddr { + LIST_ENTRY(myaddr) chain; + struct sockaddr_storage addr; + int fd; + int udp_encap; +}; -/* We could do this _much_ better. kame racoon in its current form - * will esentially die at frequent changes of address configuration. - */ +static LIST_HEAD(_myaddr_list_, myaddr) configured, opened; -struct ifaddrs +static void +myaddr_delete(my) + struct myaddr *my; { - struct ifaddrs *ifa_next; - char ifa_name[16]; - int ifa_ifindex; - struct sockaddr *ifa_addr; - struct sockaddr_storage ifa_addrbuf; -}; + if (my->fd != -1) + isakmp_close(my->fd); + LIST_REMOVE(my, chain); + racoon_free(my); +} -static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +static int +myaddr_configured(addr) + struct sockaddr *addr; { - while (RTA_OK(rta, len)) { - if (rta->rta_type <= max) - tb[rta->rta_type] = rta; - rta = RTA_NEXT(rta,len); + struct myaddr *cfg; + + if (LIST_EMPTY(&configured)) + return TRUE; + + LIST_FOREACH(cfg, &configured, chain) { + if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH) + return TRUE; } - return 0; + + return FALSE; } -static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq) +static int +myaddr_open(addr, udp_encap) + struct sockaddr *addr; + int udp_encap; { - 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 myaddr *my; - struct msghdr msg = { - (void*)&nladdr, sizeof(nladdr), - &iov, 1, - NULL, 0, - 0 - }; - - status = recvmsg(fd, &msg, 0); + /* Already open? */ + LIST_FOREACH(my, &opened, chain) { + if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH) + return TRUE; + } - if (status < 0) - continue; + my = racoon_calloc(1, sizeof(struct myaddr)); + if (my == NULL) + return FALSE; - if (status == 0) - return; + memcpy(&my->addr, addr, sysdep_sa_len(addr)); + my->fd = isakmp_open(addr, udp_encap); + if (my->fd < 0) { + racoon_free(my); + return FALSE; + } + my->udp_encap = udp_encap; + LIST_INSERT_HEAD(&opened, my, chain); + return TRUE; +} - if (nladdr.nl_pid) /* Message not from kernel */ - continue; +static int +myaddr_open_all_configured(addr) + struct sockaddr *addr; +{ + /* create all configured, not already opened addresses */ + struct myaddr *cfg, *my; - 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 (addr != NULL) { + switch (addr->sa_family) { + case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif + break; + default: + return FALSE; } - if (msg.msg_flags & MSG_TRUNC) + } + + LIST_FOREACH(cfg, &configured, chain) { + if (addr != NULL && + cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH) continue; + if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap)) + return FALSE; + } + if (LIST_EMPTY(&configured)) { +#ifdef ENABLE_HYBRID + /* Exclude any address we got through ISAKMP mode config */ + if (exclude_cfg_addr(addr) == 0) + return FALSE; +#endif + set_port(addr, lcconf->port_isakmp); + myaddr_open(addr, FALSE); +#ifdef ENABLE_NATT + set_port(addr, lcconf->port_isakmp_natt); + myaddr_open(addr, TRUE); +#endif } - return; + return TRUE; } -static int getifaddrs(struct ifaddrs **ifa0) +static void +myaddr_close_all_open(addr) + struct sockaddr *addr; { - struct { - struct nlmsghdr nlh; - struct rtgenmsg g; - } req; - struct sockaddr_nl nladdr; - static __u32 seq; - struct ifaddrs *i; - int fd; + /* delete all matching open sockets */ + struct myaddr *my, *next; - fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd < 0) - return -1; + for (my = LIST_FIRST(&opened); my; my = next) { + next = LIST_NEXT(my, chain); - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; + if (cmpsaddr((struct sockaddr *) addr, + (struct sockaddr *) &my->addr) + <= CMPSADDR_WOP_MATCH) + myaddr_delete(my); + } +} - 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; +static void +myaddr_flush_list(list) + struct _myaddr_list_ *list; +{ + struct myaddr *my, *next; - if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) { - close(fd); - return -1; + for (my = LIST_FIRST(list); my; my = next) { + next = LIST_NEXT(my, chain); + myaddr_delete(my); } +} - *ifa0 = NULL; +void +myaddr_flush() +{ + myaddr_flush_list(&configured); +} - recvaddrs(fd, ifa0, seq); +int +myaddr_listen(addr, udp_encap) + struct sockaddr *addr; + int udp_encap; +{ + struct myaddr *my; - close(fd); + if (sysdep_sa_len(addr) > sizeof(my->addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "sockaddr size larger than sockaddr_storage\n"); + return -1; + } - fd = socket(AF_INET, SOCK_DGRAM, 0); + my = racoon_calloc(1, sizeof(struct myaddr)); + if (my == NULL) + return -1; - 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); + memcpy(&my->addr, addr, sysdep_sa_len(addr)); + my->udp_encap = udp_encap; + my->fd = -1; + LIST_INSERT_HEAD(&configured, my, chain); return 0; } -static void freeifaddrs(struct ifaddrs *ifa0) +void +myaddr_sync() { - struct ifaddrs *i; + struct myaddr *my, *next; - while (ifa0) { - i = ifa0; - ifa0 = i->ifa_next; - free(i); - } -} - -#endif + if (!lcconf->strict_address) { + kernel_sync(); -#ifndef HAVE_GETIFADDRS -static unsigned int -if_maxindex() -{ - struct if_nameindex *p, *p0; - unsigned int max = 0; + /* delete all existing listeners which are not configured */ + for (my = LIST_FIRST(&opened); my; my = next) { + next = LIST_NEXT(my, chain); - p0 = if_nameindex(); - for (p = p0; p && p->if_index && p->if_name; p++) { - if (max < p->if_index) - max = p->if_index; + if (!myaddr_configured((struct sockaddr *) &my->addr)) + myaddr_delete(my); + } } - if_freenameindex(p0); - return max; } -#endif -void -clear_myaddr(db) - struct myaddrs **db; +int +myaddr_getfd(addr) + struct sockaddr *addr; { - struct myaddrs *p; + struct myaddr *my; - while (*db) { - p = (*db)->next; - delmyaddr(*db); - *db = p; + LIST_FOREACH(my, &opened, chain) { + if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH) + return my->fd; } + + return -1; } - -static struct myaddrs * -find_myaddr(db, p) - struct myaddrs *db; - struct myaddrs *p; -{ - struct myaddrs *q; - char h1[NI_MAXHOST], h2[NI_MAXHOST]; - if (getnameinfo(p->addr, sysdep_sa_len(p->addr), h1, sizeof(h1), NULL, 0, - NI_NUMERICHOST | niflags) != 0) - return NULL; +int +myaddr_getsport(addr) + struct sockaddr *addr; +{ + struct myaddr *my; - for (q = db; q; q = q->next) { - if (p->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; + LIST_FOREACH(my, &opened, chain) { + if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH) + return extract_port((struct sockaddr *) &my->addr); } - return NULL; + return PORT_ISAKMP; } void -grab_myaddrs() +myaddr_init_lists() { -#ifdef HAVE_GETIFADDRS - struct myaddrs *p, *q, *old; - struct ifaddrs *ifa0, *ifap; -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - char addr1[NI_MAXHOST]; + LIST_INIT(&configured); + LIST_INIT(&opened); +} - if (getifaddrs(&ifa0)) { - plog(LLV_ERROR, LOCATION, NULL, - "getifaddrs failed: %s\n", strerror(errno)); - exit(1); - /*NOTREACHED*/ +int +myaddr_init() +{ + if (!lcconf->strict_address) { + lcconf->rtsock = kernel_open_socket(); + if (lcconf->rtsock < 0) + return -1; + monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0); + } else { + lcconf->rtsock = -1; + if (!myaddr_open_all_configured(NULL)) + return -1; } + return 0; +} - old = lcconf->myaddrs; - - for (ifap = ifa0; ifap; ifap = ifap->ifa_next) { - if (! ifap->ifa_addr) - continue; - - 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 = newmyaddr(); - if (p == NULL) { - exit(1); - /*NOTREACHED*/ - } - p->addr = dupsaddr(ifap->ifa_addr); - if (p->addr == NULL) { - exit(1); - /*NOTREACHED*/ - } -#ifdef INET6 -#ifdef __KAME__ - if (ifap->ifa_addr->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)p->addr; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) - || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - sin6->sin6_scope_id = - ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - } - } -#else /* !__KAME__ */ - if (ifap->ifa_addr->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)p->addr; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) - || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - sin6->sin6_scope_id = - if_nametoindex(ifap->ifa_name); - } - } - -#endif -#endif - if (getnameinfo(p->addr, sysdep_sa_len(p->addr), - 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); - q = find_myaddr(old, p); - if (q) - p->sock = q->sock; - else - p->sock = -1; - p->next = lcconf->myaddrs; - lcconf->myaddrs = p; +void +myaddr_close() +{ + myaddr_flush_list(&configured); + myaddr_flush_list(&opened); + if (lcconf->rtsock != -1) { + unmonitor_fd(lcconf->rtsock); + close(lcconf->rtsock); } +} - freeifaddrs(ifa0); - - clear_myaddr(&old); - -#else /*!HAVE_GETIFADDRS*/ - int s; - unsigned int maxif; - int len; - struct ifreq *iflist; - struct ifconf ifconf; - struct ifreq *ifr, *ifr_end; - struct myaddrs *p, *q, *old; -#ifdef INET6 -#ifdef __KAME__ - struct sockaddr_in6 *sin6; -#endif -#endif - - char addr1[NI_MAXHOST]; +#if defined(USE_NETLINK) - maxif = if_maxindex() + 1; - len = maxif * sizeof(struct sockaddr_storage) * 4; /* guess guess */ +static int netlink_fd = -1; - iflist = (struct ifreq *)racoon_malloc(len); - if (!iflist) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate buffer\n"); - exit(1); - /*NOTREACHED*/ - } +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "socket(SOCK_DGRAM) failed: %s\n", - strerror(errno)); - exit(1); - /*NOTREACHED*/ - } - memset(&ifconf, 0, sizeof(ifconf)); - ifconf.ifc_req = iflist; - ifconf.ifc_len = len; - if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { - close(s); - plog(LLV_ERROR, LOCATION, NULL, - "ioctl(SIOCGIFCONF) failed: %s\n", - strerror(errno)); - exit(1); - /*NOTREACHED*/ +static void +parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta,len); } - close(s); - - old = lcconf->myaddrs; +} - /* Look for this interface in the list */ - ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); +static int +netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type, + const void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) + return FALSE; + + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return TRUE; +} -#define _IFREQ_LEN(p) \ - (sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) > sizeof(struct ifreq) \ - ? sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) : sizeof(struct ifreq)) +static int +netlink_enumerate(fd, family, type) + int fd; + int family; + int type; +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct sockaddr_nl addr; + static __u32 seq = 0; - for (ifr = ifconf.ifc_req; - ifr < ifr_end; - ifr = (struct ifreq *)((caddr_t)ifr + _IFREQ_LEN(ifr))) { + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; - switch (ifr->ifr_addr.sa_family) { - case AF_INET: -#ifdef INET6 - case AF_INET6: -#endif - if (!suitable_ifaddr(ifr->ifr_name, &ifr->ifr_addr)) { - plog(LLV_ERROR, LOCATION, NULL, - "unsuitable address: %s %s\n", - ifr->ifr_name, - saddrwop2str(&ifr->ifr_addr)); - continue; - } - - p = newmyaddr(); - if (p == NULL) { - exit(1); - /*NOTREACHED*/ - } - p->addr = dupsaddr(&ifr->ifr_addr); - if (p->addr == NULL) { - exit(1); - /*NOTREACHED*/ - } -#ifdef INET6 -#ifdef __KAME__ - sin6 = (struct sockaddr_in6 *)p->addr; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) - || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - sin6->sin6_scope_id = - ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - } -#endif -#endif - if (getnameinfo(p->addr, sysdep_sa_len(p->addr), - addr1, sizeof(addr1), - NULL, 0, - NI_NUMERICHOST | niflags)) - strlcpy(addr1, "(invalid)", sizeof(addr1)); - plog(LLV_DEBUG, LOCATION, NULL, - "my interface: %s (%s)\n", - addr1, ifr->ifr_name); - q = find_myaddr(old, p); - if (q) - p->sock = q->sock; - else - p->sock = -1; - p->next = lcconf->myaddrs; - lcconf->myaddrs = p; - break; - default: - break; - } - } - - clear_myaddr(&old); + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = type; + 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 = family; - racoon_free(iflist); -#endif /*HAVE_GETIFADDRS*/ + return sendto(fd, (void *) &req, sizeof(req), 0, + (struct sockaddr *) &addr, sizeof(addr)) >= 0; } -/* - * check the interface is suitable or not - */ -static int -suitable_ifaddr(ifname, ifaddr) - const char *ifname; - const struct sockaddr *ifaddr; +static void +netlink_add_del_address(int add, struct sockaddr *saddr) { -#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*/ + plog(LLV_DEBUG, LOCATION, NULL, + "Netlink: address %s %s\n", + saddrwop2str((struct sockaddr *) saddr), + add ? "added" : "deleted"); + + if (add) + myaddr_open_all_configured(saddr); + else + myaddr_close_all_open(saddr); } #ifdef INET6 static int -suitable_ifaddr6(ifname, ifaddr) - const char *ifname; - const struct sockaddr *ifaddr; +netlink_process_addr(struct nlmsghdr *h) { -#ifndef __linux__ - struct in6_ifreq ifr6; - int s; -#endif + struct sockaddr_storage addr; + struct ifaddrmsg *ifa; + struct rtattr *rta[IFA_MAX+1]; + struct sockaddr_in6 *sin6; - if (ifaddr->sa_family != AF_INET6) + ifa = NLMSG_DATA(h); + parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h)); + + if (ifa->ifa_family != AF_INET6) + return 0; + if (ifa->ifa_flags & IFA_F_TENTATIVE) + return 0; + if (rta[IFA_LOCAL] == NULL) + rta[IFA_LOCAL] = rta[IFA_ADDRESS]; + if (rta[IFA_LOCAL] == NULL) 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)); + memset(&addr, 0, sizeof(addr)); + addr.ss_family = ifa->ifa_family; + sin6 = (struct sockaddr_in6 *) &addr; + memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]), + sizeof(sin6->sin6_addr)); + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) return 0; - } + sin6->sin6_scope_id = ifa->ifa_index; - memset(&ifr6, 0, sizeof(ifr6)); - strncpy(ifr6.ifr_name, ifname, strlen(ifname)); + netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR, + (struct sockaddr *) &addr); - ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr; + return 0; +} +#endif - if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno)); - close(s); - return 0; - } +static int +netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len) +{ + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + struct rtmsg *r = NLMSG_DATA(&req.n); + struct rtattr *rta[RTA_MAX+1]; + struct sockaddr_nl nladdr; + ssize_t rlen; - close(s); + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETROUTE; + req.r.rtm_family = family; + netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST, + addr, addr_len); + req.r.rtm_dst_len = addr_len * 8; - 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) + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + if (sendto(netlink_fd, &req, sizeof(req), 0, + (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) + return 0; + rlen = recv(netlink_fd, &req, sizeof(req), 0); + if (rlen < 0) return 0; -#endif - /* suitable */ - return 1; + return req.n.nlmsg_type == RTM_NEWROUTE && + req.r.rtm_type == RTN_LOCAL; } -#endif -int -update_myaddrs() +static int +netlink_process_route(struct nlmsghdr *h) { -#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; + struct sockaddr_storage addr; + struct rtmsg *rtm; + struct rtattr *rta[RTA_MAX+1]; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif - 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; + rtm = NLMSG_DATA(h); + + /* local IP addresses get local route in the local table */ + if (rtm->rtm_type != RTN_LOCAL || + rtm->rtm_table != RT_TABLE_LOCAL) return 0; - } - switch (rtm->rtm_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - case RTM_DELETE: - case RTM_IFINFO: + + parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h)); + if (rta[RTA_DST] == NULL) + return 0; + + /* setup the socket address */ + memset(&addr, 0, sizeof(addr)); + addr.ss_family = rtm->rtm_family; + switch (rtm->rtm_family) { + case AF_INET: + sin = (struct sockaddr_in *) &addr; + memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]), + sizeof(sin->sin_addr)); break; - case RTM_MISS: - /* ignore this message silently */ - return 0; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *) &addr; + memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]), + sizeof(sin6->sin6_addr)); + /* Link-local addresses are handled with RTM_NEWADDR + * notifications */ + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + return 0; + break; +#endif default: + return 0; + } + + /* If local route was deleted, check if there is still local + * route for the same IP on another interface */ + if (h->nlmsg_type == RTM_DELROUTE && + netlink_route_is_local(rtm->rtm_family, + RTA_DATA(rta[RTA_DST]), + RTA_PAYLOAD(rta[RTA_DST]))) { plog(LLV_DEBUG, LOCATION, NULL, - "msg %d not interesting\n", rtm->rtm_type); + "Netlink: not deleting %s yet, it exists still\n", + saddrwop2str((struct sockaddr *) &addr)); 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__ */ + netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE, + (struct sockaddr *) &addr); + return 0; } -/* - * 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() +static int +netlink_process(struct nlmsghdr *h) { - struct myaddrs *p; - int n; - - plog(LLV_DEBUG, LOCATION, NULL, - "configuring default isakmp port.\n"); - -#ifdef ENABLE_NATT - if (natt_enabled_in_rmconf ()) { - plog(LLV_NOTIFY, LOCATION, NULL, "NAT-T is enabled, autoconfiguring ports\n"); - for (p = lcconf->myaddrs; p; p = p->next) { - struct myaddrs *new; - if (! p->udp_encap) { - new = dupmyaddr(p); - new->udp_encap = 1; - } - } - } + switch (h->nlmsg_type) { +#ifdef INET6 + case RTM_NEWADDR: + case RTM_DELADDR: + return netlink_process_addr(h); #endif - - 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); + case RTM_NEWROUTE: + case RTM_DELROUTE: + return netlink_process_route(h); } - plog(LLV_DEBUG, LOCATION, NULL, - "%d addrs are configured successfully\n", n); - return 0; } -/* - * get a port number to which racoon binded. - */ -u_short -getmyaddrsport(local) - struct sockaddr *local; +static int +kernel_receive(ctx, fd) + void *ctx; + int fd; { - 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)) - continue; - - /* use first matching address regardless of port */ - if (!bestmatch) { - bestmatch = p; + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + struct nlmsghdr *h; + int len, status; + char buf[16*1024]; + + iov.iov_base = buf; + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(fd, &msg, MSG_DONTWAIT); + if (status < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return FALSE; continue; } + if (status == 0) + return FALSE; - /* matching address with port PORT_ISAKMP */ - if (extract_port(p->addr) == PORT_ISAKMP) { - bestmatch = p; - bestmatch_port = PORT_ISAKMP; + h = (struct nlmsghdr *) buf; + while (NLMSG_OK(h, status)) { + netlink_process(h); + h = NLMSG_NEXT(h, status); } } - return bestmatch_port; + return TRUE; } -struct myaddrs * -newmyaddr() +static int +netlink_open_socket() { - struct myaddrs *new; + int fd; - new = racoon_calloc(1, sizeof(*new)); - if (new == NULL) { + fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) { plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate buffer for myaddrs.\n"); - return NULL; + "socket(PF_NETLINK) failed: %s", + strerror(errno)); + return -1; } + close_on_exec(fd); + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) + plog(LLV_WARNING, LOCATION, NULL, + "failed to put socket in non-blocking mode\n"); - new->next = NULL; - new->addr = NULL; - - return new; + return fd; } -struct myaddrs * -dupmyaddr(struct myaddrs *old) +static int +kernel_open_socket() { - struct myaddrs *new; + struct sockaddr_nl nl; + int fd; - new = racoon_calloc(1, sizeof(*new)); - if (new == NULL) { + if (netlink_fd < 0) { + netlink_fd = netlink_open_socket(); + if (netlink_fd < 0) + return -1; + } + + fd = netlink_open_socket(); + if (fd < 0) + return fd; + + /* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group + * the get the RTN_LOCAL routes which are automatically added + * by kernel. This is because: + * - Linux kernel has a bug that calling bind() immediately + * after IPv4 RTM_NEWADDR event can fail + * - if IP is configured in multiple interfaces, we get + * RTM_DELADDR for each of them. RTN_LOCAL gets deleted only + * after the last IP address is deconfigured. + * The latter reason is also why I chose to use route + * notifications for IPv6. However, we do need to use RTM_NEWADDR + * for the link-local IPv6 addresses to get the interface index + * that is needed in bind(). + */ + memset(&nl, 0, sizeof(nl)); + nl.nl_family = AF_NETLINK; + nl.nl_groups = RTMGRP_IPV4_ROUTE +#ifdef INET6 + | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE +#endif + ; + if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) { plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate buffer for myaddrs.\n"); - return NULL; + "bind(PF_NETLINK) failed: %s\n", + strerror(errno)); + close(fd); + return -1; } + return fd; +} - /* Copy the whole structure and set the differences. */ - memcpy (new, old, sizeof (*new)); - new->addr = dupsaddr (old->addr); - if (new->addr == NULL) { +static void +kernel_sync() +{ + int fd = lcconf->rtsock; + + /* refresh addresses */ + if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) { plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate buffer for myaddrs.\n"); - racoon_free(new); - return NULL; + "unable to enumerate addresses: %s\n", + strerror(errno)); } - new->next = old->next; - old->next = new; + while (kernel_receive(NULL, fd) == TRUE); - return new; +#ifdef INET6 + if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to enumerate addresses: %s\n", + strerror(errno)); + } + while (kernel_receive(NULL, fd) == TRUE); +#endif } -void -insmyaddr(new, head) - struct myaddrs *new; - struct myaddrs **head; +#elif defined(USE_ROUTE) + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +#define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) + +static size_t +parse_address(start, end, dest) + caddr_t start; + caddr_t end; + struct sockaddr_storage *dest; { - new->next = *head; - *head = new; + int len; + + if (start >= end) + return 0; + + len = SAROUNDUP(start); + if (start + len > end) + return end - start; + + if (dest != NULL && len <= sizeof(struct sockaddr_storage)) + memcpy(dest, start, len); + + return len; } -void -delmyaddr(myaddr) - struct myaddrs *myaddr; +static void +parse_addresses(start, end, flags, addr) + caddr_t start; + caddr_t end; + int flags; + struct sockaddr_storage *addr; { - if (myaddr->addr) - racoon_free(myaddr->addr); - racoon_free(myaddr); + memset(addr, 0, sizeof(*addr)); + if (flags & RTA_DST) + start += parse_address(start, end, NULL); + if (flags & RTA_GATEWAY) + start += parse_address(start, end, NULL); + if (flags & RTA_NETMASK) + start += parse_address(start, end, NULL); + if (flags & RTA_GENMASK) + start += parse_address(start, end, NULL); + if (flags & RTA_IFP) + start += parse_address(start, end, NULL); + if (flags & RTA_IFA) + start += parse_address(start, end, addr); + if (flags & RTA_AUTHOR) + start += parse_address(start, end, NULL); + if (flags & RTA_BRD) + start += parse_address(start, end, NULL); } -int -initmyaddr() +static void +kernel_handle_message(msg) + caddr_t msg; { - /* 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; + struct rt_msghdr *rtm = (struct rt_msghdr *) msg; + struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg; + struct sockaddr_storage addr; + + switch (rtm->rtm_type) { + case RTM_NEWADDR: + parse_addresses(ifa + 1, msg + ifa->ifam_msglen, + ifa->ifam_addrs, &addr); + myaddr_open_all_configured((struct sockaddr *) &addr); + break; + case RTM_DELADDR: + parse_addresses(ifa + 1, msg + ifa->ifam_msglen, + ifa->ifam_addrs, &addr); + myaddr_close_all_open((struct sockaddr *) &addr); + break; + case RTM_ADD: + case RTM_DELETE: + case RTM_CHANGE: + case RTM_MISS: + case RTM_IFINFO: +#ifdef RTM_OIFINFO + case RTM_OIFINFO: +#endif +#ifdef RTM_NEWMADDR + case RTM_NEWMADDR: + case RTM_DELMADDR: +#endif +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: +#endif + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "unrecognized route message with rtm_type: %d", + rtm->rtm_type); + break; } +} -#ifdef __linux__ - { - struct sockaddr_nl nl; - u_int addr_len; +static int +kernel_receive(ctx, fd) + void *ctx; + int fd; +{ + char buf[16*1024]; + struct rt_msghdr *rtm = (struct rt_msghdr *) buf; + int len; - memset(&nl, 0, sizeof(nl)); - nl.nl_family = AF_NETLINK; - nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK|RTMGRP_IPV6_IFADDR; + len = read(fd, &buf, sizeof(buf)); + if (len <= 0) { + if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN) + plog(LLV_WARNING, LOCATION, NULL, + "routing socket error: %s", strerror(errno)); + return FALSE; + } - 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; + if (rtm->rtm_msglen != len) { + plog(LLV_WARNING, LOCATION, NULL, + "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n", + rtm->rtm_msglen, len, rtm->rtm_type); + return FALSE; } - addr_len = sizeof(nl); - if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) { + + kernel_handle_message(buf); + return TRUE; +} + +static int +kernel_open_socket() +{ + int fd; + + fd = socket(PF_ROUTE, SOCK_RAW, 0); + if (fd < 0) { plog(LLV_ERROR, LOCATION, NULL, - "getsockname(PF_NETLINK) failed: %s\n", - strerror(errno)); + "socket(PF_ROUTE) failed: %s", + strerror(errno)); return -1; } - } -#endif + close_on_exec(fd); + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) + plog(LLV_WARNING, LOCATION, NULL, + "failed to put socket in non-blocking mode\n"); - if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) { - grab_myaddrs(); + return fd; +} - if (autoconf_myaddrsport() < 0) - return -1; +static void +kernel_sync() +{ + caddr_t ref, buf, end; + size_t bufsiz; + struct if_msghdr *ifm; + struct interface *ifp; + +#define MIBSIZ 6 + int mib[MIBSIZ] = { + CTL_NET, + PF_ROUTE, + 0, + 0, /* AF_INET & AF_INET6 */ + NET_RT_IFLIST, + 0 + }; + + if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { + plog(LLV_WARNING, LOCATION, NULL, + "sysctl() error: %s", strerror(errno)); + return; + } + + ref = buf = racoon_malloc(bufsiz); + + if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) { + /* Parse both interfaces and addresses. */ + for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { + ifm = (struct if_msghdr *) buf; + kernel_handle_message(buf); + } + } else { + plog(LLV_WARNING, LOCATION, NULL, + "sysctl() error: %s", strerror(errno)); } - return 0; + racoon_free(ref); } -/* 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 +#else - 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; - } +#error No supported interface to monitor local addresses. - return p->sock; -} +#endif diff --git a/src/racoon/grabmyaddr.h b/src/racoon/grabmyaddr.h index ac74b46..a105d8f 100644 --- a/src/racoon/grabmyaddr.h +++ b/src/racoon/grabmyaddr.h @@ -1,4 +1,4 @@ -/* $NetBSD: grabmyaddr.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: grabmyaddr.h,v 1.6 2009/04/21 18:38:32 tteras Exp $ */ /* Id: grabmyaddr.h,v 1.5 2004/06/11 16:00:16 ludvigm Exp */ @@ -34,23 +34,15 @@ #ifndef _GRABMYADDR_H #define _GRABMYADDR_H -struct myaddrs { - struct myaddrs *next; - struct sockaddr *addr; - int sock; - int udp_encap; -}; +extern void myaddr_init_lists __P((void)); +extern int myaddr_init __P((void)); +extern void myaddr_close __P((void)); -extern void clear_myaddr __P((struct myaddrs **)); -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 *)); +extern void myaddr_flush __P((void)); +extern int myaddr_listen __P((struct sockaddr *, int)); +extern void myaddr_sync __P((void)); + +extern int myaddr_getfd __P((struct sockaddr *)); +extern int myaddr_getsport __P((struct sockaddr *)); #endif /* _GRABMYADDR_H */ diff --git a/src/racoon/handler.c b/src/racoon/handler.c index b643256..a795ee6 100644 --- a/src/racoon/handler.c +++ b/src/racoon/handler.c @@ -1,11 +1,11 @@ -/* $NetBSD: handler.c,v 1.9.6.8 2009/04/20 13:25:27 tteras Exp $ */ +/* $NetBSD: handler.c,v 1.39 2011/03/14 17:18:12 tteras Exp $ */ /* Id: handler.c,v 1.28 2006/05/26 12:17:29 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -64,7 +64,7 @@ #include "evt.h" #include "isakmp.h" #ifdef ENABLE_HYBRID -#include "isakmp_xauth.h" +#include "isakmp_xauth.h" #include "isakmp_cfg.h" #endif #include "isakmp_inf.h" @@ -85,10 +85,10 @@ 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 struct sched sc_sweep = SCHED_INITIALIZER(); 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 @@ -100,6 +100,41 @@ static void sweep_recvdpkt __P((void *)); extern caddr_t val2str(const char *, size_t); +/* + * Enumerate the Phase 1 tree. + * If enum_func() internally return a non-zero value, this specific + * error value is returned. 0 is returned if everything went right. + * + * Note that it is ok for enum_func() to call insph1(). Those inserted + * Phase 1 will not interfere with current enumeration process. + */ +int +enumph1(sel, enum_func, enum_arg) + struct ph1selector *sel; + int (* enum_func)(struct ph1handle *iph1, void *arg); + void *enum_arg; +{ + struct ph1handle *p; + int ret; + + LIST_FOREACH(p, &ph1tree, chain) { + if (sel != NULL) { + if (sel->local != NULL && + cmpsaddr(sel->local, p->local) > CMPSADDR_WILDPORT_MATCH) + continue; + + if (sel->remote != NULL && + cmpsaddr(sel->remote, p->remote) > CMPSADDR_WILDPORT_MATCH) + continue; + } + + if ((ret = enum_func(p, enum_arg)) != 0) + return ret; + } + + return 0; +} + struct ph1handle * getph1byindex(index) isakmp_index *index; @@ -107,7 +142,7 @@ getph1byindex(index) struct ph1handle *p; LIST_FOREACH(p, &ph1tree, chain) { - if (p->status == PHASE1ST_EXPIRED) + if (p->status >= PHASE1ST_EXPIRED) continue; if (memcmp(&p->index, index, sizeof(*index)) == 0) return p; @@ -127,7 +162,7 @@ getph1byindex0(index) struct ph1handle *p; LIST_FOREACH(p, &ph1tree, chain) { - if (p->status == PHASE1ST_EXPIRED) + if (p->status >= PHASE1ST_EXPIRED) continue; if (memcmp(&p->index, index, sizeof(cookie_t)) == 0) return p; @@ -142,31 +177,57 @@ getph1byindex0(index) * with phase 2's destinaion. */ struct ph1handle * -getph1byaddr(local, remote, established) +getph1(ph1hint, local, remote, flags) + struct ph1handle *ph1hint; struct sockaddr *local, *remote; - int established; + int flags; { struct ph1handle *p; - plog(LLV_DEBUG2, LOCATION, NULL, "getph1byaddr: start\n"); + plog(LLV_DEBUG2, LOCATION, NULL, "getph1: start\n"); plog(LLV_DEBUG2, LOCATION, NULL, "local: %s\n", saddr2str(local)); plog(LLV_DEBUG2, LOCATION, NULL, "remote: %s\n", saddr2str(remote)); LIST_FOREACH(p, &ph1tree, chain) { - if (p->status == PHASE1ST_EXPIRED) + if (p->status >= PHASE1ST_DYING) continue; + plog(LLV_DEBUG2, LOCATION, NULL, "p->local: %s\n", saddr2str(p->local)); plog(LLV_DEBUG2, LOCATION, NULL, "p->remote: %s\n", saddr2str(p->remote)); - if(established && p->status != PHASE1ST_ESTABLISHED){ - plog(LLV_DEBUG2, LOCATION, NULL, "status %d, skipping\n", p->status); + if ((flags & GETPH1_F_ESTABLISHED) && + (p->status != PHASE1ST_ESTABLISHED)) { + plog(LLV_DEBUG2, LOCATION, NULL, + "status %d, skipping\n", p->status); continue; } - if (CMPSADDR(local, p->local) == 0 - && CMPSADDR(remote, p->remote) == 0){ - plog(LLV_DEBUG2, LOCATION, NULL, "matched\n"); - return p; + + if (local != NULL && cmpsaddr(local, p->local) == CMPSADDR_MISMATCH) + continue; + + if (remote != NULL && cmpsaddr(remote, p->remote) == CMPSADDR_MISMATCH) + continue; + + if (ph1hint != NULL) { + if (ph1hint->id && ph1hint->id->l && p->id && p->id->l && + (ph1hint->id->l != p->id->l || + memcmp(ph1hint->id->v, p->id->v, p->id->l) != 0)) { + plog(LLV_DEBUG2, LOCATION, NULL, + "local identity does match hint\n"); + continue; + } + if (ph1hint->id_p && ph1hint->id_p->l && + p->id_p && p->id_p->l && + (ph1hint->id_p->l != p->id_p->l || + memcmp(ph1hint->id_p->v, p->id_p->v, p->id_p->l) != 0)) { + plog(LLV_DEBUG2, LOCATION, NULL, + "remote identity does match hint\n"); + continue; + } } + + plog(LLV_DEBUG2, LOCATION, NULL, "matched\n"); + return p; } plog(LLV_DEBUG2, LOCATION, NULL, "no match\n"); @@ -174,44 +235,78 @@ getph1byaddr(local, remote, established) return NULL; } -struct ph1handle * -getph1byaddrwop(local, remote) - struct sockaddr *local, *remote; +int +resolveph1rmconf(iph1) + struct ph1handle *iph1; { - struct ph1handle *p; + struct remoteconf *rmconf; - LIST_FOREACH(p, &ph1tree, chain) { - if (p->status == PHASE1ST_EXPIRED) - continue; - if (cmpsaddrwop(local, p->local) == 0 - && cmpsaddrwop(remote, p->remote) == 0) - return p; + /* INITIATOR is always expected to know the exact rmconf. */ + if (iph1->side == INITIATOR) + return 0; + + rmconf = getrmconf_by_ph1(iph1); + if (rmconf == NULL) + return -1; + if (rmconf == RMCONF_ERR_MULTIPLE) + return 1; + + if (iph1->rmconf != NULL) { + if (rmconf != iph1->rmconf) { + plog(LLV_ERROR, LOCATION, NULL, + "unexpected rmconf switch; killing ph1\n"); + return -1; + } + } else { + iph1->rmconf = rmconf; } - return NULL; + return 0; } + /* - * search for isakmpsa handler by remote address. - * don't use port number to search because this function search - * with phase 2's destinaion. + * move phase2s from old_iph1 to new_iph1 */ -struct ph1handle * -getph1bydstaddrwop(remote) - struct sockaddr *remote; +void +migrate_ph12(old_iph1, new_iph1) + struct ph1handle *old_iph1, *new_iph1; +{ + struct ph2handle *p, *next; + + /* Relocate phase2s to better phase1s or request a new phase1. */ + for (p = LIST_FIRST(&old_iph1->ph2tree); p; p = next) { + next = LIST_NEXT(p, ph1bind); + + if (p->status != PHASE2ST_ESTABLISHED) + continue; + + unbindph12(p); + bindph12(new_iph1, p); + } +} + +/* + * the iph1 is new, migrate all phase2s that belong to a dying or dead ph1 + */ +void migrate_dying_ph12(iph1) + struct ph1handle *iph1; { struct ph1handle *p; LIST_FOREACH(p, &ph1tree, chain) { - if (p->status == PHASE1ST_EXPIRED) + if (p == iph1) + continue; + if (p->status < PHASE1ST_DYING) continue; - if (cmpsaddrwop(remote, p->remote) == 0) - return p; - } - return NULL; + if (cmpsaddr(iph1->local, p->local) == CMPSADDR_MATCH + && cmpsaddr(iph1->remote, p->remote) == CMPSADDR_MATCH) + migrate_ph12(p, iph1); + } } + /* * dump isakmp-sa */ @@ -268,11 +363,10 @@ newph1() #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 + evt_list_init(&iph1->evt_listeners); return iph1; } @@ -289,8 +383,7 @@ delph1(iph1) /* SA down shell script hook */ script_hook(iph1, SCRIPT_PHASE1_DOWN); - - EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL); + evt_list_cleanup(&iph1->evt_listeners); #ifdef ENABLE_NATT if (iph1->natt_flags & NAT_KA_QUEUED) @@ -308,8 +401,10 @@ delph1(iph1) #endif #ifdef ENABLE_DPD - SCHED_KILL(iph1->dpd_r_u); + sched_cancel(&iph1->dpd_r_u); #endif + sched_cancel(&iph1->sce); + sched_cancel(&iph1->scr); if (iph1->remote) { racoon_free(iph1->remote); @@ -325,13 +420,7 @@ delph1(iph1) } 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); @@ -346,14 +435,10 @@ delph1(iph1) 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->cert); + VPTRINIT(iph1->cert_p); + VPTRINIT(iph1->crl_p); + VPTRINIT(iph1->cr_p); VPTRINIT(iph1->id); VPTRINIT(iph1->id_p); @@ -415,7 +500,7 @@ flushph1() next = LIST_NEXT(p, chain); /* send delete information */ - if (p->status == PHASE1ST_ESTABLISHED) + if (p->status >= PHASE1ST_ESTABLISHED) isakmp_info_send_d1(p); remph1(p); @@ -429,26 +514,52 @@ initph1tree() LIST_INIT(&ph1tree); } +int +ph1_rekey_enabled(iph1) + struct ph1handle *iph1; +{ + if (iph1->rmconf == NULL) + return 0; + if (iph1->rmconf->rekey == REKEY_FORCE) + return 1; +#ifdef ENABLE_DPD + if (iph1->rmconf->rekey == REKEY_ON && iph1->dpd_support && + iph1->rmconf->dpd_interval) + return 1; +#endif + return 0; +} + /* %%% management phase 2 handler */ -/* - * search ph2handle with policy id. - */ -struct ph2handle * -getph2byspid(spid) - u_int32_t spid; + +int +enumph2(sel, enum_func, enum_arg) + struct ph2selector *sel; + int (*enum_func)(struct ph2handle *ph2, void *arg); + void *enum_arg; { struct ph2handle *p; + int ret; LIST_FOREACH(p, &ph2tree, chain) { - /* - * there are ph2handle independent on policy - * such like informational exchange. - */ - if (p->spid == spid) - return p; + if (sel != NULL) { + if (sel->spid != 0 && sel->spid != p->spid) + continue; + + if (sel->src != NULL && + cmpsaddr(sel->src, p->src) != CMPSADDR_MATCH) + continue; + + if (sel->dst != NULL && + cmpsaddr(sel->dst, p->dst) != CMPSADDR_MATCH) + continue; + } + + if ((ret = enum_func(p, enum_arg)) != 0) + return ret; } - return NULL; + return 0; } /* @@ -478,7 +589,7 @@ getph2bymsgid(iph1, msgid) { struct ph2handle *p; - LIST_FOREACH(p, &ph2tree, chain) { + LIST_FOREACH(p, &iph1->ph2tree, ph1bind) { if (p->msgid == msgid && p->ph1 == iph1) return p; } @@ -486,6 +597,15 @@ getph2bymsgid(iph1, msgid) return NULL; } +/* Note that src and dst are not the selectors of the SP + * but the source and destination addresses used for + * for SA negotiation (best example is tunnel mode SA + * where src and dst are the endpoints). There is at most + * a unique match because racoon does not support bundles + * which makes that there is at most a single established + * SA for a given spid. One could say that src and dst + * are in fact useless ... + */ struct ph2handle * getph2byid(src, dst, spid) struct sockaddr *src, *dst; @@ -495,8 +615,8 @@ getph2byid(src, dst, spid) LIST_FOREACH(p, &ph2tree, chain) { if (spid == p->spid && - CMPSADDR(src, p->src) == 0 && - CMPSADDR(dst, p->dst) == 0){ + cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH && + cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH){ /* Sanity check to detect zombie handlers * XXX Sould be done "somewhere" more interesting, * because we have lots of getph2byxxxx(), but this one @@ -504,7 +624,7 @@ getph2byid(src, dst, spid) */ if(p->status < PHASE2ST_ESTABLISHED && p->retry_counter == 0 - && p->sce == NULL && p->scr == NULL){ + && p->sce.func == NULL && p->scr.func == NULL) { plog(LLV_DEBUG, LOCATION, NULL, "Zombie ph2 found, expiring it\n"); isakmp_ph2expire(p); @@ -523,8 +643,8 @@ getph2bysaddr(src, dst) struct ph2handle *p; LIST_FOREACH(p, &ph2tree, chain) { - if (cmpsaddrstrict(src, p->src) == 0 && - cmpsaddrstrict(dst, p->dst) == 0) + if (cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH && + cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH) return p; } @@ -582,6 +702,7 @@ newph2() return NULL; iph2->status = PHASE1ST_SPAWN; + evt_list_init(&iph2->evt_listeners); return iph2; } @@ -595,9 +716,11 @@ void initph2(iph2) struct ph2handle *iph2; { - sched_scrub_param(iph2); - iph2->sce = NULL; - iph2->scr = NULL; + evt_list_cleanup(&iph2->evt_listeners); + unbindph12(iph2); + + sched_cancel(&iph2->sce); + sched_cancel(&iph2->scr); VPTRINIT(iph2->sendbuf); VPTRINIT(iph2->msg1); @@ -642,6 +765,17 @@ initph2(iph2) oakley_delivm(iph2->ivm); iph2->ivm = NULL; } + +#ifdef ENABLE_NATT + if (iph2->natoa_src) { + racoon_free(iph2->natoa_src); + iph2->natoa_src = NULL; + } + if (iph2->natoa_dst) { + racoon_free(iph2->natoa_dst); + iph2->natoa_dst = NULL; + } +#endif } /* @@ -661,14 +795,24 @@ delph2(iph2) racoon_free(iph2->dst); iph2->dst = NULL; } - if (iph2->src_id) { - racoon_free(iph2->src_id); - iph2->src_id = NULL; + if (iph2->sa_src) { + racoon_free(iph2->sa_src); + iph2->sa_src = NULL; + } + if (iph2->sa_dst) { + racoon_free(iph2->sa_dst); + iph2->sa_dst = NULL; + } +#ifdef ENABLE_NATT + if (iph2->natoa_src) { + racoon_free(iph2->natoa_src); + iph2->natoa_src = NULL; } - if (iph2->dst_id) { - racoon_free(iph2->dst_id); - iph2->dst_id = NULL; + if (iph2->natoa_dst) { + racoon_free(iph2->natoa_dst); + iph2->natoa_dst = NULL; } +#endif if (iph2->proposal) { flushsaprop(iph2->proposal); @@ -694,6 +838,7 @@ void remph2(iph2) struct ph2handle *iph2; { + unbindph12(iph2); LIST_REMOVE(iph2, chain); } @@ -725,7 +870,6 @@ flushph2() } delete_spd(p, 0); - unbindph12(p); remph2(p); delph2(p); } @@ -763,7 +907,6 @@ deleteallph2(src, dst, proto_id) } continue; zap_it: - unbindph12(iph2); remph2(iph2); delph2(iph2); } @@ -775,7 +918,10 @@ bindph12(iph1, iph2) struct ph1handle *iph1; struct ph2handle *iph2; { + unbindph12(iph2); + iph2->ph1 = iph1; + iph1->ph2cnt++; LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind); } @@ -784,8 +930,9 @@ unbindph12(iph2) struct ph2handle *iph2; { if (iph2->ph1 != NULL) { - iph2->ph1 = NULL; LIST_REMOVE(iph2, ph1bind); + iph2->ph1->ph2cnt--; + iph2->ph1 = NULL; } } @@ -800,7 +947,7 @@ getcontacted(remote) struct contacted *p; LIST_FOREACH(p, &ctdtree, chain) { - if (cmpsaddrstrict(remote, p->remote) == 0) + if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH) return p; } @@ -835,6 +982,22 @@ inscontacted(remote) } void +remcontacted(remote) + struct sockaddr *remote; +{ + struct contacted *p; + + LIST_FOREACH(p, &ctdtree, chain) { + if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH) { + LIST_REMOVE(p, chain); + racoon_free(p->remote); + racoon_free(p); + break; + } + } +} + +void initctdtree() { LIST_INIT(&ctdtree); @@ -856,12 +1019,9 @@ check_recvdpkt(remote, local, rbuf) { vchar_t *hash; struct recvdpkt *r; - time_t t; + struct timeval now, diff; int len, s; - /* set current time */ - t = time(NULL); - hash = eay_md5_one(rbuf); if (!hash) { plog(LLV_ERROR, LOCATION, NULL, @@ -882,7 +1042,7 @@ check_recvdpkt(remote, local, rbuf) /* * the packet was processed before, but the remote address mismatches. */ - if (cmpsaddrstrict(remote, r->remote) != 0) + if (cmpsaddr(remote, r->remote) != CMPSADDR_MATCH) return 2; /* @@ -891,7 +1051,9 @@ check_recvdpkt(remote, local, rbuf) */ /* check the previous time to send */ - if (t - r->time_send < 1) { + sched_get_monotonic_time(&now); + timersub(&now, &r->time_send, &diff); + if (diff.tv_sec == 0) { plog(LLV_WARNING, LOCATION, NULL, "the packet retransmitted in a short time from %s\n", saddr2str(remote)); @@ -899,7 +1061,7 @@ check_recvdpkt(remote, local, rbuf) } /* select the socket to be sent */ - s = getsockmyaddr(r->local); + s = myaddr_getfd(r->local); if (s == -1) return -1; @@ -920,7 +1082,7 @@ check_recvdpkt(remote, local, rbuf) "deleted the retransmission packet to %s.\n", saddr2str(remote)); } else - r->time_send = t; + r->time_send = now; return 1; } @@ -977,8 +1139,7 @@ add_recvdpkt(remote, local, sbuf, rbuf) } new->retry_counter = lcconf->retry_counter; - new->time_send = 0; - new->created = time(NULL); + sched_get_monotonic_time(&new->time_send); LIST_INSERT_HEAD(&rcptree, new, chain); @@ -1007,29 +1168,30 @@ rem_recvdpkt(r) LIST_REMOVE(r, chain); } -void +static void sweep_recvdpkt(dummy) - void *dummy; + struct sched *dummy; { struct recvdpkt *r, *next; - time_t t, lt; + struct timeval now, diff, sweep; - /* set current time */ - t = time(NULL); + sched_get_monotonic_time(&now); - /* set the lifetime of the retransmission */ - lt = lcconf->retry_counter * lcconf->retry_interval; + /* calculate sweep time; delete entries older than this */ + diff.tv_sec = lcconf->retry_counter * lcconf->retry_interval; + diff.tv_usec = 0; + timersub(&now, &diff, &sweep); for (r = LIST_FIRST(&rcptree); r; r = next) { next = LIST_NEXT(r, chain); - if (t - r->created > lt) { + if (timercmp(&r->time_send, &sweep, <)) { rem_recvdpkt(r); del_recvdpkt(r); } } - sched_new(lt, sweep_recvdpkt, NULL); + sched_schedule(&sc_sweep, diff.tv_sec, sweep_recvdpkt); } void @@ -1039,11 +1201,11 @@ init_recvdpkt() LIST_INIT(&rcptree); - sched_new(lt, sweep_recvdpkt, NULL); + sched_schedule(&sc_sweep, lt, sweep_recvdpkt); } #ifdef ENABLE_HYBRID -/* +/* * Retruns 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 */ @@ -1070,7 +1232,7 @@ exclude_cfg_addr(addr) -/* +/* * Reload conf code */ static int revalidate_ph2(struct ph2handle *iph2){ @@ -1080,19 +1242,19 @@ static int revalidate_ph2(struct ph2handle *iph2){ struct saprop *approval; struct ph1handle *iph1; - /* + /* * Get the new sainfo using values of the old one */ if (iph2->sainfo != NULL) { - iph2->sainfo = getsainfo(iph2->sainfo->idsrc, + iph2->sainfo = getsainfo(iph2->sainfo->idsrc, iph2->sainfo->iddst, iph2->sainfo->id_i, - iph2->sainfo->remoteid); + NULL, iph2->sainfo->remoteid); } approval = iph2->approval; sainfo = iph2->sainfo; if (sainfo == NULL) { - /* + /* * Sainfo has been removed */ plog(LLV_DEBUG, LOCATION, NULL, @@ -1107,7 +1269,7 @@ static int revalidate_ph2(struct ph2handle *iph2){ plog(LLV_DEBUG, LOCATION, NULL, "No approval found !\n"); return 0; - } + } /* * Don't care about proposals, should we do something ? @@ -1206,7 +1368,7 @@ static int revalidate_ph2(struct ph2handle *iph2){ } found = 0; - for (alg = sainfo->algs[algclass_ipsec_enc]; + for (alg = sainfo->algs[algclass_ipsec_enc]; (found == 0 && alg != NULL); alg = alg->next) { plog(LLV_DEBUG, LOCATION, NULL, "Reload: next ph2 enc alg...\n"); @@ -1239,7 +1401,7 @@ static int revalidate_ph2(struct ph2handle *iph2){ break; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(LLV_ERROR, LOCATION, NULL, "unexpected check_level\n"); continue; break; @@ -1263,7 +1425,7 @@ static int revalidate_ph2(struct ph2handle *iph2){ } -static void +static void remove_ph2(struct ph2handle *iph2) { u_int32_t spis[2]; @@ -1289,7 +1451,6 @@ remove_ph2(struct ph2handle *iph2) purge_ipsec_spi(iph2->dst, iph2->approval->head->proto_id, spis, 2); }else{ - unbindph12(iph2); remph2(iph2); delph2(iph2); } @@ -1304,197 +1465,41 @@ static void remove_ph1(struct ph1handle *iph1){ plog(LLV_DEBUG, LOCATION, NULL, "Removing PH1...\n"); - if (iph1->status == PHASE1ST_ESTABLISHED){ + if (iph1->status == PHASE1ST_ESTABLISHED || + iph1->status == PHASE1ST_DYING) { for (iph2 = LIST_FIRST(&iph1->ph2tree); iph2; iph2 = iph2_next) { - iph2_next = LIST_NEXT(iph2, chain); + iph2_next = LIST_NEXT(iph2, ph1bind); remove_ph2(iph2); } isakmp_info_send_d1(iph1); } iph1->status = PHASE1ST_EXPIRED; - iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + /* directly call isakmp_ph1delete to avoid as possible a race + * condition where we'll try to access iph1->rmconf after it has + * freed + */ + isakmp_ph1delete(iph1); } -static int revalidate_ph1tree_rmconf(void){ +static int revalidate_ph1tree_rmconf(void) +{ struct ph1handle *p, *next; - struct remoteconf *newrmconf; + struct remoteconf *rmconf; for (p = LIST_FIRST(&ph1tree); p; p = next) { next = LIST_NEXT(p, chain); - if (p->status == PHASE1ST_EXPIRED) + if (p->status >= PHASE1ST_EXPIRED) continue; - - newrmconf=getrmconf(p->remote); - if(newrmconf == NULL){ - p->rmconf = NULL; - remove_ph1(p); - }else{ - /* Do not free old rmconf, it is just a pointer to an entry in rmtree - */ - p->rmconf=newrmconf; - if(p->approval != NULL){ - struct isakmpsa *tmpsa; - - tmpsa=dupisakmpsa(p->approval); - if(tmpsa != NULL){ - delisakmpsa(p->approval); - p->approval=tmpsa; - p->approval->rmconf=newrmconf; - } - } - } - } - - return 1; -} - - -/* rmconf is already updated here - */ -static int revalidate_ph1(struct ph1handle *iph1){ - struct isakmpsa *p, *approval; - struct etypes *e; - - if(iph1 == NULL || - iph1->approval == NULL || - iph1->rmconf == NULL) - return 0; - - approval=iph1->approval; - - for (e = iph1->rmconf->etypes; e != NULL; e = e->next){ - if (iph1->etype == e->type) - break; - } - - if (e == NULL){ - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: Exchange type mismatch\n"); - return 0; - } - - if (iph1->etype == ISAKMP_ETYPE_AGG && - approval->dh_group != iph1->rmconf->dh_group){ - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: DH mismatch\n"); - return 0; - } - - for (p=iph1->rmconf->proposal; p != NULL; p=p->next){ - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: Trying next proposal...\n"); - - if(approval->authmethod != p->authmethod){ - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: Authmethod mismatch\n"); + if (p->rmconf == NULL) continue; - } - if(approval->enctype != p->enctype){ - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: enctype mismatch\n"); - continue; - } - - switch (iph1->rmconf->pcheck_level) { - case PROP_CHECK_OBEY: - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: OBEY pcheck level, ok...\n"); - return 1; - break; - - case PROP_CHECK_CLAIM: - /* FALLTHROUGH */ - case PROP_CHECK_STRICT: - if (approval->encklen < p->encklen) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: encklen mismatch\n"); - continue; - } - - if (approval->lifetime > p->lifetime) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: lifetime mismatch\n"); - continue; - } - -#if 0 - /* Lifebyte is deprecated, just ignore it - */ - if (approval->lifebyte > p->lifebyte) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: lifebyte mismatch\n"); - continue; - } -#endif - break; - - case PROP_CHECK_EXACT: - if (approval->encklen != p->encklen) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: encklen mismatch\n"); - continue; - } - - if (approval->lifetime != p->lifetime) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: lifetime mismatch\n"); - continue; - } - -#if 0 - /* Lifebyte is deprecated, just ignore it - */ - if (approval->lifebyte != p->lifebyte) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: lifebyte mismatch\n"); - continue; - } -#endif - break; - - default: - plog(LLV_ERROR, LOCATION, NULL, - "unexpected check_level\n"); - continue; - break; - } - - if (approval->hashtype != p->hashtype) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: hashtype mismatch\n"); - continue; - } - - if (iph1->etype != ISAKMP_ETYPE_AGG && - approval->dh_group != p->dh_group) { - plog(LLV_DEBUG, LOCATION, NULL, - "Reload: dhgroup mismatch\n"); - continue; - } - - plog(LLV_DEBUG, LOCATION, NULL, "Reload: Conf ok\n"); - return 1; - } - - plog(LLV_DEBUG, LOCATION, NULL, "Reload: No valid conf found\n"); - return 0; -} - - -static int revalidate_ph1tree(void){ - struct ph1handle *p, *next; - - for (p = LIST_FIRST(&ph1tree); p; p = next) { - next = LIST_NEXT(p, chain); - - if (p->status == PHASE1ST_EXPIRED) - continue; - - if(!revalidate_ph1(p)) + rmconf = getrmconf_by_ph1(p); + if (rmconf == NULL || rmconf == RMCONF_ERR_MULTIPLE) remove_ph1(p); + else + p->rmconf = rmconf; } return 1; @@ -1519,14 +1524,12 @@ static int revalidate_ph2tree(void){ return 1; } -int +int revalidate_ph12(void) { revalidate_ph1tree_rmconf(); - revalidate_ph2tree(); - revalidate_ph1tree(); return 1; } @@ -1559,7 +1562,10 @@ purgeph1bylogin(login) if (p->mode_cfg == NULL) continue; if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) { - if (p->status == PHASE1ST_ESTABLISHED) + if (p->status >= PHASE1ST_EXPIRED) + continue; + + if (p->status >= PHASE1ST_ESTABLISHED) isakmp_info_send_d1(p); purge_remote(p); found++; diff --git a/src/racoon/handler.h b/src/racoon/handler.h index a52dc6c..45d596e 100644 --- a/src/racoon/handler.h +++ b/src/racoon/handler.h @@ -1,11 +1,11 @@ -/* $NetBSD: handler.h,v 1.9.6.1 2008/01/11 14:12:01 vanhu Exp $ */ +/* $NetBSD: handler.h,v 1.25 2010/11/17 10:40:41 tteras Exp $ */ /* Id: handler.h,v 1.19 2006/02/25 08:25:12 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -41,6 +41,8 @@ #include "isakmp_var.h" #include "oakley.h" +#include "schedule.h" +#include "evt.h" /* Phase 1 handler */ /* @@ -93,8 +95,9 @@ #define PHASE1ST_MSG3SENT 7 #define PHASE1ST_MSG4RECEIVED 8 #define PHASE1ST_ESTABLISHED 9 -#define PHASE1ST_EXPIRED 10 -#define PHASE1ST_MAX 11 +#define PHASE1ST_DYING 10 +#define PHASE1ST_EXPIRED 11 +#define PHASE1ST_MAX 12 /* About address semantics in each case. * initiator(addr=I) responder(addr=R) @@ -131,6 +134,7 @@ struct ph1handle { u_int8_t flags; /* Flags */ u_int32_t msgid; /* message id */ + u_int32_t vendorid_mask; /* bitmask of received supported vendor ids*/ #ifdef ENABLE_NATT struct ph1natt_options *natt_options; /* Selected NAT-T IKE version */ u_int32_t natt_flags; /* NAT-T related flags */ @@ -140,9 +144,9 @@ struct ph1handle { struct isakmp_frag_item *frag_chain; /* Received fragments */ #endif - struct sched *sce; /* schedule for expire */ + struct sched sce; /* schedule for expire */ - struct sched *scr; /* schedule for resend */ + struct sched scr; /* schedule for resend */ int retry_counter; /* for resend. */ vchar_t *sendbuf; /* buffer for re-sending */ @@ -160,10 +164,10 @@ struct ph1handle { 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 */ + vchar_t *cert; /* CERT minus general header */ + vchar_t *cert_p; /* peer's CERT minus general header */ + vchar_t *crl_p; /* peer's CRL minus general header */ + vchar_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 */ @@ -190,6 +194,7 @@ struct ph1handle { struct isakmp_pl_hash *pl_hash; /* pointer to hash payload */ time_t created; /* timestamp for establish */ + int initial_contact_received; /* set if initial contact received */ #ifdef ENABLE_STATS struct timeval start; struct timeval end; @@ -197,10 +202,10 @@ struct ph1handle { #ifdef ENABLE_DPD 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_int32_t dpd_last_ack; + u_int32_t dpd_seq; /* DPD seq number to receive */ u_int8_t dpd_fails; /* number of failures */ - struct sched *dpd_r_u; + struct sched dpd_r_u; #endif u_int32_t msgid2; /* msgid counter for Phase 2 */ @@ -210,8 +215,14 @@ struct ph1handle { LIST_ENTRY(ph1handle) chain; #ifdef ENABLE_HYBRID struct isakmp_cfg_state *mode_cfg; /* ISAKMP mode config state */ -#endif +#endif + EVT_LISTENER_LIST(evt_listeners); +}; +/* For limiting enumeration of ph1 tree */ +struct ph1selector { + struct sockaddr *local; + struct sockaddr *remote; }; /* Phase 2 handler */ @@ -244,23 +255,44 @@ struct ph1handle { #define PHASE2ST_MAX 11 struct ph2handle { - struct sockaddr *src; /* my address of SA. */ - struct sockaddr *dst; /* peer's address of SA. */ + /* source and destination addresses used for IKE exchange. Might + * differ from source and destination of SA. On the initiator, + * they are tweaked if a hint is available in the SPD (set by + * MIGRATE for instance). Otherwise they are the source and + * destination of SA for transport mode and the tunnel endpoints + * for tunnel mode */ + struct sockaddr *src; + struct sockaddr *dst; + + /* source and destination addresses of the SA in the case addresses + * used for IKE exchanges (src and dst) do differ. On the initiator, + * they are set (if needed) in pk_recvacquire(). On the responder, + * they are _derived_ from the local and remote parameters of the + * SP, if available. */ + struct sockaddr *sa_src; + struct sockaddr *sa_dst; + + /* Store our Phase 2 ID and the peer ID (ID minus general header). + * On the initiator, they are set during ACQUIRE processing. + * On the responder, they are set from the content of ID payload + * in quick_r1recv(). Then, if they are of type address or + * tunnel, they are compared to sainfo selectors. + */ + vchar_t *id; /* ID minus gen header */ + vchar_t *id_p; /* peer's ID minus general header */ - /* - * 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; +#ifdef ENABLE_NATT + struct sockaddr *natoa_src; /* peer's view of my address */ + struct sockaddr *natoa_dst; /* peer's view of his address */ +#endif 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 */ + 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 */ @@ -288,6 +320,8 @@ struct ph2handle { struct sainfo *sainfo; /* place holder of sainfo */ struct saprop *proposal; /* SA(s) proposal. */ struct saprop *approval; /* SA(s) approved. */ + u_int32_t lifetime_secs; /* responder lifetime (seconds) */ + u_int32_t lifetime_kb; /* responder lifetime (kbytes) */ caddr_t spidx_gen; /* policy from peer's proposal */ struct dhgroup *pfsgrp; /* DH; prime number */ @@ -295,8 +329,6 @@ struct ph2handle { 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 */ @@ -320,6 +352,14 @@ struct ph2handle { LIST_ENTRY(ph2handle) chain; LIST_ENTRY(ph2handle) ph1bind; /* chain to ph1handle */ + EVT_LISTENER_LIST(evt_listeners); +}; + +/* For limiting enumeration of ph2 tree */ +struct ph2selector { + u_int32_t spid; + struct sockaddr *src; + struct sockaddr *dst; }; /* @@ -339,10 +379,7 @@ struct recvdpkt { 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 */ + struct timeval time_send; /* timestamp of previous send */ LIST_ENTRY(recvdpkt) chain; }; @@ -413,7 +450,7 @@ struct ph1dump { struct sockaddr_storage remote; struct sockaddr_storage local; u_int8_t version; - u_int8_t etype; + u_int8_t etype; time_t created; int ph2cnt; }; @@ -425,25 +462,42 @@ 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 *, int)); -extern struct ph1handle *getph1byaddrwop __P((struct sockaddr *, - struct sockaddr *)); -extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *)); + +extern int enumph1 __P((struct ph1selector *ph1sel, + int (* enum_func)(struct ph1handle *iph1, void *arg), + void *enum_arg)); + +#define GETPH1_F_ESTABLISHED 0x0001 + +extern struct ph1handle *getph1 __P((struct ph1handle *ph1hint, + struct sockaddr *local, + struct sockaddr *remote, + int flags)); + +#define getph1byaddr(local, remote, est) \ + getph1(NULL, local, remote, est ? GETPH1_F_ESTABLISHED : 0) +#define getph1bydstaddr(remote) \ + getph1(NULL, NULL, remote, 0) + #ifdef ENABLE_HYBRID struct ph1handle *getph1bylogin __P((char *)); int purgeph1bylogin __P((char *)); #endif +extern void migrate_ph12 __P((struct ph1handle *old_iph1, struct ph1handle *new_iph1)); +extern void migrate_dying_ph12 __P((struct ph1handle *iph1)); 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 int resolveph1rmconf __P((struct ph1handle *)); extern void flushph1 __P((void)); extern void initph1tree __P((void)); +extern int ph1_rekey_enabled __P((struct ph1handle *)); -extern struct ph2handle *getph2byspidx __P((struct policyindex *)); -extern struct ph2handle *getph2byspid __P((u_int32_t)); +extern int enumph2 __P((struct ph2selector *ph2sel, + int (* enum_func)(struct ph2handle *iph2, void *arg), + void *enum_arg)); extern struct ph2handle *getph2byseq __P((u_int32_t)); extern struct ph2handle *getph2bysaddr __P((struct sockaddr *, struct sockaddr *)); @@ -466,6 +520,7 @@ extern void unbindph12 __P((struct ph2handle *)); extern struct contacted *getcontacted __P((struct sockaddr *)); extern int inscontacted __P((struct sockaddr *)); +extern void remcontacted __P((struct sockaddr *)); extern void initctdtree __P((void)); extern int check_recvdpkt __P((struct sockaddr *, diff --git a/src/racoon/ipsec_doi-0.7.3.c b/src/racoon/ipsec_doi-0.7.3.c new file mode 100644 index 0000000..7ae9f67 --- /dev/null +++ b/src/racoon/ipsec_doi-0.7.3.c @@ -0,0 +1,5022 @@ +/* $NetBSD: ipsec_doi.c,v 1.23.4.10 2009/06/19 07:32:52 tteras Exp $ */ + +/* Id: ipsec_doi.c,v 1.55 2006/08/17 09:20:41 vanhu Exp */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include PATH_IPSEC_H + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <netdb.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "var.h" +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "cfparse_proto.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "sockmisc.h" +#include "handler.h" +#include "policy.h" +#include "algorithm.h" +#include "sainfo.h" +#include "proposal.h" +#include "crypto_openssl.h" +#include "strnames.h" +#include "gcmalloc.h" + +#ifdef ENABLE_NATT +#include "nattraversal.h" +#endif +#ifdef ENABLE_HYBRID +static int switch_authmethod(int); +#endif + +#ifdef HAVE_GSSAPI +#include <iconv.h> +#include "gssapi.h" +#ifdef HAVE_ICONV_2ND_CONST +#define __iconv_const const +#else +#define __iconv_const +#endif +#endif + +int verbose_proposal_check = 1; + +static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **)); +static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *, + struct isakmpsa *, struct isakmpsa *, int)); +static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *)); +static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *)); +static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *)); +static struct prop_pair *get_ph2approval __P((struct ph2handle *, + struct prop_pair **)); +static struct prop_pair *get_ph2approvalx __P((struct ph2handle *, + struct prop_pair *)); +static void free_proppair0 __P((struct prop_pair *)); + +static int get_transform + __P((struct isakmp_pl_p *, struct prop_pair **, int *)); +static u_int32_t ipsecdoi_set_ld __P((vchar_t *)); + +static int check_doi __P((u_int32_t)); +static int check_situation __P((u_int32_t)); + +static int check_prot_main __P((int)); +static int check_prot_quick __P((int)); +static int (*check_protocol[]) __P((int)) = { + check_prot_main, /* IPSECDOI_TYPE_PH1 */ + check_prot_quick, /* IPSECDOI_TYPE_PH2 */ +}; + +static int check_spi_size __P((int, int)); + +static int check_trns_isakmp __P((int)); +static int check_trns_ah __P((int)); +static int check_trns_esp __P((int)); +static int check_trns_ipcomp __P((int)); +static int (*check_transform[]) __P((int)) = { + 0, + check_trns_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_trns_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_trns_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_trns_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int check_attr_isakmp __P((struct isakmp_pl_t *)); +static int check_attr_ah __P((struct isakmp_pl_t *)); +static int check_attr_esp __P((struct isakmp_pl_t *)); +static int check_attr_ipsec __P((int, struct isakmp_pl_t *)); +static int check_attr_ipcomp __P((struct isakmp_pl_t *)); +static int (*check_attributes[]) __P((struct isakmp_pl_t *)) = { + 0, + check_attr_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_attr_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_attr_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_attr_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int setph1prop __P((struct isakmpsa *, caddr_t)); +static int setph1trns __P((struct isakmpsa *, caddr_t)); +static int setph1attr __P((struct isakmpsa *, caddr_t)); +static vchar_t *setph2proposal0 __P((const struct ph2handle *, + const struct saprop *, const struct saproto *)); + +static vchar_t *getidval __P((int, vchar_t *)); + +#ifdef HAVE_GSSAPI +static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *, + struct isakmpsa *)); +#endif + +/*%%%*/ +/* + * check phase 1 SA payload. + * make new SA payload to be replyed not including general header. + * the pointer to one of isakmpsa in proposal is set into iph1->approval. + * OUT: + * positive: the pointer to new buffer of SA payload. + * network byte order. + * NULL : error occurd. + */ +int +ipsecdoi_checkph1proposal(sa, iph1) + vchar_t *sa; + struct ph1handle *iph1; +{ + vchar_t *newsa; /* new SA payload approved. */ + struct prop_pair **pair; + + /* get proposal pair */ + pair = get_proppair(sa, IPSECDOI_TYPE_PH1); + if (pair == NULL) + return -1; + + /* check and get one SA for use */ + newsa = get_ph1approval(iph1, pair); + + free_proppair(pair); + + if (newsa == NULL) + return -1; + + iph1->sa_ret = newsa; + + return 0; +} + +/* + * acceptable check for remote configuration. + * return a new SA payload to be reply to peer. + */ +static vchar_t * +get_ph1approval(iph1, pair) + struct ph1handle *iph1; + struct prop_pair **pair; +{ + vchar_t *newsa; + struct isakmpsa *sa, tsa; + struct prop_pair *s, *p; + int prophlen; + int i; + + if (iph1->approval) { + delisakmpsa(iph1->approval); + iph1->approval = NULL; + } + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = + sizeof(struct isakmp_pl_p) + s->prop->spi_size; + + /* compare proposal and select one */ + for (p = s; p; p = p->tnext) { + if ((sa = get_ph1approvalx(p, + iph1->rmconf->proposal, &tsa, + iph1->rmconf->pcheck_level)) != NULL) + goto found; + } + } + } + + /* + * if there is no suitable proposal, racoon complains about all of + * mismatched items in those proposal. + */ + if (verbose_proposal_check) { + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = sizeof(struct isakmp_pl_p) + + s->prop->spi_size; + for (p = s; p; p = p->tnext) { + print_ph1mismatched(p, + iph1->rmconf->proposal); + } + } + } + } + plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n"); + + return NULL; + +found: + plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n"); + + /* check DH group settings */ + if (sa->dhgrp) { + if (sa->dhgrp->prime && sa->dhgrp->gen1) { + /* it's ok */ + goto saok; + } + plog(LLV_WARNING, LOCATION, NULL, + "invalid DH parameter found, use default.\n"); + oakley_dhgrp_free(sa->dhgrp); + sa->dhgrp=NULL; + } + + if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) { + sa->dhgrp = NULL; + racoon_free(sa); + return NULL; + } + +saok: +#ifdef HAVE_GSSAPI + if (sa->gssid != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n", + (int)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", + (int)iph1->gi_i->l, iph1->gi_i->v); + if (iph1->gi_r != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n", + (int)iph1->gi_r->l, iph1->gi_r->v); +#else + iph1->approval = sa; +#endif + if(iph1->approval) { + plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n", + s_oakley_attr_method(iph1->approval->authmethod)); + } + + 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, + s->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); + tsap->dhgrp = NULL; + } + + 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); + sa.dhgrp=NULL; + } +} + +/* + * 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: + { + int error = -1; + iconv_t cd = (iconv_t) -1; + 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) { + if ((sa->gssid = vmalloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate memory\n"); + goto out; + } + memcpy(sa->gssid->v, d + 1, len); + plog(LLV_DEBUG, LOCATION, NULL, + "received old-style gss " + "id '%.*s' (len %zu)\n", + (int)sa->gssid->l, sa->gssid->v, + sa->gssid->l); + error = 0; + goto out; + } + + /* + * 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)); + goto out; + } + + if ((sa->gssid = vmalloc(len / 2)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate memory\n"); + goto out; + } + + 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"); + } + goto out; + } + + /* XXX dstleft should always be 0; assert it? */ + sa->gssid->l = (len / 2) - dstleft; + + plog(LLV_DEBUG, LOCATION, NULL, + "received gss id '%.*s' (len %zu)\n", + (int)sa->gssid->l, sa->gssid->v, sa->gssid->l); + + error = 0; +out: + if (cd != (iconv_t)-1) + (void)iconv_close(cd); + + if ((error != 0) && (sa->gssid != NULL)) { + vfree(sa->gssid); + sa->gssid = NULL; + } + 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->spi_size != r->prop->spi_size) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid spi size: %d.\n", + p->prop->spi_size); + 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, *x; + struct prop_pair *n = NULL; + + 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 == NULL) { + 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 = NULL; + 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); + goto bad; + } + + /* check DOI */ + if (check_doi(ntohl(sab->doi)) < 0) + goto bad; + + /* check SITUATION */ + if (check_situation(ntohl(sab->sit)) < 0) + goto bad; + + pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair)); + if (pair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + goto bad; + } + 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) + goto bad; + + 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); + goto bad; + } + + 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); + goto bad; + } + + /* 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); + goto bad; + } + } + 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"); + goto bad; + } + + return pair; +bad: + if (pair != NULL) + racoon_free(pair); + return NULL; +} + +/* + * 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 = NULL; + vchar_t *newsa = NULL; + 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; + int error = -1; + + /* get proposal pair */ + pair = get_proppair(sa0, IPSECDOI_TYPE_PH2); + if (pair == NULL) + goto out; + + newtlen = sizeof(struct ipsecdoi_sa_b); + for (pp = pp0; pp; pp = pp->next) { + + if (pair[pp->prop_no] == NULL) + goto out; + + 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) + goto out; + + newtlen += ntohs(p->trns->h.len); + } + } + } + + newsa = vmalloc(newtlen); + if (newsa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); + goto out; + } + 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) + goto out; + + 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; + } + } + } + + error = 0; +out: + if (pair != NULL) + racoon_free(pair); + + if (error != 0) { + if (newsa != NULL) { + vfree(newsa); + newsa = NULL; + } + } + + 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: + case IPSECDOI_ESP_CAMELLIA: + 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: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: +#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: +#endif +#endif + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_ERROR, LOCATION, NULL, + "auth method %s isn't supported.\n", + s_oakley_attr_method(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; + +#ifdef HAVE_SECCTX + case IPSECDOI_ATTR_SECCTX: + if (flag) { + plog(LLV_ERROR, LOCATION, NULL, + "SECCTX must be in TLV.\n"); + return -1; + } + break; +#endif + + 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(rmconf, props) + struct remoteconf *rmconf; + 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(rmconf->doitype); + ((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(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 %zu, " + "val '%.*s'\n", sa->gssid->l, (int)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; +#ifdef HAVE_SECCTX + int truectxlen = 0; +#endif + + 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); + +#ifdef HAVE_SECCTX + /* ctx_str is defined as char ctx_str[MAX_CTXSTR_SIZ]. + * The string may be smaller than MAX_CTXSTR_SIZ. + */ + if (*pp->sctx.ctx_str) { + truectxlen = sizeof(struct security_ctx) - + (MAX_CTXSTR_SIZE - pp->sctx.ctx_strlen); + attrlen += sizeof(struct isakmp_data) + truectxlen; + } +#endif /* HAVE_SECCTX */ + + 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); + +#ifdef HAVE_SECCTX + if (*pp->sctx.ctx_str) { + struct security_ctx secctx; + secctx = pp->sctx; + secctx.ctx_strlen = htons(pp->sctx.ctx_strlen); + x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SECCTX, + (caddr_t)&secctx, truectxlen); + } +#endif + /* 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; +} + +/* + * 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 if a subnet id is valid for comparison + * with an address id ( address length mask ) + * and compare them + * Return value + * = 0 for match + * = 1 for mismatch + */ + +int +ipsecdoi_subnetisaddr_v4( subnet, address ) + const vchar_t *subnet; + const vchar_t *address; +{ + struct in_addr *mask; + + if (address->l != sizeof(struct in_addr)) + return 1; + + if (subnet->l != (sizeof(struct in_addr)*2)) + return 1; + + mask = (struct in_addr*)(subnet->v + sizeof(struct in_addr)); + + if (mask->s_addr!=0xffffffff) + return 1; + + return memcmp(subnet->v,address->v,address->l); +} + +#ifdef INET6 + +int +ipsecdoi_subnetisaddr_v6( subnet, address ) + const vchar_t *subnet; + const vchar_t *address; +{ + struct in6_addr *mask; + int i; + + if (address->l != sizeof(struct in6_addr)) + return 1; + + if (subnet->l != (sizeof(struct in6_addr)*2)) + return 1; + + mask = (struct in6_addr*)(subnet->v + sizeof(struct in6_addr)); + + for (i=0; i<16; i++) + if(mask->s6_addr[i]!=0xff) + return 1; + + return memcmp(subnet->v,address->v,address->l); +} + +#endif + +/* + * Check and Compare two IDs + * - specify 0 for exact if wildcards are allowed + * Return value + * = 0 for match + * = 1 for misatch + * = -1 for integrity error + */ + +int +ipsecdoi_chkcmpids( idt, ids, exact ) + const vchar_t *idt; /* id cmp target */ + const vchar_t *ids; /* id cmp source */ + int exact; +{ + struct ipsecdoi_id_b *id_bt; + struct ipsecdoi_id_b *id_bs; + vchar_t ident_t; + vchar_t ident_s; + int result; + + /* handle wildcard IDs */ + + if (idt == NULL || ids == NULL) + { + if( !exact ) + { + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : values matched (ANONYMOUS)\n" ); + return 0; + } + else + { + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : value mismatch (ANONYMOUS)\n" ); + return -1; + } + } + + /* make sure the ids are of the same type */ + + id_bt = (struct ipsecdoi_id_b *) idt->v; + id_bs = (struct ipsecdoi_id_b *) ids->v; + + ident_t.v = idt->v + sizeof(*id_bt); + ident_t.l = idt->l - sizeof(*id_bt); + ident_s.v = ids->v + sizeof(*id_bs); + ident_s.l = ids->l - sizeof(*id_bs); + + if (id_bs->type != id_bt->type) + { + /* + * special exception for comparing + * address to subnet id types when + * the netmask is address length + */ + + if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR)&& + (id_bt->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)) { + result = ipsecdoi_subnetisaddr_v4(&ident_t,&ident_s); + goto cmpid_result; + } + + if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)&& + (id_bt->type == IPSECDOI_ID_IPV4_ADDR)) { + result = ipsecdoi_subnetisaddr_v4(&ident_s,&ident_t); + goto cmpid_result; + } + +#ifdef INET6 + if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR)&& + (id_bt->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + result = ipsecdoi_subnetisaddr_v6(&ident_t,&ident_s); + goto cmpid_result; + } + + if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)&& + (id_bt->type == IPSECDOI_ID_IPV6_ADDR)) { + result = ipsecdoi_subnetisaddr_v6(&ident_s,&ident_t); + goto cmpid_result; + } +#endif + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : id type mismatch %s != %s\n", + s_ipsecdoi_ident(id_bs->type), + s_ipsecdoi_ident(id_bt->type)); + + return 1; + } + + if(id_bs->proto_id != id_bt->proto_id){ + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : proto_id mismatch %d != %d\n", + id_bs->proto_id, id_bt->proto_id); + + return 1; + } + + /* compare the ID data. */ + + switch (id_bt->type) { + case IPSECDOI_ID_DER_ASN1_DN: + case IPSECDOI_ID_DER_ASN1_GN: + /* compare asn1 ids */ + result = eay_cmp_asn1dn(&ident_t, &ident_s); + goto cmpid_result; + + case IPSECDOI_ID_IPV4_ADDR: + /* validate lengths */ + if ((ident_t.l != sizeof(struct in_addr))|| + (ident_s.l != sizeof(struct in_addr))) + goto cmpid_invalid; + break; + + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + /* validate lengths */ + if ((ident_t.l != (sizeof(struct in_addr)*2))|| + (ident_s.l != (sizeof(struct in_addr)*2))) + goto cmpid_invalid; + break; + +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + /* validate lengths */ + if ((ident_t.l != sizeof(struct in6_addr))|| + (ident_s.l != sizeof(struct in6_addr))) + goto cmpid_invalid; + break; + + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + /* validate lengths */ + if ((ident_t.l != (sizeof(struct in6_addr)*2))|| + (ident_s.l != (sizeof(struct in6_addr)*2))) + goto cmpid_invalid; + break; +#endif + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + case IPSECDOI_ID_KEY_ID: + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unhandled id type %i specified for comparison\n", + id_bt->type); + return -1; + } + + /* validate matching data and length */ + if (ident_t.l == ident_s.l) + result = memcmp(ident_t.v,ident_s.v,ident_t.l); + else + result = 1; + +cmpid_result: + + /* debug level output */ + if(loglevel >= LLV_DEBUG) { + char *idstrt = ipsecdoi_id2str(idt); + char *idstrs = ipsecdoi_id2str(ids); + + if (!result) + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : values matched (%s)\n", + s_ipsecdoi_ident(id_bs->type) ); + else + plog(LLV_DEBUG, LOCATION, NULL, + "check and compare ids : value mismatch (%s)\n", + s_ipsecdoi_ident(id_bs->type)); + + plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: \'%s\'\n", idstrt ); + plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: \'%s\'\n", idstrs ); + + racoon_free(idstrs); + racoon_free(idstrt); + } + + /* return result */ + if( !result ) + return 0; + else + return 1; + +cmpid_invalid: + + /* id integrity error */ + plog(LLV_DEBUG, LOCATION, NULL, "check and compare ids : %s integrity error\n", + s_ipsecdoi_ident(id_bs->type)); + plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: length = \'%zu\'\n", ident_t.l ); + plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: length = \'%zu\'\n", ident_s.l ); + + return -1; +} + +/* + * 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 (iph1->etype == ISAKMP_ETYPE_IDENT && + iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY) { + 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 || + 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 expecting port. + * always permit if port is equal to PORT_ISAKMP + */ + if (ntohs(id_b->port) != PORT_ISAKMP) { + u_int16_t port; + + port = extract_port(iph1->remote); + 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 = iph1->id_p->v + sizeof(*id_b); + ident.l = iph1->id_p->l - sizeof(*id_b); + 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: + 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); + } + 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); + return new; +} + +/* it's only called by cfparse.y. */ +int +set_identifier(vpp, type, value) + vchar_t **vpp, *value; + int type; +{ + return set_identifier_qual(vpp, type, value, IDQUAL_UNSPEC); +} + +int +set_identifier_qual(vpp, type, value, qual) + vchar_t **vpp, *value; + int type; + int qual; +{ + 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; + } + /* 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: + /* + * If no qualifier is specified: IDQUAL_UNSPEC. It means + * to use a file for backward compatibility sake. + */ + switch(qual) { + case IDQUAL_FILE: + case IDQUAL_UNSPEC: { + 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; + } + fclose(fp); + break; + } + + case IDQUAL_TAG: + new = vmalloc(value->l - 1); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "can not allocate memory"); + return -1; + } + memcpy(new->v, value->v, new->l); + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown qualifier"); + return -1; + } + 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) { + racoon_free(sa); + return -1; + } + memcpy(new->v, sa, new->l); + racoon_free(sa); + 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 (prefixlen == (sizeof(struct in_addr) << 3)) { + 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 (prefixlen == (sizeof(struct in6_addr) << 3)) { + 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; +} + +vchar_t * +ipsecdoi_sockrange2id(laddr, haddr, ul_proto) + struct sockaddr *laddr, *haddr; + u_int ul_proto; +{ + vchar_t *new; + int type, len1, len2; + u_short port; + + if (laddr->sa_family != haddr->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, "Address family mismatch\n"); + return NULL; + } + + switch (laddr->sa_family) { + case AF_INET: + type = IPSECDOI_ID_IPV4_ADDR_RANGE; + len1 = sizeof(struct in_addr); + len2 = sizeof(struct in_addr); + break; +#ifdef INET6 + case AF_INET6: + type = IPSECDOI_ID_IPV6_ADDR_RANGE; + len1 = sizeof(struct in6_addr); + len2 = sizeof(struct in6_addr); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d.\n", laddr->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; + port = ((struct sockaddr_in *)(laddr))->sin_port; + ((struct ipsecdoi_id_b *)new->v)->port = + port == IPSEC_PORT_ANY ? 0 : port; + memcpy(new->v + sizeof(struct ipsecdoi_id_b), + (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, + len1); + memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, + (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr, + len2); + 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: + do_plog(LLV_INFO, "XXXXXXXXXXXXXXXXXXXXXX error\n"); + 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++) { + plen += 8; + if (plen >= max) + break; + } + + 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. + */ +char * +ipsecdoi_id2str(id) + const vchar_t *id; +{ +#define BUFLEN 512 + char * ret = NULL; + int len = 0; + char *dat; + static char buf[BUFLEN]; + struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)id->v; + struct sockaddr_storage saddr_storage; + struct sockaddr *saddr; + struct sockaddr_in *saddr_in; + struct sockaddr_in6 *saddr_in6; + u_int plen = 0; + + saddr = (struct sockaddr *)&saddr_storage; + saddr_in = (struct sockaddr_in *)&saddr_storage; + saddr_in6 = (struct sockaddr_in6 *)&saddr_storage; + + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in); +#endif + saddr->sa_family = AF_INET; + + saddr_in->sin_port = IPSEC_PORT_ANY; + memcpy(&saddr_in->sin_addr, + id->v + sizeof(*id_b), sizeof(struct in_addr)); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in6); +#endif + saddr->sa_family = AF_INET6; + + saddr_in6->sin6_port = IPSEC_PORT_ANY; + memcpy(&saddr_in6->sin6_addr, + id->v + sizeof(*id_b), sizeof(struct in6_addr)); + saddr_in6->sin6_scope_id = + (IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr) + ? ((struct sockaddr_in6 *)id_b)->sin6_scope_id + : 0); + break; +#endif + } + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: +#endif + len = snprintf( buf, BUFLEN, "%s", saddrwop2str(saddr)); + break; + + 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 (id->l < alen) { + len = 0; + break; + } + + /* get subnet mask length */ + plen = 0; + max = alen <<3; + + p = (unsigned char *) id->v + + sizeof(struct ipsecdoi_id_b) + + alen; + + for (; *p == 0xff; p++) { + plen += 8; + if (plen >= max) + break; + } + + if (plen < max) { + u_int l = 0; + u_char b = ~(*p); + + while (b) { + b >>= 1; + l++; + } + + l = 8 - l; + plen += l; + } + + len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(saddr), plen); + } + break; + + case IPSECDOI_ID_IPV4_ADDR_RANGE: + + len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr)); + +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in); +#endif + saddr->sa_family = AF_INET; + saddr_in->sin_port = IPSEC_PORT_ANY; + memcpy(&saddr_in->sin_addr, + id->v + sizeof(*id_b) + sizeof(struct in_addr), + sizeof(struct in_addr)); + + len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr)); + + break; + +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_RANGE: + + len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr)); + +#ifndef __linux__ + saddr->sa_len = sizeof(struct sockaddr_in6); +#endif + saddr->sa_family = AF_INET6; + saddr_in6->sin6_port = IPSEC_PORT_ANY; + memcpy(&saddr_in6->sin6_addr, + id->v + sizeof(*id_b) + sizeof(struct in6_addr), + sizeof(struct in6_addr)); + saddr_in6->sin6_scope_id = + (IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr) + ? ((struct sockaddr_in6 *)id_b)->sin6_scope_id + : 0); + + len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr)); + + break; +#endif + + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + len = id->l - sizeof(*id_b); + if (len > BUFLEN) + len = BUFLEN; + memcpy(buf, id->v + sizeof(*id_b), len); + break; + + case IPSECDOI_ID_DER_ASN1_DN: + case IPSECDOI_ID_DER_ASN1_GN: + { + X509_NAME *xn = NULL; + + dat = id->v + sizeof(*id_b); + len = id->l - sizeof(*id_b); + + if (d2i_X509_NAME(&xn, (void*) &dat, len) != NULL) { + BIO *bio = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(bio, xn, 0, 0); + len = BIO_get_mem_data(bio, &dat); + if (len > BUFLEN) + len = BUFLEN; + memcpy(buf,dat,len); + BIO_free(bio); + X509_NAME_free(xn); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "unable to extract asn1dn from id\n"); + + len = sprintf(buf, "<ASN1-DN>"); + } + + break; + } + + /* currently unhandled id types */ + case IPSECDOI_ID_KEY_ID: + len = sprintf( buf, "<KEY-ID>"); + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown ID type %d\n", id_b->type); + } + + if (!len) + len = sprintf( buf, "<?>"); + + ret = racoon_malloc(len+1); + if (ret != NULL) { + memcpy(ret,buf,len); + ret[len]=0; + } + + return ret; +} + +/* + * 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; +#ifdef HAVE_SECCTX + case IPSECDOI_ATTR_SECCTX: + { + int len = ntohs(d->lorv); + memcpy(&pp->sctx, d + 1, len); + pp->sctx.ctx_strlen = ntohs(pp->sctx.ctx_strlen); + break; + } +#endif /* HAVE_SECCTX */ + 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 */ +}; + +/* + * 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; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I; + break; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I; + break; + /* Those are not implemented */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_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 + +/* + * parse responder-lifetime attributes from payload + */ +int +ipsecdoi_parse_responder_lifetime(notify, lifetime_sec, lifetime_kb) + struct isakmp_pl_n *notify; + u_int32_t *lifetime_sec; + u_int32_t *lifetime_kb; +{ + struct isakmp_data *d; + int flag, type, tlen, ld_type = -1; + u_int16_t lorv; + u_int32_t value; + + tlen = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; + d = (struct isakmp_data *)((char *)(notify + 1) + + notify->spi_size); + + while (tlen >= sizeof(struct isakmp_data)) { + 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)); + + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + ld_type = lorv; + break; + case IPSECDOI_ATTR_SA_LD: + if (flag) + value = lorv; + else if (lorv == 2) + value = ntohs(*(u_int16_t *)(d + 1)); + else if (lorv == 4) + value = ntohl(*(u_int32_t *)(d + 1)); + else { + plog(LLV_ERROR, LOCATION, NULL, + "payload length %d for lifetime " + "data length is unsupported.\n", lorv); + return -1; + } + + switch (ld_type) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + if (lifetime_sec != NULL) + *lifetime_sec = value; + plog(LLV_INFO, LOCATION, NULL, + "received RESPONDER-LIFETIME: %d " + "seconds\n", value); + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + if (lifetime_kb != NULL) + *lifetime_kb = value; + plog(LLV_INFO, LOCATION, NULL, + "received RESPONDER-LIFETIME: %d " + "kbytes\n", value); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "lifetime data received without " + "lifetime data type.\n"); + return -1; + } + break; + } + + 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; +} diff --git a/src/racoon/ipsec_doi.c b/src/racoon/ipsec_doi.c index d0d289b..5890314 100644 --- a/src/racoon/ipsec_doi.c +++ b/src/racoon/ipsec_doi.c @@ -1,11 +1,11 @@ -/* $NetBSD: ipsec_doi.c,v 1.23.4.10 2009/06/19 07:32:52 tteras Exp $ */ +/* $NetBSD: ipsec_doi.c,v 1.46 2010/12/14 17:57:31 tteras Exp $ */ /* Id: ipsec_doi.c,v 1.55 2006/08/17 09:20:41 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -83,9 +83,6 @@ #ifdef ENABLE_NATT #include "nattraversal.h" #endif -#ifdef ENABLE_HYBRID -static int switch_authmethod(int); -#endif #ifdef HAVE_GSSAPI #include <iconv.h> @@ -97,19 +94,19 @@ static int switch_authmethod(int); #endif #endif -int verbose_proposal_check = 1; +static vchar_t *get_ph1approval __P((struct ph1handle *, u_int32_t, u_int32_t, + struct prop_pair **)); +static int get_ph1approvalx __P((struct remoteconf *, void *)); -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 t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *, u_int32_t)); 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 struct prop_pair ** get_proppair_and_doi_sit __P((vchar_t *, int, + u_int32_t *, u_int32_t *)); static int get_transform __P((struct isakmp_pl_p *, struct prop_pair **, int *)); @@ -158,12 +155,10 @@ 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 +struct ph1approvalx_ctx { + struct prop_pair *p; + struct isakmpsa *sa; +}; /*%%%*/ /* @@ -182,40 +177,82 @@ ipsecdoi_checkph1proposal(sa, iph1) { vchar_t *newsa; /* new SA payload approved. */ struct prop_pair **pair; + u_int32_t doitype, sittype; /* get proposal pair */ - pair = get_proppair(sa, IPSECDOI_TYPE_PH1); + pair = get_proppair_and_doi_sit(sa, IPSECDOI_TYPE_PH1, + &doitype, &sittype); if (pair == NULL) return -1; /* check and get one SA for use */ - newsa = get_ph1approval(iph1, pair); - + newsa = get_ph1approval(iph1, doitype, sittype, pair); free_proppair(pair); if (newsa == NULL) return -1; iph1->sa_ret = newsa; - return 0; } +static void +print_ph1proposal(pair, s) + struct prop_pair *pair; + struct isakmpsa *s; +{ + struct isakmp_pl_p *prop = pair->prop; + struct isakmp_pl_t *trns = pair->trns; + + 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)); + plog(LLV_DEBUG, LOCATION, NULL, + " lifetime = %ld\n", (long) s->lifetime); + plog(LLV_DEBUG, LOCATION, NULL, + " lifebyte = %zu\n", s->lifebyte); + plog(LLV_DEBUG, LOCATION, NULL, + " enctype = %s\n", + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, s->enctype)); + plog(LLV_DEBUG, LOCATION, NULL, + " encklen = %d\n", s->encklen); + plog(LLV_DEBUG, LOCATION, NULL, + " hashtype = %s\n", + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, s->hashtype)); + plog(LLV_DEBUG, LOCATION, NULL, + " authmethod = %s\n", + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, s->authmethod)); + plog(LLV_DEBUG, LOCATION, NULL, + " dh_group = %s\n", + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, s->dh_group)); +} + + /* * acceptable check for remote configuration. * return a new SA payload to be reply to peer. */ + static vchar_t * -get_ph1approval(iph1, pair) +get_ph1approval(iph1, doitype, sittype, pair) struct ph1handle *iph1; + u_int32_t doitype, sittype; struct prop_pair **pair; { vchar_t *newsa; - struct isakmpsa *sa, tsa; + struct ph1approvalx_ctx ctx; struct prop_pair *s, *p; - int prophlen; + struct rmconfselector rmsel; + struct isakmpsa *sa; int i; + memset(&rmsel, 0, sizeof(rmsel)); + rmsel.remote = iph1->remote; + if (iph1->approval) { delisakmpsa(iph1->approval); iph1->approval = NULL; @@ -225,42 +262,35 @@ get_ph1approval(iph1, pair) 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; - } - } - } + struct isakmp_pl_p *prop = p->prop; - /* - * 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); + sa = newisakmpsa(); + ctx.p = p; + ctx.sa = sa; + if (t2isakmpsa(p->trns, sa, + iph1->vendorid_mask) < 0) + continue; + print_ph1proposal(p, sa); + if (iph1->rmconf != NULL) { + if (get_ph1approvalx(iph1->rmconf, &ctx)) + goto found; + } else { + if (enumrmconf(&rmsel, get_ph1approvalx, &ctx)) + goto found; } + delisakmpsa(sa); } } } + plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n"); return NULL; found: + sa = ctx.sa; plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n"); /* check DH group settings */ @@ -277,7 +307,7 @@ found: if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) { sa->dhgrp = NULL; - racoon_free(sa); + delisakmpsa(sa); return NULL; } @@ -286,20 +316,16 @@ saok: if (sa->gssid != NULL) plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n", (int)sa->gssid->l, sa->gssid->v); - if (iph1-> side == INITIATOR) { + 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); + if (sa->gssid != NULL) + iph1->gi_r = vdup(sa->gssid); } else { - if (tsa.gssid != NULL) { - iph1->gi_r = vdup(tsa.gssid); + if (sa->gssid != NULL) { + iph1->gi_r = vdup(sa->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", @@ -307,19 +333,15 @@ saok: if (iph1->gi_r != NULL) plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n", (int)iph1->gi_r->l, iph1->gi_r->v); -#else - iph1->approval = sa; #endif - if(iph1->approval) { - plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n", - s_oakley_attr_method(iph1->approval->authmethod)); - } + plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n", + s_oakley_attr_method(sa->authmethod)); - newsa = get_sabyproppair(p, iph1); - if (newsa == NULL){ - delisakmpsa(iph1->approval); - iph1->approval = NULL; - } + newsa = get_sabyproppair(doitype, sittype, p); + if (newsa == NULL) + delisakmpsa(sa); + else + iph1->approval = sa; return newsa; } @@ -327,228 +349,57 @@ saok: /* * 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; +static int +get_ph1approvalx(rmconf, ctx) + struct remoteconf *rmconf; + void *ctx; { - 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, - s->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; + struct ph1approvalx_ctx *pctx = (struct ph1approvalx_ctx *) ctx; + struct isakmpsa *sa; - case PROP_CHECK_EXACT: - if ((tsap->lifetime != s->lifetime) || - (tsap->lifebyte != s->lifebyte)) - continue; - goto found; - break; + /* do the hard work */ + sa = checkisakmpsa(rmconf->pcheck_level, pctx->sa, rmconf->proposal); + if (sa == NULL) + return 0; - default: - plog(LLV_ERROR, LOCATION, NULL, - "Unexpected proposal_check value\n"); - continue; - break; - } - } - } + /* duplicate and modify the found SA to match proposal */ + sa = dupisakmpsa(sa); -found: - if (tsap->dhgrp != NULL){ - oakley_dhgrp_free(tsap->dhgrp); - tsap->dhgrp = NULL; + switch (rmconf->pcheck_level) { + case PROP_CHECK_OBEY: + sa->lifetime = pctx->sa->lifetime; + sa->lifebyte = pctx->sa->lifebyte; + sa->encklen = pctx->sa->encklen; + break; + case PROP_CHECK_CLAIM: + case PROP_CHECK_STRICT: + if (pctx->sa->lifetime < sa->lifetime) + sa->lifetime = pctx->sa->lifetime; + if (pctx->sa->lifebyte < sa->lifebyte) + sa->lifebyte = pctx->sa->lifebyte; + if (pctx->sa->encklen > sa->encklen) + sa->encklen = pctx->sa->encklen; + break; + default: + break; } - 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; + /* replace the proposal with our approval sa */ + delisakmpsa(pctx->sa); + pctx->sa = sa; - 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); - sa.dhgrp=NULL; - } + return 1; } /* * get ISAKMP data attributes */ static int -t2isakmpsa(trns, sa) +t2isakmpsa(trns, sa, vendorid_mask) struct isakmp_pl_t *trns; struct isakmpsa *sa; + u_int32_t vendorid_mask; { struct isakmp_data *d, *prev; int flag, type; @@ -618,6 +469,11 @@ t2isakmpsa(trns, sa) case OAKLEY_ATTR_AUTH_METHOD: sa->authmethod = ntohs(d->lorv); +#ifdef HAVE_GSSAPI + if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB_REAL && + (vendorid_mask & VENDORID_GSSAPI_MASK)) + sa->authmethod = OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB; +#endif break; case OAKLEY_ATTR_GRP_DESC: @@ -770,7 +626,7 @@ t2isakmpsa(trns, sa) plog(LLV_DEBUG, LOCATION, NULL, "received old-style gss " "id '%.*s' (len %zu)\n", - (int)sa->gssid->l, sa->gssid->v, + (int)sa->gssid->l, sa->gssid->v, sa->gssid->l); error = 0; goto out; @@ -805,7 +661,7 @@ t2isakmpsa(trns, sa) dst = sa->gssid->v; dstleft = len / 2; - rv = iconv(cd, (__iconv_const char **)&src, &srcleft, + rv = iconv(cd, (__iconv_const char **)&src, &srcleft, &dst, &dstleft); if (rv != 0) { if (rv == -1) { @@ -891,9 +747,11 @@ ipsecdoi_selectph2proposal(iph2) { struct prop_pair **pair; struct prop_pair *ret; + u_int32_t doitype, sittype; /* get proposal pair */ - pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + pair = get_proppair_and_doi_sit(iph2->sa, IPSECDOI_TYPE_PH2, + &doitype, &sittype); if (pair == NULL) return -1; @@ -905,7 +763,7 @@ ipsecdoi_selectph2proposal(iph2) /* make a SA to be replayed. */ /* SPI must be updated later. */ - iph2->sa_ret = get_sabyproppair(ret, iph2->ph1); + iph2->sa_ret = get_sabyproppair(doitype, sittype, ret); free_proppair0(ret); if (iph2->sa_ret == NULL) return -1; @@ -929,9 +787,11 @@ ipsecdoi_checkph2proposal(iph2) int i, n, num; int error = -1; vchar_t *sa_ret = NULL; + u_int32_t doitype, sittype; /* get proposal pair of SA sent. */ - spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + spair = get_proppair_and_doi_sit(iph2->sa, IPSECDOI_TYPE_PH2, + &doitype, &sittype); if (spair == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get prop pair.\n"); @@ -972,7 +832,7 @@ ipsecdoi_checkph2proposal(iph2) plog(LLV_WARNING, LOCATION, NULL, "invalid proposal number:%d received.\n", i); } - + if (rpair[n]->tnext != NULL) { plog(LLV_ERROR, LOCATION, NULL, @@ -997,7 +857,7 @@ ipsecdoi_checkph2proposal(iph2) /* make a SA to be replayed. */ sa_ret = iph2->sa_ret; - iph2->sa_ret = get_sabyproppair(p, iph2->ph1); + iph2->sa_ret = get_sabyproppair(doitype, sittype, p); free_proppair0(p); if (iph2->sa_ret == NULL) goto end; @@ -1282,10 +1142,11 @@ free_proppair0(pair) * get proposal pairs from SA payload. * tiny check for proposal payload. */ -struct prop_pair ** -get_proppair(sa, mode) +static struct prop_pair ** +get_proppair_and_doi_sit(sa, mode, doitype, sittype) vchar_t *sa; int mode; + u_int32_t *doitype, *sittype; { struct prop_pair **pair = NULL; int num_p = 0; /* number of proposal for use */ @@ -1307,10 +1168,14 @@ get_proppair(sa, mode) /* check DOI */ if (check_doi(ntohl(sab->doi)) < 0) goto bad; + if (doitype != NULL) + *doitype = ntohl(sab->doi); /* check SITUATION */ if (check_situation(ntohl(sab->sit)) < 0) goto bad; + if (sittype != NULL) + *sittype = ntohl(sab->sit); pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair)); if (pair == NULL) { @@ -1446,6 +1311,15 @@ bad: return NULL; } +struct prop_pair ** +get_proppair(sa, mode) + vchar_t *sa; + int mode; +{ + return get_proppair_and_doi_sit(sa, mode, NULL, NULL); +} + + /* * check transform payload. * OUT: @@ -1560,9 +1434,9 @@ get_transform(prop, pair, num_p) * NOTE: this function make spi value clear. */ vchar_t * -get_sabyproppair(pair, iph1) +get_sabyproppair(doitype, sittype, pair) + u_int32_t doitype, sittype; struct prop_pair *pair; - struct ph1handle *iph1; { vchar_t *newsa; int newtlen; @@ -1588,8 +1462,8 @@ get_sabyproppair(pair, iph1) ((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); + ((struct ipsecdoi_sa_b *)bp)->doi = htonl(doitype); + ((struct ipsecdoi_sa_b *)bp)->sit = htonl(sittype); bp += sizeof(struct ipsecdoi_sa_b); /* create proposal payloads */ @@ -1824,6 +1698,96 @@ ipsecdoi_set_ld(buf) return ld; } +/* + * parse responder-lifetime attributes from payload + */ +int +ipsecdoi_parse_responder_lifetime(notify, lifetime_sec, lifetime_kb) + struct isakmp_pl_n *notify; + u_int32_t *lifetime_sec; + u_int32_t *lifetime_kb; +{ + struct isakmp_data *d; + int flag, type, tlen, ld_type = -1; + u_int16_t lorv; + u_int32_t value; + + tlen = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; + d = (struct isakmp_data *)((char *)(notify + 1) + + notify->spi_size); + + while (tlen >= sizeof(struct isakmp_data)) { + 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)); + + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + ld_type = lorv; + break; + case IPSECDOI_ATTR_SA_LD: + if (flag) + value = lorv; + else if (lorv == 2) + value = ntohs(*(u_int16_t *)(d + 1)); + else if (lorv == 4) + value = ntohl(*(u_int32_t *)(d + 1)); + else { + plog(LLV_ERROR, LOCATION, NULL, + "payload length %d for lifetime " + "data length is unsupported.\n", lorv); + return -1; + } + + switch (ld_type) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + if (lifetime_sec != NULL) + *lifetime_sec = value; + plog(LLV_INFO, LOCATION, NULL, + "received RESPONDER-LIFETIME: %d " + "seconds\n", value); + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + if (lifetime_kb != NULL) + *lifetime_kb = value; + plog(LLV_INFO, LOCATION, NULL, + "received RESPONDER-LIFETIME: %d " + "kbytes\n", value); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "lifetime data received without " + "lifetime data type.\n"); + return -1; + } + break; + } + + 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 DOI @@ -2130,11 +2094,12 @@ check_attr_isakmp(trns) #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: -#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */ - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: #endif +#if defined(ENABLE_HYBRID) || defined(HAVE_GSSAPI) + /* These two authentication method IDs overlap. */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: + /*case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:*/ #endif - case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: break; case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: #ifdef ENABLE_HYBRID @@ -2351,7 +2316,7 @@ ahmismatch: 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) { @@ -2638,7 +2603,8 @@ check_attr_ipcomp(trns) * NOT INCLUDING isakmp general header of SA payload */ vchar_t * -ipsecdoi_setph1proposal(props) +ipsecdoi_setph1proposal(rmconf, props) + struct remoteconf *rmconf; struct isakmpsa *props; { vchar_t *mysa; @@ -2658,8 +2624,8 @@ ipsecdoi_setph1proposal(props) /* 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); + ((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(rmconf->doitype); + ((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(rmconf->sittype); (void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b)); @@ -2767,7 +2733,7 @@ setph1attr(sa, buf) OAKLEY_ATTR_SA_LD_TYPE_SEC); if (sa->lifetime > 0xffff) { p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD, - (caddr_t)&lifetime, + (caddr_t)&lifetime, sizeof(lifetime)); } else { p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD, @@ -2778,7 +2744,7 @@ setph1attr(sa, buf) 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) @@ -2810,11 +2776,8 @@ setph1attr(sa, buf) if (sa->authmethod) { int authmethod; -#ifdef ENABLE_HYBRID - authmethod = switch_authmethod(sa->authmethod); -#else - authmethod = sa->authmethod; -#endif + authmethod = isakmpsa_switch_authmethod(sa->authmethod); + authmethod &= 0xffff; attrlen += sizeof(struct isakmp_data); if (buf) p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod); @@ -2896,7 +2859,7 @@ setph1attr(sa, buf) goto gssid_done; } odst = dst; - rv = iconv(cd, (__iconv_const char **)&src, + rv = iconv(cd, (__iconv_const char **)&src, &srcleft, &dst, &dstleft); if (rv != 0) { if (rv == -1) { @@ -2989,7 +2952,7 @@ setph2proposal0(iph2, pp, pr) np_t = NULL; for (tr = pr->head; tr; tr = tr->next) { - + switch (pr->proto_id) { case IPSECDOI_PROTO_IPSEC_ESP: /* @@ -3237,7 +3200,9 @@ ipsecdoi_transportmode(pp) for (; pp; pp = pp->next) { for (pr = pp->head; pr; pr = pr->next) { - if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS) + if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS && + pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC && + pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT) return 0; } } @@ -3597,8 +3562,6 @@ 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, @@ -3614,7 +3577,6 @@ ipsecdoi_checkid1(iph1) id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; -#ifndef ANDROID_PATCHED /* In main mode with pre-shared key, only address type can be used. */ if (iph1->etype == ISAKMP_ETYPE_IDENT && iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY) { @@ -3626,7 +3588,6 @@ ipsecdoi_checkid1(iph1) return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } } -#endif /* if proper type for phase 1 ? */ switch (id_b->type) { @@ -3670,73 +3631,12 @@ ipsecdoi_checkid1(iph1) } } - /* 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 = iph1->id_p->v + sizeof(*id_b); - ident.l = iph1->id_p->l - sizeof(*id_b); - 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); - } + /* resolve remote configuration if not done yet */ + if (resolveph1rmconf(iph1) < 0) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + + if (iph1->rmconf == NULL) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; return 0; } @@ -3763,15 +3663,15 @@ ipsecdoi_setid1(iph1) switch (iph1->rmconf->idvtype) { case IDTYPE_FQDN: id_b.type = IPSECDOI_ID_FQDN; - ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + ident = vdup(iph1->rmconf->idv); break; case IDTYPE_USERFQDN: id_b.type = IPSECDOI_ID_USER_FQDN; - ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + ident = vdup(iph1->rmconf->idv); break; case IDTYPE_KEYID: id_b.type = IPSECDOI_ID_KEY_ID; - ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + ident = vdup(iph1->rmconf->idv); break; case IDTYPE_ASN1DN: id_b.type = IPSECDOI_ID_DER_ASN1_DN; @@ -3784,7 +3684,7 @@ ipsecdoi_setid1(iph1) "failed to get own CERT.\n"); goto err; } - ident = eay_get_x509asn1subjectname(&iph1->cert->cert); + ident = eay_get_x509asn1subjectname(iph1->cert); } break; case IDTYPE_ADDRESS: @@ -3829,7 +3729,7 @@ ipsecdoi_setid1(iph1) if (!ident) { plog(LLV_ERROR, LOCATION, NULL, "failed to get ID buffer.\n"); - return 0; + return -1; } memcpy(ident->v, p, ident->l); } @@ -3837,7 +3737,7 @@ ipsecdoi_setid1(iph1) if (!ident) { plog(LLV_ERROR, LOCATION, NULL, "failed to get ID buffer.\n"); - return 0; + return -1; } ret = vmalloc(sizeof(id_b) + ident->l); @@ -3865,21 +3765,6 @@ err: 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) @@ -3922,9 +3807,9 @@ set_identifier_qual(vpp, type, value, qual) memcpy(new->v, value->v, new->l); break; case IDTYPE_KEYID: - /* + /* * If no qualifier is specified: IDQUAL_UNSPEC. It means - * to use a file for backward compatibility sake. + * to use a file for backward compatibility sake. */ switch(qual) { case IDQUAL_FILE: @@ -3969,7 +3854,7 @@ set_identifier_qual(vpp, type, value, qual) return -1; } break; - + case IDTYPE_ADDRESS: { struct sockaddr *sa; @@ -4013,7 +3898,7 @@ set_identifier_qual(vpp, type, value, qual) 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]; @@ -4053,8 +3938,25 @@ ipsecdoi_setid2(iph2) return -1; } - iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src, - sp->spidx.prefs, sp->spidx.ul_proto); + if (!ipsecdoi_transportmode(iph2->proposal)) + iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + else if (iph2->sa_src != NULL) { + /* He have a specific hint indicating that the transport + * mode SA will be negotiated using addresses that differ + * with the one from the SA. We need to indicate that to + * our peer by setting the SA address as ID. + * This is typically the case for the bootstrapping of the + * transport mode SA protecting BU/BA for MIPv6 traffic + * + * --arno*/ + iph2->id = ipsecdoi_sockaddr2id(iph2->sa_src, + IPSECDOI_PREFIX_HOST, + sp->spidx.ul_proto); + } else + iph2->id = ipsecdoi_sockaddr2id(iph2->src, IPSECDOI_PREFIX_HOST, + sp->spidx.ul_proto); + if (iph2->id == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get ID for %s\n", @@ -4065,8 +3967,18 @@ ipsecdoi_setid2(iph2) s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type)); /* remote side */ - iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst, + if (!ipsecdoi_transportmode(iph2->proposal)) + iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd, sp->spidx.ul_proto); + else if (iph2->sa_dst != NULL) { + /* See comment above for local side. */ + iph2->id_p = ipsecdoi_sockaddr2id(iph2->sa_dst, + IPSECDOI_PREFIX_HOST, + sp->spidx.ul_proto); + } else + iph2->id_p = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST, + sp->spidx.ul_proto); + if (iph2->id_p == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get ID for %s\n", @@ -4103,7 +4015,7 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) switch (saddr->sa_family) { case AF_INET: len1 = sizeof(struct in_addr); - if (prefixlen == (sizeof(struct in_addr) << 3)) { + if (prefixlen >= (sizeof(struct in_addr) << 3)) { type = IPSECDOI_ID_IPV4_ADDR; len2 = 0; } else { @@ -4116,7 +4028,7 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) #ifdef INET6 case AF_INET6: len1 = sizeof(struct in6_addr); - if (prefixlen == (sizeof(struct in6_addr) << 3)) { + if (prefixlen >= (sizeof(struct in6_addr) << 3)) { type = IPSECDOI_ID_IPV6_ADDR; len2 = 0; } else { @@ -4161,7 +4073,7 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) /* set prefix */ if (len2) { - u_char *p = (unsigned char *) new->v + + u_char *p = (unsigned char *) new->v + sizeof(struct ipsecdoi_id_b) + len1; u_int bits = prefixlen; @@ -4232,10 +4144,10 @@ ipsecdoi_sockrange2id(laddr, haddr, ul_proto) port = ((struct sockaddr_in *)(laddr))->sin_port; ((struct ipsecdoi_id_b *)new->v)->port = port == IPSEC_PORT_ANY ? 0 : port; - memcpy(new->v + sizeof(struct ipsecdoi_id_b), - (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, + memcpy(new->v + sizeof(struct ipsecdoi_id_b), + (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, len1); - memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, + memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr, len2); return new; @@ -4254,9 +4166,14 @@ ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) u_int8_t *prefixlen; u_int16_t *ul_proto; { - struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v; + struct ipsecdoi_id_b *id_b = NULL; u_int plen = 0; + if (buf == NULL) + return ISAKMP_INTERNAL_ERROR; + + id_b = (struct ipsecdoi_id_b *)buf->v; + /* * When a ID payload of subnet type with a IP address of full bit * masked, it has to be processed as host address. @@ -4291,6 +4208,11 @@ ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) : id_b->port); /* see sockaddr2id() */ memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr, buf->v + sizeof(*id_b), sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)saddr)->sin6_scope_id = + (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)saddr)->sin6_addr) + ? ((struct sockaddr_in6 *)id_b)->sin6_scope_id + : 0); + break; #endif default: @@ -4384,29 +4306,20 @@ ipsecdoi_id2str(id) char *dat; static char buf[BUFLEN]; struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)id->v; - struct sockaddr_storage saddr_storage; - struct sockaddr *saddr; - struct sockaddr_in *saddr_in; - struct sockaddr_in6 *saddr_in6; + union sockaddr_any saddr; u_int plen = 0; - saddr = (struct sockaddr *)&saddr_storage; - saddr_in = (struct sockaddr_in *)&saddr_storage; - saddr_in6 = (struct sockaddr_in6 *)&saddr_storage; - - switch (id_b->type) { case IPSECDOI_ID_IPV4_ADDR: case IPSECDOI_ID_IPV4_ADDR_SUBNET: case IPSECDOI_ID_IPV4_ADDR_RANGE: #ifndef __linux__ - saddr->sa_len = sizeof(struct sockaddr_in); + saddr.sa.sa_len = sizeof(struct sockaddr_in); #endif - saddr->sa_family = AF_INET; - - saddr_in->sin_port = IPSEC_PORT_ANY; - memcpy(&saddr_in->sin_addr, + saddr.sa.sa_family = AF_INET; + saddr.sin.sin_port = IPSEC_PORT_ANY; + memcpy(&saddr.sin.sin_addr, id->v + sizeof(*id_b), sizeof(struct in_addr)); break; #ifdef INET6 @@ -4415,15 +4328,14 @@ ipsecdoi_id2str(id) case IPSECDOI_ID_IPV6_ADDR_RANGE: #ifndef __linux__ - saddr->sa_len = sizeof(struct sockaddr_in6); + saddr.sa.sa_len = sizeof(struct sockaddr_in6); #endif - saddr->sa_family = AF_INET6; - - saddr_in6->sin6_port = IPSEC_PORT_ANY; - memcpy(&saddr_in6->sin6_addr, + saddr.sa.sa_family = AF_INET6; + saddr.sin6.sin6_port = IPSEC_PORT_ANY; + memcpy(&saddr.sin6.sin6_addr, id->v + sizeof(*id_b), sizeof(struct in6_addr)); - saddr_in6->sin6_scope_id = - (IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr) + saddr.sin6.sin6_scope_id = + (IN6_IS_ADDR_LINKLOCAL(&saddr.sin6.sin6_addr) ? ((struct sockaddr_in6 *)id_b)->sin6_scope_id : 0); break; @@ -4435,7 +4347,7 @@ ipsecdoi_id2str(id) #ifdef INET6 case IPSECDOI_ID_IPV6_ADDR: #endif - len = snprintf( buf, BUFLEN, "%s", saddrwop2str(saddr)); + len = snprintf( buf, BUFLEN, "%s", saddrwop2str(&saddr.sa)); break; case IPSECDOI_ID_IPV4_ADDR_SUBNET: @@ -4491,47 +4403,44 @@ ipsecdoi_id2str(id) plen += l; } - len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(saddr), plen); + len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(&saddr.sa), plen); } break; case IPSECDOI_ID_IPV4_ADDR_RANGE: - len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr)); + len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(&saddr.sa)); #ifndef __linux__ - saddr->sa_len = sizeof(struct sockaddr_in); + saddr.sa.sa_len = sizeof(struct sockaddr_in); #endif - saddr->sa_family = AF_INET; - saddr_in->sin_port = IPSEC_PORT_ANY; - memcpy(&saddr_in->sin_addr, + saddr.sa.sa_family = AF_INET; + saddr.sin.sin_port = IPSEC_PORT_ANY; + memcpy(&saddr.sin.sin_addr, id->v + sizeof(*id_b) + sizeof(struct in_addr), sizeof(struct in_addr)); - len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr)); - + len += snprintf(buf + len, BUFLEN - len, "%s", saddrwop2str(&saddr.sa)); break; #ifdef INET6 case IPSECDOI_ID_IPV6_ADDR_RANGE: - - len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr)); + len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(&saddr.sa)); #ifndef __linux__ - saddr->sa_len = sizeof(struct sockaddr_in6); + saddr.sa.sa_len = sizeof(struct sockaddr_in6); #endif - saddr->sa_family = AF_INET6; - saddr_in6->sin6_port = IPSEC_PORT_ANY; - memcpy(&saddr_in6->sin6_addr, + saddr.sa.sa_family = AF_INET6; + saddr.sin6.sin6_port = IPSEC_PORT_ANY; + memcpy(&saddr.sin6.sin6_addr, id->v + sizeof(*id_b) + sizeof(struct in6_addr), sizeof(struct in6_addr)); - saddr_in6->sin6_scope_id = - (IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr) + saddr.sin6.sin6_scope_id = + (IN6_IS_ADDR_LINKLOCAL(&saddr.sin6.sin6_addr) ? ((struct sockaddr_in6 *)id_b)->sin6_scope_id : 0); - len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr)); - + len += snprintf(buf + len, BUFLEN - len, "%s", saddrwop2str(&saddr.sa)); break; #endif @@ -4836,24 +4745,12 @@ ipsecdoi_authalg2trnsid(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 + 255, /* IDTYPE_ADDRESS, 4 * it expands into 4 types by another function. */ IPSECDOI_ID_DER_ASN1_DN, /* IDTYPE_ASN1DN, 5 */ }; @@ -4898,39 +4795,3 @@ doi2idtype(doi) } /*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; - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: - authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I; - break; - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: - authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I; - break; - /* Those are not implemented */ - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: - authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_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/src/racoon/ipsec_doi.h b/src/racoon/ipsec_doi.h index 21dd93d..19a861a 100644 --- a/src/racoon/ipsec_doi.h +++ b/src/racoon/ipsec_doi.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_doi.h,v 1.9 2006/12/09 05:52:57 manu Exp $ */ +/* $NetBSD: ipsec_doi.h,v 1.12 2009/03/12 10:57:26 tteras Exp $ */ /* Id: ipsec_doi.h,v 1.15 2006/08/11 16:06:30 vanhu Exp */ @@ -34,6 +34,8 @@ #ifndef _IPSEC_DOI_H #define _IPSEC_DOI_H +#include "isakmp.h" + /* refered to RFC2407 */ #define IPSEC_DOI 1 @@ -197,6 +199,12 @@ struct ipsecdoi_pl_id { #define IPSECDOI_TYPE_PH1 0 #define IPSECDOI_TYPE_PH2 1 +/* + * Prefix that will make ipsecdoi_sockaddr2id() generate address type + * identities without knowning the exact length of address. + */ +#define IPSECDOI_PREFIX_HOST 0xff + struct isakmpsa; struct ipsecdoi_pl_sa; struct saprop; @@ -209,7 +217,11 @@ extern int ipsecdoi_selectph2proposal __P((struct ph2handle *)); extern int ipsecdoi_checkph2proposal __P((struct ph2handle *)); extern struct prop_pair **get_proppair __P((vchar_t *, int)); +#ifdef ANDROID_PATCHED extern vchar_t *get_sabyproppair __P((struct prop_pair *, struct ph1handle *)); +#else +extern vchar_t *get_sabyproppair __P((u_int32_t, u_int32_t, struct prop_pair *)); +#endif extern int ipsecdoi_updatespi __P((struct ph2handle *iph2)); extern vchar_t *get_sabysaprop __P((struct saprop *, vchar_t *)); extern int ipsecdoi_chkcmpids( const vchar_t *, const vchar_t *, int ); @@ -225,7 +237,8 @@ extern char *ipsecdoi_id2str __P((const vchar_t *)); extern vchar_t *ipsecdoi_sockrange2id __P(( struct sockaddr *, struct sockaddr *, u_int)); -extern vchar_t *ipsecdoi_setph1proposal __P((struct isakmpsa *)); +extern vchar_t *ipsecdoi_setph1proposal __P((struct remoteconf *, + struct isakmpsa *)); extern int ipsecdoi_setph2proposal __P((struct ph2handle *)); extern int ipsecdoi_transportmode __P((struct saprop *)); extern int ipsecdoi_get_defaultlifetime __P((void)); @@ -239,5 +252,8 @@ extern int ipsecdoi_authalg2trnsid __P((int)); extern int idtype2doi __P((int)); extern int doi2idtype __P((int)); +extern int ipsecdoi_parse_responder_lifetime __P((struct isakmp_pl_n *notify, + u_int32_t *lifetime_sec, u_int32_t *liftime_kb)); + #endif /* _IPSEC_DOI_H */ diff --git a/src/racoon/isakmp.c b/src/racoon/isakmp.c index 12eb5a0..048ca71 100644 --- a/src/racoon/isakmp.c +++ b/src/racoon/isakmp.c @@ -1,11 +1,11 @@ -/* $NetBSD: isakmp.c,v 1.20.6.13 2008/09/25 09:34:39 vanhu Exp $ */ +/* $NetBSD: isakmp.c,v 1.71 2011/03/15 13:20:14 vanhu Exp $ */ /* Id: isakmp.c,v 1.74 2006/05/07 21:32:59 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -72,6 +72,7 @@ #include "plog.h" #include "sockmisc.h" #include "schedule.h" +#include "session.h" #include "debug.h" #include "remoteconf.h" @@ -88,6 +89,9 @@ #include "pfkey.h" #include "crypto_openssl.h" #include "policy.h" +#include "algorithm.h" +#include "proposal.h" +#include "sainfo.h" #include "isakmp_ident.h" #include "isakmp_agg.h" #include "isakmp_base.h" @@ -116,9 +120,6 @@ # ifndef SOL_UDP # define SOL_UDP 17 # endif -#ifdef ANDROID_CHANGES -#define __linux -#endif # endif /* __linux__ */ # if defined(__NetBSD__) || defined(__FreeBSD__) || \ (defined(__APPLE__) && defined(__MACH__)) @@ -137,34 +138,34 @@ extern caddr_t val2str(const char *, size_t); static int (*ph1exchange[][2][PHASE1ST_MAX]) __P((struct ph1handle *, vchar_t *)) = { /* error */ - { {}, {}, }, + { { 0 }, { 0 }, }, /* Identity Protection exchange */ { { nostate1, ident_i1send, nostate1, ident_i2recv, ident_i2send, - ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, }, + ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, nostate1,}, { nostate1, ident_r1recv, ident_r1send, ident_r2recv, ident_r2send, - ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, }, + ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, nostate1, }, }, /* Aggressive exchange */ { { nostate1, agg_i1send, nostate1, agg_i2recv, agg_i2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, + nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, }, { nostate1, agg_r1recv, agg_r1send, agg_r2recv, agg_r2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, + nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, }, }, /* Base exchange */ { { nostate1, base_i1send, nostate1, base_i2recv, base_i2send, - base_i3recv, base_i3send, nostate1, nostate1, nostate1, }, + base_i3recv, base_i3send, nostate1, nostate1, nostate1, nostate1, }, { nostate1, base_r1recv, base_r1send, base_r2recv, base_r2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, + nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, }, }, }; static int (*ph2exchange[][2][PHASE2ST_MAX]) __P((struct ph2handle *, vchar_t *)) = { /* error */ - { {}, {}, }, + { { 0 }, { 0 }, }, /* Quick mode for IKE */ { { nostate2, nostate2, quick_i1prep, nostate2, quick_i1send, @@ -175,7 +176,7 @@ static int (*ph2exchange[][2][PHASE2ST_MAX]) }; 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 *)); @@ -185,29 +186,35 @@ 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)); +static int isakmp_ph1resend __P((struct ph1handle *)); +static int isakmp_ph2resend __P((struct ph2handle *)); + #ifdef ENABLE_FRAG -static int frag_handler(struct ph1handle *, +static int frag_handler(struct ph1handle *, vchar_t *, struct sockaddr *, struct sockaddr *); #endif /* * isakmp packet handler */ -int -isakmp_handler(so_isakmp) +static int +isakmp_handler(ctx, so_isakmp) + void *ctx; int so_isakmp; { struct isakmp isakmp; union { char buf[sizeof (isakmp) + 4]; u_int32_t non_esp[2]; - char lbuf[sizeof(struct udphdr) + + struct { + struct udphdr udp; #ifdef __linux - sizeof(struct iphdr) + + struct iphdr ip; #else - sizeof(struct ip) + + struct ip ip; #endif - sizeof(isakmp) + 4]; + char buf[sizeof(isakmp) + 4]; + } lbuf; } x; struct sockaddr_storage remote; struct sockaddr_storage local; @@ -243,34 +250,25 @@ isakmp_handler(so_isakmp) /* Lucent IKE in UDP encapsulation */ { - struct udphdr *udp; #ifdef __linux__ - struct iphdr *ip; - - udp = (struct udphdr *)&x.lbuf[0]; - if (ntohs(udp->dest) == 501) { - ip = (struct iphdr *)(x.lbuf + sizeof(*udp)); - extralen += sizeof(*udp) + ip->ihl; + if (ntohs(x.lbuf.udp.dest) == 501) { + extralen += sizeof(x.lbuf.udp) + x.lbuf.ip.ihl; } #else - struct ip *ip; - - udp = (struct udphdr *)&x.lbuf[0]; - if (ntohs(udp->uh_dport) == 501) { - ip = (struct ip *)(x.lbuf + sizeof(*udp)); - extralen += sizeof(*udp) + ip->ip_hl; + if (ntohs(x.lbuf.udp.uh_dport) == 501) { + extralen += sizeof(x.lbuf.udp) + x.lbuf.ip.ip_hl; } #endif - } + } #ifdef ENABLE_NATT - /* we don't know about portchange yet, + /* 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 + /* now we know if there is an extra non-esp marker at the beginning or not */ memcpy ((char *)&isakmp, x.buf + extralen, sizeof (isakmp)); @@ -311,7 +309,7 @@ isakmp_handler(so_isakmp) 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", + "failed to receive isakmp packet: %s\n", strerror (errno)); } goto end; @@ -334,11 +332,11 @@ isakmp_handler(so_isakmp) (len - extralen)); goto end; } - + memcpy (buf->v, tmpbuf->v + extralen, buf->l); len -= extralen; - + if (len != buf->l) { plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, "received invalid length (%d != %zu), why ?\n", @@ -349,7 +347,7 @@ isakmp_handler(so_isakmp) plog(LLV_DEBUG, LOCATION, NULL, "===\n"); plog(LLV_DEBUG, LOCATION, NULL, "%d bytes message received %s\n", - len, saddr2str_fromto("from %s to %s", + len, saddr2str_fromto("from %s to %s", (struct sockaddr *)&remote, (struct sockaddr *)&local)); plogdump(LLV_DEBUG, buf->v, buf->l); @@ -386,8 +384,7 @@ end: vfree(tmpbuf); if (buf != NULL) vfree(buf); - - return(error); + return error; } /* @@ -471,8 +468,8 @@ isakmp_main(msg, remote, local) /* 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))) + ((cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) || + (cmpsaddr(iph1->local, local) != CMPSADDR_MATCH))) { /* prevent memory leak */ racoon_free(iph1->remote); @@ -499,12 +496,12 @@ isakmp_main(msg, remote, local) } /* set the flag to prevent further port floating - (FIXME: should we allow it? E.g. when the NAT gw + (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, + plog (LLV_INFO, LOCATION, NULL, "NAT-T: ports changed to: %s\n", saddr2str_fromto ("%s<->%s", iph1->remote, iph1->local)); @@ -513,7 +510,7 @@ isakmp_main(msg, remote, local) #endif /* must be same addresses in one stream of a phase at least. */ - if (cmpsaddrstrict(iph1->remote, remote) != 0) { + if (cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) { char *saddr_db, *saddr_act; saddr_db = racoon_strdup(saddr2str(iph1->remote)); @@ -639,7 +636,7 @@ isakmp_main(msg, remote, local) "exchange received.\n"); return -1; } - if (cmpsaddrstrict(iph1->remote, remote) != 0) { + if (cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) { plog(LLV_WARNING, LOCATION, remote, "remote address mismatched. " "db=%s\n", @@ -671,7 +668,7 @@ isakmp_main(msg, remote, local) return -1; } #ifdef ENABLE_HYBRID - /* Reinit the IVM if it's still there */ + /* Reinit the IVM if it's still there */ if (iph1->mode_cfg && iph1->mode_cfg->ivm) { oakley_delivm(iph1->mode_cfg->ivm); iph1->mode_cfg->ivm = NULL; @@ -683,7 +680,8 @@ isakmp_main(msg, remote, local) #endif /* check status of phase 1 whether negotiated or not. */ - if (iph1->status != PHASE1ST_ESTABLISHED) { + if (iph1->status != PHASE1ST_ESTABLISHED && + iph1->status != PHASE1ST_DYING) { plog(LLV_ERROR, LOCATION, remote, "can't start the quick mode, " "there is no valid ISAKMP-SA, %s\n", @@ -715,7 +713,6 @@ isakmp_main(msg, remote, local) if (quick_main(iph2, msg) < 0) { plog(LLV_ERROR, LOCATION, iph1->remote, "phase2 negotiation failed.\n"); - unbindph12(iph2); remph2(iph2); delph2(iph2); return -1; @@ -756,7 +753,7 @@ isakmp_main(msg, remote, local) isakmp_cfg_r(iph1, msg); break; -#endif +#endif case ISAKMP_ETYPE_NONE: default: @@ -783,7 +780,7 @@ ph1_main(iph1, msg) #endif /* ignore a packet */ - if (iph1->status == PHASE1ST_ESTABLISHED) + if (iph1->status >= PHASE1ST_ESTABLISHED) return 0; #ifdef ENABLE_STATS @@ -813,7 +810,8 @@ ph1_main(iph1, msg) if (iph1->side == RESPONDER && iph1->status == PHASE1ST_START) { plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to pre-process packet.\n"); + "failed to pre-process ph1 packet (side: %d, status %d).\n", + iph1->side, iph1->status); return -1; } else { /* ignore the error and keep phase 1 handler */ @@ -825,7 +823,7 @@ ph1_main(iph1, msg) /* free resend buffer */ if (iph1->sendbuf == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "no buffer found as sendbuf\n"); + "no buffer found as sendbuf\n"); return -1; } #endif @@ -833,7 +831,7 @@ ph1_main(iph1, msg) VPTRINIT(iph1->sendbuf); /* turn off schedule */ - SCHED_KILL(iph1->scr); + sched_cancel(&iph1->scr); /* send */ plog(LLV_DEBUG, LOCATION, NULL, "===\n"); @@ -841,7 +839,8 @@ ph1_main(iph1, msg) [iph1->side] [iph1->status])(iph1, msg) != 0) { plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to process packet.\n"); + "failed to process ph1 packet (side: %d, status: %d).\n", + iph1->side, iph1->status); return -1; } @@ -863,12 +862,23 @@ ph1_main(iph1, msg) /* save created date. */ (void)time(&iph1->created); + /* migrate ph2s from dying ph1s */ + migrate_dying_ph12(iph1); + /* add to the schedule to expire, and seve back pointer. */ - iph1->sce = sched_new(iph1->approval->lifetime, - isakmp_ph1expire_stub, iph1); + if (ph1_rekey_enabled(iph1)) { + sched_schedule(&iph1->sce, + iph1->approval->lifetime * + PFKEY_SOFT_LIFETIME_RATE / 100, + isakmp_ph1dying_stub); + } else { + sched_schedule(&iph1->sce, iph1->approval->lifetime, + isakmp_ph1expire_stub); + } + #ifdef ENABLE_HYBRID if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) { - switch(AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: @@ -905,18 +915,20 @@ ph1_main(iph1, msg) /* ignore */ } } + if (iph1->initial_contact_received) + isakmp_info_recv_initialcontact(iph1, NULL); log_ph1established(iph1); plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - /* + /* * 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) { - switch (AUTHMETHOD(iph1)) { + !iph1->rmconf->mode_cfg) { + switch (iph1->approval->authmethod) { #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: @@ -974,7 +986,8 @@ quick_main(iph2, msg) [iph2->status])(iph2, msg); if (error != 0) { plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to pre-process packet.\n"); + "failed to pre-process ph2 packet (side: %d, status %d).\n", + iph2->side, iph2->status); if (error == ISAKMP_INTERNAL_ERROR) return 0; isakmp_info_send_n1(iph2->ph1, error, NULL); @@ -988,13 +1001,13 @@ quick_main(iph2, msg) /* free resend buffer */ if (iph2->sendbuf == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "no buffer found as sendbuf\n"); + "no buffer found as sendbuf\n"); return -1; } VPTRINIT(iph2->sendbuf); /* turn off schedule */ - SCHED_KILL(iph2->scr); + sched_cancel(&iph2->scr); /* send */ plog(LLV_DEBUG, LOCATION, NULL, "===\n"); @@ -1002,7 +1015,8 @@ quick_main(iph2, msg) [iph2->side] [iph2->status])(iph2, msg) != 0) { plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to process packet.\n"); + "failed to process ph2 packet (side: %d, status: %d).\n", + iph2->side, iph2->status); return -1; } @@ -1018,7 +1032,7 @@ quick_main(iph2, msg) } /* new negotiation of phase 1 for initiator */ -int +struct ph1handle * isakmp_ph1begin_i(rmconf, remote, local) struct remoteconf *rmconf; struct sockaddr *remote, *local; @@ -1031,7 +1045,7 @@ isakmp_ph1begin_i(rmconf, remote, local) /* get new entry to isakmp status table. */ iph1 = newph1(); if (iph1 == NULL) - return -1; + return NULL; iph1->status = PHASE1ST_START; iph1->rmconf = rmconf; @@ -1046,7 +1060,7 @@ isakmp_ph1begin_i(rmconf, remote, local) #ifdef ENABLE_HYBRID if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) { delph1(iph1); - return -1; + return NULL; } #endif #ifdef ENABLE_FRAG @@ -1062,7 +1076,7 @@ isakmp_ph1begin_i(rmconf, remote, local) /* XXX copy remote address */ if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) { delph1(iph1); - return -1; + return NULL; } (void)insph1(iph1); @@ -1098,7 +1112,7 @@ isakmp_ph1begin_i(rmconf, remote, local) remph1(iph1); delph1(iph1); - return -1; + return NULL; } #ifdef ENABLE_STATS @@ -1109,7 +1123,7 @@ isakmp_ph1begin_i(rmconf, remote, local) timedelta(&start, &end)); #endif - return 0; + return iph1; } /* new negotiation of phase 1 for responder */ @@ -1120,27 +1134,19 @@ isakmp_ph1begin_r(msg, remote, local, etype) u_int8_t etype; { struct isakmp *isakmp = (struct isakmp *)msg->v; - struct remoteconf *rmconf; struct ph1handle *iph1; - struct etypes *etypeok; + struct rmconfselector rmsel; #ifdef ENABLE_STATS struct timeval start, end; #endif - /* look for my configuration */ - rmconf = getrmconf(remote); - if (rmconf == NULL) { + /* check if this etype is allowed */ + memset(&rmsel, 0, sizeof(rmsel)); + rmsel.remote = remote; + if (enumrmconf(&rmsel, check_etypeok, (void *) (intptr_t) etype) == 0) { 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)); + "exchange %s not allowed in any applicable rmconf.\n", + s_isakmp_etype(etype)); return -1; } @@ -1151,10 +1157,9 @@ isakmp_ph1begin_r(msg, remote, local, etype) 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->etype = etype; iph1->version = isakmp->v; iph1->msgid = 0; #ifdef HAVE_GSSAPI @@ -1181,8 +1186,9 @@ isakmp_ph1begin_r(msg, remote, local, etype) iph1->natt_flags |= (NAT_PORTS_CHANGED); #endif - /* copy remote address */ - if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) { + /* copy remote address; remote and local always contain + * port numbers so rmconf is not needed */ + if (copy_ph1addresses(iph1, NULL, remote, local) < 0) { delph1(iph1); return -1; } @@ -1218,7 +1224,8 @@ isakmp_ph1begin_r(msg, remote, local, etype) [iph1->side] [iph1->status])(iph1, msg) < 0) { plog(LLV_ERROR, LOCATION, remote, - "failed to process packet.\n"); + "failed to process ph1 packet (side: %d, status: %d).\n", + iph1->side, iph1->status); remph1(iph1); delph1(iph1); return -1; @@ -1260,6 +1267,12 @@ isakmp_ph2begin_i(iph1, iph2) } #endif + /* fixup ph2 ports for this ph1 */ + if (extract_port(iph2->src) == 0) + set_port(iph2->src, extract_port(iph1->local)); + if (extract_port(iph2->dst) == 0) + set_port(iph2->dst, extract_port(iph1->remote)); + /* found ISAKMP-SA. */ plog(LLV_DEBUG, LOCATION, NULL, "===\n"); plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); @@ -1277,14 +1290,13 @@ isakmp_ph2begin_i(iph1, iph2) #ifdef ENABLE_STATS gettimeofday(&iph2->start, NULL); #endif - /* found isakmp-sa */ - bindph12(iph1, iph2); + if (iph2->status != PHASE2ST_EXPIRED) /* Phase 1 is already bound (ongoing rekeying) */ + 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; @@ -1319,7 +1331,6 @@ isakmp_ph2begin_r(iph1, msg) return -1; } - iph2->ph1 = iph1; iph2->side = RESPONDER; iph2->status = PHASE2ST_START; iph2->flags = isakmp->flags; @@ -1340,15 +1351,6 @@ isakmp_ph2begin_r(iph1, msg) delph2(iph2); return -1; } -#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT)) - if (set_port(iph2->dst, 0) == NULL || - set_port(iph2->src, 0) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph2->dst->sa_family); - delph2(iph2); - return -1; - } -#endif /* add new entry to isakmp status table */ insph2(iph2); @@ -1376,14 +1378,14 @@ isakmp_ph2begin_r(iph1, msg) [iph2->status])(iph2, msg); if (error != 0) { plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to pre-process packet.\n"); + "failed to pre-process ph2 packet (side: %d, status: %d).\n", + iph2->side, iph2->status); 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; @@ -1395,7 +1397,8 @@ isakmp_ph2begin_r(iph1, msg) [iph2->side] [iph2->status])(iph2, msg) < 0) { plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to process packet.\n"); + "failed to process ph2 packet (side: %d, status: %d).\n", + iph2->side, iph2->status); /* don't release handler */ return -1; } @@ -1526,14 +1529,7 @@ isakmp_init() initctdtree(); init_recvdpkt(); - if (isakmp_open() < 0) - goto err; - - return(0); - -err: - isakmp_close(); - return(-1); + return 0; } /* @@ -1572,211 +1568,172 @@ isakmp_pindex(index, msgid) /* open ISAKMP sockets. */ int -isakmp_open() +isakmp_open(struct sockaddr *addr, int udp_encap) { const int yes = 1; - int ifnum = 0, encap_ifnum = 0; + int ifnum = 0, encap_ifnum = 0, fd; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; #ifdef INET6 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; int pktinfo; #endif - struct myaddrs *p; - - for (p = lcconf->myaddrs; p; p = p->next) { - if (!p->addr) - continue; - - /* 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; +#ifdef ENABLE_NATT + int option = -1; #endif - default: - plog(LLV_ERROR, LOCATION, NULL, - "unsupported address family %d\n", - lcconf->default_af); - goto err_and_next; - } + /* warn if wildcard address - should we forbid this? */ + switch (addr->sa_family) { + case AF_INET: + if (sin->sin_addr.s_addr == 0) + plog(LLV_WARNING, LOCATION, NULL, + "listening to wildcard address," + "broadcast IKE packet may kill you\n"); + break; #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; + case AF_INET6: + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignoring multicast address %s\n", + saddr2str(addr)); + return -1; } - if (fcntl(p->sock, F_SETFL, O_NONBLOCK) == -1) + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) plog(LLV_WARNING, LOCATION, NULL, - "failed to put socket in non-blocking mode\n"); + "listening to wildcard address, " + "broadcast IKE packet may kill you\n"); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported address family %d\n", + addr->sa_family); + return -1; + } - /* receive my interface address on inbound packets. */ - switch (p->addr->sa_family) { - case AF_INET: - if (setsockopt(p->sock, IPPROTO_IP, + if ((fd = privsep_socket(addr->sa_family, SOCK_DGRAM, 0)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(%s)\n", strerror(errno)); + return -1; + } + close_on_exec(fd); + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) + plog(LLV_WARNING, LOCATION, NULL, + "failed to put socket in non-blocking mode\n"); + + /* receive my interface address on inbound packets. */ + switch (addr->sa_family) { + case AF_INET: + if (setsockopt(fd, IPPROTO_IP, #ifdef __linux__ - IP_PKTINFO, + IP_PKTINFO, #else - IP_RECVDSTADDR, + IP_RECVDSTADDR, #endif - (const void *)&yes, sizeof(yes)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "setsockopt IP_RECVDSTADDR (%s)\n", - strerror(errno)); - goto err_and_next; - } + (const void *) &yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt IP_RECVDSTADDR (%s)\n", + strerror(errno)); + goto err; + } + +#ifdef ENABLE_NATT + if (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) break; + + if (setsockopt(fd, SOL_UDP, + UDP_ENCAP, &option, + sizeof(option)) < 0) { + plog(LLV_WARNING, LOCATION, NULL, + "setsockopt(%s): UDP_ENCAP %s\n", + option == UDP_ENCAP_ESPINUDP ? "UDP_ENCAP_ESPINUDP" : "UDP_ENCAP_ESPINUDP_NON_IKE", + strerror(errno)); + } else { + plog(LLV_INFO, LOCATION, NULL, + "%s used for NAT-T\n", + saddr2str(addr)); + } +#endif + break; + #ifdef INET6 - case AF_INET6: -#ifdef INET6_ADVAPI + case AF_INET6: +#if defined(INET6_ADVAPI) #ifdef IPV6_RECVPKTINFO - pktinfo = IPV6_RECVPKTINFO; + pktinfo = IPV6_RECVPKTINFO; #else /* old adv. API */ - pktinfo = IPV6_PKTINFO; + 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 IPV6_RECVDSTADDR (%d):%s\n", - pktinfo, strerror(errno)); - goto err_and_next; - } - break; + pktinfo = IPV6_RECVDSTADDR; #endif + if (setsockopt(fd, IPPROTO_IPV6, pktinfo, + (const void *) &yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt IPV6_RECVDSTADDR (%d):%s\n", + pktinfo, strerror(errno)); + goto err; } #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) { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *) &yes, sizeof(yes)) < 0) { plog(LLV_ERROR, LOCATION, NULL, - "setsockopt IPV6_USE_MIN_MTU (%s)\n", - strerror(errno)); - return -1; + "setsockopt IPV6_USE_MIN_MTU (%s)\n", + strerror(errno)); + goto err; } #endif - - if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0) - goto err_and_next; - - 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); - goto err_and_next; - } - - ifnum++; - - plog(LLV_INFO, LOCATION, NULL, - "%s used as isakmp port (fd=%d)\n", - saddr2str(p->addr), p->sock); - -#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): UDP_ENCAP %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: + break; #endif - continue; - - err_and_next: - racoon_free(p->addr); - p->addr = NULL; - if (! lcconf->autograbaddr && lcconf->strict_address) - return -1; - continue; } - if (!ifnum) { + if (setsockopt(fd, SOL_SOCKET, +#ifdef __linux__ + SO_REUSEADDR, +#else + SO_REUSEPORT, +#endif + (void *) &yes, sizeof(yes)) < 0) { plog(LLV_ERROR, LOCATION, NULL, - "no address could be bound.\n"); - return -1; + "failed to set REUSE flag on %s (%s).\n", + saddr2str(addr), strerror(errno)); + goto err; } -#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"); + if (setsockopt_bypass(fd, addr->sa_family) < 0) + goto err; + + if (privsep_bind(fd, addr, sysdep_sa_len(addr)) < 0) { + plog(LLV_ERROR, LOCATION, addr, + "failed to bind to address %s (%s).\n", + saddr2str(addr), strerror(errno)); + goto err; } -#endif - return 0; + plog(LLV_INFO, LOCATION, NULL, + "%s used as isakmp port (fd=%d)\n", + saddr2str(addr), fd); + + monitor_fd(fd, isakmp_handler, NULL, 1); + return fd; + +err: + close(fd); + return -1; } void -isakmp_close() +isakmp_close(int fd) { -#ifndef ANDROID_PATCHED - struct myaddrs *p, *next; - - for (p = lcconf->myaddrs; p; p = next) { - next = p->next; - - if (!p->addr) { - racoon_free(p); - continue; - } - close(p->sock); - racoon_free(p->addr); - racoon_free(p); - } - - lcconf->myaddrs = NULL; -#endif + unmonitor_fd(fd); + close(fd); } int @@ -1798,23 +1755,23 @@ isakmp_send(iph1, sbuf) extralen = 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 + * 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) + 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 + /* 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) { if ((vbuf = vmalloc (sbuf->l + extralen)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(LLV_ERROR, LOCATION, NULL, "vbuf allocation failed\n"); return -1; } @@ -1831,22 +1788,21 @@ isakmp_send(iph1, sbuf) #endif /* select the socket to be sent */ - s = getsockmyaddr(iph1->local); - if (s == -1){ + s = myaddr_getfd(iph1->local); + if (s == -1) return -1; - } - plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l, + 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, + plog(LLV_ERROR, LOCATION, NULL, "isakmp_sendfrags failed\n"); return -1; } - } else + } else #endif { len = sendfromto(s, sbuf->v, sbuf->l, @@ -1857,32 +1813,24 @@ isakmp_send(iph1, sbuf) return -1; } } - + return 0; } /* called from scheduler */ -void +static void isakmp_ph1resend_stub(p) - void *p; + struct sched *p; { - struct ph1handle *iph1; - - iph1=(struct ph1handle *)p; - if(isakmp_ph1resend(iph1) < 0){ - if(iph1->scr != NULL){ - /* Should not happen... - */ - sched_kill(iph1->scr); - iph1->scr=NULL; - } + struct ph1handle *iph1 = container_of(p, struct ph1handle, scr); + if (isakmp_ph1resend(iph1) < 0) { remph1(iph1); delph1(iph1); } } -int +static int isakmp_ph1resend(iph1) struct ph1handle *iph1; { @@ -1892,8 +1840,9 @@ isakmp_ph1resend(iph1) 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); + /* XXX is the peer really "dead" here ??? */ + script_hook(iph1, SCRIPT_PHASE1_DEAD); + evt_phase1(iph1, EVT_PHASE1_NO_RESPONSE, NULL); return -1; } @@ -1902,8 +1851,7 @@ isakmp_ph1resend(iph1) plog(LLV_ERROR, LOCATION, NULL, "phase1 negotiation failed due to send error. %s\n", isakmp_pindex(&iph1->index, iph1->msgid)); - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEER_NO_RESPONSE, NULL); + evt_phase1(iph1, EVT_PHASE1_NO_RESPONSE, NULL); return -1; } @@ -1913,35 +1861,40 @@ isakmp_ph1resend(iph1) iph1->retry_counter--; - iph1->scr = sched_new(iph1->rmconf->retry_interval, - isakmp_ph1resend_stub, iph1); + sched_schedule(&iph1->scr, lcconf->retry_interval, + isakmp_ph1resend_stub); return 0; } +int +isakmp_ph1send(iph1) + struct ph1handle *iph1; +{ + iph1->retry_counter = lcconf->retry_counter; + return isakmp_ph1resend(iph1); +} + /* called from scheduler */ -void +static void isakmp_ph2resend_stub(p) - void *p; + struct sched *p; { - struct ph2handle *iph2; - - iph2=(struct ph2handle *)p; + struct ph2handle *iph2 = container_of(p, struct ph2handle, scr); - if(isakmp_ph2resend(iph2) < 0){ - unbindph12(iph2); + if (isakmp_ph2resend(iph2) < 0) { remph2(iph2); delph2(iph2); } } -int +static int isakmp_ph2resend(iph2) struct ph2handle *iph2; { /* Note: NEVER do the unbind/rem/del here, it will be done by the caller or by the _stub function */ - if (iph2->ph1->status == PHASE1ST_EXPIRED){ + if (iph2->ph1->status >= PHASE1ST_EXPIRED) { plog(LLV_ERROR, LOCATION, NULL, "phase2 negotiation failed due to phase1 expired. %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); @@ -1952,7 +1905,7 @@ isakmp_ph2resend(iph2) 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); + evt_phase2(iph2, EVT_PHASE2_NO_RESPONSE, NULL); unbindph12(iph2); return -1; } @@ -1961,8 +1914,7 @@ isakmp_ph2resend(iph2) plog(LLV_ERROR, LOCATION, NULL, "phase2 negotiation failed due to send error. %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); - EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL); - + evt_phase2(iph2, EVT_PHASE2_NO_RESPONSE, NULL); return -1; } @@ -1972,19 +1924,77 @@ isakmp_ph2resend(iph2) iph2->retry_counter--; - iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval, - isakmp_ph2resend_stub, iph2); + sched_schedule(&iph2->scr, lcconf->retry_interval, + isakmp_ph2resend_stub); return 0; } +int +isakmp_ph2send(iph2) + struct ph2handle *iph2; +{ + iph2->retry_counter = lcconf->retry_counter; + return isakmp_ph2resend(iph2); +} + /* called from scheduler */ void -isakmp_ph1expire_stub(p) - void *p; +isakmp_ph1dying_stub(p) + struct sched *p; +{ + + isakmp_ph1dying(container_of(p, struct ph1handle, sce)); +} + +void +isakmp_ph1dying(iph1) + struct ph1handle *iph1; { + struct ph1handle *new_iph1; + struct ph2handle *p; + struct remoteconf *rmconf; + + if (iph1->status >= PHASE1ST_DYING) + return; + + /* Going away in after a while... */ + iph1->status = PHASE1ST_DYING; + + /* Any fresh phase1s? */ + new_iph1 = getph1(iph1, iph1->local, iph1->remote, 1); + if (new_iph1 == NULL) { + LIST_FOREACH(p, &iph1->ph2tree, ph1bind) { + if (p->status != PHASE2ST_ESTABLISHED) + continue; + + plog(LLV_INFO, LOCATION, NULL, + "renegotiating phase1 to %s due to " + "active phase2\n", + saddrwop2str(iph1->remote)); - isakmp_ph1expire((struct ph1handle *)p); + if (iph1->side == INITIATOR) + isakmp_ph1begin_i(iph1->rmconf, iph1->remote, + iph1->local); + + break; + } + } else { + migrate_ph12(iph1, new_iph1); + } + + /* Schedule for expiration */ + sched_schedule(&iph1->sce, iph1->approval->lifetime * + (100 - PFKEY_SOFT_LIFETIME_RATE) / 100, + isakmp_ph1expire_stub); +} + +/* called from scheduler */ +void +isakmp_ph1expire_stub(p) + struct sched *p; +{ + isakmp_ph1expire(container_of(p, struct ph1handle, sce)); } void @@ -1993,9 +2003,7 @@ isakmp_ph1expire(iph1) { char *src, *dst; - SCHED_KILL(iph1->sce); - - if(iph1->status != PHASE1ST_EXPIRED){ + if (iph1->status < PHASE1ST_EXPIRED) { src = racoon_strdup(saddr2str(iph1->local)); dst = racoon_strdup(saddr2str(iph1->remote)); STRDUP_FATAL(src); @@ -2010,41 +2018,44 @@ isakmp_ph1expire(iph1) 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); + isakmp_ph1delete(iph1); } /* called from scheduler */ void isakmp_ph1delete_stub(p) - void *p; + struct sched *p; { - isakmp_ph1delete((struct ph1handle *)p); + isakmp_ph1delete(container_of(p, struct ph1handle, sce)); } void isakmp_ph1delete(iph1) struct ph1handle *iph1; { + struct ph2handle *p, *next; + struct ph1handle *new_iph1; char *src, *dst; - SCHED_KILL(iph1->sce); - - if (LIST_FIRST(&iph1->ph2tree) != NULL) { - iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); - return; + /* Migrate established phase2s. Any fresh phase1s? */ + new_iph1 = getph1(iph1, iph1->local, iph1->remote, 1); + if (new_iph1 != NULL) + migrate_ph12(iph1, new_iph1); + + /* Discard any left phase2s */ + for (p = LIST_FIRST(&iph1->ph2tree); p; p = next) { + next = LIST_NEXT(p, ph1bind); + if (p->status == PHASE2ST_ESTABLISHED) + isakmp_info_send_d2(p); + /* remove all ph2 handles, + * as ph1handle will be expired soon + */ + delete_spd(p, 1); + remph2(p); + delph2(p); } - /* don't re-negosiation when the phase 1 SA expires. */ - src = racoon_strdup(saddr2str(iph1->local)); dst = racoon_strdup(saddr2str(iph1->remote)); STRDUP_FATAL(src); @@ -2053,14 +2064,16 @@ isakmp_ph1delete(iph1) 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); + + evt_phase1(iph1, EVT_PHASE1_DOWN, NULL); + if (new_iph1 == NULL && ph1_rekey_enabled(iph1)) + script_hook(iph1, SCRIPT_PHASE1_DEAD); + racoon_free(src); racoon_free(dst); remph1(iph1); delph1(iph1); - - return; } /* called from scheduler. @@ -2071,10 +2084,10 @@ isakmp_ph1delete(iph1) */ void isakmp_ph2expire_stub(p) - void *p; + struct sched *p; { - isakmp_ph2expire((struct ph2handle *)p); + isakmp_ph2expire(container_of(p, struct ph2handle, sce)); } void @@ -2083,8 +2096,6 @@ isakmp_ph2expire(iph2) { char *src, *dst; - SCHED_KILL(iph2->sce); - src = racoon_strdup(saddrwop2str(iph2->src)); dst = racoon_strdup(saddrwop2str(iph2->dst)); STRDUP_FATAL(src); @@ -2096,19 +2107,16 @@ isakmp_ph2expire(iph2) racoon_free(dst); iph2->status = PHASE2ST_EXPIRED; - - iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2); - - return; + sched_schedule(&iph2->sce, 1, isakmp_ph2delete_stub); } /* called from scheduler */ void isakmp_ph2delete_stub(p) - void *p; + struct sched *p; { - isakmp_ph2delete((struct ph2handle *)p); + isakmp_ph2delete(container_of(p, struct ph2handle, sce)); } void @@ -2117,8 +2125,6 @@ isakmp_ph2delete(iph2) { char *src, *dst; - SCHED_KILL(iph2->sce); - src = racoon_strdup(saddrwop2str(iph2->src)); dst = racoon_strdup(saddrwop2str(iph2->dst)); STRDUP_FATAL(src); @@ -2129,7 +2135,6 @@ isakmp_ph2delete(iph2) racoon_free(src); racoon_free(dst); - unbindph12(iph2); remph2(iph2); delph2(iph2); @@ -2144,25 +2149,39 @@ isakmp_ph2delete(iph2) * if phase1 has been finished, begin phase2. */ int -isakmp_post_acquire(iph2) +isakmp_post_acquire(iph2, iph1hint, nopassive) struct ph2handle *iph2; + struct ph1handle *iph1hint; + int nopassive; { struct remoteconf *rmconf; struct ph1handle *iph1 = NULL; - + plog(LLV_DEBUG, LOCATION, NULL, "in post_acquire\n"); - /* 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; + /* Search appropriate configuration with masking port. Note that + * we always use iph2->dst, and not iph2->sa_dst. + * + * XXX One possible need for using iph2->sa_dst if not NULL would + * be for selecting a remote configuration based on a stable + * address of a mobile node (not a CoA provided by MIGRATE/KMADDRESS + * as iph2->dst hint). This scenario would require additional changes, + * so no need to bother yet. --arno */ + + if (iph1hint == NULL || iph1hint->rmconf == NULL) { + rmconf = getrmconf(iph2->dst, nopassive ? GETRMCONF_F_NO_PASSIVE : 0); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no configuration found for %s.\n", + saddrwop2str(iph2->dst)); + return -1; + } + } else { + rmconf = iph1hint->rmconf; } /* if passive mode, ignore the acquire message */ - if (rmconf->passive) { + if (nopassive && rmconf->passive) { plog(LLV_DEBUG, LOCATION, NULL, "because of passive mode, " "ignore the acquire message for %s.\n", @@ -2170,38 +2189,25 @@ isakmp_post_acquire(iph2) 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. + /* + * XXX Searching by IP addresses + ports might fail on + * some cases, we should use the ISAKMP identity to search + * matching ISAKMP. */ -#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, 0); - } -#else - iph1 = getph1byaddr(iph2->src, iph2->dst, 0); -#endif + iph1 = getph1(iph1hint, iph2->src, iph2->dst, 0); /* no ISAKMP-SA found. */ if (iph1 == NULL) { - struct sched *sc; - iph2->retry_checkph1 = lcconf->retry_checkph1; - sc = sched_new(1, isakmp_chkph1there_stub, iph2); + sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub); 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); + if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src) == NULL) { + sched_cancel(&iph2->sce); return -1; } @@ -2210,9 +2216,9 @@ isakmp_post_acquire(iph2) } /* found ISAKMP-SA, but on negotiation. */ - if (iph1->status != PHASE1ST_ESTABLISHED) { + if (iph1->status < PHASE1ST_ESTABLISHED) { iph2->retry_checkph1 = lcconf->retry_checkph1; - sched_new(1, isakmp_chkph1there_stub, iph2); + sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub); plog(LLV_INFO, LOCATION, iph2->dst, "request for establishing IPsec-SA was queued " "due to no phase1 found.\n"); @@ -2233,6 +2239,69 @@ isakmp_post_acquire(iph2) return 0; } +int +isakmp_get_sainfo(iph2, sp_out, sp_in) + struct ph2handle *iph2; + struct secpolicy *sp_out, *sp_in; +{ + struct remoteconf *conf; + uint32_t remoteid = 0; + + 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)); + 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); + return -1; + } + + conf = getrmconf(iph2->dst, 0); + if (conf != NULL) + remoteid = conf->ph1id; + else + plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n"); + + iph2->sainfo = getsainfo(idsrc, iddst, NULL, NULL, remoteid); + vfree(idsrc); + vfree(iddst); + if (iph2->sainfo == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + return -1; + /* XXX should use the algorithm list from register message */ + } + + plog(LLV_DEBUG, LOCATION, NULL, + "selected sainfo: %s\n", sainfo2str(iph2->sainfo)); + } + + if (set_proposal_from_policy(iph2, sp_out, sp_in) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to create saprop.\n"); + return -1; + } + + return 0; +} + + /* * receive GETSPI from kernel. */ @@ -2245,7 +2314,7 @@ isakmp_post_getspi(iph2) #endif /* don't process it because there is no suitable phase1-sa. */ - if (iph2->ph1->status == PHASE1ST_EXPIRED) { + 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"); @@ -2273,9 +2342,9 @@ isakmp_post_getspi(iph2) /* called by scheduler */ void isakmp_chkph1there_stub(p) - void *p; + struct sched *p; { - isakmp_chkph1there((struct ph2handle *)p); + isakmp_chkph1there(container_of(p, struct ph2handle, sce)); } void @@ -2297,33 +2366,14 @@ isakmp_chkph1there(iph2) /* 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)) { - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: extract_port.\n"); - if( (iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL){ - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found a ph1 wop.\n"); - } - } else { - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: searching byaddr.\n"); - iph1 = getph1byaddr(iph2->src, iph2->dst, 0); - if(iph1 != NULL) - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found byaddr.\n"); - } -#else + /* Search isakmp status table by address and port */ iph1 = getph1byaddr(iph2->src, iph2->dst, 0); -#endif /* XXX Even if ph1 as responder is there, should we not start * phase 2 negotiation ? */ @@ -2351,7 +2401,7 @@ isakmp_chkph1there(iph2) plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: no established ph1 handler found\n"); /* no isakmp-sa found */ - sched_new(1, isakmp_chkph1there_stub, iph2); + sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub); return; } @@ -2874,7 +2924,9 @@ copy_ph1addresses(iph1, rmconf, remote, local) * respect content of "remote". */ if (extract_port(iph1->remote) == 0) { - port = extract_port(rmconf->remote); + port = 0; + if (rmconf != NULL) + port = extract_port(rmconf->remote); if (port == 0) port = PORT_ISAKMP; set_port(iph1->remote, port); @@ -2887,8 +2939,12 @@ copy_ph1addresses(iph1, rmconf, remote, local) if (iph1->local == NULL) return -1; - if (extract_port(iph1->local) == 0) + if (extract_port(iph1->local) == 0) { + port = myaddr_getsport(iph1->local); + if (port == 0) + port = PORT_ISAKMP; set_port(iph1->local, PORT_ISAKMP); + } #ifdef ENABLE_NATT if (extract_port(iph1->local) == lcconf->port_isakmp_natt) { @@ -2935,10 +2991,10 @@ log_ph1established(iph1) "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); + + evt_phase1(iph1, EVT_PHASE1_UP, NULL); if(!iph1->rmconf->mode_cfg) - EVT_PUSH(iph1->local, iph1->remote, EVTT_NO_ISAKMP_CFG, NULL); + evt_phase1(iph1, EVT_PHASE1_MODE_CFG, NULL); racoon_free(src); racoon_free(dst); @@ -2947,7 +3003,8 @@ log_ph1established(iph1) } struct payload_list * -isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_type) +isakmp_plist_append_full (struct payload_list *plist, vchar_t *payload, + u_int8_t payload_type, u_int8_t free_payload) { if (! plist) { plist = racoon_malloc (sizeof (struct payload_list)); @@ -2962,11 +3019,12 @@ isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_t plist->next = NULL; plist->payload = payload; plist->payload_type = payload_type; + plist->free_payload = free_payload; return plist; } -vchar_t * +vchar_t * isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) { struct payload_list *ptr = *plist, *first; @@ -2977,7 +3035,7 @@ isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) /* Seek to the first item. */ while (ptr->prev) ptr = ptr->prev; first = ptr; - + /* Compute the whole length. */ while (ptr) { tlen += ptr->payload->l + sizeof (struct isakmp_gen); @@ -3002,6 +3060,8 @@ isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) p = set_isakmp_payload (p, ptr->payload, ptr->next ? ptr->next->payload_type : ISAKMP_NPTYPE_NONE); first = ptr; ptr = ptr->next; + if (first->free_payload) + vfree(first->payload); racoon_free (first); /* ptr->prev = NULL; first = NULL; ... omitted. */ n++; @@ -3017,7 +3077,7 @@ end: } #ifdef ENABLE_FRAG -int +int frag_handler(iph1, msg, remote, local) struct ph1handle *iph1; vchar_t *msg; @@ -3028,7 +3088,7 @@ frag_handler(iph1, msg, remote, local) if (isakmp_frag_extract(iph1, msg) == 1) { if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) { - plog(LLV_ERROR, LOCATION, remote, + plog(LLV_ERROR, LOCATION, remote, "Packet reassembly failed\n"); return -1; } @@ -3050,7 +3110,6 @@ script_hook(iph1, script) char portstr[PORT_MAX]; char **envp = NULL; int envc = 1; - struct sockaddr_in *sin; char **c; if (iph1 == NULL || @@ -3063,9 +3122,7 @@ script_hook(iph1, script) #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)); + GETNAMEINFO(iph1->local, addrstr, portstr); if (script_env_append(&envp, &envc, "LOCAL_ADDR", addrstr) != 0) { plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_ADDR\n"); @@ -3079,9 +3136,7 @@ script_hook(iph1, script) /* Peer address */ if (iph1->remote != NULL) { - 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)); + GETNAMEINFO(iph1->remote, addrstr, portstr); if (script_env_append(&envp, &envc, "REMOTE_ADDR", addrstr) != 0) { @@ -3098,6 +3153,16 @@ script_hook(iph1, script) } } + /* Peer identity. */ + if (iph1->id_p != NULL) { + if (script_env_append(&envp, &envc, "REMOTE_ID", + ipsecdoi_id2str(iph1->id_p)) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot set REMOTE_ID\n"); + goto out; + } + } + if (privsep_script_exec(iph1->rmconf->script[script]->v, script, envp) != 0) plog(LLV_ERROR, LOCATION, NULL, @@ -3160,7 +3225,7 @@ script_exec(script, name, envp) argv[1] = script_names[name]; argv[2] = NULL; - switch (fork()) { + switch (fork()) { case 0: execve(argv[0], argv, envp); plog(LLV_ERROR, LOCATION, NULL, @@ -3175,7 +3240,7 @@ script_exec(script, name, envp) break; default: break; - } + } return 0; } @@ -3201,7 +3266,7 @@ purge_remote(iph1) iph1->status = PHASE1ST_EXPIRED; /* Check if we have another, still valid, phase1 SA. */ - new_iph1 = getph1byaddr(iph1->local, iph1->remote, 1); + new_iph1 = getph1(iph1, iph1->local, iph1->remote, GETPH1_F_ESTABLISHED); /* * Delete all orphaned or binded to the deleting ph1handle phase2 SAs. @@ -3240,6 +3305,7 @@ purge_remote(iph1) msg = next; continue; } + pk_fixup_sa_addresses(mhp); src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); @@ -3255,8 +3321,10 @@ purge_remote(iph1) * Select only SAs where src == local and dst == remote (outgoing) * or src == remote and dst == local (incoming). */ - if ((CMPSADDR(iph1->local, src) || CMPSADDR(iph1->remote, dst)) && - (CMPSADDR(iph1->local, dst) || CMPSADDR(iph1->remote, src))) { + if ((cmpsaddr(iph1->local, src) != CMPSADDR_MATCH || + cmpsaddr(iph1->remote, dst) != CMPSADDR_MATCH) && + (cmpsaddr(iph1->local, dst) != CMPSADDR_MATCH || + cmpsaddr(iph1->remote, src) != CMPSADDR_MATCH)) { msg = next; continue; } @@ -3274,7 +3342,7 @@ purge_remote(iph1) ntohl(sa->sadb_sa_spi)); }else{ - /* + /* * If we have a new ph1, do not purge IPsec-SAs binded * to a different ISAKMP-SA */ @@ -3286,7 +3354,7 @@ purge_remote(iph1) /* 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), @@ -3297,7 +3365,7 @@ purge_remote(iph1) } } - + pfkey_send_delete(lcconf->sock_pfkey, msg->sadb_msg_satype, IPSEC_MODE_ANY, @@ -3306,7 +3374,6 @@ purge_remote(iph1) /* delete a relative phase 2 handle. */ if (iph2 != NULL) { delete_spd(iph2, 0); - unbindph12(iph2); remph2(iph2); delph2(iph2); } @@ -3326,12 +3393,10 @@ purge_remote(iph1) "purged ISAKMP-SA spi=%s.\n", isakmp_pindex(&(iph1->index), iph1->msgid)); - SCHED_KILL(iph1->sce); - - iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + isakmp_ph1delete(iph1); } -void +void delete_spd(iph2, created) struct ph2handle *iph2; u_int64_t created; @@ -3356,23 +3421,23 @@ delete_spd(iph2, created) dst = iph2->dst; plog(LLV_INFO, LOCATION, NULL, - "generated policy, deleting it.\n"); - + "deleting a generated policy.\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. @@ -3388,48 +3453,48 @@ delete_spd(iph2, created) &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 + * a destination address to search for a inbound * policy entry because rcoon is responder. */ if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { - if ((error = + 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 + * 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 = + spidx.prefd = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: - spidx.prefd = + spidx.prefd = sizeof(struct in6_addr) << 3; break; #endif @@ -3438,8 +3503,8 @@ delete_spd(iph2, created) break; } } - - /* make source address in spidx */ + + /* 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 @@ -3447,8 +3512,8 @@ delete_spd(iph2, created) || _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); + (struct sockaddr *)&spidx.src, + &spidx.prefs, &spidx.ul_proto); if (error) goto purge; @@ -3458,7 +3523,7 @@ delete_spd(iph2, created) * for more detail, see above of this function. */ if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { - error = + error = setscopeid((struct sockaddr *)&spidx.src, iph2->dst); if (error) @@ -3466,19 +3531,19 @@ delete_spd(iph2, created) } #endif - /* make id[src,dst] if both ID types are IP address and same */ + /* make sa_[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 = + iph2->sa_src = dupsaddr((struct sockaddr *)&spidx.dst); - if (iph2->src_id == NULL) { + if (iph2->sa_src == NULL) { plog(LLV_ERROR, LOCATION, NULL, "allocation failed\n"); goto purge; } - iph2->dst_id = + iph2->sa_dst = dupsaddr((struct sockaddr *)&spidx.src); - if (iph2->dst_id == NULL) { + if (iph2->sa_dst == NULL) { plog(LLV_ERROR, LOCATION, NULL, "allocation failed\n"); goto purge; @@ -3496,12 +3561,12 @@ delete_spd(iph2, created) memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); switch (spidx.src.ss_family) { case AF_INET: - spidx.prefs = + spidx.prefs = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: - spidx.prefs = + spidx.prefs = sizeof(struct in6_addr) << 3; break; #endif @@ -3539,7 +3604,7 @@ delete_spd(iph2, created) */ if( created ){ struct secpolicy *p; - + p = getsp(&spidx); if(p != NULL){ /* just do no test if p is NULL, because this probably just means @@ -3604,7 +3669,7 @@ 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; diff --git a/src/racoon/isakmp.h b/src/racoon/isakmp.h index d0fd242..16986a9 100644 --- a/src/racoon/isakmp.h +++ b/src/racoon/isakmp.h @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: isakmp.h,v 1.7 2009/05/20 07:54:50 vanhu Exp $ */ /* Id: isakmp.h,v 1.11 2005/04/25 22:19:39 manubsd Exp */ @@ -36,8 +36,8 @@ /* refer to RFC 2408 */ -/* must include <netinet/in.h> first. */ -/* must include "isakmp_var.h" first. */ +#include <netinet/in.h> +#include "isakmp_var.h" #define INITIATOR 0 /* synonym sender */ #define RESPONDER 1 /* synonym receiver */ @@ -133,7 +133,7 @@ struct isakmp { /* Exchange Type */ #define ISAKMP_ETYPE_NONE 0 /* NONE */ #define ISAKMP_ETYPE_BASE 1 /* Base */ -#define ISAKMP_ETYPE_IDENT 2 /* Identity Proteciton */ +#define ISAKMP_ETYPE_IDENT 2 /* Identity Protection */ #define ISAKMP_ETYPE_AUTH 3 /* Authentication Only */ #define ISAKMP_ETYPE_AGG 4 /* Aggressive */ #define ISAKMP_ETYPE_INFO 5 /* Informational */ @@ -270,11 +270,6 @@ struct isakmp_pl_cert { #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; @@ -384,7 +379,8 @@ struct isakmp_pl_d { struct payload_list { struct payload_list *next, *prev; vchar_t *payload; - int payload_type; + u_int8_t payload_type; + u_int8_t free_payload; }; diff --git a/src/racoon/isakmp_agg.c b/src/racoon/isakmp_agg.c index 0d43883..2e387fb 100644 --- a/src/racoon/isakmp_agg.c +++ b/src/racoon/isakmp_agg.c @@ -1,11 +1,11 @@ -/* $NetBSD: isakmp_agg.c,v 1.9 2006/09/30 21:49:37 manu Exp $ */ +/* $NetBSD: isakmp_agg.c,v 1.16 2009/09/18 10:31:11 tteras Exp $ */ /* Id: isakmp_agg.c,v 1.28 2006/04/06 16:46:08 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -113,8 +113,6 @@ agg_i1send(iph1, msg) vchar_t *msg; /* must be null */ { struct payload_list *plist = NULL; - int need_cr = 0; - vchar_t *cr = NULL; int error = -1; #ifdef ENABLE_NATT vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL }; @@ -135,7 +133,6 @@ agg_i1send(iph1, msg) vchar_t *vid_dpd = NULL; #endif - /* validity check */ if (msg != NULL) { plog(LLV_ERROR, LOCATION, NULL, @@ -157,7 +154,7 @@ agg_i1send(iph1, msg) goto end; /* create SA payload for my proposal */ - iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf, iph1->rmconf->proposal); if (iph1->sa == NULL) goto end; @@ -180,8 +177,8 @@ agg_i1send(iph1, msg) #ifdef ENABLE_HYBRID /* Do we need Xauth VID? */ - switch (RMAUTHMETHOD(iph1)) { - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + switch (iph1->rmconf->proposal->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: @@ -189,10 +186,10 @@ agg_i1send(iph1, msg) case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: if ((vid_xauth = set_vendorid(VENDORID_XAUTH)) == NULL) - plog(LLV_ERROR, LOCATION, 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, + plog(LLV_ERROR, LOCATION, NULL, "Unity vendor ID generation failed\n"); break; default: @@ -209,26 +206,13 @@ agg_i1send(iph1, msg) 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; - } } +#endif plog(LLV_DEBUG, LOCATION, NULL, "authmethod is %s\n", s_oakley_attr_method(iph1->rmconf->proposal->authmethod)); #ifdef HAVE_GSSAPI - if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) gssapi_get_itoken(iph1, &len); #endif @@ -245,33 +229,37 @@ agg_i1send(iph1, msg) plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); #ifdef HAVE_GSSAPI - if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { - gssapi_get_token_to_send(iph1, &gsstoken); + if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get gssapi token.\n"); + goto end; + } plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); } #endif /* create isakmp CR payload */ - if (need_cr) - plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR); + if (oakley_needcr(iph1->rmconf->proposal->authmethod)) + plist = oakley_append_cr(plist, iph1); #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 + /* + * set VID payload for NAT-T if NAT-T + * support allowed in the config file */ - if (iph1->rmconf->nat_traversal) + 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, + plist = isakmp_plist_append(plist, vid_xauth, ISAKMP_NPTYPE_VID); if (vid_unity) - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, vid_unity, ISAKMP_NPTYPE_VID); #endif #ifdef ENABLE_DPD @@ -289,8 +277,7 @@ agg_i1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; iph1->status = PHASE1ST_MSG1SENT; @@ -298,8 +285,6 @@ agg_i1send(iph1, msg) error = 0; end: - if (cr) - vfree(cr); #ifdef HAVE_GSSAPI if (gsstoken) vfree(gsstoken); @@ -343,7 +328,6 @@ agg_i2recv(iph1, msg) struct isakmp_parse_t *pa; vchar_t *satmp = NULL; int error = -1; - int vid_numeric; int ptype; #ifdef ENABLE_HYBRID vchar_t *unity_vid; @@ -425,37 +409,12 @@ agg_i2recv(iph1, msg) 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 + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph1); + isakmp_log_notify(iph1, + (struct isakmp_pl_n *) pa->ptr, + "aggressive exchange"); break; #ifdef HAVE_GSSAPI case ISAKMP_NPTYPE_GSS: @@ -529,7 +488,7 @@ agg_i2recv(iph1, msg) 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)); @@ -537,9 +496,9 @@ agg_i2recv(iph1, msg) /* 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 + /* this function will clear appropriate bits bits from iph1->natt_flags */ natd_verified = natt_compare_addr_hash (iph1, natd->payload, natd->seq); @@ -547,7 +506,7 @@ agg_i2recv(iph1, msg) 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); @@ -555,7 +514,7 @@ agg_i2recv(iph1, msg) } plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n", - iph1->natt_flags & NAT_DETECTED ? + iph1->natt_flags & NAT_DETECTED ? "detected:" : "not detected", iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "", iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : ""); @@ -587,8 +546,7 @@ agg_i2recv(iph1, msg) /* message printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, ptype, NULL); goto end; } @@ -616,13 +574,10 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); - oakley_delcert(iph1->cr_p); - iph1->cr_p = NULL; + VPTRINIT(iph1->cr_p); } return error; @@ -669,15 +624,15 @@ agg_i2send(iph1, msg) goto end; } - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: -#endif +#endif /* set HASH payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH); break; @@ -700,11 +655,11 @@ agg_i2send(iph1, msg) /* add CERT payload if there */ if (need_cert) - plist = isakmp_plist_append(plist, - iph1->cert->pl, ISAKMP_NPTYPE_CERT); + plist = isakmp_plist_append(plist, iph1->cert, + ISAKMP_NPTYPE_CERT); /* add SIG payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); break; @@ -726,7 +681,7 @@ agg_i2send(iph1, msg) goto end; } - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH); break; #endif @@ -737,26 +692,26 @@ agg_i2send(iph1, msg) if (NATT_AVAILABLE(iph1)) { vchar_t *natd[2] = { NULL, NULL }; - plog(LLV_INFO, LOCATION, + 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", + "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", + "NAT-D hashing failed for %s\n", saddr2str(iph1->local)); goto end; } - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, natd[0], iph1->natt_options->payload_nat_d); - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); } #endif @@ -860,37 +815,7 @@ agg_r1recv(iph1, msg) 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 + vid_numeric = handle_vendorid(iph1, pa->ptr); #ifdef ENABLE_FRAG if ((vid_numeric == VENDORID_FRAG) && (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_AGG)) @@ -970,8 +895,7 @@ end: VPTRINIT(iph1->dhpub_p); VPTRINIT(iph1->nonce_p); VPTRINIT(iph1->id_p); - oakley_delcert(iph1->cr_p); - iph1->cr_p = NULL; + VPTRINIT(iph1->cr_p); } return error; @@ -991,9 +915,7 @@ agg_r1send(iph1, msg) vchar_t *msg; { struct payload_list *plist = NULL; - int need_cr = 0; int need_cert = 0; - vchar_t *cr = NULL; int error = -1; #ifdef ENABLE_HYBRID vchar_t *xauth_vid = NULL; @@ -1057,7 +979,7 @@ agg_r1send(iph1, msg) goto end; #ifdef HAVE_GSSAPI - if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) gssapi_get_rtoken(iph1, &gsslen); #endif @@ -1073,19 +995,6 @@ agg_r1send(iph1, msg) 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)) { @@ -1124,35 +1033,34 @@ agg_r1send(iph1, msg) } #endif - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: #endif /* set SA payload to reply */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA); /* create isakmp KE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); /* create isakmp NONCE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); /* create isakmp ID payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID); /* create isakmp HASH payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->hash, ISAKMP_NPTYPE_HASH); /* create isakmp CR payload if needed */ - if (need_cr) - plist = isakmp_plist_append(plist, - cr, ISAKMP_NPTYPE_CR); + if (oakley_needcr(iph1->approval->authmethod)) + plist = oakley_append_cr(plist, iph1); break; case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: @@ -1174,34 +1082,33 @@ agg_r1send(iph1, msg) need_cert = 1; /* set SA payload to reply */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->sa_ret, ISAKMP_NPTYPE_SA); /* create isakmp KE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); /* create isakmp NONCE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); /* add ID payload */ - plist = isakmp_plist_append(plist, + 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); + plist = isakmp_plist_append(plist, iph1->cert, + ISAKMP_NPTYPE_CERT); /* add SIG payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); /* create isakmp CR payload if needed */ - if (need_cr) - plist = isakmp_plist_append(plist, - cr, ISAKMP_NPTYPE_CR); + if (oakley_needcr(iph1->approval->authmethod)) + plist = oakley_append_cr(plist, iph1); break; case OAKLEY_ATTR_AUTH_METHOD_RSAENC: @@ -1219,9 +1126,9 @@ agg_r1send(iph1, msg) 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 + * 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, @@ -1229,8 +1136,8 @@ agg_r1send(iph1, msg) goto end; } if (iph1->approval->gssid != NULL) - gss_sa = - ipsecdoi_setph1proposal(iph1->approval); + gss_sa = ipsecdoi_setph1proposal(iph1->rmconf, + iph1->approval); else gss_sa = iph1->sa_ret; @@ -1238,28 +1145,32 @@ agg_r1send(iph1, msg) free_gss_sa = 1; /* set SA payload to reply */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, gss_sa, ISAKMP_NPTYPE_SA); /* create isakmp KE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->dhpub, ISAKMP_NPTYPE_KE); /* create isakmp NONCE payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); /* create isakmp ID payload */ - plist = isakmp_plist_append(plist, + 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, + if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get gssapi token.\n"); + goto end; + } + plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); /* create isakmp HASH payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, gsshash, ISAKMP_NPTYPE_HASH); /* append vendor id, if needed */ @@ -1275,7 +1186,7 @@ agg_r1send(iph1, msg) "Cannot create Xauth vendor ID\n"); goto end; } - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, xauth_vid, ISAKMP_NPTYPE_VID); } @@ -1285,7 +1196,7 @@ agg_r1send(iph1, msg) "Cannot create Unity vendor ID\n"); goto end; } - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, unity_vid, ISAKMP_NPTYPE_VID); } #endif @@ -1318,8 +1229,7 @@ agg_r1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; /* the sending message is added to the received-list. */ @@ -1334,8 +1244,6 @@ agg_r1send(iph1, msg) error = 0; end: - if (cr) - vfree(cr); #ifdef ENABLE_HYBRID if (xauth_vid) vfree(xauth_vid); @@ -1378,9 +1286,7 @@ agg_r2recv(iph1, msg0) vchar_t *msg = NULL; vchar_t *pbuf = NULL; struct isakmp_parse_t *pa; - int error = -1; - int ptype; - + int error = -1, ptype; #ifdef ENABLE_NATT int natd_seq = 0; #endif @@ -1418,7 +1324,7 @@ agg_r2recv(iph1, msg0) iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; break; case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_CERT: if (oakley_savecert(iph1, pa->ptr) < 0) @@ -1429,7 +1335,9 @@ agg_r2recv(iph1, msg0) goto end; break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph1); + isakmp_log_notify(iph1, + (struct isakmp_pl_n *) pa->ptr, + "aggressive exchange"); break; #ifdef ENABLE_NATT @@ -1440,20 +1348,20 @@ agg_r2recv(iph1, msg0) { 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; } @@ -1473,7 +1381,7 @@ agg_r2recv(iph1, msg0) #ifdef ENABLE_NATT if (NATT_AVAILABLE(iph1)) plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n", - iph1->natt_flags & NAT_DETECTED ? + iph1->natt_flags & NAT_DETECTED ? "detected:" : "not detected", iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "", iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : ""); @@ -1486,8 +1394,7 @@ agg_r2recv(iph1, msg0) /* message printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, ptype, NULL); goto end; } @@ -1502,10 +1409,8 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); } diff --git a/src/racoon/isakmp_base.c b/src/racoon/isakmp_base.c index 3ac0b72..f37d51e 100644 --- a/src/racoon/isakmp_base.c +++ b/src/racoon/isakmp_base.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_base.c,v 1.7 2006/10/02 21:51:33 manu Exp $ */ +/* $NetBSD: isakmp_base.c,v 1.12 2009/03/12 10:57:26 tteras Exp $ */ /* $KAME: isakmp_base.c,v 1.49 2003/11/13 02:30:20 sakane Exp $ */ @@ -143,7 +143,8 @@ base_i1send(iph1, msg) goto end; /* create SA payload for my proposal */ - iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf, + iph1->rmconf->proposal); if (iph1->sa == NULL) goto end; @@ -154,8 +155,8 @@ base_i1send(iph1, msg) #ifdef ENABLE_HYBRID /* Do we need Xauth VID? */ - switch (RMAUTHMETHOD(iph1)) { - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + switch (iph1->rmconf->proposal->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: @@ -250,8 +251,7 @@ base_i1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; iph1->status = PHASE1ST_MSG1SENT; @@ -297,7 +297,6 @@ base_i2recv(iph1, msg) struct isakmp_parse_t *pa; vchar_t *satmp = NULL; int error = -1; - int vid_numeric; #ifdef ENABLE_HYBRID vchar_t *unity_vid; vchar_t *xauth_vid; @@ -342,34 +341,7 @@ base_i2recv(iph1, msg) 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 + handle_vendorid(iph1, pa->ptr); break; default: /* don't send information, see ident_r1recv() */ @@ -462,7 +434,7 @@ base_i2send(iph1, msg) goto end; /* generate SKEYID to compute hash if not signature mode */ - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_RSASIG: case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: #ifdef ENABLE_HYBRID @@ -484,10 +456,10 @@ base_i2send(iph1, msg) iph1->hash = oakley_ph1hash_base_i(iph1, GENERATE); if (iph1->hash == NULL) goto end; - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: #endif @@ -521,16 +493,16 @@ base_i2send(iph1, msg) need_cert = 1; /* create isakmp KE payload */ - plist = isakmp_plist_append(plist, - iph1->dhpub, ISAKMP_NPTYPE_KE); + 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); + plist = isakmp_plist_append(plist, iph1->cert, + ISAKMP_NPTYPE_CERT); /* add SIG payload */ - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG); break; @@ -579,8 +551,7 @@ base_i2send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; /* the sending message is added to the received-list. */ @@ -614,8 +585,7 @@ base_i3recv(iph1, msg) { vchar_t *pbuf = NULL; struct isakmp_parse_t *pa; - int error = -1; - int ptype; + int error = -1, ptype; #ifdef ENABLE_NATT vchar_t *natd_received; int natd_seq = 0, natd_verified; @@ -654,7 +624,7 @@ base_i3recv(iph1, msg) goto end; break; case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; #ifdef ENABLE_NATT @@ -716,8 +686,7 @@ base_i3recv(iph1, msg) /* message printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, ptype, NULL); goto end; } @@ -728,7 +697,7 @@ base_i3recv(iph1, msg) goto end; /* generate SKEYID to compute hash if signature mode */ - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_RSASIG: case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: #ifdef ENABLE_HYBRID @@ -769,10 +738,8 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); } @@ -829,9 +796,6 @@ base_r1recv(iph1, msg) } /* 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; @@ -863,39 +827,12 @@ base_r1recv(iph1, msg) 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 + vid_numeric = handle_vendorid(iph1, pa->ptr); #ifdef ENABLE_FRAG if ((vid_numeric == VENDORID_FRAG) && (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_BASE)) iph1->frag = 1; #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; default: /* don't send information, see ident_r1recv() */ @@ -1073,8 +1010,7 @@ base_r1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) { + if (isakmp_ph1send(iph1) == -1) { iph1 = NULL; goto end; } @@ -1130,8 +1066,7 @@ base_r2recv(iph1, msg) { vchar_t *pbuf = NULL; struct isakmp_parse_t *pa; - int error = -1; - int ptype; + int error = -1, ptype; #ifdef ENABLE_NATT int natd_seq = 0; #endif @@ -1171,7 +1106,7 @@ base_r2recv(iph1, msg) goto end; break; case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; #ifdef ENABLE_NATT @@ -1242,8 +1177,7 @@ base_r2recv(iph1, msg) /* message printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, ptype, NULL); goto end; } @@ -1258,10 +1192,8 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); } @@ -1294,7 +1226,7 @@ base_r2send(iph1, msg) /* generate HASH to send */ plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: @@ -1329,7 +1261,7 @@ base_r2send(iph1, msg) if (iph1->hash == NULL) goto end; - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: @@ -1369,16 +1301,17 @@ base_r2send(iph1, msg) need_cert = 1; /* create isakmp KE payload */ - plist = isakmp_plist_append(plist, - iph1->dhpub, ISAKMP_NPTYPE_KE); + 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); + plist = isakmp_plist_append(plist, iph1->cert, + ISAKMP_NPTYPE_CERT); + /* add SIG payload */ - plist = isakmp_plist_append(plist, - iph1->sig, ISAKMP_NPTYPE_SIG); + plist = isakmp_plist_append(plist, iph1->sig, + ISAKMP_NPTYPE_SIG); break; #ifdef HAVE_GSSAPI case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: diff --git a/src/racoon/isakmp_cfg.c b/src/racoon/isakmp_cfg.c index 52862c4..0ec30ee 100644 --- a/src/racoon/isakmp_cfg.c +++ b/src/racoon/isakmp_cfg.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_cfg.c,v 1.12.6.4 2008/11/27 15:25:20 vanhu Exp $ */ +/* $NetBSD: isakmp_cfg.c,v 1.24 2010/09/21 13:14:17 vanhu Exp $ */ /* Id: isakmp_cfg.c,v 1.55 2006/08/22 18:17:17 manubsd Exp */ @@ -38,7 +38,7 @@ #include <sys/socket.h> #include <sys/queue.h> -#include <utmp.h> +#include <utmpx.h> #if defined(__APPLE__) && defined(__MACH__) #include <util.h> #endif @@ -114,6 +114,8 @@ 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 vchar_t *isakmp_cfg_addrnet4(struct ph1handle *, + struct isakmp_data *, in_addr_t *, in_addr_t *); static void isakmp_cfg_getaddr4(struct isakmp_data *, struct in_addr *); static vchar_t *isakmp_cfg_addr4_list(struct ph1handle *, struct isakmp_data *, in_addr_t *, int); @@ -446,8 +448,8 @@ isakmp_cfg_reply(iph1, attrpl) if ((iph1->status == PHASE1ST_ESTABLISHED) && iph1->rmconf->mode_cfg) { - switch (AUTHMETHOD(iph1)) { - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: /* Unimplemented */ case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: @@ -473,8 +475,7 @@ isakmp_cfg_reply(iph1, attrpl) "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); + evt_phase1(iph1, EVT_PHASE1_MODE_CFG, buf); vfree(buf); } } @@ -629,7 +630,7 @@ isakmp_cfg_request(iph1, attrpl) ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0); if (iph1->status == PHASE1ST_ESTABLISHED) { - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: /* Unimplemented */ @@ -731,7 +732,8 @@ isakmp_cfg_set(iph1, attrpl) ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0); if (iph1->mode_cfg->flags & ISAKMP_CFG_DELETE_PH1) { - if (iph1->status == PHASE1ST_ESTABLISHED) + if (iph1->status == PHASE1ST_ESTABLISHED || + iph1->status == PHASE1ST_DYING) isakmp_info_send_d1(iph1); remph1(iph1); delph1(iph1); @@ -901,8 +903,15 @@ retry_source: break; case INTERNAL_IP4_SUBNET: - return isakmp_cfg_addr4(iph1, - attr, &isakmp_cfg_config.network4); + if(isakmp_cfg_config.splitnet_count > 0){ + return isakmp_cfg_addrnet4(iph1, attr, + &isakmp_cfg_config.splitnet_list->network.addr4.s_addr, + &isakmp_cfg_config.splitnet_list->network.mask4.s_addr); + }else{ + plog(LLV_INFO, LOCATION, NULL, + "%s requested but no splitnet in configuration\n", + s_isakmp_cfg_type(type)); + } break; default: @@ -1042,6 +1051,36 @@ isakmp_cfg_addr4(iph1, attr, addr) } static vchar_t * +isakmp_cfg_addrnet4(iph1, attr, addr, mask) + struct ph1handle *iph1; + struct isakmp_data *attr; + in_addr_t *addr; + in_addr_t *mask; +{ + vchar_t *buffer; + struct isakmp_data *new; + size_t len; + in_addr_t netbuff[2]; + + len = sizeof(netbuff); + 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); + netbuff[0]=*addr; + netbuff[1]=*mask; + memcpy(new + 1, netbuff, len); + + return buffer; +} + + +static vchar_t * isakmp_cfg_addr4_list(iph1, attr, addr, nbr) struct ph1handle *iph1; struct isakmp_data *attr; @@ -1127,7 +1166,7 @@ isakmp_cfg_send(iph1, payload, np, flags, new_exchange) struct isakmp_cfg_state *ics = iph1->mode_cfg; /* Check if phase 1 is established */ - if ((iph1->status != PHASE1ST_ESTABLISHED) || + if ((iph1->status < PHASE1ST_ESTABLISHED) || (iph1->local == NULL) || (iph1->remote == NULL)) { plog(LLV_ERROR, LOCATION, NULL, @@ -1151,16 +1190,6 @@ isakmp_cfg_send(iph1, payload, np, flags, new_exchange) goto end; } -#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT)) - if (set_port(iph2->dst, 0) == NULL || - set_port(iph2->src, 0) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph1->remote->sa_family); - delph2(iph2); - goto end; - } -#endif - iph2->ph1 = iph1; iph2->side = INITIATOR; iph2->status = PHASE2ST_START; @@ -1179,7 +1208,7 @@ isakmp_cfg_send(iph1, payload, np, flags, new_exchange) } /* generate HASH(1) */ - hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload); + hash = oakley_compute_hash1(iph1, iph2->msgid, payload); if (hash == NULL) { delph2(iph2); goto end; @@ -1278,7 +1307,6 @@ err: if (iph2->sendbuf != NULL) vfree(iph2->sendbuf); - unbindph12(iph2); remph2(iph2); delph2(iph2); end: @@ -1492,24 +1520,6 @@ 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, @@ -1651,8 +1661,7 @@ isakmp_cfg_accounting_system(port, raddr, usr, inout) int inout; { int error = 0; - struct utmp ut; - char term[UT_LINESIZE]; + struct utmpx ut; char addr[NI_MAXHOST]; if (usr == NULL || usr[0]=='\0') { @@ -1661,36 +1670,33 @@ isakmp_cfg_accounting_system(port, raddr, usr, inout) return -1; } - sprintf(term, TERMSPEC, port); + memset(&ut, 0, sizeof ut); + gettimeofday((struct timeval *)&ut.ut_tv, NULL); + snprintf(ut.ut_id, sizeof ut.ut_id, TERMSPEC, port); switch (inout) { case ISAKMP_CFG_LOGIN: - strncpy(ut.ut_name, usr, UT_NAMESIZE); - ut.ut_name[UT_NAMESIZE - 1] = '\0'; - - strncpy(ut.ut_line, term, UT_LINESIZE); - ut.ut_line[UT_LINESIZE - 1] = '\0'; + ut.ut_type = USER_PROCESS; + strncpy(ut.ut_user, usr, sizeof ut.ut_user); GETNAMEINFO_NULL(raddr, addr); - strncpy(ut.ut_host, addr, UT_HOSTSIZE); - ut.ut_host[UT_HOSTSIZE - 1] = '\0'; + strncpy(ut.ut_host, addr, sizeof ut.ut_host); - ut.ut_time = time(NULL); - plog(LLV_INFO, LOCATION, NULL, "Accounting : '%s' logging on '%s' from %s.\n", - ut.ut_name, ut.ut_line, ut.ut_host); + ut.ut_user, ut.ut_id, addr); - login(&ut); + pututxline(&ut); break; case ISAKMP_CFG_LOGOUT: + ut.ut_type = DEAD_PROCESS; plog(LLV_INFO, LOCATION, NULL, "Accounting : '%s' unlogging from '%s'.\n", - usr, term); + usr, ut.ut_id); - logout(term); + pututxline(&ut); break; default: @@ -1865,6 +1871,7 @@ isakmp_cfg_setenv(iph1, envp, envc) char addrstr[IP_MAX]; char addrlist[IP_MAX * MAXNS + MAXNS]; char *splitlist = addrlist; + char *splitlist_cidr; char defdom[MAXPATHLEN + 1]; int cidr, tmp; char cidrstr[4]; @@ -2005,10 +2012,14 @@ isakmp_cfg_setenv(iph1, envp, envc) } /* Split networks */ - if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_INCLUDE) - splitlist = splitnet_list_2str(iph1->mode_cfg->split_include); - else { + if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_INCLUDE) { + splitlist = + splitnet_list_2str(iph1->mode_cfg->split_include, NETMASK); + splitlist_cidr = + splitnet_list_2str(iph1->mode_cfg->split_include, CIDR); + } else { splitlist = addrlist; + splitlist_cidr = addrlist; addrlist[0] = '\0'; } @@ -2016,13 +2027,25 @@ isakmp_cfg_setenv(iph1, envp, envc) plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_INCLUDE\n"); return -1; } + if (script_env_append(envp, envc, + "SPLIT_INCLUDE_CIDR", splitlist_cidr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot set SPLIT_INCLUDE_CIDR\n"); + return -1; + } if (splitlist != addrlist) racoon_free(splitlist); - - if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_LOCAL) - splitlist = splitnet_list_2str(iph1->mode_cfg->split_local); - else { + if (splitlist_cidr != addrlist) + racoon_free(splitlist_cidr); + + if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_LOCAL) { + splitlist = + splitnet_list_2str(iph1->mode_cfg->split_local, NETMASK); + splitlist_cidr = + splitnet_list_2str(iph1->mode_cfg->split_local, CIDR); + } else { splitlist = addrlist; + splitlist_cidr = addrlist; addrlist[0] = '\0'; } @@ -2030,8 +2053,16 @@ isakmp_cfg_setenv(iph1, envp, envc) plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_LOCAL\n"); return -1; } + if (script_env_append(envp, envc, + "SPLIT_LOCAL_CIDR", splitlist_cidr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot set SPLIT_LOCAL_CIDR\n"); + return -1; + } if (splitlist != addrlist) racoon_free(splitlist); + if (splitlist_cidr != addrlist) + racoon_free(splitlist_cidr); return 0; } diff --git a/src/racoon/isakmp_frag.c b/src/racoon/isakmp_frag.c index 6fac6a2..ebba34b 100644 --- a/src/racoon/isakmp_frag.c +++ b/src/racoon/isakmp_frag.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_frag.c,v 1.4.6.1 2009/04/22 11:25:35 tteras Exp $ */ +/* $NetBSD: isakmp_frag.c,v 1.5 2009/04/22 11:24:20 tteras Exp $ */ /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */ diff --git a/src/racoon/isakmp_ident.c b/src/racoon/isakmp_ident.c index 1e00dc4..a9c3a01 100644 --- a/src/racoon/isakmp_ident.c +++ b/src/racoon/isakmp_ident.c @@ -1,11 +1,11 @@ -/* $NetBSD: isakmp_ident.c,v 1.6 2006/10/02 21:41:59 manu Exp $ */ +/* $NetBSD: isakmp_ident.c,v 1.13 2009/09/18 10:31:11 tteras Exp $ */ /* Id: isakmp_ident.c,v 1.21 2006/04/06 16:46:08 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -86,12 +86,13 @@ #include "isakmp_xauth.h" #include "isakmp_cfg.h" #endif -#ifdef ENABLE_FRAG +#ifdef ENABLE_FRAG #include "isakmp_frag.h" #endif static vchar_t *ident_ir2mx __P((struct ph1handle *)); static vchar_t *ident_ir3mx __P((struct ph1handle *)); +static int ident_recv_n __P((struct ph1handle *, struct isakmp_gen *)); /* %%% * begin Identity Protection Mode as initiator. @@ -114,13 +115,13 @@ ident_i1send(iph1, msg) vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL }; int i; #endif -#ifdef ENABLE_HYBRID +#ifdef ENABLE_HYBRID vchar_t *vid_xauth = NULL; vchar_t *vid_unity = NULL; #endif -#ifdef ENABLE_FRAG +#ifdef ENABLE_FRAG vchar_t *vid_frag = NULL; -#endif +#endif #ifdef ENABLE_DPD vchar_t *vid_dpd = NULL; #endif @@ -141,7 +142,8 @@ ident_i1send(iph1, msg) isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local); /* create SA payload for my proposal */ - iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf, + iph1->rmconf->proposal); if (iph1->sa == NULL) goto end; @@ -150,13 +152,13 @@ ident_i1send(iph1, msg) #ifdef ENABLE_NATT /* set VID payload for NAT-T if NAT-T support allowed in the config file */ - if (iph1->rmconf->nat_traversal) + if (iph1->rmconf->nat_traversal) plist = isakmp_plist_append_natt_vids(plist, vid_natt); #endif #ifdef ENABLE_HYBRID /* Do we need Xauth VID? */ - switch (RMAUTHMETHOD(iph1)) { - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + switch (iph1->rmconf->proposal->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: @@ -169,12 +171,12 @@ ident_i1send(iph1, msg) else plist = isakmp_plist_append(plist, vid_xauth, ISAKMP_NPTYPE_VID); - + if ((vid_unity = set_vendorid(VENDORID_UNITY)) == NULL) plog(LLV_ERROR, LOCATION, NULL, "Unity vendor ID generation failed\n"); else - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, vid_unity, ISAKMP_NPTYPE_VID); break; default: @@ -189,7 +191,7 @@ ident_i1send(iph1, msg) } else { vid_frag = isakmp_frag_addcap(vid_frag, VENDORID_FRAG_IDENT); - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, vid_frag, ISAKMP_NPTYPE_VID); } } @@ -210,8 +212,7 @@ ident_i1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; iph1->status = PHASE1ST_MSG1SENT; @@ -220,9 +221,9 @@ ident_i1send(iph1, msg) end: #ifdef ENABLE_FRAG - if (vid_frag) + if (vid_frag) vfree(vid_frag); -#endif +#endif #ifdef ENABLE_NATT for (i = 0; i < MAX_NATT_VID_COUNT && vid_natt[i] != NULL; i++) vfree(vid_natt[i]); @@ -257,7 +258,6 @@ ident_i2recv(iph1, msg) struct isakmp_parse_t *pa; vchar_t *satmp = NULL; int error = -1; - int vid_numeric; /* validity check */ if (iph1->status != PHASE1ST_MSG1SENT) { @@ -299,31 +299,7 @@ ident_i2recv(iph1, msg) 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_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; -#endif + handle_vendorid(iph1, pa->ptr); break; default: /* don't send information, see ident_r1recv() */ @@ -401,7 +377,7 @@ ident_i2send(iph1, msg) goto end; #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && gssapi_get_itoken(iph1, NULL) < 0) goto end; #endif @@ -416,8 +392,7 @@ ident_i2send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; /* the sending message is added to the received-list. */ @@ -485,7 +460,7 @@ ident_i3recv(iph1, msg) goto end; break; case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_CR: if (oakley_savecr(iph1, pa->ptr) < 0) @@ -507,21 +482,21 @@ ident_i3recv(iph1, msg) 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 + + /* 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; } @@ -541,7 +516,7 @@ ident_i3recv(iph1, msg) #ifdef ENABLE_NATT if (NATT_AVAILABLE(iph1)) { plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n", - iph1->natt_flags & NAT_DETECTED ? + iph1->natt_flags & NAT_DETECTED ? "detected:" : "not detected", iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "", iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : ""); @@ -577,8 +552,7 @@ end: VPTRINIT(iph1->dhpub_p); VPTRINIT(iph1->nonce_p); VPTRINIT(iph1->id_p); - oakley_delcert(iph1->cr_p); - iph1->cr_p = NULL; + VPTRINIT(iph1->cr_p); } return error; @@ -630,7 +604,7 @@ ident_i3send(iph1, msg0) goto end; #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + 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) @@ -657,8 +631,7 @@ ident_i3send(iph1, msg0) goto end; /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; /* the sending message is added to the received-list. */ @@ -754,10 +727,10 @@ ident_i4recv(iph1, msg0) break; #endif case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph1); + ident_recv_n(iph1, pa->ptr); break; default: /* don't send information, see ident_r1recv() */ @@ -788,8 +761,7 @@ ident_i4recv(iph1, msg0) /* msg printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, type, NULL); goto end; } @@ -812,7 +784,7 @@ ident_i4recv(iph1, msg0) * If we got a GSS token, we need to this roundtrip again. */ #ifdef HAVE_GSSAPI - iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED : + iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED : PHASE1ST_MSG4RECEIVED; #else iph1->status = PHASE1ST_MSG4RECEIVED; @@ -832,10 +804,8 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); } @@ -921,35 +891,11 @@ ident_r1recv(iph1, msg) 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 + vid_numeric = handle_vendorid(iph1, pa->ptr); #ifdef ENABLE_FRAG if ((vid_numeric == VENDORID_FRAG) && (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_IDENT)) iph1->frag = 1; -#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; #endif break; default: @@ -1021,13 +967,13 @@ ident_r1send(iph1, msg) #ifdef ENABLE_HYBRID vchar_t *vid_xauth = NULL; vchar_t *vid_unity = NULL; -#endif +#endif #ifdef ENABLE_DPD vchar_t *vid_dpd = NULL; #endif -#ifdef ENABLE_FRAG +#ifdef ENABLE_FRAG vchar_t *vid_frag = NULL; -#endif +#endif /* validity check */ if (iph1->status != PHASE1ST_MSG1RECEIVED) { @@ -1041,10 +987,10 @@ ident_r1send(iph1, msg) #ifdef HAVE_GSSAPI if (iph1->approval->gssid != NULL) { - gss_sa = ipsecdoi_setph1proposal(iph1->approval); + gss_sa = ipsecdoi_setph1proposal(iph1->rmconf, iph1->approval); if (gss_sa != iph1->sa_ret) free_gss_sa = 1; - } else + } else #endif gss_sa = iph1->sa_ret; @@ -1082,8 +1028,7 @@ ident_r1send(iph1, msg) 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){ + if (iph1->dpd_support) { vid_dpd = set_vendorid(VENDORID_DPD); if (vid_dpd != NULL) plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID); @@ -1099,7 +1044,7 @@ ident_r1send(iph1, msg) plog(LLV_ERROR, LOCATION, NULL, "Frag vendorID construction failed\n"); else - plist = isakmp_plist_append(plist, + plist = isakmp_plist_append(plist, vid_frag, ISAKMP_NPTYPE_VID); } #endif @@ -1111,10 +1056,8 @@ ident_r1send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) { + if (isakmp_ph1send(iph1) == -1) goto end; - } /* the sending message is added to the received-list. */ if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { @@ -1203,7 +1146,7 @@ ident_r2recv(iph1, msg) goto end; break; case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_CR: plog(LLV_WARNING, LOCATION, iph1->remote, @@ -1226,20 +1169,20 @@ ident_r2recv(iph1, msg) { 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; } @@ -1259,7 +1202,7 @@ ident_r2recv(iph1, msg) #ifdef ENABLE_NATT if (NATT_AVAILABLE(iph1)) plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n", - iph1->natt_flags & NAT_DETECTED ? + iph1->natt_flags & NAT_DETECTED ? "detected:" : "not detected", iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "", iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : ""); @@ -1321,12 +1264,12 @@ ident_r2send(iph1, msg) goto end; /* generate NONCE value */ - iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + iph1->nonce = eay_set_random(RMCONF_NONCE_SIZE(iph1->rmconf)); if (iph1->nonce == NULL) goto end; #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) gssapi_get_rtoken(iph1, NULL); #endif @@ -1340,8 +1283,7 @@ ident_r2send(iph1, msg) #endif /* send the packet, add to the schedule to resend */ - iph1->retry_counter = iph1->rmconf->retry_counter; - if (isakmp_ph1resend(iph1) == -1) + if (isakmp_ph1send(iph1) == -1) goto end; /* the sending message is added to the received-list. */ @@ -1429,6 +1371,8 @@ ident_r3recv(iph1, msg0) case ISAKMP_NPTYPE_ID: if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) goto end; + if (resolveph1rmconf(iph1) < 0) + goto end; break; case ISAKMP_NPTYPE_HASH: iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; @@ -1453,10 +1397,10 @@ ident_r3recv(iph1, msg0) break; #endif case ISAKMP_NPTYPE_VID: - (void)check_vendorid(pa->ptr); + handle_vendorid(iph1, pa->ptr); break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph1); + ident_recv_n(iph1, pa->ptr); break; default: /* don't send information, see ident_r1recv() */ @@ -1473,7 +1417,7 @@ ident_r3recv(iph1, msg0) { int ng = 0; - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: @@ -1537,8 +1481,7 @@ ident_r3recv(iph1, msg0) /* msg printed inner oakley_validate_auth() */ goto end; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEERPH1AUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL); isakmp_info_send_n1(iph1, type, NULL); goto end; } @@ -1583,13 +1526,10 @@ end: 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->cert_p); + VPTRINIT(iph1->crl_p); VPTRINIT(iph1->sig_p); - oakley_delcert(iph1->cr_p); - iph1->cr_p = NULL; + VPTRINIT(iph1->cr_p); } return error; @@ -1626,7 +1566,7 @@ ident_r3send(iph1, msg) goto end; #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && gssapi_more_tokens(iph1)) { gssapi_get_rtoken(iph1, &len); if (len != 0) @@ -1694,8 +1634,6 @@ ident_ir2mx(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 @@ -1705,23 +1643,14 @@ ident_ir2mx(iph1) 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) { +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) { plog(LLV_ERROR, LOCATION, NULL, - "failed to get cr buffer.\n"); + "Failed to get gssapi token.\n"); goto end; } } - -#ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) - gssapi_get_token_to_send(iph1, &gsstoken); #endif /* create isakmp KE payload */ @@ -1731,7 +1660,7 @@ ident_ir2mx(iph1) plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE); #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS); #endif @@ -1739,9 +1668,10 @@ ident_ir2mx(iph1) 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); + /* create CR if need */ + if (iph1->side == RESPONDER && + oakley_needcr(iph1->approval->authmethod)) + plist = oakley_append_cr(plist, iph1); #ifdef ENABLE_NATT /* generate and append NAT-D payloads */ @@ -1764,9 +1694,9 @@ ident_ir2mx(iph1) plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d); } #endif - + buf = isakmp_plist_set_all (&plist, iph1); - + error = 0; end: @@ -1774,8 +1704,6 @@ end: vfree(buf); buf = NULL; } - if (cr) - vfree(cr); #ifdef HAVE_GSSAPI if (gsstoken) vfree(gsstoken); @@ -1814,9 +1742,7 @@ ident_ir3mx(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; @@ -1824,10 +1750,10 @@ ident_ir3mx(iph1) vchar_t *gsshash = NULL; #endif - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: @@ -1847,27 +1773,13 @@ ident_ir3mx(iph1) case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: -#endif +#endif 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; @@ -1876,13 +1788,15 @@ ident_ir3mx(iph1) /* add CERT payload if there */ if (need_cert) - plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT); + plist = isakmp_plist_append(plist, iph1->cert, + 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); + if (iph1->side == INITIATOR && + oakley_needcr(iph1->approval->authmethod)) + plist = oakley_append_cr(plist, iph1); break; #ifdef HAVE_GSSAPI case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: @@ -1891,7 +1805,11 @@ ident_ir3mx(iph1) if (gsshash == NULL) goto end; } else { - gssapi_get_token_to_send(iph1, &gsstoken); + if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get gssapi token.\n"); + goto end; + } } if (!gssapi_id_sent(iph1)) { @@ -1927,7 +1845,7 @@ ident_ir3mx(iph1) } buf = isakmp_plist_set_all (&plist, iph1); - + #ifdef HAVE_PRINT_ISAKMP_C isakmp_printpacket(buf, iph1->local, iph1->remote, 1); #endif @@ -1948,8 +1866,6 @@ end: if (gsstoken) vfree(gsstoken); #endif - if (cr) - vfree(cr); if (error && buf != NULL) { vfree(buf); buf = NULL; @@ -1957,3 +1873,28 @@ end: return buf; } + +/* + * handle a notification payload inside identity exchange. + * called only when the packet has been verified to be encrypted. + */ +static int +ident_recv_n(iph1, gen) + struct ph1handle *iph1; + struct isakmp_gen *gen; +{ + struct isakmp_pl_n *notify = (struct isakmp_pl_n *) gen; + u_int type; + + type = ntohs(notify->type); + switch (type) { + case ISAKMP_NTYPE_INITIAL_CONTACT: + iph1->initial_contact_received = TRUE; + break; + default: + isakmp_log_notify(iph1, notify, "identity exchange"); + break; + } + return 0; +} + diff --git a/src/racoon/isakmp_inf.c b/src/racoon/isakmp_inf.c index 5f487d2..9bf81c6 100644 --- a/src/racoon/isakmp_inf.c +++ b/src/racoon/isakmp_inf.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_inf.c,v 1.14.4.17 2009/05/18 17:07:46 tteras Exp $ */ +/* $NetBSD: isakmp_inf.c,v 1.47 2011/03/15 13:20:14 vanhu Exp $ */ /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */ @@ -107,11 +107,10 @@ 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 *)); +static void isakmp_info_send_r_u __P((struct sched *)); #endif static void purge_isakmp_spi __P((int, isakmp_index *, size_t)); -static void info_recv_initialcontact __P((struct ph1handle *)); /* %%% * Information Exchange @@ -168,7 +167,8 @@ isakmp_info_recv(iph1, msg0) if (msg->l < sizeof(*isakmp) + sizeof(*gen)) { plog(LLV_ERROR, LOCATION, NULL, "ignore information because the " - "message is way too short - %zu byte(s).\n", msg->l); + "message is way too short - %zu byte(s).\n", + msg->l); goto end; } @@ -179,14 +179,15 @@ isakmp_info_recv(iph1, msg0) if (encrypted) { if (isakmp->np != ISAKMP_NPTYPE_HASH) { plog(LLV_ERROR, LOCATION, NULL, - "ignore information because the" + "ignore information because the " "message has no hash payload.\n"); goto end; } - if (iph1->status != PHASE1ST_ESTABLISHED) { + if (iph1->status != PHASE1ST_ESTABLISHED && + iph1->status != PHASE1ST_DYING) { plog(LLV_ERROR, LOCATION, NULL, - "ignore information because ISAKMP-SA" + "ignore information because ISAKMP-SA " "has not been established yet.\n"); goto end; } @@ -195,7 +196,8 @@ isakmp_info_recv(iph1, msg0) if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) { plog(LLV_ERROR, LOCATION, NULL, "ignore information because the " - "message is too short - %zu byte(s).\n", msg->l); + "message is too short - %zu byte(s).\n", + msg->l); goto end; } @@ -323,6 +325,65 @@ isakmp_info_recv(iph1, msg0) return error; } + +/* + * log unhandled / unallowed Notification payload + */ +int +isakmp_log_notify(iph1, notify, exchange) + struct ph1handle *iph1; + struct isakmp_pl_n *notify; + const char *exchange; +{ + u_int type; + char *nraw, *ndata, *nhex; + size_t l; + + type = ntohs(notify->type); + if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid spi_size in %s notification in %s.\n", + s_isakmp_notify_msg(type), exchange); + return -1; + } + + plog(LLV_ERROR, LOCATION, iph1->remote, + "notification %s received in %s.\n", + s_isakmp_notify_msg(type), exchange); + + nraw = ((char*) notify) + sizeof(*notify) + notify->spi_size; + l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; + if (l > 0) { + if (type >= ISAKMP_NTYPE_MINERROR && + type <= ISAKMP_NTYPE_MAXERROR) { + ndata = binsanitize(nraw, l); + if (ndata != NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "error message: '%s'.\n", + ndata); + racoon_free(ndata); + } else { + plog(LLV_ERROR, LOCATION, iph1->remote, + "Cannot allocate memory\n"); + } + } else { + nhex = val2str(nraw, l); + if (nhex != NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "notification payload: %s.\n", + nhex); + racoon_free(nhex); + } else { + plog(LLV_ERROR, LOCATION, iph1->remote, + "Cannot allocate memory\n"); + } + } + } + + return 0; +} + + /* * handling of Notification payload */ @@ -334,13 +395,8 @@ isakmp_info_recv_n(iph1, notify, msgid, encrypted) int encrypted; { u_int type; - vchar_t *pbuf; - char *nraw, *ndata; - size_t l; - char *spi; type = ntohs(notify->type); - switch (type) { case ISAKMP_NTYPE_CONNECTED: case ISAKMP_NTYPE_RESPONDER_LIFETIME: @@ -352,8 +408,7 @@ isakmp_info_recv_n(iph1, notify, msgid, encrypted) break; case ISAKMP_NTYPE_INITIAL_CONTACT: if (encrypted) - info_recv_initialcontact(iph1); - return 0; + return isakmp_info_recv_initialcontact(iph1, NULL); break; #ifdef ENABLE_DPD case ISAKMP_NTYPE_R_U_THERE: @@ -367,76 +422,23 @@ isakmp_info_recv_n(iph1, notify, msgid, encrypted) (struct isakmp_pl_ru *)notify, msgid); break; #endif - default: - { - /* XXX there is a potential of dos attack. */ - if(type >= ISAKMP_NTYPE_MINERROR && - type <= ISAKMP_NTYPE_MAXERROR) { - if (msgid == 0) { - /* don't think this realy deletes ph1 ? */ - plog(LLV_ERROR, LOCATION, iph1->remote, - "delete phase1 handle.\n"); - return -1; - } else { - if (getph2bymsgid(iph1, msgid) == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "fatal %s notify messsage, " - "phase1 should be deleted.\n", - s_isakmp_notify_msg(type)); - } else { - plog(LLV_ERROR, LOCATION, iph1->remote, - "fatal %s notify messsage, " - "phase2 should be deleted.\n", - s_isakmp_notify_msg(type)); - } - } - } else { - plog(LLV_ERROR, LOCATION, iph1->remote, - "unhandled notify message %s, " - "no phase2 handle found.\n", - s_isakmp_notify_msg(type)); - } - } - break; } - /* get spi if specified and allocate */ - if(notify->spi_size > 0) { - if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "invalid spi_size in notification payload.\n"); - return -1; - } - spi = val2str((char *)(notify + 1), notify->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(notify->doi), notify->proto_id, spi, notify->spi_size); - - racoon_free(spi); - } + /* If we receive a error notification we should delete the related + * phase1 / phase2 handle, and send an event to racoonctl. + * However, since phase1 error notifications are not encrypted and + * can not be authenticated, it would allow a DoS attack possibility + * to handle them. + * Phase2 error notifications should be encrypted, so we could handle + * those, but it needs implementing (the old code didn't implement + * that either). + * So we are good to just log the messages here. + */ + if (encrypted) + isakmp_log_notify(iph1, notify, "informational exchange"); + else + isakmp_log_notify(iph1, notify, "unencrypted informational exchange"); - /* Send the message data to the logs */ - if(type >= ISAKMP_NTYPE_MINERROR && - type <= ISAKMP_NTYPE_MAXERROR) { - l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; - if (l > 0) { - nraw = (char*)notify; - nraw += sizeof(*notify) + notify->spi_size; - ndata = binsanitize(nraw, l); - if (ndata != NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "Message: '%s'.\n", - ndata); - racoon_free(ndata); - } else { - plog(LLV_ERROR, LOCATION, iph1->remote, - "Cannot allocate memory\n"); - } - } - } return 0; } @@ -510,16 +512,16 @@ isakmp_info_recv_d(iph1, delete, msgid, encrypted) del_ph1=getph1byindex((isakmp_index *)(delete + 1)); if(del_ph1 != NULL){ - EVT_PUSH(del_ph1->local, del_ph1->remote, - EVTT_PEERPH1_NOPROP, NULL); - if (del_ph1->scr) - SCHED_KILL(del_ph1->scr); + evt_phase1(iph1, EVT_PHASE1_PEER_DELETED, NULL); + sched_cancel(&del_ph1->scr); /* - * Do not delete IPsec SAs when receiving an IKE delete notification. - * Just delete the IKE SA. + * Delete also IPsec-SAs if rekeying is enabled. */ - isakmp_ph1expire(del_ph1); + if (ph1_rekey_enabled(del_ph1)) + purge_remote(del_ph1); + else + isakmp_ph1expire(del_ph1); } break; @@ -532,8 +534,6 @@ isakmp_info_recv_d(iph1, delete, msgid, encrypted) delete->spi_size, delete->proto_id); return 0; } - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEER_DELETE, NULL); purge_ipsec_spi(iph1->remote, delete->proto_id, (u_int32_t *)(delete + 1), num_spi); break; @@ -636,7 +636,7 @@ isakmp_info_send_d2(iph2) * 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, 0); + iph1 = getph1byaddr(iph2->src, iph2->dst, 0); if (iph1 == NULL){ plog(LLV_DEBUG2, LOCATION, NULL, "No ph1 handler found, could not send DELETE_SA\n"); @@ -696,21 +696,12 @@ isakmp_info_send_nx(isakmp, remote, local, type, data) 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) @@ -719,7 +710,6 @@ isakmp_info_send_nx(isakmp, remote, local, type, data) 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; @@ -734,7 +724,7 @@ isakmp_info_send_nx(isakmp, remote, local, type, data) #endif /* copy remote address */ - if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) + if (copy_ph1addresses(iph1, NULL, remote, local) < 0) goto end; tlen = sizeof(*n) + spisiz; @@ -911,16 +901,6 @@ isakmp_info_send_common(iph1, payload, np, flags) delph2(iph2); goto end; } -#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT)) - if (set_port(iph2->dst, 0) == NULL || - set_port(iph2->src, 0) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph1->remote->sa_family); - delph2(iph2); - goto end; - } -#endif - iph2->ph1 = iph1; iph2->side = INITIATOR; iph2->status = PHASE2ST_START; iph2->msgid = isakmp_newmsgid2(iph1); @@ -934,7 +914,7 @@ isakmp_info_send_common(iph1, payload, np, flags) } /* generate HASH(1) */ - hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload); + hash = oakley_compute_hash1(iph1, iph2->msgid, payload); if (hash == NULL) { delph2(iph2); goto end; @@ -1035,7 +1015,6 @@ end: return error; err: - unbindph12(iph2); remph2(iph2); delph2(iph2); goto end; @@ -1114,9 +1093,8 @@ purge_isakmp_spi(proto, spi, n) s_ipsecdoi_proto(proto), isakmp_pindex(&spi[i], 0)); - SCHED_KILL(iph1->sce); iph1->status = PHASE1ST_EXPIRED; - iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + isakmp_ph1delete(iph1); } } @@ -1138,10 +1116,6 @@ purge_ipsec_spi(dst0, proto, spi, n) u_int64_t created; size_t i; caddr_t mhp[SADB_EXT_MAX + 1]; -#ifdef ENABLE_NATT - struct sadb_x_nat_t_type *natt_type; - struct sadb_x_nat_t_port *natt_port; -#endif plog(LLV_DEBUG2, LOCATION, NULL, "purge_ipsec_spi:\n"); @@ -1181,6 +1155,7 @@ purge_ipsec_spi(dst0, proto, spi, n) msg = next; continue; } + pk_fixup_sa_addresses(mhp); src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); lt = (struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD]; @@ -1194,25 +1169,7 @@ purge_ipsec_spi(dst0, proto, spi, n) msg = next; continue; } -#ifdef ENABLE_NATT - natt_type = (void *)mhp[SADB_X_EXT_NAT_T_TYPE]; - if (natt_type && natt_type->sadb_x_nat_t_type_type) { - /* NAT-T is enabled for this SADB entry; copy - * the ports from NAT-T extensions */ - natt_port = (void *)mhp[SADB_X_EXT_NAT_T_SPORT]; - if (extract_port(src) == 0 && natt_port != NULL) - set_port(src, ntohs(natt_port->sadb_x_nat_t_port_port)); - - natt_port = (void *)mhp[SADB_X_EXT_NAT_T_DPORT]; - if (extract_port(dst) == 0 && natt_port != NULL) - set_port(dst, ntohs(natt_port->sadb_x_nat_t_port_port)); - }else{ - /* Force default UDP ports, so CMPSADDR will match SAs with NO encapsulation - */ - set_port(src, PORT_ISAKMP); - set_port(dst, PORT_ISAKMP); - } -#endif + plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(src)); plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(dst)); @@ -1220,20 +1177,11 @@ purge_ipsec_spi(dst0, proto, spi, n) /* don't delete inbound SAs at the moment */ /* XXX should we remove SAs with opposite direction as well? */ - if (CMPSADDR(dst0, dst)) { + if (cmpsaddr(dst0, dst) != CMPSADDR_MATCH) { msg = next; continue; } -#ifdef ENABLE_NATT - if (natt_type == NULL || - ! natt_type->sadb_x_nat_t_type_type) { - /* Set back port to 0 if it was forced to default UDP port - */ - set_port(src, 0); - set_port(dst, 0); - } -#endif for (i = 0; i < n; i++) { plog(LLV_DEBUG, LOCATION, NULL, "check spi(packet)=%u spi(db)=%u.\n", @@ -1254,7 +1202,6 @@ purge_ipsec_spi(dst0, proto, spi, n) iph2 = getph2bysaidx(src, dst, proto, spi[i]); if(iph2 != NULL){ delete_spd(iph2, created); - unbindph12(iph2); remph2(iph2); delph2(iph2); } @@ -1273,15 +1220,17 @@ purge_ipsec_spi(dst0, proto, spi, n) } /* - * delete all phase2 sa relatived to the destination address. + * delete all phase2 sa relatived to the destination address + * (except the phase2 within which the INITIAL-CONTACT was received). * 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) +int +isakmp_info_recv_initialcontact(iph1, protectedph2) struct ph1handle *iph1; + struct ph2handle *protectedph2; { vchar_t *buf = NULL; struct sadb_msg *msg, *next, *end; @@ -1294,8 +1243,10 @@ info_recv_initialcontact(iph1) char *loc, *rem; #endif + plog(LLV_INFO, LOCATION, iph1->remote, "received INITIAL-CONTACT\n"); + if (f_local) - return; + return 0; #if 0 loc = racoon_strdup(saddrwop2str(iph1->local)); @@ -1344,7 +1295,7 @@ info_recv_initialcontact(iph1) racoon_free(loc); racoon_free(rem); - return; + return 0; the_hard_way: racoon_free(loc); @@ -1355,43 +1306,39 @@ info_recv_initialcontact(iph1) if (buf == NULL) { plog(LLV_DEBUG, LOCATION, NULL, "pfkey_dump_sadb returned nothing.\n"); - return; + return 0; } msg = (struct sadb_msg *)buf->v; end = (struct sadb_msg *)(buf->v + buf->l); - while (msg < end) { + for (; msg < end; msg = next) { 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; + if (msg->sadb_msg_type != SADB_DUMP) 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; + || mhp[SADB_EXT_ADDRESS_DST] == NULL) continue; - } + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + pk_fixup_sa_addresses(mhp); 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; + && sa->sadb_sa_state != SADB_SASTATE_DYING) continue; - } /* * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that @@ -1401,39 +1348,18 @@ info_recv_initialcontact(iph1) * 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; + + /* + * Check that the IP and port match. But this is not optimal, + * since NAT-T can make the peer have multiple different + * ports. Correct thing to do is delete all entries with + * same identity. -TT + */ + if ((cmpsaddr(iph1->local, src) != CMPSADDR_MATCH || + cmpsaddr(iph1->remote, dst) != CMPSADDR_MATCH) && + (cmpsaddr(iph1->local, dst) != CMPSADDR_MATCH || + cmpsaddr(iph1->remote, src) != CMPSADDR_MATCH)) continue; - } /* * Make sure this is an SATYPE that we manage. @@ -1445,10 +1371,8 @@ info_recv_initialcontact(iph1) msg->sadb_msg_satype) break; } - if (i == pfkey_nsatypes) { - msg = next; + if (i == pfkey_nsatypes) continue; - } plog(LLV_INFO, LOCATION, NULL, "purging spi=%u.\n", ntohl(sa->sadb_sa_spi)); @@ -1463,54 +1387,15 @@ info_recv_initialcontact(iph1) */ proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); - if (iph2) { + if (iph2 && iph2 != protectedph2) { delete_spd(iph2, 0); - unbindph12(iph2); remph2(iph2); delph2(iph2); } - - msg = next; } vfree(buf); -} - -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: - case ISAKMP_NTYPE_RESPONDER_LIFETIME: - case ISAKMP_NTYPE_REPLAY_STATUS: - case ISAKMP_NTYPE_HEARTBEAT: -#ifdef ENABLE_HYBRID - case ISAKMP_NTYPE_UNITY_HEARTBEAT: -#endif - plog(LLV_WARNING, LOCATION, iph1->remote, - "ignore %s notification.\n", - s_isakmp_notify_msg(ntohs(notify->type))); - 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; - default: - isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); - plog(LLV_ERROR, LOCATION, iph1->remote, - "received unknown notification type %s.\n", - s_isakmp_notify_msg(ntohs(notify->type))); - } - - return; + return 0; } @@ -1567,17 +1452,16 @@ isakmp_info_recv_r_u_ack (iph1, ru, msgid) struct isakmp_pl_ru *ru; u_int32_t msgid; { + u_int32_t seq; 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) { + seq = ntohl(ru->data); + if (seq <= iph1->dpd_last_ack || seq > iph1->dpd_seq) { plog(LLV_ERROR, LOCATION, iph1->remote, - "Wrong DPD sequence number (%d, %d expected).\n", - ntohl(ru->data), iph1->dpd_seq-1); + "Wrong DPD sequence number (%d; last_ack=%d, seq=%d).\n", + seq, iph1->dpd_last_ack, iph1->dpd_seq); return 0; } @@ -1589,12 +1473,8 @@ isakmp_info_recv_r_u_ack (iph1, ru, msgid) } iph1->dpd_fails = 0; - - /* Useless ??? */ - iph1->dpd_lastack = time(NULL); - - SCHED_KILL(iph1->dpd_r_u); - + iph1->dpd_last_ack = seq; + sched_cancel(&iph1->dpd_r_u); isakmp_sched_r_u(iph1, 0); plog(LLV_DEBUG, LOCATION, NULL, "received an R-U-THERE-ACK\n"); @@ -1609,10 +1489,10 @@ isakmp_info_recv_r_u_ack (iph1, ru, msgid) * send DPD R-U-THERE payload in Informational exchange. */ static void -isakmp_info_send_r_u(arg) - void *arg; +isakmp_info_send_r_u(sc) + struct sched *sc; { - struct ph1handle *iph1 = arg; + struct ph1handle *iph1 = container_of(sc, struct ph1handle, dpd_r_u); /* create R-U-THERE payload */ struct isakmp_pl_ru *ru; @@ -1622,7 +1502,14 @@ isakmp_info_send_r_u(arg) plog(LLV_DEBUG, LOCATION, iph1->remote, "DPD monitoring....\n"); - iph1->dpd_r_u=NULL; + if (iph1->status == PHASE1ST_EXPIRED) { + /* This can happen after removing tunnels from the + * config file and then reloading. + * Such iph1 have rmconf=NULL, so return before the if + * block below. + */ + return; + } if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) { @@ -1630,7 +1517,8 @@ isakmp_info_send_r_u(arg) "DPD: remote (ISAKMP-SA spi=%s) seems to be dead.\n", isakmp_pindex(&iph1->index, 0)); - EVT_PUSH(iph1->local, iph1->remote, EVTT_DPD_TIMEOUT, NULL); + script_hook(iph1, SCRIPT_PHASE1_DEAD); + evt_phase1(iph1, EVT_PHASE1_DPD_TIMEOUT, NULL); purge_remote(iph1); /* Do not reschedule here: phase1 is deleted, @@ -1659,12 +1547,13 @@ isakmp_info_send_r_u(arg) 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){ + if (iph1->dpd_seq == 0) { /* generate a random seq which is not too big */ - srand(time(NULL)); - iph1->dpd_seq = rand() & 0x0fff; + iph1->dpd_seq = iph1->dpd_last_ack = rand() & 0x0fff; } + iph1->dpd_seq++; + iph1->dpd_fails++; ru->data = htonl(iph1->dpd_seq); error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); @@ -1673,12 +1562,6 @@ isakmp_info_send_r_u(arg) 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); @@ -1703,11 +1586,11 @@ isakmp_sched_r_u(iph1, retry) return 0; if(retry) - iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_retry, - isakmp_info_send_r_u, iph1); + sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_retry, + isakmp_info_send_r_u); else - iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_interval, - isakmp_info_send_r_u, iph1); + sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_interval, + isakmp_info_send_r_u); return 0; } diff --git a/src/racoon/isakmp_inf.h b/src/racoon/isakmp_inf.h index c7682d9..40cdc02 100644 --- a/src/racoon/isakmp_inf.h +++ b/src/racoon/isakmp_inf.h @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_inf.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: isakmp_inf.h,v 1.5 2008/07/14 05:40:13 tteras Exp $ */ /* Id: isakmp_inf.h,v 1.6 2005/05/07 14:15:59 manubsd Exp */ @@ -48,7 +48,8 @@ extern int isakmp_info_send_common __P((struct ph1handle *, 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 *)); +extern int isakmp_log_notify __P((struct ph1handle *, struct isakmp_pl_n *, const char *exchange)); +extern int isakmp_info_recv_initialcontact __P((struct ph1handle *, struct ph2handle *)); #ifdef ENABLE_DPD extern int isakmp_sched_r_u __P((struct ph1handle *, int)); diff --git a/src/racoon/isakmp_quick.c b/src/racoon/isakmp_quick.c index 963438d..056e905 100644 --- a/src/racoon/isakmp_quick.c +++ b/src/racoon/isakmp_quick.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_quick.c,v 1.11.4.1 2007/08/01 11:52:21 vanhu Exp $ */ +/* $NetBSD: isakmp_quick.c,v 1.29 2011/03/14 17:18:13 tteras Exp $ */ /* Id: isakmp_quick.c,v 1.29 2006/08/22 18:17:17 manubsd Exp */ @@ -53,9 +53,6 @@ # include <time.h> # endif #endif -#ifdef ENABLE_HYBRID -#include <resolv.h> -#endif #include PATH_IPSEC_H @@ -87,10 +84,47 @@ #include "admin.h" #include "strnames.h" +#ifdef ENABLE_HYBRID +#include <resolv.h> +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" +#endif + +#ifdef ENABLE_NATT +#include "nattraversal.h" +#endif + /* 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 *)); +static int ph2_recv_n __P((struct ph2handle *, struct isakmp_gen *)); +static void quick_timeover_stub __P((struct sched *)); +static void quick_timeover __P((struct ph2handle *)); + +/* called from scheduler */ +static void +quick_timeover_stub(p) + struct sched *p; +{ + quick_timeover(container_of(p, struct ph2handle, sce)); +} + +static void +quick_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)); + + /* If initiator side, send error to kernel by SADB_ACQUIRE. */ + if (iph2->side == INITIATOR) + pk_sendeacquire(iph2); + + remph2(iph2); + delph2(iph2); +} /* %%% * Quick Mode @@ -131,8 +165,8 @@ quick_i1prep(iph2, msg) plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); - iph2->sce = sched_new(lcconf->wait_ph2complete, - pfkey_timeover_stub, iph2); + sched_schedule(&iph2->sce, lcconf->wait_ph2complete, + quick_timeover_stub); error = 0; @@ -142,7 +176,7 @@ end: /* * send to responder - * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ] */ int quick_i1send(iph2, msg) @@ -155,9 +189,14 @@ quick_i1send(iph2, msg) char *p; int tlen; int error = ISAKMP_INTERNAL_ERROR; + int natoa = ISAKMP_NPTYPE_NONE; int pfsgroup, idci, idcr; int np; struct ipsecdoi_id_b *id, *id_p; +#ifdef ENABLE_NATT + vchar_t *nat_oai = NULL; + vchar_t *nat_oar = NULL; +#endif /* validity check */ if (msg != NULL) { @@ -217,17 +256,49 @@ quick_i1send(iph2, msg) * - no MIP6 or proxy * - id payload suggests to encrypt all the traffic (no specific * protocol type) + * - SA endpoints and IKE addresses for the nego are the same + * (iph2->src/dst) */ 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)) { + if (id->proto_id == 0 && + id_p->proto_id == 0 && + iph2->ph1->rmconf->support_proxy == 0 && + iph2->sa_src == NULL && iph2->sa_dst == NULL && + ipsecdoi_transportmode(iph2->proposal)) { idci = idcr = 0; } else idci = idcr = 1; +#ifdef ENABLE_NATT + /* + * RFC3947 5.2. if we propose UDP-Encapsulated-Transport + * we should send NAT-OA + */ + if (ipsecdoi_transportmode(iph2->proposal) + && (iph2->ph1->natt_flags & NAT_DETECTED)) { + natoa = iph2->ph1->natt_options->payload_nat_oa; + + nat_oai = ipsecdoi_sockaddr2id(iph2->src, + IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); + nat_oar = ipsecdoi_sockaddr2id(iph2->dst, + IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); + + if (nat_oai == NULL || nat_oar == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to generate NAT-OA payload.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n"); + plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l); + plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n"); + plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l); + } else { + natoa = ISAKMP_NPTYPE_NONE; + } +#endif + /* create SA;NONCE payload, and KE if need, and IDii, IDir. */ tlen = + sizeof(*gen) + iph2->sa->l + sizeof(*gen) + iph2->nonce->l; @@ -237,6 +308,10 @@ quick_i1send(iph2, msg) tlen += sizeof(*gen) + iph2->id->l; if (idcr) tlen += sizeof(*gen) + iph2->id_p->l; +#ifdef ENABLE_NATT + if (natoa != ISAKMP_NPTYPE_NONE) + tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l; +#endif body = vmalloc(tlen); if (body == NULL) { @@ -256,22 +331,30 @@ quick_i1send(iph2, msg) else if (idci || idcr) np = ISAKMP_NPTYPE_ID; else - np = ISAKMP_NPTYPE_NONE; + np = natoa; p = set_isakmp_payload(p, iph2->nonce, np); /* add KE payload if need. */ - np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; + np = (idci || idcr) ? ISAKMP_NPTYPE_ID : natoa; if (pfsgroup) p = set_isakmp_payload(p, iph2->dhpub, np); /* IDci */ - np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; + np = (idcr) ? ISAKMP_NPTYPE_ID : natoa; if (idci) p = set_isakmp_payload(p, iph2->id, np); /* IDcr */ if (idcr) - p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE); + p = set_isakmp_payload(p, iph2->id_p, natoa); + +#ifdef ENABLE_NATT + /* NAT-OA */ + if (natoa != ISAKMP_NPTYPE_NONE) { + p = set_isakmp_payload(p, nat_oai, natoa); + p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE); + } +#endif /* generate HASH(1) */ hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body); @@ -284,8 +367,7 @@ quick_i1send(iph2, msg) goto end; /* send the packet, add to the schedule to resend */ - iph2->retry_counter = iph2->ph1->rmconf->retry_counter; - if (isakmp_ph2resend(iph2) == -1) + if (isakmp_ph2send(iph2) == -1) goto end; /* change status of isakmp status entry */ @@ -298,13 +380,19 @@ end: vfree(body); if (hash != NULL) vfree(hash); +#ifdef ENABLE_NATT + if (nat_oai != NULL) + vfree(nat_oai); + if (nat_oar != NULL) + vfree(nat_oar); +#endif return error; } /* * receive from responder - * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ] */ int quick_i2recv(iph2, msg0) @@ -314,10 +402,11 @@ quick_i2recv(iph2, msg0) vchar_t *msg = NULL; vchar_t *hbuf = NULL; /* for hash computing. */ vchar_t *pbuf = NULL; /* for payload parsing */ + vchar_t *idci = NULL; + vchar_t *idcr = NULL; 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; @@ -391,7 +480,6 @@ quick_i2recv(iph2, msg0) * 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++) { @@ -407,54 +495,84 @@ quick_i2recv(iph2, msg0) "isn't supported.\n"); break; } - if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_SA.\n"); goto end; + } break; case ISAKMP_NPTYPE_NONCE: - if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_NONCE.\n"); goto end; + } break; case ISAKMP_NPTYPE_KE: - if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_KE.\n"); 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; + if (idci == NULL) { + if (isakmp_p2ph(&idci, pa->ptr) < 0) + goto end; + } else if (idcr == NULL) { + if (isakmp_p2ph(&idcr, pa->ptr) < 0) + goto end; } else { - /* for IDcr */ - vp = iph2->id_p; - } - -#ifndef ANDROID_PATCHED - if (memcmp(vp->v, (caddr_t)pa->ptr + sizeof(struct isakmp_gen), vp->l)) { - - plog(LLV_ERROR, LOCATION, NULL, - "mismatched ID was returned.\n"); - error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "too many ISAKMP_NPTYPE_ID payloads.\n"); goto end; } -#endif - } break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); + ph2_recv_n(iph2, pa->ptr); break; #ifdef ENABLE_NATT case ISAKMP_NPTYPE_NATOA_DRAFT: case ISAKMP_NPTYPE_NATOA_RFC: - /* Ignore original source/destination messages */ + { + struct sockaddr_storage addr; + struct sockaddr *daddr; + u_int8_t prefix; + u_int16_t ul_proto; + vchar_t *vp = NULL; + + if (isakmp_p2ph(&vp, pa->ptr) < 0) + goto end; + + error = ipsecdoi_id2sockaddr(vp, + (struct sockaddr *) &addr, + &prefix, &ul_proto); + + vfree(vp); + + if (error) + goto end; + + daddr = dupsaddr((struct sockaddr *) &addr); + if (daddr == NULL) + goto end; + + if (iph2->natoa_src == NULL) + iph2->natoa_src = daddr; + else if (iph2->natoa_dst == NULL) + iph2->natoa_dst = daddr; + else { + racoon_free(daddr); + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "too many ISAKMP_NPTYPE_NATOA payloads.\n"); + goto end; + } + } break; #endif @@ -480,6 +598,118 @@ quick_i2recv(iph2, msg0) goto end; } +#ifdef ANDROID_PATCHED + if (idcr != NULL) { + struct ipsecdoi_id_b *id_b = idcr->v; + if (id_b->type != IPSECDOI_ID_IPV4_ADDR && + id_b->type != IPSECDOI_ID_IPV4_ADDR_SUBNET && + id_b->type != IPSECDOI_ID_IPV6_ADDR && + id_b->type != IPSECDOI_ID_IPV6_ADDR_SUBNET) { + vfree(idcr); + idcr = NULL; + } + } +#endif + + /* identity check */ + if (idci != NULL) { + struct sockaddr_storage proposed_addr, got_addr; + u_int8_t proposed_prefix, got_prefix; + u_int16_t proposed_ulproto, got_ulproto; + + error = ipsecdoi_id2sockaddr(iph2->id, + (struct sockaddr *) &proposed_addr, + &proposed_prefix, &proposed_ulproto); + if (error) + goto end; + + error = ipsecdoi_id2sockaddr(idci, + (struct sockaddr *) &got_addr, + &got_prefix, &got_ulproto); + if (error) + goto end; + + if (proposed_prefix != got_prefix + || proposed_ulproto != got_ulproto) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDci prefix/ulproto does not match proposal.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } +#ifdef ENABLE_NATT + set_port(iph2->natoa_src, + extract_port((struct sockaddr *) &proposed_addr)); +#endif + + if (cmpsaddr((struct sockaddr *) &proposed_addr, + (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDci matches proposal.\n"); +#ifdef ENABLE_NATT + } else if (iph2->natoa_src != NULL + && cmpsaddr(iph2->natoa_src, + (struct sockaddr *) &got_addr) == 0) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDci matches NAT-OAi.\n"); +#endif +#ifndef ANDROID_PATCHED + } else { + plog(LLV_ERROR, LOCATION, NULL, + "mismatched IDci was returned.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; +#endif + } + } + if (idcr != NULL) { + struct sockaddr_storage proposed_addr, got_addr; + u_int8_t proposed_prefix, got_prefix; + u_int16_t proposed_ulproto, got_ulproto; + + error = ipsecdoi_id2sockaddr(iph2->id_p, + (struct sockaddr *) &proposed_addr, + &proposed_prefix, &proposed_ulproto); + if (error) + goto end; + + error = ipsecdoi_id2sockaddr(idcr, + (struct sockaddr *) &got_addr, + &got_prefix, &got_ulproto); + if (error) + goto end; + + if (proposed_prefix != got_prefix + || proposed_ulproto != got_ulproto) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDcr prefix/ulproto does not match proposal.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } + +#ifdef ENABLE_NATT + set_port(iph2->natoa_dst, + extract_port((struct sockaddr *) &proposed_addr)); +#endif + + if (cmpsaddr((struct sockaddr *) &proposed_addr, + (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDcr matches proposal.\n"); +#ifdef ENABLE_NATT + } else if (iph2->natoa_dst != NULL + && cmpsaddr(iph2->natoa_dst, + (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) { + plog(LLV_DEBUG, LOCATION, NULL, + "IDcr matches NAT-OAr.\n"); +#endif + } else { + plog(LLV_ERROR, LOCATION, NULL, + "mismatched IDcr was returned.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } + } + /* Fixed buffer for calculating HASH */ memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l); plog(LLV_DEBUG, LOCATION, NULL, @@ -516,6 +746,8 @@ quick_i2recv(iph2, msg0) /* validity check SA payload sent from responder */ if (ipsecdoi_checkph2proposal(iph2) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "proposal check failed.\n"); error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; goto end; } @@ -532,6 +764,10 @@ end: vfree(pbuf); if (msg) vfree(msg); + if (idci) + vfree(idci); + if (idcr) + vfree(idcr); if (error) { VPTRINIT(iph2->sa_ret); @@ -539,6 +775,16 @@ end: VPTRINIT(iph2->dhpub_p); VPTRINIT(iph2->id); VPTRINIT(iph2->id_p); +#ifdef ENABLE_NATT + if (iph2->natoa_src) { + racoon_free(iph2->natoa_src); + iph2->natoa_src = NULL; + } + if (iph2->natoa_dst) { + racoon_free(iph2->natoa_dst); + iph2->natoa_dst = NULL; + } +#endif } return error; @@ -619,8 +865,7 @@ quick_i2send(iph2, msg0) /* 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) + if (isakmp_ph2send(iph2) == -1) goto end; } else { /* send the packet */ @@ -735,7 +980,7 @@ quick_i3recv(iph2, msg0) "Ignoring multiples notifications\n"); break; } - isakmp_check_notify(pa->ptr, iph2->ph1); + ph2_recv_n(iph2, pa->ptr); notify = vmalloc(pa->len); if (notify == NULL) { plog(LLV_ERROR, LOCATION, NULL, @@ -828,7 +1073,7 @@ end: /* * receive from initiator - * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ] */ int quick_r1recv(iph2, msg0) @@ -862,8 +1107,11 @@ quick_r1recv(iph2, msg0) } /* decrypt packet */ msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); - if (msg == NULL) + if (msg == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet decryption failed.\n"); goto end; + } /* create buffer for using to validate HASH(1) */ /* @@ -947,18 +1195,27 @@ quick_r1recv(iph2, msg0) "Multi SAs isn't supported.\n"); goto end; } - if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_SA.\n"); goto end; + } break; case ISAKMP_NPTYPE_NONCE: - if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_NONCE.\n"); goto end; + } break; case ISAKMP_NPTYPE_KE: - if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "duplicate ISAKMP_NPTYPE_KE.\n"); goto end; + } break; case ISAKMP_NPTYPE_ID: @@ -991,13 +1248,47 @@ quick_r1recv(iph2, msg0) break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); + ph2_recv_n(iph2, pa->ptr); break; #ifdef ENABLE_NATT case ISAKMP_NPTYPE_NATOA_DRAFT: case ISAKMP_NPTYPE_NATOA_RFC: - /* Ignore original source/destination messages */ + { + struct sockaddr_storage addr; + struct sockaddr *daddr; + u_int8_t prefix; + u_int16_t ul_proto; + vchar_t *vp = NULL; + + if (isakmp_p2ph(&vp, pa->ptr) < 0) + goto end; + + error = ipsecdoi_id2sockaddr(vp, + (struct sockaddr *) &addr, + &prefix, &ul_proto); + + vfree(vp); + + if (error) + goto end; + + daddr = dupsaddr((struct sockaddr *) &addr); + if (daddr == NULL) + goto end; + + if (iph2->natoa_dst == NULL) + iph2->natoa_dst = daddr; + else if (iph2->natoa_src == NULL) + iph2->natoa_src = daddr; + else { + racoon_free(daddr); + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "received too many NAT-OA payloads.\n"); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + } break; #endif @@ -1080,12 +1371,15 @@ quick_r1recv(iph2, msg0) plog(LLV_ERROR, LOCATION, NULL, "failed to generate a proposal template " "from client's proposal.\n"); - return ISAKMP_INTERNAL_ERROR; + error = ISAKMP_INTERNAL_ERROR; + goto end; } /*FALLTHROUGH*/ case 0: /* select single proposal or reject it. */ if (ipsecdoi_selectph2proposal(iph2) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "no proposal chosen.\n"); error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; goto end; } @@ -1135,6 +1429,16 @@ end: VPTRINIT(iph2->dhpub_p); VPTRINIT(iph2->id); VPTRINIT(iph2->id_p); +#ifdef ENABLE_NATT + if (iph2->natoa_src) { + racoon_free(iph2->natoa_src); + iph2->natoa_src = NULL; + } + if (iph2->natoa_dst) { + racoon_free(iph2->natoa_dst); + iph2->natoa_dst = NULL; + } +#endif } return error; @@ -1165,8 +1469,8 @@ quick_r1prep(iph2, msg) plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); - iph2->sce = sched_new(lcconf->wait_ph2complete, - pfkey_timeover_stub, iph2); + sched_schedule(&iph2->sce, lcconf->wait_ph2complete, + quick_timeover_stub); error = 0; @@ -1176,7 +1480,7 @@ end: /* * send to initiator - * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ] */ int quick_r2send(iph2, msg) @@ -1189,8 +1493,13 @@ quick_r2send(iph2, msg) char *p; int tlen; int error = ISAKMP_INTERNAL_ERROR; + int natoa = ISAKMP_NPTYPE_NONE; int pfsgroup; u_int8_t *np_p = NULL; +#ifdef ENABLE_NATT + vchar_t *nat_oai = NULL; + vchar_t *nat_oar = NULL; +#endif /* validity check */ if (msg != NULL) { @@ -1231,6 +1540,33 @@ quick_r2send(iph2, msg) } } +#ifdef ENABLE_NATT + /* + * RFC3947 5.2. if we chose UDP-Encapsulated-Transport + * we should send NAT-OA + */ + if (ipsecdoi_transportmode(iph2->proposal) + && (iph2->ph1->natt_flags & NAT_DETECTED)) { + natoa = iph2->ph1->natt_options->payload_nat_oa; + + nat_oai = ipsecdoi_sockaddr2id(iph2->dst, + IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); + nat_oar = ipsecdoi_sockaddr2id(iph2->src, + IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); + + if (nat_oai == NULL || nat_oar == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to generate NAT-OA payload.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n"); + plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l); + plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n"); + plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l); + } +#endif + /* create SA;NONCE payload, and KE and ID if need */ tlen = sizeof(*gen) + iph2->sa_ret->l + sizeof(*gen) + iph2->nonce->l; @@ -1239,6 +1575,10 @@ quick_r2send(iph2, msg) if (iph2->id_p != NULL) tlen += (sizeof(*gen) + iph2->id_p->l + sizeof(*gen) + iph2->id->l); +#ifdef ENABLE_NATT + if (natoa != ISAKMP_NPTYPE_NONE) + tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l; +#endif body = vmalloc(tlen); if (body == NULL) { @@ -1258,14 +1598,14 @@ quick_r2send(iph2, msg) ? ISAKMP_NPTYPE_KE : (iph2->id_p != NULL ? ISAKMP_NPTYPE_ID - : ISAKMP_NPTYPE_NONE)); + : natoa)); /* 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) - ? ISAKMP_NPTYPE_NONE + ? natoa : ISAKMP_NPTYPE_ID); } @@ -1275,9 +1615,17 @@ quick_r2send(iph2, msg) p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID); /* IDcr */ np_p = &((struct isakmp_gen *)p)->np; /* XXX */ - p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE); + p = set_isakmp_payload(p, iph2->id, natoa); } +#ifdef ENABLE_NATT + /* NAT-OA */ + if (natoa != ISAKMP_NPTYPE_NONE) { + p = set_isakmp_payload(p, nat_oai, natoa); + p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE); + } +#endif + /* add a RESPONDER-LIFETIME notify payload if needed */ { vchar_t *data = NULL; @@ -1350,8 +1698,7 @@ quick_r2send(iph2, msg) goto end; /* send the packet, add to the schedule to resend */ - iph2->retry_counter = iph2->ph1->rmconf->retry_counter; - if (isakmp_ph2resend(iph2) == -1) + if (isakmp_ph2send(iph2) == -1) goto end; /* the sending message is added to the received-list. */ @@ -1371,6 +1718,12 @@ end: vfree(body); if (hash != NULL) vfree(hash); +#ifdef ENABLE_NATT + if (nat_oai != NULL) + vfree(nat_oai); + if (nat_oar != NULL) + vfree(nat_oar); +#endif return error; } @@ -1378,6 +1731,7 @@ end: /* * receive from initiator * HDR*, HASH(3) + */ int quick_r3recv(iph2, msg0) @@ -1421,7 +1775,7 @@ quick_r3recv(iph2, msg0) hash = (struct isakmp_pl_hash *)pa->ptr; break; case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); + ph2_recv_n(iph2, pa->ptr); break; default: /* don't send information, see ident_r1recv() */ @@ -1802,25 +2156,11 @@ static int get_sainfo_r(iph2) struct ph2handle *iph2; { - vchar_t *idsrc = NULL, *iddst = NULL; - int prefixlen; + vchar_t *idsrc = NULL, *iddst = NULL, *client = NULL; int error = ISAKMP_INTERNAL_ERROR; - int remoteid = 0; if (iph2->id == 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, + idsrc = ipsecdoi_sockaddr2id(iph2->src, IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); } else { idsrc = vdup(iph2->id); @@ -1832,19 +2172,7 @@ get_sainfo_r(iph2) } if (iph2->id_p == 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, + iddst = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY); } else { iddst = vdup(iph2->id_p); @@ -1855,19 +2183,34 @@ get_sainfo_r(iph2) goto end; } - { - struct remoteconf *conf; - conf = getrmconf(iph2->dst); - if (conf != NULL) - remoteid=conf->ph1id; - else{ - plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n"); - remoteid=0; +#ifdef ENABLE_HYBRID + + /* clientaddr check : obtain modecfg address */ + if (iph2->ph1->mode_cfg != NULL) { + if ((iph2->ph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN) || + (iph2->ph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_LOCAL)){ + struct sockaddr saddr; + saddr.sa_family = AF_INET; +#ifndef __linux__ + saddr.sa_len = sizeof(struct sockaddr_in); +#endif + ((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY; + memcpy(&((struct sockaddr_in *)&saddr)->sin_addr, + &iph2->ph1->mode_cfg->addr4, sizeof(struct in_addr)); + client = ipsecdoi_sockaddr2id(&saddr, 32, IPSEC_ULPROTO_ANY); } - } - iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, remoteid); + /* clientaddr check, fallback to peer address */ + if (client == NULL) + { + client = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST, + IPSEC_ULPROTO_ANY); + } +#endif + + /* obtain a matching sainfo section */ + iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, client, iph2->ph1->rmconf->ph1id); if (iph2->sainfo == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get sainfo.\n"); @@ -1890,6 +2233,8 @@ end: vfree(idsrc); if (iddst) vfree(iddst); + if (client) + vfree(client); return error; } @@ -1921,8 +2266,8 @@ get_proposal_r(iph2) return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } - /* make sure if id[src,dst] is null. */ - if (iph2->src_id || iph2->dst_id) { + /* make sure if sa_[src, dst] are null. */ + if (iph2->sa_src || iph2->sa_dst) { plog(LLV_ERROR, LOCATION, NULL, "Why do ID[src,dst] exist already.\n"); return ISAKMP_INTERNAL_ERROR; @@ -2026,29 +2371,45 @@ get_proposal_r(iph2) } #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); - if (iph2->src_id == NULL) { + /* Before setting iph2->[sa_src, sa_dst] with the addresses + * provided in ID payloads, we check: + * - they are both addresses of same family + * - sainfo has not been selected only based on ID payload + * information but also based on specific Phase 1 + * credentials (iph2->sainfo->id_i is defined), i.e. + * local configuration _explicitly_ expect that user + * (e.g. from asn1dn "C=FR, ...") with those IDs) */ + if (_XIDT(iph2->id_p) == idi2type && + spidx.dst.ss_family == spidx.src.ss_family && + iph2->sainfo && iph2->sainfo->id_i) { + + iph2->sa_src = dupsaddr((struct sockaddr *)&spidx.dst); + if (iph2->sa_src == NULL) { plog(LLV_ERROR, LOCATION, NULL, "buffer allocation failed.\n"); return ISAKMP_INTERNAL_ERROR; } - iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src); - if (iph2->dst_id == NULL) { + + iph2->sa_dst = dupsaddr((struct sockaddr *)&spidx.src); + if (iph2->sa_dst == NULL) { plog(LLV_ERROR, LOCATION, NULL, "buffer allocation failed.\n"); return ISAKMP_INTERNAL_ERROR; } + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "Either family (%d - %d), types (%d - %d) of ID " + "from initiator differ or matching sainfo " + "has no id_i defined for the peer. Not filling " + "iph2->sa_src and iph2->sa_dst.\n", + spidx.src.ss_family, spidx.dst.ss_family, + _XIDT(iph2->id_p),idi2type); } - } 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"); + "get a source address of SP index from Phase 1" + "addresses 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)); @@ -2070,7 +2431,7 @@ get_proposal_r(iph2) #undef _XIDT plog(LLV_DEBUG, LOCATION, NULL, - "get a src address from ID payload " + "get src address from ID payload " "%s prefixlen=%u ul_proto=%u\n", saddr2str((struct sockaddr *)&spidx.src), spidx.prefs, spidx.ul_proto); @@ -2184,6 +2545,76 @@ get_proposal_r(iph2) } #endif /* HAVE_SECCTX */ + iph2->spid = sp_in->id; + + return 0; +} + +/* + * handle a notification payload inside phase2 exchange. + * phase2 is always encrypted, so it does not need to be checked + * for explicitely. + */ +static int +ph2_recv_n(iph2, gen) + struct ph2handle *iph2; + struct isakmp_gen *gen; +{ + struct ph1handle *iph1 = iph2->ph1; + struct isakmp_pl_n *notify = (struct isakmp_pl_n *) gen; + u_int type; + int check_level; + + type = ntohs(notify->type); + switch (type) { + case ISAKMP_NTYPE_CONNECTED: + break; + case ISAKMP_NTYPE_INITIAL_CONTACT: + return isakmp_info_recv_initialcontact(iph1, iph2); + case ISAKMP_NTYPE_RESPONDER_LIFETIME: + ipsecdoi_parse_responder_lifetime(notify, + &iph2->lifetime_secs, &iph2->lifetime_kb); + + if (iph1 != NULL && iph1->rmconf != NULL) { + check_level = iph1->rmconf->pcheck_level; + } else { + if (iph1 != NULL) + plog(LLV_DEBUG, LOCATION, NULL, + "No phase1 rmconf found !\n"); + else + plog(LLV_DEBUG, LOCATION, NULL, + "No phase1 found !\n"); + check_level = PROP_CHECK_EXACT; + } + + switch (check_level) { + case PROP_CHECK_OBEY: + break; + case PROP_CHECK_STRICT: + case PROP_CHECK_CLAIM: + if (iph2->sainfo == NULL + || iph2->sainfo->lifetime <= iph2->lifetime_secs) { + plog(LLV_WARNING, LOCATION, NULL, + "RESPONDER-LIFETIME: lifetime mismatch\n"); + iph2->lifetime_secs = 0; + } + break; + case PROP_CHECK_EXACT: + if (iph2->sainfo == NULL + || iph2->sainfo->lifetime != iph2->lifetime_secs) { + plog(LLV_WARNING, LOCATION, NULL, + "RESPONDER-LIFETIME: lifetime mismatch\n"); + iph2->lifetime_secs = 0; + } + break; + } + break; + default: + isakmp_log_notify(iph2->ph1, notify, "phase2 exchange"); + isakmp_info_send_n2(iph2, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, + NULL); + break; + } return 0; } diff --git a/src/racoon/isakmp_unity.c b/src/racoon/isakmp_unity.c index 9873f59..a1bf793 100644 --- a/src/racoon/isakmp_unity.c +++ b/src/racoon/isakmp_unity.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_unity.c,v 1.7 2006/10/09 06:17:20 manu Exp $ */ +/* $NetBSD: isakmp_unity.c,v 1.9 2007/10/19 03:37:19 manu Exp $ */ /* Id: isakmp_unity.c,v 1.10 2006/07/31 04:49:23 manubsd Exp */ @@ -305,32 +305,41 @@ int splitnet_list_add(list, network, count) struct unity_network * network; int *count; { - struct unity_netentry * newentry; + struct unity_netentry * nentry; + + /* + * search for network in current list + * to avoid adding duplicates + */ + for (nentry = *list; nentry != NULL; nentry = nentry->next) + if (memcmp(&nentry->network, network, + sizeof(struct unity_network)) == 0) + return 0; /* it's a dupe */ /* * allocate new netentry and copy - * new splitnet network data + * new splitnet network data */ - newentry = (struct unity_netentry *) + nentry = (struct unity_netentry *) racoon_malloc(sizeof(struct unity_netentry)); - if (newentry == NULL) + if (nentry == NULL) return -1; - memcpy(&newentry->network,network, + memcpy(&nentry->network,network, sizeof(struct unity_network)); - newentry->next = NULL; + nentry->next = NULL; /* * locate the last netentry in our * splitnet list and add our entry */ if (*list == NULL) - *list = newentry; + *list = nentry; else { struct unity_netentry * tmpentry = *list; while (tmpentry->next != NULL) tmpentry = tmpentry->next; - tmpentry->next = newentry; + tmpentry->next = nentry; } (*count)++; @@ -354,8 +363,9 @@ void splitnet_list_free(list, count) } } -char * splitnet_list_2str(list) +char * splitnet_list_2str(list, splitnet_ipaddr) struct unity_netentry * list; + enum splinet_ipaddr splitnet_ipaddr; { struct unity_netentry * netentry; char tmp1[40]; @@ -389,8 +399,17 @@ char * splitnet_list_2str(list) inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40); inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40); - - len += sprintf(str+len, "%s/%s ", tmp1, tmp2); + if (splitnet_ipaddr == CIDR) { + uint32_t tmp3; + int cidrmask; + + tmp3 = ntohl(netentry->network.mask4.s_addr); + for (cidrmask = 0; tmp3 != 0; cidrmask++) + tmp3 <<= 1; + len += sprintf(str+len, "%s/%d ", tmp1, cidrmask); + } else { + len += sprintf(str+len, "%s/%s ", tmp1, tmp2); + } netentry = netentry->next; } diff --git a/src/racoon/isakmp_unity.h b/src/racoon/isakmp_unity.h index b52f02c..3667d0d 100644 --- a/src/racoon/isakmp_unity.h +++ b/src/racoon/isakmp_unity.h @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_unity.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: isakmp_unity.h,v 1.5 2007/10/19 03:37:19 manu Exp $ */ /* $KAME$ */ @@ -31,6 +31,8 @@ * SUCH DAMAGE. */ +enum splinet_ipaddr { NETMASK, CIDR }; + /* ISAKMP notifies specific to the Unity vendor Id */ /* Sent during xauth if the user types his password too slowly */ #define ISAKMP_NTYPE_UNITY_HEARTBEAT 40500 @@ -66,7 +68,7 @@ struct unity_netentry { int splitnet_list_add(struct unity_netentry **, struct unity_network *, int *); void splitnet_list_free(struct unity_netentry *, int *); -char * splitnet_list_2str(struct unity_netentry *); +char * splitnet_list_2str(struct unity_netentry *, enum splinet_ipaddr); vchar_t *isakmp_unity_req(struct ph1handle *, struct isakmp_data *); void isakmp_unity_reply(struct ph1handle *, struct isakmp_data *); diff --git a/src/racoon/isakmp_var.h b/src/racoon/isakmp_var.h index f4ef45d..09e4e7f 100644 --- a/src/racoon/isakmp_var.h +++ b/src/racoon/isakmp_var.h @@ -1,11 +1,11 @@ -/* $NetBSD: isakmp_var.h,v 1.6.6.1 2007/02/20 09:08:49 vanhu Exp $ */ +/* $NetBSD: isakmp_var.h,v 1.17 2010/11/12 10:36:37 tteras Exp $ */ /* Id: isakmp_var.h,v 1.12 2005/05/07 14:45:31 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,6 +35,7 @@ #define _ISAKMP_VAR_H #include "vmbuf.h" +#include "policy.h" #define PORT_ISAKMP 500 #define PORT_ISAKMP_NATT 4500 @@ -56,40 +57,39 @@ 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 struct ph1handle *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 const char *isakmp_pindex __P((const isakmp_index *, const u_int32_t)); -extern int isakmp_open __P((void)); -extern void isakmp_close __P((void)); +extern int isakmp_open __P((struct sockaddr *, int)); +extern void isakmp_close __P((int fd)); 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 int isakmp_ph1send __P((struct ph1handle *)); +extern int isakmp_ph2send __P((struct ph2handle *)); +extern void isakmp_ph1dying_stub __P((struct sched *)); +extern void isakmp_ph1dying __P((struct ph1handle *)); +extern void isakmp_ph1expire_stub __P((struct sched *)); extern void isakmp_ph1expire __P((struct ph1handle *)); -extern void isakmp_ph1delete_stub __P((void *)); +extern void isakmp_ph1delete_stub __P((struct sched *)); extern void isakmp_ph1delete __P((struct ph1handle *)); -extern void isakmp_ph2expire_stub __P((void *)); +extern void isakmp_ph2expire_stub __P((struct sched *)); extern void isakmp_ph2expire __P((struct ph2handle *)); -extern void isakmp_ph2delete_stub __P((void *)); +extern void isakmp_ph2delete_stub __P((struct sched *)); extern void isakmp_ph2delete __P((struct ph2handle *)); -extern int isakmp_post_acquire __P((struct ph2handle *)); +extern int isakmp_get_sainfo __P((struct ph2handle *, struct secpolicy *, struct secpolicy *)); +extern int isakmp_post_acquire __P((struct ph2handle *, struct ph1handle *, int)); extern int isakmp_post_getspi __P((struct ph2handle *)); -extern void isakmp_chkph1there_stub __P((void *)); +extern void isakmp_chkph1there_stub __P((struct sched *)); extern void isakmp_chkph1there __P((struct ph2handle *)); extern caddr_t isakmp_set_attr_v __P((caddr_t, int, caddr_t, int)); @@ -106,8 +106,19 @@ 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 struct payload_list *isakmp_plist_append_full __P(( + struct payload_list *plist, vchar_t *payload, + u_int8_t payload_type, u_int8_t free)); + +static inline struct payload_list *isakmp_plist_append(plist, payload, payload_type) + struct payload_list *plist; + vchar_t *payload; + u_int8_t payload_type; +{ + return isakmp_plist_append_full(plist, payload, payload_type, 0); +} + + extern vchar_t *isakmp_plist_set_all __P((struct payload_list **plist, struct ph1handle *iph1)); @@ -120,7 +131,7 @@ 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 void script_hook __P((struct ph1handle *, int)); extern int script_env_append __P((char ***, int *, char *, char *)); extern int script_exec __P((char *, int, char * const *)); @@ -129,4 +140,5 @@ void delete_spd __P((struct ph2handle *, u_int64_t)); #ifdef INET6 u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *)); #endif + #endif /* _ISAKMP_VAR_H */ diff --git a/src/racoon/isakmp_xauth.c b/src/racoon/isakmp_xauth.c index 12e5ef6..853caaa 100644 --- a/src/racoon/isakmp_xauth.c +++ b/src/racoon/isakmp_xauth.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_xauth.c,v 1.11.6.2 2009/04/20 13:35:36 tteras Exp $ */ +/* $NetBSD: isakmp_xauth.c,v 1.22 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: isakmp_xauth.c,v 1.38 2006/08/22 18:17:17 manubsd Exp */ @@ -40,6 +40,7 @@ #include <netinet/in.h> +#include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -95,9 +96,9 @@ #ifdef HAVE_LIBRADIUS #include <radlib.h> - struct rad_handle *radius_auth_state = NULL; struct rad_handle *radius_acct_state = NULL; +struct xauth_rad_config xauth_rad_config; #endif #ifdef HAVE_LIBPAM @@ -129,7 +130,7 @@ xauth_sendreq(iph1) size_t tlen; /* Status checks */ - if (iph1->status != PHASE1ST_ESTABLISHED) { + if (iph1->status < PHASE1ST_ESTABLISHED) { plog(LLV_ERROR, LOCATION, NULL, "Xauth request while phase 1 is not completed\n"); return; @@ -311,7 +312,7 @@ xauth_attr_reply(iph1, attr, id) * 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); + throttle_delay = throttle_host(iph1->remote, res); if (throttle_delay > 0) { char *str; @@ -329,7 +330,7 @@ skip_auth: if (throttle_delay != 0) { struct xauth_reply_arg *xra; - if ((xra = racoon_malloc(sizeof(*xra))) == NULL) { + if ((xra = racoon_calloc(1, sizeof(*xra))) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "malloc failed, bypass throttling\n"); return xauth_reply(iph1, port, id, res); @@ -344,7 +345,8 @@ skip_auth: xra->port = port; xra->id = id; xra->res = res; - sched_new(throttle_delay, xauth_reply_stub, xra); + sched_schedule(&xra->sc, throttle_delay, + xauth_reply_stub); } else { return xauth_reply(iph1, port, id, res); } @@ -354,10 +356,10 @@ skip_auth: } void -xauth_reply_stub(args) - void *args; +xauth_reply_stub(sc) + struct sched *sc; { - struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args; + struct xauth_reply_arg *xra = container_of(sc, struct xauth_reply_arg, sc); struct ph1handle *iph1; if ((iph1 = getph1byindex(&xra->index)) != NULL) @@ -367,7 +369,6 @@ xauth_reply_stub(args) "Delayed Xauth reply: phase 1 no longer exists.\n"); racoon_free(xra); - return; } int @@ -390,7 +391,7 @@ xauth_reply(iph1, port, id, res) xst->status = XAUTHST_NOTYET; /* Delete Phase 1 SA */ - if (iph1->status == PHASE1ST_ESTABLISHED) + if (iph1->status >= PHASE1ST_ESTABLISHED) isakmp_info_send_d1(iph1); remph1(iph1); delph1(iph1); @@ -447,6 +448,31 @@ xauth_sendstatus(iph1, status, id) #ifdef HAVE_LIBRADIUS int +xauth_radius_init_conf(int free) +{ + /* free radius config resources */ + if (free) { + int i; + for (i = 0; i < xauth_rad_config.auth_server_count; i++) { + vfree(xauth_rad_config.auth_server_list[i].host); + vfree(xauth_rad_config.auth_server_list[i].secret); + } + for (i = 0; i < xauth_rad_config.acct_server_count; i++) { + vfree(xauth_rad_config.acct_server_list[i].host); + vfree(xauth_rad_config.acct_server_list[i].secret); + } + if (radius_auth_state != NULL) + rad_close(radius_auth_state); + if (radius_acct_state != NULL) + rad_close(radius_acct_state); + } + + /* initialize radius config */ + memset(&xauth_rad_config, 0, sizeof(xauth_rad_config)); + return 0; +} + +int xauth_radius_init(void) { /* For first time use, initialize Radius */ @@ -458,13 +484,35 @@ xauth_radius_init(void) 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; + int auth_count = xauth_rad_config.auth_server_count; + int auth_added = 0; + if (auth_count) { + int i; + for (i = 0; i < auth_count; i++) { + if(!rad_add_server( + radius_auth_state, + xauth_rad_config.auth_server_list[i].host->v, + xauth_rad_config.auth_server_list[i].port, + xauth_rad_config.auth_server_list[i].secret->v, + xauth_rad_config.timeout, + xauth_rad_config.retries )) + auth_added++; + else + plog(LLV_WARNING, LOCATION, NULL, + "could not add radius auth server %s\n", + xauth_rad_config.auth_server_list[i].host->v); + } + } + + if (!auth_added) { + if (rad_config(radius_auth_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open libradius config file: %s\n", + rad_strerror(radius_auth_state)); + rad_close(radius_auth_state); + radius_auth_state = NULL; + return -1; + } } } @@ -476,13 +524,35 @@ xauth_radius_init(void) 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; + int acct_count = xauth_rad_config.acct_server_count; + int acct_added = 0; + if (acct_count) { + int i; + for (i = 0; i < acct_count; i++) { + if(!rad_add_server( + radius_acct_state, + xauth_rad_config.acct_server_list[i].host->v, + xauth_rad_config.acct_server_list[i].port, + xauth_rad_config.acct_server_list[i].secret->v, + xauth_rad_config.timeout, + xauth_rad_config.retries )) + acct_added++; + else + plog(LLV_WARNING, LOCATION, NULL, + "could not add radius account server %s\n", + xauth_rad_config.acct_server_list[i].host->v); + } + } + + if (!acct_added) { + if (rad_config(radius_acct_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open libradius config file: %s\n", + rad_strerror(radius_acct_state)); + rad_close(radius_acct_state); + radius_acct_state = NULL; + return -1; + } } } @@ -670,7 +740,7 @@ xauth_login_pam(port, raddr, usr, pwd) "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", @@ -678,6 +748,13 @@ xauth_login_pam(port, raddr, usr, pwd) goto out; } + if ((error = pam_set_item(pam, PAM_RUSER, usr)) != 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); @@ -720,7 +797,7 @@ out: #ifdef HAVE_LIBLDAP int -xauth_ldap_init(void) +xauth_ldap_init_conf(void) { int tmplen; int error = -1; @@ -1255,7 +1332,7 @@ xauth_check(iph1) * status. It does it if the chose authmethod is using Xauth. * On the client side (roadwarrior), we don't check anything. */ - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: @@ -1546,9 +1623,9 @@ isakmp_xauth_set(iph1, attr) * when running as a client (initiator). */ xst = &iph1->mode_cfg->xauth; - switch(AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: /* Not implemented ... */ case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: @@ -1568,13 +1645,11 @@ isakmp_xauth_set(iph1, attr) plog(LLV_ERROR, LOCATION, NULL, "Xauth authentication failed\n"); - EVT_PUSH(iph1->local, iph1->remote, - EVTT_XAUTH_FAILED, NULL); + evt_phase1(iph1, EVT_PHASE1_XAUTH_FAILED, NULL); iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1; } else { - EVT_PUSH(iph1->local, iph1->remote, - EVTT_XAUTH_SUCCESS, NULL); + evt_phase1(iph1, EVT_PHASE1_XAUTH_SUCCESS, NULL); } @@ -1689,3 +1764,42 @@ xauth_rmconf_delete(xauth_rmconf) return; } + +struct xauth_rmconf * +xauth_rmconf_dup(xauth_rmconf) + struct xauth_rmconf *xauth_rmconf; +{ + struct xauth_rmconf *new; + + if (xauth_rmconf != NULL) { + new = racoon_malloc(sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed\n"); + return NULL; + } + + memcpy(new, xauth_rmconf, sizeof(*new)); + + if (xauth_rmconf->login != NULL) { + new->login = vdup(xauth_rmconf->login); + if (new->login == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed (login)\n"); + return NULL; + } + } + if (xauth_rmconf->pass != NULL) { + new->pass = vdup(xauth_rmconf->pass); + if (new->pass == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed (password)\n"); + return NULL; + } + } + + return new; + } + + return NULL; +} diff --git a/src/racoon/isakmp_xauth.h b/src/racoon/isakmp_xauth.h index ebb5214..f9e778f 100644 --- a/src/racoon/isakmp_xauth.h +++ b/src/racoon/isakmp_xauth.h @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_xauth.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: isakmp_xauth.h,v 1.7 2011/03/14 15:50:36 vanhu Exp $ */ /* $KAME$ */ @@ -34,6 +34,8 @@ #ifndef _ISAKMP_XAUTH_H #define _ISAKMP_XAUTH_H +#include "schedule.h" + /* ISAKMP mode config attribute types specific to the Xauth vendor ID */ #define XAUTH_TYPE 16520 #define XAUTH_USER_NAME 16521 @@ -90,6 +92,7 @@ struct xauth_rmconf { #define XAUTHST_OK 2 struct xauth_reply_arg { + struct sched sc; isakmp_index index; int port; int id; @@ -107,18 +110,41 @@ int group_check(struct ph1handle *, char **, int); 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_stub(struct sched *); int xauth_reply(struct ph1handle *, int, int, int); int xauth_rmconf_used(struct xauth_rmconf **); void xauth_rmconf_delete(struct xauth_rmconf **); +struct xauth_rmconf * xauth_rmconf_dup(struct xauth_rmconf *); + +#ifdef HAVE_LIBPAM +int xauth_login_pam(int, struct sockaddr *, char *, char *); +#endif #ifdef HAVE_LIBRADIUS -int xauth_login_radius(struct ph1handle *, char *, char *); + +#define RADIUS_MAX_SERVERS 5 + +struct rad_serv { + vchar_t *host; + int port; + vchar_t *secret; +}; + +struct xauth_rad_config { + struct rad_serv auth_server_list[RADIUS_MAX_SERVERS]; + int auth_server_count; + struct rad_serv acct_server_list[RADIUS_MAX_SERVERS]; + int acct_server_count; + int timeout; + int retries; +}; + +extern struct xauth_rad_config xauth_rad_config; + +int xauth_radius_init_conf(int free); int xauth_radius_init(void); -#endif +int xauth_login_radius(struct ph1handle *, char *, char *); -#ifdef HAVE_LIBPAM -int xauth_login_pam(int, struct sockaddr *, char *, char *); #endif #ifdef HAVE_LIBLDAP @@ -148,8 +174,9 @@ struct xauth_ldap_config { extern struct xauth_ldap_config xauth_ldap_config; -int xauth_ldap_init(void); +int xauth_ldap_init_conf(void); int xauth_login_ldap(struct ph1handle *, char *, char *); + #endif #endif /* _ISAKMP_XAUTH_H */ diff --git a/src/racoon/kmpstat.c b/src/racoon/kmpstat.c index c59e43a..50c478d 100644 --- a/src/racoon/kmpstat.c +++ b/src/racoon/kmpstat.c @@ -1,4 +1,4 @@ -/* $NetBSD: kmpstat.c,v 1.4.6.2 2007/11/06 16:41:33 vanhu Exp $ */ +/* $NetBSD: kmpstat.c,v 1.7 2010/11/12 09:08:26 tteras Exp $ */ /* $KAME: kmpstat.c,v 1.33 2004/08/16 08:20:28 itojun Exp $ */ @@ -138,7 +138,7 @@ com_recv(combufp) { struct admin_com h, *com; caddr_t buf; - int len; + int len, rlen; int l = 0; caddr_t p; @@ -153,19 +153,25 @@ com_recv(combufp) if (len < sizeof(h)) goto bad1; - if (h.ac_errno) { + if (h.ac_errno && !(h.ac_cmd & ADMIN_FLAG_LONG_REPLY)) { errno = h.ac_errno; goto bad1; } + /* real length */ + if (h.ac_cmd & ADMIN_FLAG_LONG_REPLY) + rlen = ((u_int32_t)h.ac_len) + (((u_int32_t)h.ac_len_high) << 16); + else + rlen = h.ac_len; + /* allocate buffer */ - if ((*combufp = vmalloc(h.ac_len)) == NULL) + if ((*combufp = vmalloc(rlen)) == NULL) goto bad1; /* read real message */ p = (*combufp)->v; - while (l < len) { - if ((len = recv(so, p, h.ac_len, 0)) < 0) { + while (l < rlen) { + if ((len = recv(so, p, rlen - l, 0)) < 0) { perror("recv"); goto bad2; } diff --git a/src/racoon/localconf.c b/src/racoon/localconf.c index ede1d9b..a512953 100644 --- a/src/racoon/localconf.c +++ b/src/racoon/localconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: localconf.c,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: localconf.c,v 1.7 2008/12/23 14:04:42 tteras Exp $ */ /* $KAME: localconf.c,v 1.33 2001/08/09 07:32:19 sakane Exp $ */ @@ -85,18 +85,14 @@ flushlcconf() int i; setdefault(); - clear_myaddr(&lcconf->myaddrs); + myaddr_flush(); + 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 @@ -105,7 +101,6 @@ 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; @@ -124,6 +119,7 @@ setdefault() 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->pfkey_buffer_size = LC_DEFAULT_PFKEY_BUFFER_SIZE; } /* @@ -340,21 +336,12 @@ 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/src/racoon/localconf.h b/src/racoon/localconf.h index f7cf33a..04ac8e4 100644 --- a/src/racoon/localconf.h +++ b/src/racoon/localconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: localconf.h,v 1.4 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: localconf.h,v 1.7 2008/12/23 14:04:42 tteras Exp $ */ /* Id: localconf.h,v 1.13 2005/11/06 18:13:18 monas Exp */ @@ -57,11 +57,10 @@ #define LC_DEFAULT_RETRY_CHECKPH1 30 #define LC_DEFAULT_WAIT_PH2COMPLETE 30 #define LC_DEFAULT_NATT_KA_INTERVAL 20 +#define LC_DEFAULT_PFKEY_BUFFER_SIZE 0 #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 @@ -74,18 +73,13 @@ struct localconf { 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_pfkey; int rtsock; /* routing socket */ - int autograbaddr; - struct myaddrs *myaddrs; - char *pathinfo[LC_PATHTYPE_MAX]; - vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */ int pad_random; int pad_randomlen; @@ -118,6 +112,7 @@ struct localconf { */ int gss_id_enc; /* GSS ID encoding to use */ + int pfkey_buffer_size; /* Set socket buffer size for pfkey */ }; extern struct localconf *lcconf; diff --git a/src/racoon/main.c b/src/racoon/main.c index 094026e..ab71b3e 100644 --- a/src/racoon/main.c +++ b/src/racoon/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.6.6.2 2008/11/27 15:25:26 vanhu Exp $ */ +/* $NetBSD: main.c,v 1.12 2009/01/26 18:13:06 tteras Exp $ */ /* Id: main.c,v 1.25 2006/06/20 20:31:34 manubsd Exp */ @@ -66,12 +66,6 @@ #include "cfparse_proto.h" #include "isakmp_var.h" -#ifdef ENABLE_HYBRID -#include <resolv.h> -#include "isakmp.h" -#include "isakmp_xauth.h" -#include "isakmp_cfg.h" -#endif #include "remoteconf.h" #include "localconf.h" #include "session.h" @@ -84,10 +78,10 @@ #include "package_version.h" +int dump_config = 0; /* dump parsed config file. */ 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. */ #ifdef TOP_PACKAGE static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")"; @@ -95,197 +89,77 @@ static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")"; 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 **)); -#if 0 -static void cleanup_pidfile __P((void)); -#endif - -void -usage() +static void +print_version() { - printf("usage: racoon [-BdFv%s] %s[-f (file)] [-l (file)] [-p (port)]\n", + printf("%s\n" + "\n" + "Compiled with:\n" + "- %s (http://www.openssl.org/)\n" #ifdef INET6 - "46", -#else - "", + "- IPv6 support\n" #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"); -#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(); +#ifdef ENABLE_DPD + "- Dead Peer Detection\n" #endif - -#ifdef HAVE_SECCTX - init_avc(); +#ifdef ENABLE_FRAG + "- IKE fragmentation\n" #endif - eay_init(); - initlcconf(); - initrmconf(); - oakley_dhinit(); - compute_vendorids(); - - parse(ac, av); - - ploginit(); - - plog(LLV_INFO, LOCATION, NULL, "%s\n", version); - plog(LLV_INFO, LOCATION, NULL, "@(#)" - "This product linked %s (http://www.openssl.org/)" - "\n", eay_version()); - plog(LLV_INFO, LOCATION, NULL, "Reading configuration from \"%s\"\n", - lcconf->racoon_conf); - - if (pfkey_init() < 0) { - errx(1, "something error happened " - "while pfkey initializing."); - /* NOTREACHED*/ - } - #ifdef ENABLE_HYBRID - if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD)) - errx(1, "could not initialize ISAKMP mode config structures"); + "- Hybrid authentication\n" #endif - -#ifdef HAVE_LIBLDAP - if (xauth_ldap_init() != 0) - errx(1, "could not initialize libldap"); +#ifdef ENABLE_GSSAPI + "- GSS-API authentication\n" #endif - - /* - * 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(); - -#ifdef ENABLE_HYBRID - if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0) - if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0) - return error; +#ifdef ENABLE_NATT + "- NAT Traversal\n" #endif - - if (dump_config) - dumprmconf (); - -#ifdef HAVE_LIBRADIUS - if (xauth_radius_init() != 0) { - errx(1, "could not initialize libradius"); - /* NOTREACHED*/ - } +#ifdef ENABLE_STATS + "- Timing statistics\n" #endif - - /* - * 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 (daemon(0, 0) < 0) { - errx(1, "failed to be daemon. (%s)", - strerror(errno)); - } -#ifndef __linux__ - /* - * In case somebody has started inetd manually, we need to - * clear the logname, so that old servers run as root do not - * get the user's logname.. - */ - if (setlogin("") < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "cannot clear logname: %s\n", strerror(errno)); - /* no big deal if it fails.. */ - } +#ifdef ENABLE_ADMINPORT + "- Admin port\n" #endif - if (!f_local) { -#if 0 - if (atexit(cleanup_pidfile) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "cannot register pidfile cleanup"); - } +#ifdef HAVE_CLOCK_MONOTONIC + "- Monotonic clock\n" #endif - } - } - - session(); - +#ifdef HAVE_SECCTX + "- Security context\n" +#endif + "\n", + version, + eay_version()); exit(0); } -#if 0 static void -cleanup_pidfile() +usage() { - pid_t p = getpid(); - - /* if it's not child process, clean everything */ - if (racoon_pid == p) { - const char *pid_file = _PATH_VARRUN "racoon.pid"; - - (void) unlink(pid_file); - } -} + printf("usage: racoon [-BdFv" +#ifdef INET6 + "46" #endif + "] [-f (file)] [-l (file)] [-p (port)] [-P (natt port)]\n" + " -B: install SA to the kernel from the file " + "specified by the configuration file.\n" + " -d: debug level, more -d will generate more debug message.\n" + " -C: dump parsed config file.\n" + " -L: include location in debug messages\n" + " -F: run in foreground, do not become daemon.\n" + " -v: be more verbose\n" + " -V: print version and exit\n" +#ifdef INET6 + " -4: IPv4 mode.\n" + " -6: IPv6 mode.\n" +#endif + " -f: pathname for configuration file.\n" + " -l: pathname for log file.\n" + " -p: port number for isakmp (default: %d).\n" + " -P: port number for NAT-T (default: %d).\n" + "\n", + PORT_ISAKMP, PORT_ISAKMP_NATT); + exit(1); +} static void parse(ac, av) @@ -305,7 +179,7 @@ parse(ac, av) else pname = *av; - while ((c = getopt(ac, av, "dLFp:P:a:f:l:vZBC" + while ((c = getopt(ac, av, "dLFp:P:f:l:vVZBC" #ifdef YYDEBUG "y" #endif @@ -330,15 +204,6 @@ parse(ac, av) 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; @@ -348,6 +213,9 @@ parse(ac, av) case 'v': vflag++; break; + case 'V': + print_version(); + break; case 'Z': /* * only local test. @@ -393,6 +261,89 @@ parse(ac, av) usage(); /* NOTREACHED */ } +} + +int +main(ac, av) + int ac; + char **av; +{ + int error; + + initlcconf(); + parse(ac, av); + + 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 + +#ifdef HAVE_SECCTX + init_avc(); +#endif + eay_init(); + initrmconf(); + oakley_dhinit(); + compute_vendorids(); + + ploginit(); + + plog(LLV_INFO, LOCATION, NULL, "%s\n", version); + plog(LLV_INFO, LOCATION, NULL, "@(#)" + "This product linked %s (http://www.openssl.org/)" + "\n", eay_version()); + plog(LLV_INFO, LOCATION, NULL, "Reading configuration from \"%s\"\n", + lcconf->racoon_conf); + + /* + * 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 (daemon(0, 0) < 0) { + errx(1, "failed to be daemon. (%s)", + strerror(errno)); + } +#ifndef __linux__ + /* + * In case somebody has started inetd manually, we need to + * clear the logname, so that old servers run as root do not + * get the user's logname.. + */ + if (setlogin("") < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot clear logname: %s\n", strerror(errno)); + /* no big deal if it fails.. */ + } +#endif + } - return; + session(); + + return 0; } + diff --git a/src/racoon/misc.c b/src/racoon/misc.c index 4daa0ed..91b8e77 100644 --- a/src/racoon/misc.c +++ b/src/racoon/misc.c @@ -1,4 +1,4 @@ -/* $NetBSD: misc.c,v 1.4.6.1 2008/07/15 00:55:48 mgrooms Exp $ */ +/* $NetBSD: misc.c,v 1.6 2008/07/15 00:47:09 mgrooms Exp $ */ /* $KAME: misc.c,v 1.23 2001/08/16 14:37:29 itojun Exp $ */ @@ -44,6 +44,7 @@ #include <errno.h> #include <syslog.h> #include <ctype.h> +#include <fcntl.h> #include "var.h" #include "misc.h" @@ -154,6 +155,16 @@ getfsize(path) } /* + * set the close-on-exec flag for file descriptor fd. + */ +void +close_on_exec(fd) + int fd; +{ + fcntl(fd, F_SETFD, FD_CLOEXEC); +} + +/* * calculate the difference between two times. * t1: start * t2: end diff --git a/src/racoon/misc.h b/src/racoon/misc.h index 66e42b1..3e758d9 100644 --- a/src/racoon/misc.h +++ b/src/racoon/misc.h @@ -1,4 +1,4 @@ -/* $NetBSD: misc.h,v 1.4.6.1 2008/07/15 00:55:48 mgrooms Exp $ */ +/* $NetBSD: misc.h,v 1.6 2008/07/15 00:47:09 mgrooms Exp $ */ /* Id: misc.h,v 1.9 2006/04/06 14:00:06 manubsd Exp */ @@ -50,6 +50,7 @@ extern int getfsize __P((char *)); struct timeval; extern double timedelta __P((struct timeval *, struct timeval *)); char *strdup __P((const char *)); +extern void close_on_exec __P((int fd)); #if defined(__APPLE__) && defined(__MACH__) #define RACOON_TAILQ_FOREACH_REVERSE(var, head, headname ,field) \ diff --git a/src/racoon/nattraversal.c b/src/racoon/nattraversal.c index 9fd4bcd..b04cc1b 100644 --- a/src/racoon/nattraversal.c +++ b/src/racoon/nattraversal.c @@ -1,4 +1,4 @@ -/* $NetBSD: nattraversal.c,v 1.6.6.2 2009/05/18 17:01:07 tteras Exp $ */ +/* $NetBSD: nattraversal.c,v 1.14 2011/03/14 17:18:13 tteras Exp $ */ /* * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. @@ -77,6 +77,7 @@ struct natt_ka_addrs { }; static TAILQ_HEAD(_natt_ka_addrs, natt_ka_addrs) ka_tree; +static struct sched sc_natt = SCHED_INITIALIZER(); /* * check if the given vid is NAT-T. @@ -126,10 +127,14 @@ natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr) char *ptr; void *addr_ptr, *addr_port; size_t buf_size, addr_size; + int natt_force = 0; + + if (iph1->rmconf != NULL && iph1->rmconf->nat_traversal == NATT_FORCE) + natt_force = 1; 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)":""); + natt_force?"(NAT-T forced)":""); if (addr->sa_family == AF_INET) { addr_size = sizeof (struct in_addr); /* IPv4 address */ @@ -163,7 +168,7 @@ natt_hash_addr (struct ph1handle *iph1, struct sockaddr *addr) ptr += sizeof (cookie_t); /* Copy-in Address (or zeroes if NATT_FORCE) */ - if (iph1->rmconf->nat_traversal == NATT_FORCE) + if (natt_force) memset (ptr, 0, addr_size); else memcpy (ptr, addr_ptr, addr_size); @@ -186,7 +191,8 @@ natt_compare_addr_hash (struct ph1handle *iph1, vchar_t *natd_received, u_int32_t flag; int verified = 0; - if (iph1->rmconf->nat_traversal == NATT_FORCE) + if (iph1->rmconf != NULL && + iph1->rmconf->nat_traversal == NATT_FORCE) return verified; if (natd_seq == 0) { @@ -302,9 +308,28 @@ natt_float_ports (struct ph1handle *iph1) natt_keepalive_add_ph1 (iph1); } +static int +natt_is_enabled (struct remoteconf *rmconf, void *args) +{ + if (rmconf->nat_traversal) + return 1; + return 0; +} + void natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric) { + if (iph1->rmconf == NULL) { + /* Check if any candidate remote conf allows nat-t */ + struct rmconfselector rmconf; + rmconf_selector_from_ph1(&rmconf, iph1); + if (enumrmconf(&rmconf, natt_is_enabled, NULL) == 0) + return; + } else { + if (!iph1->rmconf->nat_traversal) + return; + } + if (! iph1->natt_options) iph1->natt_options = racoon_calloc (1, sizeof (*iph1->natt_options)); @@ -330,7 +355,7 @@ natt_keepalive_delete (struct natt_ka_addrs *ka) /* NAT keepalive functions */ static void -natt_keepalive_send (void *param) +natt_keepalive_send (struct sched *param) { struct natt_ka_addrs *ka, *next = NULL; char keepalive_packet[] = { 0xff }; @@ -340,7 +365,7 @@ natt_keepalive_send (void *param) for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) { next = TAILQ_NEXT(ka, chain); - s = getsockmyaddr(ka->src); + s = myaddr_getfd(ka->src); if (s == -1) { natt_keepalive_delete(ka); continue; @@ -354,7 +379,7 @@ natt_keepalive_send (void *param) strerror (errno)); } - sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL); + sched_schedule (&sc_natt, lcconf->natt_ka_interval, natt_keepalive_send); } void @@ -364,7 +389,7 @@ natt_keepalive_init (void) /* 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); + sched_schedule (&sc_natt, lcconf->natt_ka_interval, natt_keepalive_send); } int @@ -373,8 +398,8 @@ 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) { + if (cmpsaddr(ka->src, src) == CMPSADDR_MATCH && + cmpsaddr(ka->dst, dst) == CMPSADDR_MATCH) { ka->in_use++; plog (LLV_INFO, LOCATION, NULL, "KA found: %s (in_use=%u)\n", saddr2str_fromto("%s->%s", src, dst), ka->in_use); @@ -437,8 +462,8 @@ natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst) 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 && + if (cmpsaddr(ka->src, src) == CMPSADDR_MATCH && + cmpsaddr(ka->dst, dst) == CMPSADDR_MATCH && -- ka->in_use <= 0) { plog (LLV_DEBUG, LOCATION, NULL, "KA removing this one...\n"); @@ -451,16 +476,16 @@ natt_keepalive_remove (struct sockaddr *src, struct sockaddr *dst) } } -static struct remoteconf * +static int natt_enabled_in_rmconf_stub (struct remoteconf *rmconf, void *data) { - return (rmconf->nat_traversal ? rmconf : NULL); + return rmconf->nat_traversal ? 1 : 0; } int natt_enabled_in_rmconf () { - return foreachrmconf (natt_enabled_in_rmconf_stub, NULL) != NULL; + return enumrmconf(NULL, natt_enabled_in_rmconf_stub, NULL) != 0; } diff --git a/src/racoon/nattraversal.h b/src/racoon/nattraversal.h index cec5815..3b0b03b 100644 --- a/src/racoon/nattraversal.h +++ b/src/racoon/nattraversal.h @@ -1,4 +1,4 @@ -/* $NetBSD: nattraversal.h,v 1.6 2006/09/09 16:22:09 manu Exp $ */ +/* $NetBSD: nattraversal.h,v 1.7 2010/09/22 07:34:51 vanhu Exp $ */ /* * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. @@ -42,12 +42,12 @@ #define NAT_KA_QUEUED (1L<<4) #define NAT_ADD_NON_ESP_MARKER (1L<<5) -#define NATT_AVAILABLE(ph1) ((iph1)->natt_flags & NAT_ANNOUNCED) +#define NATT_AVAILABLE(_ph1) ((_ph1)->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) +#define NON_ESP_MARKER_USE(_ph1) ((_ph1)->natt_flags & NAT_ADD_NON_ESP_MARKER) /* These are the values from parsing "remote {}" block of the config file. */ diff --git a/src/racoon/oakley.c b/src/racoon/oakley.c index 183ac2f..4a106df 100644 --- a/src/racoon/oakley.c +++ b/src/racoon/oakley.c @@ -1,4 +1,4 @@ -/* $NetBSD: oakley.c,v 1.9.6.4 2009/08/13 09:18:45 vanhu Exp $ */ +/* $NetBSD: oakley.c,v 1.22 2011/03/17 14:42:58 vanhu Exp $ */ /* Id: oakley.c,v 1.32 2006/05/26 12:19:46 manubsd Exp */ @@ -123,13 +123,63 @@ 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)); static int oakley_check_certid __P((struct ph1handle *iph1)); 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)); +static int get_plainrsa_fromlocal __P((struct ph1handle *, int)); + +int oakley_get_certtype(cert) + vchar_t *cert; +{ + if (cert == NULL) + return ISAKMP_CERT_NONE; + + return cert->v[0]; +} + +static vchar_t * +dump_isakmp_payload(gen) + struct isakmp_gen *gen; +{ + vchar_t p; + + if (ntohs(gen->len) <= sizeof(*gen)) { + plog(LLV_ERROR, LOCATION, NULL, + "Len is too small !!.\n"); + return NULL; + } + + p.v = (caddr_t) (gen + 1); + p.l = ntohs(gen->len) - sizeof(*gen); + + return vdup(&p); +} + +static vchar_t * +dump_x509(cert) + X509 *cert; +{ + vchar_t *pl; + u_char *bp; + int len; + + len = i2d_X509(cert, NULL); + + pl = vmalloc(len + 1); + if (pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to copy CERT from packet.\n"); + return NULL; + } + + pl->v[0] = ISAKMP_CERT_X509SIGN; + bp = (u_char *) &pl->v[1]; + i2d_X509(cert, &bp); + + return pl; +} + + int oakley_get_defaultlifetime() @@ -418,7 +468,7 @@ oakley_hash(buf, iph1) res = alg_oakley_hashdef_one(type, buf); if (res == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "invalid hash algoriym %d.\n", type); + "invalid hash algorithm %d.\n", type); return NULL; } @@ -858,7 +908,7 @@ oakley_ph1hash_common(iph1, sw) + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + 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; @@ -919,7 +969,7 @@ oakley_ph1hash_common(iph1, sw) p += bp->l; #ifdef HAVE_GSSAPI - if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + 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); @@ -980,7 +1030,7 @@ oakley_ph1hash_base_i(iph1, sw) return NULL; } - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: case OAKLEY_ATTR_AUTH_METHOD_RSAENC: case OAKLEY_ATTR_AUTH_METHOD_RSAREV: @@ -989,7 +1039,7 @@ oakley_ph1hash_base_i(iph1, sw) case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: #endif if (iph1->skeyid == NULL) { @@ -1121,7 +1171,7 @@ oakley_ph1hash_base_r(iph1, sw) return NULL; } - switch(AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID @@ -1133,7 +1183,7 @@ oakley_ph1hash_base_r(iph1, sw) case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: #endif break; default: @@ -1249,10 +1299,10 @@ oakley_validate_auth(iph1) gettimeofday(&start, NULL); #endif - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: #endif /* validate HASH */ @@ -1265,7 +1315,7 @@ oakley_validate_auth(iph1) return ISAKMP_NTYPE_PAYLOAD_MALFORMED; } #ifdef ENABLE_HYBRID - if (AUTHMETHOD(iph1) == FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I && + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I && ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0)) { plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, " @@ -1323,7 +1373,7 @@ oakley_validate_auth(iph1) #endif { int error = 0; - int certtype = 0; + int certtype; /* validation */ if (iph1->id_p == NULL) { @@ -1341,132 +1391,104 @@ oakley_validate_auth(iph1) plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l); /* get peer's cert */ - switch (iph1->rmconf->getcert_method) { - case ISAKMP_GETCERT_PAYLOAD: + certtype = oakley_get_certtype(iph1->rmconf->peerscert); + switch (certtype) { + case ISAKMP_CERT_NONE: + /* expect to receive one from peer */ if (iph1->cert_p == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "no peer's CERT payload found.\n"); + "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); -#ifdef ANDROID_PATCHED - if (!error) - break; - default: - return ISAKMP_INTERNAL_ERROR; -#else - break; + /* verify the cert if needed */ + if (!iph1->rmconf->verify_cert) + break; - case ISAKMP_CERT_PLAINRSA: - error = get_plainrsa_fromlocal(iph1, 0); - break; - } - if (error) + switch (oakley_get_certtype(iph1->cert_p)) { + case ISAKMP_CERT_X509SIGN: { + 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, + lcconf->pathinfo[LC_PATHTYPE_CERT], + ca, 0); + break; + } + default: + plog(LLV_ERROR, LOCATION, NULL, + "peers_cert certtype %d was not expected\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; + } break; - case ISAKMP_GETCERT_DNS: - if (iph1->rmconf->peerscertfile != NULL) { + case ISAKMP_CERT_X509SIGN: + if (iph1->rmconf->peerscert == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "why peer's CERT file is defined " - "though getcert method is dns ?\n"); + "no peer's CERT file found.\n"); return ISAKMP_INTERNAL_ERROR; } - - /* don't use cached cert */ + /* don't use received cert */ + if (iph1->cert_p != NULL) { + vfree(iph1->cert_p); + iph1->cert_p = NULL; + } + /* copy from remoteconf instead */ + iph1->cert_p = vdup(iph1->rmconf->peerscert); + break; +#ifndef ANDROID_PATCHED + case ISAKMP_CERT_PLAINRSA: + if (get_plainrsa_fromlocal(iph1, 0)) + return ISAKMP_INTERNAL_ERROR; + break; + case ISAKMP_CERT_DNS: + /* don't use received cert */ if (iph1->cert_p != NULL) { - oakley_delcert(iph1->cert_p); + vfree(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"); + "no CERT RR found.\n"); return ISAKMP_INTERNAL_ERROR; -#endif } break; +#endif default: plog(LLV_ERROR, LOCATION, NULL, - "invalid getcert_mothod: %d\n", - iph1->rmconf->getcert_method); + "invalid certificate type: %d\n", + oakley_get_certtype(iph1->rmconf->peerscert)); return ISAKMP_INTERNAL_ERROR; } /* compare ID payload and certificate name */ - if (iph1->rmconf->verify_cert && - (error = oakley_check_certid(iph1)) != 0) + if ((error = oakley_check_certid(iph1)) != 0) return error; - /* verify certificate */ - if (iph1->rmconf->verify_cert - && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) { - certtype = iph1->rmconf->certtype; -#ifdef ENABLE_HYBRID - switch (AUTHMETHOD(iph1)) { - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: - certtype = iph1->cert_p->type; - break; - default: - break; - } -#endif - switch (certtype) { - case ISAKMP_CERT_X509SIGN: { - 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; - } - } - - /* Generate a warning if verify_cert == 0 - */ - if (iph1->rmconf->verify_cert){ - plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n"); - }else{ + /* Generate a warning if verify_cert */ + if (iph1->rmconf->verify_cert) { + plog(LLV_DEBUG, LOCATION, NULL, + "CERT validated\n"); + } else { plog(LLV_WARNING, LOCATION, NULL, - "CERT validation disabled by configuration\n"); + "CERT validation disabled by configuration\n"); } /* compute hash */ @@ -1489,38 +1511,30 @@ oakley_validate_auth(iph1) if (my_hash == NULL) return ISAKMP_INTERNAL_ERROR; - - certtype = iph1->rmconf->certtype; -#ifdef ENABLE_HYBRID - switch (AUTHMETHOD(iph1)) { - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: - certtype = iph1->cert_p->type; - break; - default: - break; - } -#endif /* check signature */ + certtype = oakley_get_certtype(iph1->cert_p); + if (certtype == ISAKMP_CERT_NONE) + certtype = oakley_get_certtype(iph1->rmconf->peerscert); switch (certtype) { case ISAKMP_CERT_X509SIGN: case ISAKMP_CERT_DNS: error = eay_check_x509sign(my_hash, - iph1->sig_p, - &iph1->cert_p->cert); + iph1->sig_p, + iph1->cert_p); break; #ifndef ANDROID_PATCHED 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; - + genlist_free(iph1->rsa_candidates, NULL); + iph1->rsa_candidates = NULL; break; #endif default: plog(LLV_ERROR, LOCATION, NULL, - "no supported certtype %d\n", - certtype); + "cannot check signature for certtype %d\n", + certtype); vfree(my_hash); return ISAKMP_INTERNAL_ERROR; } @@ -1634,115 +1648,26 @@ 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); - -#ifndef ANDROID_PATCHED - case ISAKMP_CERT_PLAINRSA: - if (iph1->rsa) - return 0; - return get_plainrsa_fromlocal(iph1, 1); -#endif - - 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; - } - if (!certfile) { - plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n"); - return 0; - } - - switch (iph1->rmconf->certtype) { + switch (oakley_get_certtype(iph1->rmconf->mycert)) { case ISAKMP_CERT_X509SIGN: - 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); - }; + if (iph1->cert) + return 0; + iph1->cert = vdup(iph1->rmconf->mycert); break; - +#ifndef ANDROID_PATCHED + case ISAKMP_CERT_PLAINRSA: + if (iph1->rsa) + return 0; + return get_plainrsa_fromlocal(iph1, 1); +#endif 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; + "Unknown certtype #%d\n", + oakley_get_certtype(iph1->rmconf->mycert)); + return -1; } - 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; + return 0; } #ifndef ANDROID_PATCHED @@ -1808,7 +1733,7 @@ oakley_getsign(iph1) vchar_t *privkey = NULL; int error = -1; - switch (iph1->rmconf->certtype) { + switch (oakley_get_certtype(iph1->rmconf->mycert)) { case ISAKMP_CERT_X509SIGN: case ISAKMP_CERT_DNS: if (iph1->rmconf->myprivfile == NULL) { @@ -1828,7 +1753,6 @@ oakley_getsign(iph1) } plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n"); plogdump(LLV_DEBUG2, privkey->v, privkey->l); - iph1->sig = eay_get_x509sign(iph1->hash, privkey); break; #ifndef ANDROID_PATCHED @@ -1839,7 +1763,7 @@ oakley_getsign(iph1) default: plog(LLV_ERROR, LOCATION, NULL, "Unknown certtype #%d\n", - iph1->rmconf->certtype); + oakley_get_certtype(iph1->rmconf->mycert)); goto end; } @@ -1873,8 +1797,11 @@ oakley_check_certid(iph1) int idlen, type; int error; + if (iph1->rmconf == NULL || iph1->rmconf->verify_cert == FALSE) + return 0; + if (iph1->id_p == NULL || iph1->cert_p == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); + plog(LLV_ERROR, LOCATION, iph1->remote, "no ID nor CERT found.\n"); return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } @@ -1883,27 +1810,30 @@ oakley_check_certid(iph1) switch (id_b->type) { case IPSECDOI_ID_DER_ASN1_DN: - name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); + name = eay_get_x509asn1subjectname(iph1->cert_p); if (!name) { - plog(LLV_ERROR, LOCATION, NULL, + plog(LLV_ERROR, LOCATION, iph1->remote, "failed to get subjectName\n"); return ISAKMP_NTYPE_INVALID_CERTIFICATE; } if (idlen != name->l) { - plog(LLV_ERROR, LOCATION, NULL, + plog(LLV_ERROR, LOCATION, iph1->remote, "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, + plog(LLV_ERROR, LOCATION, iph1->remote, "ID mismatched with ASN1 SubjectName.\n"); plogdump(LLV_DEBUG, id_b + 1, idlen); plogdump(LLV_DEBUG, name->v, idlen); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + if (iph1->rmconf->verify_identifier) { + vfree(name); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } } + vfree(name); return 0; case IPSECDOI_ID_IPV4_ADDR: case IPSECDOI_ID_IPV6_ADDR: @@ -1918,7 +1848,7 @@ oakley_check_certid(iph1) int pos; for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + if (eay_get_x509subjectaltname(iph1->cert_p, &altname, &type, pos) !=0) { plog(LLV_ERROR, LOCATION, NULL, "failed to get subjectAltName\n"); @@ -1944,10 +1874,11 @@ oakley_check_certid(iph1) hints.ai_socktype = SOCK_RAW; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(altname, NULL, &hints, &res); + racoon_free(altname); + altname = NULL; if (error != 0) { plog(LLV_ERROR, LOCATION, NULL, "no proper subjectAltName.\n"); - racoon_free(altname); return ISAKMP_NTYPE_INVALID_CERTIFICATE; } switch (res->ai_family) { @@ -1962,7 +1893,6 @@ oakley_check_certid(iph1) default: plog(LLV_ERROR, LOCATION, NULL, "family not supported: %d.\n", res->ai_family); - racoon_free(altname); freeaddrinfo(res); return ISAKMP_NTYPE_INVALID_CERTIFICATE; } @@ -1974,7 +1904,8 @@ oakley_check_certid(iph1) "ID mismatched with subjectAltName.\n"); plogdump(LLV_DEBUG, id_b + 1, idlen); plogdump(LLV_DEBUG, a, idlen); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + if (iph1->rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } return 0; } @@ -1984,7 +1915,7 @@ oakley_check_certid(iph1) int pos; for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + if (eay_get_x509subjectaltname(iph1->cert_p, &altname, &type, pos) != 0){ plog(LLV_ERROR, LOCATION, NULL, "failed to get subjectAltName\n"); @@ -2078,7 +2009,7 @@ oakley_savecert(iph1, gen) struct ph1handle *iph1; struct isakmp_gen *gen; { - cert_t **c; + vchar_t **c; u_int8_t type; STACK_OF(X509) *certs=NULL; PKCS7 *p7; @@ -2173,7 +2104,7 @@ oakley_savecert(iph1, gen) "Trying PKCS#7 cert %d.\n", i); /* We'll just try each cert in turn */ - *c = save_certx509(cert); + *c = dump_x509(cert); if (!*c) { plog(LLV_ERROR, LOCATION, NULL, @@ -2185,19 +2116,18 @@ oakley_savecert(iph1, gen) * XXX If verify cert is disabled, we still just take * the first certificate.... */ - if(iph1->rmconf->verify_cert && - oakley_check_certid(iph1)) { + if (oakley_check_certid(iph1)) { plog(LLV_DEBUG, LOCATION, NULL, "Discarding CERT: does not match ID.\n"); - oakley_delcert((*c)); + vfree((*c)); *c = NULL; continue; } { - char *p = eay_get_x509text(&(*c)->cert); + char *p = eay_get_x509text(*c); plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plogdump(LLV_DEBUG, (*c)->v, (*c)->l); plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); racoon_free(p); @@ -2205,21 +2135,15 @@ oakley_savecert(iph1, gen) break; } PKCS7_free(p7); - } else { - *c = save_certbuf(gen); + *c = dump_isakmp_payload(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; + switch (type) { case ISAKMP_CERT_PGP: case ISAKMP_CERT_X509SIGN: case ISAKMP_CERT_KERBEROS: @@ -2228,33 +2152,32 @@ oakley_savecert(iph1, gen) * XXX If verify cert is disabled, we still just take * the first certificate.... */ - if(iph1->rmconf->verify_cert && - oakley_check_certid(iph1)){ + if (oakley_check_certid(iph1)){ plog(LLV_DEBUG, LOCATION, NULL, "Discarding CERT: does not match ID.\n"); - oakley_delcert((*c)); + vfree((*c)); *c = NULL; return 0; } { - char *p = eay_get_x509text(&(*c)->cert); + char *p = eay_get_x509text(*c); plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plogdump(LLV_DEBUG, (*c)->v, (*c)->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); + plogdump(LLV_DEBUG, (*c)->v, (*c)->l); break; case ISAKMP_CERT_X509KE: case ISAKMP_CERT_X509ATTR: case ISAKMP_CERT_ARL: default: /* XXX */ - oakley_delcert((*c)); + vfree(*c); *c = NULL; return 0; } @@ -2271,11 +2194,11 @@ oakley_savecr(iph1, gen) struct ph1handle *iph1; struct isakmp_gen *gen; { - cert_t **c; + vchar_t *cert; + vchar_t **c; u_int8_t type; type = *(u_int8_t *)(gen + 1) & 0xff; - switch (type) { case ISAKMP_CERT_DNS: plog(LLV_WARNING, LOCATION, NULL, @@ -2301,119 +2224,109 @@ oakley_savecr(iph1, gen) return -1; } - *c = save_certbuf(gen); - if (!*c) { + /* Already found an acceptable CR? */ + if (*c != NULL) + return 0; + + cert = dump_isakmp_payload(gen); + if (cert == NULL) { 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); + plog(LLV_DEBUG, LOCATION, NULL, "CR received:\n"); + plogdump(LLV_DEBUG, cert->v, cert->l); + *c = cert; + if (resolveph1rmconf(iph1) == 0) { + /* Found unique match */ + plog(LLV_DEBUG, LOCATION, NULL, "CR saved.\n"); + } else { + /* Still ambiguous or matches nothing, ignore this CR */ + *c = NULL; + vfree(cert); + } return 0; } -static cert_t * -save_certbuf(gen) - struct isakmp_gen *gen; +/* + * Add a single CR. + */ +struct append_cr_ctx { + struct ph1handle *iph1; + struct payload_list *plist; +}; + +static int +oakley_append_rmconf_cr(rmconf, ctx) + struct remoteconf *rmconf; + void *ctx; { - cert_t *new; + struct append_cr_ctx *actx = (struct append_cr_ctx *) ctx; + vchar_t *buf, *asn1dn = NULL; + int type; - if(ntohs(gen->len) <= sizeof(*gen)){ - plog(LLV_ERROR, LOCATION, NULL, - "Len is too small !!.\n"); - return NULL; - } + /* Do we want to send CR about this? */ + if (rmconf->send_cr == FALSE) + return 0; - new = oakley_newcert(); - if (!new) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to get CERT buffer.\n"); - return NULL; - } + if (rmconf->peerscert != NULL) { + type = oakley_get_certtype(rmconf->peerscert); + asn1dn = eay_get_x509asn1issuername(rmconf->peerscert); + } else if (rmconf->cacert != NULL) { + type = oakley_get_certtype(rmconf->cacert); + asn1dn = eay_get_x509asn1subjectname(rmconf->cacert); + } else + return 0; - 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; + if (asn1dn == NULL) { + plog(LLV_ERROR, LOCATION, actx->iph1->remote, + "Failed to get CR ASN1 DN from certificate\n"); + return 0; } - 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; -} + buf = vmalloc(1 + asn1dn->l); + if (buf == NULL) + goto err; -static cert_t * -save_certx509(cert) - X509 *cert; -{ - cert_t *new; - int len; - u_char *bp; + buf->v[0] = type; + memcpy(&buf->v[1], asn1dn->v, asn1dn->l); - new = oakley_newcert(); - if (!new) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to get CERT buffer.\n"); - return NULL; - } + plog(LLV_DEBUG, LOCATION, actx->iph1->remote, + "appending CR: %s\n", + s_isakmp_certtype(buf->v[0])); + plogdump(LLV_DEBUG, buf->v, buf->l); - 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; + actx->plist = isakmp_plist_append_full(actx->plist, buf, ISAKMP_NPTYPE_CR, 1); - return new; +err: + vfree(asn1dn); + return 0; } /* - * 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. + * Append list of acceptable CRs. + * RFC2048 3.10 */ -vchar_t * -oakley_getcr(iph1) +struct payload_list * +oakley_append_cr(plist, iph1) + struct payload_list *plist; 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; - } - if(iph1->rmconf->certtype == ISAKMP_CERT_NONE) { - buf->v[0] = iph1->rmconf->cacerttype; - plog(LLV_DEBUG, LOCATION, NULL, "create my CR: NONE, using %s instead\n", - s_isakmp_certtype(iph1->rmconf->cacerttype)); + struct append_cr_ctx ctx; + struct rmconfselector sel; + + ctx.iph1 = iph1; + ctx.plist = plist; + if (iph1->rmconf == NULL) { + rmconf_selector_from_ph1(&sel, iph1); + enumrmconf(&sel, oakley_append_rmconf_cr, &ctx); } else { - buf->v[0] = iph1->rmconf->certtype; - plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n", - s_isakmp_certtype(iph1->rmconf->certtype)); + oakley_append_rmconf_cr(iph1->rmconf, &ctx); } - if (buf->l > 1) - plogdump(LLV_DEBUG, buf->v, buf->l); - return buf; + return ctx.plist; } /* @@ -2423,17 +2336,20 @@ int oakley_checkcr(iph1) struct ph1handle *iph1; { + int type; + 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)); + s_isakmp_certtype(oakley_get_certtype(iph1->cr_p))); - if (iph1->cr_p->type != iph1->rmconf->certtype) { + type = oakley_get_certtype(iph1->cr_p); + if (type != oakley_get_certtype(iph1->rmconf->mycert)) { plog(LLV_ERROR, LOCATION, iph1->remote, - "such a cert type isn't supported: %d\n", - (char)iph1->cr_p->type); + "such a cert type isn't supported: %d\n", + type); return -1; } @@ -2482,10 +2398,10 @@ oakley_skeyid(iph1) int error = -1; /* SKEYID */ - switch (AUTHMETHOD(iph1)) { + switch (iph1->approval->authmethod) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: #ifdef ENABLE_HYBRID - case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: #endif if (iph1->etype != ISAKMP_ETYPE_IDENT) { @@ -2748,7 +2664,7 @@ oakley_compute_enckey(iph1) iph1->approval->encklen); if (keylen == -1) { plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoritym %d, " + "invalid encryption algorithm %d, " "or invalid key length %d.\n", iph1->approval->enctype, iph1->approval->encklen); @@ -2852,7 +2768,7 @@ oakley_compute_enckey(iph1) 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", + "encryption algorithm %d isn't supported.\n", iph1->approval->enctype); goto end; } @@ -2872,36 +2788,6 @@ 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) @@ -2956,7 +2842,7 @@ oakley_newiv(iph1) 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", + "invalid encryption algorithm %d.\n", iph1->approval->enctype); vfree(buf); oakley_delivm(newivm); @@ -3038,7 +2924,7 @@ oakley_newiv2(iph1, msgid) 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", + "invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } @@ -3102,7 +2988,7 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (blen == -1) { plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + "invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } @@ -3224,7 +3110,7 @@ oakley_do_encrypt(iph1, msg, ivep, ivp) blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (blen == -1) { plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + "invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } diff --git a/src/racoon/oakley.h b/src/racoon/oakley.h index a8dbbd2..f8cdb76 100644 --- a/src/racoon/oakley.h +++ b/src/racoon/oakley.h @@ -1,4 +1,4 @@ -/* $NetBSD: oakley.h,v 1.5 2006/10/06 12:02:27 manu Exp $ */ +/* $NetBSD: oakley.h,v 1.7 2009/03/12 10:57:26 tteras Exp $ */ /* Id: oakley.h,v 1.13 2005/05/30 20:12:43 fredsen Exp */ @@ -89,21 +89,18 @@ #define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R 65010 #endif - /* 65500 -> still private - * to avoid clash with GSSAPI_KRB below - */ -#define FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I 65500 +/* + * 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 + 0x10000) +#define OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB_REAL 65001 - /* - * 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 @@ -163,13 +160,6 @@ struct dhgroup { 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; @@ -200,10 +190,13 @@ 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_get_certtype __P((vchar_t *)); 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 struct payload_list *oakley_append_cr __P((struct payload_list *, + struct ph1handle *)); extern int oakley_checkcr __P((struct ph1handle *)); extern int oakley_needcr __P((int)); struct isakmp_gen; @@ -214,8 +207,6 @@ 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 *)); @@ -224,20 +215,4 @@ extern vchar_t *oakley_do_decrypt __P((struct ph1handle *, extern vchar_t *oakley_do_encrypt __P((struct ph1handle *, vchar_t *, vchar_t *, vchar_t *)); -#ifdef ENABLE_HYBRID -#define AUTHMETHOD(iph1) \ - (((iph1)->rmconf->xauth && \ - (iph1)->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I) ? \ - FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I : (iph1)->approval->authmethod) -#define RMAUTHMETHOD(iph1) \ - (((iph1)->rmconf->xauth && \ - (iph1)->rmconf->proposal->authmethod == \ - OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I) ? \ - FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I : \ - (iph1)->rmconf->proposal->authmethod) -#else -#define AUTHMETHOD(iph1) (iph1)->approval->authmethod -#define RMAUTHMETHOD(iph1) (iph1)->rmconf->proposal->authmethod -#endif /* ENABLE_HYBRID */ - #endif /* _OAKLEY_H */ diff --git a/src/racoon/pfkey.c b/src/racoon/pfkey.c index e73acc8..e69cb94 100644 --- a/src/racoon/pfkey.c +++ b/src/racoon/pfkey.c @@ -1,11 +1,11 @@ -/* $NetBSD: pfkey.c,v 1.18.4.5 2008/03/05 22:14:24 mgrooms Exp $ */ +/* $NetBSD: pfkey.c,v 1.57 2011/03/15 13:20:14 vanhu Exp $ */ -/* $Id: pfkey.c,v 1.18.4.5 2008/03/05 22:14:24 mgrooms Exp $ */ +/* $Id: pfkey.c,v 1.57 2011/03/15 13:20:14 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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -77,6 +77,7 @@ #include "vmbuf.h" #include "plog.h" #include "sockmisc.h" +#include "session.h" #include "debug.h" #include "schedule.h" @@ -94,6 +95,7 @@ #include "algorithm.h" #include "sainfo.h" #include "admin.h" +#include "evt.h" #include "privsep.h" #include "strnames.h" #include "backupsa.h" @@ -129,6 +131,9 @@ 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 *)); +#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS) +static int pk_recvmigrate __P((caddr_t *)); +#endif static struct sadb_msg *pk_recv __P((int, int *)); static int (*pkrecvf[]) __P((caddr_t *)) = { @@ -156,17 +161,21 @@ NULL, /* SADB_X_SPDSETIDX */ pk_recvspdexpire, NULL, /* SADB_X_SPDDELETE2 */ NULL, /* SADB_X_NAT_T_NEW_MAPPING */ +#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS) +pk_recvmigrate, +#else NULL, /* SADB_X_MIGRATE */ +#endif #if (SADB_MAX > 24) #error "SADB extra message?" #endif }; -static int addnewsp __P((caddr_t *)); +static int addnewsp __P((caddr_t *, struct sockaddr *, struct sockaddr *)); /* cope with old kame headers - ugly */ #ifndef SADB_X_AALG_MD5 -#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 #endif #ifndef SADB_X_AALG_SHA #define SADB_X_AALG_SHA SADB_AALG_SHA @@ -192,8 +201,10 @@ static int addnewsp __P((caddr_t *)); * 0: success * -1: fail */ -int -pfkey_handler() +static int +pfkey_handler(ctx, fd) + void *ctx; + int fd; { struct sadb_msg *msg; int len; @@ -202,9 +213,16 @@ pfkey_handler() /* receive pfkey message. */ len = 0; - msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len); + msg = (struct sadb_msg *) pk_recv(fd, &len); if (msg == NULL) { if (len < 0) { + /* do not report EAGAIN as error; well get + * called from main loop later. and it's normal + * when spd dump is received during reload and + * this function is called in loop. */ + if (errno == EAGAIN) + goto end; + plog(LLV_ERROR, LOCATION, NULL, "failed to recv from pfkey (%s)\n", strerror(errno)); @@ -215,7 +233,7 @@ pfkey_handler() } } - plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n", + plog(LLV_DEBUG, LOCATION, NULL, "got pfkey %s message\n", s_pfkey_type(msg->sadb_msg_type)); plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3); @@ -271,7 +289,7 @@ pfkey_handler() if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0) goto end; - error = 0; + error = 1; end: if (msg) racoon_free(msg); @@ -285,20 +303,32 @@ vchar_t * pfkey_dump_sadb(satype) int satype; { - int s = -1; + int s; vchar_t *buf = NULL; pid_t pid = getpid(); struct sadb_msg *msg = NULL; size_t bl, ml; int len; + int bufsiz; - if ((s = privsep_pfkey_open()) < 0) { + if ((s = privsep_socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { plog(LLV_ERROR, LOCATION, NULL, "libipsec failed pfkey open: %s\n", ipsec_strerror()); return NULL; } + if ((bufsiz = pfkey_set_buffer_size(s, lcconf->pfkey_buffer_size)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey set buffer size to %d: %s\n", + lcconf->pfkey_buffer_size, ipsec_strerror()); + return NULL; + } else if (bufsiz < lcconf->pfkey_buffer_size) { + plog(LLV_WARNING, LOCATION, NULL, + "pfkey socket receive buffer set to %dKB, instead of %d\n", + bufsiz, lcconf->pfkey_buffer_size); + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n"); if (pfkey_send_dump(s, satype) < 0) { plog(LLV_ERROR, LOCATION, NULL, @@ -325,7 +355,7 @@ pfkey_dump_sadb(satype) "type %i, pid %i\n", msg->sadb_msg_type, msg->sadb_msg_pid); continue; } - + ml = msg->sadb_msg_len << 3; bl = buf ? buf->l : 0; @@ -349,8 +379,7 @@ fail: done: if (msg) racoon_free(msg); - if (s >= 0) - privsep_pfkey_close(s); + close(s); return buf; } @@ -400,12 +429,25 @@ int pfkey_init() { int i, reg_fail; + int bufsiz; - if ((lcconf->sock_pfkey = privsep_pfkey_open()) < 0) { + if ((lcconf->sock_pfkey = pfkey_open()) < 0) { plog(LLV_ERROR, LOCATION, NULL, "libipsec failed pfkey open (%s)\n", ipsec_strerror()); return -1; } + if ((bufsiz = pfkey_set_buffer_size(lcconf->sock_pfkey, + lcconf->pfkey_buffer_size)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed to set pfkey buffer size to %d (%s)\n", + lcconf->pfkey_buffer_size, ipsec_strerror()); + return -1; + } else if (bufsiz < lcconf->pfkey_buffer_size) { + plog(LLV_WARNING, LOCATION, NULL, + "pfkey socket receive buffer set to %dKB, instead of %d\n", + bufsiz, lcconf->pfkey_buffer_size); + } + if (fcntl(lcconf->sock_pfkey, F_SETFL, O_NONBLOCK) == -1) plog(LLV_WARNING, LOCATION, NULL, "failed to set the pfkey socket to NONBLOCK\n"); @@ -447,6 +489,25 @@ pfkey_init() return -1; } #endif + monitor_fd(lcconf->sock_pfkey, pfkey_handler, NULL, 0); + return 0; +} + +int +pfkey_reload() +{ + flushsp(); + + if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec sending spddump failed: %s\n", + ipsec_strerror()); + return -1; + } + + while (pfkey_handler(NULL, lcconf->sock_pfkey) > 0) + continue; + return 0; } @@ -717,6 +778,29 @@ keylen_ealg(enctype, encklen) return res; } +void +pk_fixup_sa_addresses(mhp) + caddr_t *mhp; +{ + struct sockaddr *src, *dst; + + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + set_port(src, PORT_ISAKMP); + set_port(dst, PORT_ISAKMP); + +#ifdef ENABLE_NATT + if (PFKEY_ADDR_X_NATTYPE(mhp[SADB_X_EXT_NAT_T_TYPE])) { + /* NAT-T is enabled for this SADB entry; copy + * the ports from NAT-T extensions */ + if(mhp[SADB_X_EXT_NAT_T_SPORT] != NULL) + set_port(src, PFKEY_ADDR_X_PORT(mhp[SADB_X_EXT_NAT_T_SPORT])); + if(mhp[SADB_X_EXT_NAT_T_DPORT] != NULL) + set_port(dst, PFKEY_ADDR_X_PORT(mhp[SADB_X_EXT_NAT_T_DPORT])); + } +#endif +} + int pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, e_type, e_keylen, a_type, a_keylen, flags) @@ -757,7 +841,7 @@ pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, goto bad; *a_keylen >>= 3; - if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 + 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; @@ -798,35 +882,6 @@ pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, 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 */ /* @@ -843,25 +898,28 @@ pk_sendgetspi(iph2) struct saprop *pp; struct saproto *pr; u_int32_t minspi, maxspi; - int proxy = 0; + u_int8_t natt_type = 0; + u_int16_t sport = 0, dport = 0; - if (iph2->side == INITIATOR) { + if (iph2->side == INITIATOR) pp = iph2->proposal; - proxy = iph2->ph1->rmconf->support_proxy; - } else { + 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; + if (iph2->sa_src && iph2->sa_dst) { + /* MIPv6: Use SA addresses, not IKE ones */ + src = dupsaddr(iph2->sa_src); + dst = dupsaddr(iph2->sa_dst); } else { - src = iph2->src; - dst = iph2->dst; + /* Common case: SA addresses and IKE ones are the same */ + src = dupsaddr(iph2->src); + dst = dupsaddr(iph2->dst); + } + + if (src == NULL || dst == NULL) { + racoon_free(src); + racoon_free(dst); + return -1; } for (pr = pp->head; pr != NULL; pr = pr->next) { @@ -871,6 +929,8 @@ pk_sendgetspi(iph2) if (satype == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid proto_id %d\n", pr->proto_id); + racoon_free(src); + racoon_free(dst); return -1; } /* this works around a bug in Linux kernel where it allocates 4 byte @@ -887,30 +947,36 @@ pk_sendgetspi(iph2) if (mode == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid encmode %d\n", pr->encmode); + racoon_free(src); + racoon_free(dst); return -1; } #ifdef ENABLE_NATT - /* XXX should we do a copy of src/dst for each pr ? - */ - if (! pr->udp_encap) { - /* Remove port information, that SA doesn't use it */ - set_port(src, 0); - set_port(dst, 0); + if (pr->udp_encap) { + natt_type = iph2->ph1->natt_options->encaps_type; + sport=extract_port(src); + dport=extract_port(dst); } #endif + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n"); - if (pfkey_send_getspi( + if (pfkey_send_getspi_nat( lcconf->sock_pfkey, satype, mode, dst, /* src of SA */ src, /* dst of SA */ + natt_type, + dport, + sport, minspi, maxspi, pr->reqid_in, iph2->seq) < 0) { plog(LLV_ERROR, LOCATION, NULL, "ipseclib failed send getspi (%s)\n", ipsec_strerror()); + racoon_free(src); + racoon_free(dst); return -1; } plog(LLV_DEBUG, LOCATION, NULL, @@ -918,6 +984,8 @@ pk_sendgetspi(iph2) sadbsecas2str(dst, src, satype, 0, mode)); } + racoon_free(src); + racoon_free(dst); return 0; } @@ -925,13 +993,13 @@ pk_sendgetspi(iph2) * receive GETSPI from kernel. */ static int -pk_recvgetspi(mhp) +pk_recvgetspi(mhp) caddr_t *mhp; { struct sadb_msg *msg; struct sadb_sa *sa; struct ph2handle *iph2; - struct sockaddr *dst; + struct sockaddr *src, *dst; int proto_id; int allspiok, notfound; struct saprop *pp; @@ -939,14 +1007,17 @@ pk_recvgetspi(mhp) /* validity check */ if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == 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]; + pk_fixup_sa_addresses(mhp); dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */ + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); /* the message has to be processed or not ? */ if (msg->sadb_msg_pid != getpid()) { @@ -986,7 +1057,7 @@ pk_recvgetspi(mhp) notfound = 0; plog(LLV_DEBUG, LOCATION, NULL, "pfkey GETSPI succeeded: %s\n", - sadbsecas2str(iph2->dst, iph2->src, + sadbsecas2str(dst, src, msg->sadb_msg_satype, sa->sadb_sa_spi, ipsecdoi2pfkey_mode(pr->encmode))); @@ -998,7 +1069,7 @@ pk_recvgetspi(mhp) if (notfound) { plog(LLV_ERROR, LOCATION, NULL, "get spi for unknown address %s\n", - saddrwop2str(iph2->dst)); + saddrwop2str(dst)); return -1; } @@ -1008,7 +1079,6 @@ pk_recvgetspi(mhp) 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; @@ -1028,34 +1098,38 @@ pk_sendupdate(iph2) { struct saproto *pr; struct pfkey_send_sa_args sa_args; - int proxy = 0; /* sanity check */ if (iph2->approval == NULL) { plog(LLV_ERROR, LOCATION, NULL, "no approvaled SAs found.\n"); + return -1; } - if (iph2->side == INITIATOR) - proxy = iph2->ph1->rmconf->support_proxy; - else if (iph2->sainfo && iph2->sainfo->id_i) - proxy = 1; - /* fill in some needed for pfkey_send_update2 */ memset (&sa_args, 0, sizeof (sa_args)); sa_args.so = lcconf->sock_pfkey; - sa_args.l_addtime = iph2->approval->lifetime; - sa_args.seq = iph2->seq; + if (iph2->lifetime_secs) + sa_args.l_addtime = iph2->lifetime_secs; + else + sa_args.l_addtime = iph2->approval->lifetime; + sa_args.seq = iph2->seq; sa_args.wsize = 4; - /* for mobile IPv6 */ - if (proxy && iph2->src_id && iph2->dst_id && - ipsecdoi_transportmode(iph2->approval)) { - sa_args.dst = iph2->src_id; - sa_args.src = iph2->dst_id; + if (iph2->sa_src && iph2->sa_dst) { + /* MIPv6: Use SA addresses, not IKE ones */ + sa_args.dst = dupsaddr(iph2->sa_src); + sa_args.src = dupsaddr(iph2->sa_dst); } else { - sa_args.dst = iph2->src; - sa_args.src = iph2->dst; + /* Common case: SA addresses and IKE ones are the same */ + sa_args.dst = dupsaddr(iph2->src); + sa_args.src = dupsaddr(iph2->dst); + } + + if (sa_args.src == NULL || sa_args.dst == NULL) { + racoon_free(sa_args.src); + racoon_free(sa_args.dst); + return -1; } for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { @@ -1064,6 +1138,8 @@ pk_sendupdate(iph2) if (sa_args.satype == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid proto_id %d\n", pr->proto_id); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } else if (sa_args.satype == SADB_X_SATYPE_IPCOMP) { @@ -1077,6 +1153,8 @@ pk_sendupdate(iph2) if (sa_args.mode == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid encmode %d\n", pr->encmode); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } #endif @@ -1087,9 +1165,12 @@ pk_sendupdate(iph2) pr->head->trns_id, pr->head->authtype, &sa_args.e_type, &sa_args.e_keylen, - &sa_args.a_type, &sa_args.a_keylen, - &sa_args.flags) < 0) + &sa_args.a_type, &sa_args.a_keylen, + &sa_args.flags) < 0){ + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; + } #if 0 sa_args.l_bytes = iph2->approval->lifebyte * 1024, @@ -1109,19 +1190,15 @@ pk_sendupdate(iph2) #ifdef ENABLE_NATT if (pr->udp_encap) { sa_args.l_natt_type = iph2->ph1->natt_options->encaps_type; - sa_args.l_natt_sport = extract_port (iph2->ph1->remote); - sa_args.l_natt_dport = extract_port (iph2->ph1->local); - sa_args.l_natt_oa = NULL; // FIXME: Here comes OA!!! + sa_args.l_natt_sport = extract_port(iph2->ph1->remote); + sa_args.l_natt_dport = extract_port(iph2->ph1->local); + sa_args.l_natt_oa = iph2->natoa_src; #ifdef SADB_X_EXT_NAT_T_FRAG sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag; #endif - } else { - /* Remove port information, that SA doesn't use it */ - set_port(sa_args.src, 0); - set_port(sa_args.dst, 0); } - #endif + /* more info to fill in */ sa_args.spi = pr->spi; sa_args.reqid = pr->reqid_in; @@ -1132,6 +1209,8 @@ pk_sendupdate(iph2) plog(LLV_ERROR, LOCATION, NULL, "libipsec failed send update (%s)\n", ipsec_strerror()); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } @@ -1145,11 +1224,11 @@ pk_sendupdate(iph2) * But it is impossible because there is not key in the * information from the kernel. */ - + /* change some things before backing up */ sa_args.wsize = 4; sa_args.l_bytes = iph2->approval->lifebyte * 1024; - + if (backupsa_to_file(&sa_args) < 0) { plog(LLV_ERROR, LOCATION, NULL, "backuped SA failed: %s\n", @@ -1163,6 +1242,8 @@ pk_sendupdate(iph2) #endif } + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return 0; } @@ -1192,6 +1273,7 @@ pk_recvupdate(mhp) return -1; } msg = (struct sadb_msg *)mhp[0]; + pk_fixup_sa_addresses(mhp); 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]; @@ -1246,14 +1328,14 @@ pk_recvupdate(mhp) pr->ok = 1; plog(LLV_DEBUG, LOCATION, NULL, "pfkey UPDATE succeeded: %s\n", - sadbsecas2str(iph2->dst, iph2->src, + sadbsecas2str(dst, 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, + sadbsecas2str(dst, src, msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); } @@ -1266,10 +1348,11 @@ pk_recvupdate(mhp) return 0; /* turn off the timer for calling pfkey_timeover() */ - SCHED_KILL(iph2->sce); - + sched_cancel(&iph2->sce); + /* update status */ iph2->status = PHASE2ST_ESTABLISHED; + evt_phase2(iph2, EVT_PHASE2_UP, NULL); #ifdef ENABLE_STATS gettimeofday(&iph2->end, NULL); @@ -1277,29 +1360,15 @@ pk_recvupdate(mhp) "phase2", "quick", timedelta(&iph2->start, &iph2->end)); #endif - /* count up */ - iph2->ph1->ph2cnt++; - /* turn off schedule */ - SCHED_KILL(iph2->scr); - - /* Force the update of ph2's ports, as there is at least one - * situation where they'll mismatch with ph1's values - */ - -#ifdef ENABLE_NATT - set_port(iph2->src, extract_port(iph2->ph1->local)); - set_port(iph2->dst, extract_port(iph2->ph1->remote)); -#endif + sched_cancel(&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); + sched_schedule(&iph2->sce, iph2->approval->lifetime, + isakmp_ph2expire_stub); plog(LLV_DEBUG, LOCATION, NULL, "===\n"); return 0; @@ -1313,7 +1382,6 @@ pk_sendadd(iph2) struct ph2handle *iph2; { struct saproto *pr; - int proxy = 0; struct pfkey_send_sa_args sa_args; /* sanity check */ @@ -1323,26 +1391,30 @@ pk_sendadd(iph2) return -1; } - if (iph2->side == INITIATOR) - proxy = iph2->ph1->rmconf->support_proxy; - else if (iph2->sainfo && iph2->sainfo->id_i) - proxy = 1; - /* fill in some needed for pfkey_send_update2 */ memset (&sa_args, 0, sizeof (sa_args)); sa_args.so = lcconf->sock_pfkey; - sa_args.l_addtime = iph2->approval->lifetime; + if (iph2->lifetime_secs) + sa_args.l_addtime = iph2->lifetime_secs; + else + sa_args.l_addtime = iph2->approval->lifetime; sa_args.seq = iph2->seq; sa_args.wsize = 4; - /* for mobile IPv6 */ - if (proxy && iph2->src_id && iph2->dst_id && - ipsecdoi_transportmode(iph2->approval)) { - sa_args.src = iph2->src_id; - sa_args.dst = iph2->dst_id; + if (iph2->sa_src && iph2->sa_dst) { + /* MIPv6: Use SA addresses, not IKE ones */ + sa_args.src = dupsaddr(iph2->sa_src); + sa_args.dst = dupsaddr(iph2->sa_dst); } else { - sa_args.src = iph2->src; - sa_args.dst = iph2->dst; + /* Common case: SA addresses and IKE ones are the same */ + sa_args.src = dupsaddr(iph2->src); + sa_args.dst = dupsaddr(iph2->dst); + } + + if (sa_args.src == NULL || sa_args.dst == NULL) { + racoon_free(sa_args.src); + racoon_free(sa_args.dst); + return -1; } for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { @@ -1351,6 +1423,8 @@ pk_sendadd(iph2) if (sa_args.satype == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid proto_id %d\n", pr->proto_id); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } else if (sa_args.satype == SADB_X_SATYPE_IPCOMP) { @@ -1364,6 +1438,8 @@ pk_sendadd(iph2) if (sa_args.mode == ~0) { plog(LLV_ERROR, LOCATION, NULL, "invalid encmode %d\n", pr->encmode); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } #endif @@ -1375,9 +1451,12 @@ pk_sendadd(iph2) pr->head->trns_id, pr->head->authtype, &sa_args.e_type, &sa_args.e_keylen, - &sa_args.a_type, &sa_args.a_keylen, - &sa_args.flags) < 0) + &sa_args.a_type, &sa_args.a_keylen, + &sa_args.flags) < 0){ + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; + } #if 0 sa_args.l_bytes = iph2->approval->lifebyte * 1024, @@ -1402,22 +1481,12 @@ pk_sendadd(iph2) sa_args.l_natt_type = UDP_ENCAP_ESPINUDP; sa_args.l_natt_sport = extract_port(iph2->ph1->local); sa_args.l_natt_dport = extract_port(iph2->ph1->remote); - sa_args.l_natt_oa = NULL; // FIXME: Here comes OA!!! + sa_args.l_natt_oa = iph2->natoa_dst; #ifdef SADB_X_EXT_NAT_T_FRAG sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag; #endif - } else { - /* Remove port information, that SA doesn't use it */ - set_port(sa_args.src, 0); - set_port(sa_args.dst, 0); } - -#else - /* Remove port information, it is not used without NAT-T */ - set_port(sa_args.src, 0); - set_port(sa_args.dst, 0); #endif - /* more info to fill in */ sa_args.spi = pr->spi_p; sa_args.reqid = pr->reqid_out; @@ -1428,6 +1497,8 @@ pk_sendadd(iph2) plog(LLV_ERROR, LOCATION, NULL, "libipsec failed send add (%s)\n", ipsec_strerror()); + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return -1; } @@ -1453,6 +1524,8 @@ pk_sendadd(iph2) sa_args.satype, sa_args.spi, sa_args.mode)); #endif } + racoon_free(sa_args.src); + racoon_free(sa_args.dst); return 0; } @@ -1480,6 +1553,7 @@ pk_recvadd(mhp) return -1; } msg = (struct sadb_msg *)mhp[0]; + pk_fixup_sa_addresses(mhp); 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]; @@ -1514,7 +1588,7 @@ pk_recvadd(mhp) plog(LLV_INFO, LOCATION, NULL, "IPsec-SA established: %s\n", - sadbsecas2str(iph2->src, iph2->dst, + sadbsecas2str(src, dst, msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); plog(LLV_DEBUG, LOCATION, NULL, "===\n"); @@ -1544,6 +1618,7 @@ pk_recvexpire(mhp) } msg = (struct sadb_msg *)mhp[0]; sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + pk_fixup_sa_addresses(mhp); src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); @@ -1577,54 +1652,63 @@ pk_recvexpire(mhp) sa_mode)); return 0; } - if (iph2->status != PHASE2ST_ESTABLISHED) { + + /* resent expiry message? */ + if (iph2->status > PHASE2ST_ESTABLISHED) + return 0; + + /* still negotiating? */ + if (iph2->status < PHASE2ST_ESTABLISHED) { + /* not a hard timeout? */ + if (mhp[SADB_EXT_LIFETIME_HARD] == NULL) + return 0; + /* - * 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. + * We were negotiating for that SA (w/o much success + * from current status) and kernel has decided our time + * is over trying (xfrm_larval_drop controls that and + * is enabled by default on Linux >= 2.6.28 kernels). */ plog(LLV_WARNING, LOCATION, NULL, - "the expire message is received " - "but the handler has not been established.\n"); - return 0; + "PF_KEY EXPIRE message received from kernel for SA" + " being negotiated. Stopping negotiation.\n"); } - /* turn off the timer for calling isakmp_ph2expire() */ - SCHED_KILL(iph2->sce); - - iph2->status = PHASE2ST_EXPIRED; + /* turn off the timer for calling isakmp_ph2expire() */ + sched_cancel(&iph2->sce); - /* INITIATOR, begin phase 2 exchange. */ - /* allocate buffer for status management of pfkey message */ - if (iph2->side == INITIATOR) { - - initph2(iph2); + if (iph2->status == PHASE2ST_ESTABLISHED && + iph2->side == INITIATOR) { + struct ph1handle *iph1hint; + /* + * Active phase 2 expired and we were initiator. + * Begin new phase 2 exchange, so we can keep on sending + * traffic. + */ /* update status for re-use */ + iph1hint = iph2->ph1; + initph2(iph2); iph2->status = PHASE2ST_STATUS2; - /* start isakmp initiation by using ident exchange */ - if (isakmp_post_acquire(iph2) < 0) { + /* start quick exchange */ + if (isakmp_post_acquire(iph2, iph1hint, FALSE) < 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); + /* + * We are responder or the phase 2 was not established. + * Just remove the ph2handle to reflect SADB. + */ + iph2->status = PHASE2ST_EXPIRED; remph2(iph2); delph2(iph2); @@ -1638,17 +1722,15 @@ pk_recvacquire(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 */ - int remoteid=0; + struct ph2handle *iph2; + struct sockaddr *src, *dst; /* IKE addresses (for exchanges) */ + struct sockaddr *sp_src, *sp_dst; /* SP addresses (selectors). */ + struct sockaddr *sa_src = NULL, *sa_dst = NULL ; /* SA addresses */ #ifdef HAVE_SECCTX struct sadb_x_sec_ctx *m_sec_ctx; #endif /* HAVE_SECCTX */ struct policyindex spidx; - /* ignore this message because of local test mode. */ if (f_local) return 0; @@ -1664,8 +1746,11 @@ pk_recvacquire(mhp) } 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]); + /* acquire does not have nat-t ports; so do not bother setting + * the default port 500; just use the port zero for wildcard + * matching the get a valid natted destination */ + sp_src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + sp_dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); #ifdef HAVE_SECCTX m_sec_ctx = (struct sadb_x_sec_ctx *)mhp[SADB_X_EXT_SEC_CTX]; @@ -1673,7 +1758,7 @@ pk_recvacquire(mhp) if (m_sec_ctx != NULL) { plog(LLV_INFO, LOCATION, NULL, "security context doi: %u\n", m_sec_ctx->sadb_x_ctx_doi); - plog(LLV_INFO, LOCATION, NULL, + plog(LLV_INFO, LOCATION, NULL, "security context algorithm: %u\n", m_sec_ctx->sadb_x_ctx_alg); plog(LLV_INFO, LOCATION, NULL, "security context length: %u\n", @@ -1690,50 +1775,81 @@ pk_recvacquire(mhp) return 0; } - /* ignore it if src is multicast address */ - { - struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + /* ignore it if src or dst are multicast addresses. */ + if ((sp_dst->sa_family == AF_INET + && IN_MULTICAST(ntohl(((struct sockaddr_in *)sp_dst)->sin_addr.s_addr))) +#ifdef INET6 + || (sp_dst->sa_family == AF_INET6 + && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sp_dst)->sin6_addr)) +#endif + ) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore due to multicast destination address: %s.\n", + saddrwop2str(sp_dst)); + return 0; + } - if ((sa->sa_family == AF_INET - && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr))) + if ((sp_src->sa_family == AF_INET + && IN_MULTICAST(ntohl(((struct sockaddr_in *)sp_src)->sin_addr.s_addr))) #ifdef INET6 - || (sa->sa_family == AF_INET6 - && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr)) + || (sp_src->sa_family == AF_INET6 + && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sp_src)->sin6_addr)) #endif ) { plog(LLV_DEBUG, LOCATION, NULL, - "ignore due to multicast address: %s.\n", - saddrwop2str(sa)); + "ignore due to multicast source address: %s.\n", + saddrwop2str(sp_src)); 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; - } + /* 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)); + + /* Before going further, let first get the source and destination + * address that would be used for IKE negotiation. The logic is: + * - if SP from SPD image contains local and remote hints, we + * use them (provided by MIGRATE). + * - otherwise, we use the ones from the ipsecrequest, which means: + * - the addresses from the request for transport mode + * - the endpoints addresses for tunnel mode + * + * Note that: + * 1) racoon does not support negotiation of bundles which + * simplifies the lookup for the addresses in the ipsecrequest + * list, as we expect only one. + * 2) We do source and destination parts all together and do not + * accept semi-defined information. This is just a decision, + * there might be needs. + * + * --arno + */ + if (sp_out->req && sp_out->req->saidx.mode == IPSEC_MODE_TUNNEL) { + /* For Tunnel mode, SA addresses are the endpoints */ + src = (struct sockaddr *) &sp_out->req->saidx.src; + dst = (struct sockaddr *) &sp_out->req->saidx.dst; + } else { + /* Otherwise use requested addresses. + * + * We need to explicitly setup sa_src and sa_dst too, + * since the SA ports are different from IKE port. And + * src/dst ports will be overwritten when the matching + * phase1 is found. */ + src = sa_src = sp_src; + dst = sa_dst = sp_dst; + } + if (sp_out->local && sp_out->remote) { + /* hints available, let's use them */ + sa_src = src; + sa_dst = dst; + src = (struct sockaddr *) sp_out->local; + dst = (struct sockaddr *) sp_out->remote; } /* @@ -1746,27 +1862,25 @@ pk_recvacquire(mhp) * 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) { + iph2 = getph2byid(src, dst, xpl->sadb_x_policy_id); + if (iph2 != NULL) { + if (iph2->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; + if (iph2->status == PHASE2ST_EXPIRED) + iph2 = 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; + /* Check we are listening on source address. If not, ignore. */ + if (myaddr_getsport(src) == -1) { + plog(LLV_DEBUG, LOCATION, NULL, + "Not listening on source address %s. Ignoring ACQUIRE.\n", + saddrwop2str(src)); + return 0; } - plog(LLV_DEBUG, LOCATION, NULL, - "suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx)); /* get inbound policy */ { @@ -1802,119 +1916,67 @@ pk_recvacquire(mhp) } } - memset(iph2, 0, MAXNESTEDSA); - - n = 0; - /* allocate a phase 2 */ - iph2[n] = newph2(); - if (iph2[n] == NULL) { + iph2 = newph2(); + if (iph2 == 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]); + iph2->side = INITIATOR; + iph2->spid = xpl->sadb_x_policy_id; + iph2->satype = msg->sadb_msg_satype; + iph2->seq = msg->sadb_msg_seq; + iph2->status = PHASE2ST_STATUS2; + + /* set address used by IKE for the negotiation (might differ from + * SA address, i.e. might not be tunnel endpoints or addresses + * of transport mode SA) */ + iph2->dst = dupsaddr(dst); + if (iph2->dst == NULL) { + delph2(iph2); return -1; } - iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC])); - if (iph2[n]->src == NULL) { - delph2(iph2[n]); + iph2->src = dupsaddr(src); + if (iph2->src == NULL) { + delph2(iph2); 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; + /* If sa_src and sa_dst have been set, this mean we have to + * set iph2->sa_src and iph2->sa_dst to provide the addresses + * of the SA because iph2->src and iph2->dst are only the ones + * used for the IKE exchanges. Those that need these addresses + * are for instance pk_sendupdate() or pk_sendgetspi() */ + if (sa_src) { + iph2->sa_src = dupsaddr(sa_src); + iph2->sa_dst = dupsaddr(sa_dst); } - 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; - } - { - struct remoteconf *conf; - conf = getrmconf(iph2[n]->dst); - if (conf != NULL) - remoteid=conf->ph1id; - else{ - plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n"); - remoteid=0; - } - } - iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL, remoteid); - 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 */ - } - - plog(LLV_DEBUG, LOCATION, NULL, - "selected sainfo: %s\n", sainfo2str(iph2[n]->sainfo)); - } - 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]); + if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) { + delph2(iph2); return -1; } + #ifdef HAVE_SECCTX if (m_sec_ctx) { - set_secctx_in_proposal(iph2[n], spidx); + set_secctx_in_proposal(iph2, spidx); } #endif /* HAVE_SECCTX */ - insph2(iph2[n]); + insph2(iph2); /* 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) { + if (isakmp_post_acquire(iph2, NULL, TRUE) < 0) { plog(LLV_ERROR, LOCATION, NULL, "failed to begin ipsec sa negotication.\n"); - goto err; + remph2(iph2); + delph2(iph2); + return -1; } return 0; - -err: - while (n >= 0) { - unbindph12(iph2[n]); - remph2(iph2[n]); - delph2(iph2[n]); - iph2[n] = NULL; - n--; - } - return -1; } static int @@ -1942,6 +2004,7 @@ pk_recvdelete(mhp) } msg = (struct sadb_msg *)mhp[0]; sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + pk_fixup_sa_addresses(mhp); src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); @@ -1973,14 +2036,13 @@ pk_recvdelete(mhp) plog(LLV_ERROR, LOCATION, NULL, "pfkey DELETE received: %s\n", - sadbsecas2str(iph2->src, iph2->dst, + sadbsecas2str(src, 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); @@ -2014,6 +2076,7 @@ getsadbpolicy(policy0, policylen0, type, iph2) struct ph2handle *iph2; { struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + struct sockaddr *src = NULL, *dst = NULL; struct sadb_x_policy *xpl; struct sadb_x_ipsecrequest *xisr; struct saproto *pr; @@ -2032,11 +2095,19 @@ getsadbpolicy(policy0, policylen0, type, iph2) /* get policy buffer size */ policylen = sizeof(struct sadb_x_policy); if (type != SADB_X_SPDDELETE) { + if (iph2->sa_src && iph2->sa_dst) { + src = iph2->sa_src; /* MIPv6: Use SA addresses, */ + dst = iph2->sa_dst; /* not IKE ones */ + } else { + src = iph2->src; /* Common case: SA addresses */ + dst = iph2->dst; /* and IKE ones are the same */ + } + 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)); + xisrlen += (sysdep_sa_len(src) + + sysdep_sa_len(dst)); } policylen += PFKEY_ALIGN8(xisrlen); @@ -2082,7 +2153,7 @@ getsadbpolicy(policy0, policylen0, type, iph2) p->sadb_x_ctx_len = spidx->sec_ctx.ctx_strlen; p->sadb_x_ctx_doi = spidx->sec_ctx.ctx_doi; p->sadb_x_ctx_alg = spidx->sec_ctx.ctx_alg; - + memcpy(p + 1,spidx->sec_ctx.ctx_str,spidx->sec_ctx.ctx_strlen); len += ctxlen; } @@ -2121,7 +2192,7 @@ getsadbpolicy(policy0, policylen0, type, iph2) goto err; } - /* + /* * the policy level cannot be unique because the policy * is defined later than SA, so req_id cannot be bound to SA. */ @@ -2141,20 +2212,20 @@ getsadbpolicy(policy0, policylen0, type, iph2) 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); + src_len = sysdep_sa_len(src); + dst_len = sysdep_sa_len(dst); xisrlen += src_len + dst_len; - memcpy(p, iph2->src, src_len); + memcpy(p, src, src_len); p += src_len; - memcpy(p, iph2->dst, dst_len); + memcpy(p, dst, dst_len); p += dst_len; } xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen); xisr = (struct sadb_x_ipsecrequest *)p; - + } racoon_free(pr_rlist); @@ -2219,10 +2290,12 @@ pk_recvspdupdate(mhp) { struct sadb_address *saddr, *daddr; struct sadb_x_policy *xpl; - struct sadb_lifetime *lt; + struct sadb_lifetime *lt; struct policyindex spidx; struct secpolicy *sp; - u_int64_t created; + struct sockaddr *local=NULL, *remote=NULL; + u_int64_t created; + int ret; /* sanity check */ if (mhp[0] == NULL @@ -2277,15 +2350,29 @@ pk_recvspdupdate(mhp) sp = getsp(&spidx); if (sp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "such policy does not already exist: \"%s\"\n", + plog(LLV_DEBUG, LOCATION, NULL, + "this policy did not exist for removal: \"%s\"\n", spidx2str(&spidx)); } else { + /* preserve hints before deleting the SP */ + local = sp->local; + remote = sp->remote; + sp->local = NULL; + sp->remote = NULL; + remsp(sp); delsp(sp); } - if (addnewsp(mhp) < 0) + /* Add new SP (with old hints) */ + ret = addnewsp(mhp, local, remote); + + if (local != NULL) + racoon_free(local); + if (remote != NULL) + racoon_free(remote); + + if (ret < 0) return -1; return 0; @@ -2344,7 +2431,9 @@ pk_recvspdadd(mhp) struct sadb_lifetime *lt; struct policyindex spidx; struct secpolicy *sp; + struct sockaddr *local = NULL, *remote = NULL; u_int64_t created; + int ret; /* sanity check */ if (mhp[0] == NULL @@ -2403,11 +2492,26 @@ pk_recvspdadd(mhp) "such policy already exists. " "anyway replace it: %s\n", spidx2str(&spidx)); + + /* preserve hints before deleting the SP */ + local = sp->local; + remote = sp->remote; + sp->local = NULL; + sp->remote = NULL; + remsp(sp); delsp(sp); } - if (addnewsp(mhp) < 0) + /* Add new SP (with old hints) */ + ret = addnewsp(mhp, local, remote); + + if (local != NULL) + racoon_free(local); + if (remote != NULL) + racoon_free(remote); + + if (ret < 0) return -1; return 0; @@ -2628,7 +2732,9 @@ pk_recvspddump(mhp) struct sadb_lifetime *lt; struct policyindex spidx; struct secpolicy *sp; + struct sockaddr *local=NULL, *remote=NULL; u_int64_t created; + int ret; /* sanity check */ if (mhp[0] == NULL) { @@ -2637,7 +2743,6 @@ pk_recvspddump(mhp) 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]; @@ -2692,11 +2797,26 @@ pk_recvspddump(mhp) "such policy already exists. " "anyway replace it: %s\n", spidx2str(&spidx)); + + /* preserve hints before deleting the SP */ + local = sp->local; + remote = sp->remote; + sp->local = NULL; + sp->remote = NULL; + remsp(sp); delsp(sp); } - if (addnewsp(mhp) < 0) + /* Add new SP (with old hints) */ + ret = addnewsp(mhp, local, remote); + + if (local != NULL) + racoon_free(local); + if (remote != NULL) + racoon_free(remote); + + if (ret < 0) return -1; return 0; @@ -2718,10 +2838,731 @@ pk_recvspdflush(mhp) return 0; } +#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS) + +/* MIGRATE support (pk_recvmigrate() is the handler of MIGRATE message). + * + * pk_recvmigrate() + * 1) some preprocessing and checks + * 2) parsing of sadb_x_kmaddress extension + * 3) SP lookup using selectors and content of policy extension from MIGRATE + * 4) resolution of current local and remote IKE addresses + * 5) Use of addresses to get Phase 1 handler if any + * 6) Update of IKE addresses in Phase 1 (iph1->local and iph1->remote) + * 7) Update of IKE addresses in Phase 2 (iph2->src and iph2->dst) + * 8) Update of IKE addresses in SP (sp->local and sp->remote) + * 9) Loop on sadb_x_ipsecrequests pairs from MIGRATE + * - update of associated ipsecrequests entries in sp->req (should be + * only one as racoon does not support bundles), i.e. update of + * tunnel endpoints when required. + * - If tunnel mode endpoints have been updated, lookup of associated + * Phase 2 handle to also update sa_src and sa_dst entries + * + * XXX Note that we do not support yet the update of SA addresses for transport + * mode, but only the update of SA addresses for tunnel mode (endpoints). + * Reasons are: + * - there is no initial need for MIPv6 + * - racoon does not support bundles + * - this would imply more work to deal with sainfo update (if feasible). + */ + +/* Generic argument structure for migration callbacks */ +struct migrate_args { + struct sockaddr *local; + struct sockaddr *remote; +}; + +/* + * Update local and remote addresses of given Phase 1. Schedule removal + * if negotiation was going on and restart a one from updated address. + * + * -1 is returned on error. 0 if everything went right. + */ +static int +migrate_ph1_ike_addresses(iph1, arg) + struct ph1handle *iph1; + void *arg; +{ + struct migrate_args *ma = (struct migrate_args *) arg; + struct remoteconf *rmconf; + u_int16_t port; + + /* Already up-to-date? */ + if (cmpsaddr(iph1->local, ma->local) == CMPSADDR_MATCH && + cmpsaddr(iph1->remote, ma->remote) == CMPSADDR_MATCH) + return 0; + + if (iph1->status < PHASE1ST_ESTABLISHED) { + /* Bad luck! We received a MIGRATE *while* negotiating + * Phase 1 (i.e. it was not established yet). If we act as + * initiator we need to restart the negotiation. As + * responder, our best bet is to update our addresses + * and wait for the initiator to do something */ + plog(LLV_WARNING, LOCATION, NULL, "MIGRATE received *during* " + "Phase 1 negotiation (%s).\n", + saddr2str_fromto("%s => %s", ma->local, ma->remote)); + + /* If we are not acting as initiator, let's just leave and + * let the remote peer handle the restart */ + rmconf = getrmconf(ma->remote, 0); + if (rmconf == NULL || !rmconf->passive) { + iph1->status = PHASE1ST_EXPIRED; + isakmp_ph1delete(iph1); + + /* This is unlikely, but let's just check if a Phase 1 + * for the new addresses already exist */ + if (getph1byaddr(ma->local, ma->remote, 0)) { + plog(LLV_WARNING, LOCATION, NULL, "No need " + "to start a new Phase 1 negotiation. One " + "already exists.\n"); + return 0; + } + + plog(LLV_WARNING, LOCATION, NULL, "As initiator, " + "restarting it.\n"); + /* Note that the insertion of the new Phase 1 will not + * interfere with the fact we are called from enumph1, + * because it is inserted as first element. --arno */ + isakmp_ph1begin_i(rmconf, ma->local, ma->remote); + + return 0; + } + } + + if (iph1->local != NULL) { + plog(LLV_DEBUG, LOCATION, NULL, "Migrating Phase 1 local " + "address from %s\n", + saddr2str_fromto("%s to %s", iph1->local, ma->local)); + port = extract_port(iph1->local); + racoon_free(iph1->local); + } else + port = 0; + + iph1->local = dupsaddr(ma->local); + if (iph1->local == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "unable to allocate " + "Phase 1 local address.\n"); + return -1; + } + set_port(iph1->local, port); + + if (iph1->remote != NULL) { + plog(LLV_DEBUG, LOCATION, NULL, "Migrating Phase 1 remote " + "address from %s\n", + saddr2str_fromto("%s to %s", iph1->remote, ma->remote)); + port = extract_port(iph1->remote); + racoon_free(iph1->remote); + } else + port = 0; + + iph1->remote = dupsaddr(ma->remote); + if (iph1->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "unable to allocate " + "Phase 1 remote address.\n"); + return -1; + } + set_port(iph1->remote, port); + + return 0; +} + +/* Update src and dst of all current Phase 2 handles. + * with provided local and remote addresses. + * Our intent is NOT to modify IPsec SA endpoints but IKE + * addresses so we need to take care to separate those if + * they are different. -1 is returned on error. 0 if everything + * went right. + * + * Note: we do not maintain port information as it is not + * expected to be meaningful --arno + */ +static int +migrate_ph2_ike_addresses(iph2, arg) + struct ph2handle *iph2; + void *arg; +{ + struct migrate_args *ma = (struct migrate_args *) arg; + struct ph1handle *iph1; + + /* If Phase 2 has an associated Phase 1, migrate addresses */ + if (iph2->ph1) + migrate_ph1_ike_addresses(iph2->ph1, arg); + + /* Already up-to-date? */ + if (cmpsaddr(iph2->src, ma->local) == CMPSADDR_MATCH && + cmpsaddr(iph2->dst, ma->remote) == CMPSADDR_MATCH) + return 0; + + /* save src/dst as sa_src/sa_dst before rewriting */ + if (iph2->sa_src == NULL && iph2->sa_dst == NULL) { + iph2->sa_src = iph2->src; + iph2->sa_dst = iph2->dst; + iph2->src = NULL; + iph2->dst = NULL; + } + + if (iph2->src != NULL) + racoon_free(iph2->src); + iph2->src = dupsaddr(ma->local); + if (iph2->src == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to allocate Phase 2 src address.\n"); + return -1; + } + + if (iph2->dst != NULL) + racoon_free(iph2->dst); + iph2->dst = dupsaddr(ma->remote); + if (iph2->dst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to allocate Phase 2 dst address.\n"); + return -1; + } + + return 0; +} + +/* Consider existing Phase 2 handles with given spid and update their source + * and destination addresses for SA. As racoon does not support bundles, if + * we modify multiple occurrences, this probably imply rekeying has happened. + * + * Both addresses passed to the function are expected not to be NULL and of + * same family. -1 is returned on error. 0 if everything went right. + * + * Specific care is needed to support Phase 2 for which negotiation has + * already started but are which not yet established. + */ +static int +migrate_ph2_sa_addresses(iph2, args) + struct ph2handle *iph2; + void *args; +{ + struct migrate_args *ma = (struct migrate_args *) args; + + if (iph2->sa_src != NULL) { + racoon_free(iph2->sa_src); + iph2->sa_src = NULL; + } + + if (iph2->sa_dst != NULL) { + racoon_free(iph2->sa_dst); + iph2->sa_dst = NULL; + } + + iph2->sa_src = dupsaddr(ma->local); + if (iph2->sa_src == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to allocate Phase 2 sa_src address.\n"); + return -1; + } + + iph2->sa_dst = dupsaddr(ma->remote); + if (iph2->sa_dst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to allocate Phase 2 sa_dst address.\n"); + return -1; + } + + if (iph2->status < PHASE2ST_ESTABLISHED) { + struct remoteconf *rmconf; + /* We were negotiating for that SA when we received the MIGRATE. + * We cannot simply update the addresses and let the exchange + * go on. We have to restart the whole negotiation if we are + * the initiator. Otherwise (acting as responder), we just need + * to delete our ph2handle and wait for the initiator to start + * a new negotiation. */ + + if (iph2->ph1 && iph2->ph1->rmconf) + rmconf = iph2->ph1->rmconf; + else + rmconf = getrmconf(iph2->dst, 0); + + if (rmconf && !rmconf->passive) { + struct ph1handle *iph1hint; + + plog(LLV_WARNING, LOCATION, iph2->dst, "MIGRATE received " + "*during* IPsec SA negotiation. As initiator, " + "restarting it.\n"); + + /* Turn off expiration timer ...*/ + sched_cancel(&iph2->sce); + iph2->status = PHASE2ST_EXPIRED; + + /* ... clean Phase 2 handle ... */ + iph1hint = iph2->ph1; + initph2(iph2); + iph2->status = PHASE2ST_STATUS2; + + /* and start a new negotiation */ + if (isakmp_post_acquire(iph2, iph1hint, FALSE) < 0) { + plog(LLV_ERROR, LOCATION, iph2->dst, "failed " + "to begin IPsec SA renegotiation after " + "MIGRATE reception.\n"); + remph2(iph2); + delph2(iph2); + return -1; + } + } else { + plog(LLV_WARNING, LOCATION, iph2->dst, "MIGRATE received " + "*during* IPsec SA negotiation. As responder, let's" + "wait for the initiator to act.\n"); + + /* Simply schedule deletion */ + isakmp_ph2expire(iph2); + } + } + + return 0; +} + +/* Update SP hints (local and remote addresses) for future IKE + * negotiations of SA associated with that SP. -1 is returned + * on error. 0 if everything went right. + * + * Note: we do not maintain port information as it is not + * expected to be meaningful --arno + */ +static int +migrate_sp_ike_addresses(sp, local, remote) + struct secpolicy *sp; + struct sockaddr *local, *remote; +{ + if (sp == NULL || local == NULL || remote == NULL) + return -1; + + if (sp->local != NULL) + racoon_free(sp->local); + + sp->local = dupsaddr(local); + if (sp->local == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "unable to allocate " + "local hint for SP.\n"); + return -1; + } + + if (sp->remote != NULL) + racoon_free(sp->remote); + + sp->remote = dupsaddr(remote); + if (sp->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "unable to allocate " + "remote hint for SP.\n"); + return -1; + } + + return 0; +} + +/* Given current ipsecrequest (isr_cur) to be migrated in considered + tree, the function first checks that it matches the expected one + (xisr_old) provided in MIGRATE message and then updates the addresses + if it is tunnel mode (with content of xisr_new). Various other checks + are performed. For transport mode, structures are not modified, only + the checks are done. -1 is returned on error. */ +static int +migrate_ph2_one_isr(spid, isr_cur, xisr_old, xisr_new) + u_int32_t spid; + struct ipsecrequest *isr_cur; + struct sadb_x_ipsecrequest *xisr_old, *xisr_new; +{ + struct secasindex *saidx = &isr_cur->saidx; + struct sockaddr *osaddr, *odaddr, *nsaddr, *ndaddr; + struct ph2selector ph2sel; + struct migrate_args ma; + + /* First, check that mode and proto do match */ + if (xisr_old->sadb_x_ipsecrequest_proto != saidx->proto || + xisr_old->sadb_x_ipsecrequest_mode != saidx->mode || + xisr_new->sadb_x_ipsecrequest_proto != saidx->proto || + xisr_new->sadb_x_ipsecrequest_mode != saidx->mode) + return -1; + + /* Then, verify reqid if necessary */ + if (isr_cur->saidx.reqid && + (xisr_old->sadb_x_ipsecrequest_reqid != IPSEC_LEVEL_UNIQUE || + xisr_new->sadb_x_ipsecrequest_reqid != IPSEC_LEVEL_UNIQUE || + isr_cur->saidx.reqid != xisr_old->sadb_x_ipsecrequest_reqid || + isr_cur->saidx.reqid != xisr_new->sadb_x_ipsecrequest_reqid)) + return -1; + + /* If not tunnel mode, our work is over */ + if (saidx->mode != IPSEC_MODE_TUNNEL) { + plog(LLV_DEBUG, LOCATION, NULL, "SADB_X_MIGRATE: " + "non tunnel mode isr, skipping SA address migration.\n"); + return 0; + } + + /* Tunnel mode: let's check addresses do match and then update them. */ + osaddr = (struct sockaddr *)(xisr_old + 1); + odaddr = (struct sockaddr *)(((u_int8_t *)osaddr) + sysdep_sa_len(osaddr)); + nsaddr = (struct sockaddr *)(xisr_new + 1); + ndaddr = (struct sockaddr *)(((u_int8_t *)nsaddr) + sysdep_sa_len(nsaddr)); + + /* Check family does match */ + if (osaddr->sa_family != odaddr->sa_family || + nsaddr->sa_family != ndaddr->sa_family) + return -1; + + /* Check family does match */ + if (saidx->src.ss_family != osaddr->sa_family) + return -1; + + /* We log IPv4 to IPv6 and IPv6 to IPv4 switches */ + if (nsaddr->sa_family != osaddr->sa_family) + plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: " + "changing address families (%d to %d) for endpoints.\n", + osaddr->sa_family, nsaddr->sa_family); + + if (cmpsaddr(osaddr, (struct sockaddr *) &saidx->src) != CMPSADDR_MATCH || + cmpsaddr(odaddr, (struct sockaddr *) &saidx->dst) != CMPSADDR_MATCH) { + plog(LLV_DEBUG, LOCATION, NULL, "SADB_X_MIGRATE: " + "mismatch of addresses in saidx and xisr.\n"); + return -1; + } + + /* Excellent. Let's grab associated Phase 2 handle (if any) + * and update its sa_src and sa_dst entries. Note that we + * make the assumption that racoon does not support bundles + * and make the lookup using spid: we blindly update + * sa_src and sa_dst for _all_ found Phase 2 handles */ + memset(&ph2sel, 0, sizeof(ph2sel)); + ph2sel.spid = spid; + + memset(&ma, 0, sizeof(ma)); + ma.local = nsaddr; + ma.remote = ndaddr; + + if (enumph2(&ph2sel, migrate_ph2_sa_addresses, &ma) < 0) + return -1; + + /* Now we can do the update of endpoints in secasindex */ + memcpy(&saidx->src, nsaddr, sysdep_sa_len(nsaddr)); + memcpy(&saidx->dst, ndaddr, sysdep_sa_len(ndaddr)); + + return 0; +} + +/* Process the raw (unparsed yet) list of sadb_x_ipsecrequests of MIGRATE + * message. For each sadb_x_ipsecrequest pair (old followed by new), + * the corresponding ipsecrequest entry in the SP is updated. Associated + * existing Phase 2 handle is also updated (if any) */ +static int +migrate_sp_isr_list(sp, xisr_list, xisr_list_len) + struct secpolicy *sp; + struct sadb_x_ipsecrequest *xisr_list; + int xisr_list_len; +{ + struct sadb_x_ipsecrequest *xisr_new, *xisr_old = xisr_list; + int xisr_old_len, xisr_new_len; + struct ipsecrequest *isr_cur; + + isr_cur = sp->req; /* ipsecrequest list from from sp */ + + while (xisr_list_len > 0 && isr_cur != NULL) { + /* Get old xisr (length field is in bytes) */ + xisr_old_len = xisr_old->sadb_x_ipsecrequest_len; + if (xisr_old_len < sizeof(*xisr_old) || + xisr_old_len + sizeof(*xisr_new) > xisr_list_len) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "invalid ipsecrequest length. Exiting.\n"); + return -1; + } + + /* Get new xisr with updated info */ + xisr_new = (struct sadb_x_ipsecrequest *)(((u_int8_t *)xisr_old) + xisr_old_len); + xisr_new_len = xisr_new->sadb_x_ipsecrequest_len; + if (xisr_new_len < sizeof(*xisr_new) || + xisr_new_len + xisr_old_len > xisr_list_len) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "invalid ipsecrequest length. Exiting.\n"); + return -1; + } + + /* Start by migrating current ipsecrequest from SP */ + if (migrate_ph2_one_isr(sp->id, isr_cur, xisr_old, xisr_new) == -1) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "Unable to match and migrate isr. Exiting.\n"); + return -1; + } + + /* Update pointers for next round */ + xisr_list_len -= xisr_old_len + xisr_new_len; + xisr_old = (struct sadb_x_ipsecrequest *)(((u_int8_t *)xisr_new) + + xisr_new_len); + + isr_cur = isr_cur->next; /* Get next ipsecrequest from SP */ + } + + /* Check we had the same amount of pairs in the MIGRATE + as the number of ipsecrequests in the SP */ + if ((xisr_list_len != 0) || isr_cur != NULL) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "number of ipsecrequest does not match the one in SP.\n"); + return -1; + } + + return 0; +} + +/* Parse sadb_x_kmaddress extension and make local and remote + * parameters point to the new addresses (zero copy). -1 is + * returned on error, meaning that addresses are not usable */ +static int +parse_kmaddress(kmaddr, local, remote) + struct sadb_x_kmaddress *kmaddr; + struct sockaddr **local, **remote; +{ + int addrslen, local_len=0; + struct ph1handle *iph1; + + if (kmaddr == NULL) + return -1; + + /* Grab addresses in sadb_x_kmaddress extension */ + addrslen = PFKEY_EXTLEN(kmaddr) - sizeof(*kmaddr); + if (addrslen < sizeof(struct sockaddr)) + return -1; + + *local = (struct sockaddr *)(kmaddr + 1); + + switch ((*local)->sa_family) { + case AF_INET: + local_len = sizeof(struct sockaddr_in); + break; +#ifdef INET6 + case AF_INET6: + local_len = sizeof(struct sockaddr_in6); + break; +#endif + default: + return -1; + } + + if (addrslen != PFKEY_ALIGN8(2*local_len)) + return -1; + + *remote = (struct sockaddr *)(((u_int8_t *)(*local)) + local_len); + + if ((*local)->sa_family != (*remote)->sa_family) + return -1; + + return 0; +} + +/* Handler of PF_KEY MIGRATE message. Helpers are above */ +static int +pk_recvmigrate(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sockaddr *old_saddr, *new_saddr; + struct sockaddr *old_daddr, *new_daddr; + struct sockaddr *old_local, *old_remote; + struct sockaddr *local, *remote; + struct sadb_x_kmaddress *kmaddr; + struct sadb_x_policy *xpl; + struct sadb_x_ipsecrequest *xisr_list; + struct sadb_lifetime *lt; + struct policyindex spidx; + struct secpolicy *sp; + struct ipsecrequest *isr_cur; + struct secasindex *oldsaidx; + struct ph2handle *iph2; + struct ph1handle *iph1; + struct ph2selector ph2sel; + struct ph1selector ph1sel; + u_int32_t spid; + u_int64_t created; + int xisr_list_len; + int ulproto; + struct migrate_args ma; + + /* Some sanity checks */ + + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_KMADDRESS] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "SADB_X_MIGRATE: invalid MIGRATE message received.\n"); + return -1; + } + kmaddr = (struct sadb_x_kmaddress *)mhp[SADB_X_EXT_KMADDRESS]; + 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]; + lt = (struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD]; + if (lt != NULL) + created = lt->sadb_lifetime_addtime; + else + created = 0; + + if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + plog(LLV_WARNING, LOCATION, NULL,"SADB_X_MIGRATE: " + "found non IPsec policy in MIGRATE message. Exiting.\n"); + return -1; + } + + if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "invalid size for sadb_x_policy. Exiting.\n"); + return -1; + } + + /* Some logging to help debbugging */ + if (xpl->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND) + plog(LLV_DEBUG, LOCATION, NULL, + "SADB_X_MIGRATE: Outbound SA being migrated.\n"); + else + plog(LLV_DEBUG, LOCATION, NULL, + "SADB_X_MIGRATE: Inbound SA being migrated.\n"); + + /* validity check */ + xisr_list = (struct sadb_x_ipsecrequest *)(xpl + 1); + xisr_list_len = PFKEY_EXTLEN(xpl) - sizeof(*xpl); + if (xisr_list_len < sizeof(*xisr_list)) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "invalid sadb_x_policy message length. Exiting.\n"); + return -1; + } + + if (parse_kmaddress(kmaddr, &local, &remote) == -1) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: " + "invalid sadb_x_kmaddress extension. Exiting.\n"); + return -1; + } + + /* 0 means ANY */ + if (saddr->sadb_address_proto == 0) + ulproto = IPSEC_ULPROTO_ANY; + else + ulproto = saddr->sadb_address_proto; + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + ulproto, + xpl->sadb_x_policy_priority, + created, + &spidx); +#else + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + ulproto, + created, + &spidx); +#endif + + /* Everything seems ok, let's get the SP. + * + * XXX We could also do the lookup using the spid from xpl. + * I don't know which one is better. --arno */ + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "SADB_X_MIGRATE: Passed policy does not exist: %s\n", + spidx2str(&spidx)); + return -1; + } + + /* Get the best source and destination addresses used for IKE + * negotiation, to find and migrate existing Phase 1 */ + if (sp->local && sp->remote) { + /* hints available, let's use them */ + old_local = (struct sockaddr *)sp->local; + old_remote = (struct sockaddr *)sp->remote; + } else if (sp->req && sp->req->saidx.mode == IPSEC_MODE_TUNNEL) { + /* Tunnel mode and no hint, use endpoints */ + old_local = (struct sockaddr *)&sp->req->saidx.src; + old_remote = (struct sockaddr *)&sp->req->saidx.dst; + } else { + /* default, use selectors as fallback */ + old_local = (struct sockaddr *)&sp->spidx.src; + old_remote = (struct sockaddr *)&sp->spidx.dst; + } + + /* We migrate all Phase 1 that match our old local and remote + * addresses (no matter their state). + * + * XXX In fact, we should probably havea special treatment for + * Phase 1 that are being established when we receive a MIGRATE. + * This can happen if a movement occurs during the initial IKE + * negotiation. In that case, I wonder if should restart the + * negotiation from the new address or just update things like + * we do it now. + * + * XXX while looking at getph1byaddr(), the comment at the + * beginning of the function expects comparison to happen + * without ports considerations but it uses CMPSADDR() which + * relies either on cmpsaddrstrict() or cmpsaddrwop() based + * on NAT-T support being activated. That make me wonder if I + * should force ports to 0 (ANY) in local and remote values + * used below. + * + * -- arno */ + + /* Apply callback data ...*/ + memset(&ma, 0, sizeof(ma)); + ma.local = local; + ma.remote = remote; + + /* Fill phase1 match criteria ... */ + memset(&ph1sel, 0, sizeof(ph1sel)); + ph1sel.local = old_local; + ph1sel.remote = old_remote; + + + /* Have matching Phase 1 found and addresses updated. As this is a + * time consuming task on a busy responder, and MIGRATE messages + * are always sent for *both* inbound and outbound (and possibly + * forward), we only do that for outbound SP. */ + if (xpl->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND && + enumph1(&ph1sel, migrate_ph1_ike_addresses, &ma) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: Unable " + "to migrate Phase 1 addresses.\n"); + return -1; + } + + /* We can now update IKE addresses in Phase 2 handle. */ + memset(&ph2sel, 0, sizeof(ph2sel)); + ph2sel.spid = sp->id; + if (enumph2(&ph2sel, migrate_ph2_ike_addresses, &ma) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: Unable " + "to migrate Phase 2 IKE addresses.\n"); + return -1; + } + + /* and _then_ in SP. */ + if (migrate_sp_ike_addresses(sp, local, remote) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "SADB_X_MIGRATE: Unable to migrate SP IKE addresses.\n"); + return -1; + } + + /* Loop on sadb_x_ipsecrequest list to possibly update sp->req + * entries and associated live Phase 2 handles (their sa_src + * and sa_dst) */ + if (migrate_sp_isr_list(sp, xisr_list, xisr_list_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "SADB_X_MIGRATE: Unable to migrate isr list.\n"); + return -1; + } + + return 0; +} +#endif + #ifndef ANDROID_PATCHED /* - * send error against acquire message to kenrel. + * send error against acquire message to kernel. */ int pk_sendeacquire(iph2) @@ -2759,8 +3600,8 @@ pk_sendeacquire(iph2) #else int pk_sendeacquire(struct ph2handle *iph2) -{ - exit(1); +{ + exit(1); } #endif @@ -2787,8 +3628,8 @@ pk_checkalg(class, calg, keylen) break; case IPSECDOI_PROTO_IPCOMP: plog(LLV_DEBUG, LOCATION, NULL, - "compression algorithm can not be checked " - "because sadb message doesn't support it.\n"); + "no check of compression algorithm; " + "not supported in sadb message.\n"); return 0; default: plog(LLV_ERROR, LOCATION, NULL, @@ -2848,6 +3689,11 @@ pk_recv(so, lenp) return NULL; reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if (reallen < sizeof(buf)) { + *lenp = -1; + errno = EIO; + return NULL; /*fatal*/ + } if ((newmsg = racoon_calloc(1, reallen)) == NULL) return NULL; @@ -2880,8 +3726,9 @@ pk_getseq() } static int -addnewsp(mhp) +addnewsp(mhp, local, remote) caddr_t *mhp; + struct sockaddr *local, *remote; { struct secpolicy *new = NULL; struct sadb_address *saddr, *daddr; @@ -3090,6 +3937,12 @@ addnewsp(mhp) } #endif /* HAVE_SECCTX */ + /* Set local and remote hints for that SP, if available */ + if (local && remote) { + new->local = dupsaddr(local); + new->remote = dupsaddr(remote); + } + inssp(new); return 0; diff --git a/src/racoon/pfkey.h b/src/racoon/pfkey.h index 547f94a..cfe111d 100644 --- a/src/racoon/pfkey.h +++ b/src/racoon/pfkey.h @@ -1,4 +1,4 @@ -/* $NetBSD: pfkey.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: pfkey.h,v 1.8 2009/07/03 06:40:10 tteras Exp $ */ /* Id: pfkey.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp */ @@ -42,16 +42,17 @@ struct pfkey_satype { 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 int pfkey_reload __P((void)); extern struct pfkey_st *pfkey_getpst __P((caddr_t *, int, int)); extern int pk_checkalg __P((int, int, int)); struct ph2handle; +extern void pk_fixup_sa_addresses __P((caddr_t *mhp)); extern int pk_sendgetspi __P((struct ph2handle *)); extern int pk_sendupdate __P((struct ph2handle *)); extern int pk_sendadd __P((struct ph2handle *)); @@ -60,9 +61,6 @@ 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)); diff --git a/src/racoon/plainrsa-gen.c b/src/racoon/plainrsa-gen.c index 1bd5f67..cad1861 100644 --- a/src/racoon/plainrsa-gen.c +++ b/src/racoon/plainrsa-gen.c @@ -1,4 +1,4 @@ -/* $NetBSD: plainrsa-gen.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: plainrsa-gen.c,v 1.6 2011/02/11 10:07:19 tteras Exp $ */ /* Id: plainrsa-gen.c,v 1.6 2005/04/21 09:08:40 monas Exp */ /* @@ -43,11 +43,13 @@ #include <sys/stat.h> #include <sys/socket.h> #include <unistd.h> +#include <fcntl.h> #include <openssl/bio.h> #include <openssl/bn.h> #include <openssl/err.h> #include <openssl/objects.h> +#include <openssl/pem.h> #include <openssl/rsa.h> #include <openssl/evp.h> #ifdef HAVE_OPENSSL_ENGINE_H @@ -72,6 +74,7 @@ usage (char *argv0) fprintf(stderr, " -b bits Generate <bits> long RSA key (default=1024)\n"); fprintf(stderr, " -e pubexp Public exponent to use (default=0x3)\n"); fprintf(stderr, " -f filename Filename to store the key to (default=stdout)\n"); + fprintf(stderr, " -i filename Input source for format conversion\n"); fprintf(stderr, " -h Help\n"); fprintf(stderr, "\n"); fprintf(stderr, "Report bugs to <ipsec-tools-devel@lists.sourceforge.net>\n"); @@ -82,7 +85,7 @@ usage (char *argv0) * See RFC 2065, section 3.5 for details about the output format. */ vchar_t * -mix_b64_pubkey(RSA *key) +mix_b64_pubkey(const RSA *key) { char *binbuf; long binlen, ret; @@ -116,17 +119,10 @@ lowercase(char *input) } int -gen_rsa_key(FILE *fp, size_t bits, unsigned long exp) +print_rsa_key(FILE *fp, const RSA *key) { - 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()); @@ -135,7 +131,7 @@ gen_rsa_key(FILE *fp, size_t bits, unsigned long exp) fprintf(fp, "# : PUB 0s%s\n", pubkey64->v); fprintf(fp, ": RSA\t{\n"); - fprintf(fp, "\t# RSA %zu bits\n", bits); + fprintf(fp, "\t# RSA %d bits\n", BN_num_bits(key->n)); 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))); @@ -148,23 +144,92 @@ gen_rsa_key(FILE *fp, size_t bits, unsigned long exp) fprintf(fp, " }\n"); vfree(pubkey64); + return 0; +} + +int +print_public_rsa_key(FILE *fp, const RSA *key) +{ + vchar_t *pubkey64 = NULL; + 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); + + vfree(pubkey64); return 0; } int +convert_rsa_key(FILE *fpout, FILE *fpin) +{ + int ret; + RSA *key = NULL; + + key = PEM_read_RSAPrivateKey(fpin, NULL, NULL, NULL); + if (key) { + ret = print_rsa_key(fpout, key); + RSA_free(key); + + return ret; + } + + rewind(fpin); + + key = PEM_read_RSA_PUBKEY(fpin, NULL, NULL, NULL); + if (key) { + ret = print_public_rsa_key(fpout, key); + RSA_free(key); + + return ret; + } + + /* Implement parsing of input stream containing + * private or public "plainrsa" formatted text. + * Convert the result to PEM formatted output. + * + * This seemingly needs manual use of prsaparse(). + * An expert ought to do this. */ + + fprintf(stderr, "convert_rsa_key: %s\n", "Only conversion from PEM at this time"); + return -1; +} + +int +gen_rsa_key(FILE *fp, size_t bits, unsigned long exp) +{ + int ret; + RSA *key; + + key = RSA_generate_key(bits, exp, NULL, NULL); + if (!key) { + fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror()); + return -1; + } + + ret = print_rsa_key(fp, key); + RSA_free(key); + + return ret; +} + +int main (int argc, char *argv[]) { - FILE *fp = stdout; + FILE *fp = stdout, *fpin = NULL; size_t bits = 1024; unsigned int pubexp = 0x3; struct stat st; extern char *optarg; extern int optind; - int c; - char *fname = NULL; + int c, fd = -1, fdin = -1; + char *fname = NULL, *finput = NULL; - while ((c = getopt(argc, argv, "e:b:f:h")) != -1) + while ((c = getopt(argc, argv, "e:b:f:i:h")) != -1) switch (c) { case 'e': if (strncmp(optarg, "0x", 2) == 0) @@ -178,31 +243,65 @@ main (int argc, char *argv[]) case 'f': fname = optarg; break; + case 'i': + finput = 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); + umask(0077); + /* Restrictive access due to private key material. */ + fd = open(fname, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); + if (fd < 0) { + if (errno == EEXIST) + fprintf(stderr, "%s: file exists! Please use a different name.\n", fname); + else + fprintf(stderr, "%s: %s\n", fname, strerror(errno)); exit(1); } - - umask(0077); - fp = fopen(fname, "w"); + fp = fdopen(fd, "w"); if (fp == NULL) { fprintf(stderr, "%s: %s\n", fname, strerror(errno)); + close(fd); exit(1); } } + if (finput) { + /* Restrictive access once more. Do not be fooled by a link. */ + fdin = open(finput, O_RDONLY | O_NOFOLLOW); + if (fdin < 0) { + if (errno == ELOOP) + fprintf(stderr, "%s: file is a link. Discarded for security.\n", fname); + if (fp) + fclose(fp); + exit(1); + } + fpin = fdopen(fdin, "r"); + if (fpin == NULL) { + fprintf(stderr, "%s: %s\n", fname, strerror(errno)); + close(fdin); + if (fp) + fclose(fp); + exit(1); + } + + } + ploginit(); eay_init(); - gen_rsa_key(fp, bits, pubexp); + if (fpin) + convert_rsa_key(fp, fpin); + else + gen_rsa_key(fp, bits, pubexp); fclose(fp); + if (fpin) + fclose(fpin); return 0; } diff --git a/src/racoon/plog.c b/src/racoon/plog.c index 008260d..aebfed2 100644 --- a/src/racoon/plog.c +++ b/src/racoon/plog.c @@ -1,4 +1,4 @@ -/* $NetBSD: plog.c,v 1.4.6.2 2009/04/20 13:35:36 tteras Exp $ */ +/* $NetBSD: plog.c,v 1.7 2011/01/28 12:51:40 tteras Exp $ */ /* Id: plog.c,v 1.11 2006/06/20 09:57:31 vanhu Exp */ @@ -36,6 +36,7 @@ #include <sys/types.h> #include <sys/param.h> +#include <arpa/inet.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -78,7 +79,7 @@ int print_location = 0; static struct log *logp = NULL; static char *logfile = NULL; -static char *plog_common __P((int, const char *, const char *)); +static char *plog_common __P((int, const char *, const char *, struct sockaddr *)); static struct plogtags { char *name; @@ -94,11 +95,13 @@ static struct plogtags { }; static char * -plog_common(pri, fmt, func) +plog_common(pri, fmt, func, sa) int pri; const char *fmt, *func; + struct sockaddr *sa; { static char buf[800]; /* XXX shoule be allocated every time ? */ + void *addr; char *p; int reslen, len; @@ -116,19 +119,43 @@ plog_common(pri, fmt, func) reslen -= len; } + if (sa && reslen > 3) { + addr = NULL; + switch (sa->sa_family) { + case AF_INET: + addr = &((struct sockaddr_in*)sa)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6*)sa)->sin6_addr; + break; + } + if (inet_ntop(sa->sa_family, addr, p + 1, reslen - 3) != NULL) { + *p++ = '['; + len = strlen(p); + p += len; + *p++ = ']'; + *p++ = ' '; + reslen -= len + 3; + } + } + if (pri < ARRAYLEN(ptab)) { len = snprintf(p, reslen, "%s: ", ptab[pri].name); - if (len >= 0 && len < reslen) { - p += len; - reslen -= len; - } else - *p = '\0'; + p += len; + reslen -= len; } if (print_location) - snprintf(p, reslen, "%s: %s", func, fmt); + len = snprintf(p, reslen, "%s: %s", func, fmt); else - snprintf(p, reslen, "%s", fmt); + len = snprintf(p, reslen, "%s", fmt); + p += len; + reslen -= len; + + /* Force nul termination */ + if (reslen == 0) + p[-1] = 0; + #ifdef BROKEN_PRINTF while ((p = strstr(buf,"%z")) != NULL) p[1] = 'l'; @@ -157,7 +184,7 @@ plogv(int pri, const char *func, struct sockaddr *sa, if (pri > loglevel) return; - newfmt = plog_common(pri, fmt, func); + newfmt = plog_common(pri, fmt, func, sa); VA_COPY(ap_bak, ap); diff --git a/src/racoon/plog.h b/src/racoon/plog.h index 4d9a93f..6c3ac12 100644 --- a/src/racoon/plog.h +++ b/src/racoon/plog.h @@ -1,4 +1,4 @@ -/* $NetBSD: plog.h,v 1.4.6.1 2007/11/06 16:41:27 vanhu Exp $ */ +/* $NetBSD: plog.h,v 1.5 2007/10/02 09:47:40 vanhu Exp $ */ /* Id: plog.h,v 1.7 2006/06/20 09:57:31 vanhu Exp */ diff --git a/src/racoon/policy.c b/src/racoon/policy.c index 29a6818..4c00677 100644 --- a/src/racoon/policy.c +++ b/src/racoon/policy.c @@ -1,4 +1,4 @@ -/* $NetBSD: policy.c,v 1.6.4.1 2007/08/01 11:52:21 vanhu Exp $ */ +/* $NetBSD: policy.c,v 1.12 2011/03/14 17:18:13 tteras Exp $ */ /* $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */ @@ -91,13 +91,17 @@ getsp_r(spidx) struct policyindex *spidx; { struct secpolicy *p; + struct secpolicy *found = NULL; for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { - if (!cmpspidxwild(spidx, &p->spidx)) + if (!cmpspidxstrict(spidx, &p->spidx)) return p; + + if (!found && !cmpspidxwild(spidx, &p->spidx)) + found = p; } - return NULL; + return found; } #else struct secpolicy * @@ -137,16 +141,18 @@ getsp_r(spidx, iph2) 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) + + if (cmpsaddr(iph2->src, (struct sockaddr *) &spidx->src) != CMPSADDR_MATCH || + 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) + + if (cmpsaddr(iph2->dst, (struct sockaddr *) &spidx->dst) != CMPSADDR_MATCH || + spidx->prefd != prefixlen) return NULL; plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n"); @@ -194,11 +200,11 @@ cmpspidxstrict(a, b) || a->ul_proto != b->ul_proto) return 1; - if (cmpsaddrstrict((struct sockaddr *)&a->src, - (struct sockaddr *)&b->src)) + if (cmpsaddr((struct sockaddr *) &a->src, + (struct sockaddr *) &b->src) != CMPSADDR_MATCH) return 1; - if (cmpsaddrstrict((struct sockaddr *)&a->dst, - (struct sockaddr *)&b->dst)) + if (cmpsaddr((struct sockaddr *) &a->dst, + (struct sockaddr *) &b->dst) != CMPSADDR_MATCH) return 1; #ifdef HAVE_SECCTX @@ -228,8 +234,7 @@ cmpspidxwild(a, 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 || + if (!(b->ul_proto == IPSEC_ULPROTO_ANY || a->ul_proto == b->ul_proto)) return 1; @@ -256,7 +261,7 @@ cmpspidxwild(a, b) 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)) + if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH) return 1; #ifndef __linux__ @@ -274,7 +279,7 @@ cmpspidxwild(a, b) 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)) + if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH) return 1; #ifdef HAVE_SECCTX @@ -309,6 +314,11 @@ delsp(sp) racoon_free(req); } + if (sp->local) + racoon_free(sp->local); + if (sp->remote) + racoon_free(sp->remote); + racoon_free(sp); } diff --git a/src/racoon/policy.h b/src/racoon/policy.h index 8c47451..ef7f923 100644 --- a/src/racoon/policy.h +++ b/src/racoon/policy.h @@ -1,4 +1,4 @@ -/* $NetBSD: policy.h,v 1.5.4.2 2007/06/07 20:34:19 manu Exp $ */ +/* $NetBSD: policy.h,v 1.8 2008/12/05 06:02:20 tteras Exp $ */ /* Id: policy.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp */ @@ -82,6 +82,12 @@ struct secpolicy { struct ipsecrequest *req; /* pointer to the ipsec request tree, */ /* if policy == IPSEC else this value == NULL.*/ + + /* MIPv6 needs to perform negotiation of SA using different addresses + * than the endpoints of the SA (CoA for the source). In that case, + * MIGRATE msg provides that info (before movement occurs on the MN) */ + struct sockaddr *local; + struct sockaddr *remote; }; /* Security Assocciation Index */ @@ -111,7 +117,7 @@ struct ipsecrequest { #ifdef HAVE_PFKEY_POLICY_PRIORITY #define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _priority, _created, idx) \ do { \ - memset((idx), 0, sizeof(struct policyindex)); \ + bzero((idx), sizeof(struct policyindex)); \ (idx)->dir = (_dir); \ (idx)->prefs = (ps); \ (idx)->prefd = (pd); \ @@ -124,7 +130,7 @@ do { \ #else #define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _created, idx) \ do { \ - memset((idx), 0, sizeof(struct policyindex)); \ + bzero((idx), sizeof(struct policyindex)); \ (idx)->dir = (_dir); \ (idx)->prefs = (ps); \ (idx)->prefd = (pd); \ diff --git a/src/racoon/privsep.c b/src/racoon/privsep.c index 9e60b89..55a3908 100644 --- a/src/racoon/privsep.c +++ b/src/racoon/privsep.c @@ -1,4 +1,4 @@ -/* $NetBSD: privsep.c,v 1.6 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: privsep.c,v 1.21 2011/03/06 08:28:10 tteras Exp $ */ /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */ @@ -42,15 +42,17 @@ #include <signal.h> #include <pwd.h> +#include <sys/types.h> #include <sys/socket.h> #include <sys/param.h> +#include <netinet/in.h> + #include "gcmalloc.h" #include "vmbuf.h" #include "misc.h" #include "plog.h" #include "var.h" -#include "libpfkey.h" #include "crypto_openssl.h" #include "isakmp_var.h" @@ -75,6 +77,28 @@ static int port_check(int); static int unsafe_env(char *const *); static int unknown_name(int); static int unsafe_path(char *, int); +static int rec_fd(int); +static int send_fd(int, int); + +struct socket_args { + int domain; + int type; + int protocol; +}; + +struct sockopt_args { + int s; + int level; + int optname; + const void *optval; + socklen_t optlen; +}; + +struct bind_args { + int s; + const struct sockaddr *addr; + socklen_t addrlen; +}; static int privsep_send(sock, buf, len) @@ -116,13 +140,19 @@ privsep_recv(sock, bufp, lenp) sizeof(com), MSG_PEEK, NULL, NULL)) == -1) { if (errno == EINTR) continue; + if (errno == ECONNRESET) + return -1; plog(LLV_ERROR, LOCATION, NULL, "privsep_recv failed: %s\n", strerror(errno)); return -1; } - + + /* EOF, other side has closed. */ + if (len == 0) + return -1; + /* Check for short packets */ if (len < sizeof(com)) { plog(LLV_ERROR, LOCATION, NULL, @@ -142,6 +172,8 @@ privsep_recv(sock, bufp, lenp) com.ac_len, 0, NULL, NULL)) == -1) { if (errno == EINTR) continue; + if (errno == ECONNRESET) + return -1; plog(LLV_ERROR, LOCATION, NULL, "failed to recv privsep command: %s\n", strerror(errno)); @@ -174,7 +206,7 @@ privsep_init(void) /* * When running privsep, certificate and script paths * are mandatory, as they enable us to check path safety - * in the privilegied instance + * in the privileged instance */ if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) || (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) { @@ -183,7 +215,7 @@ privsep_init(void) return -1; } - if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) { + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) { plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate privsep_sock: %s\n", strerror(errno)); return -1; @@ -197,6 +229,8 @@ privsep_init(void) break; case 0: /* Child: drop privileges */ + (void)close(privsep_sock[0]); + if (lcconf->chroot != NULL) { if (chdir(lcconf->chroot) != 0) { plog(LLV_ERROR, LOCATION, NULL, @@ -243,7 +277,7 @@ privsep_init(void) return 0; break; - default: /* Parent: privilegied process */ + default: /* Parent: privileged process */ break; } @@ -254,8 +288,6 @@ privsep_init(void) 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); @@ -265,16 +297,20 @@ privsep_init(void) ploginit(); plog(LLV_INFO, LOCATION, NULL, - "racoon privilegied process running with PID %d\n", getpid()); + "racoon privileged process running with PID %d\n", getpid()); -#ifdef __NetBSD__ + plog(LLV_INFO, LOCATION, NULL, + "racoon unprivileged process running with PID %d\n", child_pid); + +#if defined(__NetBSD__) || defined(__FreeBSD__) setproctitle("[priv]"); #endif - /* - * Don't catch any signal + /* + * Don't catch any signal * This duplicate session:signals[], which is static... */ + signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); @@ -331,7 +367,7 @@ privsep_init(void) /* * XXX Improvement: instead of returning the key, * stuff eay_get_pkcs1privkey and eay_get_x509sign - * together and sign the hash in the privilegied + * together and sign the hash in the privileged * instance? * pro: the key remains inaccessible to unpriv * con: a compromised unpriv racoon can still sign anything @@ -503,6 +539,154 @@ privsep_init(void) break; } + case PRIVSEP_SOCKET: { + struct socket_args socket_args; + int s; + + /* Make sure the string is NULL terminated */ + if (safety_check(combuf, 0) != 0) + break; + + if (combuf->bufs.buflen[0] != + sizeof(struct socket_args)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_socket: corrupted message\n"); + goto out; + } + memcpy(&socket_args, bufs[0], + sizeof(struct socket_args)); + + if (socket_args.domain != PF_INET && + socket_args.domain != PF_INET6) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_socket: " + "unauthorized domain (%d)\n", + socket_args.domain); + goto out; + } + + if ((s = socket(socket_args.domain, socket_args.type, + socket_args.protocol)) == -1) { + reply->hdr.ac_errno = errno; + break; + } + + if (send_fd(privsep_sock[0], s) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_socket: send_fd failed\n"); + close(s); + goto out; + } + + close(s); + break; + } + + case PRIVSEP_BIND: { + struct bind_args bind_args; + int err, port = 0; + + /* Make sure the string is NULL terminated */ + if (safety_check(combuf, 0) != 0) + break; + + if (combuf->bufs.buflen[0] != + sizeof(struct bind_args)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_bind: corrupted message\n"); + goto out; + } + memcpy(&bind_args, bufs[0], sizeof(struct bind_args)); + + if (combuf->bufs.buflen[1] != bind_args.addrlen) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_bind: corrupted message\n"); + goto out; + } + bind_args.addr = (const struct sockaddr *)bufs[1]; + + if ((bind_args.s = rec_fd(privsep_sock[0])) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_bind: rec_fd failed\n"); + goto out; + } + + port = extract_port(bind_args.addr); + if (port != PORT_ISAKMP && port != PORT_ISAKMP_NATT && + port != lcconf->port_isakmp && + port != lcconf->port_isakmp_natt) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_bind: " + "unauthorized port (%d)\n", + port); + close(bind_args.s); + goto out; + } + + err = bind(bind_args.s, bind_args.addr, + bind_args.addrlen); + + if (err) + reply->hdr.ac_errno = errno; + + close(bind_args.s); + break; + } + + case PRIVSEP_SETSOCKOPTS: { + struct sockopt_args sockopt_args; + int err; + + /* Make sure the string is NULL terminated */ + if (safety_check(combuf, 0) != 0) + break; + + if (combuf->bufs.buflen[0] != + sizeof(struct sockopt_args)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_setsockopt: " + "corrupted message\n"); + goto out; + } + memcpy(&sockopt_args, bufs[0], + sizeof(struct sockopt_args)); + + if (combuf->bufs.buflen[1] != sockopt_args.optlen) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_setsockopt: corrupted message\n"); + goto out; + } + sockopt_args.optval = bufs[1]; + + if (sockopt_args.optname != + (sockopt_args.level == + IPPROTO_IP ? IP_IPSEC_POLICY : + IPV6_IPSEC_POLICY)) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_setsockopt: " + "unauthorized option (%d)\n", + sockopt_args.optname); + goto out; + } + + if ((sockopt_args.s = rec_fd(privsep_sock[0])) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_setsockopt: rec_fd failed\n"); + goto out; + } + + err = setsockopt(sockopt_args.s, + sockopt_args.level, + sockopt_args.optname, + sockopt_args.optval, + sockopt_args.optlen); + if (err) + reply->hdr.ac_errno = errno; + + close(sockopt_args.s); + break; + } + #ifdef ENABLE_HYBRID case PRIVSEP_ACCOUNTING_SYSTEM: { int pool_size; @@ -687,14 +871,17 @@ privsep_init(void) /* This frees reply */ if (privsep_send(privsep_sock[0], - reply, reply->hdr.ac_len) != 0) + reply, reply->hdr.ac_len) != 0) { + racoon_free(reply); goto out; + } racoon_free(combuf); } out: - plog(LLV_INFO, LOCATION, NULL, "privsep exit\n"); + plog(LLV_INFO, LOCATION, NULL, + "racoon privileged process %d terminated\n", getpid()); _exit(0); } @@ -745,37 +932,6 @@ out: 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) char *script; @@ -941,6 +1097,224 @@ out: return NULL; } +/* + * Create a privileged socket. On BSD systems a socket obtains special + * capabilities if it is created by root; setsockopt(IP_IPSEC_POLICY) will + * succeed but will be ineffective if performed on an unprivileged socket. + */ +int +privsep_socket(domain, type, protocol) + int domain; + int type; + int protocol; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + struct socket_args socket_args; + int s, saved_errno = 0; + + if (geteuid() == 0) + return socket(domain, type, protocol); + + len = sizeof(*msg) + sizeof(socket_args); + + 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_SOCKET; + msg->hdr.ac_len = len; + + socket_args.domain = domain; + socket_args.type = type; + socket_args.protocol = protocol; + + data = (char *)(msg + 1); + msg->bufs.buflen[0] = sizeof(socket_args); + memcpy(data, &socket_args, msg->bufs.buflen[0]); + + /* frees msg */ + if (privsep_send(privsep_sock[1], msg, len) != 0) + goto out; + + /* Get the privileged socket descriptor from the privileged process. */ + if ((s = rec_fd(privsep_sock[1])) == -1) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + goto out; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + racoon_free(msg); + return s; + +out: + racoon_free(msg); + return -1; +} + +/* + * Bind() a socket to a port. This works just like regular bind(), except that + * if you want to bind to the designated isakmp ports and you don't have the + * privilege to do so, it will ask a privileged process to do it. + */ +int +privsep_bind(s, addr, addrlen) + int s; + const struct sockaddr *addr; + socklen_t addrlen; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + struct bind_args bind_args; + int err, saved_errno = 0; + + err = bind(s, addr, addrlen); + if ((err == 0) || (saved_errno = errno) != EACCES || geteuid() == 0) { + if (saved_errno) + plog(LLV_ERROR, LOCATION, NULL, + "privsep_bind (%s) = %d\n", strerror(saved_errno), err); + errno = saved_errno; + return err; + } + + len = sizeof(*msg) + sizeof(bind_args) + addrlen; + + 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_BIND; + msg->hdr.ac_len = len; + + bind_args.s = -1; + bind_args.addr = NULL; + bind_args.addrlen = addrlen; + + data = (char *)(msg + 1); + msg->bufs.buflen[0] = sizeof(bind_args); + memcpy(data, &bind_args, msg->bufs.buflen[0]); + + data += msg->bufs.buflen[0]; + msg->bufs.buflen[1] = addrlen; + memcpy(data, addr, addrlen); + + /* frees msg */ + if (privsep_send(privsep_sock[1], msg, len) != 0) + goto out; + + /* Send the socket descriptor to the privileged process. */ + if (send_fd(privsep_sock[1], s) < 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) + goto out; + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + racoon_free(msg); + return 0; + +out: + racoon_free(msg); + return -1; +} + +/* + * Set socket options. This works just like regular setsockopt(), except that + * if you want to change IP_IPSEC_POLICY or IPV6_IPSEC_POLICY and you don't + * have the privilege to do so, it will ask a privileged process to do it. + */ +int +privsep_setsockopt(s, level, optname, optval, optlen) + int s; + int level; + int optname; + const void *optval; + socklen_t optlen; +{ + struct privsep_com_msg *msg; + size_t len; + char *data; + struct sockopt_args sockopt_args; + int err, saved_errno = 0; + + if ((err = setsockopt(s, level, optname, optval, optlen) == 0) || + (saved_errno = errno) != EACCES || + geteuid() == 0) { + if (saved_errno) + plog(LLV_ERROR, LOCATION, NULL, + "privsep_setsockopt (%s)\n", + strerror(saved_errno)); + + errno = saved_errno; + return err; + } + + len = sizeof(*msg) + sizeof(sockopt_args) + optlen; + + 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_SETSOCKOPTS; + msg->hdr.ac_len = len; + + sockopt_args.s = -1; + sockopt_args.level = level; + sockopt_args.optname = optname; + sockopt_args.optval = NULL; + sockopt_args.optlen = optlen; + + data = (char *)(msg + 1); + msg->bufs.buflen[0] = sizeof(sockopt_args); + memcpy(data, &sockopt_args, msg->bufs.buflen[0]); + + data += msg->bufs.buflen[0]; + msg->bufs.buflen[1] = optlen; + memcpy(data, optval, optlen); + + /* frees msg */ + if (privsep_send(privsep_sock[1], msg, len) != 0) + goto out; + + if (send_fd(privsep_sock[1], s) < 0) + return -1; + + if (privsep_recv(privsep_sock[1], &msg, &len) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "privsep_recv failed\n"); + goto out; + } + + if (msg->hdr.ac_errno != 0) { + errno = msg->hdr.ac_errno; + goto out; + } + + racoon_free(msg); + return 0; + +out: + racoon_free(msg); + return -1; +} + #ifdef ENABLE_HYBRID int privsep_xauth_login_system(usr, pwd) @@ -972,6 +1346,7 @@ privsep_xauth_login_system(usr, pwd) msg->bufs.buflen[1] = strlen(pwd) + 1; memcpy(data, pwd, msg->bufs.buflen[1]); + /* frees msg */ if (privsep_send(privsep_sock[1], msg, len) != 0) return -1; @@ -1034,6 +1409,7 @@ privsep_accounting_system(port, raddr, usr, inout) data += msg->bufs.buflen[2]; memcpy(data, &inout, msg->bufs.buflen[3]); + /* frees msg */ if (privsep_send(privsep_sock[1], msg, len) != 0) return -1; @@ -1089,7 +1465,7 @@ safety_check(msg, index) } /* - * Filter unsafe environement variables + * Filter unsafe environment variables */ static int unsafe_env(envp) @@ -1110,7 +1486,7 @@ unsafe_env(envp) return 0; found: plog(LLV_ERROR, LOCATION, NULL, - "privsep_script_exec: unsafe environement variable\n"); + "privsep_script_exec: unsafe environment variable\n"); return -1; } @@ -1161,6 +1537,86 @@ unknown_name(name) return 0; } +/* Receive a file descriptor through the argument socket */ +static int +rec_fd(s) + int s; +{ + struct msghdr msg; + struct cmsghdr *cmsg; + int *fdptr; + int fd; + char cmsbuf[1024]; + struct iovec iov; + char iobuf[1]; + + iov.iov_base = iobuf; + iov.iov_len = 1; + + if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) { + plog(LLV_ERROR, LOCATION, NULL, + "send_fd: buffer size too small\n"); + return -1; + } + bzero(&msg, sizeof(msg)); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsbuf; + msg.msg_controllen = CMSG_SPACE(sizeof(fd)); + + if (recvmsg(s, &msg, MSG_WAITALL) == -1) + return -1; + + cmsg = CMSG_FIRSTHDR(&msg); + fdptr = (int *) CMSG_DATA(cmsg); + return fdptr[0]; +} + +/* Send the file descriptor fd through the argument socket s */ +static int +send_fd(s, fd) + int s; + int fd; +{ + struct msghdr msg; + struct cmsghdr *cmsg; + char cmsbuf[1024]; + struct iovec iov; + int *fdptr; + + iov.iov_base = " "; + iov.iov_len = 1; + + if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) { + plog(LLV_ERROR, LOCATION, NULL, + "send_fd: buffer size too small\n"); + return -1; + } + bzero(&msg, sizeof(msg)); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsbuf; + msg.msg_controllen = CMSG_SPACE(sizeof(fd)); + msg.msg_flags = 0; + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fdptr = (int *)CMSG_DATA(cmsg); + fdptr[0] = fd; + msg.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(s, &msg, 0) == -1) + return -1; + + return 0; +} + #ifdef HAVE_LIBPAM int privsep_accounting_pam(port, inout) @@ -1202,6 +1658,7 @@ privsep_accounting_pam(port, inout) *inout_data = inout; *pool_size_data = isakmp_cfg_config.pool_size; + /* frees msg */ if (privsep_send(privsep_sock[1], msg, len) != 0) return -1; @@ -1272,6 +1729,7 @@ privsep_xauth_login_pam(port, raddr, usr, pwd) data += msg->bufs.buflen[3]; memcpy(data, pwd, msg->bufs.buflen[4]); + /* frees msg */ if (privsep_send(privsep_sock[1], msg, len) != 0) return -1; @@ -1324,6 +1782,7 @@ privsep_cleanup_pam(port) data += msg->bufs.buflen[0]; memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); + /* frees msg */ if (privsep_send(privsep_sock[1], msg, len) != 0) return; diff --git a/src/racoon/privsep.h b/src/racoon/privsep.h index 0fa4363..732743c 100644 --- a/src/racoon/privsep.h +++ b/src/racoon/privsep.h @@ -1,4 +1,4 @@ -/* $NetBSD: privsep.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: privsep.h,v 1.6 2008/12/08 06:00:54 tteras Exp $ */ /* Id: privsep.h,v 1.5 2005/06/07 12:22:11 fredsen Exp */ @@ -42,6 +42,9 @@ #define PRIVSEP_XAUTH_LOGIN_PAM 0x0807 /* admin_com_bufs follows */ #define PRIVSEP_CLEANUP_PAM 0x0808 /* admin_com_bufs follows */ #define PRIVSEP_ACCOUNTING_SYSTEM 0x0809 /* admin_com_bufs follows */ +#define PRIVSEP_SETSOCKOPTS 0x080A /* admin_com_bufs follows */ +#define PRIVSEP_BIND 0x080B /* admin_com_bufs follows */ +#define PRIVSEP_SOCKET 0x080C /* admin_com_bufs follows */ #define PRIVSEP_NBUF_MAX 24 #define PRIVSEP_BUFLEN_MAX 4096 @@ -58,9 +61,10 @@ struct privsep_com_msg { 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((char *, int, char * const *)); +int privsep_setsockopt __P((int, int, int, const void *, socklen_t)); +int privsep_socket __P((int, int, int)); +int privsep_bind __P((int, const struct sockaddr *, socklen_t)); vchar_t *privsep_getpsk __P((const char *, const int)); int privsep_xauth_login_system __P((char *, char *)); #ifdef HAVE_LIBPAM diff --git a/src/racoon/proposal.c b/src/racoon/proposal.c index 26c9274..33dd311 100644 --- a/src/racoon/proposal.c +++ b/src/racoon/proposal.c @@ -1,6 +1,6 @@ -/* $NetBSD: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $ */ +/* $NetBSD: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $ */ -/* $Id: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $ */ +/* $Id: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -1186,10 +1186,10 @@ set_proposal_from_proposal(iph2) * 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; - + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + if (pp_peer != NULL) flushsaprop(pp_peer); @@ -1226,8 +1226,6 @@ set_proposal_from_proposal(iph2) for (pr = pp_peer->head; pr; pr = pr->next) { - struct remoteconf *conf; - newpr = newsaproto(); if (newpr == NULL) { @@ -1244,9 +1242,7 @@ set_proposal_from_proposal(iph2) newpr->reqid_in = 0; newpr->reqid_out = 0; - conf = getrmconf(iph2->dst); - if (conf != NULL && - conf->gen_policy == GENERATE_POLICY_UNIQUE){ + if (iph2->ph1->rmconf->gen_policy == GENERATE_POLICY_UNIQUE){ newpr->reqid_in = g_nextreqid ; newpr->reqid_out = g_nextreqid ++; /* diff --git a/src/racoon/proposal.h b/src/racoon/proposal.h index 60fc531..11fbab8 100644 --- a/src/racoon/proposal.h +++ b/src/racoon/proposal.h @@ -1,4 +1,4 @@ -/* $NetBSD: proposal.h,v 1.6 2006/12/09 05:52:57 manu Exp $ */ +/* $NetBSD: proposal.h,v 1.7 2010/02/09 23:05:16 wiz Exp $ */ /* Id: proposal.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp */ @@ -88,7 +88,7 @@ struct saproto { int reqid_out; /* request id (outbound) */ int reqid_in; /* request id (inbound) */ - int ok; /* if 1, success to set SA in kenrel */ + int ok; /* if 1, success to set SA in kernel */ struct satrns *head; /* header of transform */ struct saproto *next; /* next protocol */ diff --git a/src/racoon/prsa_par.h b/src/racoon/prsa_par.h index 3bdb11d..6e845d8 100644 --- a/src/racoon/prsa_par.h +++ b/src/racoon/prsa_par.h @@ -1,24 +1,23 @@ -/* A Bison parser, made by GNU Bison 2.3. */ -/* Skeleton interface for Bison's Yacc-like parsers in C +/* A Bison parser, made by GNU Bison 2.4.1. */ - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,10 +28,11 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ + /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -90,21 +90,27 @@ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 130 "prsa_par.y" { + +/* Line 1676 of yacc.c */ +#line 130 "prsa_par.y" + BIGNUM *bn; RSA *rsa; char *chr; long num; struct netaddr *naddr; -} -/* Line 1489 of yacc.c. */ -#line 103 "prsa_par.h" - YYSTYPE; + + + +/* Line 1676 of yacc.c */ +#line 108 "prsa_par.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE prsalval; + diff --git a/src/racoon/prsa_par.y b/src/racoon/prsa_par.y index f21a82b..1987e4d 100644 --- a/src/racoon/prsa_par.y +++ b/src/racoon/prsa_par.y @@ -1,4 +1,4 @@ -/* $NetBSD: prsa_par.y,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: prsa_par.y,v 1.6 2011/03/02 14:49:21 vanhu Exp $ */ /* Id: prsa_par.y,v 1.3 2004/11/08 12:04:23 ludvigm Exp */ @@ -211,6 +211,7 @@ rsa_statement: YYABORT; } $$ = base64_pubkey2rsa($2); + free($2); } | TAG_PUB HEX { @@ -236,6 +237,7 @@ addr4: { int err; struct sockaddr_in *sap; + struct addrinfo hints, *res; if ($2 == -1) $2 = 32; if ($2 < 0 || $2 > 32) { @@ -245,12 +247,17 @@ addr4: $$ = 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)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_flags = AI_NUMERICHOST; + err = getaddrinfo($1, NULL, &hints, &res); + if (err < 0) { + prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err)); YYABORT; } + memcpy(sap, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + free($1); } ; @@ -259,6 +266,7 @@ addr6: { int err; struct sockaddr_in6 *sap; + struct addrinfo hints, *res; if ($2 == -1) $2 = 128; if ($2 < 0 || $2 > 128) { @@ -268,12 +276,17 @@ addr6: $$ = 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)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + err = getaddrinfo($1, NULL, &hints, &res); + if (err < 0) { + prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err)); YYABORT; } + memcpy(sap, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + free($1); } ; diff --git a/src/racoon/racoon.8 b/src/racoon/racoon.8 index a6d39d7..58fefdd 100644 --- a/src/racoon/racoon.8 +++ b/src/racoon/racoon.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: racoon.8,v 1.10 2006/09/09 16:22:10 manu Exp $ +.\" $NetBSD: racoon.8,v 1.12 2009/01/24 10:42:31 wiz Exp $ .\" .\" Id: racoon.8,v 1.4 2005/04/18 11:07:55 manubsd Exp .\" @@ -29,7 +29,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd November 20, 2000 +.Dd January 23, 2009 .Dt RACOON 8 .Os .\" @@ -40,7 +40,7 @@ .Sh SYNOPSIS .Nm racoon .Bk -words -.Op Fl 46BdFLv +.Op Fl 46BdFLVv .Ek .Bk -words .Op Fl f Ar configfile @@ -115,6 +115,8 @@ The default is 4500. Listen to the ISAKMP key exchange on port .Ar isakmp-port instead of the default port number, 500. +.It Fl V +Print racoon version and compilation options and exit. .It Fl v This flag causes the packet dump be more verbose, with higher debugging level. diff --git a/src/racoon/racoon.conf.5 b/src/racoon/racoon.conf.5 index 9ddee80..70c7eda 100644 --- a/src/racoon/racoon.conf.5 +++ b/src/racoon/racoon.conf.5 @@ -1,4 +1,4 @@ -.\" $NetBSD: racoon.conf.5,v 1.34.4.3 2007/09/03 18:07:29 mgrooms Exp $ +.\" $NetBSD: racoon.conf.5,v 1.61 2010/06/22 20:51:04 wiz Exp $ .\" .\" Id: racoon.conf.5,v 1.54 2006/08/22 18:17:17 manubsd Exp .\" @@ -29,7 +29,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 19, 2006 +.Dd June 22, 2010 .Dt RACOON.CONF 5 .Os .\" @@ -152,7 +152,7 @@ The user to which the unprivileged instance of should switch. This can be a quoted user name or a numeric UID. .It Ic group Ar group ; -The group the unprivilegied instance of +The group the unprivileged instance of .Xr racoon 8 , should switch. This can be a quoted group name or a numeric GID. @@ -184,7 +184,8 @@ When running in privilege separation mode, .Ic certificate and .Ic script -paths are mandatory. A +paths are mandatory. +A .Xr racoon 8 restart is required if you want path changes to be taken into account. .Bl -tag -width Ds -compact @@ -223,7 +224,8 @@ will refuse to execute a script stored outside of this directory. Specifies file where to store PID of process. If path starts with .Pa / -it is treated as an absolute path. Otherwise, it is treated as a relative +it is treated as an absolute path. +Otherwise, it is treated as a relative path to the VARRUN directory specified at compilation time. Default is .Pa racoon.pid . @@ -235,12 +237,6 @@ Default is Specifies other configuration files to 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 } @@ -319,12 +315,14 @@ The .Ar owner , and .Ar group -values specify the socket path, owner, and group. They must be quoted. +values specify the socket path, owner, and group. +They must be quoted. The defaults are .Pa /var/racoon/racoon.sock , UID 0, and GID 0. .Ar mode -is the access mode in octal. The default is 0600. +is the access mode in octal. +The default is 0600. .It Ic adminsock disabled ; This directive tells racoon to not listen on the admin socket. .El @@ -360,22 +358,66 @@ This is the encoding used by older versions of .El .El .\" +.Pp +.Bl -tag -width Ds -compact +.It Ic pfkey_buffer Ar kBytes +Specifies the socket send/receive buffer size in kilobytes. +Numerous kernel PF_KEY implementations have problems with dumping +SAD/SDP with large amount of entries (this happens when 100s to +1000s of tunnels are configured). +.Pp +The default value of 0 leaves everything at the OS-specific default value. +If the default buffer size is greater than what is specified here racoon +will not decrease it. +.Pp +This problem is known to be fixed in Linux 2.6.25 and later. +.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 +.It Ic remote Ar name Bo Ic inherit Ar parent_name Bc Ic { Ar statements Ic } Specifies the IKE phase 1 parameters for each remote node. -The default port is 500. -If -.Ic anonymous -is specified, the statements will apply to any peer that does not match a -more specific -.Ic remote -directive. +.Pp +If connection is initiated using racoonctl, a unique match using the +remote IP must be found or the remote block name has to be given. +For received acquires (kernel notices traffic requiring a new SA) the +remote IP and remoteid from matching sainfo block are used to decide +the remoteblock. +If no uniquely matching remoteblock is found using +these criteria, no connection attempt is done. +.Pp +When acting as responder, racoon picks the first proposal that has one +or more acceptable remote configurations. +When determining if a remote +specification is matching the following information is checked: +.Bl -bullet -width Ds -compact +.It +The remote IP is checked against +.Ic remote_address . +.It +ISAKMP exchange type is checked against +.Ic exchange_mode . +.It +ISAKMP SA attributes must match a +.Ic proposal +block. +.It +The remote identity is matched against +.Ic peers_identifier +if +.Ic verify_identifier +is on. +.It +If a certificate request was received, it must match the issuer of +.Ic "certificate_type x509" +certificate. +If certificate request without issuer name was sent, the +.Ic match_empty_cr +parameter specifies whether or not remote block matches. +.El +.Pp +Similarly, NAT-T is enabled if any of the initial remote configuration +candidates allow NAT-T. .Pp Sections with .Ic inherit Ar parent @@ -393,6 +435,9 @@ The following are valid statements. .Pp .Bl -tag -width Ds -compact .\" +.It Ic remote_address Ar address ; +Defines the IP address of the peer. +.\" .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 the responder. @@ -408,14 +453,7 @@ You can omit this statement. Means to use SIT_IDENTITY_ONLY as specified in RFC 2407. You can omit this statement. .\" -.It Ic identifier Ar idtype ; -This statment is obsolete. Instead, use -.Ic my_identifier . -.\" -.It Xo -.Ic my_identifier Bq Ar qualifier -.Ar idtype ... ; -.Xc +.It Ic my_identifier Bo Ar qualifier Bc 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 , @@ -440,10 +478,7 @@ This is the default type if you do not specify an identifier to use. 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 Xo -.Ic my_identifier Ic keyid Bq Ic file -.Ar file ; -.Xc +.It Ic my_identifier Ic keyid Bo Ic file Bc Ar file ; The type is a KEY_ID, read from the file. .It Ic my_identifier Ic keyid Ic tag Ar string ; The type is a KEY_ID, specified in the quoted string. @@ -482,6 +517,13 @@ except that the individual component values of an identifier may specified as .Ic * to match any value (e.g. "C=XX, O=MyOrg, OU=*, CN=Mine"). +The format of the +specification should correspond to RFC 2253; in particular, commas and certain +other characters - +.Ic ,=+\*[Lt]\*[Gt]#; +- may be included in a name by preceeding them with a backslash "\e", and +arbitrary characters may be inserted in a name with the "\enn" escape, where +nn is the hex representation of the ascii value of the desired character. Alternative acceptable peer identifiers may be specified by repeating the .Ic peers_identifier statement. @@ -509,7 +551,9 @@ means a file name of a secret key. .Bl -tag -width Ds -compact .It Ic plain_rsa Ar privkeyfile ; .Ar privkeyfile -means a file name of a private key generated by plainrsa-gen(8). Required +means a file name of a private key generated by +.Xr plainrsa-gen 8 . +Required for RSA authentication. .El .It Ic ca_type Ar cacertspec ; @@ -553,16 +597,20 @@ is defined, .Xr racoon 8 will expect .Ar pubkeyfile -to be the peer's public key that was generated -by plainrsa-gen(8). +to be the peer's public key that was generated by +.Xr plainrsa-gen 8 . .\" .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 +.It Ic script Ar script Ic phase1_dead +Shell scripts that get executed when a phase 1 SA goes up or down, or +when it is detected as dead by DPD. +All scripts get either .Ic phase1_up -or +, .Ic phase1_down +or +.Ic phase1_dead as first argument, and the following variables are set in their environment: .Bl -tag -width Ds -compact @@ -574,6 +622,8 @@ The local port used for IKE for the phase 1 SA. The remote address of the phase 1 SA. .It Ev REMOTE_PORT The remote port used for IKE for the phase 1 SA. +.It Ev REMOTE_ID +The remote identity received in IKE for the phase 1 SA. .El The following variables are only set if .Ic mode_cfg @@ -604,6 +654,10 @@ SPLIT_INCLUDE and SPLIT_LOCAL are mutually exclusive. The space separated list of IPv4 addresses and masks (address slash mask) that define the networks to be considered local, and thus excluded from the tunnels ; obtained by ISAKMP mode config. +.It SPLIT_INCLUDE_CIDR +Same as SPLIT_INCLUDE, with netmasks in CIDR notation. +.It SPLIT_LOCAL_CIDR +Same as SPLIT_LOCAL, with netmasks in CIDR notation. .It DEFAULT_DOMAIN The DNS default domain name obtained by ISAKMP mode config. .El @@ -617,16 +671,21 @@ The default is on. If you do not want to send a certificate request, set this to off. The default is on. .\" +.It Ic match_empty_cr (on | off) ; +Specifies whether this remote block is a valid match when a non-specific +certificate request is received. +The default is on. +.\" .It Ic verify_cert (on | off) ; By default, the identifier sent by the remote host (as specified in its .Ic my_identifier statement) is compared with the credentials in the certificate used to authenticate the remote host as follows: .Bl -tag -width Ds -compact -.It Type Ic asn1dn: +.It Type Ic asn1dn : The entire certificate subject name is compared with the identifier, e.g. "C=XX, O=YY, ...". -.It Type Ic address, fqdn, or user_fqdn: +.It Type Ic address, fqdn, or user_fqdn : The certificate's subjectAltName is compared with the identifier. .El If the two do not match the negotiation will fail. @@ -692,7 +751,7 @@ The default value is It is useful for a server. .\" .It Ic proposal_check Ar level ; -Specifies the action of lifetime length, key length and PFS of the phase 2 +Specifies the action of lifetime length, key 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 @@ -812,6 +871,22 @@ is set, this sets the maximum number of liveliness proofs to request The default value is .Ic 5 . .\" +.It Ic rekey (on | off | force) ; +Enable automatic renegotiation of expired phase1 when there are non-dying +phase2 SAs. +Possible values are: +.Bl -tag -width Ds -compact +.It Ic force +Rekeying is done unconditionally. +.It Ic on +Rekeying is done only if DPD monitoring is active. +This is the default. +.It Ic off +No automatic rekeying. +Do note that turning off automatic rekeying will +result in inaccurate DPD monitoring. +.El +.\" .It Ic nonce_size Ar number ; define the byte size of nonce value. Racoon can send any value although @@ -819,13 +894,11 @@ RFC2409 specifies that the value MUST be between 8 and 256 bytes. The default size is 16 bytes. .\" .It Ic ph1id Ar number ; -An optionnal number to identify the remote proposal and to link it +An optional number to identify the remote proposal and to link it only with sainfos who have the same number. Defaults to 0. .\" -.It Xo -.Ic proposal { Ar sub-substatements Ic } -.Xc +.It Ic proposal { Ar sub-substatements Ic } .Bl -tag -width Ds -compact .\" .It Ic encryption_algorithm Ar algorithm ; @@ -888,30 +961,35 @@ is used, where hostname is the value returned by the command. .El .El +.Pp +.It Ic remote Po Ar address | Ic anonymous Pc Bo Bo Ar port Bc Bc \ +Bo Ic inherit Ar parent Bc Ic { Ar statements Ic } +Deprecated format of specifying a remote block. +This will be removed in future. +It is a remnant from time when remote block was decided +solely based on the peers IP address. +.Pp +This is equivalent to: +.Bd -literal -offset +remote "address" [inherit "parent-address"] { + remote_address address; +} +.Ed .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 | Ar source_id Ic anonymous | Ic anonymous Ar destination_id | Ic anonymous ) [ from Ar idtype [ Ar string ] ] [ Ic group Ar string ] -.Ic { Ar statements Ic } -.Xc -defines the parameters of the IKE phase 2 (IPsec-SA establishment). -.Ar source_id +.It Ic sainfo Po Ar local_id | Ic anonymous Pc \ +Po Ar remote_id | Ic clientaddr | Ic anonymous Pc \ +Bo Ic from Ar idtype Bo Ar string Bc Bc Bo Ic group Ar string Bc \ +Ic { Ar statements Ic } +Defines the parameters of the IKE phase 2 (IPsec-SA establishment). +.Pp +The +.Ar local_id and -.Ar destination_id -are constructed like: +.Ar remote_id +strings are constructed like: .Pp .Ic address Ar address .Bq Ic / Ar prefix @@ -925,17 +1003,11 @@ or .Bq Ic [ Ar port ] .Ar ul_proto .Pp -or -.Pp -.Ar idtype Ar string -.Pp -An id string should be expressed to match the exact value of an ID payload -(source is the local end, destination is the remote end). +An id string should be expressed to match the exact value of an ID payload. This is not like a filter rule. For example, if you define 3ffe:501:4819::/48 as -.Ar source_id . +.Ar local_id . 3ffe:501:4819:1000:/64 will not match. -.Pp In the case of a longest prefix (selecting a single host), .Ar address instructs to send ID type of ADDRESS while @@ -943,7 +1015,24 @@ instructs to send ID type of ADDRESS while instructs to send ID type of SUBNET. Otherwise, these instructions are identical. .Pp -The group keyword allows an XAuth group membership check to be performed +The +.Ic anonymous +keyword can be used to match any id. +The +.Ic clientaddr +keyword can be used to match a remote id that is equal to either the peer +ip address or the mode_cfg ip address (if assigned). +This can be useful +to restrict policy generation when racoon is acting as a client gateway +for peers with dynamic ip addresses. +.Pp +The +.Ic from +keyword allows an sainfo to only match for peers that use a specific phase1 +id value during authentication. +The +.Ic group +keyword allows an XAuth group membership check to be performed for this sainfo section. When the mode_cfg auth source is set to .Ic system @@ -977,10 +1066,6 @@ directive. Sainfos will only be used if their remoteid matches the ph1id of the remote section used for phase 1. Defaults to 0, which is also the default for ph1id. -.\" -.It Ic my_identifier Ar idtype ... ; -is obsolete. -It does not make sense to specify an identifier in the phase 2. .El .\" .Pp @@ -1037,7 +1122,7 @@ Defines the logging level. .Ar level is one of following: .Ic error , warning , notify , info , debug -and +or .Ic debug2 . The default is .Ic info . @@ -1091,8 +1176,10 @@ This is the default. means to use a RADIUS server. It works only if .Xr racoon 8 -was built with libradius support. Radius configuration is hanlded by -.Xr radius.conf 5 . +was built with libradius support. +Radius configuration is handled by statements in the +.Ic radiuscfg +section. .Ar pam means to use PAM. It works only if @@ -1102,8 +1189,8 @@ was built with libpam support. means to use LDAP. It works only if .Xr racoon 8 -was built with libldap support. LDAP configuration is handled by -statements in the +was built with libldap support. +LDAP configuration is handled by statements in the .Ic ldapcfg section. .It Ic auth_groups Ar "group1", ... ; @@ -1111,7 +1198,7 @@ Specifies the group memberships for Xauth in quoted group name strings. When defined, the authenticating user must be a member of at least one group for Xauth to succeed. .It Ic group_source (system | ldap) ; -Specifies the source for group validataion of users through Xauth. +Specifies the source for group validation of users through Xauth. .Ar system means to use the Unix user database. This is the default. @@ -1137,9 +1224,10 @@ This is the default. means to use a RADIUS server. It works only if .Xr racoon 8 -was built with libradius support and requires RADIUS authentiation. -RADIUS configuration is handled by -.Xr radius.conf 5 . +was built with libradius support and requires RADIUS authentication. +RADIUS configuration is handled by statements in the +.Ic radiuscfg +section. .Ar ldap means to use an LDAP server. It works only if @@ -1164,8 +1252,9 @@ enables RADIUS accounting. It works only if .Xr racoon 8 was built with libradius support and requires RADIUS authentication. -RADIUS configuration is handled by -.Xr radius.conf 5 . +RADIUS configuration is handled by statements in the +.Ic radiuscfg +section. Specifying .Ar pam enables PAM accounting. @@ -1198,12 +1287,13 @@ A list of IPv4 addresses for DNS servers, separated by commas, or on multiple .Ic dns4 lines. .It Ic wins4 Ar addresses ; -A list of IPv4 address for WINS servers. The keyword +A list of IPv4 address for WINS servers. +The keyword .It nbns4 can also be used as an alias for .It wins4 . .It Ic split_network (include | local_lan) Ar network/mask, ... -The network configuration to send, in cidr notation (e.g. 192.168.1.0/24). +The network configuration to send, in CIDR notation (e.g. 192.168.1.0/24). If .Ic include is specified, the tunnel should be only used to encrypt the indicated @@ -1255,11 +1345,11 @@ The default is The host name or ip address of the ldap server. The default is .Ic localhost . -.It Ic port Ar number; +.It Ic port Ar number ; The port that the ldap server is configured to listen on. The default is .Ic 389 . -.It Ic base Ar distinguished name; +.It Ic base Ar distinguished name ; The ldap search base. This option has no default value. .It Ic subtree (on | off) ; @@ -1267,20 +1357,20 @@ Use the subtree ldap search scope. Otherwise, use the one level search scope. The default is .Ic off . -.It Ic bind_dn Ar distinguised name; -The user dn used to optionaly bind as before performing ldap search operations. +.It Ic bind_dn Ar distinguished name ; +The user dn used to optionally bind as before performing ldap search operations. If this option is not specified, anonymous binds are used. -.It Ic bind_pw Ar string; +.It Ic bind_pw Ar string ; The password used when binding as .Ic bind_dn . -.It Ic attr_user Ar attribute name; +.It Ic attr_user Ar attribute name ; The attribute used to specify a users name in an ldap directory. For example, if a user dn is "cn=jdoe,dc=my,dc=net" then the attribute would be "cn". The default value is .Ic cn . -.It Ic attr_addr Ar attribute name; -.It Ic attr_mask Ar attribute name; +.It Ic attr_addr Ar attribute name ; +.It Ic attr_mask Ar attribute name ; The attributes used to specify a users network address and subnet mask in an ldap directory. These values are forwarded during mode_cfg negotiation when @@ -1289,18 +1379,54 @@ The default values are .Ic racoon-address and .Ic racoon-netmask . -.It Ic attr_group Ar attribute name; +.It Ic attr_group Ar attribute name ; The attribute used to specify a group name in an ldap directory. For example, if a group dn is "cn=users,dc=my,dc=net" then the attribute would be "cn". The default value is .Ic cn . -.It Ic attr_member Ar attribute name; +.It Ic attr_member Ar attribute name ; The attribute used to specify group membership in an ldap directory. The default value is .Ic member . .El .El +.Ss Radius configuration settings +.Bl -tag -width Ds -compact +.It Ic radiuscfg { Ar statements Ic } +Defines the parameters that will be used to communicate with radius +servers for +.Ic xauth +authentication. +If radius is selected as the xauth authentication or accounting +source and no servers are defined in this section, settings from +the system +.Xr radius.conf 5 +configuration file will be used instead. +.Pp +The following are valid statements: +.Bl -tag -width Ds -compact +.It Ic auth Ar (hostname | address) [port] sharedsecret ; +The host name or ip address, optional port value and shared secret value +of a radius authentication server. +Up to 5 radius authentication servers +may be specified using multiple lines. +.It Ic acct Ar (hostname | address) [port] sharedsecret ; +The host name or ip address, optional port value and shared secret value +of a radius accounting server. +Up to 5 radius accounting servers may be +specified using multiple lines. +.It Ic timeout Ar seconds ; +The timeout for receiving replies from radius servers. +The default is +.Ic 3 . +.It Ic retries Ar count ; +The maximum number of repeated requests to make before giving up +on a radius server. +The default is +.Ic 3 . +.El +.El .Ss Special directives .Bl -tag -width Ds -compact .It Ic complex_bundle (on | off) ; diff --git a/src/racoon/racoonctl.8 b/src/racoon/racoonctl.8 index b27b188..697f3ed 100644 --- a/src/racoon/racoonctl.8 +++ b/src/racoon/racoonctl.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: racoonctl.8,v 1.13 2006/09/09 16:22:10 manu Exp $ +.\" $NetBSD: racoonctl.8,v 1.22 2009/03/12 14:01:09 wiz Exp $ .\" .\" Id: racoonctl.8,v 1.6 2006/05/07 21:32:59 manubsd Exp .\" @@ -29,7 +29,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd November 16, 2004 +.Dd March 12, 2009 .Dt RACOONCTL 8 .Os .\" @@ -39,34 +39,49 @@ .\" .Sh SYNOPSIS .Nm +.Op opts reload-config .Nm +.Op opts show-schedule .Nm -.Op Fl l Op Fl l +.Op opts show-sa .Op isakmp|esp|ah|ipsec .Nm +.Op opts +get-sa-cert +.Op inet|inet6 +.Ar src dst +.Nm +.Op opts flush-sa .Op isakmp|esp|ah|ipsec .Nm +.Op opts delete-sa .Ar saopts .Nm +.Op opts establish-sa +.Op Fl w +.Op Fl n Ar remoteconf .Op Fl u Ar identity .Ar saopts .Nm +.Op opts vpn-connect -.Op Fl u identity +.Op Fl u Ar identity .Ar vpn_gateway .Nm +.Op opts vpn-disconnect .Ar vpn_gateway .Nm +.Op opts show-event -.Op Fl l .Nm +.Op opts logout-user .Ar login .\" @@ -85,6 +100,19 @@ of the socket, you can allow non-root users to alter .Xr racoon 8 behavior, so do that with caution. .Pp +The following general options are available: +.Bl -tag -width Ds +.It Fl d +Debug mode. +Hexdump sent admin port commands. +.It Fl l +Increase verbosity. +Mainly for show-sa command. +.It Fl s Ar socket +Specify unix socket name used to connecting racoon. +.El +.\" +.Pp The following commands are available: .Bl -tag -width Ds .It reload-config @@ -99,33 +127,41 @@ IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs. Use .Fl l to increase verbosity. +.It get-sa-cert Oo inet|inet6 Oc Ar src dst +Output the raw certificate that was used to authenticate the phase 1 +matching +.Ar src +and +.Ar dst . .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 +.It establish-sa Oo Fl w Oc Oo Fl n Ar remoteconf Oc Oo Fl u Ar username \ +Oc Ar saopts 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. +The exact remote block to use can be specified with +.Fl n Ar remoteconf . .Nm will prompt you for the password associated with .Ar username and these credentials will be used in the Xauth exchange. .Pp +Specifying +.Fl w +will make racoonctl wait until the SA is actually established or +an error occurs. +.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} +{icmp|tcp|udp|gre|any} .El -.It Xo vpn-connect -.Oo Fl u Ar username -.Oc Ar vpn_gateway -.Xc +.It vpn-connect Oo Fl u Ar username Oc Ar vpn_gateway This is a particular case of the previous command. It will establish an ISAKMP SA with .Ar vpn_gateway . @@ -135,16 +171,9 @@ Delete an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA. 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. +.It show-event +Listen for all events reported by +.Xr racoon 8 . .It logout-user Ar login Delete all SA established on behalf of the Xauth user .Ar login . diff --git a/src/racoon/racoonctl.c b/src/racoon/racoonctl.c index 1dd26f0..da28ecd 100644 --- a/src/racoon/racoonctl.c +++ b/src/racoon/racoonctl.c @@ -1,9 +1,10 @@ -/* $NetBSD: racoonctl.c,v 1.7.6.2 2009/04/20 13:32:57 tteras Exp $ */ +/* $NetBSD: racoonctl.c,v 1.18 2010/11/12 09:08:26 tteras Exp $ */ /* Id: racoonctl.c,v 1.11 2006/04/06 17:06:25 manubsd Exp */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * Copyright (C) 2008 Timo Teras. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,6 +93,7 @@ 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_getsacert __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 **)); @@ -104,59 +106,59 @@ static vchar_t *f_logoutusr __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" }, + { f_reload, "reload-config" }, + { f_reload, "rc" }, + { f_getsched, "show-schedule" }, + { f_getsched, "sc" }, + { f_getsa, "show-sa" }, + { f_getsa, "ss" }, + { f_getsacert, "get-cert" }, + { f_getsacert, "gc" }, + { f_flushsa, "flush-sa" }, + { f_flushsa, "fs" }, + { f_deletesa, "delete-sa" }, + { f_deletesa, "ds" }, + { f_exchangesa, "establish-sa" }, + { f_exchangesa, "es" }, + { f_vpnc, "vpn-connect" }, + { f_vpnc, "vc" }, + { f_vpnd, "vpn-disconnect" }, + { f_vpnd, "vd" }, + { f_getevt, "show-event" }, + { f_getevt, "se" }, #ifdef ENABLE_HYBRID - { f_logoutusr, ADMIN_LOGOUT_USER, "logout-user" }, - { f_logoutusr, ADMIN_LOGOUT_USER, "lu" }, + { f_logoutusr, "logout-user" }, + { f_logoutusr, "lu" }, #endif - { NULL, 0, NULL }, + { NULL, 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 }, - { EVTT_PEERPH1_NOPROP, "Peer failed phase 1 initiation " - "(proposal problem?)", ERROR }, - { 0, NULL, UNSPEC }, - { EVTT_NO_ISAKMP_CFG, "No need for ISAKMP mode config ", INFO }, + { EVT_RACOON_QUIT, "Racoon terminated" }, + + { EVT_PHASE1_UP, "Phase 1 established" }, + { EVT_PHASE1_DOWN, "Phase 1 deleted" }, + { EVT_PHASE1_NO_RESPONSE, "Phase 1 error: peer not responding" }, + { EVT_PHASE1_NO_PROPOSAL, "Phase 1 error: no proposal chosen" }, + { EVT_PHASE1_AUTH_FAILED, + "Phase 1 error: authentication failed (bad certificate?)" }, + { EVT_PHASE1_DPD_TIMEOUT, "Phase 1 error: dead peer detected" }, + { EVT_PHASE1_MODE_CFG, "Phase 1 mode configuration done" }, + { EVT_PHASE1_XAUTH_SUCCESS, "Phase 1 Xauth succeeded" }, + { EVT_PHASE1_XAUTH_FAILED, "Phase 1 Xauth failed" }, + + { EVT_PHASE2_NO_PHASE1, "Phase 2 error: no suitable phase 1" }, + { EVT_PHASE2_UP, "Phase 2 established" }, + { EVT_PHASE2_DOWN, "Phase 2 deleted" }, + { EVT_PHASE2_NO_RESPONSE, "Phase 2 error: no response" }, }; +static vchar_t *get_proto_and_index __P((int, char **, u_int16_t *)); static int get_proto __P((char *)); static vchar_t *get_index __P((int, char **)); static int get_family __P((char *)); @@ -184,6 +186,7 @@ struct ulproto_tag { { IPPROTO_ICMP, "icmp" }, { IPPROTO_TCP, "tcp" }, { IPPROTO_UDP, "udp" }, + { IPPROTO_GRE, "gre" }, { 0, NULL }, }; @@ -193,31 +196,13 @@ 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; +int evt_quit_event = 0; 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)); -void print_ph1up __P((caddr_t, int)); -int evt_poll __P((void)); +void print_evt __P((struct evt_async *)); char * fixed_addr __P((char *, char *, int)); static void @@ -225,14 +210,23 @@ usage() { printf( "Usage:\n" -" %s reload-config\n" -" %s [-l [-l]] show-sa [protocol]\n" -" %s flush-sa [protocol]\n" -" %s delete-sa <saopts>\n" -" %s establish-sa [-u identity] <saopts>\n" -" %s vpn-connect [-u identity] vpn_gateway\n" -" %s vpn-disconnect vpn_gateway\n" +" %s [opts] reload-config\n" +" %s [opts] show-schedule\n" +" %s [opts] show-sa [protocol]\n" +" %s [opts] flush-sa [protocol]\n" +" %s [opts] delete-sa <saopts>\n" +" %s [opts] establish-sa [-u identity] [-n remoteconf] [-w] <saopts>\n" +" %s [opts] vpn-connect [-u identity] vpn_gateway\n" +" %s [opts] vpn-disconnect vpn_gateway\n" +" %s [opts] show-event\n" +" %s [opts] logout-user login\n" "\n" +"General options:\n" +" -d Debug: hexdump admin messages before sending\n" +" -l Increase output verbosity (mainly for show-sa)\n" +" -s <socket> Specify adminport socket to use (default: %s)\n" +"\n" +"Parameter specifications:\n" " <protocol>: \"isakmp\", \"esp\" or \"ah\".\n" " In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n" "\n" @@ -240,8 +234,10 @@ usage() " : {\"esp\",\"ah\"} <family> <src/prefixlen/port> <dst/prefixlen/port>\n" " <ul_proto>\n" " <family>: \"inet\" or \"inet6\"\n" -" <ul_proto>: \"icmp\", \"tcp\", \"udp\" or \"any\"\n", - pname, pname, pname, pname, pname, pname, pname); +" <ul_proto>: \"icmp\", \"tcp\", \"udp\", \"gre\" or \"any\"\n" +"\n", + pname, pname, pname, pname, pname, pname, pname, pname, pname, pname, + ADMINSOCK_PATH); } /* @@ -312,54 +308,24 @@ main(ac, av) vfree(combuf); - if (com_recv(&combuf) != 0) - goto bad; - if (handle_recv(combuf) != 0) - goto bad; - - vfree(combuf); + do { + if (com_recv(&combuf) != 0) + goto bad; + if (handle_recv(combuf) != 0) + goto bad; + vfree(combuf); + } while (evt_quit_event != 0); - if (evt_filter != EVTF_NONE) - if (evt_poll() != 0) - goto bad; - + close(so); exit(0); - bad: +bad: + close(so); + if (errno == EEXIST) + exit(0); 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)) { - /* handle_recv closes the socket time, so open it each time */ - 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); - } - - vfree(sendbuf); - return 0; -} - /* %%% */ /* * return command buffer. @@ -394,61 +360,42 @@ get_combuf(ac, av) } static vchar_t * -f_reload(ac, av) - int ac; - char **av; +make_request(u_int16_t cmd, u_int16_t proto, size_t len) { vchar_t *buf; struct admin_com *head; - buf = vmalloc(sizeof(*head)); + buf = vmalloc(sizeof(struct admin_com) + len); if (buf == NULL) errx(1, "not enough core"); - head = (struct admin_com *)buf->v; + 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; + head->ac_cmd = ADMIN_FLAG_VERSION | cmd; + head->ac_version = 1; + head->ac_proto = proto; return buf; } static vchar_t * -f_getevt(ac, av) +f_reload(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; + return make_request(ADMIN_RELOAD_CONF, 0, 0); +} - if (ac >= 2) +static vchar_t * +f_getevt(ac, av) + int ac; + char **av; +{ + evt_quit_event = -1; + if (ac >= 1) 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; + return make_request(ADMIN_SHOW_EVT, 0, 0); } static vchar_t * @@ -456,20 +403,7 @@ 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; + return make_request(ADMIN_SHOW_SCHED, 0, 0); } static vchar_t * @@ -477,8 +411,6 @@ f_getsa(ac, av) int ac; char **av; { - vchar_t *buf; - struct admin_com *head; int proto; /* need protocol */ @@ -488,15 +420,29 @@ f_getsa(ac, av) if (proto == -1) errx(1, "unknown protocol %s", *av); - buf = vmalloc(sizeof(*head)); + return make_request(ADMIN_SHOW_SA, proto, 0); +} + +static vchar_t * +f_getsacert(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com_indexes *com; + + index = get_index(ac, av); + if (index == NULL) + return NULL; + + com = (struct admin_com_indexes *) index->v; + buf = make_request(ADMIN_GET_SA_CERT, ADMIN_PROTO_ISAKMP, index->l); if (buf == NULL) - errx(1, "not enough core"); + errx(1, "Cannot allocate buffer"); - 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; + memcpy(buf->v+sizeof(struct admin_com), index->v, index->l); + + vfree(index); return buf; } @@ -517,17 +463,7 @@ f_flushsa(ac, 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; + return make_request(ADMIN_FLUSH_SA, proto, 0); } static vchar_t * @@ -536,7 +472,6 @@ f_deletesa(ac, av) char **av; { vchar_t *buf, *index; - struct admin_com *head; int proto; /* need protocol */ @@ -566,17 +501,11 @@ f_deletesa(ac, av) return NULL; } - buf = vmalloc(sizeof(*head) + index->l); + buf = make_request(ADMIN_DELETE_SA, proto, index->l); if (buf == NULL) goto out; - 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); + memcpy(buf->v + sizeof(struct admin_com), index->v, index->l); out: if (index != NULL) @@ -591,47 +520,17 @@ f_deleteallsadst(ac, av) 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); + u_int16_t proto; - /* 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; + index = get_proto_and_index(ac, av, &proto); + if (index == NULL) return NULL; - } - buf = vmalloc(sizeof(*head) + index->l); + buf = make_request(ADMIN_DELETE_ALL_SA_DST, proto, index->l); if (buf == NULL) goto out; - 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); + memcpy(buf->v+sizeof(struct admin_com), index->v, index->l); out: if (index != NULL) @@ -646,13 +545,14 @@ f_exchangesa(ac, av) char **av; { vchar_t *buf, *index; - struct admin_com *head; - int proto; + u_int16_t proto; int cmd = ADMIN_ESTABLISH_SA; size_t com_len = 0; char *id = NULL; char *key = NULL; + char *remoteconf = NULL; struct admin_com_psk *acp; + int wait = 0; if (ac < 1) errx(1, "insufficient arguments"); @@ -673,48 +573,57 @@ f_exchangesa(ac, av) ac -= 2; } - /* need protocol */ - if (ac < 1) - errx(1, "insufficient arguments"); - if ((proto = get_proto(*av)) == -1) - errx(1, "unknown protocol %s", *av); + if (ac >= 2 && strcmp(av[0], "-n") == 0) { + /* Remoteconf name */ + remoteconf = av[1]; + av += 2; + ac -= 2; + } - /* 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; + if (ac >= 1 && strcmp(av[0], "-w") == 0) { + wait = 1; + av++; + ac--; + } + + index = get_proto_and_index(ac, av, &proto); + if (index == NULL) return NULL; + + if (proto == ADMIN_PROTO_ISAKMP && cmd == ADMIN_ESTABLISH_SA && + remoteconf != NULL) + com_len += strlen(remoteconf) + 1; + + if (wait) { + switch (proto) { + case ADMIN_PROTO_ISAKMP: + evt_quit_event = EVT_PHASE1_MODE_CFG; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + evt_quit_event = EVT_PHASE2_UP; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } } - com_len += sizeof(*head) + index->l; - if ((buf = vmalloc(com_len)) == NULL) + com_len += index->l; + buf = make_request(cmd, proto, com_len); + if (buf == 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); + memcpy(buf->v+sizeof(struct admin_com), index->v, index->l); - if (id && key) { + if (proto == ADMIN_PROTO_ISAKMP && cmd == ADMIN_ESTABLISH_SA && + remoteconf != NULL) { + strcpy(buf->v + sizeof(struct admin_com) + index->l, + remoteconf); + } else if (id && key) { char *data; acp = (struct admin_com_psk *) - (buf->v + sizeof(*head) + index->l); + (buf->v + sizeof(struct admin_com) + index->l); acp->id_type = IDTYPE_USERFQDN; acp->id_len = strlen(id) + 1; @@ -749,8 +658,7 @@ f_vpnc(ac, av) if (ac < 1) errx(1, "insufficient arguments"); - evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP); - time(&evt_start); + evt_quit_event = EVT_PHASE1_MODE_CFG; /* Optional -u identity */ if (strcmp(av[0], "-u") == 0) { @@ -765,7 +673,7 @@ f_vpnc(ac, av) } if (ac < 1) - errx(1, "VPN gateway required"); + errx(1, "VPN gateway required"); if (ac > 1) warnx("Extra arguments"); @@ -810,12 +718,11 @@ f_vpnd(ac, av) char *idx; if (ac < 1) - errx(1, "VPN gateway required"); + 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); + evt_quit_event = EVT_PHASE1_DOWN; nav[nac++] = isakmp; nav[nac++] = inet; @@ -832,7 +739,6 @@ f_logoutusr(ac, av) char **av; { vchar_t *buf; - struct admin_com *head; char *user; size_t userlen; @@ -844,22 +750,46 @@ f_logoutusr(ac, av) if ((user == NULL) || (userlen > LOGINLEN)) errx(1, "bad login (too long?)"); - buf = vmalloc(sizeof(*head) + userlen); + buf = make_request(ADMIN_LOGOUT_USER, 0, userlen); if (buf == NULL) return NULL; - head = (struct admin_com *)buf->v; - head->ac_len = buf->l; - head->ac_cmd = ADMIN_LOGOUT_USER; - head->ac_errno = 0; - head->ac_proto = 0; - - strncpy((char *)(head + 1), user, userlen); + strncpy(buf->v + sizeof(struct admin_com), user, userlen); return buf; } #endif /* ENABLE_HYBRID */ +static vchar_t * +get_proto_and_index(ac, av, proto) + int ac; + char **av; + u_int16_t *proto; +{ + vchar_t *index = NULL; + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + *proto = get_proto(*av); + if (*proto == (u_int16_t) -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (*proto) { + case ADMIN_PROTO_ISAKMP: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + break; + default: + errno = EPROTONOSUPPORT; + break; + } + return index; +} static int get_proto(str) @@ -1337,84 +1267,32 @@ print_schedule(buf, len) void -print_evt(buf, len) - caddr_t buf; - int len; +print_evt(evtdump) + struct evt_async *evtdump; { - 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); + for (i = 0; i < sizeof(evtmsg) / sizeof(evtmsg[0]); i++) + if (evtmsg[i].type == evtdump->ec_type) + break; + + if (evtmsg[i].msg == NULL) + printf("Event %d: ", evtdump->ec_type); else printf("%s : ", evtmsg[i].msg); - if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL) + if ((srcstr = saddr2str((struct sockaddr *)&evtdump->ec_ph1src)) == NULL) printf("unknown"); - else + else printf("%s", srcstr); printf(" -> "); - if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL) + if ((dststr = saddr2str((struct sockaddr *)&evtdump->ec_ph1dst)) == NULL) printf("unknown"); - else + 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; } /* @@ -1425,15 +1303,14 @@ print_cfg(buf, len) caddr_t buf; int len; { - struct evtdump *evtdump = (struct evtdump *)buf; + struct evt_async *evtdump = (struct evt_async *)buf; struct isakmp_data *attr; char *banner = NULL; struct in_addr addr4; memset(&addr4, 0, sizeof(addr4)); - if (evtdump->type != EVTT_ISAKMP_CFG_DONE && - evtdump->type != EVTT_NO_ISAKMP_CFG) + if (evtdump->ec_type != EVT_PHASE1_MODE_CFG) return; len -= sizeof(*evtdump); @@ -1486,12 +1363,12 @@ print_cfg(buf, len) (n + sizeof(*attr) + ntohs(attr->lorv)); } } - - if (evtdump->type == EVTT_ISAKMP_CFG_DONE) + + if (len > 0) printf("Bound to address %s\n", inet_ntoa(addr4)); else printf("VPN connexion established\n"); - + if (banner) { struct winsize win; int col = 0; @@ -1508,13 +1385,8 @@ print_cfg(buf, len) printf("\n"); racoon_free(banner); } - - if (evt_filter & EVTF_CFG_STOP) - evt_filter &= ~EVTF_LOOP; - - return; } - + char * fixed_addr(addr, port, len) @@ -1549,49 +1421,54 @@ static int handle_recv(combuf) vchar_t *combuf; { - struct admin_com h, *com; + struct admin_com *com; caddr_t buf; int len; com = (struct admin_com *)combuf->v; - len = com->ac_len - sizeof(*com); + if (com->ac_cmd & ADMIN_FLAG_LONG_REPLY) + len = ((u_int32_t)com->ac_len) + (((u_int32_t)com->ac_len_high) << 16); + else + len = com->ac_len; + len -= sizeof(*com); buf = combuf->v + sizeof(*com); - switch (com->ac_cmd) { + switch (com->ac_cmd & ~ADMIN_FLAG_LONG_REPLY) { case ADMIN_SHOW_SCHED: print_schedule(buf, len); break; case ADMIN_SHOW_EVT: { - struct evtdump *evtdump; + struct evt_async *ec; - /* 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; + /* We got no event? */ + if (len == 0) 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 (len < sizeof(struct evt_async)) + errx(1, "Short buffer\n"); - 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); + ec = (struct evt_async *) buf; + if (evt_quit_event <= 0) + print_evt(ec); + else if (evt_quit_event == ec->ec_type) { + switch (ec->ec_type) { + case EVT_PHASE1_MODE_CFG: + print_cfg(ec, len); + break; + default: + print_evt(ec); + break; + } + evt_quit_event = 0; + } break; } + case ADMIN_GET_SA_CERT: + fwrite(buf, len, 1, stdout); + break; + case ADMIN_SHOW_SA: { switch (com->ac_proto) { @@ -1645,10 +1522,8 @@ handle_recv(combuf) break; } - close(so); return 0; - bad: - close(so); +bad: return -1; } diff --git a/src/racoon/remoteconf.c b/src/racoon/remoteconf.c index c9c803f..74e386c 100644 --- a/src/racoon/remoteconf.c +++ b/src/racoon/remoteconf.c @@ -1,11 +1,11 @@ -/* $NetBSD: remoteconf.c,v 1.9.4.2 2008/06/18 07:30:19 mgrooms Exp $ */ +/* $NetBSD: remoteconf.c,v 1.26 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: remoteconf.c,v 1.38 2006/05/06 15:52: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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -63,6 +63,7 @@ #endif #include "isakmp.h" #include "ipsec_doi.h" +#include "crypto_openssl.h" #include "oakley.h" #include "remoteconf.h" #include "localconf.h" @@ -75,16 +76,307 @@ #include "algorithm.h" #include "nattraversal.h" #include "isakmp_frag.h" +#include "handler.h" #include "genlist.h" +#include "rsalist.h" -static TAILQ_HEAD(_rmtree, remoteconf) rmtree, rmtree_save, rmtree_tmp; +typedef TAILQ_HEAD(_rmtree, remoteconf) remoteconf_tailq_head_t; +static remoteconf_tailq_head_t rmtree, rmtree_save; -/* +/* * Script hook names and script hook paths */ -char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" }; +char *script_names[SCRIPT_MAX + 1] = { + "phase1_up", "phase1_down", "phase1_dead" }; /*%%%*/ + +int +rmconf_match_identity(rmconf, id_p) + struct remoteconf *rmconf; + vchar_t *id_p; +{ + struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *) id_p->v; + struct sockaddr *sa; + caddr_t sa1, sa2; + vchar_t ident; + struct idspec *id; + struct genlist_entry *gpb; + + /* compare with the ID if specified. */ + if (!genlist_next(rmconf->idvl_p, 0)) + return 0; + + for (id = genlist_next(rmconf->idvl_p, &gpb); id; id = genlist_next(0, &gpb)) { + /* No ID specified in configuration, so it is ok */ + if (id->id == 0) + return 0; + + /* check the type of both IDs */ + if (id->idtype != doi2idtype(id_b->type)) + continue; /* ID type mismatch */ + + /* compare defined ID with the ID sent by peer. */ + switch (id->idtype) { + case IDTYPE_ASN1DN: + ident.v = id_p->v + sizeof(*id_b); + ident.l = id_p->l - sizeof(*id_b); + if (eay_cmp_asn1dn(id->id, &ident) == 0) + return 0; + break; + case IDTYPE_ADDRESS: + sa = (struct sockaddr *)id->id->v; + sa2 = (caddr_t)(id_b + 1); + switch (sa->sa_family) { + case AF_INET: + if (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) + return 0; + break; +#ifdef INET6 + case AF_INET6: + if (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) + return 0; + break; +#endif + default: + break; + } + break; + default: + if (memcmp(id->id->v, id_b + 1, id->id->l) == 0) + return 0; + break; + } + } + + plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n"); + if (rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + + return 0; +} + +static int +rmconf_match_etype_and_approval(rmconf, etype, approval) + struct remoteconf *rmconf; + int etype; + struct isakmpsa *approval; +{ + struct isakmpsa *p; + + if (check_etypeok(rmconf, (void *) (intptr_t) etype) == 0) + return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + + if (approval == NULL) + return 0; + + if (etype == ISAKMP_ETYPE_AGG && + approval->dh_group != rmconf->dh_group) + return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + + if (checkisakmpsa(rmconf->pcheck_level, approval, + rmconf->proposal) == NULL) + return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + + return 0; +} + +enum rmconf_match_t { + MATCH_NONE = 0, + MATCH_BASIC = 0x0000001, + MATCH_ADDRESS = 0x0000002, + MATCH_SA = 0x0000004, + MATCH_IDENTITY = 0x0000008, + MATCH_AUTH_IDENTITY = 0x0000010, +}; + +static int +rmconf_match_type(rmsel, rmconf) + struct rmconfselector *rmsel; + struct remoteconf *rmconf; +{ + int ret = MATCH_NONE, tmp; + + /* No match at all: unwanted anonymous */ + if ((rmsel->flags & GETRMCONF_F_NO_ANONYMOUS) && + rmconf->remote->sa_family == AF_UNSPEC){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: Anonymous conf.\n"); + return MATCH_NONE; + } + + if ((rmsel->flags & GETRMCONF_F_NO_PASSIVE) && rmconf->passive){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: passive conf.\n"); + return MATCH_NONE; + } + + ret |= MATCH_BASIC; + + /* Check address */ + if (rmsel->remote != NULL) { + if (rmconf->remote->sa_family != AF_UNSPEC) { + if (cmpsaddr(rmsel->remote, rmconf->remote) == CMPSADDR_MISMATCH){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: address mismatch.\n"); + return MATCH_NONE; + } + + /* Address matched */ + ret |= MATCH_ADDRESS; + } + } + + /* Check etype and approval */ + if (rmsel->etype != ISAKMP_ETYPE_NONE) { + tmp=rmconf_match_etype_and_approval(rmconf, rmsel->etype, + rmsel->approval); + if (tmp != 0){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: etype (%d)/approval mismatch (%d).\n", rmsel->etype, tmp); + return MATCH_NONE; + } + ret |= MATCH_SA; + } + + /* Check identity */ + if (rmsel->identity != NULL && rmconf->verify_identifier) { + if (rmconf_match_identity(rmconf, rmsel->identity) != 0){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: identity mismatch.\n"); + return MATCH_NONE; + } + ret |= MATCH_IDENTITY; + } + + /* Check certificate request */ + if (rmsel->certificate_request != NULL) { + if (oakley_get_certtype(rmsel->certificate_request) != + oakley_get_certtype(rmconf->mycert)){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: cert type mismatch.\n"); + return MATCH_NONE; + } + + if (rmsel->certificate_request->l > 1) { + vchar_t *issuer; + + issuer = eay_get_x509asn1issuername(rmconf->mycert); + if (rmsel->certificate_request->l - 1 != issuer->l || + memcmp(rmsel->certificate_request->v + 1, + issuer->v, issuer->l) != 0) { + vfree(issuer); + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: cert issuer mismatch.\n"); + return MATCH_NONE; + } + vfree(issuer); + } else { + if (!rmconf->match_empty_cr){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched: empty certificate request.\n"); + return MATCH_NONE; + } + } + + ret |= MATCH_AUTH_IDENTITY; + } + + return ret; +} + +void rmconf_selector_from_ph1(rmsel, iph1) + struct rmconfselector *rmsel; + struct ph1handle *iph1; +{ + memset(rmsel, 0, sizeof(*rmsel)); + rmsel->flags = 0; + rmsel->remote = iph1->remote; + rmsel->etype = iph1->etype; + rmsel->approval = iph1->approval; + rmsel->identity = iph1->id_p; + rmsel->certificate_request = iph1->cr_p; +} + +int +enumrmconf(rmsel, enum_func, enum_arg) + struct rmconfselector *rmsel; + int (* enum_func)(struct remoteconf *rmconf, void *arg); + void *enum_arg; +{ + struct remoteconf *p; + int ret = 0; + + RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) { + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Checking remote conf \"%s\" %s.\n", p->name, + p->remote->sa_family == AF_UNSPEC ? + "anonymous" : saddr2str(p->remote)); + + if (rmsel != NULL) { + if (rmconf_match_type(rmsel, p) == MATCH_NONE){ + plog(LLV_DEBUG2, LOCATION, rmsel->remote, + "Not matched.\n"); + continue; + } + } + + plog(LLV_DEBUG2, LOCATION, NULL, + "enumrmconf: \"%s\" matches.\n", p->name); + + ret = (*enum_func)(p, enum_arg); + if (ret) + break; + } + + return ret; +} + +struct rmconf_find_context { + struct rmconfselector sel; + + struct remoteconf *rmconf; + int match_type; + int num_found; +}; + +static int +rmconf_find(rmconf, ctx) + struct remoteconf *rmconf; + void *ctx; +{ + struct rmconf_find_context *fctx = (struct rmconf_find_context *) ctx; + int match_type; + + /* First matching remote conf? */ + match_type = rmconf_match_type(&fctx->sel, rmconf); + + if (fctx->rmconf != NULL) { + /* More ambiguous matches are ignored. */ + if (match_type < fctx->match_type) + return 0; + + if (match_type == fctx->match_type) { + /* Ambiguous match */ + fctx->num_found++; + return 0; + } + } + + /* More exact match found */ + fctx->match_type = match_type; + fctx->num_found = 1; + fctx->rmconf = rmconf; + + return 0; +} + /* * search remote configuration. * don't use port number to search if its value is either IPSEC_PORT_ANY. @@ -93,76 +385,110 @@ char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" }; * OUT: NULL: NG * Other: remote configuration entry. */ + struct remoteconf * -getrmconf_strict(remote, allow_anon) +getrmconf(remote, flags) struct sockaddr *remote; - int allow_anon; + int flags; { - 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. - */ - if (remote->sa_family != AF_UNSPEC && - extract_port(remote) != IPSEC_PORT_ANY) - withport = 1; -#endif /* ENABLE_NATT */ + struct rmconf_find_context ctx; + int n = 0; - 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; - } + memset(&ctx, 0, sizeof(ctx)); + ctx.sel.flags = flags; + ctx.sel.remote = remote; - /* save the pointer to the anonymous configuration */ - if (p->remote->sa_family == AF_UNSPEC) - anon = p; + if (enumrmconf(&ctx.sel, rmconf_find, &ctx) != 0) { + plog(LLV_ERROR, LOCATION, remote, + "multiple exact configurations.\n"); + return NULL; } - if (allow_anon && anon != NULL) { - plog(LLV_DEBUG, LOCATION, NULL, - "anonymous configuration selected for %s.\n", buf); - return anon; + if (ctx.rmconf == NULL) { + plog(LLV_DEBUG, LOCATION, remote, + "no remote configuration found.\n"); + return NULL; } - plog(LLV_DEBUG, LOCATION, NULL, - "no remote configuration found.\n"); + if (ctx.num_found != 1) { + plog(LLV_DEBUG, LOCATION, remote, + "multiple non-exact configurations found.\n"); + return NULL; + } - return NULL; + plog(LLV_DEBUG, LOCATION, remote, + "configuration \"%s\" selected.\n", + ctx.rmconf->name); + + return ctx.rmconf; } struct remoteconf * -getrmconf(remote) - struct sockaddr *remote; +getrmconf_by_ph1(iph1) + struct ph1handle *iph1; { - return getrmconf_strict(remote, 1); + struct rmconf_find_context ctx; + + memset(&ctx, 0, sizeof(ctx)); + rmconf_selector_from_ph1(&ctx.sel, iph1); + if (loglevel >= LLV_DEBUG) { + char *idstr = NULL; + + if (iph1->id_p != NULL) + idstr = ipsecdoi_id2str(iph1->id_p); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "getrmconf_by_ph1: remote %s, identity %s.\n", + saddr2str(iph1->remote), idstr ? idstr : "<any>"); + + if (idstr) + racoon_free(idstr); + } + + if (enumrmconf(&ctx.sel, rmconf_find, &ctx) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "multiple exact configurations.\n"); + return RMCONF_ERR_MULTIPLE; + } + + if (ctx.rmconf == NULL) { + plog(LLV_DEBUG, LOCATION, iph1->remote, + "no remote configuration found\n"); + return NULL; + } + + if (ctx.num_found != 1) { + plog(LLV_DEBUG, LOCATION, iph1->remote, + "multiple non-exact configurations found.\n"); + return RMCONF_ERR_MULTIPLE; + } + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "configuration \"%s\" selected.\n", + ctx.rmconf->name); + + return ctx.rmconf; +} + +struct remoteconf * +getrmconf_by_name(name) + const char *name; +{ + struct remoteconf *p; + + plog(LLV_DEBUG, LOCATION, NULL, + "getrmconf_by_name: remote \"%s\".\n", + name); + + RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) { + if (p->name == NULL) + continue; + + if (strcmp(name, p->name) == 0) + return p; + } + + return NULL; } struct remoteconf * @@ -191,19 +517,14 @@ newrmconf() 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->certtype = ISAKMP_CERT_NONE; new->cacertfile = NULL; new->send_cert = TRUE; new->send_cr = TRUE; + new->match_empty_cr = FALSE; new->support_proxy = FALSE; for (i = 0; i <= SCRIPT_MAX; i++) new->script[i] = NULL; new->gen_policy = FALSE; - new->retry_counter = lcconf->retry_counter; - new->retry_interval = lcconf->retry_interval; new->nat_traversal = FALSE; new->rsa_private = genlist_init(); new->rsa_public = genlist_init(); @@ -215,34 +536,21 @@ newrmconf() new->dpd_retry = 5; new->dpd_maxfails = 5; + new->rekey = REKEY_ON; + new->weak_phase1_check = 0; #ifdef ENABLE_HYBRID new->xauth = NULL; #endif - 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); + new->lifetime = oakley_get_defaultlifetime(); return new; } +#ifndef ANDROID_PATCHED + void * dupidvl(entry, arg) void *entry; @@ -264,29 +572,147 @@ dupidvl(entry, arg) return NULL; } +void * +duprsa(entry, arg) + void *entry; + void *arg; +{ + struct rsa_key *new; + + new = rsa_key_dup((struct rsa_key *)entry); + if (new == NULL) + return (void *) -1; + genlist_append(arg, new); + + /* keep genlist_foreach going */ + return NULL; +} + +/* Creates shallow copy of a remote config. Used for "inherit" keyword. */ struct remoteconf * -duprmconf (rmconf) +duprmconf_shallow (rmconf) struct remoteconf *rmconf; { struct remoteconf *new; + struct proposalspec *prspec; 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); + + memcpy(new, rmconf, sizeof(*new)); + new->name = NULL; + new->inherited_from = rmconf; + + new->proposal = NULL; /* will be filled by set_isakmp_proposal() */ return new; } +/* Copies pointer structures of an inherited remote config. + * Used by "inherit" mechanism in a two step copy method, necessary to + * prevent both double free() and memory leak during config reload. + */ +int +duprmconf_finish (new) + struct remoteconf *new; +{ + struct remoteconf *rmconf; + int i; + + if (new->inherited_from == NULL) + return 0; /* nothing todo, no inheritance */ + + rmconf = new->inherited_from; + + /* duplicate dynamic structures unless value overridden */ + if (new->etypes != NULL && new->etypes == rmconf->etypes) + new->etypes = dupetypes(new->etypes); + if (new->idvl_p == rmconf->idvl_p) { + new->idvl_p = genlist_init(); + genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p); + } + + if (new->rsa_private == rmconf->rsa_private) { + new->rsa_private = genlist_init(); + genlist_foreach(rmconf->rsa_private, duprsa, new->rsa_private); + } + if (new->rsa_public == rmconf->rsa_public) { + new->rsa_public = genlist_init(); + genlist_foreach(rmconf->rsa_public, duprsa, new->rsa_public); + } + if (new->remote != NULL && new->remote == rmconf->remote) { + new->remote = racoon_malloc(sizeof(*new->remote)); + if (new->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "duprmconf_finish: malloc failed (remote)\n"); + exit(1); + } + memcpy(new->remote, rmconf->remote, sizeof(*new->remote)); + } + if (new->spspec != NULL && new->spspec == rmconf->spspec) { + dupspspec_list(new, rmconf); + } + + /* proposal has been deep copied already from spspec's, see + * cfparse.y:set_isakmp_proposal, which in turn calls + * cfparse.y:expand_isakmpspec where the copying happens. + */ + +#ifdef ENABLE_HYBRID + if (new->xauth != NULL && new->xauth == rmconf->xauth) { + new->xauth = xauth_rmconf_dup(new->xauth); + if (new->xauth == NULL) + exit(1); + } +#endif + + /* duplicate strings unless value overridden */ + if (new->mycertfile != NULL && new->mycertfile == rmconf->mycertfile) { + new->mycertfile = racoon_strdup(new->mycertfile); + STRDUP_FATAL(new->mycertfile); + } + if (new->myprivfile != NULL && new->myprivfile == rmconf->myprivfile) { + new->myprivfile = racoon_strdup(new->myprivfile); + STRDUP_FATAL(new->myprivfile); + } + if (new->peerscertfile != NULL && new->peerscertfile == rmconf->peerscertfile) { + new->peerscertfile = racoon_strdup(new->peerscertfile); + STRDUP_FATAL(new->peerscertfile); + } + if (new->cacertfile != NULL && new->cacertfile == rmconf->cacertfile) { + new->cacertfile = racoon_strdup(new->cacertfile); + STRDUP_FATAL(new->cacertfile); + } + if (new->idv != NULL && new->idv == rmconf->idv) { + new->idv = vdup(new->idv); + STRDUP_FATAL(new->idv); + } + if (new->key != NULL && new->key == rmconf->key) { + new->key = vdup(new->key); + STRDUP_FATAL(new->key); + } + if (new->mycert != NULL && new->mycert == rmconf->mycert) { + new->mycert = vdup(new->mycert); + STRDUP_FATAL(new->mycert); + } + if (new->peerscert != NULL && new->peerscert == rmconf->peerscert) { + new->peerscert = vdup(new->peerscert); + STRDUP_FATAL(new->peerscert); + } + if (new->cacert != NULL && new->cacert == rmconf->cacert) { + new->cacert = vdup(new->cacert); + STRDUP_FATAL(new->cacert); + } + for (i = 0; i <= SCRIPT_MAX; i++) + if (new->script[i] != NULL && new->script[i] == rmconf->script[i]) { + new->script[i] = vdup(new->script[i]); + STRDUP_FATAL(new->script[i]); + } + + return 0; +} + static void idspec_free(void *data) { @@ -298,6 +724,8 @@ void delrmconf(rmconf) struct remoteconf *rmconf; { + int i; + #ifdef ENABLE_HYBRID if (rmconf->xauth) xauth_rmconf_delete(&rmconf->xauth); @@ -306,15 +734,55 @@ delrmconf(rmconf) deletypes(rmconf->etypes); rmconf->etypes=NULL; } + if (rmconf->idv) + vfree(rmconf->idv); + if (rmconf->key) + vfree(rmconf->key); 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); + flushspspec(rmconf); + if (rmconf->mycert) + vfree(rmconf->mycert); + if (rmconf->mycertfile) + racoon_free(rmconf->mycertfile); + if (rmconf->myprivfile) + racoon_free(rmconf->myprivfile); + if (rmconf->peerscert) + vfree(rmconf->peerscert); + if (rmconf->peerscertfile) + racoon_free(rmconf->peerscertfile); + if (rmconf->cacert) + vfree(rmconf->cacert); + if (rmconf->cacertfile) + racoon_free(rmconf->cacertfile); + if (rmconf->rsa_private) + genlist_free(rmconf->rsa_private, rsa_key_free); + if (rmconf->rsa_public) + genlist_free(rmconf->rsa_public, rsa_key_free); + if (rmconf->name) + racoon_free(rmconf->name); + if (rmconf->remote) + racoon_free(rmconf->remote); + for (i = 0; i <= SCRIPT_MAX; i++) + if (rmconf->script[i]) + vfree(rmconf->script[i]); + racoon_free(rmconf); } +#else + +void delrmconf(struct remoteconf *rmconf) +{ + exit(1); +} + +#endif + void delisakmpsa(sa) struct isakmpsa *sa; @@ -336,11 +804,11 @@ dupetypes(orig) { struct etypes *new; - if (!orig) + if (!orig) return NULL; new = racoon_malloc(sizeof(struct etypes)); - if (new == NULL) + if (new == NULL) return NULL; new->type = orig->type; @@ -368,6 +836,14 @@ void insrmconf(new) struct remoteconf *new; { + if (new->name == NULL) { + new->name = racoon_strdup(saddr2str(new->remote)); + } + if (new->remote == NULL) { + new->remote = newsaddr(sizeof(struct sockaddr)); + new->remote->sa_family = AF_UNSPEC; + } + TAILQ_INSERT_HEAD(&rmtree, new, chain); } @@ -397,15 +873,17 @@ initrmconf() } void -save_rmconf() +rmconf_start_reload() { rmtree_save=rmtree; initrmconf(); } void -save_rmconf_flush() +rmconf_finish_reload() { + remoteconf_tailq_head_t rmtree_tmp; + rmtree_tmp=rmtree; rmtree=rmtree_save; flushrmconf(); @@ -416,19 +894,22 @@ save_rmconf_flush() /* check exchange type to be acceptable */ -struct etypes * -check_etypeok(rmconf, etype) +int +check_etypeok(rmconf, ctx) struct remoteconf *rmconf; - u_int8_t etype; + void *ctx; { + u_int8_t etype = (u_int8_t) (intptr_t) ctx; struct etypes *e; for (e = rmconf->etypes; e != NULL; e = e->next) { if (e->type == etype) - break; + return 1; + plog(LLV_DEBUG2, LOCATION, NULL, + "Etype mismatch: got %d, expected %d.\n", e->type, etype); } - return e; + return 0; } /*%%%*/ @@ -448,7 +929,6 @@ newisakmpsa() new->vendorid = VENDORID_UNKNOWN; new->next = NULL; - new->rmconf = NULL; #ifdef HAVE_GSSAPI new->gssid = NULL; #endif @@ -466,8 +946,6 @@ insisakmpsa(new, rmconf) { struct isakmpsa *p; - new->rmconf = rmconf; - if (rmconf->proposal == NULL) { rmconf->proposal = new; return; @@ -476,21 +954,6 @@ insisakmpsa(new, rmconf) 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; - RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) { - ret = (*rmconf_func)(p, data); - if (ret) - break; - } - - return ret; } static void * @@ -507,7 +970,7 @@ dump_peers_identifiers (void *entry, void *arg) return NULL; } -static struct remoteconf * +static int dump_rmconf_single (struct remoteconf *p, void *data) { struct etypes *etype = p->etypes; @@ -515,10 +978,11 @@ dump_rmconf_single (struct remoteconf *p, void *data) char buf[1024], *pbuf; pbuf = buf; - pbuf += sprintf(pbuf, "remote %s", saddr2str(p->remote)); + + pbuf += sprintf(pbuf, "remote \"%s\"", p->name); if (p->inherited_from) - pbuf += sprintf(pbuf, " inherit %s", - saddr2str(p->inherited_from->remote)); + pbuf += sprintf(pbuf, " inherit \"%s\"", + p->inherited_from->name); plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf); pbuf = buf; pbuf += sprintf(pbuf, "\texchange_type "); @@ -533,23 +997,30 @@ dump_rmconf_single (struct remoteconf *p, void *data) pbuf += sprintf(pbuf, "\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"); + plog(LLV_INFO, LOCATION, NULL, + "\tcertificate_type %s \"%s\" \"%s\";\n", + oakley_get_certtype(p->mycert) == ISAKMP_CERT_X509SIGN + ? "x509" : "*UNKNOWN*", + p->mycertfile, p->myprivfile); + + switch (oakley_get_certtype(p->peerscert)) { + case ISAKMP_CERT_NONE: + plog(LLV_INFO, LOCATION, NULL, + "\t/* peers certificate from payload */\n"); + break; + case ISAKMP_CERT_X509SIGN: + plog(LLV_INFO, LOCATION, NULL, + "\tpeers_certfile \"%s\";\n", p->peerscertfile); break; - case ISAKMP_GETCERT_LOCALFILE: - plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile); + case ISAKMP_CERT_DNS: + plog(LLV_INFO, LOCATION, NULL, + "\tpeers_certfile dnssec;\n"); break; - case ISAKMP_GETCERT_DNS: - plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n"); + default: + plog(LLV_INFO, LOCATION, NULL, + "\tpeers_certfile *UNKNOWN* (%d)\n", + oakley_get_certtype(p->peerscert)); break; - default: - plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method); } } else { @@ -559,10 +1030,14 @@ dump_rmconf_single (struct remoteconf *p, void *data) genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL); } + plog(LLV_INFO, LOCATION, NULL, "\trekey %s;\n", + p->rekey == REKEY_FORCE ? "force" : s_switch (p->rekey)); 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, "\tmatch_empty_cr %s;\n", + s_switch (p->match_empty_cr)); plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n", s_switch (p->verify_cert)); plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n", @@ -588,9 +1063,8 @@ dump_rmconf_single (struct remoteconf *p, void *data) 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)); + "\t/* prop_no=%d, trns_no=%d */\n", + prop->prop_no, prop->trns_no); plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n"); plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n", (long)prop->lifetime); @@ -598,11 +1072,11 @@ dump_rmconf_single (struct remoteconf *p, void *data) 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", + 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", + 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", + 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; @@ -610,13 +1084,13 @@ dump_rmconf_single (struct remoteconf *p, void *data) plog(LLV_INFO, LOCATION, NULL, "}\n"); plog(LLV_INFO, LOCATION, NULL, "\n"); - return NULL; + return 0; } void dumprmconf() { - foreachrmconf (dump_rmconf_single, NULL); + enumrmconf(NULL, dump_rmconf_single, NULL); } struct idspec * @@ -671,25 +1145,115 @@ script_path_add(path) struct isakmpsa * dupisakmpsa(struct isakmpsa *sa) { - struct isakmpsa *res=NULL; + struct isakmpsa *res = NULL; if(sa == NULL) return NULL; - res=newisakmpsa(); + res = newisakmpsa(); if(res == NULL) return NULL; - *res=*sa; + *res = *sa; #ifdef HAVE_GSSAPI - /* XXX gssid - */ + if (sa->gssid != NULL) + res->gssid = vdup(sa->gssid); #endif - res->next=NULL; + res->next = NULL; if(sa->dhgrp != NULL) - oakley_setdhgroup (sa->dh_group, &(res->dhgrp)); + oakley_setdhgroup(sa->dh_group, &res->dhgrp); return res; } + +#ifdef ENABLE_HYBRID +int +isakmpsa_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; + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_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_DSSSIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_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 + +/* + * Given a proposed ISAKMP SA, and a list of acceptable + * ISAKMP SAs, it compares using pcheck_level policy and + * returns first match (if any). + */ +struct isakmpsa * +checkisakmpsa(pcheck_level, proposal, acceptable) + int pcheck_level; + struct isakmpsa *proposal, *acceptable; +{ + struct isakmpsa *p; + + for (p = acceptable; p != NULL; p = p->next){ + plog(LLV_DEBUG2, LOCATION, NULL, + "checkisakmpsa:\nauthmethod: %d / %d\n", + isakmpsa_switch_authmethod(proposal->authmethod), isakmpsa_switch_authmethod(p->authmethod)); + if (isakmpsa_switch_authmethod(proposal->authmethod) != isakmpsa_switch_authmethod(p->authmethod) || + proposal->enctype != p->enctype || + proposal->dh_group != p->dh_group || + proposal->hashtype != p->hashtype) + continue; + + switch (pcheck_level) { + case PROP_CHECK_OBEY: + break; + + case PROP_CHECK_CLAIM: + case PROP_CHECK_STRICT: + if (proposal->encklen < p->encklen || +#if 0 + proposal->lifebyte > p->lifebyte || +#endif + proposal->lifetime > p->lifetime) + continue; + break; + + case PROP_CHECK_EXACT: + if (proposal->encklen != p->encklen || +#if 0 + proposal->lifebyte != p->lifebyte || +#endif + proposal->lifetime != p->lifetime) + continue; + break; + + default: + continue; + } + + return p; + } + + return NULL; +} diff --git a/src/racoon/remoteconf.h b/src/racoon/remoteconf.h index ca5945e..3ebe004 100644 --- a/src/racoon/remoteconf.h +++ b/src/racoon/remoteconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: remoteconf.h,v 1.7 2006/10/03 08:01:56 vanhu Exp $ */ +/* $NetBSD: remoteconf.h,v 1.16 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: remoteconf.h,v 1.26 2006/05/06 15:52:44 manubsd Exp */ @@ -43,20 +43,49 @@ #include "isakmp_xauth.h" #endif -struct proposalspec; +struct ph1handle; +struct secprotospec; struct etypes { int type; struct etypes *next; }; +/* 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 */ +}; + +/* Certificate information */ +struct rmconf_cert { + vchar_t *data; /* certificate payload */ + char *filename; /* name of local file */ +}; + /* Script hooks */ #define SCRIPT_PHASE1_UP 0 #define SCRIPT_PHASE1_DOWN 1 -#define SCRIPT_MAX 1 +#define SCRIPT_PHASE1_DEAD 2 +#define SCRIPT_MAX 2 extern char *script_names[SCRIPT_MAX + 1]; struct remoteconf { + char *name; /* remote configuration name */ struct sockaddr *remote; /* remote IP address */ /* if family is AF_UNSPEC, that is * for anonymous configuration. */ @@ -71,16 +100,17 @@ struct remoteconf { vchar_t *key; /* my pre-shared key */ struct genlist *idvl_p; /* peer's identifiers list */ - int certtype; /* certificate type if need */ - char *mycertfile; /* file name of my certificate */ char *myprivfile; /* file name of my private key file */ + char *mycertfile; /* file name of my certificate */ + vchar_t *mycert; /* my certificate */ char *peerscertfile; /* file name of peer's certifcate */ - int getcert_method; /* the way to get peer's certificate */ - int cacerttype; /* CA type is needed */ + vchar_t *peerscert; /* peer's certificate */ char *cacertfile; /* file name of CA */ - int getcacert_method; /* the way to get the CA */ + vchar_t *cacert; /* CA certificate */ + int send_cert; /* send to CERT or not */ int send_cr; /* send to CR or not */ + int match_empty_cr; /* does this match if CR is empty */ int verify_cert; /* verify a CERT strictly */ int verify_identifier; /* vefify the peer's identifier */ int nonce_size; /* the number of bytes of nonce */ @@ -89,9 +119,9 @@ struct remoteconf { int esp_frag; /* ESP fragmentation */ int mode_cfg; /* Gets config through mode config */ int support_proxy; /* support mip6/proxy */ -#define GENERATE_POLICY_NONE 0 -#define GENERATE_POLICY_REQUIRE 1 -#define GENERATE_POLICY_UNIQUE 2 +#define GENERATE_POLICY_NONE 0 +#define GENERATE_POLICY_REQUIRE 1 +#define GENERATE_POLICY_UNIQUE 2 int gen_policy; /* generate policy if no policy found */ int ini_contact; /* initial contact */ int pcheck_level; /* level of propocl checking */ @@ -101,16 +131,17 @@ struct remoteconf { 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; + int dpd_maxfails; + + int rekey; /* rekey ph1 when active ph2s? */ +#define REKEY_OFF FALSE +#define REKEY_ON TRUE +#define REKEY_FORCE 2 - int ph1id; /* ph1id to be matched with sainfo sections */ + uint32_t ph1id; /* ph1id to be matched with sainfo sections */ int weak_phase1_check; /* act on unencrypted deletions ? */ @@ -118,7 +149,10 @@ struct remoteconf { struct remoteconf *inherited_from; /* the original rmconf from which this one was inherited */ - struct proposalspec *prhead; + + time_t lifetime; /* for isakmp/ipsec */ + int lifebyte; /* for isakmp/ipsec */ + struct secprotospec *spspec; /* the head is always current spec. */ struct genlist *rsa_private, /* lists of PlainRSA keys to use */ *rsa_public; @@ -130,62 +164,75 @@ struct remoteconf { 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 */ +#define RMCONF_NONCE_SIZE(rmconf) \ + (rmconf != NULL ? rmconf->nonce_size : DEFAULT_NONCE_SIZE) - struct isakmpsa *next; /* next transform */ - struct remoteconf *rmconf; /* backpointer to remoteconf */ -}; +struct dhgroup; struct idspec { int idtype; /* identifier type */ vchar_t *id; /* identifier */ }; -typedef struct remoteconf * (rmconf_func_t)(struct remoteconf *rmconf, void *data); +struct rmconfselector { + int flags; + struct sockaddr *remote; + int etype; + struct isakmpsa *approval; + vchar_t *identity; + vchar_t *certificate_request; +}; + +extern void rmconf_selector_from_ph1 __P((struct rmconfselector *rmsel, + struct ph1handle *iph1)); +extern int enumrmconf __P((struct rmconfselector *rmsel, + int (* enum_func)(struct remoteconf *rmconf, void *arg), + void *enum_arg)); + +#define GETRMCONF_F_NO_ANONYMOUS 0x0001 +#define GETRMCONF_F_NO_PASSIVE 0x0002 + +#define RMCONF_ERR_MULTIPLE ((struct remoteconf *) -1) + +extern int rmconf_match_identity __P((struct remoteconf *rmconf, + vchar_t *id_p)); +extern struct remoteconf *getrmconf __P((struct sockaddr *remote, int flags)); +extern struct remoteconf *getrmconf_by_ph1 __P((struct ph1handle *iph1)); +extern struct remoteconf *getrmconf_by_name __P((const char *name)); -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 struct remoteconf *duprmconf_shallow __P((struct remoteconf *)); +extern int duprmconf_finish __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 dupspspec_list __P((struct remoteconf *, struct remoteconf *)); +extern void flushspspec __P((struct remoteconf *)); extern void initrmconf __P((void)); -extern void save_rmconf __P((void)); -extern void save_rmconf_flush __P((void)); +extern void rmconf_start_reload __P((void)); +extern void rmconf_finish_reload __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 int check_etypeok __P((struct remoteconf *, void *)); extern struct isakmpsa *newisakmpsa __P((void)); extern struct isakmpsa *dupisakmpsa __P((struct isakmpsa *)); - +extern void delisakmpsa __P((struct isakmpsa *)); extern void insisakmpsa __P((struct isakmpsa *, struct remoteconf *)); +#ifdef ENABLE_HYBRID +extern int isakmpsa_switch_authmethod __P((int authmethod)); +#else +static inline int isakmpsa_switch_authmethod(int authmethod) +{ + return authmethod; +} +#endif +extern struct isakmpsa * checkisakmpsa __P((int pcheck, + struct isakmpsa *proposal, + struct isakmpsa *acceptable)); + extern void dumprmconf __P((void)); diff --git a/src/racoon/rsalist.c b/src/racoon/rsalist.c index 850aa4c..f152c82 100644 --- a/src/racoon/rsalist.c +++ b/src/racoon/rsalist.c @@ -1,4 +1,4 @@ -/* $NetBSD: rsalist.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: rsalist.c,v 1.6 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: rsalist.c,v 1.3 2004/11/08 12:04:23 ludvigm Exp */ @@ -88,6 +88,65 @@ rsa_key_insert(struct genlist *list, struct netaddr *src, return 0; } +struct rsa_key * +rsa_key_dup(struct rsa_key *key) +{ + struct rsa_key *new; + + new = calloc(sizeof(struct rsa_key), 1); + if (new == NULL) + return NULL; + + if (key->rsa) { + new->rsa = key->rsa->d != NULL ? RSAPrivateKey_dup(key->rsa) : RSAPublicKey_dup(key->rsa); + if (new->rsa == NULL) + goto dup_error; + } + + if (key->src) { + new->src = malloc(sizeof(*new->src)); + if (new->src == NULL) + goto dup_error; + memcpy(new->src, key->src, sizeof(*new->src)); + } + if (key->dst) { + new->dst = malloc(sizeof(*new->dst)); + if (new->dst == NULL) + goto dup_error; + memcpy(new->dst, key->dst, sizeof(*new->dst)); + } + + return new; + +dup_error: + if (new->rsa != NULL) + RSA_free(new->rsa); + if (new->dst != NULL) + free(new->dst); + if (new->src != NULL) + free(new->src); + + free(new); + return NULL; +} + +void +rsa_key_free(void *data) +{ + struct rsa_key *rsa_key; + + + rsa_key = (struct rsa_key *)data; + if (rsa_key->src) + free(rsa_key->src); + if (rsa_key->dst) + free(rsa_key->dst); + if (rsa_key->rsa) + RSA_free(rsa_key->rsa); + + free(rsa_key); +} + static void * rsa_key_dump_one(void *entry, void *arg) { diff --git a/src/racoon/rsalist.h b/src/racoon/rsalist.h index 911670f..bc6a8d9 100644 --- a/src/racoon/rsalist.h +++ b/src/racoon/rsalist.h @@ -1,4 +1,4 @@ -/* $NetBSD: rsalist.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: rsalist.h,v 1.6 2011/03/14 15:50:36 vanhu Exp $ */ /* Id: rsalist.h,v 1.2 2004/07/12 20:43:51 ludvigm Exp */ /* @@ -53,6 +53,8 @@ struct rsa_key { }; int rsa_key_insert(struct genlist *list, struct netaddr *src, struct netaddr *dst, RSA *rsa); +struct rsa_key *rsa_key_dup(struct rsa_key *key); +void rsa_key_free(void *data); void rsa_key_dump(struct genlist *list); struct genlist *rsa_lookup_keys(struct ph1handle *iph1, int my); diff --git a/src/racoon/sainfo.c b/src/racoon/sainfo.c index afa0aac..b6577c2 100644 --- a/src/racoon/sainfo.c +++ b/src/racoon/sainfo.c @@ -1,4 +1,4 @@ -/* $NetBSD: sainfo.c,v 1.7.6.1 2007/08/01 11:52:22 vanhu Exp $ */ +/* $NetBSD: sainfo.c,v 1.14 2011/02/02 15:21:34 vanhu Exp $ */ /* $KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $ */ @@ -64,7 +64,8 @@ #include "sainfo.h" #include "gcmalloc.h" -static LIST_HEAD(_sitree, sainfo) sitree, sitree_save, sitree_tmp; +typedef LIST_HEAD(_sitree, sainfo) sainfo_tailq_head_t; +static sainfo_tailq_head_t sitree, sitree_save; /* %%% * modules for ipsec sa info @@ -76,88 +77,112 @@ static LIST_HEAD(_sitree, sainfo) sitree, sitree_save, sitree_tmp; * First pass is for sainfo from a specified peer, second for others. */ struct sainfo * -getsainfo(loc, rmt, peer, remoteid) - const vchar_t *loc, *rmt, *peer; - int remoteid; +getsainfo(loc, rmt, peer, client, remoteid) + const vchar_t *loc, *rmt, *peer, *client; + uint32_t remoteid; { struct sainfo *s = NULL; - struct sainfo *anonymous = NULL; - int pass = 1; - - if (peer == NULL) - pass = 2; /* debug level output */ if(loglevel >= LLV_DEBUG) { char *dloc, *drmt, *dpeer, *dclient; - + if (loc == NULL) dloc = strdup("ANONYMOUS"); else dloc = ipsecdoi_id2str(loc); - - if (rmt == NULL) + + if (rmt == SAINFO_ANONYMOUS) drmt = strdup("ANONYMOUS"); + else if (rmt == SAINFO_CLIENTADDR) + drmt = strdup("CLIENTADDR"); else drmt = ipsecdoi_id2str(rmt); - + if (peer == NULL) dpeer = strdup("NULL"); else dpeer = ipsecdoi_id2str(peer); - + + if (client == NULL) + dclient = strdup("NULL"); + else + dclient = ipsecdoi_id2str(client); + plog(LLV_DEBUG, LOCATION, NULL, - "getsainfo params: loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%i\n", - dloc, drmt, dpeer, remoteid ); + "getsainfo params: loc=\'%s\' rmt=\'%s\' peer=\'%s\' client=\'%s\' id=%u\n", + dloc, drmt, dpeer, dclient, remoteid ); racoon_free(dloc); racoon_free(drmt); racoon_free(dpeer); + racoon_free(dclient); } - again: - plog(LLV_DEBUG, LOCATION, NULL, - "getsainfo pass #%i\n", pass); - LIST_FOREACH(s, &sitree, chain) { const char *sainfostr = sainfo2str(s); plog(LLV_DEBUG, LOCATION, NULL, "evaluating sainfo: %s\n", sainfostr); - if(s->remoteid != remoteid) - continue; - - if (s->id_i != NULL) { - if (pass == 2) + if(s->remoteid != remoteid) { + plog(LLV_DEBUG, LOCATION, NULL, + "remoteid mismatch: %u != %u\n", + s->remoteid, remoteid); continue; + } + + /* compare 'from' id value */ + if (s->id_i != NULL) if (ipsecdoi_chkcmpids(peer, s->id_i, 0)) continue; - } else if (pass == 1) - continue; - if (s->idsrc == NULL && s->iddst == NULL) { - anonymous = s; - continue; - } - /* anonymous ? */ - if (loc == NULL) { - if (anonymous != NULL) - break; + /* compare ids - client */ + if( s->iddst == SAINFO_CLIENTADDR ) { + /* + * This sainfo section enforces client address + * checking. Prevent match if the client value + * ( modecfg or tunnel address ) is NULL. + */ + + if (client == NULL) + continue; + + if( rmt == SAINFO_CLIENTADDR ) { + /* + * In the case where a supplied rmt value is + * also SAINFO_CLIENTADDR, we are comparing + * with another sainfo to check for duplicate. + * Only compare the local values to determine + * a match. + */ + + if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0)) + return s; + } + else { + /* + * In the case where a supplied rmt value is + * not SAINFO_CLIENTADDR, do a standard match + * for local values and enforce that the rmt + * id matches the client address value. + */ + + if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && + !ipsecdoi_chkcmpids(rmt, client, 0)) + return s; + } + continue; } - /* compare the ids */ + + /* compare ids - standard */ if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && !ipsecdoi_chkcmpids(rmt, s->iddst, 0)) return s; } - if ((anonymous == NULL) && (pass == 1)) { - pass++; - goto again; - } - - return anonymous; + return NULL; } struct sainfo * @@ -186,7 +211,8 @@ delsainfo(si) if (si->idsrc) vfree(si->idsrc); - if (si->iddst) + if (si->iddst != NULL && + si->iddst != SAINFO_CLIENTADDR) vfree(si->iddst); #ifdef ENABLE_HYBRID @@ -197,11 +223,75 @@ delsainfo(si) racoon_free(si); } +int prisainfo(s) + struct sainfo *s; +{ + /* + * determine the matching priority + * of an sainfo section + */ + + int pri = 0; + + if(s->remoteid) + pri += 3; + + if(s->id_i) + pri += 3; + + if(s->idsrc) + pri++; + + if(s->iddst) + pri++; + + return pri; +} + void inssainfo(new) struct sainfo *new; { - LIST_INSERT_HEAD(&sitree, new, chain); + if(LIST_EMPTY(&sitree)) { + + /* first in list */ + LIST_INSERT_HEAD(&sitree, new, chain); + } + else { + int npri, spri; + struct sainfo *s, *n; + + /* + * insert our new sainfo section + * into our list which is sorted + * based on the match priority + */ + + npri = prisainfo(new); + + s = LIST_FIRST(&sitree); + while (1) { + + spri = prisainfo(s); + n = LIST_NEXT(s, chain); + + if(npri > spri) + { + /* higher priority */ + LIST_INSERT_BEFORE(s, new, chain); + return; + } + + if(n == NULL) + { + /* last in list */ + LIST_INSERT_AFTER(s, new, chain); + return; + } + + s = n; + } + } } void @@ -276,13 +366,15 @@ sainfo2str(si) char *idloc = NULL, *idrmt = NULL, *id_i; - if (si->idsrc == NULL) + if (si->idsrc == SAINFO_ANONYMOUS) idloc = strdup("ANONYMOUS"); else idloc = ipsecdoi_id2str(si->idsrc); - if (si->iddst == NULL) + if (si->iddst == SAINFO_ANONYMOUS) idrmt = strdup("ANONYMOUS"); + else if (si->iddst == SAINFO_CLIENTADDR) + idrmt = strdup("CLIENTADDR"); else idrmt = ipsecdoi_id2str(si->iddst); @@ -291,7 +383,7 @@ sainfo2str(si) else id_i = ipsecdoi_id2str(si->id_i); - snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%i", + snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u", idloc, idrmt, id_i, si->remoteid); racoon_free(idloc); @@ -301,12 +393,14 @@ sainfo2str(si) return buf; } -void save_sainfotree(void){ +void sainfo_start_reload(void){ sitree_save=sitree; initsainfo(); } -void save_sainfotree_flush(void){ +void sainfo_finish_reload(void){ + sainfo_tailq_head_t sitree_tmp; + sitree_tmp=sitree; sitree=sitree_save; flushsainfo(); diff --git a/src/racoon/sainfo.h b/src/racoon/sainfo.h index 357da3f..e708cd6 100644 --- a/src/racoon/sainfo.h +++ b/src/racoon/sainfo.h @@ -1,4 +1,4 @@ -/* $NetBSD: sainfo.h,v 1.5 2006/10/03 08:01:56 vanhu Exp $ */ +/* $NetBSD: sainfo.h,v 1.8 2011/02/02 15:21:34 vanhu Exp $ */ /* Id: sainfo.h,v 1.5 2006/07/09 17:19:38 manubsd Exp */ @@ -36,6 +36,9 @@ #include <sys/queue.h> +#define SAINFO_ANONYMOUS ((void *)NULL) +#define SAINFO_CLIENTADDR ((void *)~0) + /* SA info */ struct sainfo { vchar_t *idsrc; @@ -44,6 +47,7 @@ struct sainfo { * idsrc and iddst are constructed body of ID payload. * that is (struct ipsecdoi_id_b) + ID value. * If idsrc == NULL, that is anonymous entry. + * If idsrc == ~0, that is client address entry. */ #ifdef ENABLE_HYBRID @@ -56,7 +60,7 @@ struct sainfo { vchar_t *id_i; /* identifier of the authorized initiator */ struct sainfoalg *algs[MAXALGCLASS]; - int remoteid; + uint32_t remoteid; LIST_ENTRY(sainfo) chain; }; @@ -69,7 +73,7 @@ struct sainfoalg { }; extern struct sainfo *getsainfo __P((const vchar_t *, - const vchar_t *, const vchar_t *, int)); + const vchar_t *, const vchar_t *, const vchar_t *, uint32_t)); extern struct sainfo *newsainfo __P((void)); extern void delsainfo __P((struct sainfo *)); extern void inssainfo __P((struct sainfo *)); @@ -81,8 +85,8 @@ extern void delsainfoalg __P((struct sainfoalg *)); extern void inssainfoalg __P((struct sainfoalg **, struct sainfoalg *)); extern const char * sainfo2str __P((const struct sainfo *)); -extern void save_sainfotree __P((void)); -extern void save_sainfotree_flush __P((void)); +extern void sainfo_start_reload __P((void)); +extern void sainfo_finish_reload __P((void)); extern void save_sainfotree_restore __P((void)); #endif /* _SAINFO_H */ diff --git a/src/racoon/samples/roadwarrior/client/phase1-down.sh b/src/racoon/samples/roadwarrior/client/phase1-down.sh index 8edc187..92f2ba8 100755 --- a/src/racoon/samples/roadwarrior/client/phase1-down.sh +++ b/src/racoon/samples/roadwarrior/client/phase1-down.sh @@ -8,10 +8,10 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin case `uname -s` in NetBSD) - DEFAULT_GW=`netstat -rn | awk '($1 == "default"){print $2}'` + DEFAULT_GW=`netstat -finet -rn | awk '($1 == "default"){print $2; exit}'` ;; Linux) - DEFAULT_GW=`netstat -rn | awk '($1 == "0.0.0.0"){print $2}'` + DEFAULT_GW=`netstat --inet -rn | awk '($1 == "0.0.0.0"){print $2; exit}'` ;; esac @@ -21,24 +21,29 @@ echo "LOCAL_PORT = ${LOCAL_PORT}" echo "REMOTE_ADDR = ${REMOTE_ADDR}" echo "REMOTE_PORT = ${REMOTE_PORT}" echo "DEFAULT_GW = ${DEFAULT_GW}" +echo "INTERNAL_NETMASK4 = ${INTERNAL_NETMASK4}" echo "INTERNAL_ADDR4 = ${INTERNAL_ADDR4}" echo "INTERNAL_DNS4 = ${INTERNAL_DNS4}" echo ${INTERNAL_ADDR4} | grep '[0-9]' > /dev/null || exit 0 +echo ${INTERNAL_NETMASK4} | grep '[0-9]' > /dev/null || exit 0 echo ${DEFAULT_GW} | grep '[0-9]' > /dev/null || exit 0 -test -f /etc/resolv.conf.bak && cp /etc/resolv.conf.bak /etc/resolv.conf +if [ -f /etc/resolv.conf.bak ]; then + rm -f /etc/resolv.conf + mv /etc/resolv.conf.bak /etc/resolv.conf +fi case `uname -s` in NetBSD) - if=`netstat -rn|awk '($1 == "default"){print $7}'` - ifconfig ${if} delete ${INTERNAL_ADDR4} + if=`netstat -finet -rn|awk '($1 == "default"){print $7; exit}'` route delete default route delete ${REMOTE_ADDR} + ifconfig ${if} delete ${INTERNAL_ADDR4} route add default ${DEFAULT_GW} -ifa ${LOCAL_ADDR} ;; Linux) - if=`netstat -rn|awk '($1 == "0.0.0.0"){print $8}'` + if=`netstat --inet -rn|awk '($1 == "0.0.0.0"){print $8; exit}'` route delete default route delete ${REMOTE_ADDR} ifconfig ${if}:1 del ${INTERNAL_ADDR4} @@ -54,13 +59,13 @@ Linux) ;; esac -# Use this for a NAT-T setup -LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]" -REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]" - -# Use this for a non NAT-T setup -#LOCAL="${LOCAL_ADDR}" -#REMOTE="${REMOTE_ADDR}" +LOCAL="${LOCAL_ADDR}" +REMOTE="${REMOTE_ADDR}" +if [ "x${LOCAL_PORT}" != "x500" ]; then + # NAT-T setup + LOCAL="${LOCAL}[${LOCAL_PORT}]" + REMOTE="${REMOTE}[${REMOTE_PORT}]" +fi echo " deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp; diff --git a/src/racoon/samples/roadwarrior/client/phase1-up.sh b/src/racoon/samples/roadwarrior/client/phase1-up.sh index e45b648..9275811 100755 --- a/src/racoon/samples/roadwarrior/client/phase1-up.sh +++ b/src/racoon/samples/roadwarrior/client/phase1-up.sh @@ -7,10 +7,10 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin case `uname -s` in NetBSD) - DEFAULT_GW=`netstat -rn | awk '($1 == "default"){print $2}'` + DEFAULT_GW=`netstat -finet -rn | awk '($1 == "default"){print $2; exit}'` ;; Linux) - DEFAULT_GW=`netstat -rn | awk '($1 == "0.0.0.0"){print $2}'` + DEFAULT_GW=`netstat --inet -rn | awk '($1 == "0.0.0.0"){print $2; exit}'` ;; esac @@ -21,25 +21,28 @@ echo "REMOTE_ADDR = ${REMOTE_ADDR}" echo "REMOTE_PORT = ${REMOTE_PORT}" echo "DEFAULT_GW = ${DEFAULT_GW}" echo "INTERNAL_ADDR4 = ${INTERNAL_ADDR4}" +echo "INTERNAL_NETMASK4 = ${INTERNAL_NETMASK4}" echo "INTERNAL_DNS4 = ${INTERNAL_DNS4}" echo ${INTERNAL_ADDR4} | grep '[0-9]' > /dev/null || exit 0 +echo ${INTERNAL_NETMASK4} | grep '[0-9]' > /dev/null || exit 0 echo ${DEFAULT_GW} | grep '[0-9]' > /dev/null || exit 0 -test -f /etc/resolv.conf.bak || cp /etc/resolv.conf /etc/resolv.conf.bak -echo "# Generated by racoon on `date`" > /etc/resolv.conf +mv /etc/resolv.conf /etc/resolv.conf.bak +( umask 22; touch /etc/resolv.conf ) +echo "# Generated by racoon on `date`" >> /etc/resolv.conf echo "nameserver ${INTERNAL_DNS4}" >> /etc/resolv.conf case `uname -s` in NetBSD) - if=`netstat -rn|awk '($1 == "default"){print $7}'` + if=`netstat -finet -rn|awk '($1 == "default"){print $7; exit}'` ifconfig ${if} alias ${INTERNAL_ADDR4} netmask ${INTERNAL_NETMASK4} route delete default route add default ${DEFAULT_GW} -ifa ${INTERNAL_ADDR4} route add ${REMOTE_ADDR} ${DEFAULT_GW} ;; Linux) - if=`netstat -rn|awk '($1 == "0.0.0.0"){print $8}'` + if=`netstat --inet -rn|awk '($1 == "0.0.0.0"){print $8; exit}'` ifconfig ${if}:1 ${INTERNAL_ADDR4} route delete default route add ${REMOTE_ADDR} gw ${DEFAULT_GW} dev ${if} @@ -47,13 +50,13 @@ Linux) ;; esac -# Use this for a NAT-T setup -LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]" -REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]" - -# Use this for a non NAT-T setup -#LOCAL="${LOCAL_ADDR}" -#REMOTE="${REMOTE_ADDR}" +LOCAL="${LOCAL_ADDR}" +REMOTE="${REMOTE_ADDR}" +if [ "x${LOCAL_PORT}" != "x500" ]; then + # NAT-T setup + LOCAL="${LOCAL}[${LOCAL_PORT}]" + REMOTE="${REMOTE}[${REMOTE_PORT}]" +fi echo " diff --git a/src/racoon/schedule.c b/src/racoon/schedule.c index 04723c5..018f920 100644 --- a/src/racoon/schedule.c +++ b/src/racoon/schedule.c @@ -1,9 +1,10 @@ -/* $NetBSD: schedule.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: schedule.c,v 1.7 2009/01/23 09:10:13 tteras Exp $ */ /* $KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * Copyright (C) 2008 Timo Teras. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +41,7 @@ #include <sys/socket.h> #include <stdlib.h> +#include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> @@ -51,25 +53,46 @@ #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; +static TAILQ_HEAD(_schedtree, sched) sctree; + +void +sched_get_monotonic_time(tv) + struct timeval *tv; +{ +#ifdef HAVE_CLOCK_MONOTONIC + struct timespec ts; -#ifdef FIXY2038PROBLEM -#define Y2038TIME_T 0x7fffffff -static time_t launched; /* time when the program launched. */ -static time_t deltaY2038; + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; +#else + gettimeofday(tv, NULL); #endif +} -static TAILQ_HEAD(_schedtree, sched) sctree; +time_t +sched_monotonic_to_time_t(tv, now) + struct timeval *tv, *now; +{ +#ifdef HAVE_CLOCK_MONOTONIC + struct timeval mynow, res; + + if (now == NULL) { + sched_get_monotonic_time(&mynow); + now = &mynow; + } + timersub(now, tv, &res); -static void sched_add __P((struct sched *)); -static time_t current_time __P((void)); + return time(NULL) + res.tv_sec; +#else + return tv->tv_sec; +#endif +} /* * schedule handler @@ -80,42 +103,26 @@ static time_t current_time __P((void)); 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 daed, 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; - } + static struct timeval timeout; + struct timeval now; + struct sched *p; - /* mark it with dead. and call the function. */ - p->dead = 1; - if (p->func != NULL) - (p->func)(p->param); + sched_get_monotonic_time(&now); + while (!TAILQ_EMPTY(&sctree) && + timercmp(&TAILQ_FIRST(&sctree)->xtime, &now, <=)) { + void (*func)(struct sched *); - next_schedule: - next = TAILQ_NEXT(p, chain); - TAILQ_REMOVE(&sctree, p, chain); - racoon_free(p); + p = TAILQ_FIRST(&sctree); + func = p->func; + sched_cancel(p); + func(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; + timersub(&p->xtime, &now, &timeout); return &timeout; } @@ -123,101 +130,46 @@ schedular() /* * add new schedule to schedule table. */ -struct sched * -sched_new(tick, func, param) +void +sched_schedule(sc, tick, func) + struct sched *sc; time_t tick; - void (*func) __P((void *)); - void *param; + void (*func) __P((struct sched *)); { 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; + struct sched *p; + struct timeval now; - new->id = id++; - time(&new->created); - new->tick = tick; + sched_cancel(sc); - new->xtime = current_time() + tick; - new->dead = 0; + sc->func = func; + sc->id = id++; + sc->tick.tv_sec = tick; + sc->tick.tv_usec = 0; + sched_get_monotonic_time(&now); + timeradd(&now, &sc->tick, &sc->xtime); /* 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 (timercmp(&sc->xtime, &p->xtime, <)) + break; } if (p == NULL) TAILQ_INSERT_TAIL(&sctree, sc, chain); - - return; + else + TAILQ_INSERT_BEFORE(p, sc, chain); } -/* get current time. - * if defined FIXY2038PROBLEM, base time is the time when called sched_init(). - * Otherwise, conform to time(3). +/* + * cancel scheduled callback */ -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) +sched_cancel(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); - } + if (sc->func != NULL) { + TAILQ_REMOVE(&sctree, sc, chain); + sc->func = NULL; } } @@ -232,6 +184,7 @@ sched_dump(buf, len) caddr_t new; struct sched *p; struct scheddump *dst; + struct timeval now, created; int cnt = 0; /* initialize */ @@ -252,12 +205,14 @@ sched_dump(buf, len) return -1; dst = (struct scheddump *)new; - p = TAILQ_FIRST(&sctree); + sched_get_monotonic_time(&now); + p = TAILQ_FIRST(&sctree); while (p) { - dst->xtime = p->xtime; + timersub(&p->xtime, &p->tick, &created); + dst->xtime = p->xtime.tv_sec; dst->id = p->id; - dst->created = p->created; - dst->tick = p->tick; + dst->created = sched_monotonic_to_time_t(&created, &now); + dst->tick = p->tick.tv_sec; p = TAILQ_NEXT(p, chain); if (p == NULL) @@ -274,15 +229,7 @@ sched_dump(buf, len) void sched_init() { -#ifdef FIXY2038PROBLEM - time(&launched); - - deltaY2038 = Y2038TIME_T - launched; -#endif - TAILQ_INIT(&sctree); - - return; } #ifdef STEST diff --git a/src/racoon/schedule.h b/src/racoon/schedule.h index bd66593..228e677 100644 --- a/src/racoon/schedule.h +++ b/src/racoon/schedule.h @@ -1,9 +1,10 @@ -/* $NetBSD: schedule.h,v 1.4.6.1 2007/03/21 14:29:48 vanhu Exp $ */ +/* $NetBSD: schedule.h,v 1.8 2009/08/17 12:00:53 vanhu Exp $ */ /* Id: schedule.h,v 1.5 2006/05/03 21:53:42 vanhu Exp */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * Copyright (C) 2008 Timo Teras. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,39 +35,47 @@ #ifndef _SCHEDULE_H #define _SCHEDULE_H +#include <stddef.h> + #include <sys/queue.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif #include "gnuc.h" +#ifndef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + + /* 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 */ - + void (*func) __P((struct sched *)); /* callback on timeout */ + struct timeval xtime; /* expiration time */ + struct timeval tick; /* relative timeout */ TAILQ_ENTRY(sched) chain; + long id; /* for debug */ }; -/* cancel schedule */ -#define SCHED_KILL(s) \ -do { \ - if(s != NULL){ \ - sched_kill(s); \ - s = NULL; \ - }\ -} while(0) - -/* must be called after it's called from scheduler. */ -#define SCHED_INIT(s) (s) = NULL +#define SCHED_INITIALIZER() { NULL, } struct scheddump { time_t xtime; @@ -75,11 +84,16 @@ struct scheddump { time_t tick; }; +time_t sched_monotonic_to_time_t __P((struct timeval *tv, + struct timeval *now)); +void sched_get_monotonic_time __P((struct timeval *tv)); + struct timeval *schedular __P((void)); -struct sched *sched_new __P((time_t, void (*func) __P((void *)), void *)); -void sched_kill __P((struct sched *)); +void sched_schedule __P((struct sched *, time_t, + void (*func) __P((struct sched *)))); +void sched_cancel __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/src/racoon/session.c b/src/racoon/session.c index 9db901d..85e29a3 100644 --- a/src/racoon/session.c +++ b/src/racoon/session.c @@ -1,11 +1,11 @@ -/* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */ +/* $NetBSD: session.c,v 1.32 2011/03/02 15:09:16 vanhu Exp $ */ /* $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: @@ -17,7 +17,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -59,6 +59,7 @@ #include <signal.h> #include <sys/stat.h> #include <paths.h> +#include <err.h> #include <netinet/in.h> #include <resolv.h> @@ -77,6 +78,8 @@ #include "evt.h" #include "cfparse_proto.h" #include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_var.h" #include "isakmp_xauth.h" #include "isakmp_cfg.h" #include "admin_var.h" @@ -88,80 +91,174 @@ #include "localconf.h" #include "remoteconf.h" #include "backupsa.h" +#include "remoteconf.h" #ifdef ENABLE_NATT #include "nattraversal.h" #endif - #include "algorithm.h" /* XXX ??? */ #include "sainfo.h" +struct fd_monitor { + int (*callback)(void *ctx, int fd); + void *ctx; + int prio; + int fd; + TAILQ_ENTRY(fd_monitor) chain; +}; + +#define NUM_PRIORITIES 2 + 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 int close_sockets __P((void)); -static fd_set mask0; -static fd_set maskdying; +static fd_set preset_mask, active_mask; +static struct fd_monitor fd_monitors[FD_SETSIZE]; +static TAILQ_HEAD(fd_monitor_list, fd_monitor) fd_monitor_tree[NUM_PRIORITIES]; static int nfds = 0; + static volatile sig_atomic_t sigreq[NSIG + 1]; -static int dying = 0; +static struct sched scflushsa = SCHED_INITIALIZER(); + +void +monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority) +{ + if (fd < 0 || fd >= FD_SETSIZE) { + plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun"); + exit(1); + } + + FD_SET(fd, &preset_mask); + if (fd > nfds) + nfds = fd; + if (priority <= 0) + priority = 0; + if (priority >= NUM_PRIORITIES) + priority = NUM_PRIORITIES - 1; + + fd_monitors[fd].callback = callback; + fd_monitors[fd].ctx = ctx; + fd_monitors[fd].prio = priority; + fd_monitors[fd].fd = fd; + TAILQ_INSERT_TAIL(&fd_monitor_tree[priority], + &fd_monitors[fd], chain); +} + +void +unmonitor_fd(int fd) +{ + if (fd < 0 || fd >= FD_SETSIZE) { + plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun"); + exit(1); + } + + if (fd_monitors[fd].callback == NULL) + return; + + FD_CLR(fd, &preset_mask); + FD_CLR(fd, &active_mask); + fd_monitors[fd].callback = NULL; + fd_monitors[fd].ctx = NULL; + TAILQ_REMOVE(&fd_monitor_tree[fd_monitors[fd].prio], + &fd_monitors[fd], chain); +} int session(void) { - fd_set rfds; struct timeval *timeout; int error; - struct myaddrs *p; char pid_file[MAXPATHLEN]; FILE *fp; pid_t racoon_pid = 0; - int i; + int i, count; + struct fd_monitor *fdm; + + nfds = 0; + FD_ZERO(&preset_mask); + + for (i = 0; i < NUM_PRIORITIES; i++) + TAILQ_INIT(&fd_monitor_tree[i]); /* initialize schedular */ sched_init(); - init_signal(); + if (pfkey_init() < 0) + errx(1, "failed to initialize pfkey socket"); + + if (isakmp_init() < 0) + errx(1, "failed to initialize ISAKMP structures"); + +#ifdef ENABLE_HYBRID + if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD)) + errx(1, "could not initialize ISAKMP mode config structures"); +#endif + +#ifdef HAVE_LIBLDAP + if (xauth_ldap_init_conf() != 0) + errx(1, "could not initialize ldap config"); +#endif + +#ifdef HAVE_LIBRADIUS + if (xauth_radius_init_conf(0) != 0) + errx(1, "could not initialize radius config"); +#endif + + myaddr_init_lists(); + + /* + * in order to prefer the parameters by command line, + * saving some parameters before parsing configuration file. + */ + save_params(); + if (cfparse() != 0) + errx(1, "failed to parse configuration file."); + restore_params(); + #ifdef ENABLE_ADMINPORT if (admin_init() < 0) - exit(1); + errx(1, "failed to initialize admin port socket"); #endif - initmyaddr(); - if (isakmp_init() < 0) - exit(1); +#ifdef ENABLE_HYBRID + if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0) + if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0) + return error; +#endif - initfds(); + if (dump_config) + dumprmconf(); -#ifdef ENABLE_NATT - natt_keepalive_init (); +#ifdef HAVE_LIBRADIUS + if (xauth_radius_init() != 0) + errx(1, "could not initialize libradius"); #endif - if (privsep_init() != 0) - exit(1); + if (myaddr_init() != 0) + errx(1, "failed to listen to configured addresses"); + myaddr_sync(); - for (i = 0; i <= NSIG; i++) - sigreq[i] = 0; +#ifdef ENABLE_NATT + natt_keepalive_init (); +#endif /* write .pid file */ - racoon_pid = getpid(); - if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) + if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN); - else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') + 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), @@ -170,19 +267,26 @@ session(void) 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) { - if (dying) - rfds = maskdying; - else - rfds = mask0; + if (privsep_init() != 0) + exit(1); + /* + * The fork()'ed privileged side will close its copy of fp. We wait + * until here to get the correct child pid. + */ + racoon_pid = getpid(); + fprintf(fp, "%ld\n", (long)racoon_pid); + fclose(fp); + + for (i = 0; i <= NSIG; i++) + sigreq[i] = 0; + + while (1) { /* * asynchronous requests via signal. * make sure to reset sigreq to 0. @@ -192,7 +296,11 @@ session(void) /* scheduling */ timeout = schedular(); - error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); + /* schedular can change select() mask, so we reset + * the working copy here */ + active_mask = preset_mask; + + error = select(nfds + 1, &active_mask, NULL, NULL, timeout); if (error < 0) { switch (errno) { case EINTR: @@ -206,28 +314,24 @@ session(void) /*NOTREACHED*/ } -#ifdef ENABLE_ADMINPORT - if ((lcconf->sock_admin != -1) && - (FD_ISSET(lcconf->sock_admin, &rfds))) - admin_handler(); -#endif - - for (p = lcconf->myaddrs; p; p = p->next) { - if (!p->addr) - continue; - if (FD_ISSET(p->sock, &rfds)) - isakmp_handler(p->sock); + count = 0; + for (i = 0; i < NUM_PRIORITIES; i++) { + TAILQ_FOREACH(fdm, &fd_monitor_tree[i], chain) { + if (!FD_ISSET(fdm->fd, &active_mask)) + continue; + + FD_CLR(fdm->fd, &active_mask); + if (fdm->callback != NULL) { + fdm->callback(fdm->ctx, fdm->fd); + count++; + } else + plog(LLV_ERROR, LOCATION, NULL, + "fd %d set, but no active callback\n", i); + } + if (count != 0) + break; } - if (FD_ISSET(lcconf->sock_pfkey, &rfds)) - pfkey_handler(); - - if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) { - if (update_myaddrs() && lcconf->autograbaddr) - check_rtsock(NULL); - else - initfds(); - } } } @@ -235,82 +339,18 @@ session(void) static void close_session() { -#ifdef ENABLE_FASTQUIT + evt_generic(EVT_RACOON_QUIT, NULL); + pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); flushph2(); -#endif flushph1(); + flushrmconf(); + flushsainfo(); close_sockets(); backupsa_clean(); - plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); - exit(0); -} + plog(LLV_INFO, LOCATION, NULL, "racoon process %d shutdown\n", getpid()); -static void -check_rtsock(unused) - void *unused; -{ - isakmp_close(); - grab_myaddrs(); - 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_ERROR, LOCATION, NULL, "fd_set overrun\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 - if (lcconf->sock_pfkey >= FD_SETSIZE) { - plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\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_ERROR, LOCATION, NULL, "fd_set overrun\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 >= FD_SETSIZE) { - plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n"); - exit(1); - } - FD_SET(p->sock, &mask0); - nfds = (nfds > p->sock ? nfds : p->sock); - } - nfds++; + exit(0); } static int signals[] = { @@ -331,10 +371,7 @@ 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]++; + sigreq[sig] = 1; } @@ -345,27 +382,28 @@ static void reload_conf(){ #ifdef ENABLE_HYBRID if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(LLV_ERROR, LOCATION, NULL, "ISAKMP mode config structure reset failed, " "not reloading\n"); return; } #endif - save_sainfotree(); + sainfo_start_reload(); /* TODO: save / restore / flush old lcconf (?) / rmtree */ -/* initlcconf();*/ /* racoon_conf ? ! */ + rmconf_start_reload(); - save_rmconf(); - initrmconf(); +#ifdef HAVE_LIBRADIUS + /* free and init radius configuration */ + xauth_radius_init_conf(1); +#endif + + pfkey_reload(); - /* Do a part of pfkey_init() ? - * SPD reload ? - */ - save_params(); + flushlcconf(); error = cfparse(); if (error != 0){ plog(LLV_ERROR, LOCATION, NULL, "config reload failed\n"); @@ -374,19 +412,17 @@ static void reload_conf(){ } restore_params(); -#if 0 +#if 0 if (dump_config) dumprmconf (); #endif - /* - * init_myaddr() ? - * If running in privilege separation, do not reinitialize - * the IKE listener, as we will not have the right to - * setsockopt(IP_IPSEC_POLICY). - */ - if (geteuid() == 0) - check_rtsock(NULL); + myaddr_sync(); + +#ifdef HAVE_LIBRADIUS + /* re-initialize radius state */ + xauth_radius_init(); +#endif /* Revalidate ph1 / ph2tree !!! * update ctdtree if removing some ph1 ! @@ -395,44 +431,33 @@ static void reload_conf(){ /* Update ctdtree ? */ - save_sainfotree_flush(); - save_rmconf_flush(); + sainfo_finish_reload(); + rmconf_finish_reload(); } static void check_sigreq() { - int sig; + int sig, s; - /* - * 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] = 0; - sigreq[sig]--; switch(sig) { case 0: return; - - /* Catch up childs, mainly scripts. - */ + case SIGCHLD: - { - pid_t pid; - int s; - - pid = wait(&s); - } - break; + /* Reap all pending children */ + while (waitpid(-1, &s, WNOHANG) > 0) + ; + break; #ifdef DEBUG_RECORD_MALLOCATION - /* - * XXX This operation is signal handler unsafe and may lead to + /* + * 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. @@ -448,108 +473,31 @@ check_sigreq() break; case SIGINT: - case SIGTERM: - plog(LLV_INFO, LOCATION, NULL, + 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); -#ifdef ENABLE_FASTQUIT close_session(); -#else - sched_new(1, check_flushsa_stub, NULL); -#endif - dying = 1; break; default: - plog(LLV_INFO, LOCATION, NULL, + 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(); -} - static void init_signal() { int i; + /* + * Ignore SIGPIPE as we check the return value of system calls + * that write to pipe-like fds. + */ + signal(SIGPIPE, SIG_IGN); + for (i = 0; signals[i] != 0; i++) if (set_signal(signals[i], signal_handler) < 0) { plog(LLV_ERROR, LOCATION, NULL, @@ -582,7 +530,7 @@ set_signal(sig, func) static int close_sockets() { - isakmp_close(); + myaddr_close(); pfkey_close(lcconf->sock_pfkey); #ifdef ENABLE_ADMINPORT (void)admin_close(); diff --git a/src/racoon/session.h b/src/racoon/session.h index 58799ee..7764c62 100644 --- a/src/racoon/session.h +++ b/src/racoon/session.h @@ -1,4 +1,4 @@ -/* $NetBSD: session.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: session.h,v 1.9 2010/10/21 06:15:28 tteras Exp $ */ /* Id: session.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp */ @@ -37,4 +37,7 @@ extern int session __P((void)); extern RETSIGTYPE signal_handler __P((int)); +extern void monitor_fd __P((int fd, int (*callback)(void *, int), void *ctx, int priority)); +extern void unmonitor_fd __P((int fd)); + #endif /* _SESSION_H */ diff --git a/src/racoon/sockmisc.c b/src/racoon/sockmisc.c index 16c949d..48bede1 100644 --- a/src/racoon/sockmisc.c +++ b/src/racoon/sockmisc.c @@ -1,4 +1,4 @@ -/* $NetBSD: sockmisc.c,v 1.8.6.1 2007/08/01 11:52:22 vanhu Exp $ */ +/* $NetBSD: sockmisc.c,v 1.19 2011/03/14 17:18:13 tteras Exp $ */ /* Id: sockmisc.c,v 1.24 2006/05/07 21:32:59 manubsd Exp */ @@ -56,75 +56,28 @@ #include "var.h" #include "misc.h" +#include "vmbuf.h" #include "plog.h" #include "sockmisc.h" #include "debug.h" #include "gcmalloc.h" #include "debugrm.h" #include "libpfkey.h" +#include "isakmp_var.h" -#ifndef IP_IPSEC_POLICY -#define IP_IPSEC_POLICY 16 /* XXX: from linux/in.h */ -#endif - -#ifndef IPV6_IPSEC_POLICY -#define IPV6_IPSEC_POLICY 34 /* XXX: from linux/???.h per - "Tom Lendacky" <toml@us.ibm.com> */ -#endif - -const int niflags = 0; - -/* - * compare two sockaddr without port number. - * OUT: 0: equal. - * 1: not equal. - */ -int -cmpsaddrwop(addr1, addr2) - const struct sockaddr *addr1; - const struct sockaddr *addr2; -{ - caddr_t sa1, sa2; - - if (addr1 == 0 && addr2 == 0) - return 0; - if (addr1 == 0 || addr2 == 0) - return 1; - -#ifdef __linux__ - if (addr1->sa_family != addr2->sa_family) - return 1; +#ifdef NOUSE_PRIVSEP +#define BIND bind +#define SOCKET socket +#define SETSOCKOPT setsockopt #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; +#include "admin.h" +#include "privsep.h" +#define BIND privsep_bind +#define SOCKET privsep_socket +#define SETSOCKOPT privsep_setsockopt #endif - default: - return 1; - } - return 0; -} +const int niflags = 0; /* * compare two sockaddr with port, taking care wildcard. @@ -133,40 +86,34 @@ cmpsaddrwop(addr1, addr2) * 1: not equal. */ int -cmpsaddrwild(addr1, addr2) +cmpsaddr(addr1, addr2) const struct sockaddr *addr1; const struct sockaddr *addr2; { caddr_t sa1, sa2; - u_short port1, port2; + u_short port1 = IPSEC_PORT_ANY; + u_short port2 = IPSEC_PORT_ANY; - if (addr1 == 0 && addr2 == 0) - return 0; - if (addr1 == 0 || addr2 == 0) - return 1; + if (addr1 == NULL && addr2 == NULL) + return CMPSADDR_MATCH; -#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; + if (addr1 == NULL || addr2 == NULL) + return CMPSADDR_MISMATCH; -#endif /* __linux__ */ + if (addr1->sa_family != addr2->sa_family || + sysdep_sa_len(addr1) != sysdep_sa_len(addr2)) + return CMPSADDR_MISMATCH; switch (addr1->sa_family) { + case AF_UNSPEC: + break; 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; + return CMPSADDR_MISMATCH; break; #ifdef INET6 case AF_INET6: @@ -174,89 +121,31 @@ cmpsaddrwild(addr1, addr2) 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; + return CMPSADDR_MISMATCH; if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != ((struct sockaddr_in6 *)addr2)->sin6_scope_id) - return 1; + return CMPSADDR_MISMATCH; break; #endif default: - return 1; + return CMPSADDR_MISMATCH; } - return 0; -} + if (port1 == port2) + return CMPSADDR_MATCH; -/* - * 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 (port1 == IPSEC_PORT_ANY || + port2 == IPSEC_PORT_ANY) + return CMPSADDR_WILDPORT_MATCH; - 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; + return CMPSADDR_WOP_MATCH; } #ifdef ANDROID_PATCHED struct sockaddr *getlocaladdr(struct sockaddr *remote) -{ +{ struct sockaddr_storage local; socklen_t len = sysdep_sa_len(remote); int s = socket(remote->sa_family, SOCK_DGRAM, 0); @@ -266,13 +155,12 @@ struct sockaddr *getlocaladdr(struct sockaddr *remote) return NULL; } close(s); - set_port((struct sockaddr *)&local, 0); return dupsaddr((struct sockaddr *)&local); } int recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen, struct sockaddr *to, unsigned int *tolen) -{ +{ *tolen = sizeof(struct sockaddr_storage); if (getsockname(s, to, (socklen_t *)tolen) == -1) { return -1; @@ -282,7 +170,7 @@ int recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, int sendfromto(int s, const void *buf, size_t len, struct sockaddr *from, struct sockaddr *to, int count) -{ +{ socklen_t tolen = sysdep_sa_len(to); int i; for (i = 0; i < count; ++i) { @@ -294,7 +182,7 @@ int sendfromto(int s, const void *buf, size_t len, struct sockaddr *from, } int setsockopt_bypass(int s, int family) -{ +{ struct sadb_x_policy p = { .sadb_x_policy_len = PFKEY_UNIT64(sizeof(struct sadb_x_policy)), .sadb_x_policy_exttype = SADB_X_EXT_POLICY, @@ -315,7 +203,7 @@ int setsockopt_bypass(int s, int family) } return 0; } - + #else /* get local address against the destination. */ @@ -335,7 +223,7 @@ getlocaladdr(remote) } /* get real interface received packet */ - if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) { + if ((s = SOCKET(remote->sa_family, SOCK_DGRAM, 0)) < 0) { plog(LLV_ERROR, LOCATION, NULL, "socket (%s)\n", strerror(errno)); goto err; @@ -382,8 +270,9 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) u_int *tolen; { int otolen; - u_int len; - struct sockaddr_storage ss; + socklen_t slen; + int len; + union sockaddr_any sa; struct msghdr m; struct cmsghdr *cm; struct iovec iov[2]; @@ -396,8 +285,8 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) struct sockaddr_in6 *sin6; #endif - len = sizeof(ss); - if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + slen = sizeof(sa); + if (getsockname(s, &sa.sa, &slen) < 0) { plog(LLV_ERROR, LOCATION, NULL, "getsockname (%s)\n", strerror(errno)); return -1; @@ -430,7 +319,7 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);) #endif #if defined(INET6) && defined(INET6_ADVAPI) - if (ss.ss_family == AF_INET6 + if (sa.sa.sa_family == AF_INET6 && cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && otolen >= sizeof(*sin6)) { @@ -449,14 +338,13 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) sin6->sin6_scope_id = pi->ipi6_ifindex; else sin6->sin6_scope_id = 0; - sin6->sin6_port = - ((struct sockaddr_in6 *)&ss)->sin6_port; + sin6->sin6_port = sa.sin6.sin6_port; otolen = -1; /* "to" already set */ continue; } #endif #ifdef __linux__ - if (ss.ss_family == AF_INET + if (sa.sa.sa_family == AF_INET && cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO && otolen >= sizeof(sin)) { @@ -467,14 +355,13 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) 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; + sin->sin_port = sa.sin.sin_port; otolen = -1; /* "to" already set */ continue; } #endif #if defined(INET6) && defined(IPV6_RECVDSTADDR) - if (ss.ss_family == AF_INET6 + if (sa.sa.sa_family == AF_INET6 && cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_RECVDSTADDR && otolen >= sizeof(*sin6)) { @@ -485,14 +372,13 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) 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; + sin6->sin6_port = sa.sin6.sin6_port; otolen = -1; /* "to" already set */ continue; } #endif #ifndef __linux__ - if (ss.ss_family == AF_INET + if (sa.sa.sa_family == AF_INET && cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR && otolen >= sizeof(*sin)) { @@ -503,7 +389,7 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) 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; + sin->sin_port = sa.sin.sin_port; otolen = -1; /* "to" already set */ continue; } @@ -523,7 +409,8 @@ sendfromto(s, buf, buflen, src, dst, cnt) struct sockaddr *dst; { struct sockaddr_storage ss; - u_int len; + socklen_t slen; + int len = 0; int i; if (src->sa_family != dst->sa_family) { @@ -532,8 +419,8 @@ sendfromto(s, buf, buflen, src, dst, cnt) return -1; } - len = sizeof(ss); - if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + slen = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &slen) < 0) { plog(LLV_ERROR, LOCATION, NULL, "getsockname (%s)\n", strerror(errno)); return -1; @@ -701,7 +588,7 @@ sendfromto(s, buf, buflen, src, dst, cnt) * Better approach is to prepare bind'ed udp sockets for * each of the interface addresses. */ - sendsock = socket(src->sa_family, SOCK_DGRAM, 0); + sendsock = SOCKET(src->sa_family, SOCK_DGRAM, 0); if (sendsock < 0) { plog(LLV_ERROR, LOCATION, NULL, "socket (%s)\n", strerror(errno)); @@ -736,7 +623,8 @@ sendfromto(s, buf, buflen, src, dst, cnt) return -1; } - if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) { + if (BIND(sendsock, (struct sockaddr *)src, + sysdep_sa_len(src)) < 0) { plog(LLV_ERROR, LOCATION, NULL, "bind 1 (%s)\n", strerror(errno)); close(sendsock); @@ -800,7 +688,7 @@ setsockopt_bypass(so, family) ipsec_strerror()); return -1; } - if (setsockopt(so, level, + if (SETSOCKOPT(so, level, (level == IPPROTO_IP ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), buf, ipsec_get_policylen(buf)) < 0) { @@ -819,7 +707,7 @@ setsockopt_bypass(so, family) ipsec_strerror()); return -1; } - if (setsockopt(so, level, + if (SETSOCKOPT(so, level, (level == IPPROTO_IP ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), buf, ipsec_get_policylen(buf)) < 0) { @@ -833,6 +721,8 @@ setsockopt_bypass(so, family) return 0; } +#endif + struct sockaddr * newsaddr(len) int len; @@ -858,8 +748,6 @@ out: return new; } -#endif - struct sockaddr * dupsaddr(src) struct sockaddr *src; @@ -1114,13 +1002,13 @@ naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr) free(a2); free(a3); } - if (cmpsaddrwop(&sa, &naddr->sa.sa) == 0) + if (cmpsaddr(&sa, &naddr->sa.sa) <= CMPSADDR_WOP_MATCH) return naddr->prefix + port_score; return -1; } -/* Some usefull functions for sockaddr port manipulations. */ +/* Some useful functions for sockaddr port manipulations. */ u_int16_t extract_port (const struct sockaddr *addr) { @@ -1130,6 +1018,8 @@ extract_port (const struct sockaddr *addr) return port; switch (addr->sa_family) { + case AF_UNSPEC: + break; case AF_INET: port = ((struct sockaddr_in *)addr)->sin_port; break; diff --git a/src/racoon/sockmisc.h b/src/racoon/sockmisc.h index a035dec..67bfdaf 100644 --- a/src/racoon/sockmisc.h +++ b/src/racoon/sockmisc.h @@ -1,4 +1,4 @@ -/* $NetBSD: sockmisc.h,v 1.7 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: sockmisc.h,v 1.13 2011/03/14 17:18:13 tteras Exp $ */ /* Id: sockmisc.h,v 1.9 2005/10/05 16:55:41 manubsd Exp */ @@ -34,26 +34,34 @@ #ifndef _SOCKMISC_H #define _SOCKMISC_H +#ifndef IP_IPSEC_POLICY +#define IP_IPSEC_POLICY 16 /* XXX: from linux/in.h */ +#endif + +#ifndef IPV6_IPSEC_POLICY +#define IPV6_IPSEC_POLICY 34 /* XXX: from linux/???.h per + "Tom Lendacky" <toml@us.ibm.com> */ +#endif + +union sockaddr_any { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; + struct netaddr { - union { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } sa; + union sockaddr_any 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 *)); +#define CMPSADDR_MATCH 0 +#define CMPSADDR_WILDPORT_MATCH 1 +#define CMPSADDR_WOP_MATCH 2 +#define CMPSADDR_MISMATCH 3 -#ifdef ENABLE_NATT -#define CMPSADDR(saddr1, saddr2) cmpsaddrstrict((saddr1), (saddr2)) -#else -#define CMPSADDR(saddr1, saddr2) cmpsaddrwop((saddr1), (saddr2)) -#endif +extern int cmpsaddr __P((const struct sockaddr *, const struct sockaddr *)); extern struct sockaddr *getlocaladdr __P((struct sockaddr *)); @@ -81,7 +89,7 @@ extern char *naddrwop2str_fromto __P((const char *format, const struct netaddr * const struct netaddr *daddr)); extern int naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr); -/* Some usefull functions for sockaddr port manipulations. */ +/* Some useful 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)); diff --git a/src/racoon/strnames.c b/src/racoon/strnames.c index fa5df0f..4906b33 100644 --- a/src/racoon/strnames.c +++ b/src/racoon/strnames.c @@ -1,4 +1,4 @@ -/* $NetBSD: strnames.c,v 1.7.6.1 2007/08/01 11:52:22 vanhu Exp $ */ +/* $NetBSD: strnames.c,v 1.9 2008/07/14 05:40:13 tteras Exp $ */ /* $KAME: strnames.c,v 1.25 2003/11/13 10:53:26 itojun Exp $ */ @@ -276,6 +276,8 @@ static struct ksmap name_isakmp_notify_msg[] = { { ISAKMP_NTYPE_RESPONDER_LIFETIME, "RESPONDER-LIFETIME", NULL }, { ISAKMP_NTYPE_REPLAY_STATUS, "REPLAY-STATUS", NULL }, { ISAKMP_NTYPE_INITIAL_CONTACT, "INITIAL-CONTACT", NULL }, +{ ISAKMP_NTYPE_R_U_THERE, "R-U-THERE", NULL }, +{ ISAKMP_NTYPE_R_U_THERE_ACK, "R-U-THERE-ACK", NULL }, #ifdef ENABLE_HYBRID { ISAKMP_NTYPE_UNITY_HEARTBEAT, "HEARTBEAT (Unity)", NULL }, #endif diff --git a/src/racoon/throttle.c b/src/racoon/throttle.c index cd7de1f..84a2d6b 100644 --- a/src/racoon/throttle.c +++ b/src/racoon/throttle.c @@ -1,4 +1,4 @@ -/* $NetBSD: throttle.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: throttle.c,v 1.7 2011/03/14 17:18:13 tteras Exp $ */ /* Id: throttle.c,v 1.5 2006/04/05 20:54:50 manubsd Exp */ @@ -33,23 +33,10 @@ #include "config.h" -#include <stdio.h> #include <stdlib.h> #include <string.h> -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif #include <sys/param.h> #include <sys/queue.h> -#include <sys/socket.h> - #include <netinet/in.h> #include <resolv.h> @@ -58,21 +45,21 @@ #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); - +static struct throttle_list throttle_list = + TAILQ_HEAD_INITIALIZER(throttle_list); struct throttle_entry * throttle_add(addr) struct sockaddr *addr; { struct throttle_entry *te; + struct timeval now, penalty; size_t len; len = sizeof(*te) @@ -82,7 +69,11 @@ throttle_add(addr) if ((te = racoon_malloc(len)) == NULL) return NULL; - te->penalty = time(NULL) + isakmp_cfg_config.auth_throttle; + sched_get_monotonic_time(&now); + penalty.tv_sec = isakmp_cfg_config.auth_throttle; + penalty.tv_usec = 0; + timeradd(&now, &penalty, &te->penalty_ends); + memcpy(&te->host, addr, sysdep_sa_len(addr)); TAILQ_INSERT_HEAD(&throttle_list, te, next); @@ -95,26 +86,25 @@ throttle_host(addr, authfail) int authfail; { struct throttle_entry *te; + struct timeval now, res; int found = 0; - time_t now; if (isakmp_cfg_config.auth_throttle == 0) return 0; - now = time(NULL); - + sched_get_monotonic_time(&now); restart: RACOON_TAILQ_FOREACH_REVERSE(te, &throttle_list, throttle_list, next) { - /* - * Remove outdated entries - */ - if (te->penalty < now) { + /* + * Remove outdated entries + */ + if (timercmp(&te->penalty_ends, &now, <)) { TAILQ_REMOVE(&throttle_list, te, next); racoon_free(te); goto restart; } - - if (cmpsaddrwop(addr, (struct sockaddr *)&te->host) == 0) { + + if (cmpsaddr(addr, (struct sockaddr *) &te->host) <= CMPSADDR_WOP_MATCH) { found = 1; break; } @@ -130,8 +120,7 @@ restart: if ((te = throttle_add(addr)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Throttle insertion failed\n"); - return (time(NULL) - + isakmp_cfg_config.auth_throttle); + return isakmp_cfg_config.auth_throttle; } } return 0; @@ -140,19 +129,21 @@ restart: * 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; + struct timeval remaining, penalty; + + timersub(&te->penalty_ends, &now, &remaining); + penalty.tv_sec = isakmp_cfg_config.auth_throttle; + penalty.tv_usec = 0; + timeradd(&penalty, &remaining, &res); + if (res.tv_sec >= THROTTLE_PENALTY_MAX) { + res.tv_sec = THROTTLE_PENALTY_MAX; + res.tv_usec = 0; + } + timeradd(&now, &res, &te->penalty_ends); } } - - return te->penalty; + + timersub(&te->penalty_ends, &now, &res); + return res.tv_sec; } diff --git a/src/racoon/throttle.h b/src/racoon/throttle.h index baa9af5..54a8ed1 100644 --- a/src/racoon/throttle.h +++ b/src/racoon/throttle.h @@ -1,4 +1,4 @@ -/* $NetBSD: throttle.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: throttle.h,v 1.5 2009/01/23 08:25:07 tteras Exp $ */ /* Id: throttle.h,v 1.1 2004/11/30 00:46:09 manubsd Exp */ @@ -34,8 +34,10 @@ #ifndef _THROTTLE_H #define _THROTTLE_H +#include "schedule.h" + struct throttle_entry { - int penalty; + struct timeval penalty_ends; TAILQ_ENTRY(throttle_entry) next; struct sockaddr_storage host; }; diff --git a/src/racoon/var.h b/src/racoon/var.h index 8abb1c2..2946a9f 100644 --- a/src/racoon/var.h +++ b/src/racoon/var.h @@ -1,4 +1,4 @@ -/* $NetBSD: var.h,v 1.4.6.1 2007/06/06 15:36:38 vanhu Exp $ */ +/* $NetBSD: var.h,v 1.5 2007/06/06 15:37:15 vanhu Exp $ */ /* Id: var.h,v 1.6 2004/11/20 16:16:59 monas Exp */ diff --git a/src/racoon/vendorid.c b/src/racoon/vendorid.c index 82ddfe4..81297bd 100644 --- a/src/racoon/vendorid.c +++ b/src/racoon/vendorid.c @@ -1,4 +1,4 @@ -/* $NetBSD: vendorid.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: vendorid.c,v 1.8 2009/09/01 12:22:09 tteras Exp $ */ /* Id: vendorid.c,v 1.10 2006/02/22 16:10:21 vanhu Exp */ @@ -53,6 +53,16 @@ #include "isakmp.h" #include "vendorid.h" #include "crypto_openssl.h" +#include "handler.h" +#include "remoteconf.h" +#ifdef ENABLE_NATT +#include "nattraversal.h" +#endif +#ifdef ENABLE_HYBRID +#include <resolv.h> +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" +#endif static struct vendor_id all_vendor_ids[] = { { VENDORID_IPSEC_TOOLS, "IPSec-Tools" }, @@ -205,7 +215,7 @@ set_vendorid(int vendorid) * * gen ... points to Vendor ID payload. */ -int +static int check_vendorid(struct isakmp_gen *gen) { vchar_t vid, *vidhash; @@ -238,6 +248,44 @@ unknown: return (VENDORID_UNKNOWN); } +int +handle_vendorid(struct ph1handle *iph1, struct isakmp_gen *gen) +{ + int vid_numeric; + + vid_numeric = check_vendorid(gen); + if (vid_numeric == VENDORID_UNKNOWN) + return vid_numeric; + + iph1->vendorid_mask |= BIT(vid_numeric); + +#ifdef ENABLE_NATT + if (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 == NULL || iph1->rmconf->dpd)) { + iph1->dpd_support = 1; + plog(LLV_DEBUG, LOCATION, NULL, "remote supports DPD\n"); + } +#endif + + return vid_numeric; +} + static vchar_t * vendorid_fixup(vendorid, vidhash) int vendorid; diff --git a/src/racoon/vendorid.h b/src/racoon/vendorid.h index 7e2dcda..1774575 100644 --- a/src/racoon/vendorid.h +++ b/src/racoon/vendorid.h @@ -1,4 +1,4 @@ -/* $NetBSD: vendorid.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: vendorid.h,v 1.6 2009/01/23 08:06:56 tteras Exp $ */ /* Id: vendorid.h,v 1.11 2006/02/17 14:09:10 vanhu Exp */ @@ -34,25 +34,26 @@ #ifndef _VENDORID_H #define _VENDORID_H -/* The unknown vendor ID. */ -#define VENDORID_UNKNOWN -1 +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif +/* The unknown vendor ID. */ +#define VENDORID_UNKNOWN -1 /* Our default vendor ID. */ -#define VENDORID_DEFAULT VENDORID_IPSEC_TOOLS +#define VENDORID_DEFAULT VENDORID_IPSEC_TOOLS -#define VENDORID_IPSEC_TOOLS 0 +#define VENDORID_IPSEC_TOOLS 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) +/* 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 VENDORID_GSSAPI_MASK (BIT(VENDORID_GSSAPI_LONG) | \ + BIT(VENDORID_GSSAPI) | \ + BIT(VENDORID_MS_NT5)) /* NAT-T support */ #define VENDORID_NATT_00 4 @@ -70,8 +71,7 @@ #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 ) +#define MAX_NATT_VID_COUNT (VENDORID_NATT_LAST - VENDORID_NATT_FIRST + 1) /* Hybrid auth */ #define VENDORID_XAUTH 15 @@ -88,8 +88,7 @@ * XXX: do some cleanup to have separate lists for "real" vendors (to complete) * and "features" VendorIDs */ -#define VENDORID_KAME 19 - +#define VENDORID_KAME 19 struct vendor_id { int id; @@ -98,7 +97,7 @@ struct vendor_id { }; vchar_t *set_vendorid __P((int)); -int check_vendorid __P((struct isakmp_gen *)); +int handle_vendorid __P((struct ph1handle *, struct isakmp_gen *)); void compute_vendorids __P((void)); const char *vid_string_by_id __P((int id)); |