diff options
| author | Yves-Alexis Perez <corsac@debian.org> | 2013-10-17 21:23:38 +0200 |
|---|---|---|
| committer | Yves-Alexis Perez <corsac@debian.org> | 2013-10-17 21:23:38 +0200 |
| commit | 9d37ad77ef660b92ea51b69d74e14f931d2a04e2 (patch) | |
| tree | d6bbb4a5fed1959f8675df9ee7c03713b543fcc9 /src/libcharon/plugins/stroke | |
| parent | 104f57d4b0fb6d7547d6898352eaa5fb4b222010 (diff) | |
| parent | e5ee4e7fcdd58b7d86bf1b458da2c63e8e19627b (diff) | |
| download | vyos-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.am | 16 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/Makefile.in | 168 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_attribute.c | 282 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_attribute.h | 23 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_ca.c | 12 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 687 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.h | 4 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_control.c | 187 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_counter.c | 464 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_counter.h | 112 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.c | 536 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.h | 9 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_handler.c | 231 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_handler.h | 64 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.c | 168 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_plugin.c | 46 | ||||
| -rw-r--r-- | src/libcharon/plugins/stroke/stroke_socket.c | 441 |
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, ¤t)) { - 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**)§ion)) { - 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; } - |
