diff options
Diffstat (limited to 'src')
105 files changed, 6430 insertions, 1771 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4d41ea9e5..e01ad84b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,31 @@ -SUBDIRS = include libfreeswan libcrypto libstrongswan pluto whack charon stroke starter openac scepclient ipsec _updown _updown_espmark _copyright +SUBDIRS = include + +if USE_FILE_CONFIG + SUBDIRS += libfreeswan starter ipsec _copyright +endif + +if USE_LIBSTRONGSWAN + SUBDIRS += libstrongswan +endif + +if USE_PLUTO + SUBDIRS += libcrypto pluto whack +endif +if USE_CHARON + SUBDIRS += charon +endif + +if USE_STROKE + SUBDIRS += stroke +endif + +if USE_PLUTO_OR_CHARON + SUBDIRS += _updown _updown_espmark +endif + +if USE_TOOLS + SUBDIRS += openac scepclient +endif if USE_UML SUBDIRS += dumm @@ -8,3 +35,16 @@ if USE_MANAGER SUBDIRS += manager endif +if USE_FILE_CONFIG +install-exec-local : + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/cacerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/ocspcerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/certs + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/acerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/aacerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/crls + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/reqs + mkdir -p -m 700 $(DESTDIR)$(confdir)/ipsec.d/private +endif + diff --git a/src/Makefile.in b/src/Makefile.in index aea3c7a2b..f2e6dcefe 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -31,8 +31,15 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@USE_UML_TRUE@am__append_1 = dumm -@USE_MANAGER_TRUE@am__append_2 = manager +@USE_FILE_CONFIG_TRUE@am__append_1 = libfreeswan starter ipsec _copyright +@USE_LIBSTRONGSWAN_TRUE@am__append_2 = libstrongswan +@USE_PLUTO_TRUE@am__append_3 = libcrypto pluto whack +@USE_CHARON_TRUE@am__append_4 = charon +@USE_STROKE_TRUE@am__append_5 = stroke +@USE_PLUTO_OR_CHARON_TRUE@am__append_6 = _updown _updown_espmark +@USE_TOOLS_TRUE@am__append_7 = openac scepclient +@USE_UML_TRUE@am__append_8 = dumm +@USE_MANAGER_TRUE@am__append_9 = manager subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -54,9 +61,9 @@ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = include libfreeswan libcrypto libstrongswan pluto whack \ - charon stroke starter openac scepclient ipsec _updown \ - _updown_espmark _copyright dumm manager +DIST_SUBDIRS = include libfreeswan starter ipsec _copyright \ + libstrongswan libcrypto pluto whack charon stroke _updown \ + _updown_espmark openac scepclient dumm manager DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -188,9 +195,9 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ -SUBDIRS = include libfreeswan libcrypto libstrongswan pluto whack \ - charon stroke starter openac scepclient ipsec _updown \ - _updown_espmark _copyright $(am__append_1) $(am__append_2) +SUBDIRS = include $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_7) $(am__append_8) $(am__append_9) all: all-recursive .SUFFIXES: @@ -433,6 +440,7 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." +@USE_FILE_CONFIG_FALSE@install-exec-local: clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am @@ -455,7 +463,7 @@ install-data-am: install-dvi: install-dvi-recursive -install-exec-am: +install-exec-am: install-exec-local install-html: install-html-recursive @@ -496,14 +504,25 @@ uninstall-am: distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs installdirs-am maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ - uninstall uninstall-am - + install-exec-am install-exec-local install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +@USE_FILE_CONFIG_TRUE@install-exec-local : +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/cacerts +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/ocspcerts +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/certs +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/acerts +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/aacerts +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/crls +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/reqs +@USE_FILE_CONFIG_TRUE@ mkdir -p -m 700 $(DESTDIR)$(confdir)/ipsec.d/private # 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/_updown/Makefile.am b/src/_updown/Makefile.am index d0b7a27a4..9fd592797 100644 --- a/src/_updown/Makefile.am +++ b/src/_updown/Makefile.am @@ -5,6 +5,7 @@ EXTRA_DIST = _updown.in _updown : _updown.in sed \ + -e "s:@IPSEC_SBINDIR@:$(sbindir):" \ -e "s:\@IPSEC_ROUTING_TABLE\@:$(IPSEC_ROUTING_TABLE):" \ -e "s:\@IPSEC_ROUTING_TABLE_PRIO\@:$(IPSEC_ROUTING_TABLE_PRIO):" \ $< > $@ diff --git a/src/_updown/Makefile.in b/src/_updown/Makefile.in index 21e38da5d..52f1109e5 100644 --- a/src/_updown/Makefile.in +++ b/src/_updown/Makefile.in @@ -425,6 +425,7 @@ uninstall-man: uninstall-man8 _updown : _updown.in sed \ + -e "s:@IPSEC_SBINDIR@:$(sbindir):" \ -e "s:\@IPSEC_ROUTING_TABLE\@:$(IPSEC_ROUTING_TABLE):" \ -e "s:\@IPSEC_ROUTING_TABLE_PRIO\@:$(IPSEC_ROUTING_TABLE_PRIO):" \ $< > $@ diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in index 4002449dd..cb0404b34 100644 --- a/src/_updown/_updown.in +++ b/src/_updown/_updown.in @@ -16,7 +16,7 @@ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # -# RCSID $Id: _updown.in 3268 2007-10-08 19:59:18Z andreas $ +# RCSID $Id: _updown.in 3389 2007-12-12 22:12:10Z andreas $ # CAUTION: Installing a new version of strongSwan will install a new # copy of this script, wiping out any custom changes you make. If @@ -118,6 +118,10 @@ # restricted on the peer side. # +# define a minimum PATH environment in case it is not set +PATH="/sbin:/bin:/usr/sbin:/usr/bin:@IPSEC_SBINDIR@" +export PATH + # uncomment to log VPN connections VPN_LOGGING=1 # @@ -372,11 +376,11 @@ up-host:iptables) # This is used only by the default updown script, not by your custom # ones, so do not mess with it; see CAUTION comment up at top. iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT # # log IPsec host connection setup if [ $VPN_LOGGING ] @@ -396,11 +400,11 @@ down-host:iptables) # This is used only by the default updown script, not by your custom # ones, so do not mess with it; see CAUTION comment up at top. iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT # # log IPsec host connection teardown if [ $VPN_LOGGING ] @@ -422,13 +426,11 @@ up-client:iptables) if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ] then iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ - -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \ - $IPSEC_POLICY_OUT -j ACCEPT + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT $IPSEC_POLICY_OUT -j ACCEPT iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ - -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \ - $IPSEC_POLICY_IN -j ACCEPT + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT fi # # a virtual IP requires an INPUT and OUTPUT rule on the host @@ -436,13 +438,11 @@ up-client:iptables) if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ] then iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ - -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \ - $IPSEC_POLICY_IN -j ACCEPT + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ - -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \ - $IPSEC_POLICY_OUT -j ACCEPT + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT $IPSEC_POLICY_OUT -j ACCEPT fi # # log IPsec client connection setup @@ -465,12 +465,12 @@ down-client:iptables) if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ] then iptables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ - -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT \ $IPSEC_POLICY_OUT -j ACCEPT iptables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ - -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT \ $IPSEC_POLICY_IN -j ACCEPT fi # @@ -479,12 +479,12 @@ down-client:iptables) if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ] then iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ - -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \ - -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT \ $IPSEC_POLICY_IN -j ACCEPT iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ - -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \ - -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT \ $IPSEC_POLICY_OUT -j ACCEPT fi # @@ -514,11 +514,11 @@ unroute-host-v6:*|unroute-client-v6:*) # connection to me or my client subnet being unrouted #downroute_v6 ;; -up-host-v6:*) +up-host-v6:) # connection to me coming up # If you are doing a custom version, firewall commands go here. ;; -down-host-v6:*) +down-host-v6:) # connection to me going down # If you are doing a custom version, firewall commands go here. ;; @@ -530,6 +530,136 @@ down-client-v6:) # connection to my client subnet going down # If you are doing a custom version, firewall commands go here. ;; +up-host-v6:iptables) + # connection to me, with (left/right)firewall=yes, coming up + # This is used only by the default updown script, not by your custom + # ones, so do not mess with it; see CAUTION comment up at top. + ip6tables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT + ip6tables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + # + # log IPsec host connection setup + if [ $VPN_LOGGING ] + then + if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/128" ] + then + logger -t $TAG -p $FAC_PRIO \ + "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME" + else + logger -t $TAG -p $FAC_PRIO \ + "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME" + fi + fi + ;; +down-host-v6:iptables) + # connection to me, with (left/right)firewall=yes, going down + # This is used only by the default updown script, not by your custom + # ones, so do not mess with it; see CAUTION comment up at top. + ip6tables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT + ip6tables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + # + # log IPsec host connection teardown + if [ $VPN_LOGGING ] + then + if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/128" ] + then + logger -t $TAG -p $FAC_PRIO -- \ + "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME" + else + logger -t $TAG -p $FAC_PRIO -- \ + "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME" + fi + fi + ;; +up-client-v6:iptables) + # connection to client subnet, with (left/right)firewall=yes, coming up + # This is used only by the default updown script, not by your custom + # ones, so do not mess with it; see CAUTION comment up at top. + if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/128" ] + then + ip6tables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT $IPSEC_POLICY_OUT -j ACCEPT + ip6tables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT + fi + # + # a virtual IP requires an INPUT and OUTPUT rule on the host + # or sometimes host access via the internal IP is needed + if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ] + then + ip6tables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT + ip6tables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT $IPSEC_POLICY_OUT -j ACCEPT + fi + # + # log IPsec client connection setup + if [ $VPN_LOGGING ] + then + if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/128" ] + then + logger -t $TAG -p $FAC_PRIO \ + "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT" + else + logger -t $TAG -p $FAC_PRIO \ + "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT" + fi + fi + ;; +down-client-v6:iptables) + # connection to client subnet, with (left/right)firewall=yes, going down + # This is used only by the default updown script, not by your custom + # ones, so do not mess with it; see CAUTION comment up at top. + if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/128" ] + then + ip6tables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT \ + $IPSEC_POLICY_OUT -j ACCEPT + ip6tables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT \ + $IPSEC_POLICY_IN -j ACCEPT + fi + # + # a virtual IP requires an INPUT and OUTPUT rule on the host + # or sometimes host access via the internal IP is needed + if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ] + then + ip6tables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT \ + $IPSEC_POLICY_IN -j ACCEPT + ip6tables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT \ + $IPSEC_POLICY_OUT -j ACCEPT + fi + # + # log IPsec client connection teardown + if [ $VPN_LOGGING ] + then + if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/128" ] + then + logger -t $TAG -p $FAC_PRIO -- \ + "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT" + else + logger -t $TAG -p $FAC_PRIO -- \ + "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT" + fi + fi + ;; *) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2 exit 1 ;; diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 0d783cbbb..9111191b6 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -45,7 +45,7 @@ kernel/kernel_interface.c kernel/kernel_interface.h \ network/packet.c network/packet.h \ network/receiver.c network/receiver.h \ network/sender.c network/sender.h \ -network/socket.c network/socket.h \ +network/socket.h \ processing/jobs/job.h \ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ processing/jobs/callback_job.c processing/jobs/callback_job.h \ @@ -83,8 +83,16 @@ sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ +sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/task.c sa/tasks/task.h +# Use RAW socket if pluto gets built +if USE_PLUTO + charon_SOURCES += network/socket-raw.c +else + charon_SOURCES += network/socket.c +endif + if USE_P2P charon_SOURCES += encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \ @@ -104,56 +112,74 @@ if USE_LIBCURL endif -# build EAP plugins, EAP-Identity is always built -################################################# +# build EAP plugins +################### eap_LTLIBRARIES = -eap_LTLIBRARIES += libeapidentity.la -libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c -libeapidentity_la_LDFLAGS = -module +if USE_EAP_IDENTITY + eap_LTLIBRARIES += libcharon-eapidentity.la + libcharon_eapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c + libcharon_eapidentity_la_LDFLAGS = -module +endif + +if USE_EAP_SIM + eap_LTLIBRARIES += libcharon-eapsim.la + libcharon_eapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c + libcharon_eapsim_la_LDFLAGS = -module +endif -if BUILD_EAP_SIM - eap_LTLIBRARIES += libeapsim.la - libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c - libeapsim_la_LDFLAGS = -module +if USE_EAP_MD5 + eap_LTLIBRARIES += libcharon-eapmd5.la + libcharon_eapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c + libcharon_eapmd5_la_LDFLAGS = -module endif -# build backends, local backend is always built -############################################### +if USE_EAP_AKA + eap_LTLIBRARIES += libcharon-eapaka.la + libcharon_eapaka_la_SOURCES = sa/authenticators/eap/eap_aka.h sa/authenticators/eap/eap_aka.c + libcharon_eapaka_la_LDFLAGS = -module +endif + +# build backends +################ backend_LTLIBRARIES = -backend_LTLIBRARIES += liblocal.la -liblocal_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c -liblocal_la_LDFLAGS = -module +if USE_STROKE + backend_LTLIBRARIES += libcharon-local.la + libcharon_local_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c + libcharon_local_la_LDFLAGS = -module +endif if USE_LIBSQLITE - backend_LTLIBRARIES += libsqlite.la - libsqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c - libsqlite_la_LIBADD = -lsqlite3 - libsqlite_la_LDFLAGS = -module + backend_LTLIBRARIES += libcharon-sqlite.la + libcharon_sqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c + libcharon_sqlite_la_LIBADD = -lsqlite3 + libcharon_sqlite_la_LDFLAGS = -module endif -# build control interfaces, stroke interface is always built -############################################################ +# build control interfaces +########################## interface_LTLIBRARIES = -interface_LTLIBRARIES += libstroke.la -libstroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c -libstroke_la_LDFLAGS = -module +if USE_STROKE + interface_LTLIBRARIES += libcharon-stroke.la + libcharon_stroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c + libcharon_stroke_la_LDFLAGS = -module +endif if USE_LIBDBUS - interface_LTLIBRARIES += libdbus.la - libdbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c - libdbus_la_LDFLAGS = -module - libdbus_la_LIBADD = ${dbus_LIBS} + interface_LTLIBRARIES += libcharon-dbus.la + libcharon_dbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c + libcharon_dbus_la_LDFLAGS = -module + libcharon_dbus_la_LIBADD = ${dbus_LIBS} INCLUDES += ${dbus_CFLAGS} endif if USE_LIBXML - interface_LTLIBRARIES += libxml.la - libxml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c - libxml_la_LDFLAGS = -module - libxml_la_LIBADD = ${xml_LIBS} + interface_LTLIBRARIES += libcharon-xml.la + libcharon_xml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c + libcharon_xml_la_LDFLAGS = -module + libcharon_xml_la_LIBADD = ${xml_LIBS} INCLUDES += ${xml_CFLAGS} endif diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in index e3b397f4e..bbae1270a 100644 --- a/src/charon/Makefile.in +++ b/src/charon/Makefile.in @@ -34,20 +34,29 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ ipsec_PROGRAMS = charon$(EXEEXT) -@USE_P2P_TRUE@am__append_1 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ + +# Use RAW socket if pluto gets built +@USE_PLUTO_TRUE@am__append_1 = network/socket-raw.c +@USE_PLUTO_FALSE@am__append_2 = network/socket.c +@USE_P2P_TRUE@am__append_3 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ @USE_P2P_TRUE@ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \ @USE_P2P_TRUE@ processing/jobs/mediation_job.c processing/jobs/mediation_job.h \ @USE_P2P_TRUE@ sa/connect_manager.c sa/connect_manager.h \ @USE_P2P_TRUE@ sa/mediation_manager.c sa/mediation_manager.h \ @USE_P2P_TRUE@ sa/tasks/ike_p2p.c sa/tasks/ike_p2p.h -@USE_LIBCURL_TRUE@am__append_2 = -lcurl -@BUILD_EAP_SIM_TRUE@am__append_3 = libeapsim.la -@USE_LIBSQLITE_TRUE@am__append_4 = libsqlite.la -@USE_LIBDBUS_TRUE@am__append_5 = libdbus.la -@USE_LIBDBUS_TRUE@am__append_6 = ${dbus_CFLAGS} -@USE_LIBXML_TRUE@am__append_7 = libxml.la -@USE_LIBXML_TRUE@am__append_8 = ${xml_CFLAGS} +@USE_LIBCURL_TRUE@am__append_4 = -lcurl +@USE_EAP_IDENTITY_TRUE@am__append_5 = libcharon-eapidentity.la +@USE_EAP_SIM_TRUE@am__append_6 = libcharon-eapsim.la +@USE_EAP_MD5_TRUE@am__append_7 = libcharon-eapmd5.la +@USE_EAP_AKA_TRUE@am__append_8 = libcharon-eapaka.la +@USE_STROKE_TRUE@am__append_9 = libcharon-local.la +@USE_LIBSQLITE_TRUE@am__append_10 = libcharon-sqlite.la +@USE_STROKE_TRUE@am__append_11 = libcharon-stroke.la +@USE_LIBDBUS_TRUE@am__append_12 = libcharon-dbus.la +@USE_LIBDBUS_TRUE@am__append_13 = ${dbus_CFLAGS} +@USE_LIBXML_TRUE@am__append_14 = libcharon-xml.la +@USE_LIBXML_TRUE@am__append_15 = ${xml_CFLAGS} subdir = src/charon DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -70,60 +79,102 @@ interfaceLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(backend_LTLIBRARIES) $(eap_LTLIBRARIES) \ $(interface_LTLIBRARIES) am__DEPENDENCIES_1 = -@USE_LIBDBUS_TRUE@libdbus_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__libdbus_la_SOURCES_DIST = control/interfaces/dbus_interface.h \ +@USE_LIBDBUS_TRUE@libcharon_dbus_la_DEPENDENCIES = \ +@USE_LIBDBUS_TRUE@ $(am__DEPENDENCIES_1) +am__libcharon_dbus_la_SOURCES_DIST = \ + control/interfaces/dbus_interface.h \ control/interfaces/dbus_interface.c -@USE_LIBDBUS_TRUE@am_libdbus_la_OBJECTS = dbus_interface.lo -libdbus_la_OBJECTS = $(am_libdbus_la_OBJECTS) -libdbus_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +@USE_LIBDBUS_TRUE@am_libcharon_dbus_la_OBJECTS = dbus_interface.lo +libcharon_dbus_la_OBJECTS = $(am_libcharon_dbus_la_OBJECTS) +libcharon_dbus_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libcharon_dbus_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_LIBDBUS_TRUE@am_libcharon_dbus_la_rpath = -rpath $(interfacedir) +libcharon_eapaka_la_LIBADD = +am__libcharon_eapaka_la_SOURCES_DIST = \ + sa/authenticators/eap/eap_aka.h \ + sa/authenticators/eap/eap_aka.c +@USE_EAP_AKA_TRUE@am_libcharon_eapaka_la_OBJECTS = eap_aka.lo +libcharon_eapaka_la_OBJECTS = $(am_libcharon_eapaka_la_OBJECTS) +libcharon_eapaka_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libcharon_eapaka_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_EAP_AKA_TRUE@am_libcharon_eapaka_la_rpath = -rpath $(eapdir) +libcharon_eapidentity_la_LIBADD = +am__libcharon_eapidentity_la_SOURCES_DIST = \ + sa/authenticators/eap/eap_identity.h \ + sa/authenticators/eap/eap_identity.c +@USE_EAP_IDENTITY_TRUE@am_libcharon_eapidentity_la_OBJECTS = \ +@USE_EAP_IDENTITY_TRUE@ eap_identity.lo +libcharon_eapidentity_la_OBJECTS = \ + $(am_libcharon_eapidentity_la_OBJECTS) +libcharon_eapidentity_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libdbus_la_LDFLAGS) $(LDFLAGS) -o $@ -@USE_LIBDBUS_TRUE@am_libdbus_la_rpath = -rpath $(interfacedir) -libeapidentity_la_LIBADD = -am_libeapidentity_la_OBJECTS = eap_identity.lo -libeapidentity_la_OBJECTS = $(am_libeapidentity_la_OBJECTS) -libeapidentity_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(libcharon_eapidentity_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_EAP_IDENTITY_TRUE@am_libcharon_eapidentity_la_rpath = -rpath \ +@USE_EAP_IDENTITY_TRUE@ $(eapdir) +libcharon_eapmd5_la_LIBADD = +am__libcharon_eapmd5_la_SOURCES_DIST = \ + sa/authenticators/eap/eap_md5.h \ + sa/authenticators/eap/eap_md5.c +@USE_EAP_MD5_TRUE@am_libcharon_eapmd5_la_OBJECTS = eap_md5.lo +libcharon_eapmd5_la_OBJECTS = $(am_libcharon_eapmd5_la_OBJECTS) +libcharon_eapmd5_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libeapidentity_la_LDFLAGS) $(LDFLAGS) -o $@ -libeapsim_la_LIBADD = -am__libeapsim_la_SOURCES_DIST = sa/authenticators/eap/eap_sim.h \ + $(libcharon_eapmd5_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_EAP_MD5_TRUE@am_libcharon_eapmd5_la_rpath = -rpath $(eapdir) +libcharon_eapsim_la_LIBADD = +am__libcharon_eapsim_la_SOURCES_DIST = \ + sa/authenticators/eap/eap_sim.h \ sa/authenticators/eap/eap_sim.c -@BUILD_EAP_SIM_TRUE@am_libeapsim_la_OBJECTS = eap_sim.lo -libeapsim_la_OBJECTS = $(am_libeapsim_la_OBJECTS) -libeapsim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +@USE_EAP_SIM_TRUE@am_libcharon_eapsim_la_OBJECTS = eap_sim.lo +libcharon_eapsim_la_OBJECTS = $(am_libcharon_eapsim_la_OBJECTS) +libcharon_eapsim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libeapsim_la_LDFLAGS) $(LDFLAGS) -o $@ -@BUILD_EAP_SIM_TRUE@am_libeapsim_la_rpath = -rpath $(eapdir) -liblocal_la_LIBADD = -am_liblocal_la_OBJECTS = local_backend.lo -liblocal_la_OBJECTS = $(am_liblocal_la_OBJECTS) -liblocal_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(libcharon_eapsim_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_EAP_SIM_TRUE@am_libcharon_eapsim_la_rpath = -rpath $(eapdir) +libcharon_local_la_LIBADD = +am__libcharon_local_la_SOURCES_DIST = config/backends/local_backend.h \ + config/backends/local_backend.c +@USE_STROKE_TRUE@am_libcharon_local_la_OBJECTS = local_backend.lo +libcharon_local_la_OBJECTS = $(am_libcharon_local_la_OBJECTS) +libcharon_local_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(liblocal_la_LDFLAGS) $(LDFLAGS) -o $@ -libsqlite_la_DEPENDENCIES = -am__libsqlite_la_SOURCES_DIST = config/backends/sqlite_backend.h \ + $(libcharon_local_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_STROKE_TRUE@am_libcharon_local_la_rpath = -rpath $(backenddir) +libcharon_sqlite_la_DEPENDENCIES = +am__libcharon_sqlite_la_SOURCES_DIST = \ + config/backends/sqlite_backend.h \ config/backends/sqlite_backend.c -@USE_LIBSQLITE_TRUE@am_libsqlite_la_OBJECTS = sqlite_backend.lo -libsqlite_la_OBJECTS = $(am_libsqlite_la_OBJECTS) -libsqlite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +@USE_LIBSQLITE_TRUE@am_libcharon_sqlite_la_OBJECTS = \ +@USE_LIBSQLITE_TRUE@ sqlite_backend.lo +libcharon_sqlite_la_OBJECTS = $(am_libcharon_sqlite_la_OBJECTS) +libcharon_sqlite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libsqlite_la_LDFLAGS) $(LDFLAGS) -o $@ -@USE_LIBSQLITE_TRUE@am_libsqlite_la_rpath = -rpath $(backenddir) -libstroke_la_LIBADD = -am_libstroke_la_OBJECTS = stroke_interface.lo -libstroke_la_OBJECTS = $(am_libstroke_la_OBJECTS) -libstroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(libcharon_sqlite_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_LIBSQLITE_TRUE@am_libcharon_sqlite_la_rpath = -rpath \ +@USE_LIBSQLITE_TRUE@ $(backenddir) +libcharon_stroke_la_LIBADD = +am__libcharon_stroke_la_SOURCES_DIST = \ + control/interfaces/stroke_interface.h \ + control/interfaces/stroke_interface.c +@USE_STROKE_TRUE@am_libcharon_stroke_la_OBJECTS = stroke_interface.lo +libcharon_stroke_la_OBJECTS = $(am_libcharon_stroke_la_OBJECTS) +libcharon_stroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libstroke_la_LDFLAGS) $(LDFLAGS) -o $@ -@USE_LIBXML_TRUE@libxml_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__libxml_la_SOURCES_DIST = control/interfaces/xml_interface.h \ + $(libcharon_stroke_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_STROKE_TRUE@am_libcharon_stroke_la_rpath = -rpath $(interfacedir) +@USE_LIBXML_TRUE@libcharon_xml_la_DEPENDENCIES = \ +@USE_LIBXML_TRUE@ $(am__DEPENDENCIES_1) +am__libcharon_xml_la_SOURCES_DIST = \ + control/interfaces/xml_interface.h \ control/interfaces/xml_interface.c -@USE_LIBXML_TRUE@am_libxml_la_OBJECTS = xml_interface.lo -libxml_la_OBJECTS = $(am_libxml_la_OBJECTS) -libxml_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +@USE_LIBXML_TRUE@am_libcharon_xml_la_OBJECTS = xml_interface.lo +libcharon_xml_la_OBJECTS = $(am_libcharon_xml_la_OBJECTS) +libcharon_xml_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libxml_la_LDFLAGS) $(LDFLAGS) -o $@ -@USE_LIBXML_TRUE@am_libxml_la_rpath = -rpath $(interfacedir) + $(libcharon_xml_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_LIBXML_TRUE@am_libcharon_xml_la_rpath = -rpath $(interfacedir) ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \ @@ -181,7 +232,7 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \ kernel/kernel_interface.c kernel/kernel_interface.h \ network/packet.c network/packet.h network/receiver.c \ network/receiver.h network/sender.c network/sender.h \ - network/socket.c network/socket.h processing/jobs/job.h \ + network/socket.h processing/jobs/job.h \ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ processing/jobs/callback_job.c processing/jobs/callback_job.h \ processing/jobs/delete_child_sa_job.c \ @@ -225,7 +276,9 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \ sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \ sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \ sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \ - sa/tasks/ike_reauth.h sa/tasks/task.c sa/tasks/task.h \ + sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \ + sa/tasks/ike_auth_lifetime.h sa/tasks/task.c sa/tasks/task.h \ + network/socket-raw.c network/socket.c \ encoding/payloads/endpoint_notify.c \ encoding/payloads/endpoint_notify.h \ processing/jobs/initiate_mediation_job.c \ @@ -234,7 +287,9 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \ processing/jobs/mediation_job.h sa/connect_manager.c \ sa/connect_manager.h sa/mediation_manager.c \ sa/mediation_manager.h sa/tasks/ike_p2p.c sa/tasks/ike_p2p.h -@USE_P2P_TRUE@am__objects_1 = endpoint_notify.$(OBJEXT) \ +@USE_PLUTO_TRUE@am__objects_1 = socket-raw.$(OBJEXT) +@USE_PLUTO_FALSE@am__objects_2 = socket.$(OBJEXT) +@USE_P2P_TRUE@am__objects_3 = endpoint_notify.$(OBJEXT) \ @USE_P2P_TRUE@ initiate_mediation_job.$(OBJEXT) \ @USE_P2P_TRUE@ mediation_job.$(OBJEXT) \ @USE_P2P_TRUE@ connect_manager.$(OBJEXT) \ @@ -258,7 +313,7 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \ ts_payload.$(OBJEXT) unknown_payload.$(OBJEXT) \ vendor_id_payload.$(OBJEXT) kernel_interface.$(OBJEXT) \ packet.$(OBJEXT) receiver.$(OBJEXT) sender.$(OBJEXT) \ - socket.$(OBJEXT) acquire_job.$(OBJEXT) callback_job.$(OBJEXT) \ + acquire_job.$(OBJEXT) callback_job.$(OBJEXT) \ delete_child_sa_job.$(OBJEXT) delete_ike_sa_job.$(OBJEXT) \ process_message_job.$(OBJEXT) rekey_child_sa_job.$(OBJEXT) \ rekey_ike_sa_job.$(OBJEXT) retransmit_job.$(OBJEXT) \ @@ -273,7 +328,9 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \ ike_auth.$(OBJEXT) ike_cert.$(OBJEXT) ike_config.$(OBJEXT) \ ike_delete.$(OBJEXT) ike_dpd.$(OBJEXT) ike_init.$(OBJEXT) \ ike_natd.$(OBJEXT) ike_mobike.$(OBJEXT) ike_rekey.$(OBJEXT) \ - ike_reauth.$(OBJEXT) task.$(OBJEXT) $(am__objects_1) + ike_reauth.$(OBJEXT) ike_auth_lifetime.$(OBJEXT) \ + task.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) charon_OBJECTS = $(am_charon_OBJECTS) charon_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ @@ -290,14 +347,21 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libdbus_la_SOURCES) $(libeapidentity_la_SOURCES) \ - $(libeapsim_la_SOURCES) $(liblocal_la_SOURCES) \ - $(libsqlite_la_SOURCES) $(libstroke_la_SOURCES) \ - $(libxml_la_SOURCES) $(charon_SOURCES) -DIST_SOURCES = $(am__libdbus_la_SOURCES_DIST) \ - $(libeapidentity_la_SOURCES) $(am__libeapsim_la_SOURCES_DIST) \ - $(liblocal_la_SOURCES) $(am__libsqlite_la_SOURCES_DIST) \ - $(libstroke_la_SOURCES) $(am__libxml_la_SOURCES_DIST) \ +SOURCES = $(libcharon_dbus_la_SOURCES) $(libcharon_eapaka_la_SOURCES) \ + $(libcharon_eapidentity_la_SOURCES) \ + $(libcharon_eapmd5_la_SOURCES) $(libcharon_eapsim_la_SOURCES) \ + $(libcharon_local_la_SOURCES) $(libcharon_sqlite_la_SOURCES) \ + $(libcharon_stroke_la_SOURCES) $(libcharon_xml_la_SOURCES) \ + $(charon_SOURCES) +DIST_SOURCES = $(am__libcharon_dbus_la_SOURCES_DIST) \ + $(am__libcharon_eapaka_la_SOURCES_DIST) \ + $(am__libcharon_eapidentity_la_SOURCES_DIST) \ + $(am__libcharon_eapmd5_la_SOURCES_DIST) \ + $(am__libcharon_eapsim_la_SOURCES_DIST) \ + $(am__libcharon_local_la_SOURCES_DIST) \ + $(am__libcharon_sqlite_la_SOURCES_DIST) \ + $(am__libcharon_stroke_la_SOURCES_DIST) \ + $(am__libcharon_xml_la_SOURCES_DIST) \ $(am__charon_SOURCES_DIST) ETAGS = etags CTAGS = ctags @@ -486,7 +550,7 @@ charon_SOURCES = bus/bus.c bus/bus.h bus/listeners/file_logger.c \ kernel/kernel_interface.c kernel/kernel_interface.h \ network/packet.c network/packet.h network/receiver.c \ network/receiver.h network/sender.c network/sender.h \ - network/socket.c network/socket.h processing/jobs/job.h \ + network/socket.h processing/jobs/job.h \ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ processing/jobs/callback_job.c processing/jobs/callback_job.h \ processing/jobs/delete_child_sa_job.c \ @@ -530,45 +594,52 @@ charon_SOURCES = bus/bus.c bus/bus.h bus/listeners/file_logger.c \ sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \ sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \ sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \ - sa/tasks/ike_reauth.h sa/tasks/task.c sa/tasks/task.h \ - $(am__append_1) + sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \ + sa/tasks/ike_auth_lifetime.h sa/tasks/task.c sa/tasks/task.h \ + $(am__append_1) $(am__append_2) $(am__append_3) INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke \ - $(am__append_6) $(am__append_8) + $(am__append_13) $(am__append_15) AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ -DIPSEC_EAPDIR=\"${eapdir}\" -DIPSEC_BACKENDDIR=\"${backenddir}\" -DIPSEC_INTERFACEDIR=\"${interfacedir}\" charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ - -lgmp -lpthread -lm -ldl $(am__append_2) - -# build EAP plugins, EAP-Identity is always built -################################################# -eap_LTLIBRARIES = libeapidentity.la $(am__append_3) -libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c -libeapidentity_la_LDFLAGS = -module -@BUILD_EAP_SIM_TRUE@libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c -@BUILD_EAP_SIM_TRUE@libeapsim_la_LDFLAGS = -module - -# build backends, local backend is always built -############################################### -backend_LTLIBRARIES = liblocal.la $(am__append_4) -liblocal_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c -liblocal_la_LDFLAGS = -module -@USE_LIBSQLITE_TRUE@libsqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c -@USE_LIBSQLITE_TRUE@libsqlite_la_LIBADD = -lsqlite3 -@USE_LIBSQLITE_TRUE@libsqlite_la_LDFLAGS = -module - -# build control interfaces, stroke interface is always built -############################################################ -interface_LTLIBRARIES = libstroke.la $(am__append_5) $(am__append_7) -libstroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c -libstroke_la_LDFLAGS = -module -@USE_LIBDBUS_TRUE@libdbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c -@USE_LIBDBUS_TRUE@libdbus_la_LDFLAGS = -module -@USE_LIBDBUS_TRUE@libdbus_la_LIBADD = ${dbus_LIBS} -@USE_LIBXML_TRUE@libxml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c -@USE_LIBXML_TRUE@libxml_la_LDFLAGS = -module -@USE_LIBXML_TRUE@libxml_la_LIBADD = ${xml_LIBS} + -lgmp -lpthread -lm -ldl $(am__append_4) + +# build EAP plugins +################### +eap_LTLIBRARIES = $(am__append_5) $(am__append_6) $(am__append_7) \ + $(am__append_8) +@USE_EAP_IDENTITY_TRUE@libcharon_eapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c +@USE_EAP_IDENTITY_TRUE@libcharon_eapidentity_la_LDFLAGS = -module +@USE_EAP_SIM_TRUE@libcharon_eapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c +@USE_EAP_SIM_TRUE@libcharon_eapsim_la_LDFLAGS = -module +@USE_EAP_MD5_TRUE@libcharon_eapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c +@USE_EAP_MD5_TRUE@libcharon_eapmd5_la_LDFLAGS = -module +@USE_EAP_AKA_TRUE@libcharon_eapaka_la_SOURCES = sa/authenticators/eap/eap_aka.h sa/authenticators/eap/eap_aka.c +@USE_EAP_AKA_TRUE@libcharon_eapaka_la_LDFLAGS = -module + +# build backends +################ +backend_LTLIBRARIES = $(am__append_9) $(am__append_10) +@USE_STROKE_TRUE@libcharon_local_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c +@USE_STROKE_TRUE@libcharon_local_la_LDFLAGS = -module +@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c +@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_LIBADD = -lsqlite3 +@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_LDFLAGS = -module + +# build control interfaces +########################## +interface_LTLIBRARIES = $(am__append_11) $(am__append_12) \ + $(am__append_14) +@USE_STROKE_TRUE@libcharon_stroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c +@USE_STROKE_TRUE@libcharon_stroke_la_LDFLAGS = -module +@USE_LIBDBUS_TRUE@libcharon_dbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c +@USE_LIBDBUS_TRUE@libcharon_dbus_la_LDFLAGS = -module +@USE_LIBDBUS_TRUE@libcharon_dbus_la_LIBADD = ${dbus_LIBS} +@USE_LIBXML_TRUE@libcharon_xml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c +@USE_LIBXML_TRUE@libcharon_xml_la_LDFLAGS = -module +@USE_LIBXML_TRUE@libcharon_xml_la_LIBADD = ${xml_LIBS} all: all-am .SUFFIXES: @@ -683,20 +754,24 @@ clean-interfaceLTLIBRARIES: echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done -libdbus.la: $(libdbus_la_OBJECTS) $(libdbus_la_DEPENDENCIES) - $(libdbus_la_LINK) $(am_libdbus_la_rpath) $(libdbus_la_OBJECTS) $(libdbus_la_LIBADD) $(LIBS) -libeapidentity.la: $(libeapidentity_la_OBJECTS) $(libeapidentity_la_DEPENDENCIES) - $(libeapidentity_la_LINK) -rpath $(eapdir) $(libeapidentity_la_OBJECTS) $(libeapidentity_la_LIBADD) $(LIBS) -libeapsim.la: $(libeapsim_la_OBJECTS) $(libeapsim_la_DEPENDENCIES) - $(libeapsim_la_LINK) $(am_libeapsim_la_rpath) $(libeapsim_la_OBJECTS) $(libeapsim_la_LIBADD) $(LIBS) -liblocal.la: $(liblocal_la_OBJECTS) $(liblocal_la_DEPENDENCIES) - $(liblocal_la_LINK) -rpath $(backenddir) $(liblocal_la_OBJECTS) $(liblocal_la_LIBADD) $(LIBS) -libsqlite.la: $(libsqlite_la_OBJECTS) $(libsqlite_la_DEPENDENCIES) - $(libsqlite_la_LINK) $(am_libsqlite_la_rpath) $(libsqlite_la_OBJECTS) $(libsqlite_la_LIBADD) $(LIBS) -libstroke.la: $(libstroke_la_OBJECTS) $(libstroke_la_DEPENDENCIES) - $(libstroke_la_LINK) -rpath $(interfacedir) $(libstroke_la_OBJECTS) $(libstroke_la_LIBADD) $(LIBS) -libxml.la: $(libxml_la_OBJECTS) $(libxml_la_DEPENDENCIES) - $(libxml_la_LINK) $(am_libxml_la_rpath) $(libxml_la_OBJECTS) $(libxml_la_LIBADD) $(LIBS) +libcharon-dbus.la: $(libcharon_dbus_la_OBJECTS) $(libcharon_dbus_la_DEPENDENCIES) + $(libcharon_dbus_la_LINK) $(am_libcharon_dbus_la_rpath) $(libcharon_dbus_la_OBJECTS) $(libcharon_dbus_la_LIBADD) $(LIBS) +libcharon-eapaka.la: $(libcharon_eapaka_la_OBJECTS) $(libcharon_eapaka_la_DEPENDENCIES) + $(libcharon_eapaka_la_LINK) $(am_libcharon_eapaka_la_rpath) $(libcharon_eapaka_la_OBJECTS) $(libcharon_eapaka_la_LIBADD) $(LIBS) +libcharon-eapidentity.la: $(libcharon_eapidentity_la_OBJECTS) $(libcharon_eapidentity_la_DEPENDENCIES) + $(libcharon_eapidentity_la_LINK) $(am_libcharon_eapidentity_la_rpath) $(libcharon_eapidentity_la_OBJECTS) $(libcharon_eapidentity_la_LIBADD) $(LIBS) +libcharon-eapmd5.la: $(libcharon_eapmd5_la_OBJECTS) $(libcharon_eapmd5_la_DEPENDENCIES) + $(libcharon_eapmd5_la_LINK) $(am_libcharon_eapmd5_la_rpath) $(libcharon_eapmd5_la_OBJECTS) $(libcharon_eapmd5_la_LIBADD) $(LIBS) +libcharon-eapsim.la: $(libcharon_eapsim_la_OBJECTS) $(libcharon_eapsim_la_DEPENDENCIES) + $(libcharon_eapsim_la_LINK) $(am_libcharon_eapsim_la_rpath) $(libcharon_eapsim_la_OBJECTS) $(libcharon_eapsim_la_LIBADD) $(LIBS) +libcharon-local.la: $(libcharon_local_la_OBJECTS) $(libcharon_local_la_DEPENDENCIES) + $(libcharon_local_la_LINK) $(am_libcharon_local_la_rpath) $(libcharon_local_la_OBJECTS) $(libcharon_local_la_LIBADD) $(LIBS) +libcharon-sqlite.la: $(libcharon_sqlite_la_OBJECTS) $(libcharon_sqlite_la_DEPENDENCIES) + $(libcharon_sqlite_la_LINK) $(am_libcharon_sqlite_la_rpath) $(libcharon_sqlite_la_OBJECTS) $(libcharon_sqlite_la_LIBADD) $(LIBS) +libcharon-stroke.la: $(libcharon_stroke_la_OBJECTS) $(libcharon_stroke_la_DEPENDENCIES) + $(libcharon_stroke_la_LINK) $(am_libcharon_stroke_la_rpath) $(libcharon_stroke_la_OBJECTS) $(libcharon_stroke_la_LIBADD) $(LIBS) +libcharon-xml.la: $(libcharon_xml_la_OBJECTS) $(libcharon_xml_la_DEPENDENCIES) + $(libcharon_xml_la_LINK) $(am_libcharon_xml_la_rpath) $(libcharon_xml_la_OBJECTS) $(libcharon_xml_la_LIBADD) $(LIBS) install-ipsecPROGRAMS: $(ipsec_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" @@ -756,8 +831,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_child_sa_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_ike_sa_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_payload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_aka.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_authenticator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_identity.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_md5.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_method.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@ @@ -768,6 +845,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth_lifetime.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_cert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_cfg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_config.Po@am__quote@ @@ -814,6 +892,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_dpd_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_keepalive_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sender.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket-raw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite_backend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_interface.Plo@am__quote@ @@ -857,6 +936,13 @@ dbus_interface.lo: control/interfaces/dbus_interface.c @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) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_interface.lo `test -f 'control/interfaces/dbus_interface.c' || echo '$(srcdir)/'`control/interfaces/dbus_interface.c +eap_aka.lo: sa/authenticators/eap/eap_aka.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_aka.lo -MD -MP -MF $(DEPDIR)/eap_aka.Tpo -c -o eap_aka.lo `test -f 'sa/authenticators/eap/eap_aka.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_aka.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_aka.Tpo $(DEPDIR)/eap_aka.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_aka.c' object='eap_aka.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) $(AM_CFLAGS) $(CFLAGS) -c -o eap_aka.lo `test -f 'sa/authenticators/eap/eap_aka.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_aka.c + eap_identity.lo: sa/authenticators/eap/eap_identity.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_identity.lo -MD -MP -MF $(DEPDIR)/eap_identity.Tpo -c -o eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_identity.Tpo $(DEPDIR)/eap_identity.Plo @@ -864,6 +950,13 @@ eap_identity.lo: sa/authenticators/eap/eap_identity.c @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) $(AM_CFLAGS) $(CFLAGS) -c -o eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c +eap_md5.lo: sa/authenticators/eap/eap_md5.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_md5.lo -MD -MP -MF $(DEPDIR)/eap_md5.Tpo -c -o eap_md5.lo `test -f 'sa/authenticators/eap/eap_md5.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_md5.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_md5.Tpo $(DEPDIR)/eap_md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_md5.c' object='eap_md5.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) $(AM_CFLAGS) $(CFLAGS) -c -o eap_md5.lo `test -f 'sa/authenticators/eap/eap_md5.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_md5.c + eap_sim.lo: sa/authenticators/eap/eap_sim.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_sim.lo -MD -MP -MF $(DEPDIR)/eap_sim.Tpo -c -o eap_sim.lo `test -f 'sa/authenticators/eap/eap_sim.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_sim.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_sim.Tpo $(DEPDIR)/eap_sim.Plo @@ -1473,20 +1566,6 @@ sender.obj: network/sender.c @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 sender.obj `if test -f 'network/sender.c'; then $(CYGPATH_W) 'network/sender.c'; else $(CYGPATH_W) '$(srcdir)/network/sender.c'; fi` -socket.o: network/socket.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.o' 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 socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c - -socket.obj: network/socket.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.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 socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi` - acquire_job.o: processing/jobs/acquire_job.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acquire_job.o -MD -MP -MF $(DEPDIR)/acquire_job.Tpo -c -o acquire_job.o `test -f 'processing/jobs/acquire_job.c' || echo '$(srcdir)/'`processing/jobs/acquire_job.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/acquire_job.Tpo $(DEPDIR)/acquire_job.Po @@ -1991,6 +2070,20 @@ ike_reauth.obj: sa/tasks/ike_reauth.c @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 ike_reauth.obj `if test -f 'sa/tasks/ike_reauth.c'; then $(CYGPATH_W) 'sa/tasks/ike_reauth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_reauth.c'; fi` +ike_auth_lifetime.o: sa/tasks/ike_auth_lifetime.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.o -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.o `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_auth_lifetime.Tpo $(DEPDIR)/ike_auth_lifetime.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.o' 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 ike_auth_lifetime.o `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c + +ike_auth_lifetime.obj: sa/tasks/ike_auth_lifetime.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.obj -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.obj `if test -f 'sa/tasks/ike_auth_lifetime.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth_lifetime.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth_lifetime.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_auth_lifetime.Tpo $(DEPDIR)/ike_auth_lifetime.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.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 ike_auth_lifetime.obj `if test -f 'sa/tasks/ike_auth_lifetime.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth_lifetime.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth_lifetime.c'; fi` + task.o: sa/tasks/task.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.o -MD -MP -MF $(DEPDIR)/task.Tpo -c -o task.o `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/task.Tpo $(DEPDIR)/task.Po @@ -2005,6 +2098,34 @@ task.obj: sa/tasks/task.c @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 task.obj `if test -f 'sa/tasks/task.c'; then $(CYGPATH_W) 'sa/tasks/task.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/task.c'; fi` +socket-raw.o: network/socket-raw.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket-raw.o -MD -MP -MF $(DEPDIR)/socket-raw.Tpo -c -o socket-raw.o `test -f 'network/socket-raw.c' || echo '$(srcdir)/'`network/socket-raw.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket-raw.Tpo $(DEPDIR)/socket-raw.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket-raw.c' object='socket-raw.o' 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 socket-raw.o `test -f 'network/socket-raw.c' || echo '$(srcdir)/'`network/socket-raw.c + +socket-raw.obj: network/socket-raw.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket-raw.obj -MD -MP -MF $(DEPDIR)/socket-raw.Tpo -c -o socket-raw.obj `if test -f 'network/socket-raw.c'; then $(CYGPATH_W) 'network/socket-raw.c'; else $(CYGPATH_W) '$(srcdir)/network/socket-raw.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket-raw.Tpo $(DEPDIR)/socket-raw.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket-raw.c' object='socket-raw.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 socket-raw.obj `if test -f 'network/socket-raw.c'; then $(CYGPATH_W) 'network/socket-raw.c'; else $(CYGPATH_W) '$(srcdir)/network/socket-raw.c'; fi` + +socket.o: network/socket.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.o' 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 socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c + +socket.obj: network/socket.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.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 socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi` + endpoint_notify.o: encoding/payloads/endpoint_notify.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endpoint_notify.o -MD -MP -MF $(DEPDIR)/endpoint_notify.Tpo -c -o endpoint_notify.o `test -f 'encoding/payloads/endpoint_notify.c' || echo '$(srcdir)/'`encoding/payloads/endpoint_notify.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/endpoint_notify.Tpo $(DEPDIR)/endpoint_notify.Po diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index 5fda36925..e53ac43ce 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -24,6 +24,8 @@ #include <pthread.h> +#include <daemon.h> + ENUM(signal_names, SIG_ANY, SIG_MAX, /** should not get printed */ "SIG_ANY", @@ -53,104 +55,74 @@ ENUM(signal_names, SIG_ANY, SIG_MAX, "SIG_MAX", ); -typedef struct active_listener_t active_listener_t; +typedef struct private_bus_t private_bus_t; /** - * information for a active listener + * Private data of a bus_t object. */ -struct active_listener_t { - - /** - * associated thread - */ - pthread_t id; - - /** - * condvar to wait for a signal - */ - pthread_cond_t cond; - - /** - * state of the thread - */ - enum { - /** not registered, do not wait for thread */ - UNREGISTERED, - /** registered, if a signal occurs, wait until it is LISTENING */ - REGISTERED, - /** listening, deliver signal */ - LISTENING, - } state; - - /** - * currently processed signals type - */ - signal_t signal; - +struct private_bus_t { /** - * verbosity level of the signal + * Public part of a bus_t object. */ - level_t level; + bus_t public; /** - * current processed signals thread number + * List of registered listeners as entry_t's */ - int thread; + linked_list_t *listeners; /** - * currently processed signals ike_sa + * mutex to synchronize active listeners */ - ike_sa_t *ike_sa; + pthread_mutex_t mutex; /** - * currently processed signals format string + * Thread local storage for a unique, simple thread ID */ - char *format; + pthread_key_t thread_id; /** - * currently processed signals format varargs + * Thread local storage the threads IKE_SA */ - va_list args; - + pthread_key_t thread_sa; }; -typedef struct private_bus_t private_bus_t; +typedef struct entry_t entry_t; /** - * Private data of a bus_t object. + * a listener entry, either active or passive */ -struct private_bus_t { - /** - * Public part of a bus_t object. - */ - bus_t public; - - /** - * List of registered listeners implementing the bus_t interface - */ - linked_list_t *listeners; - +struct entry_t { + /** - * List of active listeners with listener_state TRUE + * registered listener interface */ - linked_list_t *active_listeners; + bus_listener_t *listener; /** - * mutex to synchronize active listeners + * is this a active listen() call with a blocking thread */ - pthread_mutex_t mutex; + bool blocker; /** - * Thread local storage for a unique, simple thread ID + * condvar where active listeners wait */ - pthread_key_t thread_id; + pthread_cond_t cond; +}; + +/** + * create a listener entry + */ +static entry_t *entry_create(bus_listener_t *listener, bool blocker) +{ + entry_t *this = malloc_thing(entry_t); - /** - * Thread local storage the threads IKE_SA - */ - pthread_key_t thread_sa; + this->listener = listener; + this->blocker = blocker; + pthread_cond_init(&this->cond, NULL); -}; + return this; +} /** * Get a unique thread number for a calling thread. Since @@ -160,7 +132,7 @@ struct private_bus_t { static int get_thread_number(private_bus_t *this) { static long current_num = 0; - static long stored_num; + long stored_num; stored_num = (long)pthread_getspecific(this->thread_id); if (stored_num == 0) @@ -180,7 +152,7 @@ static int get_thread_number(private_bus_t *this) static void add_listener(private_bus_t *this, bus_listener_t *listener) { pthread_mutex_lock(&this->mutex); - this->listeners->insert_last(this->listeners, listener); + this->listeners->insert_last(this->listeners, entry_create(listener, FALSE)); pthread_mutex_unlock(&this->mutex); } @@ -190,15 +162,16 @@ static void add_listener(private_bus_t *this, bus_listener_t *listener) static void remove_listener(private_bus_t *this, bus_listener_t *listener) { iterator_t *iterator; - bus_listener_t *current; + entry_t *entry; pthread_mutex_lock(&this->mutex); iterator = this->listeners->create_iterator(this->listeners, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + while (iterator->iterate(iterator, (void**)&entry)) { - if (current == listener) + if (entry->listener == listener) { iterator->remove(iterator); + free(entry); break; } } @@ -206,109 +179,67 @@ static void remove_listener(private_bus_t *this, bus_listener_t *listener) pthread_mutex_unlock(&this->mutex); } +typedef struct cleanup_data_t cleanup_data_t; + +/** + * data to remove a listener using pthread_cleanup handler + */ +struct cleanup_data_t { + /** bus instance */ + private_bus_t *this; + /** listener entry */ + entry_t *entry; +}; + /** - * Get the listener object for the calling thread + * pthread_cleanup handler to remove a listener */ -static active_listener_t *get_active_listener(private_bus_t *this) +static void listener_cleanup(cleanup_data_t *data) { - active_listener_t *current, *found = NULL; iterator_t *iterator; - - /* if the thread was here once before, we have a active_listener record */ - iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + entry_t *entry; + + iterator = data->this->listeners->create_iterator(data->this->listeners, TRUE); + while (iterator->iterate(iterator, (void**)&entry)) { - if (current->id == pthread_self()) + if (entry == data->entry) { - found = current; + iterator->remove(iterator); + free(entry); break; } } iterator->destroy(iterator); - - if (found == NULL) - { - /* create a new object for a never-seen thread */ - found = malloc_thing(active_listener_t); - found->id = pthread_self(); - pthread_cond_init(&found->cond, NULL); - this->active_listeners->insert_last(this->active_listeners, found); - } - - return found; -} - -/** - * disable a listener to cleanly clean up - */ -static void unregister(active_listener_t *listener) -{ - listener->state = UNREGISTERED; - pthread_cond_broadcast(&listener->cond); } /** * Implementation of bus_t.listen. */ -static signal_t listen_(private_bus_t *this, level_t *level, int *thread, - ike_sa_t **ike_sa, char** format, va_list* args) +static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job) { - active_listener_t *listener; - int oldstate; - - pthread_mutex_lock(&this->mutex); - listener = get_active_listener(this); - /* go "listening", say hello to a thread which have a signal for us */ - listener->state = LISTENING; - pthread_cond_broadcast(&listener->cond); - /* wait until it has us delivered a signal, and go back to "registered". - * we allow cancellation here, but must cleanly disable the listener. */ - pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); - pthread_cleanup_push((void*)unregister, listener); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - pthread_cond_wait(&listener->cond, &this->mutex); - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - pthread_cleanup_pop(0); - - pthread_mutex_unlock(&this->mutex); - - /* return signal values */ - *level = listener->level; - *thread = listener->thread; - *ike_sa = listener->ike_sa; - *format = listener->format; - va_copy(*args, listener->args); - va_end(listener->args); + int old; + cleanup_data_t data; - return listener->signal; -} + data.this = this; + data.entry = entry_create(listener, TRUE); -/** - * Implementation of bus_t.set_listen_state. - */ -static void set_listen_state(private_bus_t *this, bool active) -{ - active_listener_t *listener; - pthread_mutex_lock(&this->mutex); - - listener = get_active_listener(this); - if (active) - { - listener->state = REGISTERED; - } - else + this->listeners->insert_last(this->listeners, data.entry); + charon->processor->queue_job(charon->processor, job); + pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); + pthread_cleanup_push((void*)listener_cleanup, &data); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old); + while (data.entry->blocker) { - listener->state = UNREGISTERED; - /* say hello to signal emitter; we are finished processing the signal */ - pthread_cond_broadcast(&listener->cond); + pthread_cond_wait(&data.entry->cond, &this->mutex); } - - pthread_mutex_unlock(&this->mutex); + pthread_setcancelstate(old, NULL); + pthread_cleanup_pop(FALSE); + /* unlock mutex */ + pthread_cleanup_pop(TRUE); + free(data.entry); } - /** * Implementation of bus_t.set_sa. */ @@ -324,72 +255,37 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, char* format, va_list args) { iterator_t *iterator; - bus_listener_t *listener; - active_listener_t *active_listener; + entry_t *entry; ike_sa_t *ike_sa; long thread; + pthread_mutex_lock(&this->mutex); ike_sa = pthread_getspecific(this->thread_sa); thread = get_thread_number(this); - pthread_mutex_lock(&this->mutex); - - /* do the job for all passive bus_listeners */ iterator = this->listeners->create_iterator(this->listeners, TRUE); - while (iterator->iterate(iterator, (void**)&listener)) + while (iterator->iterate(iterator, (void**)&entry)) { va_list args_copy; va_copy(args_copy, args); - if (!listener->signal(listener, signal, level, thread, - ike_sa, format, args_copy)) + if (!entry->listener->signal(entry->listener, signal, level, thread, + ike_sa, format, args_copy)) { - /* unregister listener if requested */ iterator->remove(iterator); + if (entry->blocker) + { + entry->blocker = FALSE; + pthread_cond_signal(&entry->cond); + } + else + { + free(entry); + } } va_end(args_copy); } iterator->destroy(iterator); - /* wake up all active listeners */ - iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE); - while (iterator->iterate(iterator, (void**)&active_listener)) - { - /* wait until all threads are registered. But if the thread raising - * the signal is the same as the one that listens, we skip it. - * Otherwise we would deadlock. */ - while (active_listener->id != pthread_self() && - active_listener->state == REGISTERED) - { - pthread_cond_wait(&active_listener->cond, &this->mutex); - } - /* if thread is listening now, give it the signal to process */ - if (active_listener->state == LISTENING) - { - active_listener->level = level; - active_listener->thread = thread; - active_listener->ike_sa = ike_sa; - active_listener->signal = signal; - active_listener->format = format; - va_copy(active_listener->args, args); - active_listener->state = REGISTERED; - pthread_cond_broadcast(&active_listener->cond); - } - } - - /* we must wait now until all are not in state REGISTERED, - * as they may still use our arguments */ - iterator->reset(iterator); - while (iterator->iterate(iterator, (void**)&active_listener)) - { - /* do not wait for ourself, it won't happen (see above) */ - while (active_listener->id != pthread_self() && - active_listener->state == REGISTERED) - { - pthread_cond_wait(&active_listener->cond, &this->mutex); - } - } - iterator->destroy(iterator); - pthread_mutex_unlock(&this->mutex); } @@ -411,8 +307,7 @@ static void signal_(private_bus_t *this, signal_t signal, level_t level, */ static void destroy(private_bus_t *this) { - this->active_listeners->destroy_function(this->active_listeners, free); - this->listeners->destroy(this->listeners); + this->listeners->destroy_function(this->listeners, free); free(this); } @@ -425,18 +320,17 @@ bus_t *bus_create() this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener; this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener; - this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_; - this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state; + this->public.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))listen_; this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa; this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_; this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal; this->public.destroy = (void(*)(bus_t*)) destroy; this->listeners = linked_list_create(); - this->active_listeners = linked_list_create(); pthread_mutex_init(&this->mutex, NULL); pthread_key_create(&this->thread_id, NULL); pthread_key_create(&this->thread_sa, NULL); - return &(this->public); + return &this->public; } + diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index 00f1ab7ac..f71018444 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -32,6 +32,7 @@ typedef struct bus_t bus_t; #include <sa/ike_sa.h> #include <sa/child_sa.h> +#include <processing/jobs/job.h> /** @@ -251,9 +252,7 @@ struct bus_listener_t { * in receiving event signals registers at the bus. Any signals sent to * are delivered to all registered listeners. * To deliver signals to threads, the blocking listen() call may be used - * to wait for a signal. However, passive listeners should be preferred, - * as listening actively requires some synchronization overhead as data - * must be passed from the raising thread to the listening thread. + * to wait for a signal. * * @ingroup bus */ @@ -280,44 +279,19 @@ struct bus_t { void (*remove_listener) (bus_t *this, bus_listener_t *listener); /** - * @brief Listen actively on the bus. + * @brief Register a listener and block the calling thread. * - * As we are fully multithreaded, we must provide a mechanism - * for active threads to listen to the bus. With the listen() method, - * a thread waits until a signal occurs, and then processes it. - * To prevent the listen() calling thread to miss signals emitted while - * it processes a signal, registration is required. This is done through - * the set_listen_state() method, see below. - * - * The listen() function is (has) a thread cancellation point, so you might - * want to register cleanup handlers. + * This call registers a listener and blocks the calling thread until + * its listeners function returns FALSE. This allows to wait for certain + * events. The associated job is executed after the listener has been + * registered, this allows to listen on events we initiate with the job + * without missing any signals. * * @param this bus - * @param level verbosity level of the signal - * @param thread receives thread number emitted the signal - * @param ike_sa receives the IKE_SA involved in the signal, or NULL - * @param format receives the format string supplied with the signal - * @param va_list receives the variable argument list for format - * @return the emitted signal type + * @param listener listener to register + * @param job job to execute asynchronously when registered, or NULL */ - signal_t (*listen) (bus_t *this, level_t* level, int *thread, - ike_sa_t **ike_sa, char** format, va_list* args); - - /** - * @brief Set the listening state of the calling thread. - * - * To prevent message loss for active listeners using listen(), threads - * must register themself to the bus before starting to listen(). When - * a signal occurs, the emitter waits until all threads with listen_state - * TRUE are waiting in the listen() method to process the signal. - * It is important that a thread with listen_state TRUE calls listen() - * periodically, or sets it's listening state to FALSE; otherwise - * all signal emitting threads get blocked on the bus. - * - * @param this bus - * @param active TRUE to set to listening - */ - void (*set_listen_state) (bus_t *this, bool active); + void (*listen)(bus_t *this, bus_listener_t *listener, job_t *job); /** * @brief Set the IKE_SA the calling thread is using. @@ -355,6 +329,10 @@ struct bus_t { * * Same as bus_t.signal(), but uses va_list argument list. * + * @todo Improve performace of vsignal implementation. This method is + * called extensively and therefore shouldn't allocate heap memory or + * do other expensive tasks! + * * @param this bus * @param singal kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal diff --git a/src/charon/config/backends/sqlite_backend.c b/src/charon/config/backends/sqlite_backend.c index 33093a735..e1c96c870 100644 --- a/src/charon/config/backends/sqlite_backend.c +++ b/src/charon/config/backends/sqlite_backend.c @@ -186,15 +186,15 @@ static peer_cfg_t *process_peer_cfg_row(private_sqlite_backend_t *this, 2, ike_cfg, local_id, remote_id, NULL, NULL, linked_list_create(), sqlite3_column_int(stmt, 4), /* cert_policy */ sqlite3_column_int(stmt, 5), /* auth_method */ - sqlite3_column_int(stmt, 6), /* eap_type */ + sqlite3_column_int(stmt, 6), 0 /* eap_type, vendor */ sqlite3_column_int(stmt, 7), /* keyingtries */ - sqlite3_column_int(stmt, 8), /* lifetime */ - sqlite3_column_int(stmt, 9), /* rekeytime */ - sqlite3_column_int(stmt, 10), /* jitter */ - sqlite3_column_int(stmt, 13), /* reauth */ + sqlite3_column_int(stmt, 8), /* rekey_time */ + sqlite3_column_int(stmt, 9), /* reauth_time */ + sqlite3_column_int(stmt, 10), /* jitter_time */ + sqlite3_column_int(stmt, 11), /* over_time */ sqlite3_column_int(stmt, 14), /* mobike */ - sqlite3_column_int(stmt, 11), /* dpd_delay */ - sqlite3_column_int(stmt, 12), /* dpd_action */ + sqlite3_column_int(stmt, 12), /* dpd_delay */ + sqlite3_column_int(stmt, 13), /* dpd_action */ local_vip, remote_vip, FALSE, NULL, NULL); add_children(this, peer_cfg, sqlite3_column_int(stmt, 0)); return peer_cfg; @@ -225,8 +225,9 @@ static peer_cfg_t *get_peer_cfg(private_sqlite_backend_t *this, if (sqlite3_prepare_v2(this->db, "SELECT peer_configs.oid, name, local_id, remote_id, cert_policy, " - "auth_method, eap_type, keyingtries, lifetime, rekeytime, jitter, " - "dpd_delay, dpd_action, reauth, mobike, local_vip, remote_vip, " + "auth_method, eap_type, keyingtries, " + "rekey_time, reauth_time, jitter_time, over_time, " + "dpd_delay, dpd_action, mobike, local_vip, remote_vip, " "local, remote, certreq " "FROM peer_configs, ike_configs " "ON peer_configs.ike_cfg = ike_configs.oid " diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c index b71e9e9e2..b838f032d 100644 --- a/src/charon/config/credentials/local_credential_store.c +++ b/src/charon/config/credentials/local_credential_store.c @@ -18,6 +18,8 @@ * 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. + * + * RCSID $Id: local_credential_store.c 3346 2007-11-16 20:23:29Z andreas $ */ #include <sys/stat.h> @@ -1394,7 +1396,7 @@ static void load_secrets(private_local_credential_store_t *this, bool reload) { continue; } - if (!extract_token(&ids, ':', &line)) + if (!extract_last_token(&ids, ':', &line)) { DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr); goto error; diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index d61ed9512..0b5d391c4 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -127,14 +127,14 @@ struct private_peer_cfg_t { eap_type_t eap_type; /** - * number of tries after giving up if peer does not respond + * EAP vendor ID if vendor specific type is used */ - u_int32_t keyingtries; + u_int32_t eap_vendor; /** - * user reauthentication instead of rekeying + * number of tries after giving up if peer does not respond */ - bool use_reauth; + u_int32_t keyingtries; /** * enable support for MOBIKE @@ -142,20 +142,24 @@ struct private_peer_cfg_t { bool use_mobike; /** - * Time before an SA gets invalid + * Time before starting rekeying + */ + u_int32_t rekey_time; + + /** + * Time before starting reauthentication */ - u_int32_t lifetime; + u_int32_t reauth_time; /** - * Time before an SA gets rekeyed + * Time, which specifies the range of a random value substracted from above. */ - u_int32_t rekeytime; + u_int32_t jitter_time; /** - * Time, which specifies the range of a random value - * substracted from lifetime. + * Delay before deleting a rekeying/reauthenticating SA */ - u_int32_t jitter; + u_int32_t over_time; /** * What to do with an SA when other peer seams to be dead? @@ -339,8 +343,9 @@ static auth_method_t get_auth_method(private_peer_cfg_t *this) /** * Implementation of connection_t.get_eap_type. */ -static eap_type_t get_eap_type(private_peer_cfg_t *this) +static eap_type_t get_eap_type(private_peer_cfg_t *this, u_int32_t *vendor) { + *vendor = this->eap_vendor; return this->eap_type; } @@ -353,29 +358,45 @@ static u_int32_t get_keyingtries(private_peer_cfg_t *this) } /** - * Implementation of peer_cfg_t.get_soft_lifetime + * Implementation of peer_cfg_t.get_rekey_time. */ -static u_int32_t get_lifetime(private_peer_cfg_t *this, bool rekey) +static u_int32_t get_rekey_time(private_peer_cfg_t *this) { - if (rekey) + if (this->rekey_time == 0) { - if (this->jitter == 0) - { - return this->rekeytime; - } - return this->rekeytime - (random() % this->jitter); + return 0; + } + if (this->jitter_time == 0) + { + return this->rekey_time; } - return this->lifetime; + return this->rekey_time - (random() % this->jitter_time); } - + +/** + * Implementation of peer_cfg_t.get_reauth_time. + */ +static u_int32_t get_reauth_time(private_peer_cfg_t *this) +{ + if (this->reauth_time == 0) + { + return 0; + } + if (this->jitter_time == 0) + { + return this->reauth_time; + } + return this->reauth_time - (random() % this->jitter_time); +} + /** - * Implementation of peer_cfg_t.use_reauth. + * Implementation of peer_cfg_t.get_over_time. */ -static bool use_reauth(private_peer_cfg_t *this) +static u_int32_t get_over_time(private_peer_cfg_t *this) { - return this->use_reauth; + return this->over_time; } - + /** * Implementation of peer_cfg_t.use_mobike. */ @@ -503,9 +524,10 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, identification_t *my_ca, identification_t *other_ca, linked_list_t *groups, cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, - u_int32_t keyingtries, u_int32_t lifetime, - u_int32_t rekeytime, u_int32_t jitter, - bool reauth, bool mobike, + u_int32_t eap_vendor, + u_int32_t keyingtries, u_int32_t rekey_time, + u_int32_t reauth_time, u_int32_t jitter_time, + u_int32_t over_time, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip, bool p2p_mediation, peer_cfg_t *p2p_mediated_by, @@ -527,10 +549,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_groups = (linked_list_t* (*)(peer_cfg_t *))get_groups; this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy; this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method; - this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *))get_eap_type; + this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *,u_int32_t*))get_eap_type; this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries; - this->public.get_lifetime = (u_int32_t (*) (peer_cfg_t *, bool rekey))get_lifetime; - this->public.use_reauth = (bool (*) (peer_cfg_t *))use_reauth; + this->public.get_rekey_time = (u_int32_t(*)(peer_cfg_t*))get_rekey_time; + this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time; + this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time; this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike; this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay; this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action; @@ -558,11 +581,20 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->cert_policy = cert_policy; this->auth_method = auth_method; this->eap_type = eap_type; + this->eap_vendor = eap_vendor; this->keyingtries = keyingtries; - this->lifetime = lifetime; - this->rekeytime = rekeytime; - this->jitter = jitter; - this->use_reauth = reauth; + this->rekey_time = rekey_time; + this->reauth_time = reauth_time; + if (rekey_time && jitter_time > rekey_time) + { + jitter_time = rekey_time; + } + if (reauth_time && jitter_time > reauth_time) + { + jitter_time = reauth_time; + } + this->jitter_time = jitter_time; + this->over_time = over_time; this->use_mobike = mobike; this->dpd_delay = dpd_delay; this->dpd_action = dpd_action; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index 3d238e6aa..7f1dbcab6 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -229,11 +229,16 @@ struct peer_cfg_t { /** * @brief Get the EAP type to use for peer authentication. + * + * If vendor specific types are used, a vendor ID != 0 is returned to + * to vendor argument. Then the returned type is specific for that + * vendor ID. * * @param this calling object + * @param vendor receives vendor specifier, 0 for predefined EAP types * @return authentication method */ - eap_type_t (*get_eap_type) (peer_cfg_t *this); + eap_type_t (*get_eap_type) (peer_cfg_t *this, u_int32_t *vendor); /** * @brief Get the max number of retries after timeout. @@ -244,27 +249,28 @@ struct peer_cfg_t { u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * @brief Get the lifetime of a IKE_SA. + * @brief Get a time to start rekeying (is randomized with jitter). * - * If "rekey" is set to TRUE, a lifetime is returned before the first - * rekeying should be started. If it is FALSE, the actual lifetime is - * returned when the IKE_SA must be deleted. - * The rekey time automatically contains a jitter to avoid simlutaneous - * rekeying. - * - * @param this child_config - * @param rekey TRUE to get rekey time - * @return lifetime in seconds + * @param this calling object + * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_lifetime) (peer_cfg_t *this, bool rekey); + u_int32_t (*get_rekey_time)(peer_cfg_t *this); /** - * @brief Should a full reauthentication be done instead of rekeying? - * + * @brief Get a time to start reauthentication (is randomized with jitter). + * * @param this calling object - * @return TRUE to use full reauthentication + * @return time in s when to start reauthentication, 0 disables it + */ + u_int32_t (*get_reauth_time)(peer_cfg_t *this); + + /** + * @brief Get the timeout of a rekeying/reauthenticating SA. + * + * @param thsi calling object + * @return timeout in s */ - bool (*use_reauth) (peer_cfg_t *this); + u_int32_t (*get_over_time)(peer_cfg_t *this); /** * @brief Use MOBIKE (RFC4555) if peer supports it? @@ -392,10 +398,12 @@ struct peer_cfg_t { * @param cert_policy should we send a certificate payload? * @param auth_method auth method to use to authenticate us * @param eap_type EAP type to use for peer authentication + * @param eap_vendor EAP vendor identifier, if vendor specific type is used * @param keyingtries how many keying tries should be done before giving up - * @param lifetime lifetime before deleting an SA - * @param rekeytime lifetime before rekeying an SA - * @param jitter range of random to substract from rekeytime + * @param rekey_time timeout before starting rekeying + * @param reauth_time timeout before starting reauthentication + * @param jitter_time timerange to randomly substract from rekey/reauth time + * @param over_time maximum overtime before closing a rekeying/reauth SA * @param reauth sould be done reauthentication instead of rekeying? * @param mobike use MOBIKE (RFC4555) if peer supports it * @param dpd_delay after how many seconds of inactivity to check DPD @@ -414,9 +422,10 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, identification_t *my_ca, identification_t *other_ca, linked_list_t *groups, cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, - u_int32_t keyingtries, u_int32_t lifetime, - u_int32_t rekeytime, u_int32_t jitter, - bool reauth, bool mobike, + u_int32_t eap_vendor, + u_int32_t keyingtries, u_int32_t rekey_time, + u_int32_t reauth_time, u_int32_t jitter_time, + u_int32_t over_time, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip, bool p2p_mediation, peer_cfg_t *p2p_mediated_by, diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c index c71036567..c14903c7d 100644 --- a/src/charon/control/interface_manager.c +++ b/src/charon/control/interface_manager.c @@ -56,18 +56,24 @@ struct private_interface_manager_t { linked_list_t *handles; }; + /** * helper struct to map bus listener callbacks to interface callbacks */ struct interface_bus_listener_t { /** - * bus listener callback function (called) + * public bus listener interface */ - bus_listener_t listener; + bus_listener_t public; + + /** + * status of the operation, return to method callers + */ + status_t status; /** - * IKE_SA to use for message filtering + * IKE SA to filter log output */ ike_sa_t *ike_sa; @@ -82,12 +88,48 @@ struct interface_bus_listener_t { void *param; /** - * caller has cancelled its listening subscription + * child configuration, used for initiate + */ + child_cfg_t *child_cfg; + + /** + * peer configuration, used for initiate + */ + peer_cfg_t *peer_cfg; + + /** + * unique ID, used for various methods + */ + u_int32_t id; +}; + + +typedef struct interface_job_t interface_job_t; + +/** + * job for asynchronous listen operations + */ +struct interface_job_t { + /** + * job interface + */ + job_t public; + + /** + * associated listener */ - bool cancelled; + interface_bus_listener_t listener; }; /** + * Implements the famous nop operation + */ +static void nop(job_t *job) +{ + /* NOP */ +} + +/** * Implementation of interface_manager_t.create_ike_sa_iterator. */ static iterator_t* create_ike_sa_iterator(interface_manager_t *this) @@ -106,17 +148,16 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { + case CHILD_UP_SUCCESS: + this->status = SUCCESS; + return FALSE; case IKE_UP_FAILED: case CHILD_UP_FAILED: - case CHILD_UP_SUCCESS: - { return FALSE; - } default: break; } @@ -125,112 +166,82 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, } /** - * listener function for terminate_ike + * execute function for initiate */ -static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate_execute(interface_job_t *job) { - if (this->ike_sa == ike_sa) + ike_sa_t *ike_sa; + ike_cfg_t *ike_cfg; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, + ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), + peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; + + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - return TRUE; -} - -/** - * listener function for terminate_child - */ -static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) + peer_cfg->destroy(peer_cfg); + + if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - return TRUE; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** - * listener function for route + * Implementation of interface_manager_t.initiate. */ -static bool route_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate(private_interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) { - if (this->ike_sa == ike_sa) + interface_job_t job; + + job.listener.public.signal = (void*)initiate_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.child_cfg = child_cfg; + job.listener.peer_cfg = peer_cfg; + job.public.execute = (void*)initiate_execute; + job.public.destroy = nop; + + if (callback == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case CHILD_ROUTE_SUCCESS: - case CHILD_ROUTE_FAILED: - { - return FALSE; - } - default: - break; - } + return initiate_execute(&job); } - return TRUE; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * listener function for unroute + * listener function for terminate_ike */ -static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) { if (this->ike_sa == ike_sa) { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { - case CHILD_UNROUTE_SUCCESS: - case CHILD_UNROUTE_FAILED: - { + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: return FALSE; - } default: break; } @@ -239,102 +250,29 @@ static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, } /** - * remove a previously registered listener from the bus + * execute function for terminate_ike */ -static void remove_listener(interface_bus_listener_t *listener) -{ - charon->bus->remove_listener(charon->bus, &listener->listener); -} - -/** - * Implementation of interface_manager_t.initiate. - */ -static status_t initiate(private_interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t terminate_ike_execute(interface_job_t *job) { ike_sa_t *ike_sa; - ike_cfg_t *ike_cfg; - status_t retval = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, - ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), - peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); - - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - peer_cfg->destroy(peer_cfg); - - listener.listener.signal = (void*)initiate_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS) - { - charon->bus->set_listen_state(charon->bus, FALSE); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - return FAILED; - } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - if (callback == NULL) + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, FALSE); + if (ike_sa == NULL) { - /* don't wait for a result if no callback is specified */ - charon->bus->set_listen_state(charon->bus, FALSE); - return NEED_MORE; - } + SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; - /* wait until we get a result */ - while (TRUE) + if (ike_sa->delete(ike_sa) == DESTROY_ME) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - retval = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* ike_sa is a valid pointer until we get one of the signals */ - if (ike_sa == current) - { - switch (signal) - { - case CHILD_UP_SUCCESS: - retval = SUCCESS; - case CHILD_UP_FAILED: - case IKE_UP_FAILED: - break; - default: - continue; - } - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, FALSE); - return retval; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** @@ -343,107 +281,78 @@ static status_t initiate(private_interface_manager_t *this, static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id, interface_manager_cb_t callback, void *param) { - ike_sa_t *ike_sa; - status_t status = FAILED;; - interface_bus_listener_t listener; + interface_job_t job; - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - unique_id, FALSE); - if (ike_sa == NULL) - { - return NOT_FOUND; - } - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - listener.listener.signal = (void*)terminate_ike_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete(ike_sa); - if (status == DESTROY_ME) + job.listener.public.signal = (void*)terminate_ike_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = unique_id; + job.public.execute = (void*)terminate_ike_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_ike_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} +/** + * listener function for terminate_child + */ +static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until IKE_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_DOWN_SUCCESS: + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: + case CHILD_DOWN_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.terminate_child. + * execute function for terminate_child */ -static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static status_t terminate_child_execute(interface_job_t *job) { ike_sa_t *ike_sa; child_sa_t *child_sa; iterator_t *iterator; - status_t status = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } + listener->ike_sa = ike_sa; iterator = ike_sa->create_child_sa_iterator(ike_sa); while (iterator->iterate(iterator, (void**)&child_sa)) { if (child_sa->get_state(child_sa) != CHILD_ROUTED && - child_sa->get_reqid(child_sa) == reqid) + child_sa->get_reqid(child_sa) == listener->id) { break; } @@ -453,160 +362,203 @@ static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, if (child_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with " + "ID %d not found", listener->id); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); return NOT_FOUND; } - listener.listener.signal = (void*)terminate_child_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising */ - if (callback) + if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) { - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - if (status == DESTROY_ME) + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.terminate_child. + */ +static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)terminate_child_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)terminate_child_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_child_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for route + */ +static bool route_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until CHILD_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_ROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_ROUTE_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.route. + * execute function for route */ -static status_t route(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t route_execute(interface_job_t *job) { ike_sa_t *ike_sa; ike_cfg_t *ike_cfg; - status_t status = SUCCESS; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; if (ike_sa->get_peer_cfg(ike_sa) == NULL) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)route_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.route. + */ +static status_t route(interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; - if (ike_sa->route(ike_sa, child_cfg) != SUCCESS) + job.listener.public.signal = (void*)route_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.peer_cfg = peer_cfg; + job.listener.child_cfg = child_cfg; + job.public.execute = (void*)route_execute; + job.public.destroy = nop; + + if (callback == NULL) { - status = FAILED; + return route_execute(&job); } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * Implementation of interface_manager_t.unroute. + * listener function for unroute */ -static status_t unroute(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_UNROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_UNROUTE_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} +/** + * execute function for unroute + */ +static status_t unroute_execute(interface_job_t *job) { ike_sa_t *ike_sa; - status_t status; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + listener->ike_sa = ike_sa; + if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)unroute_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - status = ike_sa->unroute(ike_sa, reqid); - if (status == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - status = SUCCESS; - } - else + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.unroute. + */ +static status_t unroute(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)unroute_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)unroute_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return unroute_execute(&job); } - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 66ed423ae..b51d53ebd 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -239,13 +239,13 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) bool other_ca_same =FALSE; host_t *my_host, *other_host, *my_subnet, *other_subnet; host_t *my_vip = NULL, *other_vip = NULL; - linked_list_t *my_groups = linked_list_create(); linked_list_t *other_groups = linked_list_create(); proposal_t *proposal; traffic_selector_t *my_ts, *other_ts; char *interface; bool use_existing = FALSE; iterator_t *iterator; + u_int32_t vendor; pop_string(msg, &msg->add_conn.name); DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); @@ -262,7 +262,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) DBG2(DBG_CFG, " p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by); DBG2(DBG_CFG, " p2p_peerid=%s", msg->add_conn.p2p.peerid); - my_host = msg->add_conn.me.address? + my_host = msg->add_conn.me.address ? host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL; if (my_host == NULL) { @@ -365,11 +365,11 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) } } else -#endif /* P2P */ { - // no peer ID supplied, assume right ID + /* no peer ID supplied, assume right ID */ peer_id = other_id->clone(other_id); } +#endif /* P2P */ my_subnet = host_create_from_string(msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT); @@ -544,7 +544,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) && ietfAttr_list_equals(other_groups, peer_cfg->get_groups(peer_cfg)) && peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) && peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method - && peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type) + && peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type + && vendor == msg->add_conn.eap_vendor) { DBG1(DBG_CFG, "reusing existing configuration '%s'", peer_cfg->get_name(peer_cfg)); @@ -564,9 +565,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) other_host->destroy(other_host); other_id->destroy(other_id); other_ca->destroy(other_ca); - peer_id->destroy(peer_id); + DESTROY_IF(peer_id); DESTROY_IF(mediated_by_cfg); - ietfAttr_list_destroy(my_groups); ietfAttr_list_destroy(other_groups); } else @@ -613,15 +613,25 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) ike_cfg->add_proposal(ike_cfg, proposal); } + u_int32_t rekey = 0, reauth = 0, over, jitter; + + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + over = msg->add_conn.rekey.margin; + if (msg->add_conn.rekey.reauth) + { + reauth = msg->add_conn.rekey.ike_lifetime - over; + } + else + { + rekey = msg->add_conn.rekey.ike_lifetime - over; + } peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1, ike_cfg, my_id, other_id, my_ca, other_ca, other_groups, - msg->add_conn.me.sendcert, - msg->add_conn.auth_method, msg->add_conn.eap_type, - msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime, - msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin, - msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, - msg->add_conn.rekey.reauth, msg->add_conn.mobike, + msg->add_conn.me.sendcert, msg->add_conn.auth_method, + msg->add_conn.eap_type, msg->add_conn.eap_vendor, + msg->add_conn.rekey.tries, rekey, reauth, jitter, over, + msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip, msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id); } @@ -1104,9 +1114,8 @@ static void stroke_del_ca(stroke_msg_t *msg, FILE *out) */ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) { - peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa); ike_sa_id_t *id = ike_sa->get_id(ike_sa); - u_int32_t next, now = time(NULL); + u_int32_t rekey, reauth; fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), @@ -1116,21 +1125,26 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) if (all) { - fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s, ", + fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); - ike_sa->get_stats(ike_sa, &next); - if (next) + rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); + reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); + if (rekey) { - fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ? - "reauthentication" : "rekeying", &now, &next); + fprintf(out, ", rekeying in %V", &rekey); } - else + if (reauth) { - fprintf(out, "rekeying disabled\n"); + fprintf(out, ", reauthentication in %V", &reauth); } + if (!rekey && !reauth) + { + fprintf(out, ", rekeying disabled"); + } + fprintf(out, "\n"); } } @@ -1188,7 +1202,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) if (rekey) { - fprintf(out, "in %V", &now, &rekey); + fprintf(out, "in %#V", &now, &rekey); } else { @@ -1692,7 +1706,6 @@ static job_requeue_t stroke_process(int *fdp) return JOB_REQUEUE_NONE; } - /** * Implementation of private_stroke_interface_t.stroke_receive. */ diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c index 02da1064d..aa2a554a0 100644 --- a/src/charon/control/interfaces/xml_interface.c +++ b/src/charon/control/interfaces/xml_interface.c @@ -91,6 +91,9 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i char *type = ""; while (TRUE) { + case ID_ANY: + type = "any"; + break; case ID_IPV4_ADDR: type = "ipv4"; break; @@ -114,9 +117,6 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i xmlTextWriterWriteFormatString(writer, "%D", id); break; } - case ID_ANY: - xmlTextWriterWriteAttribute(writer, "type", "any"); - break; default: /* TODO: base64 keyid */ xmlTextWriterWriteAttribute(writer, "type", "keyid"); @@ -146,17 +146,15 @@ static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) } /** - * write a childEnd + * write networks element */ -static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +static void write_networks(xmlTextWriterPtr writer, char *element, + linked_list_t *list) { iterator_t *iterator; - linked_list_t *list; traffic_selector_t *ts; - xmlTextWriterWriteFormatElement(writer, "spi", "%lx", - htonl(child->get_spi(child, local))); - xmlTextWriterStartElement(writer, "networks"); - list = child->get_traffic_selectors(child, local); + + xmlTextWriterStartElement(writer, element); iterator = list->create_iterator(list, TRUE); while (iterator->iterate(iterator, (void**)&ts)) { @@ -171,6 +169,19 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca } /** + * write a childEnd + */ +static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +{ + linked_list_t *list; + + xmlTextWriterWriteFormatElement(writer, "spi", "%lx", + htonl(child->get_spi(child, local))); + list = child->get_traffic_selectors(child, local); + write_networks(writer, "networks", list); +} + +/** * write a child_sa_t */ static void write_child(xmlTextWriterPtr writer, child_sa_t *child) @@ -284,6 +295,201 @@ static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer } /** + * process a configlist query request message + */ +static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + iterator_t *iterator; + peer_cfg_t *peer_cfg; + + /* <configlist> */ + xmlTextWriterStartElement(writer, "configlist"); + + iterator = charon->backends->create_iterator(charon->backends); + while (iterator->iterate(iterator, (void**)&peer_cfg)) + { + iterator_t *children; + child_cfg_t *child_cfg; + ike_cfg_t *ike_cfg; + linked_list_t *list; + + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { /* only IKEv2 connections yet */ + continue; + } + + /* <peerconfig> */ + xmlTextWriterStartElement(writer, "peerconfig"); + xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); + write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); + write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); + + /* <ikeconfig> */ + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + xmlTextWriterStartElement(writer, "ikeconfig"); + write_address(writer, "local", ike_cfg->get_my_host(ike_cfg)); + write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg)); + xmlTextWriterEndElement(writer); + /* </ikeconfig> */ + + /* <childconfiglist> */ + xmlTextWriterStartElement(writer, "childconfiglist"); + children = peer_cfg->create_child_cfg_iterator(peer_cfg); + while (children->iterate(children, (void**)&child_cfg)) + { + /* <childconfig> */ + xmlTextWriterStartElement(writer, "childconfig"); + xmlTextWriterWriteElement(writer, "name", + child_cfg->get_name(child_cfg)); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + write_networks(writer, "local", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + write_networks(writer, "remote", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + xmlTextWriterEndElement(writer); + /* </childconfig> */ + } + children->destroy(children); + /* </childconfiglist> */ + xmlTextWriterEndElement(writer); + /* </peerconfig> */ + xmlTextWriterEndElement(writer); + } + iterator->destroy(iterator); + /* </configlist> */ + xmlTextWriterEndElement(writer); +} + +/** + * callback which logs to a XML writer + */ +static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level, + ike_sa_t* ike_sa, char* format, va_list args) +{ + if (level <= 1) + { + /* <item> */ + xmlTextWriterStartElement(writer, "item"); + xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); + xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal); + xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self()); + xmlTextWriterWriteVFormatString(writer, format, args); + xmlTextWriterEndElement(writer); + /* </item> */ + } + return TRUE; +} + +/** + * process a *terminate control request message + */ +static void request_control_terminate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + u_int32_t id; + status_t status; + + str = xmlTextReaderConstValue(reader); + if (str == NULL || !(id = atoi(str))) + { + DBG1(DBG_CFG, "error parsing XML id string"); + return; + } + DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + if (ike) + { + status = charon->interfaces->terminate_ike( + charon->interfaces, id, + (interface_manager_cb_t)xml_callback, writer); + } + else + { + status = charon->interfaces->terminate_child( + charon->interfaces, id, + (interface_manager_cb_t)xml_callback, writer); + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a *initiate control request message + */ +static void request_control_initiate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + status_t status = FAILED; + peer_cfg_t *peer; + child_cfg_t *child = NULL; + iterator_t *iterator; + + str = xmlTextReaderConstValue(reader); + if (str == NULL) + { + DBG1(DBG_CFG, "error parsing XML config name string"); + return; + } + DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str); + if (peer) + { + iterator = peer->create_child_cfg_iterator(peer); + if (ike) + { + if (!iterator->iterate(iterator, (void**)&child)) + { + child = NULL; + } + child->get_ref(child); + } + else + { + while (iterator->iterate(iterator, (void**)&child)) + { + if (streq(child->get_name(child), str)) + { + child->get_ref(child); + break; + } + child = NULL; + } + } + iterator->destroy(iterator); + if (child) + { + status = charon->interfaces->initiate(charon->interfaces, + peer, child, (interface_manager_cb_t)xml_callback, + writer); + } + else + { + peer->destroy(peer); + } + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** * process a query request */ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) @@ -299,6 +505,11 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) request_query_ikesa(reader, writer); break; } + if (streq(xmlTextReaderConstName(reader), "configlist")) + { + request_query_config(reader, writer); + break; + } } } /* </query> */ @@ -306,6 +517,43 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) } /** + * process a control request + */ +static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* <control> */ + xmlTextWriterStartElement(writer, "control"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesaterminate")) + { + request_control_terminate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsaterminate")) + { + request_control_terminate(reader, writer, FALSE); + break; + } + if (streq(xmlTextReaderConstName(reader), "ikesainitiate")) + { + request_control_initiate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsainitiate")) + { + request_control_initiate(reader, writer, FALSE); + break; + } + } + } + /* </control> */ + xmlTextWriterEndElement(writer); +} + +/** * process a request message */ static void request(xmlTextReaderPtr reader, char *id, int fd) @@ -337,6 +585,11 @@ static void request(xmlTextReaderPtr reader, char *id, int fd) request_query(reader, writer); break; } + if (streq(xmlTextReaderConstName(reader), "control")) + { + request_control(reader, writer); + break; + } } } /* </message> and close document */ diff --git a/src/charon/daemon.c b/src/charon/daemon.c index 9e151c305..ee9710424 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -338,7 +338,7 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) this->public.interfaces = interface_manager_create(); this->public.backends = backend_manager_create(); this->public.kernel_interface = kernel_interface_create(); - this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT); + this->public.socket = socket_create(); this->public.sender = sender_create(); this->public.receiver = receiver_create(); diff --git a/src/charon/encoding/payloads/configuration_attribute.c b/src/charon/encoding/payloads/configuration_attribute.c index 0aa82169f..afd08c6be 100644 --- a/src/charon/encoding/payloads/configuration_attribute.c +++ b/src/charon/encoding/payloads/configuration_attribute.c @@ -165,7 +165,7 @@ static status_t verify(private_configuration_attribute_t *this) default: DBG1(DBG_ENC, "unknown attribute type %N", configuration_attribute_type_names, this->attribute_type); - return FAILED; + break; } if (failed) diff --git a/src/charon/encoding/payloads/eap_payload.c b/src/charon/encoding/payloads/eap_payload.c index 79ab32fe5..345114af0 100644 --- a/src/charon/encoding/payloads/eap_payload.c +++ b/src/charon/encoding/payloads/eap_payload.c @@ -235,11 +235,23 @@ static u_int8_t get_identifier(private_eap_payload_t *this) /** * Implementation of eap_payload_t.get_type. */ -static eap_type_t get_type(private_eap_payload_t *this) +static eap_type_t get_type(private_eap_payload_t *this, u_int32_t *vendor) { + eap_type_t type; + + *vendor = 0; if (this->data.len > 4) { - return *(this->data.ptr + 4); + type = *(this->data.ptr + 4); + if (type != EAP_EXPANDED) + { + return type; + } + if (this->data.len >= 12) + { + *vendor = ntohl(*(u_int32_t*)(this->data.ptr + 4)) & 0x00FFFFFF; + return ntohl(*(u_int32_t*)(this->data.ptr + 8)); + } } return 0; } @@ -275,7 +287,7 @@ eap_payload_t *eap_payload_create() this->public.set_data = (void (*) (eap_payload_t *,chunk_t))set_data; this->public.get_code = (eap_code_t (*) (eap_payload_t*))get_code; this->public.get_identifier = (u_int8_t (*) (eap_payload_t*))get_identifier; - this->public.get_type = (eap_type_t (*) (eap_payload_t*))get_type; + this->public.get_type = (eap_type_t (*) (eap_payload_t*,u_int32_t*))get_type; /* private variables */ this->critical = FALSE; @@ -329,3 +341,4 @@ eap_payload_t *eap_payload_create_nak() this->set_data(this, data); return this; } + diff --git a/src/charon/encoding/payloads/eap_payload.h b/src/charon/encoding/payloads/eap_payload.h index 13c0ade80..3addbb838 100644 --- a/src/charon/encoding/payloads/eap_payload.h +++ b/src/charon/encoding/payloads/eap_payload.h @@ -95,9 +95,10 @@ struct eap_payload_t { * @brief Get the EAP method type. * * @param this calling eap_payload_t object - * @return EAP method type + * @param vendor pointer receiving vendor identifier + * @return EAP method type, vendor specific if vendor != 0 */ - eap_type_t (*get_type) (eap_payload_t *this); + eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); /** * @brief Destroys an eap_payload_t object. diff --git a/src/charon/encoding/payloads/endpoint_notify.c b/src/charon/encoding/payloads/endpoint_notify.c index 30f3ecd5f..98bfb2ea0 100644 --- a/src/charon/encoding/payloads/endpoint_notify.c +++ b/src/charon/encoding/payloads/endpoint_notify.c @@ -76,6 +76,13 @@ struct private_endpoint_notify_t { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +ENUM(p2p_endpoint_type_names, HOST, RELAYED, + "HOST", + "SERVER_REFLEXIVE", + "PEER_REFLEXIVE", + "RELAYED" +); + /** * Helper functions to parse integer values */ @@ -152,14 +159,10 @@ static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t switch(this->family) { - case NO_FAMILY: - this->endpoint = NULL; - break; - case IPv6: addr_family = AF_INET6; addr.len = 16; - // fall-through + /* fall-through */ case IPv4: if (parse_uint16(&cur, top, &port) != SUCCESS) { @@ -177,8 +180,11 @@ static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t this->endpoint = host_create_from_chunk(addr_family, addr, port); break; + case NO_FAMILY: + default: + this->endpoint = NULL; + break; } - return SUCCESS; } @@ -213,7 +219,7 @@ static chunk_t build_notification_data(private_endpoint_notify_t *this) } port_chunk = chunk_from_thing(port); - // data = prio | family | type | port | addr + /* data = prio | family | type | port | addr */ data = chunk_cat("ccccc", prio_chunk, family_chunk, type_chunk, port_chunk, addr_chunk); DBG3(DBG_IKE, "p2p_endpoint_data %B", &data); @@ -251,7 +257,7 @@ static u_int32_t get_priority(private_endpoint_notify_t *this) */ static void set_priority(private_endpoint_notify_t *this, u_int32_t priority) { - return this->priority = priority; + this->priority = priority; } /** @@ -368,13 +374,15 @@ endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, ho this->priority = pow(2, 16) * P2P_PRIO_PEER; break; case RELAYED: + default: this->priority = pow(2, 16) * P2P_PRIO_RELAY; break; } this->priority += 65535; - if (!host) { + if (!host) + { return &this->public; } @@ -387,7 +395,8 @@ endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, ho this->family = IPv6; break; default: - // unsupported family type, we do not set the hsot (family is set to NO_FAMILY) + /* unsupported family type, we do not set the hsot + * (family is set to NO_FAMILY) */ return &this->public; } diff --git a/src/charon/encoding/payloads/endpoint_notify.h b/src/charon/encoding/payloads/endpoint_notify.h index 272301d5b..4a3a68f95 100644 --- a/src/charon/encoding/payloads/endpoint_notify.h +++ b/src/charon/encoding/payloads/endpoint_notify.h @@ -35,6 +35,11 @@ typedef struct endpoint_notify_t endpoint_notify_t; #include <encoding/payloads/notify_payload.h> +/** + * @brief P2P endpoint families. + * + * @ingroup payloads + */ enum p2p_endpoint_family_t { NO_FAMILY = 0, @@ -47,6 +52,11 @@ enum p2p_endpoint_family_t { }; +/** + * @brief P2P endpoint types. + * + * @ingroup payloads + */ enum p2p_endpoint_type_t { NO_TYPE = 0, @@ -64,6 +74,13 @@ enum p2p_endpoint_type_t { }; /** + * enum name for p2p_endpoint_type_t. + * + * @ingroup payloads + */ +extern enum_name_t *p2p_endpoint_type_names; + +/** * @brief Class representing a P2P_ENDPOINT notify. In fact it's not * the notify per se, but the notification data of that notify that is * handled with this class. diff --git a/src/charon/encoding/payloads/ike_header.c b/src/charon/encoding/payloads/ike_header.c index 7253e4f51..3a171b095 100644 --- a/src/charon/encoding/payloads/ike_header.c +++ b/src/charon/encoding/payloads/ike_header.c @@ -192,7 +192,8 @@ static status_t verify(private_ike_header_t *this) if (this->initiator_spi == 0 #ifdef P2P - // we allow zero spi for INFORMATIONAL exchanges, to allow P2P connectivity checks + /* we allow zero spi for INFORMATIONAL exchanges, + * to allow P2P connectivity checks */ && this->exchange_type != INFORMATIONAL #endif /* P2P */ ) diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index 74a6c3197..d32257af6 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -57,13 +57,9 @@ ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTH "INVALID_SELECTORS", "UNACCEPTABLE_ADDRESSES", "UNEXPECTED_NAT_DETECTED"); -#ifdef P2P ENUM_NEXT(notify_type_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED, "P2P_CONNECT_FAILED"); ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED, -#else -ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, -#endif /* P2P */ "INITIAL_CONTACT", "SET_WINDOW_SIZE", "ADDITIONAL_TS_POSSIBLE", @@ -86,7 +82,6 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETE "AUTH_LIFETIME"); ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, "EAP_ONLY_AUTHENTICATION"); -#ifdef P2P ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, @@ -97,9 +92,6 @@ ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, "P2P_SESSIONKEY", "P2P_RESPONSE"); ENUM_END(notify_type_names, P2P_RESPONSE); -#else -ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION); -#endif /* P2P */ ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, @@ -128,13 +120,9 @@ ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED "INVAL_SEL", "UNACCEPT_ADDR", "UNEXPECT_NAT"); -#ifdef P2P ENUM_NEXT(notify_type_short_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED, "P2P_CONN_FAIL"); ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED, -#else -ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, -#endif /* P2P */ "INIT_CONTACT", "SET_WINSIZE", "ADD_TS_POSS", @@ -157,7 +145,6 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NA "AUTH_LFT"); ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, "EAP_ONLY"); -#ifdef P2P ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, @@ -168,9 +155,6 @@ ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, "P2P_SKEY", "P2P_R"); ENUM_END(notify_type_short_names, P2P_RESPONSE); -#else -ENUM_END(notify_type_short_names, EAP_ONLY_AUTHENTICATION); -#endif /* P2P */ typedef struct private_notify_payload_t private_notify_payload_t; @@ -342,7 +326,15 @@ static status_t verify(private_notify_payload_t *this) } break; } - // FIXME: check size of P2P-NAT-T payloads + case AUTH_LIFETIME: + { + if (this->notification_data.len != 4) + { + bad_length = TRUE; + } + break; + } + /* FIXME: check size of P2P-NAT-T payloads */ default: /* TODO: verify */ break; diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 4a9ad992b..03f61d473 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -68,10 +68,9 @@ enum notify_type_t { INVALID_SELECTORS = 39, UNACCEPTABLE_ADDRESSES = 40, UNEXPECTED_NAT_DETECTED = 41, -#ifdef P2P /* P2P-NAT-T, private use */ P2P_CONNECT_FAILED = 8192, -#endif /* P2P */ + /* notify status messages */ INITIAL_CONTACT = 16384, SET_WINDOW_SIZE = 16385, @@ -99,7 +98,6 @@ enum notify_type_t { EAP_ONLY_AUTHENTICATION = 40960, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, -#ifdef P2P /* P2P-NAT-T, private use */ P2P_MEDIATION = 40962, P2P_ENDPOINT = 40963, @@ -107,7 +105,6 @@ enum notify_type_t { P2P_SESSIONID = 40965, P2P_SESSIONKEY = 40966, P2P_RESPONSE = 40967 -#endif /* P2P */ }; /** diff --git a/src/charon/network/socket-raw.c b/src/charon/network/socket-raw.c new file mode 100644 index 000000000..3b76ae570 --- /dev/null +++ b/src/charon/network/socket-raw.c @@ -0,0 +1,771 @@ +/** + * @file socket.c + * + * @brief Implementation of socket_t. + * + */ + +/* + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/udp.h> +#include <linux/ipsec.h> +#include <linux/filter.h> +#include <net/if.h> + +#include "socket.h" + +#include <daemon.h> + +/* constants for packet handling */ +#define IP_LEN sizeof(struct iphdr) +#define IP6_LEN sizeof(struct ip6_hdr) +#define UDP_LEN sizeof(struct udphdr) +#define MARKER_LEN sizeof(u_int32_t) + +/* offsets for packet handling */ +#define IP_PROTO_OFFSET 9 +#define IP6_PROTO_OFFSET 6 +#define IKE_VERSION_OFFSET 17 +#define IKE_LENGTH_OFFSET 24 + +/* from linux/in.h */ +#ifndef IP_IPSEC_POLICY +#define IP_IPSEC_POLICY 16 +#endif /*IP_IPSEC_POLICY*/ + +/* from linux/udp.h */ +#ifndef UDP_ENCAP +#define UDP_ENCAP 100 +#endif /*UDP_ENCAP*/ + +#ifndef UDP_ENCAP_ESPINUDP +#define UDP_ENCAP_ESPINUDP 2 +#endif /*UDP_ENCAP_ESPINUDP*/ + +/* needed for older kernel headers */ +#ifndef IPV6_2292PKTINFO +#define IPV6_2292PKTINFO 2 +#endif /*IPV6_2292PKTINFO*/ + +/* missing on uclibc */ +#ifndef IPV6_IPSEC_POLICY +#define IPV6_IPSEC_POLICY 34 +#endif /*IPV6_IPSEC_POLICY*/ + +typedef struct private_socket_t private_socket_t; + +/** + * Private data of an socket_t object + */ +struct private_socket_t{ + /** + * public functions + */ + socket_t public; + + /** + * regular port + */ + int port; + + /** + * port used for nat-t + */ + int natt_port; + + /** + * raw receiver socket for IPv4 + */ + int recv4; + + /** + * raw receiver socket for IPv6 + */ + int recv6; + + /** + * send socket on regular port for IPv4 + */ + int send4; + + /** + * send socket on regular port for IPv6 + */ + int send6; + + /** + * send socket on nat-t port for IPv4 + */ + int send4_natt; + + /** + * send socket on nat-t port for IPv6 + */ + int send6_natt; +}; + +/** + * implementation of socket_t.receive + */ +static status_t receiver(private_socket_t *this, packet_t **packet) +{ + char buffer[MAX_PACKET]; + chunk_t data; + packet_t *pkt; + struct udphdr *udp; + host_t *source = NULL, *dest = NULL; + int bytes_read = 0; + int data_offset, oldstate; + fd_set rfds; + + FD_ZERO(&rfds); + + if (this->recv4) + { + FD_SET(this->recv4, &rfds); + } + if (this->recv6) + { + FD_SET(this->recv6, &rfds); + } + + DBG2(DBG_NET, "waiting for data on raw sockets"); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0) + { + pthread_setcancelstate(oldstate, NULL); + return FAILED; + } + pthread_setcancelstate(oldstate, NULL); + + if (this->recv4 && FD_ISSET(this->recv4, &rfds)) + { + /* IPv4 raw sockets return the IP header. We read src/dest + * information directly from the raw header */ + struct iphdr *ip; + struct sockaddr_in src, dst; + + bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0); + if (bytes_read < 0) + { + DBG1(DBG_NET, "error reading from IPv4 socket: %s", strerror(errno)); + return FAILED; + } + DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read); + + /* read source/dest from raw IP/UDP header */ + if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) + { + DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)", + bytes_read); + return FAILED; + } + ip = (struct iphdr*) buffer; + udp = (struct udphdr*) (buffer + IP_LEN); + src.sin_family = AF_INET; + src.sin_addr.s_addr = ip->saddr; + src.sin_port = udp->source; + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = ip->daddr; + dst.sin_port = udp->dest; + source = host_create_from_sockaddr((sockaddr_t*)&src); + dest = host_create_from_sockaddr((sockaddr_t*)&dst); + + pkt = packet_create(); + pkt->set_source(pkt, source); + pkt->set_destination(pkt, dest); + DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); + data_offset = IP_LEN + UDP_LEN; + /* remove non esp marker */ + if (dest->get_port(dest) == IKEV2_NATT_PORT) + { + data_offset += MARKER_LEN; + } + /* fill in packet */ + data.len = bytes_read - data_offset; + data.ptr = malloc(data.len); + memcpy(data.ptr, buffer + data_offset, data.len); + pkt->set_data(pkt, data); + } + else if (this->recv6 && FD_ISSET(this->recv6, &rfds)) + { + /* IPv6 raw sockets return no IP header. We must query + * src/dest via socket options/ancillary data */ + struct msghdr msg; + struct cmsghdr *cmsgptr; + struct sockaddr_in6 src, dst; + struct iovec iov; + char ancillary[64]; + + msg.msg_name = &src; + msg.msg_namelen = sizeof(src); + iov.iov_base = buffer; + iov.iov_len = sizeof(buffer); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = ancillary; + msg.msg_controllen = sizeof(ancillary); + msg.msg_flags = 0; + + bytes_read = recvmsg(this->recv6, &msg, 0); + if (bytes_read < 0) + { + DBG1(DBG_NET, "error reading from IPv6 socket: %s", strerror(errno)); + return FAILED; + } + DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read); + + if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) + { + DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)", + bytes_read); + return FAILED; + } + + /* read ancillary data to get destination address */ + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) + { + if (cmsgptr->cmsg_len == 0) + { + DBG1(DBG_NET, "error reading IPv6 ancillary data"); + return FAILED; + } + if (cmsgptr->cmsg_level == SOL_IPV6 && + cmsgptr->cmsg_type == IPV6_2292PKTINFO) + { + struct in6_pktinfo *pktinfo; + pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr); + + memset(&dst, 0, sizeof(dst)); + memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr)); + dst.sin6_family = AF_INET6; + udp = (struct udphdr*) (buffer); + dst.sin6_port = udp->dest; + src.sin6_port = udp->source; + dest = host_create_from_sockaddr((sockaddr_t*)&dst); + } + } + /* ancillary data missing? */ + if (dest == NULL) + { + DBG1(DBG_NET, "error reading IPv6 packet header"); + return FAILED; + } + + source = host_create_from_sockaddr((sockaddr_t*)&src); + + pkt = packet_create(); + pkt->set_source(pkt, source); + pkt->set_destination(pkt, dest); + DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); + data_offset = UDP_LEN; + /* remove non esp marker */ + if (dest->get_port(dest) == IKEV2_NATT_PORT) + { + data_offset += MARKER_LEN; + } + /* fill in packet */ + data.len = bytes_read - data_offset; + data.ptr = malloc(data.len); + memcpy(data.ptr, buffer + data_offset, data.len); + pkt->set_data(pkt, data); + } + else + { + /* oops, shouldn't happen */ + return FAILED; + } + + /* return packet */ + *packet = pkt; + return SUCCESS; +} + +/** + * implementation of socket_t.send + */ +status_t sender(private_socket_t *this, packet_t *packet) +{ + int sport, skt, family; + ssize_t bytes_sent; + chunk_t data, marked; + host_t *src, *dst; + struct msghdr msg; + struct cmsghdr *cmsg; + struct iovec iov; + + src = packet->get_source(packet); + dst = packet->get_destination(packet); + data = packet->get_data(packet); + + DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst); + + /* send data */ + sport = src->get_port(src); + family = dst->get_family(dst); + if (sport == IKEV2_UDP_PORT) + { + if (family == AF_INET) + { + skt = this->send4; + } + else + { + skt = this->send6; + } + } + else if (sport == IKEV2_NATT_PORT) + { + if (family == AF_INET) + { + skt = this->send4_natt; + } + else + { + skt = this->send6_natt; + } + /* NAT keepalives without marker */ + if (data.len != 1 || data.ptr[0] != 0xFF) + { + /* add non esp marker to packet */ + if (data.len > MAX_PACKET - MARKER_LEN) + { + DBG1(DBG_NET, "unable to send packet: it's too big (%d bytes)", + data.len); + return FAILED; + } + marked = chunk_alloc(data.len + MARKER_LEN); + memset(marked.ptr, 0, MARKER_LEN); + memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len); + /* let the packet do the clean up for us */ + packet->set_data(packet, marked); + data = marked; + } + } + else + { + DBG1(DBG_NET, "unable to locate a send socket for port %d", sport); + return FAILED; + } + + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = dst->get_sockaddr(dst);; + msg.msg_namelen = *dst->get_sockaddr_len(dst); + iov.iov_base = data.ptr; + iov.iov_len = data.len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + if (!dst->is_anyaddr(dst)) + { + if (family == AF_INET) + { + char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; + struct in_pktinfo *pktinfo; + struct sockaddr_in *sin; + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); + memset(pktinfo, 0, sizeof(struct in_pktinfo)); + sin = (struct sockaddr_in*)src->get_sockaddr(src); + memcpy(&pktinfo->ipi_spec_dst, &sin->sin_addr, sizeof(struct in_addr)); + } + else + { + char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 *sin; + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_IPV6; + cmsg->cmsg_type = IPV6_2292PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); + memset(pktinfo, 0, sizeof(struct in6_pktinfo)); + sin = (struct sockaddr_in6*)src->get_sockaddr(src); + memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr)); + } + } + + bytes_sent = sendmsg(skt, &msg, 0); + + if (bytes_sent != data.len) + { + DBG1(DBG_NET, "error writing to socket: %s", strerror(errno)); + return FAILED; + } + return SUCCESS; +} + +/** + * open a socket to send packets + */ +static int open_send_socket(private_socket_t *this, int family, u_int16_t port) +{ + int on = TRUE; + int type = UDP_ENCAP_ESPINUDP; + struct sockaddr_storage addr; + u_int sol, ipsec_policy; + struct sadb_x_policy policy; + int skt; + + memset(&addr, 0, sizeof(addr)); + /* precalculate constants depending on address family */ + switch (family) + { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons(port); + sol = SOL_IP; + ipsec_policy = IP_IPSEC_POLICY; + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); + sin6->sin6_port = htons(port); + sol = SOL_IPV6; + ipsec_policy = IPV6_IPSEC_POLICY; + break; + } + default: + return 0; + } + + skt = socket(family, SOCK_DGRAM, IPPROTO_UDP); + if (skt < 0) + { + DBG1(DBG_NET, "could not open send socket: %s", strerror(errno)); + return 0; + } + + if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + { + DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + /* bypass outgoung IKE traffic on send socket */ + memset(&policy, 0, sizeof(policy)); + policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t); + policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; + policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + + if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) + { + DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + /* We don't receive packets on the send socket, but we need a INBOUND policy. + * Otherwise, UDP decapsulation does not work!!! */ + policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; + if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) + { + DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + /* bind the send socket */ + if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_NET, "unable to bind send socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + if (family == AF_INET) + { + /* enable UDP decapsulation globally, only for one socket needed */ + if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) + { + DBG1(DBG_NET, "unable to set UDP_ENCAP: %s; NAT-T may fail", + strerror(errno)); + } + } + + return skt; +} + +/** + * open a socket to receive packets + */ +static int open_recv_socket(private_socket_t *this, int family) +{ + int skt; + int on = TRUE; + u_int proto_offset, ip_len, sol, ipsec_policy, udp_header, ike_header; + struct sadb_x_policy policy; + + /* precalculate constants depending on address family */ + switch (family) + { + case AF_INET: + proto_offset = IP_PROTO_OFFSET; + ip_len = IP_LEN; + sol = SOL_IP; + ipsec_policy = IP_IPSEC_POLICY; + break; + case AF_INET6: + proto_offset = IP6_PROTO_OFFSET; + ip_len = 0; /* IPv6 raw sockets contain no IP header */ + sol = SOL_IPV6; + ipsec_policy = IPV6_IPSEC_POLICY; + break; + default: + return 0; + } + udp_header = ip_len; + ike_header = ip_len + UDP_LEN; + + /* This filter code filters out all non-IKEv2 traffic on + * a SOCK_RAW IP_PROTP_UDP socket. Handling of other + * IKE versions is done in pluto. + */ + struct sock_filter ikev2_filter_code[] = + { + /* Destination Port must be either port or natt_port */ + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_UDP_PORT, 1, 0), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_NATT_PORT, 5, 12), + /* port */ + /* IKE version must be 2.0 */ + BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10), + /* packet length is length in IKEv2 header + ip header + udp header */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET), + BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN), + BPF_STMT(BPF_RET+BPF_A, 0), + /* natt_port */ + /* nat-t: check for marker */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5), + /* nat-t: IKE version must be 2.0 */ + BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3), + /* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET), + BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN), + BPF_STMT(BPF_RET+BPF_A, 0), + /* packet doesn't match, ignore */ + BPF_STMT(BPF_RET+BPF_K, 0), + }; + + /* Filter struct to use with setsockopt */ + struct sock_fprog ikev2_filter = { + sizeof(ikev2_filter_code) / sizeof(struct sock_filter), + ikev2_filter_code + }; + + /* set up a raw socket */ + skt = socket(family, SOCK_RAW, IPPROTO_UDP); + if (skt < 0) + { + DBG1(DBG_NET, "unable to create raw socket: %s", strerror(errno)); + return 0; + } + + if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER, + &ikev2_filter, sizeof(ikev2_filter)) < 0) + { + DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + if (family == AF_INET6 && + /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as + * 2 or 50 depending on kernel header version */ + setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0) + { + DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + /* bypass incomining IKE traffic on this socket */ + memset(&policy, 0, sizeof(policy)); + policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t); + policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; + policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; + + if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) + { + DBG1(DBG_NET, "unable to set IPSEC_POLICY on raw socket: %s", + strerror(errno)); + close(skt); + return 0; + } + + return skt; +} + +/** + * implementation of socket_t.destroy + */ +static void destroy(private_socket_t *this) +{ + if (this->recv4) + { + close(this->recv4); + } + if (this->recv6) + { + close(this->recv6); + } + if (this->send4) + { + close(this->send4); + } + if (this->send6) + { + close(this->send6); + } + if (this->send4_natt) + { + close(this->send4_natt); + } + if (this->send6_natt) + { + close(this->send6_natt); + } + free(this); +} + +/* + * See header for description + */ +socket_t *socket_create() +{ + int key; + private_socket_t *this = malloc_thing(private_socket_t); + + /* public functions */ + this->public.send = (status_t(*)(socket_t*, packet_t*))sender; + this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver; + this->public.destroy = (void(*)(socket_t*)) destroy; + + this->recv4 = 0; + this->recv6 = 0; + this->send4 = 0; + this->send6 = 0; + this->send4_natt = 0; + this->send6_natt = 0; + + /* we open a AF_KEY socket to autoload the af_key module. Otherwise + * setsockopt(IPSEC_POLICY) won't work. */ + key = socket(AF_KEY, SOCK_RAW, PF_KEY_V2); + if (key == 0) + { + charon->kill(charon, "could not open AF_KEY socket"); + } + close(key); + + this->recv4 = open_recv_socket(this, AF_INET); + if (this->recv4 == 0) + { + DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled"); + } + else + { + this->send4 = open_send_socket(this, AF_INET, IKEV2_UDP_PORT); + if (this->send4 == 0) + { + DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled"); + close(this->recv4); + } + else + { + this->send4_natt = open_send_socket(this, AF_INET, IKEV2_NATT_PORT); + if (this->send4_natt == 0) + { + DBG1(DBG_NET, "could not open IPv4 NAT-T send socket"); + } + } + } + + this->recv6 = open_recv_socket(this, AF_INET6); + if (this->recv6 == 0) + { + DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled"); + } + else + { + this->send6 = open_send_socket(this, AF_INET6, IKEV2_UDP_PORT); + if (this->send6 == 0) + { + DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled"); + close(this->recv6); + } + else + { + this->send6_natt = open_send_socket(this, AF_INET6, IKEV2_NATT_PORT); + if (this->send6_natt == 0) + { + DBG1(DBG_NET, "could not open IPv6 NAT-T send socket"); + } + } + } + + if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6)) + { + DBG1(DBG_NET, "could not create any sockets"); + destroy(this); + charon->kill(charon, "socket initialization failed"); + } + + return (socket_t*)this; +} diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c index dd231ebed..a4c407579 100644 --- a/src/charon/network/socket.c +++ b/src/charon/network/socket.c @@ -7,7 +7,7 @@ /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -43,18 +43,9 @@ #include <daemon.h> -/* constants for packet handling */ -#define IP_LEN sizeof(struct iphdr) -#define IP6_LEN sizeof(struct ip6_hdr) -#define UDP_LEN sizeof(struct udphdr) +/* length of non-esp marker */ #define MARKER_LEN sizeof(u_int32_t) -/* offsets for packet handling */ -#define IP_PROTO_OFFSET 9 -#define IP6_PROTO_OFFSET 6 -#define IKE_VERSION_OFFSET 17 -#define IKE_LENGTH_OFFSET 24 - /* from linux/in.h */ #ifndef IP_IPSEC_POLICY #define IP_IPSEC_POLICY 16 @@ -84,51 +75,31 @@ typedef struct private_socket_t private_socket_t; /** * Private data of an socket_t object */ -struct private_socket_t{ +struct private_socket_t { /** * public functions */ socket_t public; - - /** - * regular port - */ - int port; - - /** - * port used for nat-t - */ - int natt_port; /** - * raw receiver socket for IPv4 + * IPv4 socket (500) */ - int recv4; + int ipv4; /** - * raw receiver socket for IPv6 - */ - int recv6; - - /** - * send socket on regular port for IPv4 + * IPv4 socket for NATT (4500) */ - int send4; - - /** - * send socket on regular port for IPv6 - */ - int send6; - + int ipv4_natt; + /** - * send socket on nat-t port for IPv4 + * IPv6 socket (500) */ - int send4_natt; - + int ipv6; + /** - * send socket on nat-t port for IPv6 + * IPv6 socket for NATT (4500) */ - int send6_natt; + int ipv6_natt; }; /** @@ -139,91 +110,72 @@ static status_t receiver(private_socket_t *this, packet_t **packet) char buffer[MAX_PACKET]; chunk_t data; packet_t *pkt; - struct udphdr *udp; host_t *source = NULL, *dest = NULL; int bytes_read = 0; int data_offset, oldstate; fd_set rfds; + int max_fd = 0, selected = 0; + u_int16_t port; FD_ZERO(&rfds); - if (this->recv4) + if (this->ipv4) { - FD_SET(this->recv4, &rfds); + FD_SET(this->ipv4, &rfds); } - if (this->recv6) + if (this->ipv4_natt) { - FD_SET(this->recv6, &rfds); + FD_SET(this->ipv4_natt, &rfds); } + if (this->ipv6) + { + FD_SET(this->ipv6, &rfds); + } + if (this->ipv6_natt) + { + FD_SET(this->ipv6_natt, &rfds); + } + max_fd = max(max(this->ipv4, this->ipv4_natt), max(this->ipv6, this->ipv6_natt)); - DBG2(DBG_NET, "waiting for data on raw sockets"); - + DBG2(DBG_NET, "waiting for data on sockets"); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0) + if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0) { pthread_setcancelstate(oldstate, NULL); return FAILED; } pthread_setcancelstate(oldstate, NULL); - if (this->recv4 && FD_ISSET(this->recv4, &rfds)) + if (FD_ISSET(this->ipv4, &rfds)) { - /* IPv4 raw sockets return the IP header. We read src/dest - * information directly from the raw header */ - struct iphdr *ip; - struct sockaddr_in src, dst; - - bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0); - if (bytes_read < 0) - { - DBG1(DBG_NET, "error reading from IPv4 socket: %s", strerror(errno)); - return FAILED; - } - DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read); - - /* read source/dest from raw IP/UDP header */ - if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) - { - DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)", - bytes_read); - return FAILED; - } - ip = (struct iphdr*) buffer; - udp = (struct udphdr*) (buffer + IP_LEN); - src.sin_family = AF_INET; - src.sin_addr.s_addr = ip->saddr; - src.sin_port = udp->source; - dst.sin_family = AF_INET; - dst.sin_addr.s_addr = ip->daddr; - dst.sin_port = udp->dest; - source = host_create_from_sockaddr((sockaddr_t*)&src); - dest = host_create_from_sockaddr((sockaddr_t*)&dst); - - pkt = packet_create(); - pkt->set_source(pkt, source); - pkt->set_destination(pkt, dest); - DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); - data_offset = IP_LEN + UDP_LEN; - /* remove non esp marker */ - if (dest->get_port(dest) == this->natt_port) - { - data_offset += MARKER_LEN; - } - /* fill in packet */ - data.len = bytes_read - data_offset; - data.ptr = malloc(data.len); - memcpy(data.ptr, buffer + data_offset, data.len); - pkt->set_data(pkt, data); + port = IKEV2_UDP_PORT; + selected = this->ipv4; } - else if (this->recv6 && FD_ISSET(this->recv6, &rfds)) + if (FD_ISSET(this->ipv4_natt, &rfds)) + { + port = IKEV2_NATT_PORT; + selected = this->ipv4_natt; + } + if (FD_ISSET(this->ipv6, &rfds)) + { + port = IKEV2_UDP_PORT; + selected = this->ipv6; + } + if (FD_ISSET(this->ipv6_natt, &rfds)) + { + port = IKEV2_NATT_PORT; + selected = this->ipv6_natt; + } + if (selected) { - /* IPv6 raw sockets return no IP header. We must query - * src/dest via socket options/ancillary data */ struct msghdr msg; struct cmsghdr *cmsgptr; - struct sockaddr_in6 src, dst; struct iovec iov; char ancillary[64]; + union { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + } src; msg.msg_name = &src; msg.msg_namelen = sizeof(src); @@ -234,18 +186,17 @@ static status_t receiver(private_socket_t *this, packet_t **packet) msg.msg_control = ancillary; msg.msg_controllen = sizeof(ancillary); msg.msg_flags = 0; - - bytes_read = recvmsg(this->recv6, &msg, 0); + bytes_read = recvmsg(selected, &msg, 0); if (bytes_read < 0) { - DBG1(DBG_NET, "error reading from IPv6 socket: %s", strerror(errno)); + DBG1(DBG_NET, "error reading socket: %s", strerror(errno)); return FAILED; } - DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read); + DBG3(DBG_NET, "received packet %b", buffer, bytes_read); - if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) + if (bytes_read < MARKER_LEN) { - DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)", + DBG3(DBG_NET, "received packet too short (%d bytes)", bytes_read); return FAILED; } @@ -256,40 +207,55 @@ static status_t receiver(private_socket_t *this, packet_t **packet) { if (cmsgptr->cmsg_len == 0) { - DBG1(DBG_NET, "error reading IPv6 ancillary data"); + DBG1(DBG_NET, "error reading ancillary data"); return FAILED; - } + } + if (cmsgptr->cmsg_level == SOL_IPV6 && cmsgptr->cmsg_type == IPV6_2292PKTINFO) { struct in6_pktinfo *pktinfo; pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr); + struct sockaddr_in6 dst; memset(&dst, 0, sizeof(dst)); memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr)); dst.sin6_family = AF_INET6; - udp = (struct udphdr*) (buffer); - dst.sin6_port = udp->dest; - src.sin6_port = udp->source; + dst.sin6_port = htons(port); dest = host_create_from_sockaddr((sockaddr_t*)&dst); } + if (cmsgptr->cmsg_level == SOL_IP && + cmsgptr->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgptr); + struct sockaddr_in dst; + + memset(&dst, 0, sizeof(dst)); + memcpy(&dst.sin_addr, &pktinfo->ipi_addr, sizeof(dst.sin_addr)); + dst.sin_family = AF_INET; + dst.sin_port = htons(port); + dest = host_create_from_sockaddr((sockaddr_t*)&dst); + } + if (dest) + { + break; + } } - /* ancillary data missing? */ if (dest == NULL) { - DBG1(DBG_NET, "error reading IPv6 packet header"); + DBG1(DBG_NET, "error reading IP header"); return FAILED; } - source = host_create_from_sockaddr((sockaddr_t*)&src); pkt = packet_create(); pkt->set_source(pkt, source); pkt->set_destination(pkt, dest); DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); - data_offset = UDP_LEN; + data_offset = 0; /* remove non esp marker */ - if (dest->get_port(dest) == this->natt_port) + if (dest->get_port(dest) == IKEV2_NATT_PORT) { data_offset += MARKER_LEN; } @@ -304,7 +270,6 @@ static status_t receiver(private_socket_t *this, packet_t **packet) /* oops, shouldn't happen */ return FAILED; } - /* return packet */ *packet = pkt; return SUCCESS; @@ -332,26 +297,26 @@ status_t sender(private_socket_t *this, packet_t *packet) /* send data */ sport = src->get_port(src); family = dst->get_family(dst); - if (sport == this->port) + if (sport == IKEV2_UDP_PORT) { if (family == AF_INET) { - skt = this->send4; + skt = this->ipv4; } else { - skt = this->send6; + skt = this->ipv6; } } - else if (sport == this->natt_port) + else if (sport == IKEV2_NATT_PORT) { if (family == AF_INET) { - skt = this->send4_natt; + skt = this->ipv4_natt; } else { - skt = this->send6_natt; + skt = this->ipv6_natt; } /* NAT keepalives without marker */ if (data.len != 1 || data.ptr[0] != 0xFF) @@ -437,12 +402,12 @@ status_t sender(private_socket_t *this, packet_t *packet) /** * open a socket to send packets */ -static int open_send_socket(private_socket_t *this, int family, u_int16_t port) +static int open_socket(private_socket_t *this, int family, u_int16_t port) { int on = TRUE; int type = UDP_ENCAP_ESPINUDP; struct sockaddr_storage addr; - u_int sol, ipsec_policy; + u_int sol, ipsec_policy, pktinfo; struct sadb_x_policy policy; int skt; @@ -458,6 +423,7 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port) sin->sin_port = htons(port); sol = SOL_IP; ipsec_policy = IP_IPSEC_POLICY; + pktinfo = IP_PKTINFO; break; } case AF_INET6: @@ -468,6 +434,7 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port) sin6->sin6_port = htons(port); sol = SOL_IPV6; ipsec_policy = IPV6_IPSEC_POLICY; + pktinfo = IPV6_2292PKTINFO; break; } default: @@ -477,39 +444,34 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port) skt = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (skt < 0) { - DBG1(DBG_NET, "could not open send socket: %s", strerror(errno)); + DBG1(DBG_NET, "could not open socket: %s", strerror(errno)); return 0; } - if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) { - DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %s", - strerror(errno)); + DBG1(DBG_NET, "unable to set SO_REUSEADDR on socket: %s", strerror(errno)); close(skt); return 0; } - /* bypass outgoung IKE traffic on send socket */ + /* bypass IKE traffic on socket */ memset(&policy, 0, sizeof(policy)); policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t); policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; - policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) { - DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s", + DBG1(DBG_NET, "unable to set IPSEC_POLICY on socket: %s", strerror(errno)); close(skt); return 0; } - - /* We don't receive packets on the send socket, but we need a INBOUND policy. - * Otherwise, UDP decapsulation does not work!!! */ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) { - DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s", + DBG1(DBG_NET, "unable to set IPSEC_POLICY on socket: %s", strerror(errno)); close(skt); return 0; @@ -518,138 +480,25 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port) /* bind the send socket */ if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - DBG1(DBG_NET, "unable to bind send socket: %s", - strerror(errno)); + DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno)); close(skt); return 0; } - if (family == AF_INET) + /* get additional packet info on receive */ + if (setsockopt(skt, sol, pktinfo, &on, sizeof(on)) < 0) { - /* enable UDP decapsulation globally, only for one socket needed */ - if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) - { - DBG1(DBG_NET, "unable to set UDP_ENCAP: %s; NAT-T may fail", - strerror(errno)); - } - } - - return skt; -} - -/** - * open a socket to receive packets - */ -static int open_recv_socket(private_socket_t *this, int family) -{ - int skt; - int on = TRUE; - u_int proto_offset, ip_len, sol, ipsec_policy, udp_header, ike_header; - struct sadb_x_policy policy; - - /* precalculate constants depending on address family */ - switch (family) - { - case AF_INET: - proto_offset = IP_PROTO_OFFSET; - ip_len = IP_LEN; - sol = SOL_IP; - ipsec_policy = IP_IPSEC_POLICY; - break; - case AF_INET6: - proto_offset = IP6_PROTO_OFFSET; - ip_len = 0; /* IPv6 raw sockets contain no IP header */ - sol = SOL_IPV6; - ipsec_policy = IPV6_IPSEC_POLICY; - break; - default: - return 0; - } - udp_header = ip_len; - ike_header = ip_len + UDP_LEN; - - /* This filter code filters out all non-IKEv2 traffic on - * a SOCK_RAW IP_PROTP_UDP socket. Handling of other - * IKE versions is done in pluto. - */ - struct sock_filter ikev2_filter_code[] = - { - /* Destination Port must be either port or natt_port */ - BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->port, 1, 0), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12), - /* port */ - /* IKE version must be 2.0 */ - BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10), - /* packet length is length in IKEv2 header + ip header + udp header */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET), - BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN), - BPF_STMT(BPF_RET+BPF_A, 0), - /* natt_port */ - /* nat-t: check for marker */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5), - /* nat-t: IKE version must be 2.0 */ - BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3), - /* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET), - BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN), - BPF_STMT(BPF_RET+BPF_A, 0), - /* packet doesn't match, ignore */ - BPF_STMT(BPF_RET+BPF_K, 0), - }; - - /* Filter struct to use with setsockopt */ - struct sock_fprog ikev2_filter = { - sizeof(ikev2_filter_code) / sizeof(struct sock_filter), - ikev2_filter_code - }; - - /* set up a raw socket */ - skt = socket(family, SOCK_RAW, IPPROTO_UDP); - if (skt < 0) - { - DBG1(DBG_NET, "unable to create raw socket: %s", strerror(errno)); - return 0; - } - - if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER, - &ikev2_filter, sizeof(ikev2_filter)) < 0) - { - DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %s", - strerror(errno)); + DBG1(DBG_NET, "unable to set IP_PKTINFO on socket: %s", strerror(errno)); close(skt); return 0; } - if (family == AF_INET6 && - /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as - * 2 or 50 depending on kernel header version */ - setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0) + /* enable UDP decapsulation globally, only for one socket needed */ + if (family == AF_INET && port == IKEV2_NATT_PORT && + setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) { - DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %s", - strerror(errno)); - close(skt); - return 0; - } - - /* bypass incomining IKE traffic on this socket */ - memset(&policy, 0, sizeof(policy)); - policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t); - policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; - policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; - - if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0) - { - DBG1(DBG_NET, "unable to set IPSEC_POLICY on raw socket: %s", - strerror(errno)); - close(skt); - return 0; + DBG1(DBG_NET, "unable to set UDP_ENCAP: %s", strerror(errno)); } - return skt; } @@ -658,29 +507,21 @@ static int open_recv_socket(private_socket_t *this, int family) */ static void destroy(private_socket_t *this) { - if (this->recv4) - { - close(this->recv4); - } - if (this->recv6) - { - close(this->recv6); - } - if (this->send4) + if (this->ipv4) { - close(this->send4); + close(this->ipv4); } - if (this->send6) + if (this->ipv4_natt) { - close(this->send6); + close(this->ipv4_natt); } - if (this->send4_natt) + if (this->ipv6) { - close(this->send4_natt); + close(this->ipv6); } - if (this->send6_natt) + if (this->ipv6_natt) { - close(this->send6_natt); + close(this->ipv6_natt); } free(this); } @@ -688,7 +529,7 @@ static void destroy(private_socket_t *this) /* * See header for description */ -socket_t *socket_create(u_int16_t port, u_int16_t natt_port) +socket_t *socket_create() { int key; private_socket_t *this = malloc_thing(private_socket_t); @@ -698,14 +539,10 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port) this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver; this->public.destroy = (void(*)(socket_t*)) destroy; - this->port = port; - this->natt_port = natt_port; - this->recv4 = 0; - this->recv6 = 0; - this->send4 = 0; - this->send6 = 0; - this->send4_natt = 0; - this->send6_natt = 0; + this->ipv4 = 0; + this->ipv6 = 0; + this->ipv4_natt = 0; + this->ipv6_natt = 0; /* we open a AF_KEY socket to autoload the af_key module. Otherwise * setsockopt(IPSEC_POLICY) won't work. */ @@ -715,59 +552,41 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port) charon->kill(charon, "could not open AF_KEY socket"); } close(key); - - this->recv4 = open_recv_socket(this, AF_INET); - if (this->recv4 == 0) + + this->ipv4 = open_socket(this, AF_INET, IKEV2_UDP_PORT); + if (this->ipv4 == 0) { - DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled"); + DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled"); } else { - this->send4 = open_send_socket(this, AF_INET, this->port); - if (this->send4 == 0) + this->ipv4_natt = open_socket(this, AF_INET, IKEV2_NATT_PORT); + if (this->ipv4_natt == 0) { - DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled"); - close(this->recv4); - } - else - { - this->send4_natt = open_send_socket(this, AF_INET, this->natt_port); - if (this->send4_natt == 0) - { - DBG1(DBG_NET, "could not open IPv4 NAT-T send socket"); - } + DBG1(DBG_NET, "could not open IPv4 NAT-T socket"); } } - - this->recv6 = open_recv_socket(this, AF_INET6); - if (this->recv6 == 0) + + this->ipv6 = open_socket(this, AF_INET6, IKEV2_UDP_PORT); + if (this->ipv6 == 0) { - DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled"); + DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled"); } else { - this->send6 = open_send_socket(this, AF_INET6, this->port); - if (this->send6 == 0) + this->ipv6_natt = open_socket(this, AF_INET6, IKEV2_NATT_PORT); + if (this->ipv6_natt == 0) { - DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled"); - close(this->recv6); - } - else - { - this->send6_natt = open_send_socket(this, AF_INET6, this->natt_port); - if (this->send6_natt == 0) - { - DBG1(DBG_NET, "could not open IPv6 NAT-T send socket"); - } + DBG1(DBG_NET, "could not open IPv6 NAT-T socket"); } } - if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6)) + if (!this->ipv4 && !this->ipv6) { DBG1(DBG_NET, "could not create any sockets"); destroy(this); charon->kill(charon, "socket initialization failed"); - } - + } return (socket_t*)this; } + diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h index ef60fa7b6..4d8251325 100644 --- a/src/charon/network/socket.h +++ b/src/charon/network/socket.h @@ -100,13 +100,11 @@ struct socket_t { /** * @brief Create a socket_t, wich binds multiple sockets. * - * @param port port to bind socket to - * @param natt_port port to float to in NAT-T * @return socket_t object * * @ingroup network */ -socket_t *socket_create(u_int16_t port, u_int16_t natt_port); +socket_t *socket_create(); #endif /*SOCKET_H_*/ diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c index 6f534e0f7..53297916e 100644 --- a/src/charon/processing/jobs/callback_job.c +++ b/src/charon/processing/jobs/callback_job.c @@ -121,12 +121,7 @@ static void cancel(private_callback_job_t *this) { pthread_t thread; - /* wait until thread has started */ pthread_mutex_lock(&this->mutex); - while (this->thread == 0) - { - pthread_cond_wait(&this->condvar, &this->mutex); - } thread = this->thread; /* terminate its children */ @@ -134,8 +129,11 @@ static void cancel(private_callback_job_t *this) pthread_mutex_unlock(&this->mutex); /* terminate thread */ - pthread_cancel(thread); - pthread_join(thread, NULL); + if (thread) + { + pthread_cancel(thread); + pthread_join(thread, NULL); + } } /** @@ -159,6 +157,7 @@ static void execute(private_callback_job_t *this) continue; case JOB_REQUEUE_FAIR: { + this->thread = 0; charon->processor->queue_job(charon->processor, &this->public.job_interface); break; @@ -166,6 +165,7 @@ static void execute(private_callback_job_t *this) case JOB_REQUEUE_NONE: default: { + this->thread = 0; cleanup = TRUE; break; } diff --git a/src/charon/processing/jobs/initiate_mediation_job.c b/src/charon/processing/jobs/initiate_mediation_job.c index d78f8a202..b8d516e22 100644 --- a/src/charon/processing/jobs/initiate_mediation_job.c +++ b/src/charon/processing/jobs/initiate_mediation_job.c @@ -73,7 +73,7 @@ static bool initiate_callback(private_initiate_mediation_job_t *this, signal_t s { if (signal == CHILD_UP_SUCCESS) { - // mediation connection is up + /* mediation connection is up */ this->mediation_sa_id = ike_sa->get_id(ike_sa); this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id); return FALSE; @@ -85,7 +85,7 @@ static bool initiate_callback(private_initiate_mediation_job_t *this, signal_t s * Implementation of job_t.execute. */ static void initiate(private_initiate_mediation_job_t *this) -{//FIXME: check the logging +{ /* FIXME: check the logging */ ike_sa_t *mediated_sa, *mediation_sa; peer_cfg_t *mediated_cfg, *mediation_cfg; @@ -94,7 +94,8 @@ static void initiate(private_initiate_mediation_job_t *this) if (mediated_sa) { mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa); - mediated_cfg->get_ref(mediated_cfg); // get_peer_cfg returns an internal object + /* get_peer_cfg returns an internal object */ + mediated_cfg->get_ref(mediated_cfg); charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa); @@ -107,18 +108,19 @@ static void initiate(private_initiate_mediation_job_t *this) { mediated_cfg->destroy(mediated_cfg); mediation_cfg->destroy(mediation_cfg); - charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid + /* this pointer should still be valid */ + charon->bus->set_sa(charon->bus, mediated_sa); DBG1(DBG_IKE, "mediation with the same peer is already in progress, queued"); destroy(this); return; } - - mediation_cfg->get_ref(mediation_cfg); // we need an additional reference because initiate consumes one + /* we need an additional reference because initiate consumes one */ + mediation_cfg->get_ref(mediation_cfg); - // this function call blocks until the connection is up or failed - // we do not check the status, but NEED_MORE would be returned on success - // because the registered callback returns FALSE then - // this->mediation_sa_id is set in the callback + /* this function call blocks until the connection is up or failed + * we do not check the status, but NEED_MORE would be returned on success + * because the registered callback returns FALSE then + * this->mediation_sa_id is set in the callback */ charon->interfaces->initiate(charon->interfaces, mediation_cfg, NULL, (interface_manager_cb_t)initiate_callback, this); if (!this->mediation_sa_id) @@ -127,7 +129,7 @@ static void initiate(private_initiate_mediation_job_t *this) mediation_cfg->get_name(mediation_cfg)); mediation_cfg->destroy(mediation_cfg); mediated_cfg->destroy(mediated_cfg); - charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid + charon->bus->set_sa(charon->bus, mediated_sa); SIG(IKE_UP_FAILED, "mediation failed"); destroy(this); return; @@ -146,7 +148,7 @@ static void initiate(private_initiate_mediation_job_t *this) mediated_cfg->destroy(mediated_cfg); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa); - charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid + charon->bus->set_sa(charon->bus, mediated_sa); SIG(IKE_UP_FAILED, "mediation failed"); destroy(this); return; @@ -164,7 +166,7 @@ static void initiate(private_initiate_mediation_job_t *this) * Implementation of job_t.execute. */ static void reinitiate(private_initiate_mediation_job_t *this) -{//FIXME: check the logging +{ /* FIXME: check the logging */ ike_sa_t *mediated_sa, *mediation_sa; peer_cfg_t *mediated_cfg; @@ -173,7 +175,7 @@ static void reinitiate(private_initiate_mediation_job_t *this) if (mediated_sa) { mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa); - mediated_cfg->get_ref(mediated_cfg); // get_peer_cfg returns an internal object + mediated_cfg->get_ref(mediated_cfg); charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa); mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, @@ -187,7 +189,7 @@ static void reinitiate(private_initiate_mediation_job_t *this) mediated_cfg->destroy(mediated_cfg); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa); - charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid + charon->bus->set_sa(charon->bus, mediated_sa); SIG(IKE_UP_FAILED, "mediation failed"); destroy(this); return; diff --git a/src/charon/processing/jobs/mediation_job.c b/src/charon/processing/jobs/mediation_job.c index 6f5f74372..3b9d363d7 100644 --- a/src/charon/processing/jobs/mediation_job.c +++ b/src/charon/processing/jobs/mediation_job.c @@ -104,7 +104,7 @@ static void execute(private_mediation_job_t *this) { if (this->callback) { - // send callback to a peer + /* send callback to a peer */ if (target_sa->callback(target_sa, this->source) != SUCCESS) { DBG1(DBG_JOB, "callback for '%D' to '%D' failed", @@ -116,14 +116,14 @@ static void execute(private_mediation_job_t *this) } else { - // normal mediation between two peers + /* normal mediation between two peers */ if (target_sa->relay(target_sa, this->source, this->session_id, this->session_key, this->endpoints, this->response) != SUCCESS) { DBG1(DBG_JOB, "mediation between '%D' and '%D' failed", this->source, this->target); charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); - // FIXME: notify the initiator + /* FIXME: notify the initiator */ destroy(this); return; } diff --git a/src/charon/processing/jobs/process_message_job.c b/src/charon/processing/jobs/process_message_job.c index ec2e7735d..91e7a80bf 100644 --- a/src/charon/processing/jobs/process_message_job.c +++ b/src/charon/processing/jobs/process_message_job.c @@ -60,12 +60,13 @@ static void execute(private_process_message_job_t *this) ike_sa_t *ike_sa; #ifdef P2P - // if this is an unencrypted INFORMATIONAL exchange it is likely a - // connectivity check + /* if this is an unencrypted INFORMATIONAL exchange it is likely a + * connectivity check. */ if (this->message->get_exchange_type(this->message) == INFORMATIONAL && this->message->get_first_payload_type(this->message) != ENCRYPTED) { - // theoretically this could also be an error message see RFC 4306, section 1.5. + /* theoretically this could also be an error message + * see RFC 4306, section 1.5. */ DBG1(DBG_NET, "received unencrypted informational: from %#H to %#H", this->message->get_source(this->message), this->message->get_destination(this->message)); diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c index 2706585b0..ededb479a 100644 --- a/src/charon/processing/scheduler.c +++ b/src/charon/processing/scheduler.c @@ -87,6 +87,8 @@ struct private_scheduler_t { * Condvar to wait for next job. */ pthread_cond_t condvar; + + bool cancelled; }; /** @@ -148,9 +150,7 @@ static job_requeue_t schedule(private_scheduler_t * this) pthread_cond_wait(&this->condvar, &this->mutex); } pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - - pthread_mutex_unlock(&this->mutex); + pthread_cleanup_pop(TRUE); return JOB_REQUEUE_DIRECT; } @@ -234,6 +234,7 @@ static void schedule_job(private_scheduler_t *this, job_t *job, u_int32_t time) */ static void destroy(private_scheduler_t *this) { + this->cancelled = TRUE; this->job->cancel(this->job); this->list->destroy_function(this->list, (void*)event_destroy); free(this); @@ -251,6 +252,7 @@ scheduler_t * scheduler_create() this->public.destroy = (void(*)(scheduler_t*)) destroy; this->list = linked_list_create(); + this->cancelled = FALSE; pthread_mutex_init(&this->mutex, NULL); pthread_cond_init(&this->condvar, NULL); diff --git a/src/charon/sa/authenticators/eap/eap_aka.c b/src/charon/sa/authenticators/eap/eap_aka.c new file mode 100644 index 000000000..8fb1f85cd --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_aka.c @@ -0,0 +1,1440 @@ +/** + * @file eap_aka.c + * + * @brief Implementation of eap_aka_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + + +/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA + * payloads, as the IKEv2 parser is not suitable for that job. There are + * two simple methods for parsing payloads, read_header() and read_attribute(). + * Every EAP-AKA payload consists of a header and a list of attributes. Those + * functions mentioned read the data and return the type of the found + * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a + * build_aka_payload(), which builds the whole message from a variable + * argument list containing its attributes. + * The processing of messages is split up in various functions: + * - peer_process() - General processing multiplexer for the peer + * - peer_process_challenge() - Specific AKA-Challenge processor + * - peer_process_notification() - Processing of AKA-Notification + * - server_process() - General processing multiplexer for the server + * - peer_process_challenge() - Processing of a received Challenge response + * - peer_process_synchronize() - Process a sequence number synchronization + * - server_initiate() - Initiation method for the server, calls + * - server_initiate_challenge() - Initiation of AKA-Challenge + */ + +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + +#include "eap_aka.h" + +#include <daemon.h> +#include <library.h> +#include <utils/randomizer.h> +#include <crypto/hashers/hasher.h> +#include <crypto/prfs/fips_prf.h> + +/* Use test vectors specified in S.S0055 +#define TEST_VECTORS */ + +#define RAND_LENGTH 16 +#define RES_LENGTH 16 +#define SQN_LENGTH 6 +#define K_LENGTH 16 +#define MAC_LENGTH 8 +#define CK_LENGTH 16 +#define IK_LENGTH 16 +#define AK_LENGTH 6 +#define AMF_LENGTH 2 +#define FMK_LENGTH 4 +#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) +#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) +#define PAYLOAD_LENGTH 64 +#define MK_LENGTH 20 +#define MSK_LENGTH 64 +#define EMSK_LENGTH 64 +#define KAUTH_LENGTH 16 +#define KENCR_LENGTH 16 +#define AT_MAC_LENGTH 16 + +#define F1 0x42 +#define F1STAR 0x43 +#define F2 0x44 +#define F3 0x45 +#define F4 0x46 +#define F5 0x47 +#define F5STAR 0x48 + +ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY, + "AKA_CHALLENGE", + "AKA_AUTHENTICATION_REJECT", + "AKA_3", + "AKA_SYNCHRONIZATION_FAILURE", + "AKA_IDENTITY"); +ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY, + "AKA_NOTIFICATION", + "AKA_REAUTHENTICATION", + "AKA_CLIENT_ERROR"); +ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR); + + +ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(aka_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_aka_t private_eap_aka_t; + +/** + * Private data of an eap_aka_t object. + */ +struct private_eap_aka_t { + + /** + * Public authenticator_t interface. + */ + eap_aka_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * Key for EAP MAC + */ + chunk_t k_auth; + + /** + * Key for EAP encryption + */ + chunk_t k_encr; + + /** + * MSK + */ + chunk_t msk; + + /** + * Extendend MSK + */ + chunk_t emsk; + + /** + * Expected result from client XRES + */ + chunk_t xres; + + /** + * Shared secret K from ipsec.conf (padded) + */ + chunk_t k; + + /** + * random value RAND generated by server + */ + chunk_t rand; +}; + +/** Family key, as proposed in S.S0055 */ +static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47}; +static chunk_t fmk = chunk_from_buf(fmk_buf); + +/** Authentication management field */ +static u_int8_t amf_buf[] = {0x00, 0x01}; +static chunk_t amf = chunk_from_buf(amf_buf); + +/** AT_CLIENT_ERROR_CODE AKA attribute */ +static u_int8_t client_error_code_buf[] = {0, 0}; +static chunk_t client_error_code = chunk_from_buf(client_error_code_buf); + +/** previously used sqn by peer, next one must be greater */ +static u_int8_t peer_sqn_buf[6]; +static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); + +/** set SQN to the current time */ +static void update_sqn(u_int8_t *sqn, time_t offset) +{ + timeval_t time; + gettimeofday(&time, NULL); + /* set sqb_sqn to an integer containing seconds followed by most + * significant useconds */ + time.tv_sec = htonl(time.tv_sec + offset); + /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */ + time.tv_usec <<= 12; + time.tv_usec = htonl(time.tv_usec); + memcpy(sqn, &time.tv_sec, 4); + memcpy(sqn + 4, &time.tv_usec, 2); +} + +/** initialize peers SQN to the current system time at startup */ +static void __attribute__ ((constructor))init_sqn(void) +{ + update_sqn(peer_sqn_buf, 0); +} + +/** + * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 + */ +static u_int8_t g[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t a[] = { + 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, + 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, + 0x3f, 0x4c, 0x63, 0x65 +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t b[] = { + 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, + 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, + 0x7e, 0xec, 0x45, 0xe0 +}; + +/** + * Multiplicate two mpz_t with bits interpreted as polynoms. + */ +static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) +{ + mpz_t bm, rm; + int current = 0, shifted = 0, shift; + + mpz_init_set(bm, b); + mpz_init_set_ui(rm, 0); + /* scan through a, for each found bit: */ + while ((current = mpz_scan1(a, current)) != ULONG_MAX) + { + /* XOR shifted b into r */ + shift = current - shifted; + mpz_mul_2exp(bm, bm, shift); + shifted += shift; + mpz_xor(rm, rm, bm); + current++; + } + + mpz_swap(r, rm); + mpz_clear(rm); + mpz_clear(bm); +} + +/** + * Calculate the sum of a + b interpreted as polynoms. + */ +static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) +{ + /* addition of polynominals is just the XOR */ + mpz_xor(res, a, b); +} + +/** + * Calculate the remainder of a/b interpreted as polynoms. + */ +static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) +{ + /* Example: + * a = 10001010 + * b = 00000101 + */ + int a_bit, b_bit, diff; + mpz_t bm, am; + + mpz_init_set(am, a); + mpz_init(bm); + + a_bit = mpz_sizeinbase(a, 2); + b_bit = mpz_sizeinbase(b, 2); + + /* don't do anything if b > a */ + if (a_bit >= b_bit) + { + /* shift b left to align up most signaficant "1" to a: + * a = 10001010 + * b = 10100000 + */ + mpz_mul_2exp(bm, b, a_bit - b_bit); + do + { + /* XOR b into a, this kills the most significant "1": + * a = 00101010 + */ + mpz_xor(am, am, bm); + /* find the next most significant "1" in a, and align up b: + * a = 00101010 + * b = 00101000 + */ + diff = a_bit - mpz_sizeinbase(am, 2); + mpz_div_2exp(bm, bm, diff); + a_bit -= diff; + } + while (b_bit <= mpz_sizeinbase(bm, 2)); + /* While b is not shifted to its original value */ + } + /* after another iteration: + * a = 00000010 + * which is the polynomial modulo + */ + + mpz_swap(r, am); + mpz_clear(am); + mpz_clear(bm); +} + +/** + * Step 4 of the various fx() functions: + * Polynomial whiten calculations + */ +static void step4(u_int8_t x[]) +{ + mpz_t xm, am, bm, gm; + + mpz_init(xm); + mpz_init(am); + mpz_init(bm); + mpz_init(gm); + + mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); + mpz_import(am, sizeof(a), 1, 1, 1, 0, a); + mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); + mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); + + mpz_mul_poly(xm, am, xm); + mpz_add_poly(xm, bm, xm); + mpz_mod_poly(xm, xm, gm); + + mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); + + mpz_clear(xm); + mpz_clear(am); + mpz_clear(bm); + mpz_clear(gm); +} + +/** + * Step 3 of the various fx() functions: + * XOR the key into the SHA1 IV + */ +static void step3(chunk_t k, chunk_t payload, u_int8_t h[]) +{ + u_int8_t iv[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, + }; + + /* XOR key into IV */ + memxor(iv, k.ptr, k.len); + + /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */ + g_sha1(iv, payload, h); +} + +/** + * Calculation function for f2(), f3(), f4() + */ +static void fx(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + u_int8_t i; + + for (i = 0; i < 2; i++) + { + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 24, rand.ptr, rand.len); + + payload.ptr[3] ^= i; + payload.ptr[19] ^= i; + payload.ptr[35] ^= i; + payload.ptr[51] ^= i; + + step3(k, payload, h); + step4(h); + memcpy(out + i * 8, h, 8); + } +} + +/** + * Calculation function of f1() and f1star() + */ +static void f1x(u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + /* generate MAC = f1(FMK, SQN, RAND, AMF) + * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit + * payload which gets hashed + */ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + memxor(payload.ptr + 34, sqn.ptr, sqn.len); + memxor(payload.ptr + 42, amf.ptr, amf.len); + + step3(k, payload, h); + step4(h); + memcpy(mac, h, MAC_LENGTH); +} + +/** + * Calculation function of f5() and f5star() + */ +static void f5x(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + + step3(k, payload, h); + step4(h); + memcpy(ak, h, AK_LENGTH); +} + +/** + * Calculate the MAC from a RAND, SQN, AMF value using K + */ +static void f1(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t mac[]) +{ + f1x(F1, k, rand, sqn, amf, mac); + DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH); +} + +/** + * Calculate the MACS from a RAND, SQN, AMF value using K + */ +static void f1star(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t macs[]) +{ + f1x(F1STAR, k, rand, sqn, amf, macs); + DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH); +} + +/** + * Calculate RES from RAND using K + */ +static void f2(chunk_t k, chunk_t rand, u_int8_t res[]) +{ + fx(F2, k, rand, res); + DBG3(DBG_IKE, "RES %b", res, RES_LENGTH); +} + +/** + * Calculate CK from RAND using K + */ +static void f3(chunk_t k, chunk_t rand, u_int8_t ck[]) +{ + fx(F3, k, rand, ck); + DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH); +} + +/** + * Calculate IK from RAND using K + */ +static void f4(chunk_t k, chunk_t rand, u_int8_t ik[]) +{ + fx(F4, k, rand, ik); + DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH); +} + +/** + * Calculate AK from a RAND using K + */ +static void f5(chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + f5x(F5, k, rand, ak); + DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH); +} + +/** + * Calculate AKS from a RAND using K + */ +static void f5star(chunk_t k, chunk_t rand, u_int8_t aks[]) +{ + f5x(F5STAR, k, rand, aks); + DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH); +} + +/** + * derive the keys needed for EAP_AKA + */ +static void derive_keys(private_eap_aka_t *this, identification_t *id) +{ + hasher_t *hasher; + prf_t *prf; + chunk_t ck, ik, mk, identity, tmp; + + ck = chunk_alloca(CK_LENGTH); + ik = chunk_alloca(IK_LENGTH); + mk = chunk_alloca(MK_LENGTH); + identity = id->get_encoding(id); + + /* MK = SHA1( Identity | IK | CK ) */ + f3(this->k, this->rand, ck.ptr); + f4(this->k, this->rand, ik.ptr); + DBG3(DBG_IKE, "Identity %B", &identity); + tmp = chunk_cata("ccc", identity, ik, ck); + DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); + hasher = hasher_create(HASH_SHA1); + hasher->get_hash(hasher, tmp, mk.ptr); + hasher->destroy(hasher); + + /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + prf = prf_create(PRF_FIPS_SHA1_160); + prf->set_key(prf, mk); + tmp = chunk_alloca(prf->get_block_size(prf) * 4); + prf->get_bytes(prf, chunk_empty, tmp.ptr); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3); + prf->destroy(prf); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth, + 64, &this->msk, 64, &this->emsk); + DBG3(DBG_IKE, "MK %B", &mk); + DBG3(DBG_IKE, "PRF res %B", &tmp); + DBG3(DBG_IKE, "K_encr %B", &this->k_encr); + DBG3(DBG_IKE, "K_auth %B", &this->k_auth); + DBG3(DBG_IKE, "MSK %B", &this->msk); + DBG3(DBG_IKE, "EMSK %B", &this->emsk); +} + +/* + * Get a shared key from ipsec.secrets. + * We use the standard keys as used in preshared key authentication. As + * these keys have an undefined length, we: + * - strip them if they are longer + * - fill them up with '\0' if they are shorter + */ +static status_t load_key(identification_t *me, identification_t *other, chunk_t *k) +{ + chunk_t shared_key; + + if (charon->credentials->get_eap_key(charon->credentials, me, + other, &shared_key) != SUCCESS) + { + return NOT_FOUND; + } + chunk_free(k); + *k = chunk_alloc(K_LENGTH); + memset(k->ptr, '\0', k->len); + memcpy(k->ptr, shared_key.ptr, min(shared_key.len, k->len)); + chunk_free(&shared_key); + return SUCCESS; +} + +/** + * skip EAP_AKA header in message and returns its AKA subtype + */ +static aka_subtype_t read_header(chunk_t *message) +{ + aka_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) +{ + aka_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", data); + + if (data->len < 2) + { + return AT_END; + } + /* read attribute and length */ + attribute = *data->ptr++; + length = *data->ptr++ * 4 - 2; + data->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + aka_attribute_names, attribute, length); + if (length > data->len) + { + return AT_END; + } + /* apply attribute value to attr_data */ + attr_data->len = length; + attr_data->ptr = data->ptr; + /* update data to point to next attribute */ + *data = chunk_skip(*data, length); + return attribute; +} + +/** + * Build an AKA payload from different attributes. + * The variable argument takes an aka_attribute_t + * followed by its data in a chunk. + */ +static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code, + u_int8_t identifier, aka_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); /* is enought for all current messages */ + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + aka_attribute_t attr; + u_int8_t *mac_pos = NULL; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = code; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write AKA header with type and subtype, null reserved bytes */ + *pos.ptr++ = EAP_AKA; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, aka_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_RES: + { + /* attribute length in 4byte words */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* RES length in bits */ + *(u_int16_t*)pos.ptr = htons(data.len * 8); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_AUTN: + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + /* MAC is calculated over message including zeroed AT_MAC attribute */ + memset(mac_pos, 0, AT_MAC_LENGTH); + pos.ptr += AT_MAC_LENGTH; + pos.len -= AT_MAC_LENGTH; + break; + } + default: + { + /* length is data length in 4-bytes + 1 for header */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + } + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included */ + if (mac_pos) + { + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + DBG3(DBG_IKE, "AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + signer->get_signature(signer, message, mac_pos); + DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); + signer->destroy(signer); + } + + /* payload constructor takes data with some bytes skipped */ + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * Initiate a AKA-Challenge using SQN + */ +static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + chunk_t mac, ak, autn; + + mac = chunk_alloca(MAC_LENGTH); + ak = chunk_alloca(AK_LENGTH); + chunk_free(&this->rand); + chunk_free(&this->xres); + + /* generate RAND: + * we use our standard randomizer, not f0() proposed in S.S0055 + */ + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed"); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for RAND */ + u_int8_t test_rand[] = { + 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, + 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, + }; + memcpy(this->rand.ptr, test_rand, this->rand.len); +# endif /* TEST_VECTORS */ + + /* Get the shared key K: */ + if (load_key(this->server, this->peer, &this->k) != SUCCESS) + { + DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA", this->server, this->peer); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* generate MAC */ + f1(this->k, this->rand, sqn, amf, mac.ptr); + + /* generate AK */ + f5(this->k, this->rand, ak.ptr); + + /* precalculate XRES as expected from client */ + this->xres = chunk_alloc(RES_LENGTH); + f2(this->k, this->rand, this->xres.ptr); + + /* calculate AUTN = (SQN xor AK) || AMF || MAC */ + autn = chunk_cata("ccc", sqn, amf, mac); + memxor(autn.ptr, ak.ptr, ak.len); + DBG3(DBG_IKE, "AUTN %B", &autn); + + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* build payload */ + *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE, + AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, + chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.initiate for an EAP_AKA server + */ +static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + chunk_t sqn = chunk_alloca(SQN_LENGTH); + + /* we use an offset of 3 minutes to tolerate clock inaccuracy + * without the need to synchronize sequence numbers */ + update_sqn(sqn.ptr, 180); + +# ifdef TEST_VECTORS + /* Test vector for SQN */ + u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; + memcpy(sqn.ptr, test_sqn, sqn.len); +# endif /* TEST_VECTORS */ + + return server_initiate_challenge(this, sqn, out); +} + +static status_t server_process_synchronize(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; + u_int i; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_AUTS: + auts = attr; + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (auts.len != AUTS_LENGTH) + { + DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); + return FAILED; + } + + chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); + aks = chunk_alloca(AK_LENGTH); + f5star(this->k, this->rand, aks.ptr); + /* decrypt serial number by XORing AKS */ + memxor(sqn.ptr, aks.ptr, aks.len); + + /* verify MACS */ + xmacs = chunk_alloca(MAC_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + /* an AMF of zero is used for MACS calculation */ + memset(amf.ptr, 0, amf.len); + f1star(this->k, this->rand, sqn, amf, xmacs.ptr); + if (!chunk_equals(macs, xmacs)) + { + DBG1(DBG_IKE, "received MACS does not match XMACS"); + DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); + return FAILED; + } + + /* retry the challenge with the received SQN + 1*/ + for (i = SQN_LENGTH - 1; i >= 0; i--) + { + if (++sqn.ptr[i] != 0) + { + break; + } + } + return server_initiate_challenge(this, sqn, out); +} + +/** + * process an AKA_Challenge response + */ +static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) +{ + chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RES: + res = attr; + if (attr.len == 2 + RES_LENGTH && + *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8)) + { + res = chunk_skip(attr, 2); + } + continue; + + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* zero MAC in message for MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + /* verify EAP message MAC AT_MAC */ + { + bool valid; + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + valid = signer->verify_signature(signer, message, at_mac); + signer->destroy(signer); + if (!valid) + { + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed"); + return FAILED; + } + } + + /* compare received RES against stored precalculated XRES */ + if (!chunk_equals(res, this->xres)) + { + DBG1(DBG_IKE, "received RES does not match XRES"); + DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of eap_method_t.process for EAP_AKA servers + */ +static status_t server_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message; + aka_subtype_t type; + + message = in->get_data(in); + type = read_header(&message); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return server_process_challenge(this, in); + } + case AKA_AUTHENTICATION_REJECT: + case AKA_CLIENT_ERROR: + { + DBG1(DBG_IKE, "received %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } + case AKA_SYNCHRONIZATION_FAILURE: + { + DBG1(DBG_IKE, "received %N, retrying with received SQN", + aka_subtype_names, type); + return server_process_synchronize(this, in, out); + } + default: + DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } +} + +/** + * Process an incoming AKA-Challenge client side + */ +static status_t peer_process_challenge(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr = chunk_empty; + chunk_t autn = chunk_empty, at_mac = chunk_empty; + chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; + u_int8_t identifier; + + ak = chunk_alloca(AK_LENGTH); + xmac = chunk_alloca(MAC_LENGTH); + res = chunk_alloca(RES_LENGTH); + chunk_free(&this->rand); + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RAND: + this->rand = chunk_clone(chunk_skip(attr, 2)); + continue; + case AT_AUTN: + autn = chunk_skip(attr, 2); + continue; + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* set MAC in message to zero for own MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + /* non skippable attribute, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d", + aka_attribute_names, attribute, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) + { + /* required attributes wrong/not found, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d", + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + + DBG3(DBG_IKE, "using autn %B", &autn); + /* split up AUTN = SQN xor AK | AMF | MAC */ + chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); + + /* Get the shared key K: */ + chunk_free(&this->k); + if (load_key(this->peer, this->server, &this->k) != SUCCESS) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA, sending %N", this->peer, this->server, + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + return NEED_MORE; + } + DBG3(DBG_IKE, "using K %B", &this->k); +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* calculate anonymity key AK */ + f5(this->k, this->rand, ak.ptr); + DBG3(DBG_IKE, "using rand %B", &this->rand); + DBG3(DBG_IKE, "using ak %B", &ak); + /* XOR AK into SQN to decrypt it */ + + sqn = chunk_clonea(sqn_ak); + + DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak); + memxor(sqn.ptr, ak.ptr, sqn.len); + DBG3(DBG_IKE, "using sqn %B", &sqn); + + /* calculate expected MAC and compare against received one */ + f1(this->k, this->rand, sqn, amf, xmac.ptr); + if (!chunk_equals(mac, xmac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N", + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac); + return NEED_MORE; + } + +#if SEQ_CHECK + if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0) + { + /* sequence number invalid. send AUTS */ + chunk_t auts, macs, aks, amf; + + macs = chunk_alloca(MAC_LENGTH); + aks = chunk_alloca(AK_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + + /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ + memset(amf.ptr, 0, amf.len); + /* AKS = f5*(RAND) */ + f5star(this->k, this->rand, aks.ptr); + /* MACS = f1*(RAND) */ + f1star(this->k, this->rand, peer_sqn, amf, macs.ptr); + /* AUTS = SQN xor AKS | MACS */ + memxor(aks.ptr, peer_sqn.ptr, aks.len); + auts = chunk_cata("cc", aks, macs); + + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_SYNCHRONIZATION_FAILURE, + AT_AUTS, auts, AT_END); + DBG1(DBG_IKE, "received SQN invalid, sending %N", + aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); + DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn); + return NEED_MORE; + } +#endif /* SEQ_CHECK */ + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* verify EAP message MAC AT_MAC */ + { + bool valid; + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + valid = signer->verify_signature(signer, message, at_mac); + signer->destroy(signer); + if (!valid) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification " + "failed, sending %N %d", aka_attribute_names, + AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } + + /* update stored SQN to the received one */ + memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); + + /* calculate RES */ + f2(this->k, this->rand, res.ptr); + + /* build response */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, + AT_RES, res, AT_MAC, chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Process an incoming AKA-Notification as client + */ +static status_t peer_process_notification(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, pos, attr; + u_int8_t identifier; + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_NOTIFICATION: + { + u_int16_t code; + + if (attr.len != 2) + { + DBG1(DBG_IKE, "received invalid AKA notification, ignored"); + continue; + } + code = ntohs(*(u_int16_t*)attr.ptr); + switch (code) + { + case 0: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure after authentication' (%d)", code); + return FAILED; + case 16384: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure' (%d)", code); + return FAILED; + case 32768: + DBG1(DBG_IKE, "received AKA notification 'successfully " + "authenticated' (%d)", code); + continue; + case 1026: + DBG1(DBG_IKE, "received AKA notification 'access " + "temporarily denied' (%d)", code); + return FAILED; + case 1031: + DBG1(DBG_IKE, "received AKA notification 'not " + "subscribed to service' (%d)", code); + return FAILED; + default: + DBG1(DBG_IKE, "received AKA notification code %d, " + "ignored", code); + continue; + } + } + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N", + aka_attribute_names, attribute, aka_subtype_names, + AKA_NOTIFICATION); + } + else + { + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + } + continue; + } + break; + } + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for an EAP_AKA peer + */ +static status_t peer_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + aka_subtype_t type; + chunk_t message; + u_int8_t identifier; + + message = in->get_data(in); + type = read_header(&message); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return peer_process_challenge(this, in, out); + } + case AKA_NOTIFICATION: + { + return peer_process_notification(this, in, out); + } + default: + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "received unsupported %N request, sending %N %d", + aka_subtype_names, type, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } +} + +/** + * Implementation of eap_method_t.initiate for an EAP AKA peer + */ +static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_AKA; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_aka_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_aka_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_aka_t *this) +{ + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_free(&this->xres); + chunk_free(&this->k); + chunk_free(&this->rand); + free(this); +} + +/* + * Described in header. + */ +eap_aka_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = malloc_thing(private_eap_aka_t); + + /* public functions */ + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + break; + default: + free(this); + return NULL; + } + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->server = server; + this->peer = peer; + this->k_encr = chunk_empty; + this->k_auth = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->xres = chunk_empty; + this->k = chunk_empty; + this->rand = chunk_empty; + + return &this->public; +} diff --git a/src/charon/sa/authenticators/eap/eap_aka.h b/src/charon/sa/authenticators/eap/eap_aka.h new file mode 100644 index 000000000..a886863be --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_aka.h @@ -0,0 +1,141 @@ +/** + * @file eap_aka.h + * + * @brief Interface of eap_aka_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef EAP_AKA_H_ +#define EAP_AKA_H_ + +typedef struct eap_aka_t eap_aka_t; +typedef enum aka_subtype_t aka_subtype_t; +typedef enum aka_attribute_t aka_attribute_t; + +#include <sa/authenticators/eap/eap_method.h> + + +/** + * Subtypes of AKA messages + */ +enum aka_subtype_t { + AKA_CHALLENGE = 1, + AKA_AUTHENTICATION_REJECT = 2, + AKA_SYNCHRONIZATION_FAILURE = 4, + AKA_IDENTITY = 5, + AKA_NOTIFICATION = 12, + AKA_REAUTHENTICATION = 13, + AKA_CLIENT_ERROR = 14, +}; + +/** + * enum names for aka_subtype_t + */ +extern enum_name_t *aka_subtype_names; + +/** + * Attribute types in AKA messages + */ +enum aka_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +/** + * enum names for aka_attribute_t + */ +extern enum_name_t *aka_attribute_names; + +/** check SEQ values as client for validity, disabled by default */ +#ifndef SEQ_CHECK +# define SEQ_CHECK 0 +#endif + +/** + * @brief Implementation of the eap_method_t interface using EAP-AKA. + * + * EAP-AKA uses 3rd generation mobile phone standard authentication + * mechanism for authentication. It is a mutual authentication + * mechanism which establishs a shared key and therefore supports EAP_ONLY + * authentication. This implementation follows the standard of the + * 3GPP2 (S.S0055) and not the one of 3GGP. + * The shared key used for authentication is from ipsec.secrets. The + * peers ID is used to query it. + * The AKA mechanism uses sequence numbers to detect replay attacks. The + * peer stores the sequence number normally in a USIM and accepts + * incremental sequence numbers (incremental for lifetime of the USIM). To + * prevent a complex sequence number management, this implementation uses + * a sequence number derived from time. It is initialized to the startup + * time of the daemon. As long as the (UTC) time of the system is not + * turned back while the daemon is not running, this method is secure. + * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept + * any SEQ numbers. This allows an attacker to do replay attacks. But since + * the server has proven his identity via IKE, such an attack is only + * possible between server and AAA (if any). + * + * @b Constructors: + * - eap_aka_create() + * - eap_client_create() using eap_method EAP_AKA + * + * @ingroup eap + */ +struct eap_aka_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * @brief Creates the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + * + * @ingroup eap + */ +eap_aka_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer); + +#endif /* EAP_AKA_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_md5.c b/src/charon/sa/authenticators/eap/eap_md5.c new file mode 100644 index 000000000..0ca9fc566 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_md5.c @@ -0,0 +1,282 @@ +/** + * @file eap_md5.c + * + * @brief Implementation of eap_md5_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "eap_md5.h" + +#include <daemon.h> +#include <library.h> + +typedef struct private_eap_md5_t private_eap_md5_t; + +/** + * Private data of an eap_md5_t object. + */ +struct private_eap_md5_t { + + /** + * Public authenticator_t interface. + */ + eap_md5_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * challenge sent by the server + */ + chunk_t challenge; + + /** + * EAP message identififier + */ + u_int8_t identifier; +}; + +typedef struct eap_md5_header_t eap_md5_header_t; + +/** + * packed eap MD5 header struct + */ +struct eap_md5_header_t { + /** EAP code (REQUEST/RESPONSE) */ + u_int8_t code; + /** unique message identifier */ + u_int8_t identifier; + /** length of whole message */ + u_int16_t length; + /** EAP type */ + u_int8_t type; + /** length of value (challenge) */ + u_int8_t value_size; + /** actual value */ + u_int8_t value[]; +} __attribute__((__packed__)); + +#define CHALLENGE_LEN 16 +#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t)) + +/** + * Hash the challenge string, create response + */ +static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response) +{ + chunk_t concat, secret; + hasher_t *hasher; + + if (charon->credentials->get_eap_key(charon->credentials, this->server, + this->peer, &secret) != SUCCESS) + { + DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", + this->server, this->peer); + return NOT_FOUND; + } + concat = chunk_cata("cmc", chunk_from_thing(this->identifier), + secret, this->challenge); + hasher = hasher_create(HASH_MD5); + hasher->allocate_hash(hasher, concat, response); + hasher->destroy(hasher); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + eap_md5_header_t *req; + + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN, + &this->challenge); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + return FAILED; + } + + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_REQUEST; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = this->challenge.len; + memcpy(req->value, this->challenge.ptr, this->challenge.len); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process_peer(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response; + chunk_t data; + eap_md5_header_t *req; + + this->identifier = in->get_identifier(in); + data = in->get_data(in); + this->challenge = chunk_clone(chunk_skip(data, 6)); + if (data.len < 6 || this->challenge.len < *(data.ptr + 5)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &response) != SUCCESS) + { + return FAILED; + } + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_RESPONSE; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = response.len; + memcpy(req->value, response.ptr, response.len); + chunk_free(&response); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t process_server(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response, expected; + chunk_t data; + + if (this->identifier != in->get_identifier(in)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &expected) != SUCCESS) + { + return FAILED; + } + data = in->get_data(in); + response = chunk_skip(data, 6); + + if (response.len < expected.len || + !memeq(response.ptr, expected.ptr, expected.len)) + { + chunk_free(&expected); + DBG1(DBG_IKE, "EAP-MD5 verification failed"); + return FAILED; + } + chunk_free(&expected); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_MD5; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_md5_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_md5_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_md5_t *this) +{ + chunk_free(&this->challenge); + free(this); +} + +/* + * Described in header. + */ +eap_md5_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = malloc_thing(private_eap_md5_t); + + /* public functions */ + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer; + break; + default: + free(this); + return NULL; + } + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + this->server = server; + this->challenge = chunk_empty; + this->identifier = random(); + + return &this->public; +} diff --git a/src/charon/sa/authenticators/eap/eap_md5.h b/src/charon/sa/authenticators/eap/eap_md5.h new file mode 100644 index 000000000..260210b59 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_md5.h @@ -0,0 +1,59 @@ +/** + * @file eap_md5.h + * + * @brief Interface of eap_md5_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef EAP_MD5_H_ +#define EAP_MD5_H_ + +typedef struct eap_md5_t eap_md5_t; + +#include <sa/authenticators/eap/eap_method.h> + +/** + * @brief Implementation of the eap_method_t interface using EAP-MD5 (CHAP). + * + * @b Constructors: + * - eap_md5_create() + * - eap_client_create() using eap_method EAP_MD5 + * + * @ingroup eap + */ +struct eap_md5_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * @brief Creates the EAP method EAP-MD5. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + * + * @ingroup eap + */ +eap_md5_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer); + +#endif /* EAP_MD5_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index e4a58f0a3..7434ca2a1 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -45,7 +45,10 @@ ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD, "EAP_SIM"); ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM, "EAP_AKA"); -ENUM_END(eap_type_names, EAP_AKA); +ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_EXPERIMENTAL, EAP_AKA, + "EAP_EXPANDED", + "EAP_EXPERIMENTAL"); +ENUM_END(eap_type_names, EAP_EXPERIMENTAL); ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", @@ -67,6 +70,7 @@ typedef struct module_entry_t module_entry_t; */ struct module_entry_t { eap_type_t type; + u_int32_t vendor; void *handle; eap_constructor_t constructor; }; @@ -85,7 +89,8 @@ void eap_method_unload() while (modules->remove_last(modules, (void**)&entry) == SUCCESS) { - DBG2(DBG_CFG, "unloaded module for %N", eap_type_names, entry->type); + DBG2(DBG_CFG, "unloaded module EAP module %d-%d", + entry->type, entry->vendor); dlclose(entry->handle); free(entry); } @@ -165,11 +170,19 @@ void eap_method_load(char *directory) dlclose(module.handle); continue; } - module.type = method->get_type(method); + module.type = method->get_type(method, &module.vendor); method->destroy(method); - DBG1(DBG_CFG, " loaded EAP method %N successfully from %s", - eap_type_names, module.type, entry->d_name); + if (module.vendor) + { + DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s", + module.type, module.vendor, entry->d_name); + } + else + { + DBG1(DBG_CFG, " loaded EAP method %N successfully from %s", + eap_type_names, module.type, entry->d_name); + } loaded_module = malloc_thing(module_entry_t); memcpy(loaded_module, &module, sizeof(module)); @@ -181,9 +194,8 @@ void eap_method_load(char *directory) /* * Described in header. */ -eap_method_t *eap_method_create(eap_type_t type, eap_role_t role, - identification_t *server, - identification_t *peer) +eap_method_t *eap_method_create(eap_type_t type, u_int32_t vendor, eap_role_t role, + identification_t *server, identification_t *peer) { eap_method_t *method = NULL; iterator_t *iterator; @@ -192,7 +204,7 @@ eap_method_t *eap_method_create(eap_type_t type, eap_role_t role, iterator = modules->create_iterator(modules, TRUE); while (iterator->iterate(iterator, (void**)&entry)) { - if (entry->type == type) + if (entry->type == type && entry->vendor == vendor) { method = entry->constructor(role, server, peer); if (method) @@ -205,8 +217,16 @@ eap_method_t *eap_method_create(eap_type_t type, eap_role_t role, if (method == NULL) { - DBG1(DBG_CFG, "no EAP module found for %N %N", - eap_type_names, type, eap_role_names, role); + if (vendor) + { + DBG1(DBG_CFG, "no vendor %d specific EAP module found for method " + "%d %N", vendor, type, eap_role_names, role); + } + else + { + DBG1(DBG_CFG, "no EAP module found for %N %N", + eap_type_names, type, eap_role_names, role); + } } return method; } diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h index d43dc001f..8675fd8ec 100644 --- a/src/charon/sa/authenticators/eap/eap_method.h +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -62,6 +62,8 @@ enum eap_type_t { EAP_TOKEN_CARD = 6, EAP_SIM = 18, EAP_AKA = 23, + EAP_EXPANDED = 254, + EAP_EXPERIMENTAL = 255, }; /** @@ -148,9 +150,10 @@ struct eap_method_t { * @brief Get the EAP type implemented in this method. * * @param this calling object + * @param vendor pointer receiving vendor identifier for type, 0 for none * @return type of the EAP method */ - eap_type_t (*get_type) (eap_method_t *this); + eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor); /** * @brief Check if this EAP method authenticates the server. @@ -188,6 +191,7 @@ struct eap_method_t { * @brief Creates an EAP method for a specific type and role. * * @param eap_type EAP type to use + * @param eap_vendor vendor identifier if a vendor specifc EAP type is used * @param role role of the eap_method, server or peer * @param server ID of acting server * @param peer ID of involved peer (client) @@ -195,8 +199,9 @@ struct eap_method_t { * * @ingroup eap */ -eap_method_t *eap_method_create(eap_type_t eap_type, eap_role_t role, - identification_t *server, identification_t *peer); +eap_method_t *eap_method_create(eap_type_t eap_type, u_int32_t eap_vendor, + eap_role_t role, identification_t *server, + identification_t *peer); /** * @brief (Re-)Load all EAP modules in the EAP modules directory. diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c index 38d7f2534..c9eb5ce8f 100644 --- a/src/charon/sa/authenticators/eap/eap_sim.c +++ b/src/charon/sa/authenticators/eap/eap_sim.c @@ -264,6 +264,7 @@ static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier } case AT_IDENTITY: { + u_int16_t act_len = data.len; /* align up to four byte */ if (data.len % 4) { @@ -275,7 +276,7 @@ static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier *pos.ptr = data.len/4 + 1; pos = chunk_skip(pos, 1); /* actual length in bytes */ - *(u_int16_t*)pos.ptr = htons(data.len); + *(u_int16_t*)pos.ptr = htons(act_len); pos = chunk_skip(pos, sizeof(u_int16_t)); memcpy(pos.ptr, data.ptr, data.len); pos = chunk_skip(pos, data.len); @@ -697,8 +698,9 @@ static status_t initiate(private_eap_sim_t *this, eap_payload_t **out) /** * Implementation of eap_method_t.get_type. */ -static eap_type_t get_type(private_eap_sim_t *this) +static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor) { + *vendor = 0; return EAP_SIM; } @@ -785,7 +787,7 @@ eap_sim_t *eap_create(eap_role_t role, /* public functions */ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate; this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process; - this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index 6e2f73a43..6250604a6 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -138,7 +138,7 @@ static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, * Implementation of eap_authenticator_t.initiate */ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, - eap_payload_t **out) + u_int32_t vendor, eap_payload_t **out) { /* if initiate() is called, role is always server */ this->role = EAP_SERVER; @@ -151,21 +151,30 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, return FAILED; } - DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type); - this->method = eap_method_create(type, this->role, + if (vendor) + { + DBG1(DBG_IKE, "requesting vendor specific EAP authentication %d-%d", + type, vendor); + } + else + { + DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type); + } + this->method = eap_method_create(type, vendor, this->role, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); if (this->method == NULL) { - DBG1(DBG_IKE, "configured EAP server method %N not supported, sending %N", - eap_type_names, type, eap_code_names, EAP_FAILURE); + + DBG1(DBG_IKE, "configured EAP server method not supported, sending %N", + eap_code_names, EAP_FAILURE); *out = eap_payload_create_code(EAP_FAILURE); return FAILED; } if (this->method->initiate(this->method, out) != NEED_MORE) { - DBG1(DBG_IKE, "failed to initiate %N, sending %N", + DBG1(DBG_IKE, "failed to initiate EAP exchange, sending %N", eap_type_names, type, eap_code_names, EAP_FAILURE); *out = eap_payload_create_code(EAP_FAILURE); return FAILED; @@ -179,11 +188,14 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, static status_t process_peer(private_eap_authenticator_t *this, eap_payload_t *in, eap_payload_t **out) { - eap_type_t type = in->get_type(in); + eap_type_t type; + u_int32_t vendor; - if (type == EAP_IDENTITY) + type = in->get_type(in, &vendor); + + if (!vendor && type == EAP_IDENTITY) { - eap_method_t *method = eap_method_create(type, EAP_PEER, + eap_method_t *method = eap_method_create(type, 0, EAP_PEER, this->ike_sa->get_other_id(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa)); @@ -205,32 +217,57 @@ static status_t process_peer(private_eap_authenticator_t *this, /* create an eap_method for the first call */ if (this->method == NULL) { - DBG1(DBG_IKE, "EAP server requested %N authentication", - eap_type_names, type); - this->method = eap_method_create(type, EAP_PEER, + if (vendor) + { + DBG1(DBG_IKE, "EAP server requested vendor specific EAP method %d-%d", + type, vendor); + } + else + { + DBG1(DBG_IKE, "EAP server requested %N authentication", + eap_type_names, type); + } + this->method = eap_method_create(type, vendor, EAP_PEER, this->ike_sa->get_other_id(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa)); if (this->method == NULL) { DBG1(DBG_IKE, "EAP server requested unsupported " - "EAP method %N, sending EAP_NAK", eap_type_names, type); + "EAP method, sending EAP_NAK"); *out = eap_payload_create_nak(); return NEED_MORE; } } + type = this->method->get_type(this->method, &vendor); + switch (this->method->process(this->method, in, out)) { case NEED_MORE: return NEED_MORE; case SUCCESS: - DBG1(DBG_IKE, "EAP method %N succeded", - eap_type_names, this->method->get_type(this->method)); + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded", + type, vendor); + } + else + { + DBG1(DBG_IKE, "EAP method %N succeded", eap_type_names, type); + } return SUCCESS; case FAILED: default: - DBG1(DBG_IKE, "EAP method %N failed", - eap_type_names, this->method->get_type(this->method)); + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed", + type, vendor); + } + else + { + DBG1(DBG_IKE, "EAP method %N failed", + eap_type_names, type); + } return FAILED; } } @@ -241,6 +278,11 @@ static status_t process_peer(private_eap_authenticator_t *this, static status_t process_server(private_eap_authenticator_t *this, eap_payload_t *in, eap_payload_t **out) { + eap_type_t type; + u_int32_t vendor; + + type = this->method->get_type(this->method, &vendor); + switch (this->method->process(this->method, in, out)) { case NEED_MORE: @@ -248,22 +290,35 @@ static status_t process_server(private_eap_authenticator_t *this, case SUCCESS: if (this->method->get_msk(this->method, &this->msk) == SUCCESS) { - DBG1(DBG_IKE, "EAP method %N succeded, MSK established", - eap_type_names, this->method->get_type(this->method)); this->msk = chunk_clone(this->msk); } + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded, " + "%sMSK established", type, vendor, + this->msk.ptr ? "" : "no "); + } else { - DBG1(DBG_IKE, "EAP method %N succeded, no MSK established", - eap_type_names, this->method->get_type(this->method)); + DBG1(DBG_IKE, "EAP method %N succeded, %sMSK established", + eap_type_names, type, this->msk.ptr ? "" : "no "); } *out = eap_payload_create_code(EAP_SUCCESS); return SUCCESS; case FAILED: default: - DBG1(DBG_IKE, "EAP method %N failed for peer %D", - eap_type_names, this->method->get_type(this->method), - this->ike_sa->get_other_id(this->ike_sa)); + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " + "peer %D", type, vendor, + this->ike_sa->get_other_id(this->ike_sa)); + } + else + { + DBG1(DBG_IKE, "EAP method %N failed for peer %D", + eap_type_names, type, + this->ike_sa->get_other_id(this->ike_sa)); + } *out = eap_payload_create_code(EAP_FAILURE); return FAILED; } @@ -363,7 +418,7 @@ eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa) this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy; this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual; - this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,eap_payload_t**))initiate; + this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,u_int32_t,eap_payload_t**))initiate; this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process; /* private data */ diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h index 64a3267d7..cf2180ee3 100644 --- a/src/charon/sa/authenticators/eap_authenticator.h +++ b/src/charon/sa/authenticators/eap_authenticator.h @@ -105,15 +105,16 @@ struct eap_authenticator_t { * this method. If initiate() returns NEED_MORE, the EAP authentication * process started. In any case, a payload is created in "out". * - * @param this calling object - * @param type EAP method to use to authenticate client - * @param out created initiaal EAP message to send + * @param this calling object + * @param type EAP method to use to authenticate client + * @param vendor EAP vendor identifier, if type is vendor specific, or 0 + * @param out created initiaal EAP message to send * @return * - FAILED, if initiation failed * - NEED_MORE, if more EAP exchanges reqired */ status_t (*initiate) (eap_authenticator_t* this, eap_type_t type, - eap_payload_t **out); + u_int32_t vendor, eap_payload_t **out); /** * @brief Process an EAP message. diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 44f0298d5..b6c71a8b5 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -354,7 +354,7 @@ static void updown(private_child_sa_t *this, bool up) up ? "up" : "down", policy->my_ts->is_host(policy->my_ts, this->me.addr) ? "-host" : "-client", - this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6", + this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-v6", this->config->get_name(this->config), this->iface ? this->iface : "unknown", this->reqid, diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index d583e01bb..d0f3cde8d 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -32,13 +32,13 @@ #include <processing/jobs/initiate_mediation_job.h> #include <encoding/payloads/endpoint_notify.h> -// base timeout -// the sending interval is P2P_INTERVAL * active checklists (N) -// retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) -#define P2P_INTERVAL 20 // 20 ms -// min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) -#define P2P_RTO_MIN 100 // 100 ms -// max number of retransmissions (+ the initial check) +/* base timeout + * the sending interval is P2P_INTERVAL * active checklists (N) + * retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) */ +#define P2P_INTERVAL 20 /* ms */ +/* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */ +#define P2P_RTO_MIN 100 /* ms */ +/* max number of retransmissions (+ the initial check) */ #define P2P_MAX_RETRANS 2 @@ -212,7 +212,8 @@ static void check_list_destroy(check_list_t *this) DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy)); DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy); - DESTROY_IF(this->triggered); // this list contains some of the same elements as contained in this->pairs + /* this list contains some of the same elements as contained in this->pairs */ + DESTROY_IF(this->triggered); free(this); } @@ -489,8 +490,6 @@ static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_ return this; } -// ----------------------------------------------------------------------------- - /** * Find an initiated connection by the peers' ids */ @@ -641,9 +640,6 @@ static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoi return status; } -// ----------------------------------------------------------------------------- - - /** * Updates the state of the whole checklist */ @@ -659,7 +655,8 @@ static void update_checklist_state(check_list_t *checklist) switch(current->state) { case CHECK_WAITING: - // at least one is still waiting -> checklist remains in waiting state + /* at least one is still waiting -> checklist remains + * in waiting state */ iterator->destroy(iterator); return; case CHECK_IN_PROGRESS: @@ -668,6 +665,8 @@ static void update_checklist_state(check_list_t *checklist) case CHECK_SUCCEEDED: succeeded = TRUE; break; + default: + break; } } iterator->destroy(iterator); @@ -832,7 +831,6 @@ static void prune_pairs(linked_list_t *pairs) { iterator_t *iterator, *search; endpoint_pair_t *current, *other; - bool inserted = FALSE; u_int32_t id = 0; iterator = pairs->create_iterator(pairs, TRUE); @@ -851,10 +849,10 @@ static void prune_pairs(linked_list_t *pairs) if (current->local->equals(current->local, other->local) && current->remote->equals(current->remote, other->remote)) { - // since the list of pairs is sorted by priority in descending - // order, and we iterate the list from the beginning, we are - // sure that the priority of 'other' is lower than that of - // 'current', remove it + /* since the list of pairs is sorted by priority in descending + * order, and we iterate the list from the beginning, we are + * sure that the priority of 'other' is lower than that of + * 'current', remove it */ DBG1(DBG_IKE, "pruning endpoint pair %H - %H with priority %d", other->local, other->remote, other->priority); search->remove(search); @@ -896,8 +894,6 @@ static void build_pairs(check_list_t *checklist) prune_pairs(checklist->pairs); } -// ----------------------------------------------------------------------------- - /** * Processes the payloads of a connectivity check and returns the extracted data */ @@ -936,7 +932,7 @@ static status_t process_payloads(message_t *message, check_t *check) } check->endpoint = endpoint; check->endpoint_raw = chunk_clone(notify->get_notification_data(notify)); - DBG3(DBG_IKE, "received P2P_ENDPOINT notify"); + DBG2(DBG_IKE, "received P2P_ENDPOINT notify"); break; } case P2P_SESSIONID: @@ -1000,9 +996,6 @@ static chunk_t build_signature(private_connect_manager_t *this, return sig_hash; } -// ----------------------------------------------------------------------------- - -// forward declarations static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid); static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time); static void finish_checks(private_connect_manager_t *this, check_list_t *checklist); @@ -1061,11 +1054,13 @@ retransmit_end: case CHECK_FAILED: finish_checks(this, checklist); break; + default: + break; } pthread_mutex_unlock(&(this->mutex)); - // we reschedule it manually + /* we reschedule it manually */ return JOB_REQUEUE_NONE; } @@ -1192,13 +1187,13 @@ static job_requeue_t sender(sender_data_t *data) check_destroy(check); - // schedule this job again + /* schedule this job again */ u_int32_t N = this->checklists->get_count(this->checklists); schedule_checks(this, checklist, P2P_INTERVAL * N); pthread_mutex_unlock(&(this->mutex)); - // we reschedule it manually + /* we reschedule it manually */ return JOB_REQUEUE_NONE; } @@ -1240,8 +1235,10 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) } else { - // this should (can?) not happen + /* this should (can?) not happen */ } + + return JOB_REQUEUE_NONE; } /** @@ -1270,9 +1267,10 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli } } - //remove_checklist(this, checklist); - //check_list_destroy(checklist); - // FIXME: we should do this ^^^ after a specific timeout on the responder side + /* remove_checklist(this, checklist); + * check_list_destroy(checklist); + * FIXME: we should do this ^^^ after a specific timeout on the + * responder side */ } /** @@ -1313,6 +1311,8 @@ static void process_response(private_connect_manager_t *this, check_t *check, case CHECK_FAILED: finish_checks(this, checklist); break; + default: + break; } } else @@ -1343,16 +1343,16 @@ static void process_request(private_connect_manager_t *this, check_t *check, switch(pair->state) { case CHECK_IN_PROGRESS: - pair->retransmitted = P2P_MAX_RETRANS; // prevent retransmissions - // FIXME: we should wait to the next rto to send the triggered check - // fall-through + /* prevent retransmissions */ + pair->retransmitted = P2P_MAX_RETRANS; + /* FIXME: we should wait to the next rto to send the triggered check + * fall-through */ case CHECK_WAITING: case CHECK_FAILED: queue_triggered_check(checklist, pair); break; case CHECK_SUCCEEDED: default: - // do nothing break; } } @@ -1451,8 +1451,6 @@ static void process_check(private_connect_manager_t *this, message_t *message) check_destroy(check); } -// ----------------------------------------------------------------------------- - /** * Implementation of connect_manager_t.check_and_register. */ @@ -1568,7 +1566,8 @@ static status_t set_responder_data(private_connect_manager_t *this, build_pairs(checklist); - schedule_checks(this, checklist, 0); // send the first check immediately + /* send the first check immediately */ + schedule_checks(this, checklist, 0); pthread_mutex_unlock(&(this->mutex)); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 9d7a17e89..9cada2cb5 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -51,6 +51,7 @@ #include <sa/tasks/ike_natd.h> #include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> +#include <sa/tasks/ike_auth_lifetime.h> #include <sa/tasks/ike_config.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> @@ -68,6 +69,7 @@ #ifdef P2P #include <sa/tasks/ike_p2p.h> +#include <processing/jobs/initiate_mediation_job.h> #endif #ifndef RESOLV_CONF @@ -248,6 +250,8 @@ struct private_ike_sa_t { u_int32_t established; /** when IKE_SA gets rekeyed */ u_int32_t rekey; + /** when IKE_SA gets reauthenticated */ + u_int32_t reauth; /** when IKE_SA gets deleted */ u_int32_t delete; } time; @@ -256,6 +260,11 @@ struct private_ike_sa_t { * how many times we have retried so far (keyingtries) */ u_int32_t keyingtry; + + /** + * are we the initiator of this IKE_SA (rekeying does not affect this flag) + */ + bool ike_initiator; }; /** @@ -307,16 +316,31 @@ static char *get_name(private_ike_sa_t *this) return "(unnamed)"; } - /** - * Implementation of ike_sa_t.get_stats. + * Implementation of ike_sa_t.get_statistic. */ -static void get_stats(private_ike_sa_t *this, u_int32_t *next_rekeying) +static u_int32_t get_statistic(private_ike_sa_t *this, statistic_t kind) { - if (next_rekeying) + time_t now = time(NULL); + + switch (kind) { - *next_rekeying = this->time.rekey; + case STAT_REKEY_TIME: + if (this->time.rekey > now) + { + return this->time.rekey - now; + } + break; + case STAT_REAUTH_TIME: + if (this->time.reauth > now) + { + return this->time.reauth - now; + } + break; + default: + break; } + return 0; } /** @@ -493,10 +517,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, this->conditions |= condition; switch (condition) { - case COND_STALE: - DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale", - this->other_host); - break; case COND_NAT_HERE: DBG1(DBG_IKE, "local host is behind NAT, sending keep alives"); this->conditions |= COND_NAT_ANY; @@ -519,9 +539,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, this->conditions &= ~condition; switch (condition) { - case COND_STALE: - DBG1(DBG_IKE, "new route to %H found", this->other_host); - break; case COND_NAT_HERE: case COND_NAT_FAKE: case COND_NAT_THERE: @@ -610,36 +627,58 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) if (this->state == IKE_CONNECTING) { job_t *job; - u_int32_t now = time(NULL); - u_int32_t soft, hard; - bool reauth; + u_int32_t t; - this->time.established = now; - /* start DPD checks */ - send_dpd(this); + /* calculate rekey, reauth and lifetime */ + this->time.established = time(NULL); - /* schedule rekeying/reauthentication */ - soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE); - hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE); - reauth = this->peer_cfg->use_reauth(this->peer_cfg); - DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds", - reauth ? "reauthentication": "rekeying", soft, hard); - - if (soft) + /* schedule rekeying if we have a time which is smaller than + * an already scheduled rekeying */ + t = this->peer_cfg->get_rekey_time(this->peer_cfg); + if (t && (this->time.rekey == 0 || + (this->time.rekey > t + this->time.established))) { - this->time.rekey = now + soft; - job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth); - charon->scheduler->schedule_job(charon->scheduler, job, - soft * 1000); + this->time.rekey = t + this->time.established; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE); + charon->scheduler->schedule_job(charon->scheduler, + job, t * 1000); + DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } - - if (hard) + t = this->peer_cfg->get_reauth_time(this->peer_cfg); + if (t && (this->time.reauth == 0 || + (this->time.reauth > t + this->time.established))) { - this->time.delete = now + hard; + this->time.reauth = t + this->time.established; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); + charon->scheduler->schedule_job(charon->scheduler, + job, t * 1000); + DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); + } + t = this->peer_cfg->get_over_time(this->peer_cfg); + if (this->time.rekey || this->time.reauth) + { + if (this->time.reauth == 0) + { + this->time.delete = this->time.rekey; + } + else if (this->time.rekey == 0) + { + this->time.delete = this->time.reauth; + } + else + { + this->time.delete = min(this->time.rekey, this->time.reauth); + } + this->time.delete += t; + t = this->time.delete - this->time.established; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); charon->scheduler->schedule_job(charon->scheduler, job, - hard * 1000); + t * 1000); + DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } + + /* start DPD checks */ + send_dpd(this); } break; } @@ -681,17 +720,17 @@ static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) { if (local) { - if (this->my_virtual_ip) - { - DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); - this->my_virtual_ip->destroy(this->my_virtual_ip); - } DBG1(DBG_IKE, "installing new virtual IP %H", ip); if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, this->my_host) == SUCCESS) { + if (this->my_virtual_ip) + { + DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); + charon->kernel_interface->del_ip(charon->kernel_interface, + this->my_virtual_ip); + } + DESTROY_IF(this->my_virtual_ip); this->my_virtual_ip = ip->clone(ip); } else @@ -859,6 +898,8 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, this->other_host = request->get_source(request); this->other_host = this->other_host->clone(this->other_host); } + response->set_source(response, this->my_host->clone(this->my_host)); + response->set_destination(response, this->other_host->clone(this->other_host)); if (generate_message(this, response, &packet) == SUCCESS) { charon->sender->send(charon->sender, packet); @@ -973,6 +1014,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) return DESTROY_ME; } + this->ike_initiator = TRUE; + task = (task_t*)ike_init_create(&this->public, TRUE, NULL); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_create(&this->public, TRUE); @@ -983,6 +1026,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); if (this->peer_cfg->use_mobike(this->peer_cfg)) { task = (task_t*)ike_mobike_create(&this->public, TRUE); @@ -997,7 +1042,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) #ifdef P2P if (this->peer_cfg->get_mediated_by(this->peer_cfg)) { - // mediated connection, initiate mediation process + /* mediated connection, initiate mediation process */ job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id, child_cfg); child_cfg->destroy(child_cfg); charon->processor->queue_job(charon->processor, job); @@ -1006,14 +1051,14 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) else if (this->peer_cfg->is_mediation(this->peer_cfg)) { if (this->state == IKE_ESTABLISHED) - {// FIXME: we should try to find a better solution to this + { /* FIXME: we should try to find a better solution to this */ SIG(CHILD_UP_SUCCESS, "mediation connection is already up and running"); } } else #endif /* P2P */ { - // normal IKE_SA with CHILD_SA + /* normal IKE_SA with CHILD_SA */ task = (task_t*)child_create_create(&this->public, child_cfg); child_cfg->destroy(child_cfg); this->task_manager->queue_task(this->task_manager, task); @@ -1026,7 +1071,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) * Implementation of ike_sa_t.acquire. */ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) -{// FIXME: P2P-NAT-T +{ /* FIXME: P2P-NAT-T */ child_cfg_t *child_cfg; iterator_t *iterator; child_sa_t *current, *child_sa = NULL; @@ -1073,6 +1118,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); if (this->peer_cfg->use_mobike(this->peer_cfg)) { task = (task_t*)ike_mobike_create(&this->public, TRUE); @@ -1350,7 +1397,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) * Implementation of ike_sa_t.retransmit. */ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) -{// FIXME: P2P-NAT-T +{ /* FIXME: P2P-NAT-T */ this->time.outbound = time(NULL); if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) { @@ -1467,6 +1514,8 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) task = (task_t*)child_create_create(&new->public, child_cfg); new->task_manager->queue_task(new->task_manager, task); } + task = (task_t*)ike_auth_lifetime_create(&new->public, TRUE); + new->task_manager->queue_task(new->task_manager, task); if (this->peer_cfg->use_mobike(this->peer_cfg)) { task = (task_t*)ike_mobike_create(&new->public, TRUE); @@ -1900,14 +1949,59 @@ static status_t rekey(private_ike_sa_t *this) static status_t reestablish(private_ike_sa_t *this) { task_t *task; - + + /* we can't reauthenticate as responder when we use EAP or virtual IPs. + * If the peer does not support RFC4478, there is no way to keep the + * IKE_SA up. */ + if (!this->ike_initiator) + { + DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); + if (this->other_virtual_ip != NULL || + has_condition(this, COND_EAP_AUTHENTICATED)) + { + time_t now = time(NULL); + + DBG1(DBG_IKE, "IKE_SA will timeout in %#V", &now, &this->time.delete); + return FAILED; + } + else + { + DBG1(DBG_IKE, "reauthenticating actively"); + } + } task = (task_t*)ike_reauth_create(&this->public); this->task_manager->queue_task(this->task_manager, task); - + return this->task_manager->initiate(this->task_manager); } /** + * Implementation of ike_sa_t.set_auth_lifetime. + */ +static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) +{ + job_t *job; + u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); + + this->time.reauth = time(NULL) + lifetime - reduction; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); + + if (lifetime < reduction) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", + lifetime); + charon->processor->queue_job(charon->processor, job); + } + else + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" + " in %ds", lifetime, lifetime - reduction); + charon->scheduler->schedule_job(charon->scheduler, job, + (lifetime - reduction) * 1000); + } +} + +/** * Implementation of ike_sa_t.roam. */ static status_t roam(private_ike_sa_t *this, bool address) @@ -1933,7 +2027,6 @@ static status_t roam(private_ike_sa_t *this, bool address) me = charon->kernel_interface->get_source_addr(charon->kernel_interface, other); - set_condition(this, COND_STALE, FALSE); if (me) { if (me->ip_equals(me, this->my_host) && @@ -1977,6 +2070,7 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) this->other_host = other->other_host->clone(other->other_host); this->my_id = other->my_id->clone(other->my_id); this->other_id = other->other_id->clone(other->other_id); + this->ike_initiator = other->ike_initiator; /* apply virtual assigned IPs... */ if (other->my_virtual_ip) @@ -2007,6 +2101,24 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) /* move pending tasks to the new IKE_SA */ this->task_manager->adopt_tasks(this->task_manager, other->task_manager); + /* reauthentication timeout survives a rekeying */ + if (other->time.reauth) + { + time_t reauth, delete, now = time(NULL); + + this->time.reauth = other->time.reauth; + reauth = this->time.reauth - now; + delete = reauth + this->peer_cfg->get_over_time(this->peer_cfg); + this->time.delete = this->time.reauth + delete; + DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " + "lifetime reduced to %ds", reauth, delete); + charon->scheduler->schedule_job(charon->scheduler, + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), + reauth * 1000); + charon->scheduler->schedule_job(charon->scheduler, + (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), + delete * 1000); + } /* we have to initate here, there may be new tasks to handle */ return this->task_manager->initiate(this->task_manager); } @@ -2177,7 +2289,7 @@ static void destroy(private_ike_sa_t *this) if (this->peer_cfg && this->peer_cfg->is_mediation(this->peer_cfg) && !this->ike_sa_id->is_initiator(this->ike_sa_id)) { - // mediation server + /* mediation server */ charon->mediation_manager->remove(charon->mediation_manager, this->ike_sa_id); } DESTROY_IF(this->server_reflexive_host); @@ -2207,8 +2319,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* Public functions */ this->public.get_state = (ike_sa_state_t (*)(ike_sa_t*)) get_state; this->public.set_state = (void (*)(ike_sa_t*,ike_sa_state_t)) set_state; - this->public.get_stats = (void (*)(ike_sa_t*,u_int32_t*))get_stats; this->public.get_name = (char* (*)(ike_sa_t*))get_name; + this->public.get_statistic = (u_int32_t(*)(ike_sa_t*, statistic_t kind))get_statistic; this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message; this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate; this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route; @@ -2256,6 +2368,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa; this->public.rekey = (status_t (*)(ike_sa_t*))rekey; this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish; + this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime; this->public.roam = (status_t(*)(ike_sa_t*,bool))roam; this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit; this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message; @@ -2296,6 +2409,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->time.inbound = this->time.outbound = time(NULL); this->time.established = 0; this->time.rekey = 0; + this->time.reauth = 0; this->time.delete = 0; this->ike_cfg = NULL; this->peer_cfg = NULL; @@ -2307,6 +2421,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->additional_addresses = linked_list_create(); this->pending_updates = 0; this->keyingtry = 0; + this->ike_initiator = FALSE; #ifdef P2P this->server_reflexive_host = NULL; #endif /* P2P */ diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 99f09e98a..975447d9c 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -29,6 +29,7 @@ typedef enum ike_extension_t ike_extension_t; typedef enum ike_condition_t ike_condition_t; typedef enum ike_sa_state_t ike_sa_state_t; +typedef enum statistic_t statistic_t; typedef struct ike_sa_t ike_sa_t; #include <library.h> @@ -115,9 +116,25 @@ enum ike_condition_t { COND_NAT_FAKE = (1<<3), /** - * peer is currently not reachable (due missing route, ...) + * peer has ben authenticated using EAP */ - COND_STALE = (1<<4), + COND_EAP_AUTHENTICATED = (1<<4), +}; + +/** + * Information and statistics to query from an SA + */ +enum statistic_t { + + /** + * Relative time for scheduled rekeying + */ + STAT_REKEY_TIME, + + /** + * Relative time for scheduled reauthentication + */ + STAT_REAUTH_TIME, }; /** @@ -234,13 +251,6 @@ struct ike_sa_t { ike_sa_state_t (*get_state) (ike_sa_t *this); /** - * @brief Get some statistics about this IKE_SA. - * - * @param next_rekeying when the next rekeying is scheduled - */ - void (*get_stats)(ike_sa_t *this, u_int32_t *next_rekeying); - - /** * @brief Set the state of the IKE_SA. * * @param this calling object @@ -257,6 +267,15 @@ struct ike_sa_t { char* (*get_name) (ike_sa_t *this); /** + * @brief Get statistic values from the IKE_SA. + * + * @param this calling object + * @param kind kind of requested value + * @return value as integer + */ + u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind); + + /** * @brief Get the own host address. * * @param this calling object @@ -846,6 +865,14 @@ struct ike_sa_t { status_t (*reestablish) (ike_sa_t *this); /** + * @brief Set the lifetime limit received from a AUTH_LIFETIME notify. + * + * @param this calling object + * @param lifetime lifetime in seconds + */ + void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); + + /** * @brief Set the virtual IP to use for this IKE_SA and its children. * * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c index fca53a940..f6137304d 100644 --- a/src/charon/sa/mediation_manager.c +++ b/src/charon/sa/mediation_manager.c @@ -240,7 +240,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%D'", peer_id); peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL; - // send callbacks to registered peers + /* send callbacks to registered peers */ identification_t *requester; while(peer->requested_by->remove_last(peer->requested_by, (void**)&requester) == SUCCESS) { @@ -295,7 +295,7 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, if (!peer->ike_sa_id) { - // the peer is not online + /* the peer is not online */ DBG2(DBG_IKE, "requested peer '%D' is offline, registering peer '%D'", peer_id, requester); register_peer(peer, requester); pthread_mutex_unlock(&(this->mutex)); diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index f4484774e..89f527aba 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -30,6 +30,7 @@ #include <sa/tasks/ike_natd.h> #include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> +#include <sa/tasks/ike_auth_lifetime.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> #include <sa/tasks/ike_delete.h> @@ -338,6 +339,7 @@ static status_t build_request(private_task_manager_t *this) activate_task(this, IKE_AUTHENTICATE); activate_task(this, IKE_CONFIG); activate_task(this, CHILD_CREATE); + activate_task(this, IKE_AUTH_LIFETIME); activate_task(this, IKE_MOBIKE); } break; @@ -690,19 +692,21 @@ static status_t process_request(private_task_manager_t *this, #ifdef P2P task = (task_t*)ike_p2p_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); -#endif /* P2P */ +#endif /* P2P */ task = (task_t*)ike_auth_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)ike_config_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)child_create_create(this->ike_sa, NULL); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; } case CREATE_CHILD_SA: - {//FIXME: we should prevent this on mediation connections + { /* FIXME: we should prevent this on mediation connections */ bool notify_found = FALSE, ts_found = FALSE; iterator = message->get_payload_iterator(message); while (iterator->iterate(iterator, (void**)&payload)) @@ -772,8 +776,12 @@ static status_t process_request(private_task_manager_t *this, case UNACCEPTABLE_ADDRESSES: case UNEXPECTED_NAT_DETECTED: case COOKIE2: - task = (task_t*)ike_mobike_create(this->ike_sa, - FALSE); + task = (task_t*)ike_mobike_create( + this->ike_sa, FALSE); + break; + case AUTH_LIFETIME: + task = (task_t*)ike_auth_lifetime_create( + this->ike_sa, FALSE); break; default: break; diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index a3cd6a2bc..de88a0abe 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -297,6 +297,7 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes return NEED_MORE; } + /** * Implementation of task_t.build to create AUTH payload from EAP data */ @@ -520,6 +521,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) break; case NOT_FOUND: /* use EAP if no AUTH payload found */ + this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE); this->eap_auth = eap_authenticator_create(this->ike_sa); break; default: @@ -546,6 +548,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) { peer_cfg_t *config; eap_type_t eap_type; + u_int32_t eap_vendor; eap_payload_t *eap_payload; status_t status; @@ -590,10 +593,11 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); return FAILED; } - + /* initiate EAP authenitcation */ - eap_type = config->get_eap_type(config); - status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload); + eap_type = config->get_eap_type(config, &eap_vendor); + status = this->eap_auth->initiate(this->eap_auth, eap_type, + eap_vendor, &eap_payload); message->add_payload(message, (payload_t*)eap_payload); if (status != NEED_MORE) { @@ -645,6 +649,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) case ADDITIONAL_IP6_ADDRESS: /* handled in ike_mobike task */ break; + case AUTH_LIFETIME: + /* handled in ike_auth_lifetime task */ + break; + case P2P_ENDPOINT: + /* handled in ike_p2p task */ + break; default: { if (type < 16383) diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c new file mode 100644 index 000000000..9d37ec608 --- /dev/null +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -0,0 +1,200 @@ +/** + * @file ike_auth_lifetime.c + * + * @brief Implementation of the ike_auth_lifetime task. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "ike_auth_lifetime.h" + +#include <daemon.h> +#include <encoding/payloads/notify_payload.h> + + +typedef struct private_ike_auth_lifetime_t private_ike_auth_lifetime_t; + +/** + * Private members of a ike_auth_lifetime_t task. + */ +struct private_ike_auth_lifetime_t { + + /** + * Public methods and task_t interface. + */ + ike_auth_lifetime_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; +}; + +/** + * add the AUTH_LIFETIME notify to the message + */ +static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *message) +{ + chunk_t chunk; + u_int32_t lifetime; + + lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH_TIME); + if (lifetime) + { + chunk = chunk_from_thing(lifetime); + *(u_int32_t*)chunk.ptr = htonl(lifetime); + message->add_notify(message, FALSE, AUTH_LIFETIME, chunk); + } +} + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message) +{ + iterator_t *iterator; + payload_t *payload; + notify_payload_t *notify; + + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case AUTH_LIFETIME: + { + chunk_t data = notify->get_notification_data(notify); + u_int32_t lifetime = ntohl(*(u_int32_t*)data.ptr); + this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime); + break; + } + default: + break; + } + } + } + iterator->destroy(iterator); +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t build_i(private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == INFORMATIONAL) + { + add_auth_lifetime(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.process for responder + */ +static status_t process_r(private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.build for responder + */ +static status_t build_r(private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + add_auth_lifetime(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + process_payloads(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_auth_lifetime_t *this) +{ + return IKE_AUTH_LIFETIME; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_auth_lifetime_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_auth_lifetime_t *this = malloc_thing(private_ike_auth_lifetime_t); + + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; + this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; + this->public.task.destroy = (void(*)(task_t*))destroy; + + if (initiator) + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + } + else + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + } + + this->ike_sa = ike_sa; + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_auth_lifetime.h b/src/charon/sa/tasks/ike_auth_lifetime.h new file mode 100644 index 000000000..500b89d39 --- /dev/null +++ b/src/charon/sa/tasks/ike_auth_lifetime.h @@ -0,0 +1,61 @@ +/** + * @file ike_auth_lifetime.h + * + * @brief Interface ike_auth_lifetime_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef IKE_AUTH_LIFETIME_H_ +#define IKE_AUTH_LIFETIME_H_ + +typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * @brief Task of type IKE_AUTH_LIFETIME, implements RFC4478. + * + * This task exchanges lifetimes for IKE_AUTH to force a client to + * reauthenticate before the responders lifetime reaches the limit. + * + * @b Constructors: + * - ike_auth_lifetime_create() + * + * @ingroup tasks + */ +struct ike_auth_lifetime_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * @brief Create a new IKE_AUTH_LIFETIME task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if taks is initiated by us + * @return ike_auth_lifetime task to handle by the task_manager + */ +ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator); + +#endif /* IKE_MOBIKE_H_ */ + diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index d1fc8c695..a53c243f0 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -287,7 +287,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) static status_t build_i(private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, SECURITY_ASSOCIATION)) + message->get_payload(message, ID_INITIATOR)) { message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); build_address_list(this, message); @@ -317,7 +317,7 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) static status_t process_r(private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, SECURITY_ASSOCIATION)) + message->get_payload(message, ID_INITIATOR)) { process_payloads(this, message); } @@ -348,7 +348,7 @@ static status_t process_r(private_ike_mobike_t *this, message_t *message) static status_t build_r(private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, SECURITY_ASSOCIATION)) + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) { if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) { @@ -378,7 +378,7 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message) static status_t process_i(private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, SECURITY_ASSOCIATION)) + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) { process_payloads(this, message); return SUCCESS; diff --git a/src/charon/sa/tasks/ike_p2p.c b/src/charon/sa/tasks/ike_p2p.c index de5a2e30e..84b88e16b 100644 --- a/src/charon/sa/tasks/ike_p2p.c +++ b/src/charon/sa/tasks/ike_p2p.c @@ -34,7 +34,7 @@ #define P2P_SESSIONID_LEN 8 #define P2P_SESSIONKEY_LEN 16 -// FIXME: proposed values +/* FIXME: proposed values */ #define P2P_SESSIONID_MIN_LEN 4 #define P2P_SESSIONID_MAX_LEN 16 #define P2P_SESSIONKEY_MIN_LEN 8 @@ -119,8 +119,6 @@ struct private_ike_p2p_t { }; -// ----------------------------------------------------------------------------- - /** * Adds a list of endpoints as notifies to a given message */ @@ -146,7 +144,7 @@ static void gather_and_add_endpoints(private_ike_p2p_t *this, message_t *message host_t *addr, *host; u_int16_t port; - // get the port that is used to communicate with the ms + /* get the port that is used to communicate with the ms */ host = this->ike_sa->get_my_host(this->ike_sa); port = host->get_port(host); @@ -215,7 +213,8 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message) DBG1(DBG_IKE, "received invalid P2P_ENDPOINT notify"); break; } - DBG2(DBG_IKE, "received P2P_ENDPOINT notify"); + DBG1(DBG_IKE, "received %N P2P_ENDPOINT %#H", p2p_endpoint_type_names, + endpoint->get_type(endpoint), endpoint->get_host(endpoint)); this->remote_endpoints->insert_last(this->remote_endpoints, endpoint); break; @@ -253,8 +252,6 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message) iterator->destroy(iterator); } -// ----------------------------------------------------------------------------- - /** * Implementation of task_t.process for initiator */ @@ -296,8 +293,8 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message) if (!this->response) { - // only the initiator creates a session ID. the responder returns - // the session ID that it received from the initiator + /* only the initiator creates a session ID. the responder returns + * the session ID that it received from the initiator */ if (rand->allocate_pseudo_random_bytes(rand, P2P_SESSIONID_LEN, &this->session_id) != SUCCESS) { @@ -326,7 +323,7 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message) } else { - // FIXME: should we make that configurable + /* FIXME: should we make that configurable */ message->add_notify(message, FALSE, P2P_CALLBACK, chunk_empty); } @@ -334,8 +331,9 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message) break; } + default: + break; } - return NEED_MORE; } @@ -387,11 +385,11 @@ static status_t process_r(private_ike_p2p_t *this, message_t *message) } DBG1(DBG_IKE, "received P2P_CONNECT"); - break; } + default: + break; } - return NEED_MORE; } @@ -420,16 +418,16 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message) if (this->response) { - // FIXME: handle result of set_responder_data - // as initiator, upon receiving a response from another peer, - // update the checklist and start sending checks + /* FIXME: handle result of set_responder_data + * as initiator, upon receiving a response from another peer, + * update the checklist and start sending checks */ charon->connect_manager->set_responder_data(charon->connect_manager, this->session_id, this->session_key, this->remote_endpoints); } else { - // FIXME: handle result of set_initiator_data - // as responder, create a checklist with the initiator's data + /* FIXME: handle result of set_initiator_data + * as responder, create a checklist with the initiator's data */ charon->connect_manager->set_initiator_data(charon->connect_manager, this->peer_id, this->ike_sa->get_my_id(this->ike_sa), this->session_id, this->session_key, this->remote_endpoints, @@ -440,9 +438,10 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message) return FAILED; } } - break; } + default: + break; } return SUCCESS; } @@ -469,20 +468,19 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message) case IKE_AUTH: { process_payloads(this, message); - - //FIXME: we should update the server reflexive endpoint somehow, if mobike notices a change - + /* FIXME: we should update the server reflexive endpoint somehow, + * if mobike notices a change */ endpoint_notify_t *reflexive; - if (this->remote_endpoints->get_first(this->remote_endpoints, (void**)&reflexive) == SUCCESS && - reflexive->get_type(reflexive) == SERVER_REFLEXIVE) - {//FIXME: should we accept this endpoint even if we did not send a request? + if (this->remote_endpoints->get_first(this->remote_endpoints, + (void**)&reflexive) == SUCCESS && + reflexive->get_type(reflexive) == SERVER_REFLEXIVE) + { /* FIXME: should we accept this endpoint even if we did not send + * a request? */ host_t *endpoint = reflexive->get_host(reflexive); - DBG2(DBG_IKE, "received server reflexive endpoint %#H", endpoint); this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint->clone(endpoint)); } - - // FIXME: what if it failed? e.g. AUTH failure + /* FIXME: what if it failed? e.g. AUTH failure */ SIG(CHILD_UP_SUCCESS, "established mediation connection without CHILD_SA successfully"); break; @@ -494,22 +492,23 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message) if (this->failed) { DBG1(DBG_IKE, "peer '%D' is not online", this->peer_id); - // FIXME: notify the mediated connection (job?) - // FIXME: probably delete the created checklist, at least as responder + /* FIXME: notify the mediated connection (job?) + * FIXME: probably delete the created checklist, at least as + * responder */ } else { if (this->response) { - // FIXME: handle result of set_responder_data - // as responder, we update the checklist and start sending checks + /* FIXME: handle result of set_responder_data. + * as responder, we update the checklist and start sending checks */ charon->connect_manager->set_responder_data(charon->connect_manager, this->session_id, this->session_key, this->local_endpoints); } else { - // FIXME: handle result of set_initiator_data - // as initiator, we create a checklist and set the initiator's data + /* FIXME: handle result of set_initiator_data + * as initiator, we create a checklist and set the initiator's data */ charon->connect_manager->set_initiator_data(charon->connect_manager, this->ike_sa->get_my_id(this->ike_sa), this->peer_id, this->session_id, this->session_key, this->local_endpoints, @@ -518,12 +517,12 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message) } break; } + default: + break; } return SUCCESS; } -// ----------------------------------------------------------------------------- - /** * Implementation of task_t.process for initiator (mediation server) */ @@ -542,21 +541,19 @@ static status_t build_i_ms(private_ike_p2p_t *this, message_t *message) } else { - notify_payload_t *notify; - if (this->response) { message->add_notify(message, FALSE, P2P_RESPONSE, chunk_empty); - } - + } message->add_notify(message, FALSE, P2P_SESSIONID, this->session_id); message->add_notify(message, FALSE, P2P_SESSIONKEY, this->session_key); add_endpoints_to_message(message, this->remote_endpoints); } - break; } + default: + break; } return NEED_MORE; @@ -614,9 +611,10 @@ static status_t process_r_ms(private_ike_p2p_t *this, message_t *message) this->invalid_syntax = TRUE; break; } - break; } + default: + break; } return NEED_MORE; @@ -679,7 +677,7 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message) if (!peer_sa) { - // the peer is not online + /* the peer is not online */ message->add_notify(message, TRUE, P2P_CONNECT_FAILED, chunk_empty); break; } @@ -691,6 +689,8 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message) break; } + default: + break; } return SUCCESS; } @@ -700,18 +700,9 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message) */ static status_t process_i_ms(private_ike_p2p_t *this, message_t *message) { - switch(message->get_exchange_type(message)) - { - case P2P_CONNECT: - { - break; - } - } return SUCCESS; } -// ----------------------------------------------------------------------------- - /** * Implementation of ike_p2p.connect */ @@ -813,7 +804,7 @@ ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator) } else { - // mediation server + /* mediation server */ if (initiator) { this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_ms; diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index e9d0c4da1..cc20a8861 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -28,6 +28,7 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_NATD", "IKE_MOBIKE", "IKE_AUTHENTICATE", + "IKE_AUTH_LIFETIME", "IKE_CERT", "IKE_CONFIG", "IKE_REKEY", diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h index dd2bb8a83..a59207711 100644 --- a/src/charon/sa/tasks/task.h +++ b/src/charon/sa/tasks/task.h @@ -45,6 +45,8 @@ enum task_type_t { IKE_MOBIKE, /** authenticate the initiated IKE_SA */ IKE_AUTHENTICATE, + /** AUTH_LIFETIME negotiation, RFC4478 */ + IKE_AUTH_LIFETIME, /** exchange certificates and requests */ IKE_CERT, /** Configuration payloads, virtual IP and such */ diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in index 5b35c87a5..707612e92 100755 --- a/src/ipsec/ipsec.in +++ b/src/ipsec/ipsec.in @@ -14,7 +14,11 @@ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # -# RCSID $Id: ipsec.in 3268 2007-10-08 19:59:18Z andreas $ +# RCSID $Id: ipsec.in 3390 2007-12-12 22:27:40Z andreas $ + +# define a minimum PATH environment in case it is not set +PATH="/sbin:/bin:/usr/sbin:/usr/bin:@IPSEC_SBINDIR@" +export PATH # name and version of the ipsec implementation IPSEC_NAME="@IPSEC_NAME@" @@ -97,26 +101,36 @@ down) if [ "$#" -ne 1 ] then echo "Usage: ipsec down <connection name>" - exit 1 + exit 2 fi - if test -e $IPSEC_PLUTO_PID + rc=7 + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --name "$1" --terminate + rc="$?" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then $IPSEC_STROKE down "$1" + rc="$?" fi - exit 0 + exit "$rc" ;; listalgs|listpubkeys|\listcards|\rereadgroups) op="$1" shift - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK "$@" "--$op" + exit "$?" + else + if [ -e $IPSEC_CHARON_PID ] + then + exit 3 + else + exit 7 + fi fi - exit 0 ;; listcerts|listcacerts|listaacerts|\ listacerts|listgroups|listocspcerts|\ @@ -125,75 +139,92 @@ rereadsecrets|rereadcacerts|rereadaacerts|\ rereadacerts|rereadocspcerts|rereadcrls|\ rereadall|purgeocsp) op="$1" + rc=7 shift - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK "$@" "--$op" + rc="$?" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then $IPSEC_STROKE "$op" "$@" + rc="$?" fi - exit 0 + exit "$rc" ;; ready) shift - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --listen + exit 0 + else + exit 7 fi - exit 0 ;; reload) - if test -e $IPSEC_STARTER_PID + rc=7 + if [ -e $IPSEC_STARTER_PID ] then - echo "Reloading strongSwan IPsec configuration..." >&2 - kill -s USR1 `cat $IPSEC_STARTER_PID` + echo "Reloading strongSwan IPsec configuration..." >&2 + kill -s USR1 `cat $IPSEC_STARTER_PID` 2>/dev/null && rc=0 else - echo "ipsec starter is not running" >&2 + echo "Reloading strongSwan IPsec failed: starter is not running" >&2 fi - exit 0 + exit "$rc" ;; restart) $IPSEC_SBINDIR/ipsec stop sleep 2 shift - $IPSEC_SBINDIR/ipsec start "$@" - exit 0 + exec $IPSEC_SBINDIR/ipsec start "$@" ;; route|unroute) op="$1" + rc=7 shift if [ "$#" -ne 1 ] then - echo "Usage: ipsec $op <connection name>" - exit 1 + echo "Usage: ipsec $op <connection name>" + exit 2 fi - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --name "$1" "--$op" + rc="$?" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then $IPSEC_STROKE "$op" "$1" + rc="$?" fi - exit 0 + exit "$rc" ;; scencrypt|scdecrypt) op="$1" shift - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK "--$op" "$@" + exit "$?" + else + exit 7 fi - exit 0 ;; secrets) - if test -e $IPSEC_PLUTO_PID + rc=7 + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --rereadsecrets + rc="$?" fi - exit 0 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE rereadsecrets + rc="$?" + fi + exit "$rc" ;; start) shift @@ -201,36 +232,64 @@ start) ;; status|statusall) op="$1" + # Return value is slightly different for the status command: + # 0 - service up and running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running (unused) + # 4 - service status unknown :-( + # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) shift - if test $# -eq 0 + if [ $# -eq 0 ] then - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK "--$op" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then $IPSEC_STROKE "$op" fi else - if test -e $IPSEC_PLUTO_PID + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --name "$1" "--$op" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then $IPSEC_STROKE "$op" "$1" fi fi - exit 0 + if [ -e $IPSEC_STARTER_PID ] + then + kill -0 `cat $IPSEC_STARTER_PID` 2>/dev/null + exit $? + fi + exit 3 ;; stop) - if test -e $IPSEC_STARTER_PID + # stopping a not-running service is considered as success + if [ -e $IPSEC_STARTER_PID ] then - echo "Stopping strongSwan IPsec..." >&2 - kill `cat $IPSEC_STARTER_PID` + echo "Stopping strongSwan IPsec..." >&2 + spid=`cat $IPSEC_STARTER_PID` + if [ -n "$spid" ] + then + kill $spid 2>/dev/null + loop=5 + while [ $loop -gt 0 ] ; do + kill -s 0 $spid 2>/dev/null || break + sleep 1 + loop=$(($loop - 1)) + done + if [ $loop -eq 0 ] + then + kill -s KILL $spid 2>/dev/null + rm -f $IPSEC_STARTER_PID + fi + fi else - echo "ipsec starter is not running" >&2 + echo "Stopping strongSwan IPsec failed: starter is not running" >&2 fi exit 0 ;; @@ -239,27 +298,31 @@ up) if [ "$#" -ne 1 ] then echo "Usage: ipsec up <connection name>" - exit 1 + exit 2 fi - if test -e $IPSEC_PLUTO_PID + rc=7 + if [ -e $IPSEC_PLUTO_PID ] then $IPSEC_WHACK --name "$1" --initiate + rc="$?" fi - if test -e $IPSEC_CHARON_PID + if [ -e $IPSEC_CHARON_PID ] then - $IPSEC_STROKE up "$1" + $IPSEC_STROKE up "$1" + rc="$?" fi - exit 0 + exit "$rc" ;; update) - if test -e $IPSEC_STARTER_PID + if [ -e $IPSEC_STARTER_PID ] then echo "Updating strongSwan IPsec configuration..." >&2 kill -s HUP `cat $IPSEC_STARTER_PID` + exit 0 else - echo "ipsec starter is not running" >&2 + echo "Updating strongSwan IPsec failed: starter is not running" >&2 + exit 7 fi - exit 0 ;; version|--version) echo "Linux $IPSEC_NAME $IPSEC_VERSION" @@ -269,7 +332,7 @@ version|--version) ;; --*) echo "$0: unknown option \`$1' (perhaps command name was omitted?)" >&2 - exit 1 + exit 2 ;; esac @@ -278,13 +341,13 @@ shift path="$IPSEC_DIR/$cmd" -if test ! -x "$path" +if [ ! -x "$path" ] then path="$IPSEC_DIR/$cmd" - if test ! -x "$path" + if [ ! -x "$path" ] then echo "$0: unknown IPsec command \`$cmd' (\`ipsec --help' for list)" >&2 - exit 1 + exit 2 fi fi diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c index 1367494f8..641ce5d64 100644 --- a/src/libstrongswan/crypto/ac.c +++ b/src/libstrongswan/crypto/ac.c @@ -20,7 +20,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: ac.c 3300 2007-10-12 21:53:18Z andreas $ + * RCSID $Id: ac.c 3355 2007-11-20 12:06:40Z martin $ */ #include <string.h> @@ -544,7 +544,7 @@ static void list(const private_x509ac_t *this, FILE *out, bool utc) fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); if (now < this->notBefore) { - fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore); + fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); } else { @@ -554,14 +554,14 @@ static void list(const private_x509ac_t *this, FILE *out, bool utc) fprintf(out, " not after %#T, ", &this->notAfter, utc); if (now > this->notAfter) { - fprintf(out, "expired (%V ago)\n", &now, &this->notAfter); + fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); } else { fprintf(out, "ok"); if (now > this->notAfter - ACERT_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, " (expires in %V)", &now, &this->notAfter); + fprintf(out, " (expires in %#V)", &now, &this->notAfter); } fprintf(out, " \n"); } diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c index a78590954..510e3528e 100644 --- a/src/libstrongswan/crypto/ca.c +++ b/src/libstrongswan/crypto/ca.c @@ -279,11 +279,11 @@ static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc) fprintf(out, "%#T, until %#T, ", &thisUpdate, utc, &nextUpdate, utc); if (now > nextUpdate) { - fprintf(out, "expired (%V ago)\n", &now, &nextUpdate); + fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); } else { - fprintf(out, "ok (expires in %V)\n", &now, &nextUpdate); + fprintf(out, "ok (expires in %#V)\n", &now, &nextUpdate); } fprintf(out, " serial: %#B, %N\n", &serial, cert_status_names, certinfo->get_status(certinfo)); @@ -654,7 +654,7 @@ static cert_status_t verify_by_ocsp(private_ca_info_t* this, if (comparison > 0) { - iterator->insert_after(iterator, (void *)cached_certinfo); + this->certinfos->insert_last(this->certinfos, (void *)cached_certinfo); } else { diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c index d52078ea9..ab23bb9ec 100755 --- a/src/libstrongswan/crypto/crl.c +++ b/src/libstrongswan/crypto/crl.c @@ -19,7 +19,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: crl.c 3300 2007-10-12 21:53:18Z andreas $ + * RCSID $Id: crl.c 3355 2007-11-20 12:06:40Z martin $ */ #include <sys/stat.h> @@ -463,11 +463,11 @@ static void list(private_crl_t *this, FILE* out, bool utc) } else if (now > this->nextUpdate) { - fprintf(out, "expired (%V ago)\n", &now, &this->nextUpdate); + fprintf(out, "expired (%#V ago)\n", &now, &this->nextUpdate); } else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, "ok (expires in %V)\n", &now, &this->nextUpdate); + fprintf(out, "ok (expires in %#V)\n", &now, &this->nextUpdate); } else { diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c index d9093fc62..6f154b36f 100755 --- a/src/libstrongswan/crypto/x509.c +++ b/src/libstrongswan/crypto/x509.c @@ -24,7 +24,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: x509.c 3301 2007-10-12 21:56:30Z andreas $ + * RCSID $Id: x509.c 3355 2007-11-20 12:06:40Z martin $ */ #include <gmp.h> @@ -1182,7 +1182,7 @@ static void list(private_x509_t *this, FILE *out, bool utc) fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); if (now < this->notBefore) { - fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore); + fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); } else { @@ -1192,14 +1192,14 @@ static void list(private_x509_t *this, FILE *out, bool utc) fprintf(out, " not after %#T, ", &this->notAfter, utc); if (now > this->notAfter) { - fprintf(out, "expired (%V ago)\n", &now, &this->notAfter); + fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); } else { fprintf(out, "ok"); if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, " (expires in %V)", &now, &this->notAfter); + fprintf(out, " (expires in %#V)", &now, &this->notAfter); } fprintf(out, " \n"); } diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index 9f96d119c..f66818bc2 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -150,11 +150,20 @@ static int print_time(FILE *stream, const struct printf_info *info, static int print_time_delta(FILE *stream, const struct printf_info *info, const void *const *args) { - time_t *start = *((time_t**)(args[0])); - time_t *end = *((time_t**)(args[1])); - u_int delta = abs(*end - *start); - char* unit = "second"; + time_t *arg1, *arg2; + time_t delta; + + arg1 = *((time_t**)(args[0])); + if (info->alt) + { + arg2 = *((time_t**)(args[1])); + delta = abs(*arg1 - *arg2); + } + else + { + delta = *arg1; + } if (delta > 2 * 60 * 60 * 24) { @@ -180,5 +189,5 @@ static int print_time_delta(FILE *stream, const struct printf_info *info, static void __attribute__ ((constructor))print_register() { register_printf_function(PRINTF_TIME, print_time, arginfo_ptr_alt_ptr_int); - register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_ptr); + register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_alt_ptr_ptr); } diff --git a/src/libstrongswan/printf_hook.c b/src/libstrongswan/printf_hook.c index 0407e8c82..baf339640 100644 --- a/src/libstrongswan/printf_hook.c +++ b/src/libstrongswan/printf_hook.c @@ -116,3 +116,26 @@ int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argty } return 1; } + +/** + * special arginfo handler respecting alt flag + */ +int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes) +{ + if (info->alt) + { + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_POINTER; + } + return 2; + } + + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + diff --git a/src/libstrongswan/printf_hook.h b/src/libstrongswan/printf_hook.h index 03bcf447d..77b228da0 100644 --- a/src/libstrongswan/printf_hook.h +++ b/src/libstrongswan/printf_hook.h @@ -44,7 +44,7 @@ #define PRINTF_TRAFFIC_SELECTOR 'R' /** 1 argument: time_t *time; with #-modifier 2 arguments: time_t *time, bool utc */ #define PRINTF_TIME 'T' -/** 2 arguments: time_t *begin, time_t *end */ +/** 1 argument: time_t *delta; with #-modifier 2 arguments: time_t *begin, time_t *end */ #define PRINTF_TIME_DELTA 'V' /** @@ -55,6 +55,7 @@ int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes); int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes); int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes); +int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes); #endif /* PRINTF_HOOK_H_ */ diff --git a/src/libstrongswan/utils/lexparser.c b/src/libstrongswan/utils/lexparser.c index 9d3f06593..7cc89fc90 100644 --- a/src/libstrongswan/utils/lexparser.c +++ b/src/libstrongswan/utils/lexparser.c @@ -17,8 +17,12 @@ * 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. + * + * RCSID $Id: lexparser.c 3353 2007-11-19 12:27:08Z martin $ */ +/* memrchr is a GNU extension */ +#define _GNU_SOURCE #include <string.h> #include "lexparser.h" @@ -45,7 +49,7 @@ bool match(const char *pattern, const chunk_t *ch) } /** - * extracts a token ending with a given termination symbol + * extracts a token ending with the first occurrence of a given termination symbol */ bool extract_token(chunk_t *token, const char termination, chunk_t *src) { @@ -71,6 +75,32 @@ bool extract_token(chunk_t *token, const char termination, chunk_t *src) } /** + * extracts a token ending with the last occurrence of a given termination symbol + */ +bool extract_last_token(chunk_t *token, const char termination, chunk_t *src) +{ + u_char *eot = memrchr(src->ptr, termination, src->len); + + /* initialize empty token */ + *token = chunk_empty; + + if (eot == NULL) /* termination symbol not found */ + { + return FALSE; + } + + /* extract token */ + token->ptr = src->ptr; + token->len = (u_int)(eot - src->ptr); + + /* advance src pointer after termination symbol */ + src->ptr = eot + 1; + src->len -= (token->len + 1); + + return TRUE; +} + +/** * fetches a new line terminated by \n or \r\n */ bool fetchline(chunk_t *src, chunk_t *line) diff --git a/src/libstrongswan/utils/lexparser.h b/src/libstrongswan/utils/lexparser.h index e3c2c4c70..775898139 100644 --- a/src/libstrongswan/utils/lexparser.h +++ b/src/libstrongswan/utils/lexparser.h @@ -17,6 +17,8 @@ * 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. + * + * RCSID $Id: lexparser.h 3346 2007-11-16 20:23:29Z andreas $ */ #include <library.h> @@ -32,11 +34,16 @@ bool eat_whitespace(chunk_t *src); bool match(const char *pattern, const chunk_t *ch); /** - * @brief Extracts a token ending with a given termination symbol + * @brief Extracts a token ending with the first occurence a given termination symbol */ bool extract_token(chunk_t *token, const char termination, chunk_t *src); /** + * @brief Extracts a token ending with the last occurence a given termination symbol + */ +bool extract_last_token(chunk_t *token, const char termination, chunk_t *src); + +/** * @brief Fetches a new text line terminated by \n or \r\n */ bool fetchline(chunk_t *src, chunk_t *line); diff --git a/src/manager/Makefile.am b/src/manager/Makefile.am index 17eecdbab..7f77d1dba 100644 --- a/src/manager/Makefile.am +++ b/src/manager/Makefile.am @@ -3,7 +3,9 @@ ipsec_PROGRAMS = manager.fcgi manager_fcgi_SOURCES = \ main.c manager.c manager.h gateway.h gateway.c database.h database.c \ controller/auth_controller.c controller/auth_controller.h \ -controller/status_controller.c controller/status_controller.h \ +controller/ikesa_controller.c controller/ikesa_controller.h \ +controller/control_controller.c controller/control_controller.h \ +controller/config_controller.c controller/config_controller.h \ controller/gateway_controller.c controller/gateway_controller.h manager_fcgi_LDADD = $(top_builddir)/src/manager/libappserv.la -lsqlite3 @@ -34,20 +36,31 @@ ipsec_templates_auth_DATA = templates/auth/login.cs ipsec_templates_gatewaydir = ${ipsec_templatesdir}/gateway ipsec_templates_gateway_DATA = templates/gateway/list.cs -ipsec_templates_statusdir = ${ipsec_templatesdir}/status -ipsec_templates_status_DATA = templates/status/ikesalist.cs +ipsec_templates_ikesadir = ${ipsec_templatesdir}/ikesa +ipsec_templates_ikesa_DATA = templates/ikesa/list.cs + +ipsec_templates_controldir = ${ipsec_templatesdir}/control +ipsec_templates_control_DATA = templates/control/result.cs + +ipsec_templates_configdir = ${ipsec_templatesdir}/config +ipsec_templates_config_DATA = templates/config/list.cs ipsec_templates_staticdir = ${ipsec_templatesdir}/static ipsec_templates_static_DATA = templates/static/style.css templates/static/script.js templates/static/jquery.js \ templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/pipe-thin-green.png templates/static/pipe-thin-left-green.png templates/static/pipe-thin-right-green.png \ templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ -templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png \ +templates/static/close.png templates/static/initiate.png EXTRA_DIST = manager.db templates/header.cs templates/footer.cs templates/error.cs \ -templates/auth/login.cs templates/gateway/list.cs templates/status/ikesalist.cs \ +templates/auth/login.cs templates/gateway/list.cs templates/ikesa/list.cs \ +templates/config/list.cs templates/control/result.cs \ templates/static/style.css templates/static/script.js templates/static/jquery.js \ templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/pipe-thin-green.png templates/static/pipe-thin-left-green.png templates/static/pipe-thin-right-green.png \ templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ -templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png \ +templates/static/close.png templates/static/initiate.png diff --git a/src/manager/Makefile.in b/src/manager/Makefile.in index 5c09c22d4..3830d37fc 100644 --- a/src/manager/Makefile.in +++ b/src/manager/Makefile.in @@ -52,9 +52,11 @@ am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" \ "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsec_templatesdir)" \ "$(DESTDIR)$(ipsec_templates_authdir)" \ + "$(DESTDIR)$(ipsec_templates_configdir)" \ + "$(DESTDIR)$(ipsec_templates_controldir)" \ "$(DESTDIR)$(ipsec_templates_gatewaydir)" \ - "$(DESTDIR)$(ipsec_templates_staticdir)" \ - "$(DESTDIR)$(ipsec_templates_statusdir)" + "$(DESTDIR)$(ipsec_templates_ikesadir)" \ + "$(DESTDIR)$(ipsec_templates_staticdir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = @@ -67,7 +69,8 @@ ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am_manager_fcgi_OBJECTS = main.$(OBJEXT) manager.$(OBJEXT) \ gateway.$(OBJEXT) database.$(OBJEXT) auth_controller.$(OBJEXT) \ - status_controller.$(OBJEXT) gateway_controller.$(OBJEXT) + ikesa_controller.$(OBJEXT) control_controller.$(OBJEXT) \ + config_controller.$(OBJEXT) gateway_controller.$(OBJEXT) manager_fcgi_OBJECTS = $(am_manager_fcgi_OBJECTS) manager_fcgi_DEPENDENCIES = $(top_builddir)/src/manager/libappserv.la DEFAULT_INCLUDES = -I.@am__isrc@ @@ -87,12 +90,16 @@ DIST_SOURCES = $(libappserv_la_SOURCES) $(manager_fcgi_SOURCES) ipsecDATA_INSTALL = $(INSTALL_DATA) ipsec_templatesDATA_INSTALL = $(INSTALL_DATA) ipsec_templates_authDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_configDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_controlDATA_INSTALL = $(INSTALL_DATA) ipsec_templates_gatewayDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_ikesaDATA_INSTALL = $(INSTALL_DATA) ipsec_templates_staticDATA_INSTALL = $(INSTALL_DATA) -ipsec_templates_statusDATA_INSTALL = $(INSTALL_DATA) DATA = $(ipsec_DATA) $(ipsec_templates_DATA) \ - $(ipsec_templates_auth_DATA) $(ipsec_templates_gateway_DATA) \ - $(ipsec_templates_static_DATA) $(ipsec_templates_status_DATA) + $(ipsec_templates_auth_DATA) $(ipsec_templates_config_DATA) \ + $(ipsec_templates_control_DATA) \ + $(ipsec_templates_gateway_DATA) $(ipsec_templates_ikesa_DATA) \ + $(ipsec_templates_static_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -229,7 +236,9 @@ xml_LIBS = @xml_LIBS@ manager_fcgi_SOURCES = \ main.c manager.c manager.h gateway.h gateway.c database.h database.c \ controller/auth_controller.c controller/auth_controller.h \ -controller/status_controller.c controller/status_controller.h \ +controller/ikesa_controller.c controller/ikesa_controller.h \ +controller/control_controller.c controller/control_controller.h \ +controller/config_controller.c controller/config_controller.h \ controller/gateway_controller.c controller/gateway_controller.h manager_fcgi_LDADD = $(top_builddir)/src/manager/libappserv.la -lsqlite3 @@ -251,22 +260,31 @@ ipsec_templates_authdir = ${ipsec_templatesdir}/auth ipsec_templates_auth_DATA = templates/auth/login.cs ipsec_templates_gatewaydir = ${ipsec_templatesdir}/gateway ipsec_templates_gateway_DATA = templates/gateway/list.cs -ipsec_templates_statusdir = ${ipsec_templatesdir}/status -ipsec_templates_status_DATA = templates/status/ikesalist.cs +ipsec_templates_ikesadir = ${ipsec_templatesdir}/ikesa +ipsec_templates_ikesa_DATA = templates/ikesa/list.cs +ipsec_templates_controldir = ${ipsec_templatesdir}/control +ipsec_templates_control_DATA = templates/control/result.cs +ipsec_templates_configdir = ${ipsec_templatesdir}/config +ipsec_templates_config_DATA = templates/config/list.cs ipsec_templates_staticdir = ${ipsec_templatesdir}/static ipsec_templates_static_DATA = templates/static/style.css templates/static/script.js templates/static/jquery.js \ templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/pipe-thin-green.png templates/static/pipe-thin-left-green.png templates/static/pipe-thin-right-green.png \ templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ -templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png \ +templates/static/close.png templates/static/initiate.png EXTRA_DIST = manager.db templates/header.cs templates/footer.cs templates/error.cs \ -templates/auth/login.cs templates/gateway/list.cs templates/status/ikesalist.cs \ +templates/auth/login.cs templates/gateway/list.cs templates/ikesa/list.cs \ +templates/config/list.cs templates/control/result.cs \ templates/static/style.css templates/static/script.js templates/static/jquery.js \ templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/pipe-thin-green.png templates/static/pipe-thin-left-green.png templates/static/pipe-thin-right-green.png \ templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ -templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png \ +templates/static/close.png templates/static/initiate.png all: all-am @@ -369,15 +387,17 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_controller.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/database.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatcher.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gateway.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gateway_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ikesa_controller.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status_controller.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Plo@am__quote@ .c.o: @@ -443,19 +463,47 @@ auth_controller.obj: controller/auth_controller.c @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 auth_controller.obj `if test -f 'controller/auth_controller.c'; then $(CYGPATH_W) 'controller/auth_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/auth_controller.c'; fi` -status_controller.o: controller/status_controller.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT status_controller.o -MD -MP -MF $(DEPDIR)/status_controller.Tpo -c -o status_controller.o `test -f 'controller/status_controller.c' || echo '$(srcdir)/'`controller/status_controller.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/status_controller.Tpo $(DEPDIR)/status_controller.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/status_controller.c' object='status_controller.o' libtool=no @AMDEPBACKSLASH@ +ikesa_controller.o: controller/ikesa_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ikesa_controller.o -MD -MP -MF $(DEPDIR)/ikesa_controller.Tpo -c -o ikesa_controller.o `test -f 'controller/ikesa_controller.c' || echo '$(srcdir)/'`controller/ikesa_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ikesa_controller.Tpo $(DEPDIR)/ikesa_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/ikesa_controller.c' object='ikesa_controller.o' 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 status_controller.o `test -f 'controller/status_controller.c' || echo '$(srcdir)/'`controller/status_controller.c +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ikesa_controller.o `test -f 'controller/ikesa_controller.c' || echo '$(srcdir)/'`controller/ikesa_controller.c -status_controller.obj: controller/status_controller.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT status_controller.obj -MD -MP -MF $(DEPDIR)/status_controller.Tpo -c -o status_controller.obj `if test -f 'controller/status_controller.c'; then $(CYGPATH_W) 'controller/status_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/status_controller.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/status_controller.Tpo $(DEPDIR)/status_controller.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/status_controller.c' object='status_controller.obj' libtool=no @AMDEPBACKSLASH@ +ikesa_controller.obj: controller/ikesa_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ikesa_controller.obj -MD -MP -MF $(DEPDIR)/ikesa_controller.Tpo -c -o ikesa_controller.obj `if test -f 'controller/ikesa_controller.c'; then $(CYGPATH_W) 'controller/ikesa_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/ikesa_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ikesa_controller.Tpo $(DEPDIR)/ikesa_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/ikesa_controller.c' object='ikesa_controller.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 status_controller.obj `if test -f 'controller/status_controller.c'; then $(CYGPATH_W) 'controller/status_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/status_controller.c'; fi` +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ikesa_controller.obj `if test -f 'controller/ikesa_controller.c'; then $(CYGPATH_W) 'controller/ikesa_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/ikesa_controller.c'; fi` + +control_controller.o: controller/control_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT control_controller.o -MD -MP -MF $(DEPDIR)/control_controller.Tpo -c -o control_controller.o `test -f 'controller/control_controller.c' || echo '$(srcdir)/'`controller/control_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/control_controller.Tpo $(DEPDIR)/control_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/control_controller.c' object='control_controller.o' 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 control_controller.o `test -f 'controller/control_controller.c' || echo '$(srcdir)/'`controller/control_controller.c + +control_controller.obj: controller/control_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT control_controller.obj -MD -MP -MF $(DEPDIR)/control_controller.Tpo -c -o control_controller.obj `if test -f 'controller/control_controller.c'; then $(CYGPATH_W) 'controller/control_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/control_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/control_controller.Tpo $(DEPDIR)/control_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/control_controller.c' object='control_controller.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 control_controller.obj `if test -f 'controller/control_controller.c'; then $(CYGPATH_W) 'controller/control_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/control_controller.c'; fi` + +config_controller.o: controller/config_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT config_controller.o -MD -MP -MF $(DEPDIR)/config_controller.Tpo -c -o config_controller.o `test -f 'controller/config_controller.c' || echo '$(srcdir)/'`controller/config_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/config_controller.Tpo $(DEPDIR)/config_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/config_controller.c' object='config_controller.o' 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 config_controller.o `test -f 'controller/config_controller.c' || echo '$(srcdir)/'`controller/config_controller.c + +config_controller.obj: controller/config_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT config_controller.obj -MD -MP -MF $(DEPDIR)/config_controller.Tpo -c -o config_controller.obj `if test -f 'controller/config_controller.c'; then $(CYGPATH_W) 'controller/config_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/config_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/config_controller.Tpo $(DEPDIR)/config_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/config_controller.c' object='config_controller.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 config_controller.obj `if test -f 'controller/config_controller.c'; then $(CYGPATH_W) 'controller/config_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/config_controller.c'; fi` gateway_controller.o: controller/gateway_controller.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gateway_controller.o -MD -MP -MF $(DEPDIR)/gateway_controller.Tpo -c -o gateway_controller.o `test -f 'controller/gateway_controller.c' || echo '$(srcdir)/'`controller/gateway_controller.c @@ -527,6 +575,40 @@ uninstall-ipsec_templates_authDATA: echo " rm -f '$(DESTDIR)$(ipsec_templates_authdir)/$$f'"; \ rm -f "$(DESTDIR)$(ipsec_templates_authdir)/$$f"; \ done +install-ipsec_templates_configDATA: $(ipsec_templates_config_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_configdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_configdir)" + @list='$(ipsec_templates_config_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_configDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_configdir)/$$f'"; \ + $(ipsec_templates_configDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_configdir)/$$f"; \ + done + +uninstall-ipsec_templates_configDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_config_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_configdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_configdir)/$$f"; \ + done +install-ipsec_templates_controlDATA: $(ipsec_templates_control_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_controldir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_controldir)" + @list='$(ipsec_templates_control_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_controlDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_controldir)/$$f'"; \ + $(ipsec_templates_controlDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_controldir)/$$f"; \ + done + +uninstall-ipsec_templates_controlDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_control_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_controldir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_controldir)/$$f"; \ + done install-ipsec_templates_gatewayDATA: $(ipsec_templates_gateway_DATA) @$(NORMAL_INSTALL) test -z "$(ipsec_templates_gatewaydir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_gatewaydir)" @@ -544,6 +626,23 @@ uninstall-ipsec_templates_gatewayDATA: echo " rm -f '$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f'"; \ rm -f "$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f"; \ done +install-ipsec_templates_ikesaDATA: $(ipsec_templates_ikesa_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_ikesadir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_ikesadir)" + @list='$(ipsec_templates_ikesa_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_ikesaDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_ikesadir)/$$f'"; \ + $(ipsec_templates_ikesaDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_ikesadir)/$$f"; \ + done + +uninstall-ipsec_templates_ikesaDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_ikesa_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_ikesadir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_ikesadir)/$$f"; \ + done install-ipsec_templates_staticDATA: $(ipsec_templates_static_DATA) @$(NORMAL_INSTALL) test -z "$(ipsec_templates_staticdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_staticdir)" @@ -561,23 +660,6 @@ uninstall-ipsec_templates_staticDATA: echo " rm -f '$(DESTDIR)$(ipsec_templates_staticdir)/$$f'"; \ rm -f "$(DESTDIR)$(ipsec_templates_staticdir)/$$f"; \ done -install-ipsec_templates_statusDATA: $(ipsec_templates_status_DATA) - @$(NORMAL_INSTALL) - test -z "$(ipsec_templates_statusdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_statusdir)" - @list='$(ipsec_templates_status_DATA)'; for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(ipsec_templates_statusDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_statusdir)/$$f'"; \ - $(ipsec_templates_statusDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_statusdir)/$$f"; \ - done - -uninstall-ipsec_templates_statusDATA: - @$(NORMAL_UNINSTALL) - @list='$(ipsec_templates_status_DATA)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(ipsec_templates_statusdir)/$$f'"; \ - rm -f "$(DESTDIR)$(ipsec_templates_statusdir)/$$f"; \ - done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -657,7 +739,7 @@ check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsec_templatesdir)" "$(DESTDIR)$(ipsec_templates_authdir)" "$(DESTDIR)$(ipsec_templates_gatewaydir)" "$(DESTDIR)$(ipsec_templates_staticdir)" "$(DESTDIR)$(ipsec_templates_statusdir)"; do \ + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsec_templatesdir)" "$(DESTDIR)$(ipsec_templates_authdir)" "$(DESTDIR)$(ipsec_templates_configdir)" "$(DESTDIR)$(ipsec_templates_controldir)" "$(DESTDIR)$(ipsec_templates_gatewaydir)" "$(DESTDIR)$(ipsec_templates_ikesadir)" "$(DESTDIR)$(ipsec_templates_staticdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -707,9 +789,11 @@ info-am: install-data-am: install-ipsecDATA install-ipsecPROGRAMS \ install-ipsec_templatesDATA install-ipsec_templates_authDATA \ + install-ipsec_templates_configDATA \ + install-ipsec_templates_controlDATA \ install-ipsec_templates_gatewayDATA \ - install-ipsec_templates_staticDATA \ - install-ipsec_templates_statusDATA + install-ipsec_templates_ikesaDATA \ + install-ipsec_templates_staticDATA install-dvi: install-dvi-am @@ -748,9 +832,11 @@ ps-am: uninstall-am: uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ uninstall-ipsec_templatesDATA \ uninstall-ipsec_templates_authDATA \ + uninstall-ipsec_templates_configDATA \ + uninstall-ipsec_templates_controlDATA \ uninstall-ipsec_templates_gatewayDATA \ - uninstall-ipsec_templates_staticDATA \ - uninstall-ipsec_templates_statusDATA uninstall-libLTLIBRARIES + uninstall-ipsec_templates_ikesaDATA \ + uninstall-ipsec_templates_staticDATA uninstall-libLTLIBRARIES .MAKE: install-am install-strip @@ -763,9 +849,11 @@ uninstall-am: uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ install-exec-am install-html install-html-am install-info \ install-info-am install-ipsecDATA install-ipsecPROGRAMS \ install-ipsec_templatesDATA install-ipsec_templates_authDATA \ + install-ipsec_templates_configDATA \ + install-ipsec_templates_controlDATA \ install-ipsec_templates_gatewayDATA \ - install-ipsec_templates_staticDATA \ - install-ipsec_templates_statusDATA install-libLTLIBRARIES \ + install-ipsec_templates_ikesaDATA \ + install-ipsec_templates_staticDATA install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ @@ -774,9 +862,11 @@ uninstall-am: uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ uninstall-am uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ uninstall-ipsec_templatesDATA \ uninstall-ipsec_templates_authDATA \ + uninstall-ipsec_templates_configDATA \ + uninstall-ipsec_templates_controlDATA \ uninstall-ipsec_templates_gatewayDATA \ - uninstall-ipsec_templates_staticDATA \ - uninstall-ipsec_templates_statusDATA uninstall-libLTLIBRARIES + uninstall-ipsec_templates_ikesaDATA \ + uninstall-ipsec_templates_staticDATA uninstall-libLTLIBRARIES # 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. diff --git a/src/manager/controller/auth_controller.c b/src/manager/controller/auth_controller.c index fd4a3c7a5..e9b86941a 100644 --- a/src/manager/controller/auth_controller.c +++ b/src/manager/controller/auth_controller.c @@ -60,7 +60,7 @@ static void check(private_auth_controller_t *this, request_t *request) if (username && password && this->manager->login(this->manager, username, password)) { - request->redirect(request, "status/ikesalist"); + request->redirect(request, "ikesa/list"); } else { diff --git a/src/manager/controller/config_controller.c b/src/manager/controller/config_controller.c new file mode 100644 index 000000000..e7941ada4 --- /dev/null +++ b/src/manager/controller/config_controller.c @@ -0,0 +1,214 @@ +/** + * @file config_controller.c + * + * @brief Implementation of config_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "config_controller.h" +#include "../manager.h" +#include "../gateway.h" + +#include <xml.h> + +#include <library.h> + + +typedef struct private_config_controller_t private_config_controller_t; + +/** + * private data of the task manager + */ +struct private_config_controller_t { + + /** + * public functions + */ + config_controller_t public; + + /** + * manager instance + */ + manager_t *manager; +}; + +/** + * read XML of a peerconfig element and fill template + */ +static void process_peerconfig(private_config_controller_t *this, + enumerator_t *e, request_t *r) +{ + xml_t *xml; + enumerator_t *e1, *e2, *e3; + char *name, *value, *config = "", *child = "", *section = ""; + + while (e->enumerate(e, &xml, &name, &value)) + { + if (streq(name, "name")) + { + config = value; + } + else if (streq(name, "ikeconfig")) + { + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "local") || streq(name, "remote")) + { + if (streq(value, "0.0.0.0") || streq(value, "::")) + { + value = "%any"; + } + r->setf(r, "peercfgs.%s.ikecfg.%s=%s", config, name, value); + } + } + e1->destroy(e1); + } + else if (streq(name, "childconfiglist")) + { + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "childconfig")) + { + int num = 0; + + e2 = xml->children(xml); + while (e2->enumerate(e2, &xml, &name, &value)) + { + if (streq(name, "name")) + { + child = value; + } + else if (streq(name, "local") || streq(name, "remote")) + { + section = name; + e3 = xml->children(xml); + while (e3->enumerate(e3, &xml, &name, &value)) + { + if (streq(name, "network")) + { + r->setf(r, "peercfgs.%s.childcfgs.%s.%s.networks.%d=%s", + config, child, section, ++num, value); + } + } + e3->destroy(e3); + } + } + e2->destroy(e2); + } + } + e1->destroy(e1); + } + else + { + r->setf(r, "peercfgs.%s.%s=%s", config, name, value); + } + } +} + +static void list(private_config_controller_t *this, request_t *r) +{ + gateway_t *gateway; + xml_t *xml; + enumerator_t *e1, *e2; + char *name, *value; + + gateway = this->manager->select_gateway(this->manager, 0); + e1 = gateway->query_configlist(gateway); + if (e1 == NULL) + { + r->set(r, "title", "Error"); + r->set(r, "error", "querying the gateway failed"); + r->render(r, "templates/error.cs"); + } + else + { + r->set(r, "title", "Configuration overview"); + + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "peerconfig")) + { + e2 = xml->children(xml); + process_peerconfig(this, e2, r); + e2->destroy(e2); + } + } + e1->destroy(e1); + + r->render(r, "templates/config/list.cs"); + } +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_config_controller_t *this) +{ + return "config"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_config_controller_t *this, + request_t *request, char *action) +{ + if (!this->manager->logged_in(this->manager)) + { + return request->redirect(request, "auth/login"); + } + if (this->manager->select_gateway(this->manager, 0) == NULL) + { + return request->redirect(request, "gateway/list"); + } + if (action) + { + if (streq(action, "list")) + { + return list(this, request); + } + } + return request->redirect(request, "config/list"); +} + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_config_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *config_controller_create(context_t *context, void *param) +{ + private_config_controller_t *this = malloc_thing(private_config_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->manager = (manager_t*)context; + + return &this->public.controller; +} + diff --git a/src/manager/controller/status_controller.h b/src/manager/controller/config_controller.h index a736dda83..fcf5f5c49 100644 --- a/src/manager/controller/status_controller.h +++ b/src/manager/controller/config_controller.h @@ -1,7 +1,7 @@ /** - * @file status_controller.h + * @file config_controller.h * - * @brief Interface of status_controller_t. + * @brief Interface of config_controller_t. * */ @@ -20,18 +20,18 @@ * for more details. */ -#ifndef STATUS_CONTROLLER_H_ -#define STATUS_CONTROLLER_H_ +#ifndef CONFIG_CONTROLLER_H_ +#define CONFIG_CONTROLLER_H_ #include <controller.h> -typedef struct status_controller_t status_controller_t; +typedef struct config_controller_t config_controller_t; /** * @brief Status controller. */ -struct status_controller_t { +struct config_controller_t { /** * Implements controller_t interface. @@ -40,8 +40,8 @@ struct status_controller_t { }; /** - * @brief Create a status_controller controller instance. + * @brief Create a config_controller controller instance. */ -controller_t *status_controller_create(context_t *context, void *param); +controller_t *config_controller_create(context_t *context, void *param); -#endif /* STATUS_CONTROLLER_H_ */ +#endif /* CONFIG_CONTROLLER_H_ */ diff --git a/src/manager/controller/control_controller.c b/src/manager/controller/control_controller.c new file mode 100644 index 000000000..12cb5e907 --- /dev/null +++ b/src/manager/controller/control_controller.c @@ -0,0 +1,211 @@ +/** + * @file control_controller.c + * + * @brief Implementation of control_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "control_controller.h" +#include "../manager.h" +#include "../gateway.h" + +#include <xml.h> + +#include <library.h> + + +typedef struct private_control_controller_t private_control_controller_t; + +/** + * private data of the task manager + */ +struct private_control_controller_t { + + /** + * public functions + */ + control_controller_t public; + + /** + * manager instance + */ + manager_t *manager; +}; + +/** + * handle the result of a control operation + */ +static void handle_result(private_control_controller_t *this, request_t *r, + enumerator_t *e) +{ + enumerator_t *e1; + xml_t *xml; + char *name, *value; + int num = 0; + + if (e) + { + while (e->enumerate(e, &xml, &name, &value)) + { + if (streq(name, "status")) + { + if (value && atoi(value) == 0) + { + r->set(r, "result", "Operation executed successfully:"); + } + else + { + r->set(r, "result", "Operation failed:"); + } + } + else if (streq(name, "log")) + { + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "item")) + { + r->setf(r, "log.%d=%s", ++num, value); + } + } + e1->destroy(e1); + } + } + e->destroy(e); + r->render(r, "templates/control/result.cs"); + } + else + { + r->set(r, "title", "Error"); + r->set(r, "error", "controlling the gateway failed"); + r->render(r, "templates/error.cs"); + } +} + +/** + * initiate an IKE or CHILD SA + */ +static void initiate(private_control_controller_t *this, request_t *r, + bool ike, char *config) +{ + gateway_t *gateway; + enumerator_t *e; + + r->setf(r, "title=Establishing %s SA %s", ike ? "IKE" : "CHILD", config); + gateway = this->manager->select_gateway(this->manager, 0); + e = gateway->initiate(gateway, ike, config); + handle_result(this, r, e); +} + +/** + * terminate an IKE or CHILD SA + */ +static void terminate(private_control_controller_t *this, request_t *r, + bool ike, u_int32_t id) +{ + gateway_t *gateway; + enumerator_t *e; + + r->setf(r, "title=Terminate %s SA %d", ike ? "IKE" : "CHILD", id); + gateway = this->manager->select_gateway(this->manager, 0); + e = gateway->terminate(gateway, ike, id); + handle_result(this, r, e); +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_control_controller_t *this) +{ + return "control"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_control_controller_t *this, + request_t *request, char *action, char *str) +{ + if (!this->manager->logged_in(this->manager)) + { + return request->redirect(request, "auth/login"); + } + if (this->manager->select_gateway(this->manager, 0) == NULL) + { + return request->redirect(request, "gateway/list"); + } + if (action) + { + u_int32_t id; + + if (streq(action, "terminateike")) + { + if (str && (id = atoi(str))) + { + return terminate(this, request, TRUE, id); + } + } + if (streq(action, "terminatechild")) + { + if (str && (id = atoi(str))) + { + return terminate(this, request, FALSE, id); + } + } + if (streq(action, "initiateike")) + { + if (str) + { + return initiate(this, request, TRUE, str); + } + } + if (streq(action, "initiatechild")) + { + if (str) + { + return initiate(this, request, FALSE, str); + } + } + } + return request->redirect(request, "ikesa/list"); +} + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_control_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *control_controller_create(context_t *context, void *param) +{ + private_control_controller_t *this = malloc_thing(private_control_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->manager = (manager_t*)context; + + return &this->public.controller; +} + diff --git a/src/manager/controller/control_controller.h b/src/manager/controller/control_controller.h new file mode 100644 index 000000000..6a55170aa --- /dev/null +++ b/src/manager/controller/control_controller.h @@ -0,0 +1,47 @@ +/** + * @file control_controller.h + * + * @brief Interface of control_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef CONTROL_CONTROLLER_H_ +#define CONTROL_CONTROLLER_H_ + + +#include <controller.h> + +typedef struct control_controller_t control_controller_t; + +/** + * @brief Status controller. + */ +struct control_controller_t { + + /** + * Implements controller_t interface. + */ + controller_t controller; +}; + +/** + * @brief Create a control_controller controller instance. + */ +controller_t *control_controller_create(context_t *context, void *param); + +#endif /* CONTROL_CONTROLLER_H_ */ diff --git a/src/manager/controller/gateway_controller.c b/src/manager/controller/gateway_controller.c index bdc779256..dff1cf3cf 100644 --- a/src/manager/controller/gateway_controller.c +++ b/src/manager/controller/gateway_controller.c @@ -82,7 +82,7 @@ static void _select(private_gateway_controller_t *this, request_t *request) { if (this->manager->select_gateway(this->manager, atoi(id))) { - request->redirect(request, "status/ikesalist"); + request->redirect(request, "ikesa/list"); return; } } diff --git a/src/manager/controller/status_controller.c b/src/manager/controller/ikesa_controller.c index bcdbd26ea..2b282b79c 100644 --- a/src/manager/controller/status_controller.c +++ b/src/manager/controller/ikesa_controller.c @@ -1,7 +1,7 @@ /** - * @file status_controller.c + * @file ikesa_controller.c * - * @brief Implementation of status_controller_t. + * @brief Implementation of ikesa_controller_t. * */ @@ -20,7 +20,7 @@ * for more details. */ -#include "status_controller.h" +#include "ikesa_controller.h" #include "../manager.h" #include "../gateway.h" @@ -29,17 +29,17 @@ #include <library.h> -typedef struct private_status_controller_t private_status_controller_t; +typedef struct private_ikesa_controller_t private_ikesa_controller_t; /** * private data of the task manager */ -struct private_status_controller_t { +struct private_ikesa_controller_t { /** * public functions */ - status_controller_t public; + ikesa_controller_t public; /** * manager instance @@ -50,7 +50,7 @@ struct private_status_controller_t { /** * read XML of a childsa element and fill template */ -static void process_childsa(private_status_controller_t *this, char *id, +static void process_childsa(private_ikesa_controller_t *this, char *id, enumerator_t *e, request_t *r) { xml_t *xml; @@ -102,7 +102,7 @@ static void process_childsa(private_status_controller_t *this, char *id, /** * read XML of a ikesa element and fill template */ -static void process_ikesa(private_status_controller_t *this, +static void process_ikesa(private_ikesa_controller_t *this, enumerator_t *e, request_t *r) { xml_t *xml; @@ -146,7 +146,7 @@ static void process_ikesa(private_status_controller_t *this, } } -static void ikesalist(private_status_controller_t *this, request_t *r) +static void list(private_ikesa_controller_t *this, request_t *r) { gateway_t *gateway; xml_t *xml; @@ -176,22 +176,22 @@ static void ikesalist(private_status_controller_t *this, request_t *r) } e1->destroy(e1); - r->render(r, "templates/status/ikesalist.cs"); + r->render(r, "templates/ikesa/list.cs"); } } /** * Implementation of controller_t.get_name */ -static char* get_name(private_status_controller_t *this) +static char* get_name(private_ikesa_controller_t *this) { - return "status"; + return "ikesa"; } /** * Implementation of controller_t.handle */ -static void handle(private_status_controller_t *this, +static void handle(private_ikesa_controller_t *this, request_t *request, char *action) { if (!this->manager->logged_in(this->manager)) @@ -204,18 +204,18 @@ static void handle(private_status_controller_t *this, } if (action) { - if (streq(action, "ikesalist")) + if (streq(action, "list")) { - return ikesalist(this, request); + return list(this, request); } } - return request->redirect(request, "status/ikesalist"); + return request->redirect(request, "ikesa/list"); } /** * Implementation of controller_t.destroy */ -static void destroy(private_status_controller_t *this) +static void destroy(private_ikesa_controller_t *this) { free(this); } @@ -223,9 +223,9 @@ static void destroy(private_status_controller_t *this) /* * see header file */ -controller_t *status_controller_create(context_t *context, void *param) +controller_t *ikesa_controller_create(context_t *context, void *param) { - private_status_controller_t *this = malloc_thing(private_status_controller_t); + private_ikesa_controller_t *this = malloc_thing(private_ikesa_controller_t); this->public.controller.get_name = (char*(*)(controller_t*))get_name; this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; diff --git a/src/manager/controller/ikesa_controller.h b/src/manager/controller/ikesa_controller.h new file mode 100644 index 000000000..753cccad1 --- /dev/null +++ b/src/manager/controller/ikesa_controller.h @@ -0,0 +1,47 @@ +/** + * @file ikesa_controller.h + * + * @brief Interface of ikesa_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef IKESA_CONTROLLER_H_ +#define IKESA_CONTROLLER_H_ + + +#include <controller.h> + +typedef struct ikesa_controller_t ikesa_controller_t; + +/** + * @brief Status controller. + */ +struct ikesa_controller_t { + + /** + * Implements controller_t interface. + */ + controller_t controller; +}; + +/** + * @brief Create a ikesa_controller controller instance. + */ +controller_t *ikesa_controller_create(context_t *context, void *param); + +#endif /* IKESA_CONTROLLER_H_ */ diff --git a/src/manager/gateway.c b/src/manager/gateway.c index 5f5a4b477..d4eb5279e 100644 --- a/src/manager/gateway.c +++ b/src/manager/gateway.c @@ -57,6 +57,11 @@ struct private_gateway_t { * socket file descriptor, > 0 if connected */ int fd; + + /** + * unique id assigned to each xml message + */ + int xmlid; }; struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"}; @@ -103,7 +108,7 @@ static bool connect_(private_gateway_t *this) /** * Implementation of gateway_t.request. */ -static char* request(private_gateway_t *this, char *xml) +static char* request(private_gateway_t *this, char *xml, ...) { if (this->fd < 0) { @@ -116,18 +121,25 @@ static char* request(private_gateway_t *this, char *xml) { char buf[8096]; ssize_t len; + va_list args; - len = strlen(xml); - if (send(this->fd, xml, len, 0) != len) + va_start(args, xml); + len = vsnprintf(buf, sizeof(buf), xml, args); + va_end(args); + if (len < 0 || len >= sizeof(buf)) { return NULL; } - len = recv(this->fd, buf, sizeof(buf) - 1, 0); - if (len < 0) + if (send(this->fd, buf, len, 0) != len) { - return NULL; + if (!connect_(this)) + { + return NULL; + } + continue; } - if (len == 0) + len = recv(this->fd, buf, sizeof(buf) - 1, 0); + if (len <= 0) { if (!connect_(this)) { @@ -149,11 +161,11 @@ static enumerator_t* query_ikesalist(private_gateway_t *this) xml_t *xml; enumerator_t *e1, *e2, *e3, *e4 = NULL; - str = request(this, "<message type=\"request\" id=\"1\">" + str = request(this, "<message type=\"request\" id=\"%d\">" "<query>" "<ikesalist/>" "</query>" - "</message>"); + "</message>", this->xmlid++); if (str == NULL) { return NULL; @@ -197,6 +209,152 @@ static enumerator_t* query_ikesalist(private_gateway_t *this) return NULL; } + +/** + * Implementation of gateway_t.query_configlist. + */ +static enumerator_t* query_configlist(private_gateway_t *this) +{ + char *str, *name, *value; + xml_t *xml; + enumerator_t *e1, *e2, *e3, *e4 = NULL; + + str = request(this, "<message type=\"request\" id=\"%d\">" + "<query>" + "<configlist/>" + "</query>" + "</message>", this->xmlid++); + if (str == NULL) + { + return NULL; + } + xml = xml_create(str); + if (xml == NULL) + { + return NULL; + } + + e1 = xml->children(xml); + free(str); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "message")) + { + e2 = xml->children(xml); + while (e2->enumerate(e2, &xml, &name, &value)) + { + if (streq(name, "query")) + { + e3 = xml->children(xml); + while (e3->enumerate(e3, &xml, &name, &value)) + { + if (streq(name, "configlist")) + { + e4 = xml->children(xml); + e1->destroy(e1); + e2->destroy(e2); + e3->destroy(e3); + return e4; + } + } + e3->destroy(e3); + } + } + e2->destroy(e2); + } + } + e1->destroy(e1); + return NULL; +} + +/** + * create enumerator over control elements children of a control response + */ +static enumerator_t* read_result(private_gateway_t *this, char *res) +{ + char *name, *value; + xml_t *xml; + enumerator_t *e1, *e2, *e3; + + if (res == NULL) + { + return NULL; + } + xml = xml_create(res); + if (xml == NULL) + { + return NULL; + } + e1 = xml->children(xml); + free(res); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "message")) + { + e2 = xml->children(xml); + while (e2->enumerate(e2, &xml, &name, &value)) + { + if (streq(name, "control")) + { + e3 = xml->children(xml); + e1->destroy(e1); + e2->destroy(e2); + return e3; + } + } + e2->destroy(e2); + } + } + e1->destroy(e1); + return NULL; +} + +/** + * Implementation of gateway_t.initiate. + */ +static enumerator_t* initiate(private_gateway_t *this, bool ike, char *name) +{ + char *str, *kind; + + if (ike) + { + kind = "ike"; + } + else + { + kind = "child"; + } + str = request(this, "<message type=\"request\" id=\"%d\">" + "<control>" + "<%ssainitiate>%s</%ssainitiate>" + "</control>" + "</message>", this->xmlid++, kind, name, kind); + return read_result(this, str); +} + +/** + * Implementation of gateway_t.terminate. + */ +static enumerator_t* terminate(private_gateway_t *this, bool ike, u_int32_t id) +{ + char *str, *kind; + + if (ike) + { + kind = "ike"; + } + else + { + kind = "child"; + } + str = request(this, "<message type=\"request\" id=\"%d\">" + "<control>" + "<%ssaterminate>%d</%ssaterminate>" + "</control>" + "</message>", this->xmlid++, kind, id, kind); + return read_result(this, str); +} + /** * Implementation of gateway_t.destroy */ @@ -220,11 +378,15 @@ static private_gateway_t *gateway_create(char *name) this->public.request = (char*(*)(gateway_t*, char *xml))request; this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist; + this->public.query_configlist = (enumerator_t*(*)(gateway_t*))query_configlist; + this->public.initiate = (enumerator_t*(*)(gateway_t*, bool ike, char *name))initiate; + this->public.terminate = (enumerator_t*(*)(gateway_t*, bool ike, u_int32_t id))terminate; this->public.destroy = (void(*)(gateway_t*))destroy; this->name = strdup(name); this->host = NULL; this->fd = -1; + this->xmlid = 1; return this; } diff --git a/src/manager/gateway.h b/src/manager/gateway.h index 1fe2aef4b..81d8b9c3f 100644 --- a/src/manager/gateway.h +++ b/src/manager/gateway.h @@ -49,6 +49,31 @@ struct gateway_t { enumerator_t* (*query_ikesalist)(gateway_t *this); /** + * @brief Query the list of peer configs and its subconfigs. + * + * @return enumerator over peerconfig XML elements + */ + enumerator_t* (*query_configlist)(gateway_t *this); + + /** + * @brief Terminate an IKE or a CHILD SA. + * + * @param ike TRUE for IKE-, FALSE for a CHILD-SA + * @param id ID of the SA to terminate + * @return enumerator over control response XML children + */ + enumerator_t* (*terminate)(gateway_t *this, bool ike, u_int32_t id); + + /** + * @brief Initiate an IKE or a CHILD SA. + * + * @param ike TRUE for IKE-, FALSE for CHILD-SA + * @param name name of the peer/child config + * @return enumerator over control response XML children + */ + enumerator_t* (*initiate)(gateway_t *this, bool ike, char *name); + + /** * @brief Destroy a gateway instance. */ void (*destroy)(gateway_t *this); diff --git a/src/manager/lib/dispatcher.c b/src/manager/lib/dispatcher.c index df669ceb6..ce53d39ea 100644 --- a/src/manager/lib/dispatcher.c +++ b/src/manager/lib/dispatcher.c @@ -30,6 +30,7 @@ #include <signal.h> #include <unistd.h> +#include <debug.h> #include <utils/linked_list.h> typedef struct private_dispatcher_t private_dispatcher_t; @@ -122,8 +123,8 @@ typedef struct { session_t *session; /** condvar to wait for session */ pthread_cond_t cond; - /** number of threads waiting for session */ - int waiting; + /** TRUE if session is in use */ + bool in_use; /** last use of the session */ time_t used; } session_entry_t; @@ -164,7 +165,7 @@ static session_entry_t *session_entry_create(private_dispatcher_t *this) session_entry_t *entry; entry = malloc_thing(session_entry_t); - entry->waiting = 1; + entry->in_use = FALSE; pthread_cond_init(&entry->cond, NULL); entry->session = load_session(this); entry->used = time(NULL); @@ -228,11 +229,12 @@ static void dispatch(private_dispatcher_t *this) now = time(NULL); /* find session */ - iterator = this->sessions->create_iterator_locked(this->sessions, &this->mutex); + pthread_mutex_lock(&this->mutex); + iterator = this->sessions->create_iterator(this->sessions, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { /* check all sessions for timeout */ - if (current->waiting == 0 && + if (!current->in_use && current->used < now - this->timeout) { iterator->remove(iterator); @@ -243,27 +245,24 @@ static void dispatch(private_dispatcher_t *this) streq(current->session->get_sid(current->session), sid)) { found = current; - found->waiting++; } } iterator->destroy(iterator); if (found) { /* wait until session is unused */ - pthread_mutex_lock(&this->mutex); - while (found->waiting > 1) + while (found->in_use) { pthread_cond_wait(&found->cond, &this->mutex); } - pthread_mutex_unlock(&this->mutex); } else { /* create a new session if not found */ found = session_entry_create(this); - pthread_mutex_lock(&this->mutex); this->sessions->insert_first(this->sessions, found); - pthread_mutex_unlock(&this->mutex); } + found->in_use = TRUE; + pthread_mutex_unlock(&this->mutex); /* start processing */ found->session->process(found->session, request); @@ -271,7 +270,7 @@ static void dispatch(private_dispatcher_t *this) /* release session */ pthread_mutex_lock(&this->mutex); - found->waiting--; + found->in_use = FALSE; pthread_cond_signal(&found->cond); pthread_mutex_unlock(&this->mutex); diff --git a/src/manager/lib/request.c b/src/manager/lib/request.c index 4623b3860..2e18bded5 100644 --- a/src/manager/lib/request.c +++ b/src/manager/lib/request.c @@ -179,12 +179,18 @@ static void add_cookie(private_request_t *this, char *name, char *value) /** * Implementation of request_t.redirect. */ -static void redirect(private_request_t *this, char *location) +static void redirect(private_request_t *this, char *fmt, ...) { + va_list args; + FCGX_FPrintF(this->req->out, "Status: 303 See Other\n"); - FCGX_FPrintF(this->req->out, "Location: %s%s%s\n\n", + FCGX_FPrintF(this->req->out, "Location: %s%s", FCGX_GetParam("SCRIPT_NAME", this->req->envp), - *location == '/' ? "" : "/", location); + *fmt == '/' ? "" : "/"); + va_start(args, fmt); + FCGX_VFPrintF(this->req->out, fmt, args); + va_end(args); + FCGX_FPrintF(this->req->out, "\n\n"); } /** @@ -196,6 +202,16 @@ static char* get_base(private_request_t *this) } /** + * Implementation of request_t.serve. + */ +static void serve(private_request_t *this, char *headers, chunk_t chunk) +{ + FCGX_FPrintF(this->req->out, "%s\n\n", headers); + + FCGX_PutStr(chunk.ptr, chunk.len, this->req->out); +} + +/** * Implementation of request_t.render. */ static void render(private_request_t *this, char *template) @@ -254,8 +270,9 @@ request_t *request_create(FCGX_Request *request, bool debug) this->public.add_cookie = (void(*)(request_t*, char *name, char *value))add_cookie; this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie; this->public.get_query_data = (char*(*)(request_t*, char *name))get_query_data; - this->public.redirect = (void(*)(request_t*, char *location))redirect; + this->public.redirect = (void(*)(request_t*, char *fmt,...))redirect; this->public.render = (void(*)(request_t*,char*))render; + this->public.serve = (void(*)(request_t*,char*,chunk_t))serve; this->public.set = (void(*)(request_t*, char *, char*))set; this->public.setf = (void(*)(request_t*, char *format, ...))setf; this->public.destroy = (void(*)(request_t*))destroy; diff --git a/src/manager/lib/request.h b/src/manager/lib/request.h index e6fd71e71..f78741d37 100644 --- a/src/manager/lib/request.h +++ b/src/manager/lib/request.h @@ -75,9 +75,10 @@ struct request_t { /** * @brief Redirect the client to another location. * - * @param location location to redirect to + * @param fmt location format string + * @param ... variable argument for fmt */ - void (*redirect)(request_t *this, char *location); + void (*redirect)(request_t *this, char *fmt, ...); /** * @brief Set a template value. @@ -106,11 +107,18 @@ struct request_t { * other targets without to worry about path location. * * @param template clearsilver template file location - * @return rendered template string */ void (*render)(request_t *this, char *template); /** + * @brief Serve a request with headers and a body. + * + * @param headers HTTP headers, \n separated + * @param chunk body to write to output + */ + void (*serve)(request_t *this, char *headers, chunk_t chunk); + + /** * @brief Destroy the request_t. */ void (*destroy) (request_t *this); diff --git a/src/manager/main.c b/src/manager/main.c index bbe07cbf3..eb4654ced 100644 --- a/src/manager/main.c +++ b/src/manager/main.c @@ -26,11 +26,13 @@ #include "manager.h" #include "database.h" #include "controller/auth_controller.h" -#include "controller/status_controller.h" +#include "controller/ikesa_controller.h" #include "controller/gateway_controller.h" +#include "controller/control_controller.h" +#include "controller/config_controller.h" #define DBFILE IPSECDIR "/manager.db" -#define SESSION_TIMEOUT 180 +#define SESSION_TIMEOUT 900 #define THREADS 10 int main (int arc, char *argv[]) @@ -52,9 +54,11 @@ int main (int arc, char *argv[]) dispatcher = dispatcher_create(socket, SESSION_TIMEOUT, (context_constructor_t)manager_create, database); - dispatcher->add_controller(dispatcher, status_controller_create, NULL); + dispatcher->add_controller(dispatcher, ikesa_controller_create, NULL); dispatcher->add_controller(dispatcher, gateway_controller_create, NULL); dispatcher->add_controller(dispatcher, auth_controller_create, NULL); + dispatcher->add_controller(dispatcher, control_controller_create, NULL); + dispatcher->add_controller(dispatcher, config_controller_create, NULL); dispatcher->run(dispatcher, THREADS, NULL, NULL, NULL, NULL); diff --git a/src/manager/templates/config/list.cs b/src/manager/templates/config/list.cs new file mode 100644 index 000000000..e71830d4d --- /dev/null +++ b/src/manager/templates/config/list.cs @@ -0,0 +1,104 @@ +<?cs include:"templates/header.cs" ?> +<?cs each:peercfg = peercfgs ?> + <div class="expand" id="peercfg-<?cs name:peercfg ?>"> + <h1><?cs name:peercfg ?>: + <span><?cs var:peercfg.local ?></span> <-> + <span><?cs var:peercfg.remote ?></span> + </h1> + <div class="controls"> + <?cs if:peercfg.remote != "%any" ?> + <a title="initiate SA" href="<?cs var:base ?>/control/initiateike/<?cs name:peercfg ?>"> + <img src="<?cs var:base ?>/static/initiate.png"/> + </a> + <?cs else ?> + + <?cs /if ?> + </div> + <div class="expander"> + <hr/> + <table class="drawing"> + <tr> + <td class="left" colspan="3"> + <?cs var:peercfg.local ?> + </td> + <td> + </td> + <td class="right" colspan="3"> + <?cs var:peercfg.remote ?> + </td> + </tr> + <tr class="images"> + <td> + <?cs if:peercfg.remote != "%any" ?> + <img title="Local host can be the initiator" src="<?cs var:base ?>/static/client-left.png"></img> + <?cs else ?> + <img title="Local host must be the responder" src="<?cs var:base ?>/static/gateway-left.png"></img> + <?cs /if ?> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe.png)"> + <font color="#e5bf5e">0123456789abdcef</font><br/><br/><br/> + <?cs var:peercfg.ikecfg.local ?> + </td> + <td> + <img src="<?cs var:base ?>/static/pipe.png"></img> + </td> + <td> + <img title="IKE connection is down" src="<?cs var:base ?>/static/pipe.png"></img> + </td> + <td> + <img src="<?cs var:base ?>/static/pipe.png"></img> + </td> + <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe.png)"> + <font color="#e5bf5e">0123456789abcdef</font><br/><br/><br/> + <?cs var:peercfg.ikecfg.remote ?> + </td> + <td> + <?cs if:peercfg.remote == "%any" ?> + <img title="Remote host must be the initiator" src="<?cs var:base ?>/static/client-right.png"></img> + <?cs else ?> + <img title="Remote host can be the responder" src="<?cs var:base ?>/static/gateway-right.png"></img> + <?cs /if ?> + </td> + </tr> + <?cs each:childcfg = peercfg.childcfgs ?> + <tr> + <td colspan="6" class="expand"> + <h1><?cs name:childcfg ?>:</h1> + </td> + <td class="controls"> + <?cs if:peercfg.remote != "%any" ?> + <a title="initiate SA" href="<?cs var:base ?>/control/initiatechild/<?cs name:childcfg ?>"> + <img src="<?cs var:base ?>/static/initiate.png"/> + </a> + <?cs /if ?> + </td> + </tr> + <tr> + <td colspan="7"><hr/></td> + </tr> + <tr class="images"> + <td colspan="2"> + <?cs each:net = childcfg.local.networks ?> + <p><?cs var:net ?></p> + <?cs /each ?> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin-left.png)"> + <br/><br/><br/> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin.png)"> + </td> + <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe-thin-right.png)"> + <br/><br/><br/> + </td> + <td class="right" colspan="2"> + <?cs each:net = childcfg.remote.networks ?> + <p><?cs var:net ?></p> + <?cs /each ?> + </td> + </tr> + <?cs /each ?> + </table> + </div> + </div> +<?cs /each ?> +<?cs include:"templates/footer.cs" ?> diff --git a/src/manager/templates/control/result.cs b/src/manager/templates/control/result.cs new file mode 100644 index 000000000..1d59df65f --- /dev/null +++ b/src/manager/templates/control/result.cs @@ -0,0 +1,14 @@ +<?cs include:"templates/header.cs" ?> +<div class="expand"> + <h1><?cs var:result ?></h1> + <div class="controls"> </div> + <div class="expander"> + <hr/> + <ul> + <?cs each:item = log ?> + <li><?cs var:item ?></li> + <?cs /each ?> + </ul> + </div> +</div> +<?cs include:"templates/footer.cs" ?> diff --git a/src/manager/templates/header.cs b/src/manager/templates/header.cs index 64a859a9a..bacd833e0 100644 --- a/src/manager/templates/header.cs +++ b/src/manager/templates/header.cs @@ -9,13 +9,15 @@ </head> <body> <div class="fleft"> - <a href="<?cs var:base ?>/status/ikesalist"> + <a href="<?cs var:base ?>/ikesa/list"> <img class="fleft" src="<?cs var:base ?>/static/strongswan.png"/> </a> <h1>strongSwan Manager</h1> <h2><?cs var:title ?></h2> </div> <div class="menu"> + | <a href="<?cs var:base ?>/ikesa/list">IKE SAs</a> + | <a href="<?cs var:base ?>/config/list">Config</a> | <a href="<?cs var:base ?>/gateway/list">Select Gateway</a> | <a href="<?cs var:base ?>/auth/logout">Logout</a> </div> diff --git a/src/manager/templates/status/ikesalist.cs b/src/manager/templates/ikesa/list.cs index 2238aafd3..f9a8e5c68 100644 --- a/src/manager/templates/status/ikesalist.cs +++ b/src/manager/templates/ikesa/list.cs @@ -2,11 +2,16 @@ <?cs each:ikesa = ikesas ?> <div class="expand" id="ikesa-<?cs name:ikesa ?>"> <h1> - IKE #<?cs name:ikesa ?> [<?cs var:ikesa.peerconfig ?>]: + <?cs var:ikesa.peerconfig ?> [IKE #<?cs name:ikesa ?>]: <span><?cs var:ikesa.local.identification ?></span> <-> <span><?cs var:ikesa.remote.identification ?></span> - </h1> - <div> + </h1> + <div class="controls"> + <a title="close IKE_SA" href="<?cs var:base ?>/control/terminateike/<?cs name:ikesa ?>"> + <img src="<?cs var:base ?>/static/close.png"/> + </a> + </div> + <div class="expander"> <hr/> <table class="drawing"> <tr> @@ -66,8 +71,13 @@ </tr> <?cs each:childsa = ikesa.childsas ?> <tr> - <td colspan="7" class="expand"> - <h1>IPsec #<?cs name:childsa ?> [<?cs var:childsa.childconfig ?>]:</h1> + <td colspan="6" class="expand"> + <h1><?cs var:childsa.childconfig ?> [IPsec #<?cs name:childsa ?>]:</h1> + </td> + <td class="controls"> + <a title="close CHILD_SA" href="<?cs var:base ?>/control/terminatechild/<?cs name:childsa ?>"> + <img src="<?cs var:base ?>/static/close.png"/> + </a> </td> </tr> <tr> @@ -79,12 +89,12 @@ <p><?cs var:net ?></p> <?cs /each ?> </td> - <td style="background-image:url(<?cs var:base ?>/static/pipe-thin-left.png)"> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin-left-green.png)"> <?cs var:childsa.local.spi ?> <-<br/><br/><br/> </td> - <td style="background-image:url(<?cs var:base ?>/static/pipe-thin.png)"> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin-green.png)"> </td> - <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe-thin-right.png)"> + <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe-thin-right-green.png)"> -> <?cs var:childsa.remote.spi ?><br/><br/><br/> </td> <td class="right" colspan="2"> diff --git a/src/manager/templates/static/close.png b/src/manager/templates/static/close.png Binary files differnew file mode 100644 index 000000000..7cb058d69 --- /dev/null +++ b/src/manager/templates/static/close.png diff --git a/src/manager/templates/static/initiate.png b/src/manager/templates/static/initiate.png Binary files differnew file mode 100644 index 000000000..4463e3b7a --- /dev/null +++ b/src/manager/templates/static/initiate.png diff --git a/src/manager/templates/static/pipe-thin-green.png b/src/manager/templates/static/pipe-thin-green.png Binary files differnew file mode 100644 index 000000000..df3026ec5 --- /dev/null +++ b/src/manager/templates/static/pipe-thin-green.png diff --git a/src/manager/templates/static/pipe-thin-left-green.png b/src/manager/templates/static/pipe-thin-left-green.png Binary files differnew file mode 100644 index 000000000..b76432a94 --- /dev/null +++ b/src/manager/templates/static/pipe-thin-left-green.png diff --git a/src/manager/templates/static/pipe-thin-right-green.png b/src/manager/templates/static/pipe-thin-right-green.png Binary files differnew file mode 100644 index 000000000..f193af9cc --- /dev/null +++ b/src/manager/templates/static/pipe-thin-right-green.png diff --git a/src/manager/templates/static/script.js b/src/manager/templates/static/script.js index 7b2a5823c..c9105c372 100644 --- a/src/manager/templates/static/script.js +++ b/src/manager/templates/static/script.js @@ -1,8 +1,7 @@ $(function(){ - $(".expand > div").hide(); $(".expand > h1").toggle( - function(){$(this).parent(".expand").find("div").slideDown('fast');}, - function(){$(this).parent(".expand").find("div").slideUp('fast');} + function(){$(this).parent(".expand").find(".expander").slideUp('fast');}, + function(){$(this).parent(".expand").find(".expander").slideDown('fast');} ); }); diff --git a/src/manager/templates/static/style.css b/src/manager/templates/static/style.css index 8a7f4960d..9550b8291 100644 --- a/src/manager/templates/static/style.css +++ b/src/manager/templates/static/style.css @@ -57,6 +57,8 @@ a img { font-size: 1em; cursor: pointer; margin: 0; + float: left; + padding-top: 3px; } .expand h1 span { @@ -64,6 +66,15 @@ a img { margin-right: 2em; } +.expander { + clear:left; +} + +.controls { + margin-top: 3px; + text-align: right; +} + .center { text-align: center; } diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 4519ef7bb..69902ad8f 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -132,15 +132,3 @@ if USE_LIBLDAP pluto_LDADD += -lldap -llber endif -install-exec-local : - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/cacerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/ocspcerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/certs - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/acerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/aacerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/crls - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/reqs - mkdir -p -m 700 $(DESTDIR)$(confdir)/ipsec.d/private - chown -R $(ipsecuid):$(ipsecgid) $(DESTDIR)$(confdir)/ipsec.d - diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in index 8f7a7f31b..77a0a7548 100644 --- a/src/pluto/Makefile.in +++ b/src/pluto/Makefile.in @@ -804,7 +804,7 @@ install-data-am: install-ipsecPROGRAMS install-man install-dvi: install-dvi-am -install-exec-am: install-exec-local +install-exec-am: install-html: install-html-am @@ -847,8 +847,8 @@ uninstall-man: uninstall-man5 uninstall-man8 distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-exec-local \ - install-html install-html-am install-info install-info-am \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ install-ipsecPROGRAMS install-man install-man5 install-man8 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ @@ -861,18 +861,6 @@ uninstall-man: uninstall-man5 uninstall-man8 oid.o : $(LIBSTRONGSWANDIR)/asn1/oid.c $(LIBSTRONGSWANDIR)/asn1/oid.h $(COMPILE) -c -o $@ $< - -install-exec-local : - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/cacerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/ocspcerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/certs - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/acerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/aacerts - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/crls - mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/reqs - mkdir -p -m 700 $(DESTDIR)$(confdir)/ipsec.d/private - chown -R $(ipsecuid):$(ipsecgid) $(DESTDIR)$(confdir)/ipsec.d # 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/pluto/connections.c b/src/pluto/connections.c index 952e722d2..8fbf969b6 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: connections.c 3252 2007-10-06 21:24:50Z andreas $ + * RCSID $Id: connections.c 3361 2007-11-21 23:42:27Z andreas $ */ #include <string.h> @@ -955,6 +955,7 @@ gen_reqid(void) } while (reqid != start); exit_log("unable to allocate reqid"); + return 0; /* never reached ... */ } void diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c index b54f574f2..0e6e3d9b7 100644 --- a/src/pluto/vendor.c +++ b/src/pluto/vendor.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: vendor.c 3252 2007-10-06 21:24:50Z andreas $ + * RCSID $Id: vendor.c 3380 2007-12-04 23:54:32Z andreas $ */ #include <stdlib.h> @@ -206,7 +206,9 @@ static struct vid_struct _vid_tab[] = { /* * strongSwan */ - DEC_MD5_VID(STRONGSWAN, "strongSwan 4.1.8") + DEC_MD5_VID(STRONGSWAN, "strongSwan 4.1.10") + DEC_MD5_VID(STRONGSWAN_4_1_9, "strongSwan 4.1.9") + DEC_MD5_VID(STRONGSWAN_4_1_8, "strongSwan 4.1.8") DEC_MD5_VID(STRONGSWAN_4_1_7, "strongSwan 4.1.7") DEC_MD5_VID(STRONGSWAN_4_1_6, "strongSwan 4.1.6") DEC_MD5_VID(STRONGSWAN_4_1_5, "strongSwan 4.1.5") diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h index 4f480df30..d0853b08c 100644 --- a/src/pluto/vendor.h +++ b/src/pluto/vendor.h @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: vendor.h 3252 2007-10-06 21:24:50Z andreas $ + * RCSID $Id: vendor.h 3380 2007-12-04 23:54:32Z andreas $ */ #ifndef _VENDOR_H_ @@ -111,6 +111,8 @@ enum known_vendorid { VID_STRONGSWAN_4_1_5 = 93, VID_STRONGSWAN_4_1_6 = 94, VID_STRONGSWAN_4_1_7 = 95, + VID_STRONGSWAN_4_1_8 = 96, + VID_STRONGSWAN_4_1_9 = 97, /* 101 - 200 : NAT-Traversal */ VID_NATT_STENBERG_01 =101, diff --git a/src/starter/confread.c b/src/starter/confread.c index e481ff7cf..7a312d893 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: confread.c 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: confread.c 3405 2007-12-19 00:49:32Z andreas $ */ #include <stddef.h> @@ -173,7 +173,7 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token goto err; } } - else if (streq(value, "%any")) + else if (streq(value, "%any") || streq(value, "%any4")) { anyaddr(conn->addr_family, &end->addr); } @@ -509,25 +509,46 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) } break; case KW_EAP: - /* TODO: a gperf function for all EAP types */ + { + char *sep; + + /* check for vendor-type format */ + sep = strchr(kw->value, '-'); + if (sep) + { + *(sep++) = '\0'; + conn->eap_type = atoi(kw->value); + conn->eap_vendor = atoi(sep); + if (conn->eap_type == 0 || conn->eap_vendor == 0) + { + plog("# invalid EAP type: %s=%s", kw->entry->name, kw->value); + cfg->err++; + } + break; + } if (streq(kw->value, "aka")) { - conn->eap = 23; + conn->eap_type = 23; } else if (streq(kw->value, "sim")) { - conn->eap = 18; + conn->eap_type = 18; + } + else if (streq(kw->value, "md5")) + { + conn->eap_type = 4; } else { - conn->eap = atoi(kw->value); - if (conn->eap == 0) + conn->eap_type = atoi(kw->value); + if (conn->eap_type == 0) { plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value); cfg->err++; } } break; + } case KW_KEYINGTRIES: if (streq(kw->value, "%forever")) { diff --git a/src/starter/confread.h b/src/starter/confread.h index 839f73e99..a32e7116d 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: confread.h 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: confread.h 3394 2007-12-13 17:31:21Z martin $ */ #ifndef _IPSEC_CONFREAD_H_ @@ -106,7 +106,8 @@ struct starter_conn { starter_state_t state; keyexchange_t keyexchange; - int eap; + u_int32_t eap_type; + u_int32_t eap_vendor; lset_t policy; time_t sa_ike_life_seconds; time_t sa_ipsec_life_seconds; diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c index 1cb0dfb63..111bb9c6f 100644 --- a/src/starter/invokecharon.c +++ b/src/starter/invokecharon.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: invokecharon.c 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: invokecharon.c 3344 2007-11-15 18:34:05Z martin $ */ #include <sys/types.h> @@ -78,9 +78,14 @@ starter_stop_charon (void) kill(pid, SIGINT); else if (i < 10) kill(pid, SIGTERM); + else if (i == 10) + { + kill(pid, SIGKILL); + plog("starter_stop_charon(): charon does not respond, sending KILL"); + } else kill(pid, SIGKILL); - usleep(20000); + usleep(200000); } if (_charon_pid == 0) return 0; diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5 index 1f581bce8..d542af555 100644 --- a/src/starter/ipsec.conf.5 +++ b/src/starter/ipsec.conf.5 @@ -1,5 +1,5 @@ .TH IPSEC.CONF 5 "27 Jun 2007" -.\" RCSID $Id: ipsec.conf.5 3267 2007-10-08 19:57:54Z andreas $ +.\" RCSID $Id: ipsec.conf.5 3394 2007-12-13 17:31:21Z martin $ .SH NAME ipsec.conf \- IPsec configuration and connections .SH DESCRIPTION @@ -350,13 +350,21 @@ in case of inactivity. This only applies to IKEv1, in IKEv2 the default retransmission timeout applies, as every exchange is used to detect dead peers. .TP .B eap -defines the EAP type to be used if +defines the EAP type to propose as server if the client has .B authby=eap -is selected. Acceptable values are +selected. Acceptable values are .B aka -for EAP-AKA and +for EAP-AKA, .B sim -for EAP-SIM. +for EAP-SIM and +.B md5 +for EAP-MD5. +Additionally, IANA assigned EAP method numbers are accepted, or a definition +in the form +.B eap=type-vendor +(e.g. +.B eap=7-12345 +) can be used to specify vendor specific EAP types. .TP .B esp ESP encryption/authentication algorithm to be used diff --git a/src/starter/starter.c b/src/starter/starter.c index cc591dc61..bc2e8f1df 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: starter.c 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: starter.c 3369 2007-11-28 17:02:12Z andreas $ */ #include <sys/types.h> @@ -43,6 +43,19 @@ #include "cmp.h" #include "interfaces.h" +/** + * Return codes defined by Linux Standard Base Core Specification 3.1 + * in section 20.2. Init Script Actions + */ +#define LSB_RC_SUCCESS 0 /* success */ +#define LSB_RC_FAILURE 1 /* generic or unspecified error */ +#define LSB_RC_INVALID_ARGUMENT 2 /* invalid or excess argument(s) */ +#define LSB_RC_NOT_IMPLEMENTED 3 /* unimplemented feature (reload) */ +#define LSB_RC_NOT_ALLOWED 4 /* user had insufficient privilege */ +#define LSB_RC_NOT_INSTALLED 5 /* program is not installed */ +#define LSB_RC_NOT_CONFIGURED 6 /* program is not configured */ +#define LSB_RC_NOT_RUNNING 7 /* program is not running */ + #define FLAG_ACTION_START_PLUTO 0x01 #define FLAG_ACTION_UPDATE 0x02 #define FLAG_ACTION_RELOAD 0x04 @@ -131,7 +144,7 @@ usage(char *name) { fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " "[--debug|--debug-more|--debug-all]\n"); - exit(1); + exit(LSB_RC_INVALID_ARGUMENT); } int main (int argc, char **argv) @@ -205,7 +218,7 @@ int main (int argc, char **argv) if (getuid() != 0) { plog("permission denied (must be superuser)"); - exit(1); + exit(LSB_RC_NOT_ALLOWED); } if (stat(PLUTO_PID_FILE, &stb) == 0) @@ -227,13 +240,13 @@ int main (int argc, char **argv) if (stat(DEV_RANDOM, &stb) != 0) { plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); - exit(1); + exit(LSB_RC_FAILURE); } if (stat(DEV_URANDOM, &stb)!= 0) { plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); - exit(1); + exit(LSB_RC_FAILURE); } cfg = confread_load(CONFIG_FILE); @@ -244,14 +257,14 @@ int main (int argc, char **argv) { confread_free(cfg); } - exit(1); + exit(LSB_RC_INVALID_ARGUMENT); } /* determine if we have a native netkey IPsec stack */ if (!starter_netkey_init()) { plog("no netkey IPSec stack detected"); - exit(1); + exit(LSB_RC_FAILURE); } last_reload = time(NULL); @@ -259,7 +272,7 @@ int main (int argc, char **argv) if (stat(STARTER_PID_FILE, &stb) == 0) { plog("starter is already running (%s exists) -- no fork done", STARTER_PID_FILE); - exit(0); + exit(LSB_RC_SUCCESS); } /* fork if we're not debugging stuff */ @@ -287,7 +300,7 @@ int main (int argc, char **argv) plog("can't fork: %s", strerror(errno)); break; default: - exit(0); + exit(LSB_RC_SUCCESS); } } @@ -322,7 +335,7 @@ int main (int argc, char **argv) #endif /* LEAK_DETECTIVE */ close_log(); plog("ipsec starter stopped"); - exit(0); + exit(LSB_RC_SUCCESS); } /* @@ -643,7 +656,6 @@ int main (int argc, char **argv) _action_ |= FLAG_ACTION_UPDATE; } } - - return 0; + exit(LSB_RC_SUCCESS); } diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index eb5d20628..fae895ba0 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: starterstroke.c 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: starterstroke.c 3394 2007-12-13 17:31:21Z martin $ */ #include <sys/types.h> @@ -197,7 +197,8 @@ int starter_stroke_add_conn(starter_conn_t *conn) { msg.add_conn.auth_method = AUTH_EAP; } - msg.add_conn.eap_type = conn->eap; + msg.add_conn.eap_type = conn->eap_type; + msg.add_conn.eap_vendor = conn->eap_vendor; if (conn->policy & POLICY_TUNNEL) { diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c index 19fa9558f..d29b87873 100644 --- a/src/starter/starterwhack.c +++ b/src/starter/starterwhack.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: starterwhack.c 3267 2007-10-08 19:57:54Z andreas $ + * RCSID $Id: starterwhack.c 3405 2007-12-19 00:49:32Z andreas $ */ #include <sys/types.h> @@ -148,17 +148,22 @@ connection_name(starter_conn_t *conn) } static void -set_whack_end(whack_end_t *w, starter_end_t *end) +set_whack_end(whack_end_t *w, starter_end_t *end, sa_family_t family) { w->id = end->id; w->cert = end->cert; w->ca = end->ca; w->groups = end->groups; w->host_addr = end->addr; - w->host_nexthop = end->nexthop; w->host_srcip = end->srcip; w->has_client = end->has_client; + if (family == AF_INET6 && isanyaddr(&end->nexthop)) + { + anyaddr(AF_INET6, &end->nexthop); + } + w->host_nexthop = end->nexthop; + if (w->has_client) w->client = end->subnet; else @@ -246,8 +251,8 @@ starter_whack_add_conn(starter_conn_t *conn) msg.sa_keying_tries = conn->sa_keying_tries; msg.policy = conn->policy; - set_whack_end(&msg.left, &conn->left); - set_whack_end(&msg.right, &conn->right); + set_whack_end(&msg.left, &conn->left, conn->addr_family); + set_whack_end(&msg.right, &conn->right, conn->addr_family); msg.esp = conn->esp; msg.ike = conn->ike; diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h index 18db5a894..ca4e397e4 100644 --- a/src/stroke/stroke.h +++ b/src/stroke/stroke.h @@ -19,7 +19,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: stroke.h 3271 2007-10-08 20:12:25Z andreas $ + * RCSID $Id: stroke.h 3394 2007-12-13 17:31:21Z martin $ */ #ifndef STROKE_H_ @@ -182,7 +182,8 @@ struct stroke_msg_t { char *name; int ikev2; int auth_method; - int eap_type; + u_int32_t eap_type; + u_int32_t eap_vendor; int mode; int mobike; int force_encap; |