summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/stroke
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-10-17 21:23:38 +0200
committerYves-Alexis Perez <corsac@debian.org>2013-10-17 21:23:38 +0200
commit9d37ad77ef660b92ea51b69d74e14f931d2a04e2 (patch)
treed6bbb4a5fed1959f8675df9ee7c03713b543fcc9 /src/libcharon/plugins/stroke
parent104f57d4b0fb6d7547d6898352eaa5fb4b222010 (diff)
parente5ee4e7fcdd58b7d86bf1b458da2c63e8e19627b (diff)
downloadvyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.tar.gz
vyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.zip
Merge tag 'v5.1.0-1' into sid
tag strongSwan 5.1.0-1
Diffstat (limited to 'src/libcharon/plugins/stroke')
-rw-r--r--src/libcharon/plugins/stroke/Makefile.am16
-rw-r--r--src/libcharon/plugins/stroke/Makefile.in168
-rw-r--r--src/libcharon/plugins/stroke/stroke_attribute.c282
-rw-r--r--src/libcharon/plugins/stroke/stroke_attribute.h23
-rw-r--r--src/libcharon/plugins/stroke/stroke_ca.c12
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c687
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.h4
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c187
-rw-r--r--src/libcharon/plugins/stroke/stroke_counter.c464
-rw-r--r--src/libcharon/plugins/stroke/stroke_counter.h112
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.c536
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.h9
-rw-r--r--src/libcharon/plugins/stroke/stroke_handler.c231
-rw-r--r--src/libcharon/plugins/stroke/stroke_handler.h64
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c168
-rw-r--r--src/libcharon/plugins/stroke/stroke_plugin.c46
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c441
17 files changed, 2585 insertions, 865 deletions
diff --git a/src/libcharon/plugins/stroke/Makefile.am b/src/libcharon/plugins/stroke/Makefile.am
index e561224e9..9509b1bd3 100644
--- a/src/libcharon/plugins/stroke/Makefile.am
+++ b/src/libcharon/plugins/stroke/Makefile.am
@@ -1,11 +1,13 @@
-
-INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/stroke
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon \
+ -I$(top_srcdir)/src/stroke \
+ -DIPSEC_CONFDIR=\"${sysconfdir}\" \
+ -DIPSEC_PIDDIR=\"${piddir}\"
AM_CFLAGS = \
--rdynamic \
--DIPSEC_CONFDIR=\"${sysconfdir}\" \
--DIPSEC_PIDDIR=\"${piddir}\"
+ -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-stroke.la
@@ -21,6 +23,8 @@ libstrongswan_stroke_la_SOURCES = \
stroke_cred.h stroke_cred.c \
stroke_ca.h stroke_ca.c \
stroke_attribute.h stroke_attribute.c \
+ stroke_handler.h stroke_handler.c \
+ stroke_counter.h stroke_counter.c \
stroke_list.h stroke_list.c
libstrongswan_stroke_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in
index 60f5f535a..151e7ba69 100644
--- a/src/libcharon/plugins/stroke/Makefile.in
+++ b/src/libcharon/plugins/stroke/Makefile.in
@@ -1,9 +1,9 @@
-# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,6 +16,23 @@
@SET_MAKE@
VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -45,10 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
$(top_srcdir)/m4/macros/with.m4 \
$(top_srcdir)/m4/macros/enable-disable.m4 \
$(top_srcdir)/m4/macros/add-plugin.m4 \
- $(top_srcdir)/configure.in
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@@ -72,56 +90,92 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_stroke_la_LIBADD =
am_libstrongswan_stroke_la_OBJECTS = stroke_plugin.lo stroke_socket.lo \
stroke_config.lo stroke_control.lo stroke_cred.lo stroke_ca.lo \
- stroke_attribute.lo stroke_list.lo
+ stroke_attribute.lo stroke_handler.lo stroke_counter.lo \
+ stroke_list.lo
libstrongswan_stroke_la_OBJECTS = \
$(am_libstrongswan_stroke_la_OBJECTS)
-libstrongswan_stroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libstrongswan_stroke_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libstrongswan_stroke_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_stroke_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
@MONOLITHIC_FALSE@am_libstrongswan_stroke_la_rpath = -rpath \
@MONOLITHIC_FALSE@ $(plugindir)
@MONOLITHIC_TRUE@am_libstrongswan_stroke_la_rpath =
-DEFAULT_INCLUDES = -I.@am__isrc@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
- --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
CCLD = $(CC)
-LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
- --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
- $(LDFLAGS) -o $@
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libstrongswan_stroke_la_SOURCES)
DIST_SOURCES = $(libstrongswan_stroke_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+BFDLIB = @BFDLIB@
BTLIB = @BTLIB@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+COVERAGE_CFLAGS = @COVERAGE_CFLAGS@
+COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLIB = @DLLIB@
+DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
@@ -130,13 +184,16 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
+GENHTML = @GENHTML@
GPERF = @GPERF@
+GPRBUILD = @GPRBUILD@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LEX = @LEX@
@@ -149,6 +206,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MYSQLCFLAG = @MYSQLCFLAG@
MYSQLCONFIG = @MYSQLCONFIG@
@@ -176,11 +234,13 @@ RANLIB = @RANLIB@
RTLIB = @RTLIB@
RUBY = @RUBY@
RUBYINCLUDE = @RUBYINCLUDE@
+RUBYLIB = @RUBYLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKLIB = @SOCKLIB@
STRIP = @STRIP@
+UNWINDLIB = @UNWINDLIB@
VERSION = @VERSION@
YACC = @YACC@
YFLAGS = @YFLAGS@
@@ -188,6 +248,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -196,8 +257,6 @@ am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
attest_plugins = @attest_plugins@
-axis2c_CFLAGS = @axis2c_CFLAGS@
-axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -206,14 +265,19 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+charon_natt_port = @charon_natt_port@
+charon_plugins = @charon_plugins@
+charon_udp_port = @charon_udp_port@
clearsilver_LIBS = @clearsilver_LIBS@
+cmd_plugins = @cmd_plugins@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
-default_pkcs11 = @default_pkcs11@
+dev_headers = @dev_headers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
+fips_mode = @fips_mode@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
h_plugins = @h_plugins@
@@ -227,17 +291,17 @@ imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
+ipsec_script = @ipsec_script@
+ipsec_script_upper = @ipsec_script_upper@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
-libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
libexecdir = @libexecdir@
linux_headers = @linux_headers@
localedir = @localedir@
localstatedir = @localstatedir@
-lt_ECHO = @lt_ECHO@
maemo_CFLAGS = @maemo_CFLAGS@
maemo_LIBS = @maemo_LIBS@
manager_plugins = @manager_plugins@
@@ -247,16 +311,15 @@ mkdir_p = @mkdir_p@
nm_CFLAGS = @nm_CFLAGS@
nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
+nm_plugins = @nm_plugins@
oldincludedir = @oldincludedir@
openac_plugins = @openac_plugins@
-p_plugins = @p_plugins@
pcsclite_CFLAGS = @pcsclite_CFLAGS@
pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
piddir = @piddir@
pki_plugins = @pki_plugins@
plugindir = @plugindir@
-pluto_plugins = @pluto_plugins@
pool_plugins = @pool_plugins@
prefix = @prefix@
program_transform_name = @program_transform_name@
@@ -284,13 +347,16 @@ top_srcdir = @top_srcdir@
urandom_device = @urandom_device@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
-INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/stroke
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon \
+ -I$(top_srcdir)/src/stroke \
+ -DIPSEC_CONFDIR=\"${sysconfdir}\" \
+ -DIPSEC_PIDDIR=\"${piddir}\"
AM_CFLAGS = \
--rdynamic \
--DIPSEC_CONFDIR=\"${sysconfdir}\" \
--DIPSEC_PIDDIR=\"${piddir}\"
+ -rdynamic
@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-stroke.la
@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-stroke.la
@@ -302,6 +368,8 @@ libstrongswan_stroke_la_SOURCES = \
stroke_cred.h stroke_cred.c \
stroke_ca.h stroke_ca.c \
stroke_attribute.h stroke_attribute.c \
+ stroke_handler.h stroke_handler.c \
+ stroke_counter.h stroke_counter.c \
stroke_list.h stroke_list.c
libstrongswan_stroke_la_LDFLAGS = -module -avoid-version
@@ -350,7 +418,6 @@ clean-noinstLTLIBRARIES:
done
install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
@$(NORMAL_INSTALL)
- test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
@list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
@@ -358,6 +425,8 @@ install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
else :; fi; \
done; \
test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
}
@@ -379,8 +448,8 @@ clean-pluginLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libstrongswan-stroke.la: $(libstrongswan_stroke_la_OBJECTS) $(libstrongswan_stroke_la_DEPENDENCIES)
- $(libstrongswan_stroke_la_LINK) $(am_libstrongswan_stroke_la_rpath) $(libstrongswan_stroke_la_OBJECTS) $(libstrongswan_stroke_la_LIBADD) $(LIBS)
+libstrongswan-stroke.la: $(libstrongswan_stroke_la_OBJECTS) $(libstrongswan_stroke_la_DEPENDENCIES) $(EXTRA_libstrongswan_stroke_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libstrongswan_stroke_la_LINK) $(am_libstrongswan_stroke_la_rpath) $(libstrongswan_stroke_la_OBJECTS) $(libstrongswan_stroke_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -392,31 +461,33 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_ca.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_config.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_counter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_cred.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_handler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_list.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_socket.Plo@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
-@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
@@ -523,10 +594,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
mostlyclean-generic:
clean-generic:
diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c
index 1e4615e12..0f3c38986 100644
--- a/src/libcharon/plugins/stroke/stroke_attribute.c
+++ b/src/libcharon/plugins/stroke/stroke_attribute.c
@@ -17,8 +17,7 @@
#include "stroke_attribute.h"
#include <daemon.h>
-#include <attributes/mem_pool.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <threading/rwlock.h>
typedef struct private_stroke_attribute_t private_stroke_attribute_t;
@@ -39,12 +38,37 @@ struct private_stroke_attribute_t {
linked_list_t *pools;
/**
+ * List of connection specific attributes, as attributes_t
+ */
+ linked_list_t *attrs;
+
+ /**
* rwlock to lock access to pools
*/
rwlock_t *lock;
};
/**
+ * Attributes assigned to a connection
+ */
+typedef struct {
+ /** name of the connection */
+ char *name;
+ /** list of DNS attributes, as host_t */
+ linked_list_t *dns;
+} attributes_t;
+
+/**
+ * Destroy an attributes_t entry
+ */
+static void attributes_destroy(attributes_t *this)
+{
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this->name);
+ free(this);
+}
+
+/**
* find a pool by name
*/
static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
@@ -65,88 +89,246 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
return found;
}
-METHOD(attribute_provider_t, acquire_address, host_t*,
- private_stroke_attribute_t *this, char *name, identification_t *id,
- host_t *requested)
+/**
+ * Find an existing or not yet existing lease
+ */
+static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
+ identification_t *id, host_t *requested,
+ mem_pool_op_t operation)
{
- mem_pool_t *pool;
host_t *addr = NULL;
+ enumerator_t *enumerator;
+ mem_pool_t *pool;
+ char *name;
+
+ enumerator = pools->create_enumerator(pools);
+ while (enumerator->enumerate(enumerator, &name))
+ {
+ pool = find_pool(this, name);
+ if (pool)
+ {
+ addr = pool->acquire_address(pool, id, requested, operation);
+ if (addr)
+ {
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return addr;
+}
+
+METHOD(attribute_provider_t, acquire_address, host_t*,
+ private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
+ host_t *requested)
+{
+ host_t *addr;
+
this->lock->read_lock(this->lock);
- pool = find_pool(this, name);
- if (pool)
+
+ addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING);
+ if (!addr)
{
- addr = pool->acquire_address(pool, id, requested);
+ addr = find_addr(this, pools, id, requested, MEM_POOL_NEW);
+ if (!addr)
+ {
+ addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN);
+ }
}
+
this->lock->unlock(this->lock);
+
return addr;
}
METHOD(attribute_provider_t, release_address, bool,
- private_stroke_attribute_t *this, char *name, host_t *address,
- identification_t *id)
+ private_stroke_attribute_t *this, linked_list_t *pools, host_t *address,
+ identification_t *id)
{
+ enumerator_t *enumerator;
mem_pool_t *pool;
bool found = FALSE;
+ char *name;
+
+ enumerator = pools->create_enumerator(pools);
this->lock->read_lock(this->lock);
- pool = find_pool(this, name);
- if (pool)
+ while (enumerator->enumerate(enumerator, &name))
{
- found = pool->release_address(pool, address, id);
+ pool = find_pool(this, name);
+ if (pool)
+ {
+ found = pool->release_address(pool, address, id);
+ if (found)
+ {
+ break;
+ }
+ }
}
this->lock->unlock(this->lock);
+ enumerator->destroy(enumerator);
+
return found;
}
-METHOD(stroke_attribute_t, add_pool, void,
- private_stroke_attribute_t *this, stroke_msg_t *msg)
+/**
+ * Filter function to convert host to DNS configuration attributes
+ */
+static bool attr_filter(void *lock, host_t **in,
+ configuration_attribute_type_t *type,
+ void *dummy, chunk_t *data)
{
- if (msg->add_conn.other.sourceip_mask)
+ host_t *host = *in;
+
+ switch (host->get_family(host))
{
- mem_pool_t *pool;
- host_t *base = NULL;
- u_int32_t bits = 0;
+ case AF_INET:
+ *type = INTERNAL_IP4_DNS;
+ break;
+ case AF_INET6:
+ *type = INTERNAL_IP6_DNS;
+ break;
+ default:
+ return FALSE;
+ }
+ *data = host->get_address(host);
+ return TRUE;
+}
+
+METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
+ private_stroke_attribute_t *this, linked_list_t *pools,
+ identification_t *id, linked_list_t *vips)
+{
+ ike_sa_t *ike_sa;
+ peer_cfg_t *peer_cfg;
+ enumerator_t *enumerator;
+ attributes_t *attr;
- /* if %config, add an empty pool, otherwise */
- if (msg->add_conn.other.sourceip)
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ this->lock->read_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
{
- DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
- msg->add_conn.name, msg->add_conn.other.sourceip,
- msg->add_conn.other.sourceip_mask);
- base = host_create_from_string(msg->add_conn.other.sourceip, 0);
- if (!base)
+ if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
{
- DBG1(DBG_CFG, "virtual IP address invalid, discarded");
- return;
+ enumerator->destroy(enumerator);
+ return enumerator_create_filter(
+ attr->dns->create_enumerator(attr->dns),
+ (void*)attr_filter, this->lock,
+ (void*)this->lock->unlock);
}
- bits = msg->add_conn.other.sourceip_mask;
}
- pool = mem_pool_create(msg->add_conn.name, base, bits);
- DESTROY_IF(base);
-
- this->lock->write_lock(this->lock);
- this->pools->insert_last(this->pools, pool);
+ enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
+ return enumerator_create_empty();
}
-METHOD(stroke_attribute_t, del_pool, void,
- private_stroke_attribute_t *this, stroke_msg_t *msg)
+METHOD(stroke_attribute_t, add_pool, void,
+ private_stroke_attribute_t *this, mem_pool_t *pool)
{
enumerator_t *enumerator;
- mem_pool_t *pool;
+ mem_pool_t *current;
+ host_t *base;
+ int size;
+
+ base = pool->get_base(pool);
+ size = pool->get_size(pool);
this->lock->write_lock(this->lock);
+
enumerator = this->pools->create_enumerator(this->pools);
- while (enumerator->enumerate(enumerator, &pool))
+ while (enumerator->enumerate(enumerator, &current))
{
- if (streq(msg->del_conn.name, pool->get_name(pool)))
+ if (base && current->get_base(current) &&
+ base->ip_equals(base, current->get_base(current)) &&
+ size == current->get_size(current))
{
- this->pools->remove_at(this->pools, enumerator);
+ DBG1(DBG_CFG, "reusing virtual IP address pool %s",
+ current->get_name(current));
pool->destroy(pool);
+ pool = NULL;
break;
}
}
enumerator->destroy(enumerator);
+
+ if (pool)
+ {
+ if (base)
+ {
+ DBG1(DBG_CFG, "adding virtual IP address pool %s",
+ pool->get_name(pool));
+ }
+ this->pools->insert_last(this->pools, pool);
+ }
+
+ this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_attribute_t, add_dns, void,
+ private_stroke_attribute_t *this, stroke_msg_t *msg)
+{
+ if (msg->add_conn.other.dns)
+ {
+ enumerator_t *enumerator;
+ attributes_t *attr = NULL;
+ host_t *host;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.other.dns, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ host = host_create_from_string(token, 0);
+ if (host)
+ {
+ if (!attr)
+ {
+ INIT(attr,
+ .name = strdup(msg->add_conn.name),
+ .dns = linked_list_create(),
+ );
+ }
+ attr->dns->insert_last(attr->dns, host);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (attr)
+ {
+ this->lock->write_lock(this->lock);
+ this->attrs->insert_last(this->attrs, attr);
+ this->lock->unlock(this->lock);
+ }
+ }
+}
+
+METHOD(stroke_attribute_t, del_dns, void,
+ private_stroke_attribute_t *this, stroke_msg_t *msg)
+{
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ this->lock->write_lock(this->lock);
+
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(msg->del_conn.name, attr->name))
+ {
+ this->attrs->remove_at(this->attrs, enumerator);
+ attributes_destroy(attr);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
this->lock->unlock(this->lock);
}
@@ -158,6 +340,11 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
void *d3, u_int *offline)
{
mem_pool_t *pool = *poolp;
+
+ if (pool->get_size(pool) == 0)
+ {
+ return FALSE;
+ }
*name = pool->get_name(pool);
*size = pool->get_size(pool);
*online = pool->get_online(pool);
@@ -166,7 +353,7 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
}
METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
- private_stroke_attribute_t *this)
+ private_stroke_attribute_t *this)
{
this->lock->read_lock(this->lock);
return enumerator_create_filter(this->pools->create_enumerator(this->pools),
@@ -175,7 +362,7 @@ METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
}
METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
- private_stroke_attribute_t *this, char *name)
+ private_stroke_attribute_t *this, char *name)
{
mem_pool_t *pool;
this->lock->read_lock(this->lock);
@@ -190,10 +377,11 @@ METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
}
METHOD(stroke_attribute_t, destroy, void,
- private_stroke_attribute_t *this)
+ private_stroke_attribute_t *this)
{
this->lock->destroy(this->lock);
this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy));
+ this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
free(this);
}
@@ -209,15 +397,17 @@ stroke_attribute_t *stroke_attribute_create()
.provider = {
.acquire_address = _acquire_address,
.release_address = _release_address,
- .create_attribute_enumerator = enumerator_create_empty,
+ .create_attribute_enumerator = _create_attribute_enumerator,
},
.add_pool = _add_pool,
- .del_pool = _del_pool,
+ .add_dns = _add_dns,
+ .del_dns = _del_dns,
.create_pool_enumerator = _create_pool_enumerator,
.create_lease_enumerator = _create_lease_enumerator,
.destroy = _destroy,
},
.pools = linked_list_create(),
+ .attrs = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
diff --git a/src/libcharon/plugins/stroke/stroke_attribute.h b/src/libcharon/plugins/stroke/stroke_attribute.h
index 249a9899b..f1b9d135b 100644
--- a/src/libcharon/plugins/stroke/stroke_attribute.h
+++ b/src/libcharon/plugins/stroke/stroke_attribute.h
@@ -23,6 +23,7 @@
#include <stroke_msg.h>
#include <attributes/attribute_provider.h>
+#include <attributes/mem_pool.h>
typedef struct stroke_attribute_t stroke_attribute_t;
@@ -37,18 +38,28 @@ struct stroke_attribute_t {
attribute_provider_t provider;
/**
- * Add a virtual IP address pool.
+ * Add a memory pool to this virtual IP backend.
*
- * @param msg stroke message
+ * The pool gets owned by the provider, or destroyed if such a pool
+ * is already registered.
+ *
+ * @param pool virtual IP pool to add
+ */
+ void (*add_pool)(stroke_attribute_t *this, mem_pool_t *pool);
+
+ /**
+ * Add connection specific DNS servers.
+ *
+ * @param msg stroke add message
*/
- void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+ void (*add_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
/**
- * Remove a virtual IP address pool.
+ * Remove connection specific DNS servers.
*
- * @param msg stroke message
+ * @param msg stroke del message
*/
- void (*del_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+ void (*del_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
/**
* Create an enumerator over installed pools.
diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c
index bec35a661..f8026875f 100644
--- a/src/libcharon/plugins/stroke/stroke_ca.c
+++ b/src/libcharon/plugins/stroke/stroke_ca.c
@@ -18,7 +18,7 @@
#include "stroke_cred.h"
#include <threading/rwlock.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <crypto/hashers/hasher.h>
#include <daemon.h>
@@ -348,16 +348,18 @@ METHOD(stroke_ca_t, check_for_hash_and_url, void,
enumerator = this->sections->create_enumerator(this->sections);
while (enumerator->enumerate(enumerator, (void**)&section))
{
- if (section->certuribase && cert->issued_by(cert, section->cert))
+ if (section->certuribase && cert->issued_by(cert, section->cert, NULL))
{
chunk_t hash, encoded;
if (cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
{
- hasher->allocate_hash(hasher, encoded, &hash);
- section->hashes->insert_last(section->hashes,
+ if (hasher->allocate_hash(hasher, encoded, &hash))
+ {
+ section->hashes->insert_last(section->hashes,
identification_create_from_encoding(ID_KEY_ID, hash));
- chunk_free(&hash);
+ chunk_free(&hash);
+ }
chunk_free(&encoded);
}
break;
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index 483e3d253..079e65f11 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -21,6 +21,8 @@
#include <threading/mutex.h>
#include <utils/lexparser.h>
+#include <netdb.h>
+
typedef struct private_stroke_config_t private_stroke_config_t;
/**
@@ -52,6 +54,11 @@ struct private_stroke_config_t {
* credentials
*/
stroke_cred_t *cred;
+
+ /**
+ * Virtual IP pool / DNS backend
+ */
+ stroke_attribute_t *attributes;
};
METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
@@ -186,48 +193,51 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
{
stroke_end_t tmp_end;
ike_cfg_t *ike_cfg;
- char *interface;
host_t *host;
+ u_int16_t ikeport;
host = host_create_from_dns(msg->add_conn.other.address, 0, 0);
if (host)
{
- interface = hydra->kernel_interface->get_interface(
- hydra->kernel_interface, host);
- host->destroy(host);
- if (interface)
+ if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
+ host, NULL))
{
DBG2(DBG_CFG, "left is other host, swapping ends");
tmp_end = msg->add_conn.me;
msg->add_conn.me = msg->add_conn.other;
msg->add_conn.other = tmp_end;
- free(interface);
+ host->destroy(host);
}
else
{
+ host->destroy(host);
host = host_create_from_dns(msg->add_conn.me.address, 0, 0);
if (host)
{
- interface = hydra->kernel_interface->get_interface(
- hydra->kernel_interface, host);
- host->destroy(host);
- if (!interface)
+ if (!hydra->kernel_interface->get_interface(
+ hydra->kernel_interface, host, NULL))
{
DBG1(DBG_CFG, "left nor right host is our side, "
"assuming left=local");
}
- else
- {
- free(interface);
- }
-
+ host->destroy(host);
}
}
}
- ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
- msg->add_conn.force_encap,
- msg->add_conn.me.address, msg->add_conn.me.ikeport,
- msg->add_conn.other.address, msg->add_conn.other.ikeport);
+ ikeport = msg->add_conn.me.ikeport;
+ ikeport = (ikeport == IKEV2_UDP_PORT) ?
+ charon->socket->get_port(charon->socket, FALSE) : ikeport;
+ ike_cfg = ike_cfg_create(msg->add_conn.version,
+ msg->add_conn.other.sendcert != CERT_NEVER_SEND,
+ msg->add_conn.force_encap,
+ msg->add_conn.me.address,
+ msg->add_conn.me.allow_any,
+ ikeport,
+ msg->add_conn.other.address,
+ msg->add_conn.other.allow_any,
+ msg->add_conn.other.ikeport,
+ msg->add_conn.fragmentation,
+ msg->add_conn.ikedscp);
add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
return ike_cfg;
}
@@ -257,6 +267,103 @@ static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
}
/**
+ * Parse public key / signature strength constraints
+ */
+static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
+{
+ enumerator_t *enumerator;
+ bool rsa = FALSE, ecdsa = FALSE, rsa_len = FALSE, ecdsa_len = FALSE;
+ int strength;
+ char *token;
+
+ enumerator = enumerator_create_token(auth, "-", "");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ bool found = FALSE;
+ int i;
+ struct {
+ char *name;
+ signature_scheme_t scheme;
+ key_type_t key;
+ } schemes[] = {
+ { "md5", SIGN_RSA_EMSA_PKCS1_MD5, KEY_RSA, },
+ { "sha1", SIGN_RSA_EMSA_PKCS1_SHA1, KEY_RSA, },
+ { "sha224", SIGN_RSA_EMSA_PKCS1_SHA224, KEY_RSA, },
+ { "sha256", SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, },
+ { "sha384", SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, },
+ { "sha512", SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, },
+ { "sha1", SIGN_ECDSA_WITH_SHA1_DER, KEY_ECDSA, },
+ { "sha256", SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, },
+ { "sha384", SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, },
+ { "sha512", SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, },
+ { "sha256", SIGN_ECDSA_256, KEY_ECDSA, },
+ { "sha384", SIGN_ECDSA_384, KEY_ECDSA, },
+ { "sha512", SIGN_ECDSA_521, KEY_ECDSA, },
+ };
+
+ if (rsa_len || ecdsa_len)
+ { /* expecting a key strength token */
+ strength = atoi(token);
+ if (strength)
+ {
+ if (rsa_len)
+ {
+ cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
+ }
+ else if (ecdsa_len)
+ {
+ cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
+ }
+ }
+ rsa_len = ecdsa_len = FALSE;
+ if (strength)
+ {
+ continue;
+ }
+ }
+ if (streq(token, "rsa"))
+ {
+ rsa = rsa_len = TRUE;
+ continue;
+ }
+ if (streq(token, "ecdsa"))
+ {
+ ecdsa = ecdsa_len = TRUE;
+ continue;
+ }
+ if (streq(token, "pubkey"))
+ {
+ continue;
+ }
+
+ for (i = 0; i < countof(schemes); i++)
+ {
+ if (streq(schemes[i].name, token))
+ {
+ /* for each matching string, allow the scheme, if:
+ * - it is an RSA scheme, and we enforced RSA
+ * - it is an ECDSA scheme, and we enforced ECDSA
+ * - it is not a key type specific scheme
+ */
+ if ((rsa && schemes[i].key == KEY_RSA) ||
+ (ecdsa && schemes[i].key == KEY_ECDSA) ||
+ (!rsa && !ecdsa))
+ {
+ cfg->add(cfg, AUTH_RULE_SIGNATURE_SCHEME,
+ (uintptr_t)schemes[i].scheme);
+ }
+ found = TRUE;
+ }
+ }
+ if (!found)
+ {
+ DBG1(DBG_CFG, "ignoring invalid auth token: '%s'", token);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
* build authentication config
*/
static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
@@ -264,10 +371,10 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
{
identification_t *identity;
certificate_t *certificate;
- char *auth, *id, *pubkey, *cert, *ca;
+ char *auth, *id, *pubkey, *cert, *ca, *groups;
stroke_end_t *end, *other_end;
auth_cfg_t *cfg;
- char eap_buf[32];
+ bool loose = FALSE;
/* select strings */
if (local)
@@ -310,52 +417,17 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
ca = other_end->ca2;
}
}
+ if (id && *id == '%' && !streq(id, "%any") && !streq(id, "%any6"))
+ { /* has only an effect on rightid/2 */
+ loose = !local;
+ id++;
+ }
if (!auth)
{
if (primary)
{
- if (local)
- { /* "leftauth" not defined, fall back to deprecated "authby" */
- switch (msg->add_conn.auth_method)
- {
- default:
- case AUTH_CLASS_PUBKEY:
- auth = "pubkey";
- break;
- case AUTH_CLASS_PSK:
- auth = "psk";
- break;
- case AUTH_CLASS_EAP:
- auth = "eap";
- break;
- case AUTH_CLASS_ANY:
- auth = "any";
- break;
- }
- }
- else
- { /* "rightauth" not defined, fall back to deprecated "eap" */
- if (msg->add_conn.eap_type)
- {
- if (msg->add_conn.eap_vendor)
- {
- snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d",
- msg->add_conn.eap_type,
- msg->add_conn.eap_vendor);
- }
- else
- {
- snprintf(eap_buf, sizeof(eap_buf), "eap-%d",
- msg->add_conn.eap_type);
- }
- auth = eap_buf;
- }
- else
- { /* not EAP => no constraints for this peer */
- auth = "any";
- }
- }
+ auth = "pubkey";
}
else
{ /* no second authentication round, fine. But load certificates
@@ -374,43 +446,69 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
cfg = auth_cfg_create();
- /* add identity and peer certifcate */
+ /* add identity and peer certificate */
identity = identification_create_from_string(id);
if (cert)
{
- certificate = this->cred->load_peer(this->cred, cert);
- if (certificate)
+ enumerator_t *enumerator;
+ bool has_subject = FALSE;
+ certificate_t *first = NULL;
+
+ enumerator = enumerator_create_token(cert, ",", " ");
+ while (enumerator->enumerate(enumerator, &cert))
{
- if (local)
- {
- this->ca->check_for_hash_and_url(this->ca, certificate);
- }
- cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
- if (identity->get_type(identity) == ID_ANY ||
- !certificate->has_subject(certificate, identity))
+ certificate = this->cred->load_peer(this->cred, cert);
+ if (certificate)
{
- DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
- "defaulting to '%Y'", identity,
- certificate->get_subject(certificate));
- identity->destroy(identity);
- identity = certificate->get_subject(certificate);
- identity = identity->clone(identity);
+ if (local)
+ {
+ this->ca->check_for_hash_and_url(this->ca, certificate);
+ }
+ cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
+ if (!first)
+ {
+ first = certificate;
+ }
+ if (identity->get_type(identity) != ID_ANY &&
+ certificate->has_subject(certificate, identity))
+ {
+ has_subject = TRUE;
+ }
}
}
- }
- cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
+ enumerator->destroy(enumerator);
+ if (first && !has_subject)
+ {
+ DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
+ "defaulting to '%Y'", identity, first->get_subject(first));
+ identity->destroy(identity);
+ identity = first->get_subject(first);
+ identity = identity->clone(identity);
+ }
+ }
/* add raw RSA public key */
pubkey = end->rsakey;
if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
{
- certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey,
- identity);
+ certificate = this->cred->load_pubkey(this->cred, pubkey, identity);
if (certificate)
{
cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
}
}
+ if (identity->get_type(identity) != ID_ANY)
+ {
+ cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
+ if (loose)
+ {
+ cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE);
+ }
+ }
+ else
+ {
+ identity->destroy(identity);
+ }
/* CA constraint */
if (ca)
@@ -431,12 +529,13 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
/* groups */
- if (end->groups)
+ groups = primary ? end->groups : end->groups2;
+ if (groups)
{
enumerator_t *enumerator;
char *group;
- enumerator = enumerator_create_token(end->groups, ",", " ");
+ enumerator = enumerator_create_token(groups, ",", " ");
while (enumerator->enumerate(enumerator, &group))
{
cfg->add(cfg, AUTH_RULE_GROUP,
@@ -460,75 +559,51 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
/* authentication metod (class, actually) */
- if (streq(auth, "pubkey") ||
- strneq(auth, "rsa", strlen("rsa")) ||
- strneq(auth, "ecdsa", strlen("ecdsa")))
+ if (strpfx(auth, "pubkey") ||
+ strpfx(auth, "rsa") ||
+ strpfx(auth, "ecdsa"))
{
- u_int strength;
-
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
build_crl_policy(cfg, local, msg->add_conn.crl_policy);
- if (sscanf(auth, "rsa-%d", &strength) == 1)
- {
- cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
- }
- if (sscanf(auth, "ecdsa-%d", &strength) == 1)
- {
- cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
- }
+ parse_pubkey_constraints(auth, cfg);
}
else if (streq(auth, "psk") || streq(auth, "secret"))
{
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
}
- else if (strneq(auth, "eap", 3))
+ else if (strpfx(auth, "xauth"))
{
- enumerator_t *enumerator;
- char *str;
- int i = 0, type = 0, vendor;
+ char *pos;
+
+ pos = strchr(auth, '-');
+ if (pos)
+ {
+ cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
+ }
+ cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
+ if (msg->add_conn.xauth_identity)
+ {
+ cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
+ identification_create_from_string(msg->add_conn.xauth_identity));
+ }
+ }
+ else if (strpfx(auth, "eap"))
+ {
+ eap_vendor_type_t *type;
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
- /* parse EAP string, format: eap[-type[-vendor]] */
- enumerator = enumerator_create_token(auth, "-", " ");
- while (enumerator->enumerate(enumerator, &str))
+ type = eap_vendor_type_from_string(auth);
+ if (type)
{
- switch (i)
+ cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
+ if (type->vendor)
{
- case 1:
- type = eap_type_from_string(str);
- if (!type)
- {
- type = atoi(str);
- if (!type)
- {
- DBG1(DBG_CFG, "unknown EAP method: %s", str);
- break;
- }
- }
- cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
- break;
- case 2:
- if (type)
- {
- vendor = atoi(str);
- if (vendor)
- {
- cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
- }
- else
- {
- DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
- }
- }
- break;
- default:
- break;
+ cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
}
- i++;
+ free(type);
}
- enumerator->destroy(enumerator);
if (msg->add_conn.eap_identity)
{
@@ -570,7 +645,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
{
identification_t *peer_id = NULL;
peer_cfg_t *mediated_by = NULL;
- host_t *vip = NULL;
unique_policy_t unique;
u_int32_t rekey = 0, reauth = 0, over, jitter;
peer_cfg_t *peer_cfg;
@@ -629,38 +703,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
{
rekey = msg->add_conn.rekey.ike_lifetime - over;
}
- if (msg->add_conn.me.sourceip_mask)
- {
- if (msg->add_conn.me.sourceip)
- {
- vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
- }
- if (!vip)
- { /* if it is set to something like %poolname, request an address */
- if (msg->add_conn.me.subnets)
- { /* use the same address as in subnet, if any */
- if (strchr(msg->add_conn.me.subnets, '.'))
- {
- vip = host_create_any(AF_INET);
- }
- else
- {
- vip = host_create_any(AF_INET6);
- }
- }
- else
- {
- if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
- {
- vip = host_create_any(AF_INET6);
- }
- else
- {
- vip = host_create_any(AF_INET);
- }
- }
- }
- }
switch (msg->add_conn.unique)
{
case 1: /* yes */
@@ -670,6 +712,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
case 3: /* keep */
unique = UNIQUE_KEEP;
break;
+ case 4: /* never */
+ unique = UNIQUE_NEVER;
+ break;
default: /* no */
unique = UNIQUE_NO;
break;
@@ -682,15 +727,131 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
/* other.sourceip is managed in stroke_attributes. If it is set, we define
* the pool name as the connection name, which the attribute provider
* uses to serve pool addresses. */
- peer_cfg = peer_cfg_create(msg->add_conn.name,
- msg->add_conn.ikev2 ? 2 : 1, ike_cfg,
+ peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg,
msg->add_conn.me.sendcert, unique,
msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
- msg->add_conn.mobike, msg->add_conn.dpd.delay,
- vip, msg->add_conn.other.sourceip_mask ?
- msg->add_conn.name : msg->add_conn.other.sourceip,
+ msg->add_conn.mobike, msg->add_conn.aggressive,
+ msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
msg->add_conn.ikeme.mediation, mediated_by, peer_id);
+ if (msg->add_conn.other.sourceip)
+ {
+ enumerator_t *enumerator;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
+ ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+ streq(token, "%config") || streq(token, "%cfg") ||
+ streq(token, "%config4") || streq(token, "%config6"))
+ {
+ /* empty pool, uses connection name */
+ this->attributes->add_pool(this->attributes,
+ mem_pool_create(msg->add_conn.name, NULL, 0));
+ peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
+ }
+ else if (*token == '%')
+ {
+ /* external named pool */
+ peer_cfg->add_pool(peer_cfg, token + 1);
+ }
+ else
+ {
+ /* in-memory pool, named using CIDR notation */
+ host_t *base;
+ int bits;
+
+ base = host_create_from_subnet(token, &bits);
+ if (base)
+ {
+ this->attributes->add_pool(this->attributes,
+ mem_pool_create(token, base, bits));
+ peer_cfg->add_pool(peer_cfg, token);
+ base->destroy(base);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+
+ if (msg->add_conn.me.sourceip)
+ {
+ enumerator_t *enumerator;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ host_t *vip = NULL;
+
+ if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+ streq(token, "%config") || streq(token, "%cfg"))
+ { /* try to deduce an address family */
+ if (msg->add_conn.me.subnets)
+ { /* use the same family as in local subnet, if any */
+ if (strchr(msg->add_conn.me.subnets, '.'))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ }
+ else if (msg->add_conn.other.subnets)
+ { /* use the same family as in remote subnet, if any */
+ if (strchr(msg->add_conn.other.subnets, '.'))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ }
+ else
+ {
+ if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET);
+ }
+ }
+ }
+ else if (streq(token, "%config4"))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else if (streq(token, "%config6"))
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ else
+ {
+ vip = host_create_from_string(token, 0);
+ if (vip)
+ {
+ DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
+ }
+ }
+
+ if (vip)
+ {
+ peer_cfg->add_virtual_ip(peer_cfg, vip);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+
/* build leftauth= */
auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
if (auth_cfg)
@@ -724,6 +885,96 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
}
/**
+ * Parse a protoport specifier
+ */
+static bool parse_protoport(char *token, u_int16_t *from_port,
+ u_int16_t *to_port, u_int8_t *protocol)
+{
+ char *sep, *port = "", *endptr;
+ struct protoent *proto;
+ struct servent *svc;
+ long int p;
+
+ sep = strrchr(token, ']');
+ if (!sep)
+ {
+ return FALSE;
+ }
+ *sep = '\0';
+
+ sep = strchr(token, '/');
+ if (sep)
+ { /* protocol/port */
+ *sep = '\0';
+ port = sep + 1;
+ }
+
+ if (streq(token, "%any"))
+ {
+ *protocol = 0;
+ }
+ else
+ {
+ proto = getprotobyname(token);
+ if (proto)
+ {
+ *protocol = proto->p_proto;
+ }
+ else
+ {
+ p = strtol(token, &endptr, 0);
+ if ((*token && *endptr) || p < 0 || p > 0xff)
+ {
+ return FALSE;
+ }
+ *protocol = (u_int8_t)p;
+ }
+ }
+ if (streq(port, "%any"))
+ {
+ *from_port = 0;
+ *to_port = 0xffff;
+ }
+ else if (streq(port, "%opaque"))
+ {
+ *from_port = 0xffff;
+ *to_port = 0;
+ }
+ else if (*port)
+ {
+ svc = getservbyname(port, NULL);
+ if (svc)
+ {
+ *from_port = *to_port = ntohs(svc->s_port);
+ }
+ else
+ {
+ p = strtol(port, &endptr, 0);
+ if (p < 0 || p > 0xffff)
+ {
+ return FALSE;
+ }
+ *from_port = p;
+ if (*endptr == '-')
+ {
+ port = endptr + 1;
+ p = strtol(port, &endptr, 0);
+ if (p < 0 || p > 0xffff)
+ {
+ return FALSE;
+ }
+ }
+ *to_port = p;
+ if (*endptr)
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/**
* build a traffic selector from a stroke_end
*/
static void add_ts(private_stroke_config_t *this,
@@ -734,58 +985,68 @@ static void add_ts(private_stroke_config_t *this,
if (end->tohost)
{
ts = traffic_selector_create_dynamic(end->protocol,
- end->port ? end->port : 0, end->port ? end->port : 65535);
+ end->from_port, end->to_port);
child_cfg->add_traffic_selector(child_cfg, local, ts);
}
else
{
- host_t *net;
-
if (!end->subnets)
{
+ host_t *net;
+
net = host_create_from_string(end->address, 0);
if (net)
{
ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
- end->port);
+ end->from_port, end->to_port);
child_cfg->add_traffic_selector(child_cfg, local, ts);
}
}
else
{
- char *del, *start, *bits;
+ enumerator_t *enumerator;
+ char *subnet, *pos;
+ u_int16_t from_port, to_port;
+ u_int8_t proto;
- start = end->subnets;
- do
+ enumerator = enumerator_create_token(end->subnets, ",", " ");
+ while (enumerator->enumerate(enumerator, &subnet))
{
- int intbits = 0;
+ from_port = end->from_port;
+ to_port = end->to_port;
+ proto = end->protocol;
- del = strchr(start, ',');
- if (del)
+ pos = strchr(subnet, '[');
+ if (pos)
{
- *del = '\0';
+ *(pos++) = '\0';
+ if (!parse_protoport(pos, &from_port, &to_port, &proto))
+ {
+ DBG1(DBG_CFG, "invalid proto/port: %s, skipped subnet",
+ pos);
+ continue;
+ }
}
- bits = strchr(start, '/');
- if (bits)
+ if (streq(subnet, "%dynamic"))
{
- *bits = '\0';
- intbits = atoi(bits + 1);
+ ts = traffic_selector_create_dynamic(proto,
+ from_port, to_port);
}
-
- net = host_create_from_string(start, 0);
- if (net)
+ else
+ {
+ ts = traffic_selector_create_from_cidr(subnet, proto,
+ from_port, to_port);
+ }
+ if (ts)
{
- ts = traffic_selector_create_from_subnet(net, intbits,
- end->protocol, end->port);
child_cfg->add_traffic_selector(child_cfg, local, ts);
}
else
{
- DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
+ DBG1(DBG_CFG, "invalid subnet: %s, skipped", subnet);
}
- start = del + 1;
}
- while (del);
+ enumerator->destroy(enumerator);
}
}
}
@@ -1029,8 +1290,8 @@ METHOD(stroke_config_t, set_user_credentials, void,
return;
}
- /* replace/set the username in the first EAP auth_cfg, also look for a
- * suitable remote ID.
+ /* replace/set the username in the first EAP/XAuth auth_cfg, also look for
+ * a suitable remote ID.
* note that adding the identity here is not fully thread-safe as the
* peer_cfg and in turn the auth_cfg could be in use. for the default use
* case (setting user credentials before upping the connection) this will
@@ -1049,16 +1310,25 @@ METHOD(stroke_config_t, set_user_credentials, void,
}
auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
- if (auth_class == AUTH_CLASS_EAP)
+ if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH)
{
- auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
- /* if aaa_identity is specified use that as remote ID */
- identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
- if (identity && identity->get_type(identity) != ID_ANY)
+ if (auth_class == AUTH_CLASS_EAP)
{
- gw = identity;
+ auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
+ /* if aaa_identity is specified use that as remote ID */
+ identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
+ if (identity && identity->get_type(identity) != ID_ANY)
+ {
+ gw = identity;
+ }
+ DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
+ }
+ else
+ {
+ auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY,
+ id->clone(id));
+ DBG1(DBG_CFG, " configured XAuth username %Y", id);
}
- DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
type = SHARED_EAP;
break;
}
@@ -1149,7 +1419,8 @@ METHOD(stroke_config_t, destroy, void,
/*
* see header file
*/
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+ stroke_attribute_t *attributes)
{
private_stroke_config_t *this;
@@ -1169,8 +1440,8 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
.mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
.ca = ca,
.cred = cred,
+ .attributes = attributes,
);
return &this->public;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h
index 450d517f3..894e03ce4 100644
--- a/src/libcharon/plugins/stroke/stroke_config.h
+++ b/src/libcharon/plugins/stroke/stroke_config.h
@@ -26,6 +26,7 @@
#include <stroke_msg.h>
#include "stroke_ca.h"
#include "stroke_cred.h"
+#include "stroke_attribute.h"
typedef struct stroke_config_t stroke_config_t;
@@ -71,6 +72,7 @@ struct stroke_config_t {
/**
* Create a stroke_config instance.
*/
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred);
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+ stroke_attribute_t *attributes);
#endif /** STROKE_CONFIG_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index 729e9d757..fdd1635a6 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -33,6 +33,11 @@ struct private_stroke_control_t {
* public functions
*/
stroke_control_t public;
+
+ /**
+ * Timeout for stroke commands, im ms
+ */
+ u_int timeout;
};
@@ -58,11 +63,11 @@ struct stroke_log_info_t {
* logging to the stroke interface
*/
static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
- ike_sa_t *ike_sa, char *format, va_list args)
+ ike_sa_t *ike_sa, char *message)
{
if (level <= info->level)
{
- if (vfprintf(info->out, format, args) < 0 ||
+ if (fprintf(info->out, "%s", message) < 0 ||
fprintf(info->out, "\n") < 0 ||
fflush(info->out) != 0)
{
@@ -97,8 +102,8 @@ static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
/**
* call the charon controller to initiate the connection
*/
-static void charon_initiate(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
- stroke_msg_t *msg, FILE *out)
+static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg,
+ child_cfg_t *child_cfg, stroke_msg_t *msg, FILE *out)
{
if (msg->output_verbosity < 0)
{
@@ -108,9 +113,27 @@ static void charon_initiate(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
else
{
stroke_log_info_t info = { msg->output_verbosity, out };
+ status_t status;
- charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->initiate(charon->controller,
+ peer_cfg, child_cfg, (controller_cb_t)stroke_log,
+ &info, this->timeout);
+ switch (status)
+ {
+ case SUCCESS:
+ fprintf(out, "connection '%s' established successfully\n",
+ msg->initiate.name);
+ break;
+ case OUT_OF_RES:
+ fprintf(out, "connection '%s' not established after %dms, "
+ "detaching\n", msg->initiate.name, this->timeout);
+ break;
+ default:
+ case FAILED:
+ fprintf(out, "establishing connection '%s' failed\n",
+ msg->initiate.name);
+ break;
+ }
}
}
@@ -126,14 +149,6 @@ METHOD(stroke_control_t, initiate, void,
msg->initiate.name);
if (peer_cfg)
{
- if (peer_cfg->get_ike_version(peer_cfg) != 2)
- {
- DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
- peer_cfg->get_ike_version(peer_cfg));
- peer_cfg->destroy(peer_cfg);
- return;
- }
-
child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
if (child_cfg == NULL)
{
@@ -141,7 +156,7 @@ METHOD(stroke_control_t, initiate, void,
while (enumerator->enumerate(enumerator, &child_cfg))
{
empty = FALSE;
- charon_initiate(peer_cfg->get_ref(peer_cfg),
+ charon_initiate(this, peer_cfg->get_ref(peer_cfg),
child_cfg->get_ref(child_cfg), msg, out);
}
enumerator->destroy(enumerator);
@@ -157,14 +172,10 @@ METHOD(stroke_control_t, initiate, void,
}
else
{
- enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
- NULL, NULL, NULL, NULL);
+ enumerator = charon->backends->create_peer_cfg_enumerator(
+ charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
while (enumerator->enumerate(enumerator, &peer_cfg))
{
- if (peer_cfg->get_ike_version(peer_cfg) != 2)
- {
- continue;
- }
child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
if (child_cfg)
{
@@ -181,7 +192,7 @@ METHOD(stroke_control_t, initiate, void,
return;
}
}
- charon_initiate(peer_cfg, child_cfg, msg, out);
+ charon_initiate(this, peer_cfg, child_cfg, msg, out);
}
/**
@@ -251,6 +262,41 @@ static bool parse_specifier(char *string, u_int32_t *id,
return TRUE;
}
+/**
+ * Report the result of a terminate() call to console
+ */
+static void report_terminate_status(private_stroke_control_t *this,
+ status_t status, FILE *out, u_int32_t id, bool child)
+{
+ char *prefix, *postfix;
+
+ if (child)
+ {
+ prefix = "CHILD_SA {";
+ postfix = "}";
+ }
+ else
+ {
+ prefix = "IKE_SA [";
+ postfix = "]";
+ }
+
+ switch (status)
+ {
+ case SUCCESS:
+ fprintf(out, "%s%d%s closed successfully\n", prefix, id, postfix);
+ break;
+ case OUT_OF_RES:
+ fprintf(out, "%s%d%s not closed after %dms, detaching\n",
+ prefix, id, postfix, this->timeout);
+ break;
+ default:
+ case FAILED:
+ fprintf(out, "closing %s%d%s failed\n", prefix, id, postfix);
+ break;
+ }
+}
+
METHOD(stroke_control_t, terminate, void,
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
{
@@ -262,6 +308,7 @@ METHOD(stroke_control_t, terminate, void,
linked_list_t *ike_list, *child_list;
stroke_log_info_t info;
uintptr_t del;
+ status_t status;
if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
{
@@ -276,15 +323,15 @@ METHOD(stroke_control_t, terminate, void,
{
if (child)
{
- charon->controller->terminate_child(charon->controller, id,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->terminate_child(charon->controller, id,
+ (controller_cb_t)stroke_log, &info, this->timeout);
}
else
{
- charon->controller->terminate_ike(charon->controller, id,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->terminate_ike(charon->controller, id,
+ (controller_cb_t)stroke_log, &info, this->timeout);
}
- return;
+ return report_terminate_status(this, status, out, id, child);
}
ike_list = linked_list_create();
@@ -332,16 +379,18 @@ METHOD(stroke_control_t, terminate, void,
enumerator = child_list->create_enumerator(child_list);
while (enumerator->enumerate(enumerator, &del))
{
- charon->controller->terminate_child(charon->controller, del,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->terminate_child(charon->controller, del,
+ (controller_cb_t)stroke_log, &info, this->timeout);
+ report_terminate_status(this, status, out, del, TRUE);
}
enumerator->destroy(enumerator);
enumerator = ike_list->create_enumerator(ike_list);
while (enumerator->enumerate(enumerator, &del))
{
- charon->controller->terminate_ike(charon->controller, del,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->terminate_ike(charon->controller, del,
+ (controller_cb_t)stroke_log, &info, this->timeout);
+ report_terminate_status(this, status, out, del, FALSE);
}
enumerator->destroy(enumerator);
@@ -419,10 +468,10 @@ METHOD(stroke_control_t, rekey, void,
METHOD(stroke_control_t, terminate_srcip, void,
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
{
- enumerator_t *enumerator;
+ enumerator_t *enumerator, *vips;
ike_sa_t *ike_sa;
host_t *start = NULL, *end = NULL, *vip;
- chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
+ chunk_t chunk_start, chunk_end = chunk_empty, chunk;
if (msg->terminate_srcip.start)
{
@@ -450,33 +499,40 @@ METHOD(stroke_control_t, terminate_srcip, void,
charon->controller, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa))
{
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (!vip)
- {
- continue;
- }
- if (!end)
+ bool match = FALSE;
+
+ vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
+ while (vips->enumerate(vips, &vip))
{
- if (!vip->ip_equals(vip, start))
+ if (!end)
{
- continue;
+ if (vip->ip_equals(vip, start))
+ {
+ match = TRUE;
+ break;
+ }
}
- }
- else
- {
- chunk_vip = vip->get_address(vip);
- if (chunk_vip.len != chunk_start.len ||
- chunk_vip.len != chunk_end.len ||
- memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
- memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
+ else
{
- continue;
+ chunk = vip->get_address(vip);
+ if (chunk.len == chunk_start.len &&
+ chunk.len == chunk_end.len &&
+ memcmp(chunk.ptr, chunk_start.ptr, chunk.len) >= 0 &&
+ memcmp(chunk.ptr, chunk_end.ptr, chunk.len) <= 0)
+ {
+ match = TRUE;
+ break;
+ }
}
}
+ vips->destroy(vips);
- /* schedule delete asynchronously */
- lib->processor->queue_job(lib->processor, (job_t*)
+ if (match)
+ {
+ /* schedule delete asynchronously */
+ lib->processor->queue_job(lib->processor, (job_t*)
delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
+ }
}
enumerator->destroy(enumerator);
start->destroy(start);
@@ -492,6 +548,7 @@ METHOD(stroke_control_t, purge_ike, void,
linked_list_t *list;
uintptr_t del;
stroke_log_info_t info;
+ status_t status;
info.out = out;
info.level = msg->output_verbosity;
@@ -514,8 +571,9 @@ METHOD(stroke_control_t, purge_ike, void,
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &del))
{
- charon->controller->terminate_ike(charon->controller, del,
- (controller_cb_t)stroke_log, &info, 0);
+ status = charon->controller->terminate_ike(charon->controller, del,
+ (controller_cb_t)stroke_log, &info, this->timeout);
+ report_terminate_status(this, status, out, del, TRUE);
}
enumerator->destroy(enumerator);
list->destroy(list);
@@ -545,7 +603,7 @@ static void charon_route(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
}
else
{
- if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
+ if (charon->traps->install(charon->traps, peer_cfg, child_cfg, 0))
{
fprintf(out, "'%s' routed\n", name);
}
@@ -568,14 +626,6 @@ METHOD(stroke_control_t, route, void,
msg->route.name);
if (peer_cfg)
{
- if (peer_cfg->get_ike_version(peer_cfg) != 2)
- {
- DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
- peer_cfg->get_ike_version(peer_cfg));
- peer_cfg->destroy(peer_cfg);
- return;
- }
-
child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
if (child_cfg == NULL)
{
@@ -599,14 +649,10 @@ METHOD(stroke_control_t, route, void,
}
else
{
- enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
- NULL, NULL, NULL, NULL);
+ enumerator = charon->backends->create_peer_cfg_enumerator(
+ charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
while (enumerator->enumerate(enumerator, &peer_cfg))
{
- if (peer_cfg->get_ike_version(peer_cfg) != 2)
- {
- continue;
- }
child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
if (child_cfg)
{
@@ -687,8 +733,9 @@ stroke_control_t *stroke_control_create()
.unroute = _unroute,
.destroy = _destroy,
},
+ .timeout = lib->settings->get_int(lib->settings,
+ "%s.plugins.stroke.timeout", 0, charon->name),
);
return &this->public;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_counter.c b/src/libcharon/plugins/stroke/stroke_counter.c
new file mode 100644
index 000000000..5fa1fb165
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_counter.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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 "stroke_counter.h"
+
+#include <threading/spinlock.h>
+#include <collections/hashtable.h>
+
+ENUM(stroke_counter_type_names,
+ COUNTER_INIT_IKE_SA_REKEY, COUNTER_OUT_INFORMATIONAL_RSP,
+ "ikeInitRekey",
+ "ikeRspRekey",
+ "ikeChildSaRekey",
+ "ikeInInvalid",
+ "ikeInInvalidSpi",
+ "ikeInInitReq",
+ "ikeInInitRsp",
+ "ikeOutInitReq",
+ "ikeOutInitRsp",
+ "ikeInAuthReq",
+ "ikeInAuthRsp",
+ "ikeOutAuthReq",
+ "ikeOutAuthRsp",
+ "ikeInCrChildReq",
+ "ikeInCrChildRsp",
+ "ikeOutCrChildReq",
+ "ikeOutCrChildRsp",
+ "ikeInInfoReq",
+ "ikeInInfoRsp",
+ "ikeOutInfoReq",
+ "ikeOutInfoRsp",
+);
+
+typedef struct private_stroke_counter_t private_stroke_counter_t;
+
+/**
+ * Private data of an stroke_counter_t object.
+ */
+struct private_stroke_counter_t {
+
+ /**
+ * Public stroke_counter_t interface.
+ */
+ stroke_counter_t public;
+
+ /**
+ * Global counter values
+ */
+ u_int64_t counter[COUNTER_MAX];
+
+ /**
+ * Counters for specific connection names, char* => entry_t
+ */
+ hashtable_t *conns;
+
+ /**
+ * Lock for counter values
+ */
+ spinlock_t *lock;
+};
+
+/**
+ * Counters for a specific connection name
+ */
+typedef struct {
+ /** connection name */
+ char *name;
+ /** counter values for connection */
+ u_int64_t counter[COUNTER_MAX];
+} entry_t;
+
+/**
+ * Destroy named entry
+ */
+static void destroy_entry(entry_t *this)
+{
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(char *name)
+{
+ return chunk_hash(chunk_from_str(name));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(char *a, char *b)
+{
+ return streq(a, b);
+}
+
+/**
+ * Get the name of an IKE_SA, but return NULL if it is not known yet
+ */
+static char *get_ike_sa_name(ike_sa_t *ike_sa)
+{
+ peer_cfg_t *peer_cfg;
+
+ if (ike_sa)
+ {
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ if (peer_cfg)
+ {
+ return peer_cfg->get_name(peer_cfg);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Increase a counter for a named entry
+ */
+static void count_named(private_stroke_counter_t *this,
+ ike_sa_t *ike_sa, stroke_counter_type_t type)
+{
+ entry_t *entry;
+ char *name;
+
+ name = get_ike_sa_name(ike_sa);
+ if (name)
+ {
+ entry = this->conns->get(this->conns, name);
+ if (!entry)
+ {
+ INIT(entry,
+ .name = strdup(name),
+ );
+ this->conns->put(this->conns, entry->name, entry);
+ }
+ entry->counter[type]++;
+ }
+}
+
+METHOD(listener_t, alert, bool,
+ private_stroke_counter_t *this, ike_sa_t *ike_sa,
+ alert_t alert, va_list args)
+{
+ stroke_counter_type_t type;
+
+ switch (alert)
+ {
+ case ALERT_INVALID_IKE_SPI:
+ type = COUNTER_IN_INVALID_IKE_SPI;
+ break;
+ case ALERT_PARSE_ERROR_HEADER:
+ case ALERT_PARSE_ERROR_BODY:
+ type = COUNTER_IN_INVALID;
+ break;
+ default:
+ return TRUE;
+ }
+
+ this->lock->lock(this->lock);
+ this->counter[type]++;
+ count_named(this, ike_sa, type);
+ this->lock->unlock(this->lock);
+
+ return TRUE;
+}
+
+METHOD(listener_t, ike_rekey, bool,
+ private_stroke_counter_t *this, ike_sa_t *old, ike_sa_t *new)
+{
+ stroke_counter_type_t type;
+ ike_sa_id_t *id;
+
+ id = new->get_id(new);
+ if (id->is_initiator(id))
+ {
+ type = COUNTER_INIT_IKE_SA_REKEY;
+ }
+ else
+ {
+ type = COUNTER_RESP_IKE_SA_REKEY;
+ }
+
+ this->lock->lock(this->lock);
+ this->counter[type]++;
+ count_named(this, old, type);
+ this->lock->unlock(this->lock);
+
+ return TRUE;
+}
+
+METHOD(listener_t, child_rekey, bool,
+ private_stroke_counter_t *this, ike_sa_t *ike_sa,
+ child_sa_t *old, child_sa_t *new)
+{
+ this->lock->lock(this->lock);
+ this->counter[COUNTER_CHILD_SA_REKEY]++;
+ count_named(this, ike_sa, COUNTER_CHILD_SA_REKEY);
+ this->lock->unlock(this->lock);
+
+ return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+ private_stroke_counter_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming, bool plain)
+{
+ stroke_counter_type_t type;
+ bool request;
+
+ if ((incoming && !plain) || (!incoming && !plain))
+ { /* handle each message only once */
+ return TRUE;
+ }
+
+ request = message->get_request(message);
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ if (incoming)
+ {
+ type = request ? COUNTER_IN_IKE_SA_INIT_REQ
+ : COUNTER_IN_IKE_SA_INIT_RSP;
+ }
+ else
+ {
+ type = request ? COUNTER_OUT_IKE_SA_INIT_REQ
+ : COUNTER_OUT_IKE_SA_INIT_RES;
+ }
+ break;
+ case IKE_AUTH:
+ if (incoming)
+ {
+ type = request ? COUNTER_IN_IKE_AUTH_REQ
+ : COUNTER_IN_IKE_AUTH_RSP;
+ }
+ else
+ {
+ type = request ? COUNTER_OUT_IKE_AUTH_REQ
+ : COUNTER_OUT_IKE_AUTH_RSP;
+ }
+ break;
+ case CREATE_CHILD_SA:
+ if (incoming)
+ {
+ type = request ? COUNTER_IN_CREATE_CHILD_SA_REQ
+ : COUNTER_IN_CREATE_CHILD_SA_RSP;
+ }
+ else
+ {
+ type = request ? COUNTER_OUT_CREATE_CHILD_SA_REQ
+ : COUNTER_OUT_CREATE_CHILD_SA_RSP;
+ }
+ break;
+ case INFORMATIONAL:
+ if (incoming)
+ {
+ type = request ? COUNTER_IN_INFORMATIONAL_REQ
+ : COUNTER_IN_INFORMATIONAL_RSP;
+ }
+ else
+ {
+ type = request ? COUNTER_OUT_INFORMATIONAL_REQ
+ : COUNTER_OUT_INFORMATIONAL_RSP;
+ }
+ break;
+ default:
+ return TRUE;
+ }
+
+ this->lock->lock(this->lock);
+ this->counter[type]++;
+ count_named(this, ike_sa, type);
+ this->lock->unlock(this->lock);
+
+ return TRUE;
+}
+
+/**
+ * Print a single counter value to out
+ */
+static void print_counter(FILE *out, stroke_counter_type_t type,
+ u_int64_t counter)
+{
+ fprintf(out, "%-18N %12llu\n", stroke_counter_type_names, type, counter);
+}
+
+/**
+ * Print IKE counters for a specific connection
+ */
+static void print_one(private_stroke_counter_t *this, FILE *out, char *name)
+{
+ u_int64_t counter[COUNTER_MAX];
+ entry_t *entry;
+ int i;
+
+ this->lock->lock(this->lock);
+ entry = this->conns->get(this->conns, name);
+ if (entry)
+ {
+ for (i = 0; i < countof(this->counter); i++)
+ {
+ counter[i] = entry->counter[i];
+ }
+ }
+ this->lock->unlock(this->lock);
+
+ if (entry)
+ {
+ fprintf(out, "\nList of IKE counters for '%s':\n\n", name);
+ for (i = 0; i < countof(this->counter); i++)
+ {
+ print_counter(out, i, counter[i]);
+ }
+ }
+ else
+ {
+ fprintf(out, "No IKE counters found for '%s'\n", name);
+ }
+}
+
+/**
+ * Print counters for all connections
+ */
+static void print_all(private_stroke_counter_t *this, FILE *out)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ linked_list_t *list;
+ char *name;
+
+ list = linked_list_create();
+
+ this->lock->lock(this->lock);
+ enumerator = this->conns->create_enumerator(this->conns);
+ while (enumerator->enumerate(enumerator, &name, &entry))
+ {
+ list->insert_last(list, strdup(name));
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &name))
+ {
+ print_one(this, out, name);
+ }
+ enumerator->destroy(enumerator);
+
+ list->destroy_function(list, free);
+}
+
+/**
+ * Print global counters
+ */
+static void print_global(private_stroke_counter_t *this, FILE *out)
+{
+ u_int64_t counter[COUNTER_MAX];
+ int i;
+
+ this->lock->lock(this->lock);
+ for (i = 0; i < countof(this->counter); i++)
+ {
+ counter[i] = this->counter[i];
+ }
+ this->lock->unlock(this->lock);
+
+ fprintf(out, "\nList of IKE counters:\n\n");
+
+ for (i = 0; i < countof(this->counter); i++)
+ {
+ print_counter(out, i, counter[i]);
+ }
+}
+
+METHOD(stroke_counter_t, print, void,
+ private_stroke_counter_t *this, FILE *out, char *name)
+{
+ if (name)
+ {
+ if (streq(name, "all"))
+ {
+ return print_all(this, out);
+ }
+ return print_one(this, out, name);
+ }
+ return print_global(this, out);
+}
+
+METHOD(stroke_counter_t, reset, void,
+ private_stroke_counter_t *this, char *name)
+{
+ this->lock->lock(this->lock);
+ if (name)
+ {
+ entry_t *entry;
+
+ entry = this->conns->remove(this->conns, name);
+ if (entry)
+ {
+ destroy_entry(entry);
+ }
+ }
+ else
+ {
+ memset(&this->counter, 0, sizeof(this->counter));
+ }
+ this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_counter_t, destroy, void,
+ private_stroke_counter_t *this)
+{
+ enumerator_t *enumerator;
+ char *name;
+ entry_t *entry;
+
+ enumerator = this->conns->create_enumerator(this->conns);
+ while (enumerator->enumerate(enumerator, &name, &entry))
+ {
+ destroy_entry(entry);
+ }
+ enumerator->destroy(enumerator);
+ this->conns->destroy(this->conns);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * See header
+ */
+stroke_counter_t *stroke_counter_create()
+{
+ private_stroke_counter_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .alert = _alert,
+ .ike_rekey = _ike_rekey,
+ .child_rekey = _child_rekey,
+ .message = _message_hook,
+ },
+ .print = _print,
+ .reset = _reset,
+ .destroy = _destroy,
+ },
+ .conns = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 4),
+ .lock = spinlock_create(),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/stroke/stroke_counter.h b/src/libcharon/plugins/stroke/stroke_counter.h
new file mode 100644
index 000000000..fecf39f56
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_counter.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup stroke_counter stroke_counter
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_COUNTER_H_
+#define STROKE_COUNTER_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct stroke_counter_t stroke_counter_t;
+typedef enum stroke_counter_type_t stroke_counter_type_t;
+
+enum stroke_counter_type_t {
+ /** initiated IKE_SA rekeyings */
+ COUNTER_INIT_IKE_SA_REKEY,
+ /** responded IKE_SA rekeyings */
+ COUNTER_RESP_IKE_SA_REKEY,
+ /** completed CHILD_SA rekeyings */
+ COUNTER_CHILD_SA_REKEY,
+ /** messages with invalid types, length, or a value out of range */
+ COUNTER_IN_INVALID,
+ /** messages with an invalid IKE SPI */
+ COUNTER_IN_INVALID_IKE_SPI,
+ /** received IKE_SA_INIT requests */
+ COUNTER_IN_IKE_SA_INIT_REQ,
+ /** received IKE_SA_INIT responses */
+ COUNTER_IN_IKE_SA_INIT_RSP,
+ /** sent IKE_SA_INIT requests */
+ COUNTER_OUT_IKE_SA_INIT_REQ,
+ /** sent IKE_SA_INIT responses */
+ COUNTER_OUT_IKE_SA_INIT_RES,
+ /** received IKE_AUTH requests */
+ COUNTER_IN_IKE_AUTH_REQ,
+ /** received IKE_AUTH responses */
+ COUNTER_IN_IKE_AUTH_RSP,
+ /** sent IKE_AUTH requests */
+ COUNTER_OUT_IKE_AUTH_REQ,
+ /** sent IKE_AUTH responses */
+ COUNTER_OUT_IKE_AUTH_RSP,
+ /** received CREATE_CHILD_SA requests */
+ COUNTER_IN_CREATE_CHILD_SA_REQ,
+ /** received CREATE_CHILD_SA responses */
+ COUNTER_IN_CREATE_CHILD_SA_RSP,
+ /** sent CREATE_CHILD_SA requests */
+ COUNTER_OUT_CREATE_CHILD_SA_REQ,
+ /** sent CREATE_CHILD_SA responses */
+ COUNTER_OUT_CREATE_CHILD_SA_RSP,
+ /** received INFORMATIONAL requests */
+ COUNTER_IN_INFORMATIONAL_REQ,
+ /** received INFORMATIONAL responses */
+ COUNTER_IN_INFORMATIONAL_RSP,
+ /** sent INFORMATIONAL requests */
+ COUNTER_OUT_INFORMATIONAL_REQ,
+ /** sent INFORMATIONAL responses */
+ COUNTER_OUT_INFORMATIONAL_RSP,
+ /** number of counter types */
+ COUNTER_MAX
+};
+
+/**
+ * Collection of counter values for different IKE events.
+ */
+struct stroke_counter_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Print counter values to an output stream.
+ *
+ * @param out output stream to write to
+ * @param name connection name to get counters for, NULL for global
+ */
+ void (*print)(stroke_counter_t *this, FILE *out, char *name);
+
+ /**
+ * Reset global or connection specific counters.
+ *
+ * @param name name of connection counters to reset, NULL for global
+ */
+ void (*reset)(stroke_counter_t *this, char *name);
+
+ /**
+ * Destroy a stroke_counter_t.
+ */
+ void (*destroy)(stroke_counter_t *this);
+};
+
+/**
+ * Create a stroke_counter instance.
+ */
+stroke_counter_t *stroke_counter_create();
+
+#endif /** STROKE_COUNTER_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c
index a2a6d6d9f..8d0001271 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.c
+++ b/src/libcharon/plugins/stroke/stroke_cred.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -32,9 +32,10 @@
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h>
+#include <credentials/containers/pkcs12.h>
#include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <utils/lexparser.h>
#include <threading/rwlock.h>
#include <daemon.h>
@@ -72,7 +73,7 @@ struct private_stroke_cred_t {
/**
* ignore missing CA basic constraint (i.e. treat all certificates in
- * ipsec.conf ca sections and ipsec.d/cacert as CA certificates)
+ * ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
*/
bool force_ca_cert;
@@ -82,35 +83,137 @@ struct private_stroke_cred_t {
bool cachecrl;
};
-METHOD(stroke_cred_t, load_ca, certificate_t*,
- private_stroke_cred_t *this, char *filename)
+/** Length of smartcard specifier parts (module, keyid) */
+#define SC_PART_LEN 128
+
+/**
+ * Kind of smartcard specifier token
+ */
+typedef enum {
+ SC_FORMAT_SLOT_MODULE_KEYID,
+ SC_FORMAT_SLOT_KEYID,
+ SC_FORMAT_KEYID,
+ SC_FORMAT_INVALID,
+} smartcard_format_t;
+
+/**
+ * Parse a smartcard specifier token
+ */
+static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
+ char *module, char *keyid)
{
- certificate_t *cert;
- char path[PATH_MAX];
+ /* The token has one of the following three formats:
+ * - %smartcard<slot>@<module>:<keyid>
+ * - %smartcard<slot>:<keyid>
+ * - %smartcard:<keyid>
+ */
+ char buf[2 * SC_PART_LEN], *pos;
- if (*filename == '/')
+ if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
{
- snprintf(path, sizeof(path), "%s", filename);
+ pos = strchr(buf, ':');
+ if (!pos)
+ {
+ return SC_FORMAT_INVALID;
+ }
+ *pos++ = '\0';
+ snprintf(module, SC_PART_LEN, "%s", buf);
+ snprintf(keyid, SC_PART_LEN, "%s", pos);
+ return SC_FORMAT_SLOT_MODULE_KEYID;
}
- else
+ if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
+ {
+ return SC_FORMAT_SLOT_KEYID;
+ }
+ if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
{
- snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+ return SC_FORMAT_KEYID;
}
+ return SC_FORMAT_INVALID;
+}
- if (this->force_ca_cert)
- { /* we treat this certificate as a CA certificate even if it has no
- * CA basic constraint */
- cert = lib->creds->create(lib->creds,
- CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
- BUILD_END);
+/**
+ * Load a credential from a smartcard
+ */
+static certificate_t *load_from_smartcard(smartcard_format_t format,
+ u_int slot, char *module, char *keyid,
+ credential_type_t type, int subtype)
+{
+ chunk_t chunk;
+ void *cred;
+
+ chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
+ switch (format)
+ {
+ case SC_FORMAT_SLOT_MODULE_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_SLOT, slot,
+ BUILD_PKCS11_MODULE, module,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ case SC_FORMAT_SLOT_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_SLOT, slot,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ case SC_FORMAT_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ default:
+ cred = NULL;
+ break;
+ }
+ free(chunk.ptr);
+
+ return cred;
+}
+
+METHOD(stroke_cred_t, load_ca, certificate_t*,
+ private_stroke_cred_t *this, char *filename)
+{
+ certificate_t *cert = NULL;
+ char path[PATH_MAX];
+
+ if (strpfx(filename, "%smartcard"))
+ {
+ smartcard_format_t format;
+ char module[SC_PART_LEN], keyid[SC_PART_LEN];
+ u_int slot;
+
+ format = parse_smartcard(filename, &slot, module, keyid);
+ if (format != SC_FORMAT_INVALID)
+ {
+ cert = (certificate_t*)load_from_smartcard(format,
+ slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
+ }
}
else
{
- cert = lib->creds->create(lib->creds,
- CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, path,
- BUILD_END);
+ if (*filename == '/')
+ {
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+ }
+
+ if (this->force_ca_cert)
+ { /* we treat this certificate as a CA certificate even if it has no
+ * CA basic constraint */
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
+ BUILD_END);
+ }
+ else
+ {
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, path,
+ BUILD_END);
+ }
}
if (cert)
{
@@ -123,6 +226,8 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
cert->destroy(cert);
return NULL;
}
+ DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), filename);
return this->creds->add_cert_ref(this->creds, TRUE, cert);
}
return NULL;
@@ -131,22 +236,38 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
METHOD(stroke_cred_t, load_peer, certificate_t*,
private_stroke_cred_t *this, char *filename)
{
- certificate_t *cert;
+ certificate_t *cert = NULL;
char path[PATH_MAX];
- if (*filename == '/')
+ if (strpfx(filename, "%smartcard"))
{
- snprintf(path, sizeof(path), "%s", filename);
+ smartcard_format_t format;
+ char module[SC_PART_LEN], keyid[SC_PART_LEN];
+ u_int slot;
+
+ format = parse_smartcard(filename, &slot, module, keyid);
+ if (format != SC_FORMAT_INVALID)
+ {
+ cert = (certificate_t*)load_from_smartcard(format,
+ slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
+ }
}
else
{
- snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
- }
+ if (*filename == '/')
+ {
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+ }
- cert = lib->creds->create(lib->creds,
- CRED_CERTIFICATE, CERT_ANY,
- BUILD_FROM_FILE, path,
- BUILD_END);
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_ANY,
+ BUILD_FROM_FILE, path,
+ BUILD_END);
+ }
if (cert)
{
cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
@@ -159,29 +280,45 @@ METHOD(stroke_cred_t, load_peer, certificate_t*,
}
METHOD(stroke_cred_t, load_pubkey, certificate_t*,
- private_stroke_cred_t *this, key_type_t type, char *filename,
- identification_t *identity)
+ private_stroke_cred_t *this, char *filename, identification_t *identity)
{
certificate_t *cert;
+ public_key_t *key;
char path[PATH_MAX];
+ builder_part_t build_part;
+ key_type_t type = KEY_ANY;
if (streq(filename, "%dns"))
{
-
+ return NULL;
+ }
+ if (strncaseeq(filename, "dns:", 4))
+ { /* RFC 3110 format */
+ build_part = BUILD_BLOB_DNSKEY;
+ /* not a complete RR, only RSA supported */
+ type = KEY_RSA;
+ filename += 4;
+ }
+ else if (strncaseeq(filename, "ssh:", 4))
+ { /* SSH key */
+ build_part = BUILD_BLOB_SSHKEY;
+ filename += 4;
}
- else if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
+ else
+ { /* try PKCS#1 by default */
+ build_part = BUILD_BLOB_ASN1_DER;
+ }
+ if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
{
- chunk_t printable_key, rfc3110_key;
- public_key_t *key;
+ chunk_t printable_key, raw_key;
printable_key = chunk_create(filename + 2, strlen(filename) - 2);
- rfc3110_key = strncaseeq(filename, "0x", 2) ?
+ raw_key = strncaseeq(filename, "0x", 2) ?
chunk_from_hex(printable_key, NULL) :
chunk_from_base64(printable_key, NULL);
- key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
- BUILD_BLOB_DNSKEY, rfc3110_key,
- BUILD_END);
- free(rfc3110_key.ptr);
+ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
+ build_part, raw_key, BUILD_END);
+ chunk_free(&raw_key);
if (key)
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
@@ -189,6 +326,7 @@ METHOD(stroke_cred_t, load_pubkey, certificate_t*,
BUILD_PUBLIC_KEY, key,
BUILD_SUBJECT, identity,
BUILD_END);
+ type = key->get_type(key);
key->destroy(key);
if (cert)
{
@@ -198,8 +336,7 @@ METHOD(stroke_cred_t, load_pubkey, certificate_t*,
return cert;
}
}
- DBG1(DBG_CFG, " loading %N public key for \"%Y\" failed",
- key_type_names, type, identity);
+ DBG1(DBG_CFG, " loading public key for \"%Y\" failed", identity);
}
else
{
@@ -220,12 +357,15 @@ METHOD(stroke_cred_t, load_pubkey, certificate_t*,
if (cert)
{
cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
+ key = cert->get_public_key(cert);
+ type = key->get_type(key);
+ key->destroy(key);
DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
key_type_names, type, identity, filename);
return cert;
}
- DBG1(DBG_CFG, " loading %N public key for \"%Y\" from '%s' failed",
- key_type_names, type, identity, filename);
+ DBG1(DBG_CFG, " loading public key for \"%Y\" from '%s' failed",
+ identity, filename);
}
return NULL;
}
@@ -460,8 +600,12 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line)
* Data for passphrase callback
*/
typedef struct {
+ /** cached passphrases */
+ mem_cred_t *cache;
/** socket we use for prompting */
FILE *prompt;
+ /** type of secret to unlock */
+ int type;
/** private key file */
char *path;
/** number of tries */
@@ -469,13 +613,15 @@ typedef struct {
} passphrase_cb_data_t;
/**
- * Callback function to receive Passphrases
+ * Callback function to receive passphrases
*/
static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
- shared_key_type_t type,
- identification_t *me, identification_t *other,
- id_match_t *match_me, id_match_t *match_other)
+ shared_key_type_t type, identification_t *me,
+ identification_t *other, id_match_t *match_me,
+ id_match_t *match_other)
{
+ static const int max_tries = 3;
+ shared_key_t *shared;
chunk_t secret;
char buf[256];
@@ -484,17 +630,23 @@ static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
return NULL;
}
+ data->try++;
+ if (data->try > max_tries + 1)
+ { /* another builder might call this after we gave up, fail silently */
+ return NULL;
+ }
+ if (data->try > max_tries)
+ {
+ fprintf(data->prompt, "Passphrase invalid, giving up.\n");
+ return NULL;
+ }
if (data->try > 1)
{
- if (data->try > 5)
- {
- fprintf(data->prompt, "PIN invalid, giving up.\n");
- return NULL;
- }
- fprintf(data->prompt, "PIN invalid!\n");
+ fprintf(data->prompt, "Passphrase invalid!\n");
}
- data->try++;
- fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path);
+ fprintf(data->prompt, "%s '%s' is encrypted.\n",
+ data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
+ data->path);
fprintf(data->prompt, "Passphrase:\n");
if (fgets(buf, sizeof(buf), data->prompt))
{
@@ -510,7 +662,10 @@ static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
{
*match_other = ID_MATCH_NONE;
}
- return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret));
+ shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
+ chunk_clone(secret));
+ data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
+ return shared;
}
}
return NULL;
@@ -550,12 +705,12 @@ static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
return NULL;
}
+ data->try++;
if (data->try > 1)
{
fprintf(data->prompt, "PIN invalid, aborting.\n");
return NULL;
}
- data->try++;
fprintf(data->prompt, "Login to '%s' required\n", data->card);
fprintf(data->prompt, "PIN:\n");
if (fgets(buf, sizeof(buf), data->prompt))
@@ -581,11 +736,11 @@ static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
/**
* Load a smartcard with a PIN
*/
-static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
+static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
FILE *prompt)
{
chunk_t sc = chunk_empty, secret = chunk_empty;
- char smartcard[64], keyid[64], module[64], *pos;
+ char smartcard[BUF_LEN], keyid[SC_PART_LEN], module[SC_PART_LEN];
private_key_t *key = NULL;
u_int slot;
chunk_t chunk;
@@ -594,11 +749,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
mem_cred_t *mem = NULL;
callback_cred_t *cb = NULL;
pin_cb_data_t pin_data;
- enum {
- SC_FORMAT_SLOT_MODULE_KEYID,
- SC_FORMAT_SLOT_KEYID,
- SC_FORMAT_KEYID,
- } format;
+ smartcard_format_t format;
err_t ugh = extract_value(&sc, &line);
@@ -615,33 +766,8 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
smartcard[sizeof(smartcard) - 1] = '\0';
- /* parse slot and key id. Three formats are supported:
- * - %smartcard<slot>@<module>:<keyid>
- * - %smartcard<slot>:<keyid>
- * - %smartcard:<keyid>
- */
- if (sscanf(smartcard, "%%smartcard%u@%s", &slot, module) == 2)
- {
- pos = strchr(module, ':');
- if (!pos)
- {
- DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is "
- "invalid", line_nr);
- return FALSE;
- }
- *pos = '\0';
- strncpy(keyid, pos + 1, sizeof(keyid));
- format = SC_FORMAT_SLOT_MODULE_KEYID;
- }
- else if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2)
- {
- format = SC_FORMAT_SLOT_KEYID;
- }
- else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1)
- {
- format = SC_FORMAT_KEYID;
- }
- else
+ format = parse_smartcard(smartcard, &slot, module, keyid);
+ if (format == SC_FORMAT_INVALID)
{
DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
" supported or invalid", line_nr);
@@ -661,21 +787,21 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
}
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
- if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
+ if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
free(secret.ptr);
if (!prompt)
{ /* no IO channel to prompt, skip */
- free(chunk.ptr);
+ chunk_clear(&chunk);
return TRUE;
}
/* use callback credential set to prompt for the pin */
pin_data.prompt = prompt;
pin_data.card = smartcard;
pin_data.keyid = chunk;
- pin_data.try = 1;
+ pin_data.try = 0;
cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
- lib->credmgr->add_local_set(lib->credmgr, &cb->set);
+ lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
}
else
{
@@ -684,31 +810,12 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
id = identification_create_from_encoding(ID_KEY_ID, chunk);
mem = mem_cred_create();
mem->add_shared(mem, shared, id, NULL);
- lib->credmgr->add_local_set(lib->credmgr, &mem->set);
+ lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
}
/* unlock: smartcard needs the pin and potentially calls public set */
- switch (format)
- {
- case SC_FORMAT_SLOT_MODULE_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_MODULE, module,
- BUILD_PKCS11_KEYID, chunk, BUILD_END);
- break;
- case SC_FORMAT_SLOT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_KEYID, chunk, BUILD_END);
- break;
- case SC_FORMAT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_KEYID, chunk, BUILD_END);
- break;
- }
+ key = (private_key_t*)load_from_smartcard(format, slot, module, keyid,
+ CRED_PRIVATE_KEY, KEY_ANY);
if (mem)
{
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
@@ -719,25 +826,25 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
cb->destroy(cb);
}
+ chunk_clear(&chunk);
if (key)
{
- DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr);
- this->creds->add_key(this->creds, key);
+ DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr);
+ secrets->add_key(secrets, key);
}
return TRUE;
}
/**
- * Load a private key
+ * Load a private key or PKCS#12 container from a file
*/
-static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
- FILE *prompt, key_type_t key_type)
+static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
+ char *path, int type, int subtype,
+ void **result)
{
- char path[PATH_MAX];
chunk_t filename;
chunk_t secret = chunk_empty;
- private_key_t *key;
err_t ugh = extract_value(&filename, &line);
@@ -754,12 +861,12 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
if (*filename.ptr == '/')
{
/* absolute path name */
- snprintf(path, sizeof(path), "%.*s", (int)filename.len, filename.ptr);
+ snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
}
else
{
/* relative path name */
- snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
+ snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
(int)filename.len, filename.ptr);
}
@@ -773,32 +880,37 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
return FALSE;
}
}
- if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
+ if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
- callback_cred_t *cb = NULL;
+ callback_cred_t *cb;
passphrase_cb_data_t pp_data = {
.prompt = prompt,
+ .type = type,
.path = path,
- .try = 1,
+ .try = 0,
};
free(secret.ptr);
if (!prompt)
{
+ *result = NULL;
return TRUE;
}
+ /* add cache first so if valid passphrases are needed multiple times
+ * the callback is not called anymore */
+ pp_data.cache = mem_cred_create();
+ lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
/* use callback credential set to prompt for the passphrase */
- pp_data.prompt = prompt;
- pp_data.path = path;
- pp_data.try = 1;
cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
- lib->credmgr->add_local_set(lib->credmgr, &cb->set);
+ lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
- key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
- BUILD_FROM_FILE, path, BUILD_END);
+ *result = lib->creds->create(lib->creds, type, subtype,
+ BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
cb->destroy(cb);
+ lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
+ pp_data.cache->destroy(pp_data.cache);
}
else
{
@@ -809,19 +921,49 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
mem = mem_cred_create();
mem->add_shared(mem, shared, NULL);
- lib->credmgr->add_local_set(lib->credmgr, &mem->set);
+ if (eat_whitespace(&line))
+ { /* if there is a second passphrase add that too, could be needed for
+ * PKCS#12 files using different passwords for MAC and encryption */
+ ugh = extract_secret(&secret, &line);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
+ mem->destroy(mem);
+ return FALSE;
+ }
+ shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
+ mem->add_shared(mem, shared, NULL);
+ }
+ lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
- key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
- BUILD_FROM_FILE, path, BUILD_END);
+ *result = lib->creds->create(lib->creds, type, subtype,
+ BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
mem->destroy(mem);
}
+ return TRUE;
+}
+
+/**
+ * Load a private key
+ */
+static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
+ FILE *prompt, key_type_t key_type)
+{
+ char path[PATH_MAX];
+ private_key_t *key;
+
+ if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
+ key_type, (void**)&key))
+ {
+ return FALSE;
+ }
if (key)
{
DBG1(DBG_CFG, " loaded %N private key from '%s'",
key_type_names, key->get_type(key), path);
- this->creds->add_key(this->creds, key);
+ secrets->add_key(secrets, key);
}
else
{
@@ -831,9 +973,61 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
}
/**
+ * Load a PKCS#12 container
+ */
+static bool load_pkcs12(private_stroke_cred_t *this, mem_cred_t *secrets,
+ chunk_t line, int line_nr, FILE *prompt)
+{
+ enumerator_t *enumerator;
+ char path[PATH_MAX];
+ certificate_t *cert;
+ private_key_t *key;
+ pkcs12_t *pkcs12;
+
+ if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
+ CONTAINER_PKCS12, (void**)&pkcs12))
+ {
+ return FALSE;
+ }
+ if (!pkcs12)
+ {
+ DBG1(DBG_CFG, " loading credentials from '%s' failed", path);
+ return TRUE;
+ }
+ enumerator = pkcs12->create_cert_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ x509_t *x509 = (x509_t*)cert;
+
+ if (x509->get_flags(x509) & X509_CA)
+ {
+ DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), path);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), path);
+ }
+ this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
+ }
+ enumerator->destroy(enumerator);
+ enumerator = pkcs12->create_key_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &key))
+ {
+ DBG1(DBG_CFG, " loaded %N private key from '%s'",
+ key_type_names, key->get_type(key), path);
+ secrets->add_key(secrets, key->get_ref(key));
+ }
+ enumerator->destroy(enumerator);
+ pkcs12->container.destroy(&pkcs12->container);
+ return TRUE;
+}
+
+/**
* Load a shared key
*/
-static bool load_shared(private_stroke_cred_t *this, chunk_t line, int line_nr,
+static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
shared_key_type_t type, chunk_t ids)
{
shared_key_t *shared_key;
@@ -888,15 +1082,15 @@ static bool load_shared(private_stroke_cred_t *this, chunk_t line, int line_nr,
owners->insert_last(owners,
identification_create_from_encoding(ID_ANY, chunk_empty));
}
- this->creds->add_shared_list(this->creds, shared_key, owners);
+ secrets->add_shared_list(secrets, shared_key, owners);
return TRUE;
}
/**
* reload ipsec.secrets
*/
-static void load_secrets(private_stroke_cred_t *this, char *file, int level,
- FILE *prompt)
+static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
+ char *file, int level, FILE *prompt)
{
int line_nr = 0, fd;
chunk_t src, line;
@@ -918,6 +1112,11 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
close(fd);
return;
}
+ if (sb.st_size == 0)
+ { /* skip empty files, as mmap() complains */
+ close(fd);
+ return;
+ }
addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED)
{
@@ -927,9 +1126,9 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
}
src = chunk_create(addr, sb.st_size);
- if (level == 0)
- { /* flush secrets on non-recursive invocation */
- this->creds->clear_secrets(this->creds);
+ if (!secrets)
+ {
+ secrets = mem_cred_create();
}
while (fetchline(&src, &line))
@@ -943,8 +1142,7 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
{
continue;
}
- if (line.len > strlen("include ") &&
- strneq(line.ptr, "include ", strlen("include ")))
+ if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
{
char **expanded, *dir, pattern[PATH_MAX];
u_char *pos;
@@ -999,19 +1197,20 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
{
for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
{
- load_secrets(this, *expanded, level + 1, prompt);
+ load_secrets(this, secrets, *expanded, level + 1,
+ prompt);
}
}
globfree(&buf);
}
#else /* HAVE_GLOB_H */
/* if glob(3) is not available, try to load pattern directly */
- load_secrets(this, pattern, level + 1, prompt);
+ load_secrets(this, secrets, pattern, level + 1, prompt);
#endif /* HAVE_GLOB_H */
continue;
}
- if (line.len > 2 && strneq(": ", line.ptr, 2))
+ if (line.len > 2 && strpfx(line.ptr, ": "))
{
/* no ids, skip the ':' */
ids = chunk_empty;
@@ -1036,15 +1235,22 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
}
if (match("RSA", &token) || match("ECDSA", &token))
{
- if (!load_private(this, line, line_nr, prompt,
+ if (!load_private(secrets, line, line_nr, prompt,
match("RSA", &token) ? KEY_RSA : KEY_ECDSA))
{
break;
}
}
+ else if (match("P12", &token))
+ {
+ if (!load_pkcs12(this, secrets, line, line_nr, prompt))
+ {
+ break;
+ }
+ }
else if (match("PIN", &token))
{
- if (!load_pin(this, line, line_nr, prompt))
+ if (!load_pin(secrets, line, line_nr, prompt))
{
break;
}
@@ -1054,7 +1260,7 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
(match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
(match("XAUTH", &token) && (type = SHARED_EAP)))
{
- if (!load_shared(this, line, line_nr, type, ids))
+ if (!load_shared(secrets, line, line_nr, type, ids))
{
break;
}
@@ -1062,12 +1268,18 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
else
{
DBG1(DBG_CFG, "line %d: token must be either "
- "RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr);
+ "RSA, ECDSA, P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
break;
}
}
munmap(addr, sb.st_size);
close(fd);
+
+ if (level == 0)
+ { /* replace secrets in active credential set */
+ this->creds->replace_secrets(this->creds, secrets, FALSE);
+ secrets->destroy(secrets);
+ }
}
/**
@@ -1102,7 +1314,7 @@ METHOD(stroke_cred_t, reread, void,
if (msg->reread.flags & REREAD_SECRETS)
{
DBG1(DBG_CFG, "rereading secrets");
- load_secrets(this, SECRETS_FILE, 0, prompt);
+ load_secrets(this, NULL, SECRETS_FILE, 0, prompt);
}
if (msg->reread.flags & REREAD_CACERTS)
{
@@ -1181,11 +1393,11 @@ stroke_cred_t *stroke_cred_create()
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
this->force_ca_cert = lib->settings->get_bool(lib->settings,
- "charon.plugins.stroke.ignore_missing_ca_basic_constraint", FALSE);
+ "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
+ FALSE, charon->name);
load_certs(this);
- load_secrets(this, SECRETS_FILE, 0, NULL);
+ load_secrets(this, NULL, SECRETS_FILE, 0, NULL);
return &this->public;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_cred.h b/src/libcharon/plugins/stroke/stroke_cred.h
index 83e648819..f6fbb96d3 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.h
+++ b/src/libcharon/plugins/stroke/stroke_cred.h
@@ -27,7 +27,7 @@
#include <stroke_msg.h>
#include <credentials/credential_set.h>
#include <credentials/certificates/certificate.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
typedef struct stroke_cred_t stroke_cred_t;
@@ -68,13 +68,12 @@ struct stroke_cred_t {
/**
* Load a raw public key and serve it through the credential_set.
*
- * @param type type of the raw public key (RSA or ECDSA)
- * @param filename file to load raw public key from
+ * @param filename encoding or file to load raw public key from
* @param identity identity of the raw public key owner
* @return reference to loaded raw public key, or NULL
*/
- certificate_t* (*load_pubkey)(stroke_cred_t *this, key_type_t type,
- char *filename, identification_t *identity);
+ certificate_t* (*load_pubkey)(stroke_cred_t *this, char *filename,
+ identification_t *identity);
/**
* Add a shared secret to serve through the credential_set.
diff --git a/src/libcharon/plugins/stroke/stroke_handler.c b/src/libcharon/plugins/stroke/stroke_handler.c
new file mode 100644
index 000000000..fef8cab67
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_handler.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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 "stroke_handler.h"
+
+#include <daemon.h>
+#include <collections/linked_list.h>
+#include <threading/rwlock.h>
+
+typedef struct private_stroke_handler_t private_stroke_handler_t;
+
+/**
+ * Private data of an stroke_handler_t object.
+ */
+struct private_stroke_handler_t {
+
+ /**
+ * Public stroke_handler_t interface.
+ */
+ stroke_handler_t public;
+
+ /**
+ * List of connection specific attributes, as attributes_t
+ */
+ linked_list_t *attrs;
+
+ /**
+ * rwlock to lock access to pools
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * Attributes assigned to a connection
+ */
+typedef struct {
+ /** name of the connection */
+ char *name;
+ /** list of DNS attributes, as host_t */
+ linked_list_t *dns;
+} attributes_t;
+
+/**
+ * Destroy an attributes_t entry
+ */
+static void attributes_destroy(attributes_t *this)
+{
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Filter function to convert host to DNS configuration attributes
+ */
+static bool attr_filter(void *lock, host_t **in,
+ configuration_attribute_type_t *type,
+ void *dummy, chunk_t *data)
+{
+ host_t *host = *in;
+
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ *type = INTERNAL_IP4_DNS;
+ break;
+ case AF_INET6:
+ *type = INTERNAL_IP6_DNS;
+ break;
+ default:
+ return FALSE;
+ }
+ if (host->is_anyaddr(host))
+ {
+ *data = chunk_empty;
+ }
+ else
+ {
+ *data = host->get_address(host);
+ }
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
+ private_stroke_handler_t *this, identification_t *server,
+ linked_list_t *vips)
+{
+ ike_sa_t *ike_sa;
+ peer_cfg_t *peer_cfg;
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ this->lock->read_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
+ {
+ enumerator->destroy(enumerator);
+ return enumerator_create_filter(
+ attr->dns->create_enumerator(attr->dns),
+ (void*)attr_filter, this->lock,
+ (void*)this->lock->unlock);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ }
+ return enumerator_create_empty();
+}
+
+METHOD(stroke_handler_t, add_attributes, void,
+ private_stroke_handler_t *this, stroke_msg_t *msg)
+{
+ if (msg->add_conn.me.dns)
+ {
+ enumerator_t *enumerator;
+ attributes_t *attr = NULL;
+ host_t *host;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ if (streq(token, "%config") || streq(token, "%config4"))
+ {
+ host = host_create_any(AF_INET);
+ }
+ else if (streq(token, "%config6"))
+ {
+ host = host_create_any(AF_INET6);
+ }
+ else
+ {
+ host = host_create_from_string(token, 0);
+ }
+ if (host)
+ {
+ if (!attr)
+ {
+ INIT(attr,
+ .name = strdup(msg->add_conn.name),
+ .dns = linked_list_create(),
+ );
+ }
+ attr->dns->insert_last(attr->dns, host);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (attr)
+ {
+ this->lock->write_lock(this->lock);
+ this->attrs->insert_last(this->attrs, attr);
+ this->lock->unlock(this->lock);
+ }
+ }
+}
+
+METHOD(stroke_handler_t, del_attributes, void,
+ private_stroke_handler_t *this, stroke_msg_t *msg)
+{
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(msg->del_conn.name, attr->name))
+ {
+ this->attrs->remove_at(this->attrs, enumerator);
+ attributes_destroy(attr);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_handler_t, destroy, void,
+ private_stroke_handler_t *this)
+{
+ this->lock->destroy(this->lock);
+ this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+stroke_handler_t *stroke_handler_create()
+{
+ private_stroke_handler_t *this;
+
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = (void*)return_false,
+ .release = (void*)return_false,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .add_attributes = _add_attributes,
+ .del_attributes = _del_attributes,
+ .destroy = _destroy,
+ },
+ .attrs = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/stroke/stroke_handler.h b/src/libcharon/plugins/stroke/stroke_handler.h
new file mode 100644
index 000000000..ab76f80b0
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_handler.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup stroke_handler stroke_handler
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_HANDLER_H_
+#define STROKE_HANDLER_H_
+
+#include <stroke_msg.h>
+#include <attributes/attribute_handler.h>
+
+typedef struct stroke_handler_t stroke_handler_t;
+
+/**
+ * Handler requesting DNS attributes as defined with leftdns option.
+ */
+struct stroke_handler_t {
+
+ /**
+ * Implements the attribute_handler_t interface
+ */
+ attribute_handler_t handler;
+
+ /**
+ * Add connection specific configuration attributes.
+ *
+ * @param msg stroke message
+ */
+ void (*add_attributes)(stroke_handler_t *this, stroke_msg_t *msg);
+
+ /**
+ * Remove connection specific configuration attributes.
+ *
+ * @param msg stroke message
+ */
+ void (*del_attributes)(stroke_handler_t *this, stroke_msg_t *msg);
+
+ /**
+ * Destroy a stroke_handler_t.
+ */
+ void (*destroy)(stroke_handler_t *this);
+};
+
+/**
+ * Create a stroke_handler instance.
+ */
+stroke_handler_t *stroke_handler_create();
+
+#endif /** STROKE_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 514a91e2b..e81f3fc32 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -17,6 +17,7 @@
#include <inttypes.h>
#include <time.h>
+#include <sys/utsname.h>
#ifdef HAVE_MALLINFO
#include <malloc.h>
@@ -24,7 +25,7 @@
#include <hydra.h>
#include <daemon.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <plugins/plugin.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
@@ -51,6 +52,11 @@ struct private_stroke_list_t {
stroke_list_t public;
/**
+ * Kind of *swan we run
+ */
+ char *swan;
+
+ /**
* timestamp of daemon start
*/
time_t uptime;
@@ -115,11 +121,23 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
if (all)
{
proposal_t *ike_proposal;
+ identification_t *eap_id;
+
+ eap_id = ike_sa->get_other_eap_id(ike_sa);
+
+ if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa)))
+ {
+ fprintf(out, "%12s[%d]: Remote %s identity: %Y\n",
+ ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+ ike_sa->get_version(ike_sa) == IKEV1 ? "XAuth" : "EAP",
+ eap_id);
+ }
ike_proposal = ike_sa->get_proposal(ike_sa);
- fprintf(out, "%12s[%d]: IKE SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s",
+ fprintf(out, "%12s[%d]: %N SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+ ike_version_names, ike_sa->get_version(ike_sa),
id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
@@ -187,10 +205,13 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
{
time_t use_in, use_out, rekey, now;
- u_int64_t bytes_in, bytes_out;
+ u_int64_t bytes_in, bytes_out, packets_in, packets_out;
proposal_t *proposal;
- child_cfg_t *config = child_sa->get_config(child_sa);
+ linked_list_t *my_ts, *other_ts;
+ child_cfg_t *config;
+ config = child_sa->get_config(child_sa);
+ now = time_monotonic(NULL);
fprintf(out, "%12s{%d}: %N, %N%s",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
@@ -254,19 +275,24 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
}
}
- now = time_monotonic(NULL);
- child_sa->get_usestats(child_sa, TRUE, &use_in, &bytes_in);
+ child_sa->get_usestats(child_sa, TRUE,
+ &use_in, &bytes_in, &packets_in);
fprintf(out, ", %" PRIu64 " bytes_i", bytes_in);
if (use_in)
{
- fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_in));
+ fprintf(out, " (%" PRIu64 " pkt%s, %" PRIu64 "s ago)",
+ packets_in, (packets_in == 1) ? "": "s",
+ (u_int64_t)(now - use_in));
}
- child_sa->get_usestats(child_sa, FALSE, &use_out, &bytes_out);
+ child_sa->get_usestats(child_sa, FALSE,
+ &use_out, &bytes_out, &packets_out);
fprintf(out, ", %" PRIu64 " bytes_o", bytes_out);
if (use_out)
{
- fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_out));
+ fprintf(out, " (%" PRIu64 " pkt%s, %" PRIu64 "s ago)",
+ packets_out, (packets_out == 1) ? "": "s",
+ (u_int64_t)(now - use_out));
}
fprintf(out, ", rekeying ");
@@ -289,11 +315,21 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
}
}
+ else if (child_sa->get_state(child_sa) == CHILD_REKEYING)
+ {
+ rekey = child_sa->get_lifetime(child_sa, TRUE);
+ fprintf(out, ", expires in %V", &now, &rekey);
+ }
+ my_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, FALSE));
fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ my_ts, other_ts);
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
}
/**
@@ -315,15 +351,16 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
while (enumerator->enumerate(enumerator, &auth))
{
- fprintf(out, "%12s: %s [%Y] uses ", name, local ? "local: " : "remote:",
- auth->get(auth, AUTH_RULE_IDENTITY));
-
- auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
- if (auth_class != AUTH_CLASS_EAP)
+ fprintf(out, "%12s: %s", name, local ? "local: " : "remote:");
+ id = auth->get(auth, AUTH_RULE_IDENTITY);
+ if (id)
{
- fprintf(out, "%N authentication\n", auth_class_names, auth_class);
+ fprintf(out, " [%Y]", id);
}
- else
+ fprintf(out, " uses ");
+
+ auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
+ if (auth_class == AUTH_CLASS_EAP)
{
if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK)
{
@@ -350,6 +387,21 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
}
fprintf(out, "\n");
}
+ else if (auth_class == AUTH_CLASS_XAUTH)
+ {
+ fprintf(out, "%N authentication: %s", auth_class_names, auth_class,
+ auth->get(auth, AUTH_RULE_XAUTH_BACKEND) ?: "any");
+ id = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
+ if (id)
+ {
+ fprintf(out, " with XAuth identity '%Y'", id);
+ }
+ fprintf(out, "\n");
+ }
+ else
+ {
+ fprintf(out, "%N authentication\n", auth_class_names, auth_class);
+ }
cert = auth->get(auth, AUTH_RULE_CA_CERT);
if (cert)
@@ -414,16 +466,25 @@ METHOD(stroke_list_t, status, void,
if (all)
{
peer_cfg_t *peer_cfg;
+ ike_version_t ike_version;
char *pool;
host_t *host;
u_int32_t dpd;
time_t since, now;
u_int size, online, offline, i;
+ struct utsname utsname;
+
now = time_monotonic(NULL);
since = time(NULL) - (now - this->uptime);
- fprintf(out, "Status of IKEv2 charon daemon (strongSwan "VERSION"):\n");
- fprintf(out, " uptime: %V, since %T\n", &now, &this->uptime, &since, FALSE);
+ fprintf(out, "Status of IKE charon daemon (%sSwan "VERSION, this->swan);
+ if (uname(&utsname) == 0)
+ {
+ fprintf(out, ", %s %s, %s",
+ utsname.sysname, utsname.release, utsname.machine);
+ }
+ fprintf(out, "):\n uptime: %V, since %T\n", &now, &this->uptime, &since,
+ FALSE);
#ifdef HAVE_MALLINFO
{
struct mallinfo mi = mallinfo();
@@ -469,7 +530,7 @@ METHOD(stroke_list_t, status, void,
enumerator->destroy(enumerator);
enumerator = hydra->kernel_interface->create_address_enumerator(
- hydra->kernel_interface, FALSE, FALSE);
+ hydra->kernel_interface, ADDR_TYPE_REGULAR);
fprintf(out, "Listening IP addresses:\n");
while (enumerator->enumerate(enumerator, (void**)&host))
{
@@ -479,18 +540,30 @@ METHOD(stroke_list_t, status, void,
fprintf(out, "Connections:\n");
enumerator = charon->backends->create_peer_cfg_enumerator(
- charon->backends, NULL, NULL, NULL, NULL);
+ charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
while (enumerator->enumerate(enumerator, &peer_cfg))
{
- if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
- (name && !streq(name, peer_cfg->get_name(peer_cfg))))
+ char *my_addr, *other_addr;
+ bool my_allow_any, other_allow_any;
+
+ if (name && !streq(name, peer_cfg->get_name(peer_cfg)))
{
continue;
}
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
- fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg),
- ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg));
+ ike_version = peer_cfg->get_ike_version(peer_cfg);
+ my_addr = ike_cfg->get_my_addr(ike_cfg, &my_allow_any);
+ other_addr = ike_cfg->get_other_addr(ike_cfg, &other_allow_any);
+ fprintf(out, "%12s: %s%s...%s%s %N", peer_cfg->get_name(peer_cfg),
+ my_allow_any ? "%":"", my_addr,
+ other_allow_any ? "%":"", other_addr,
+ ike_version_names, ike_version);
+
+ if (ike_version == IKEV1 && peer_cfg->use_aggressive(peer_cfg))
+ {
+ fprintf(out, " Aggressive");
+ }
dpd = peer_cfg->get_dpd(peer_cfg);
if (dpd)
@@ -666,15 +739,12 @@ static void list_public_key(public_key_t *public, FILE *out)
private_key_t *private = NULL;
chunk_t keyid;
identification_t *id;
- auth_cfg_t *auth;
if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
{
id = identification_create_from_encoding(ID_KEY_ID, keyid);
- auth = auth_cfg_create();
private = lib->credmgr->get_private(lib->credmgr,
- public->get_type(public), id, auth);
- auth->destroy(auth);
+ public->get_type(public), id, NULL);
id->destroy(id);
}
@@ -819,8 +889,8 @@ static void stroke_list_certs(linked_list_t *list, char *label,
x509_flag_t flag_mask;
/* mask all auxiliary flags */
- flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH |
- X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS );
+ flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH | X509_IKE_INTERMEDIATE |
+ X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS);
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, (void**)&cert))
@@ -1059,7 +1129,7 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
}
if (crl->is_delta_crl(crl, &chunk))
{
- chunk = chunk_skip_zero(chunk);
+ chunk = chunk_skip_zero(chunk);
fprintf(out, " delta for: %#B\n", &chunk);
}
@@ -1151,7 +1221,15 @@ static void print_alg(FILE *out, int *len, enum_name_t *alg_names, int alg_type,
char alg_name[BUF_LEN];
int alg_name_len;
- alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type, plugin_name);
+ if (alg_names)
+ {
+ alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type,
+ plugin_name);
+ }
+ else
+ {
+ alg_name_len = sprintf(alg_name, " [%s]", plugin_name);
+ }
if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE)
{
fprintf(out, "\n ");
@@ -1177,7 +1255,7 @@ static void list_algs(FILE *out)
int len;
fprintf(out, "\n");
- fprintf(out, "List of registered IKEv2 Algorithms:\n");
+ fprintf(out, "List of registered IKE algorithms:\n");
fprintf(out, "\n encryption:");
len = 13;
enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
@@ -1234,6 +1312,14 @@ static void list_algs(FILE *out)
print_alg(out, &len, rng_quality_names, quality, plugin_name);
}
enumerator->destroy(enumerator);
+ fprintf(out, "\n nonce-gen: ");
+ len = 13;
+ enumerator = lib->crypto->create_nonce_gen_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &plugin_name))
+ {
+ print_alg(out, &len, NULL, 0, plugin_name);
+ }
+ enumerator->destroy(enumerator);
fprintf(out, "\n");
}
@@ -1277,7 +1363,7 @@ static void list_plugins(FILE *out)
fprintf(out, " %s\n", str);
break;
case FEATURE_SDEPEND:
- fprintf(out, " %s(soft)\n", str);
+ fprintf(out, " %s (soft)\n", str);
break;
default:
break;
@@ -1285,6 +1371,7 @@ static void list_plugins(FILE *out)
free(str);
}
}
+ list->destroy(list);
}
enumerator->destroy(enumerator);
}
@@ -1450,16 +1537,21 @@ stroke_list_t *stroke_list_create(stroke_attribute_t *attribute)
INIT(this,
.public = {
-
.list = _list,
.status = _status,
.leases = _leases,
.destroy = _destroy,
},
.uptime = time_monotonic(NULL),
+ .swan = "strong",
.attribute = attribute,
);
+ if (lib->settings->get_bool(lib->settings,
+ "charon.i_dont_care_about_security_and_use_aggressive_mode_psk", FALSE))
+ {
+ this->swan = "weak";
+ }
+
return &this->public;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_plugin.c b/src/libcharon/plugins/stroke/stroke_plugin.c
index 2884db4bf..31df1f99b 100644
--- a/src/libcharon/plugins/stroke/stroke_plugin.c
+++ b/src/libcharon/plugins/stroke/stroke_plugin.c
@@ -42,10 +42,46 @@ METHOD(plugin_t, get_name, char*,
return "stroke";
}
+/**
+ * Register stroke plugin features
+ */
+static bool register_stroke(private_stroke_plugin_t *this,
+ plugin_feature_t *feature, bool reg, void *data)
+{
+ if (reg)
+ {
+ this->socket = stroke_socket_create();
+ return this->socket != NULL;
+ }
+ else
+ {
+ DESTROY_IF(this->socket);
+ return TRUE;
+ }
+}
+
+METHOD(plugin_t, get_features, int,
+ private_stroke_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK((plugin_feature_callback_t)register_stroke, NULL),
+ PLUGIN_PROVIDE(CUSTOM, "stroke"),
+ PLUGIN_SDEPEND(PRIVKEY, KEY_RSA),
+ PLUGIN_SDEPEND(PRIVKEY, KEY_ECDSA),
+ PLUGIN_SDEPEND(PRIVKEY, KEY_DSA),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_ANY),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_X509),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_X509_CRL),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_X509_AC),
+ PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY),
+ };
+ *features = f;
+ return countof(f);
+}
+
METHOD(plugin_t, destroy, void,
private_stroke_plugin_t *this)
{
- this->socket->destroy(this->socket);
free(this);
}
@@ -61,17 +97,11 @@ plugin_t *stroke_plugin_create()
.plugin = {
.get_name = _get_name,
.reload = (void*)return_false,
+ .get_features = _get_features,
.destroy = _destroy,
},
},
- .socket = stroke_socket_create(),
);
- if (this->socket == NULL)
- {
- free(this);
- return NULL;
- }
return &this->public.plugin;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 57648feb8..88f73f3b0 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -26,18 +26,15 @@
#include <hydra.h>
#include <daemon.h>
-#include <threading/mutex.h>
-#include <threading/thread.h>
-#include <threading/condvar.h>
-#include <utils/linked_list.h>
-#include <processing/jobs/callback_job.h>
#include "stroke_config.h"
#include "stroke_control.h"
#include "stroke_cred.h"
#include "stroke_ca.h"
#include "stroke_attribute.h"
+#include "stroke_handler.h"
#include "stroke_list.h"
+#include "stroke_counter.h"
/**
* To avoid clogging the thread pool with (blocking) jobs, we limit the number
@@ -59,44 +56,9 @@ struct private_stroke_socket_t {
stroke_socket_t public;
/**
- * Unix socket to listen for strokes
+ * Service accepting stroke connections
*/
- int socket;
-
- /**
- * job accepting stroke messages
- */
- callback_job_t *receiver;
-
- /**
- * job handling stroke messages
- */
- callback_job_t *handler;
-
- /**
- * queued stroke commands
- */
- linked_list_t *commands;
-
- /**
- * lock for command list
- */
- mutex_t *mutex;
-
- /**
- * condvar to signal the arrival or completion of commands
- */
- condvar_t *condvar;
-
- /**
- * the number of currently handled commands
- */
- u_int handling;
-
- /**
- * the maximum number of concurrently handled commands
- */
- u_int max_concurrent;
+ stream_service_t *service;
/**
* configuration backend
@@ -109,6 +71,11 @@ struct private_stroke_socket_t {
stroke_attribute_t *attribute;
/**
+ * attribute handler (requests only)
+ */
+ stroke_handler_t *handler;
+
+ /**
* controller to control daemon
*/
stroke_control_t *control;
@@ -127,22 +94,11 @@ struct private_stroke_socket_t {
* status information logging
*/
stroke_list_t *list;
-};
-
-/**
- * job context to pass to processing thread
- */
-struct stroke_job_context_t {
/**
- * file descriptor to read from
+ * Counter values for IKE events
*/
- int fd;
-
- /**
- * global stroke interface
- */
- private_stroke_socket_t *this;
+ stroke_counter_t *counter;
};
/**
@@ -181,6 +137,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
pop_string(msg, &end->address);
pop_string(msg, &end->subnets);
pop_string(msg, &end->sourceip);
+ pop_string(msg, &end->dns);
pop_string(msg, &end->auth);
pop_string(msg, &end->auth2);
pop_string(msg, &end->id);
@@ -191,12 +148,14 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
pop_string(msg, &end->ca);
pop_string(msg, &end->ca2);
pop_string(msg, &end->groups);
+ pop_string(msg, &end->groups2);
pop_string(msg, &end->cert_policy);
pop_string(msg, &end->updown);
DBG2(DBG_CFG, " %s=%s", label, end->address);
DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
+ DBG2(DBG_CFG, " %sdns=%s", label, end->dns);
DBG2(DBG_CFG, " %sauth=%s", label, end->auth);
DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
DBG2(DBG_CFG, " %sid=%s", label, end->id);
@@ -207,6 +166,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
DBG2(DBG_CFG, " %sca=%s", label, end->ca);
DBG2(DBG_CFG, " %sca2=%s", label, end->ca2);
DBG2(DBG_CFG, " %sgroups=%s", label, end->groups);
+ DBG2(DBG_CFG, " %sgroups2=%s", label, end->groups2);
DBG2(DBG_CFG, " %supdown=%s", label, end->updown);
}
@@ -223,23 +183,28 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
pop_end(msg, "right", &msg->add_conn.other);
pop_string(msg, &msg->add_conn.eap_identity);
pop_string(msg, &msg->add_conn.aaa_identity);
+ pop_string(msg, &msg->add_conn.xauth_identity);
pop_string(msg, &msg->add_conn.algorithms.ike);
pop_string(msg, &msg->add_conn.algorithms.esp);
pop_string(msg, &msg->add_conn.ikeme.mediated_by);
pop_string(msg, &msg->add_conn.ikeme.peerid);
DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity);
+ DBG2(DBG_CFG, " xauth_identity=%s", msg->add_conn.xauth_identity);
DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay);
+ DBG2(DBG_CFG, " dpdtimeout=%d", msg->add_conn.dpd.timeout);
DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action);
DBG2(DBG_CFG, " closeaction=%d", msg->add_conn.close_action);
DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by);
DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid);
+ DBG2(DBG_CFG, " keyexchange=ikev%u", msg->add_conn.version);
this->config->add(this->config, msg);
- this->attribute->add_pool(this->attribute, msg);
+ this->attribute->add_dns(this->attribute, msg);
+ this->handler->add_attributes(this->handler, msg);
}
/**
@@ -251,7 +216,8 @@ static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
this->config->del(this->config, msg);
- this->attribute->del_pool(this->attribute, msg);
+ this->attribute->del_dns(this->attribute, msg);
+ this->handler->del_attributes(this->handler, msg);
}
/**
@@ -376,7 +342,8 @@ static void stroke_status(private_stroke_socket_t *this,
/**
* list various information
*/
-static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg,
+ FILE *out)
{
if (msg->list.flags & LIST_CAINFOS)
{
@@ -419,6 +386,20 @@ static void stroke_purge(private_stroke_socket_t *this,
}
/**
+ * Print a certificate in PEM to out
+ */
+static void print_pem_cert(FILE *out, certificate_t *cert)
+{
+ chunk_t encoded;
+
+ if (cert->get_encoding(cert, CERT_PEM, &encoded))
+ {
+ fprintf(out, "%.*s", (int)encoded.len, encoded.ptr);
+ free(encoded.ptr);
+ }
+}
+
+/**
* Export in-memory credentials
*/
static void stroke_export(private_stroke_socket_t *this,
@@ -431,22 +412,67 @@ static void stroke_export(private_stroke_socket_t *this,
enumerator_t *enumerator;
identification_t *id;
certificate_t *cert;
- chunk_t encoded;
id = identification_create_from_string(msg->export.selector);
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
CERT_X509, KEY_ANY, id, FALSE);
while (enumerator->enumerate(enumerator, &cert))
{
- if (cert->get_encoding(cert, CERT_PEM, &encoded))
- {
- fprintf(out, "%.*s", (int)encoded.len, encoded.ptr);
- free(encoded.ptr);
- }
+ print_pem_cert(out, cert);
}
enumerator->destroy(enumerator);
id->destroy(id);
}
+
+ if (msg->export.flags & (EXPORT_CONN_CERT | EXPORT_CONN_CHAIN))
+ {
+ enumerator_t *sas, *auths, *certs;
+ ike_sa_t *ike_sa;
+ auth_cfg_t *auth;
+ certificate_t *cert;
+ auth_rule_t rule;
+
+ sas = charon->ike_sa_manager->create_enumerator(
+ charon->ike_sa_manager, TRUE);
+ while (sas->enumerate(sas, &ike_sa))
+ {
+ if (streq(msg->export.selector, ike_sa->get_name(ike_sa)))
+ {
+ auths = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE);
+ while (auths->enumerate(auths, &auth))
+ {
+ bool got_subject = FALSE;
+
+ certs = auth->create_enumerator(auth);
+ while (certs->enumerate(certs, &rule, &cert))
+ {
+ switch (rule)
+ {
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ if (msg->export.flags & EXPORT_CONN_CHAIN)
+ {
+ print_pem_cert(out, cert);
+ }
+ break;
+ case AUTH_RULE_SUBJECT_CERT:
+ if (!got_subject)
+ {
+ print_pem_cert(out, cert);
+ got_subject = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ certs->destroy(certs);
+ }
+ auths->destroy(auths);
+ }
+ }
+ sas->destroy(sas);
+ }
}
/**
@@ -489,39 +515,49 @@ static void stroke_user_creds(private_stroke_socket_t *this,
}
/**
+ * Print stroke counter values
+ */
+static void stroke_counters(private_stroke_socket_t *this,
+ stroke_msg_t *msg, FILE *out)
+{
+ pop_string(msg, &msg->counters.name);
+
+ if (msg->counters.reset)
+ {
+ this->counter->reset(this->counter, msg->counters.name);
+ }
+ else
+ {
+ this->counter->print(this->counter, out, msg->counters.name);
+ }
+}
+
+/**
* set the verbosity debug output
*/
static void stroke_loglevel(private_stroke_socket_t *this,
stroke_msg_t *msg, FILE *out)
{
- enumerator_t *enumerator;
- sys_logger_t *sys_logger;
- file_logger_t *file_logger;
debug_t group;
pop_string(msg, &(msg->loglevel.type));
DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
msg->loglevel.level, msg->loglevel.type);
- group = enum_from_name(debug_names, msg->loglevel.type);
- if ((int)group < 0)
+ if (strcaseeq(msg->loglevel.type, "any"))
{
- fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
- return;
- }
- /* we set the loglevel on ALL sys- and file-loggers */
- enumerator = charon->sys_loggers->create_enumerator(charon->sys_loggers);
- while (enumerator->enumerate(enumerator, &sys_logger))
- {
- sys_logger->set_level(sys_logger, group, msg->loglevel.level);
+ group = DBG_ANY;
}
- enumerator->destroy(enumerator);
- enumerator = charon->file_loggers->create_enumerator(charon->file_loggers);
- while (enumerator->enumerate(enumerator, &file_logger))
+ else
{
- file_logger->set_level(file_logger, group, msg->loglevel.level);
+ group = enum_from_name(debug_names, msg->loglevel.type);
+ if ((int)group < 0)
+ {
+ fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
+ return;
+ }
}
- enumerator->destroy(enumerator);
+ charon->set_level(charon, group, msg->loglevel.level);
}
/**
@@ -534,68 +570,47 @@ static void stroke_config(private_stroke_socket_t *this,
}
/**
- * destroy a job context
+ * process a stroke request
*/
-static void stroke_job_context_destroy(stroke_job_context_t *this)
-{
- if (this->fd)
- {
- close(this->fd);
- }
- free(this);
-}
-
-/**
- * called to signal the completion of a command
- */
-static inline job_requeue_t job_processed(private_stroke_socket_t *this)
-{
- this->mutex->lock(this->mutex);
- this->handling--;
- this->condvar->signal(this->condvar);
- this->mutex->unlock(this->mutex);
- return JOB_REQUEUE_NONE;
-}
-
-/**
- * process a stroke request from the socket pointed by "fd"
- */
-static job_requeue_t process(stroke_job_context_t *ctx)
+static bool on_accept(private_stroke_socket_t *this, stream_t *stream)
{
stroke_msg_t *msg;
- u_int16_t msg_length;
- ssize_t bytes_read;
+ u_int16_t len;
FILE *out;
- private_stroke_socket_t *this = ctx->this;
- int strokefd = ctx->fd;
- /* peek the length */
- bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
- if (bytes_read != sizeof(msg_length))
+ /* read length */
+ if (!stream->read_all(stream, &len, sizeof(len)))
{
- DBG1(DBG_CFG, "reading length of stroke message failed: %s",
- strerror(errno));
- return job_processed(this);
+ if (errno != EWOULDBLOCK)
+ {
+ DBG1(DBG_CFG, "reading length of stroke message failed: %s",
+ strerror(errno));
+ }
+ return FALSE;
}
/* read message */
- msg = alloca(msg_length);
- bytes_read = recv(strokefd, msg, msg_length, 0);
- if (bytes_read != msg_length)
+ msg = malloc(len);
+ msg->length = len;
+ if (!stream->read_all(stream, (char*)msg + sizeof(len), len - sizeof(len)))
{
- DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
- return job_processed(this);
+ if (errno != EWOULDBLOCK)
+ {
+ DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
+ }
+ free(msg);
+ return FALSE;
}
- out = fdopen(strokefd, "w+");
- if (out == NULL)
+ DBG3(DBG_CFG, "stroke message %b", (void*)msg, len);
+
+ out = stream->get_file(stream);
+ if (!out)
{
- DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
- return job_processed(this);
+ DBG1(DBG_CFG, "creating stroke output stream failed");
+ free(msg);
+ return FALSE;
}
-
- DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
-
switch (msg->type)
{
case STR_INITIATE:
@@ -664,138 +679,36 @@ static job_requeue_t process(stroke_job_context_t *ctx)
case STR_USER_CREDS:
stroke_user_creds(this, msg, out);
break;
+ case STR_COUNTERS:
+ stroke_counters(this, msg, out);
+ break;
default:
DBG1(DBG_CFG, "received unknown stroke");
break;
}
+ free(msg);
fclose(out);
- /* fclose() closes underlying FD */
- ctx->fd = 0;
- return job_processed(this);
-}
-
-/**
- * Handle queued stroke commands
- */
-static job_requeue_t handle(private_stroke_socket_t *this)
-{
- stroke_job_context_t *ctx;
- callback_job_t *job;
- bool oldstate;
-
- this->mutex->lock(this->mutex);
- thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
- oldstate = thread_cancelability(TRUE);
- while (this->commands->get_count(this->commands) == 0 ||
- this->handling >= this->max_concurrent)
- {
- this->condvar->wait(this->condvar, this->mutex);
- }
- thread_cancelability(oldstate);
- this->commands->remove_first(this->commands, (void**)&ctx);
- this->handling++;
- thread_cleanup_pop(TRUE);
- job = callback_job_create_with_prio((callback_job_cb_t)process, ctx,
- (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH);
- lib->processor->queue_job(lib->processor, (job_t*)job);
- return JOB_REQUEUE_DIRECT;
-}
-
-/**
- * Accept stroke commands and queue them to be handled
- */
-static job_requeue_t receive(private_stroke_socket_t *this)
-{
- struct sockaddr_un strokeaddr;
- int strokeaddrlen = sizeof(strokeaddr);
- int strokefd;
- bool oldstate;
- stroke_job_context_t *ctx;
-
- oldstate = thread_cancelability(TRUE);
- strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
- thread_cancelability(oldstate);
-
- if (strokefd < 0)
- {
- DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
- return JOB_REQUEUE_FAIR;
- }
-
- INIT(ctx,
- .fd = strokefd,
- .this = this,
- );
- this->mutex->lock(this->mutex);
- this->commands->insert_last(this->commands, ctx);
- this->condvar->signal(this->condvar);
- this->mutex->unlock(this->mutex);
-
- return JOB_REQUEUE_FAIR;
-}
-
-/**
- * initialize and open stroke socket
- */
-static bool open_socket(private_stroke_socket_t *this)
-{
- struct sockaddr_un socket_addr;
- mode_t old;
-
- socket_addr.sun_family = AF_UNIX;
- strcpy(socket_addr.sun_path, STROKE_SOCKET);
-
- /* set up unix socket */
- this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (this->socket == -1)
- {
- DBG1(DBG_CFG, "could not create stroke socket");
- return FALSE;
- }
-
- unlink(socket_addr.sun_path);
- old = umask(~(S_IRWXU | S_IRWXG));
- if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
- {
- DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
- close(this->socket);
- return FALSE;
- }
- umask(old);
- if (chown(socket_addr.sun_path, charon->uid, charon->gid) != 0)
- {
- DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
- strerror(errno));
- }
-
- if (listen(this->socket, 10) < 0)
- {
- DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
- close(this->socket);
- unlink(socket_addr.sun_path);
- return FALSE;
- }
- return TRUE;
+ return FALSE;
}
METHOD(stroke_socket_t, destroy, void,
private_stroke_socket_t *this)
{
- this->handler->cancel(this->handler);
- this->receiver->cancel(this->receiver);
- this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy);
- this->condvar->destroy(this->condvar);
- this->mutex->destroy(this->mutex);
+ DESTROY_IF(this->service);
lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
charon->backends->remove_backend(charon->backends, &this->config->backend);
hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider);
+ hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
+ charon->bus->remove_listener(charon->bus, &this->counter->listener);
this->cred->destroy(this->cred);
this->ca->destroy(this->ca);
this->config->destroy(this->config);
this->attribute->destroy(this->attribute);
+ this->handler->destroy(this->handler);
this->control->destroy(this->control);
this->list->destroy(this->list);
+ this->counter->destroy(this->counter);
free(this);
}
@@ -805,6 +718,8 @@ METHOD(stroke_socket_t, destroy, void,
stroke_socket_t *stroke_socket_create()
{
private_stroke_socket_t *this;
+ int max_concurrent;
+ char *uri;
INIT(this,
.public = {
@@ -812,38 +727,36 @@ stroke_socket_t *stroke_socket_create()
},
);
- if (!open_socket(this))
- {
- free(this);
- return NULL;
- }
-
this->cred = stroke_cred_create();
this->attribute = stroke_attribute_create();
+ this->handler = stroke_handler_create();
this->ca = stroke_ca_create(this->cred);
- this->config = stroke_config_create(this->ca, this->cred);
+ this->config = stroke_config_create(this->ca, this->cred, this->attribute);
this->control = stroke_control_create();
this->list = stroke_list_create(this->attribute);
-
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
- this->commands = linked_list_create();
- this->max_concurrent = lib->settings->get_int(lib->settings,
- "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT);
+ this->counter = stroke_counter_create();
lib->credmgr->add_set(lib->credmgr, &this->ca->set);
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
-
- this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive,
- this, NULL, NULL, JOB_PRIO_CRITICAL);
- lib->processor->queue_job(lib->processor, (job_t*)this->receiver);
-
- this->handler = callback_job_create_with_prio((callback_job_cb_t)handle,
- this, NULL, NULL, JOB_PRIO_CRITICAL);
- lib->processor->queue_job(lib->processor, (job_t*)this->handler);
+ hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
+ charon->bus->add_listener(charon->bus, &this->counter->listener);
+
+ max_concurrent = lib->settings->get_int(lib->settings,
+ "%s.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT,
+ charon->name);
+ uri = lib->settings->get_str(lib->settings,
+ "%s.plugins.stroke.socket", "unix://" STROKE_SOCKET, charon->name);
+ this->service = lib->streams->create_service(lib->streams, uri, 10);
+ if (!this->service)
+ {
+ DBG1(DBG_CFG, "creating stroke socket failed");
+ destroy(this);
+ return NULL;
+ }
+ this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
+ this, JOB_PRIO_CRITICAL, max_concurrent);
return &this->public;
}
-