diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-07-10 12:47:56 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-07-10 12:47:56 +0000 |
commit | eb841c5ef668a48782ef1154fda65cb6048f5885 (patch) | |
tree | 00dd0cb4313bf2291d94ed511fe51f0b4bc7ea7a /src/charon/plugins | |
parent | 738206039047924ae7e4762a53d121be1ca43000 (diff) | |
download | vyos-strongswan-eb841c5ef668a48782ef1154fda65cb6048f5885.tar.gz vyos-strongswan-eb841c5ef668a48782ef1154fda65cb6048f5885.zip |
- Updated to new upstream.
Diffstat (limited to 'src/charon/plugins')
105 files changed, 22539 insertions, 0 deletions
diff --git a/src/charon/plugins/eap_aka/Makefile.am b/src/charon/plugins/eap_aka/Makefile.am new file mode 100644 index 000000000..e1ad1eaf9 --- /dev/null +++ b/src/charon/plugins/eap_aka/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-eapaka.la + +libstrongswan_eapaka_la_SOURCES = eap_aka_plugin.h eap_aka_plugin.c eap_aka.h eap_aka.c +libstrongswan_eapaka_la_LDFLAGS = -module +libstrongswan_eapaka_la_LIBADD = -lgmp + diff --git a/src/charon/plugins/eap_aka/Makefile.in b/src/charon/plugins/eap_aka/Makefile.in new file mode 100644 index 000000000..ad28b0247 --- /dev/null +++ b/src/charon/plugins/eap_aka/Makefile.in @@ -0,0 +1,496 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/eap_aka +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_eapaka_la_DEPENDENCIES = +am_libstrongswan_eapaka_la_OBJECTS = eap_aka_plugin.lo eap_aka.lo +libstrongswan_eapaka_la_OBJECTS = \ + $(am_libstrongswan_eapaka_la_OBJECTS) +libstrongswan_eapaka_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_eapaka_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_eapaka_la_SOURCES) +DIST_SOURCES = $(libstrongswan_eapaka_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-eapaka.la +libstrongswan_eapaka_la_SOURCES = eap_aka_plugin.h eap_aka_plugin.c eap_aka.h eap_aka.c +libstrongswan_eapaka_la_LDFLAGS = -module +libstrongswan_eapaka_la_LIBADD = -lgmp +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/eap_aka/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/eap_aka/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-eapaka.la: $(libstrongswan_eapaka_la_OBJECTS) $(libstrongswan_eapaka_la_DEPENDENCIES) + $(libstrongswan_eapaka_la_LINK) -rpath $(plugindir) $(libstrongswan_eapaka_la_OBJECTS) $(libstrongswan_eapaka_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_aka.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_aka_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/eap_aka/eap_aka.c b/src/charon/plugins/eap_aka/eap_aka.c new file mode 100644 index 000000000..9e35de9e1 --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka.c @@ -0,0 +1,1539 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_aka.c 4008 2008-05-23 15:49:43Z martin $ + */ + + +/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA + * payloads, as the IKEv2 parser is not suitable for that job. There are + * two simple methods for parsing payloads, read_header() and read_attribute(). + * Every EAP-AKA payload consists of a header and a list of attributes. Those + * functions mentioned read the data and return the type of the found + * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a + * build_aka_payload(), which builds the whole message from a variable + * argument list containing its attributes. + * The processing of messages is split up in various functions: + * - peer_process() - General processing multiplexer for the peer + * - peer_process_challenge() - Specific AKA-Challenge processor + * - peer_process_notification() - Processing of AKA-Notification + * - server_process() - General processing multiplexer for the server + * - peer_process_challenge() - Processing of a received Challenge response + * - peer_process_synchronize() - Process a sequence number synchronization + * - server_initiate() - Initiation method for the server, calls + * - server_initiate_challenge() - Initiation of AKA-Challenge + */ + +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> +#include <gmp.h> + +#include "eap_aka.h" + +#include <daemon.h> +#include <library.h> +#include <crypto/hashers/hasher.h> + +/* Use test vectors specified in S.S0055 +#define TEST_VECTORS */ + +#define RAND_LENGTH 16 +#define RES_LENGTH 16 +#define SQN_LENGTH 6 +#define K_LENGTH 16 +#define MAC_LENGTH 8 +#define CK_LENGTH 16 +#define IK_LENGTH 16 +#define AK_LENGTH 6 +#define AMF_LENGTH 2 +#define FMK_LENGTH 4 +#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) +#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) +#define PAYLOAD_LENGTH 64 +#define MK_LENGTH 20 +#define MSK_LENGTH 64 +#define EMSK_LENGTH 64 +#define KAUTH_LENGTH 16 +#define KENCR_LENGTH 16 +#define AT_MAC_LENGTH 16 + +#define F1 0x42 +#define F1STAR 0x43 +#define F2 0x44 +#define F3 0x45 +#define F4 0x46 +#define F5 0x47 +#define F5STAR 0x48 + +typedef enum aka_subtype_t aka_subtype_t; +typedef enum aka_attribute_t aka_attribute_t; + +/** + * Subtypes of AKA messages + */ +enum aka_subtype_t { + AKA_CHALLENGE = 1, + AKA_AUTHENTICATION_REJECT = 2, + AKA_SYNCHRONIZATION_FAILURE = 4, + AKA_IDENTITY = 5, + AKA_NOTIFICATION = 12, + AKA_REAUTHENTICATION = 13, + AKA_CLIENT_ERROR = 14, +}; + +/** + * Attribute types in AKA messages + */ +enum aka_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY, + "AKA_CHALLENGE", + "AKA_AUTHENTICATION_REJECT", + "AKA_3", + "AKA_SYNCHRONIZATION_FAILURE", + "AKA_IDENTITY"); +ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY, + "AKA_NOTIFICATION", + "AKA_REAUTHENTICATION", + "AKA_CLIENT_ERROR"); +ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR); + + +ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(aka_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_aka_t private_eap_aka_t; + +/** + * Private data of an eap_aka_t object. + */ +struct private_eap_aka_t { + + /** + * Public authenticator_t interface. + */ + eap_aka_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * SHA11 hasher + */ + hasher_t *sha1; + + /** + * MAC function used in EAP-AKA + */ + signer_t *signer; + + /** + * pseudo random function used in EAP-aka + */ + prf_t *prf; + + /** + * Special keyed SHA1 hasher used in EAP-AKA, implemented as PRF + */ + prf_t *keyed_prf; + + /** + * Key for EAP MAC + */ + chunk_t k_auth; + + /** + * Key for EAP encryption + */ + chunk_t k_encr; + + /** + * MSK + */ + chunk_t msk; + + /** + * Extendend MSK + */ + chunk_t emsk; + + /** + * Expected result from client XRES + */ + chunk_t xres; + + /** + * Shared secret K from ipsec.conf (padded) + */ + chunk_t k; + + /** + * random value RAND generated by server + */ + chunk_t rand; +}; + +/** Family key, as proposed in S.S0055 */ +static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47}; +static chunk_t fmk = chunk_from_buf(fmk_buf); + +/** Authentication management field */ +static u_int8_t amf_buf[] = {0x00, 0x01}; +static chunk_t amf = chunk_from_buf(amf_buf); + +/** AT_CLIENT_ERROR_CODE AKA attribute */ +static u_int8_t client_error_code_buf[] = {0, 0}; +static chunk_t client_error_code = chunk_from_buf(client_error_code_buf); + +/** previously used sqn by peer, next one must be greater */ +static u_int8_t peer_sqn_buf[6]; +static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); + +/** set SQN to the current time */ +static void update_sqn(u_int8_t *sqn, time_t offset) +{ + timeval_t time; + gettimeofday(&time, NULL); + /* set sqb_sqn to an integer containing seconds followed by most + * significant useconds */ + time.tv_sec = htonl(time.tv_sec + offset); + /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */ + time.tv_usec <<= 12; + time.tv_usec = htonl(time.tv_usec); + memcpy(sqn, &time.tv_sec, 4); + memcpy(sqn + 4, &time.tv_usec, 2); +} + +/** initialize peers SQN to the current system time at startup */ +static void __attribute__ ((constructor))init_sqn(void) +{ + update_sqn(peer_sqn_buf, 0); +} + +/** + * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 + */ +static u_int8_t g[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t a[] = { + 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, + 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, + 0x3f, 0x4c, 0x63, 0x65 +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t b[] = { + 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, + 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, + 0x7e, 0xec, 0x45, 0xe0 +}; + +/** + * Multiplicate two mpz_t with bits interpreted as polynoms. + */ +static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) +{ + mpz_t bm, rm; + int current = 0, shifted = 0, shift; + + mpz_init_set(bm, b); + mpz_init_set_ui(rm, 0); + /* scan through a, for each found bit: */ + while ((current = mpz_scan1(a, current)) != ULONG_MAX) + { + /* XOR shifted b into r */ + shift = current - shifted; + mpz_mul_2exp(bm, bm, shift); + shifted += shift; + mpz_xor(rm, rm, bm); + current++; + } + + mpz_swap(r, rm); + mpz_clear(rm); + mpz_clear(bm); +} + +/** + * Calculate the sum of a + b interpreted as polynoms. + */ +static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) +{ + /* addition of polynominals is just the XOR */ + mpz_xor(res, a, b); +} + +/** + * Calculate the remainder of a/b interpreted as polynoms. + */ +static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) +{ + /* Example: + * a = 10001010 + * b = 00000101 + */ + int a_bit, b_bit, diff; + mpz_t bm, am; + + mpz_init_set(am, a); + mpz_init(bm); + + a_bit = mpz_sizeinbase(a, 2); + b_bit = mpz_sizeinbase(b, 2); + + /* don't do anything if b > a */ + if (a_bit >= b_bit) + { + /* shift b left to align up most signaficant "1" to a: + * a = 10001010 + * b = 10100000 + */ + mpz_mul_2exp(bm, b, a_bit - b_bit); + do + { + /* XOR b into a, this kills the most significant "1": + * a = 00101010 + */ + mpz_xor(am, am, bm); + /* find the next most significant "1" in a, and align up b: + * a = 00101010 + * b = 00101000 + */ + diff = a_bit - mpz_sizeinbase(am, 2); + mpz_div_2exp(bm, bm, diff); + a_bit -= diff; + } + while (b_bit <= mpz_sizeinbase(bm, 2)); + /* While b is not shifted to its original value */ + } + /* after another iteration: + * a = 00000010 + * which is the polynomial modulo + */ + + mpz_swap(r, am); + mpz_clear(am); + mpz_clear(bm); +} + +/** + * Step 4 of the various fx() functions: + * Polynomial whiten calculations + */ +static void step4(private_eap_aka_t *this, u_int8_t x[]) +{ + mpz_t xm, am, bm, gm; + + mpz_init(xm); + mpz_init(am); + mpz_init(bm); + mpz_init(gm); + + mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); + mpz_import(am, sizeof(a), 1, 1, 1, 0, a); + mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); + mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); + + mpz_mul_poly(xm, am, xm); + mpz_add_poly(xm, bm, xm); + mpz_mod_poly(xm, xm, gm); + + mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); + + mpz_clear(xm); + mpz_clear(am); + mpz_clear(bm); + mpz_clear(gm); +} + +/** + * Step 3 of the various fx() functions: + * XOR the key into the SHA1 IV + */ +static void step3(private_eap_aka_t *this, + chunk_t k, chunk_t payload, u_int8_t h[]) +{ + u_int8_t buf[64]; + + if (payload.len < sizeof(buf)) + { + /* pad c with zeros */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, payload.ptr, payload.len); + payload.ptr = buf; + payload.len = sizeof(buf); + } + else + { + /* not more than 512 bits can be G()-ed */ + payload.len = sizeof(buf); + } + + /* use the keyed hasher to build the hash */ + this->keyed_prf->set_key(this->keyed_prf, k); + this->keyed_prf->get_bytes(this->keyed_prf, payload, h); +} + +/** + * Calculation function for f2(), f3(), f4() + */ +static void fx(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + u_int8_t i; + + for (i = 0; i < 2; i++) + { + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 24, rand.ptr, rand.len); + + payload.ptr[3] ^= i; + payload.ptr[19] ^= i; + payload.ptr[35] ^= i; + payload.ptr[51] ^= i; + + step3(this, k, payload, h); + step4(this, h); + memcpy(out + i * 8, h, 8); + } +} + +/** + * Calculation function of f1() and f1star() + */ +static void f1x(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + /* generate MAC = f1(FMK, SQN, RAND, AMF) + * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit + * payload which gets hashed + */ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + memxor(payload.ptr + 34, sqn.ptr, sqn.len); + memxor(payload.ptr + 42, amf.ptr, amf.len); + + step3(this, k, payload, h); + step4(this, h); + memcpy(mac, h, MAC_LENGTH); +} + +/** + * Calculation function of f5() and f5star() + */ +static void f5x(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + + step3(this, k, payload, h); + step4(this, h); + memcpy(ak, h, AK_LENGTH); +} + +/** + * Calculate the MAC from a RAND, SQN, AMF value using K + */ +static void f1(private_eap_aka_t *this, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + f1x(this, F1, k, rand, sqn, amf, mac); + DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH); +} + +/** + * Calculate the MACS from a RAND, SQN, AMF value using K + */ +static void f1star(private_eap_aka_t *this, chunk_t k, chunk_t rand, + chunk_t sqn, chunk_t amf, u_int8_t macs[]) +{ + f1x(this, F1STAR, k, rand, sqn, amf, macs); + DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH); +} + +/** + * Calculate RES from RAND using K + */ +static void f2(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t res[]) +{ + fx(this, F2, k, rand, res); + DBG3(DBG_IKE, "RES %b", res, RES_LENGTH); +} + +/** + * Calculate CK from RAND using K + */ +static void f3(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ck[]) +{ + fx(this, F3, k, rand, ck); + DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH); +} + +/** + * Calculate IK from RAND using K + */ +static void f4(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ik[]) +{ + fx(this, F4, k, rand, ik); + DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH); +} + +/** + * Calculate AK from a RAND using K + */ +static void f5(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + f5x(this, F5, k, rand, ak); + DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH); +} + +/** + * Calculate AKS from a RAND using K + */ +static void f5star(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t aks[]) +{ + f5x(this, F5STAR, k, rand, aks); + DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH); +} + +/** + * derive the keys needed for EAP_AKA + */ +static bool derive_keys(private_eap_aka_t *this, identification_t *id) +{ + chunk_t ck, ik, mk, identity, tmp; + + ck = chunk_alloca(CK_LENGTH); + ik = chunk_alloca(IK_LENGTH); + mk = chunk_alloca(MK_LENGTH); + identity = id->get_encoding(id); + + /* MK = SHA1( Identity | IK | CK ) */ + f3(this, this->k, this->rand, ck.ptr); + f4(this, this->k, this->rand, ik.ptr); + DBG3(DBG_IKE, "Identity %B", &identity); + tmp = chunk_cata("ccc", identity, ik, ck); + DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); + this->sha1->get_hash(this->sha1, tmp, mk.ptr); + + /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + this->prf->set_key(this->prf, mk); + tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 4); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth, + 64, &this->msk, 64, &this->emsk); + DBG3(DBG_IKE, "MK %B", &mk); + DBG3(DBG_IKE, "PRF res %B", &tmp); + DBG3(DBG_IKE, "K_encr %B", &this->k_encr); + DBG3(DBG_IKE, "K_auth %B", &this->k_auth); + DBG3(DBG_IKE, "MSK %B", &this->msk); + DBG3(DBG_IKE, "EMSK %B", &this->emsk); + return TRUE; +} + +/* + * Get a shared key from ipsec.secrets. + * We use the standard keys as used in preshared key authentication. As + * these keys have an undefined length, we: + * - strip them if they are longer + * - fill them up with '\0' if they are shorter + */ +static status_t load_key(identification_t *me, identification_t *other, chunk_t *k) +{ + shared_key_t *shared; + chunk_t key; + + shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP, + me, other); + if (shared == NULL) + { + return NOT_FOUND; + } + key = shared->get_key(shared); + chunk_free(k); + *k = chunk_alloc(K_LENGTH); + memset(k->ptr, '\0', k->len); + memcpy(k->ptr, key.ptr, min(key.len, k->len)); + shared->destroy(shared); + return SUCCESS; +} + +/** + * skip EAP_AKA header in message and returns its AKA subtype + */ +static aka_subtype_t read_header(chunk_t *message) +{ + aka_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) +{ + aka_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", data); + + if (data->len < 2) + { + return AT_END; + } + /* read attribute and length */ + attribute = *data->ptr++; + length = *data->ptr++ * 4 - 2; + data->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + aka_attribute_names, attribute, length); + if (length > data->len) + { + return AT_END; + } + /* apply attribute value to attr_data */ + attr_data->len = length; + attr_data->ptr = data->ptr; + /* update data to point to next attribute */ + *data = chunk_skip(*data, length); + return attribute; +} + +/** + * Build an AKA payload from different attributes. + * The variable argument takes an aka_attribute_t + * followed by its data in a chunk. + */ +static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code, + u_int8_t identifier, aka_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); /* is enought for all current messages */ + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + aka_attribute_t attr; + u_int8_t *mac_pos = NULL; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = code; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write AKA header with type and subtype, null reserved bytes */ + *pos.ptr++ = EAP_AKA; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, aka_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_RES: + { + /* attribute length in 4byte words */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* RES length in bits */ + *(u_int16_t*)pos.ptr = htons(data.len * 8); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_AUTN: + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + /* MAC is calculated over message including zeroed AT_MAC attribute */ + memset(mac_pos, 0, AT_MAC_LENGTH); + pos.ptr += AT_MAC_LENGTH; + pos.len -= AT_MAC_LENGTH; + break; + } + default: + { + /* length is data length in 4-bytes + 1 for header */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + } + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included */ + if (mac_pos) + { + this->signer->set_key(this->signer, this->k_auth); + DBG3(DBG_IKE, "AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + this->signer->get_signature(this->signer, message, mac_pos); + DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); + } + + /* payload constructor takes data with some bytes skipped */ + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * Initiate a AKA-Challenge using SQN + */ +static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, + eap_payload_t **out) +{ + rng_t *rng; + chunk_t mac, ak, autn; + + mac = chunk_alloca(MAC_LENGTH); + ak = chunk_alloca(AK_LENGTH); + chunk_free(&this->rand); + chunk_free(&this->xres); + + /* generate RAND: + * we use a registered RNG, not f0() proposed in S.S0055 + */ + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed"); + return FAILED; + } + rng->allocate_bytes(rng, RAND_LENGTH, &this->rand); + rng->destroy(rng); + +# ifdef TEST_VECTORS + /* Test vector for RAND */ + u_int8_t test_rand[] = { + 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, + 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, + }; + memcpy(this->rand.ptr, test_rand, this->rand.len); +# endif /* TEST_VECTORS */ + + /* Get the shared key K: */ + if (load_key(this->server, this->peer, &this->k) != SUCCESS) + { + DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA", this->server, this->peer); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* generate MAC */ + f1(this, this->k, this->rand, sqn, amf, mac.ptr); + + /* generate AK */ + f5(this, this->k, this->rand, ak.ptr); + + /* precalculate XRES as expected from client */ + this->xres = chunk_alloc(RES_LENGTH); + f2(this, this->k, this->rand, this->xres.ptr); + + /* calculate AUTN = (SQN xor AK) || AMF || MAC */ + autn = chunk_cata("ccc", sqn, amf, mac); + memxor(autn.ptr, ak.ptr, ak.len); + DBG3(DBG_IKE, "AUTN %B", &autn); + + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* build payload */ + *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE, + AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, + chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.initiate for an EAP_AKA server + */ +static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + chunk_t sqn = chunk_alloca(SQN_LENGTH); + + /* we use an offset of 3 minutes to tolerate clock inaccuracy + * without the need to synchronize sequence numbers */ + update_sqn(sqn.ptr, 180); + +# ifdef TEST_VECTORS + /* Test vector for SQN */ + u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; + memcpy(sqn.ptr, test_sqn, sqn.len); +# endif /* TEST_VECTORS */ + + return server_initiate_challenge(this, sqn, out); +} + +static status_t server_process_synchronize(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; + u_int i; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_AUTS: + auts = attr; + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (auts.len != AUTS_LENGTH) + { + DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); + return FAILED; + } + + chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); + aks = chunk_alloca(AK_LENGTH); + f5star(this, this->k, this->rand, aks.ptr); + /* decrypt serial number by XORing AKS */ + memxor(sqn.ptr, aks.ptr, aks.len); + + /* verify MACS */ + xmacs = chunk_alloca(MAC_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + /* an AMF of zero is used for MACS calculation */ + memset(amf.ptr, 0, amf.len); + f1star(this, this->k, this->rand, sqn, amf, xmacs.ptr); + if (!chunk_equals(macs, xmacs)) + { + DBG1(DBG_IKE, "received MACS does not match XMACS"); + DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); + return FAILED; + } + + /* retry the challenge with the received SQN + 1*/ + for (i = SQN_LENGTH - 1; i >= 0; i--) + { + if (++sqn.ptr[i] != 0) + { + break; + } + } + return server_initiate_challenge(this, sqn, out); +} + +/** + * process an AKA_Challenge response + */ +static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) +{ + chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RES: + res = attr; + if (attr.len == 2 + RES_LENGTH && + *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8)) + { + res = chunk_skip(attr, 2); + } + continue; + + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* zero MAC in message for MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + /* verify EAP message MAC AT_MAC */ + { + this->signer->set_key(this->signer, this->k_auth); + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + if (!this->signer->verify_signature(this->signer, message, at_mac)) + { + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed"); + return FAILED; + } + } + + /* compare received RES against stored precalculated XRES */ + if (!chunk_equals(res, this->xres)) + { + DBG1(DBG_IKE, "received RES does not match XRES"); + DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of eap_method_t.process for EAP_AKA servers + */ +static status_t server_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message; + aka_subtype_t type; + + message = in->get_data(in); + type = read_header(&message); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return server_process_challenge(this, in); + } + case AKA_AUTHENTICATION_REJECT: + case AKA_CLIENT_ERROR: + { + DBG1(DBG_IKE, "received %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } + case AKA_SYNCHRONIZATION_FAILURE: + { + DBG1(DBG_IKE, "received %N, retrying with received SQN", + aka_subtype_names, type); + return server_process_synchronize(this, in, out); + } + default: + DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } +} + +/** + * Process an incoming AKA-Challenge client side + */ +static status_t peer_process_challenge(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr = chunk_empty; + chunk_t autn = chunk_empty, at_mac = chunk_empty; + chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; + u_int8_t identifier; + + ak = chunk_alloca(AK_LENGTH); + xmac = chunk_alloca(MAC_LENGTH); + res = chunk_alloca(RES_LENGTH); + chunk_free(&this->rand); + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RAND: + this->rand = chunk_clone(chunk_skip(attr, 2)); + continue; + case AT_AUTN: + autn = chunk_skip(attr, 2); + continue; + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* set MAC in message to zero for own MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + /* non skippable attribute, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d", + aka_attribute_names, attribute, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) + { + /* required attributes wrong/not found, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d", + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + + DBG3(DBG_IKE, "using autn %B", &autn); + /* split up AUTN = SQN xor AK | AMF | MAC */ + chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); + + /* Get the shared key K: */ + chunk_free(&this->k); + if (load_key(this->peer, this->server, &this->k) != SUCCESS) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA, sending %N", this->peer, this->server, + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + return NEED_MORE; + } + DBG3(DBG_IKE, "using K %B", &this->k); +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* calculate anonymity key AK */ + f5(this, this->k, this->rand, ak.ptr); + DBG3(DBG_IKE, "using rand %B", &this->rand); + DBG3(DBG_IKE, "using ak %B", &ak); + /* XOR AK into SQN to decrypt it */ + + sqn = chunk_clonea(sqn_ak); + + DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak); + memxor(sqn.ptr, ak.ptr, sqn.len); + DBG3(DBG_IKE, "using sqn %B", &sqn); + + /* calculate expected MAC and compare against received one */ + f1(this, this->k, this->rand, sqn, amf, xmac.ptr); + if (!chunk_equals(mac, xmac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N", + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac); + return NEED_MORE; + } + +#if SEQ_CHECK + if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0) + { + /* sequence number invalid. send AUTS */ + chunk_t auts, macs, aks, amf; + + macs = chunk_alloca(MAC_LENGTH); + aks = chunk_alloca(AK_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + + /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ + memset(amf.ptr, 0, amf.len); + /* AKS = f5*(RAND) */ + f5star(this, this->k, this->rand, aks.ptr); + /* MACS = f1*(RAND) */ + f1star(this, this->k, this->rand, peer_sqn, amf, macs.ptr); + /* AUTS = SQN xor AKS | MACS */ + memxor(aks.ptr, peer_sqn.ptr, aks.len); + auts = chunk_cata("cc", aks, macs); + + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_SYNCHRONIZATION_FAILURE, + AT_AUTS, auts, AT_END); + DBG1(DBG_IKE, "received SQN invalid, sending %N", + aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); + DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn); + return NEED_MORE; + } +#endif /* SEQ_CHECK */ + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* verify EAP message MAC AT_MAC */ + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + this->signer->set_key(this->signer, this->k_auth); + if (!this->signer->verify_signature(this->signer, message, at_mac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification " + "failed, sending %N %d", aka_attribute_names, + AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + + /* update stored SQN to the received one */ + memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); + + /* calculate RES */ + f2(this, this->k, this->rand, res.ptr); + + /* build response */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, + AT_RES, res, AT_MAC, chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Process an incoming AKA-Notification as client + */ +static status_t peer_process_notification(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, pos, attr; + u_int8_t identifier; + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_NOTIFICATION: + { + u_int16_t code; + + if (attr.len != 2) + { + DBG1(DBG_IKE, "received invalid AKA notification, ignored"); + continue; + } + code = ntohs(*(u_int16_t*)attr.ptr); + switch (code) + { + case 0: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure after authentication' (%d)", code); + return FAILED; + case 16384: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure' (%d)", code); + return FAILED; + case 32768: + DBG1(DBG_IKE, "received AKA notification 'successfully " + "authenticated' (%d)", code); + continue; + case 1026: + DBG1(DBG_IKE, "received AKA notification 'access " + "temporarily denied' (%d)", code); + return FAILED; + case 1031: + DBG1(DBG_IKE, "received AKA notification 'not " + "subscribed to service' (%d)", code); + return FAILED; + default: + DBG1(DBG_IKE, "received AKA notification code %d, " + "ignored", code); + continue; + } + } + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N", + aka_attribute_names, attribute, aka_subtype_names, + AKA_NOTIFICATION); + } + else + { + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + } + continue; + } + break; + } + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for an EAP_AKA peer + */ +static status_t peer_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + aka_subtype_t type; + chunk_t message; + u_int8_t identifier; + + message = in->get_data(in); + type = read_header(&message); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return peer_process_challenge(this, in, out); + } + case AKA_NOTIFICATION: + { + return peer_process_notification(this, in, out); + } + default: + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "received unsupported %N request, sending %N %d", + aka_subtype_names, type, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } +} + +/** + * Implementation of eap_method_t.initiate for an EAP AKA peer + */ +static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_AKA; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_aka_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_aka_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_aka_t *this) +{ + DESTROY_IF(this->sha1); + DESTROY_IF(this->signer); + DESTROY_IF(this->prf); + DESTROY_IF(this->keyed_prf); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_free(&this->xres); + chunk_free(&this->k); + chunk_free(&this->rand); + free(this); +} + +/** + * generic constructor used by client & server + */ +static private_eap_aka_t *eap_aka_create_generic(identification_t *server, + identification_t *peer) +{ + private_eap_aka_t *this = malloc_thing(private_eap_aka_t); + + this->public.eap_method_interface.initiate = NULL; + this->public.eap_method_interface.process = NULL; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->server = server; + this->peer = peer; + this->k_encr = chunk_empty; + this->k_auth = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->xres = chunk_empty; + this->k = chunk_empty; + this->rand = chunk_empty; + + this->sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128); + this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + this->keyed_prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1); + + if (!this->sha1 || !this->signer || !this->prf || !this->keyed_prf) + { + DBG1(DBG_IKE, "unable to initiate EAP-AKA, FIPS-PRF/SHA1 not supported"); + DESTROY_IF(this->sha1); + DESTROY_IF(this->signer); + DESTROY_IF(this->prf); + DESTROY_IF(this->keyed_prf); + destroy(this); + return NULL; + } + return this; +} + +/* + * Described in header. + */ +eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = eap_aka_create_generic(server, peer); + + if (this) + { + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + } + return (eap_aka_t*)this; +} + +/* + * Described in header. + */ +eap_aka_t *eap_aka_create_peer(identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = eap_aka_create_generic(server, peer); + + if (this) + { + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + } + return (eap_aka_t*)this; +} + diff --git a/src/charon/plugins/eap_aka/eap_aka.h b/src/charon/plugins/eap_aka/eap_aka.h new file mode 100644 index 000000000..118f2c44f --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_aka.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_aka_i eap_aka + * @{ @ingroup eap_aka + */ + +#ifndef EAP_AKA_H_ +#define EAP_AKA_H_ + +typedef struct eap_aka_t eap_aka_t; + +#include <sa/authenticators/eap/eap_method.h> + +/** check SEQ values as client for validity, disabled by default */ +#ifndef SEQ_CHECK +# define SEQ_CHECK 0 +#endif + +/** + * Implementation of the eap_method_t interface using EAP-AKA. + * + * EAP-AKA uses 3rd generation mobile phone standard authentication + * mechanism for authentication. It is a mutual authentication + * mechanism which establishs a shared key and therefore supports EAP_ONLY + * authentication. This implementation follows the standard of the + * 3GPP2 (S.S0055) and not the one of 3GGP. + * The shared key used for authentication is from ipsec.secrets. The + * peers ID is used to query it. + * The AKA mechanism uses sequence numbers to detect replay attacks. The + * peer stores the sequence number normally in a USIM and accepts + * incremental sequence numbers (incremental for lifetime of the USIM). To + * prevent a complex sequence number management, this implementation uses + * a sequence number derived from time. It is initialized to the startup + * time of the daemon. As long as the (UTC) time of the system is not + * turned back while the daemon is not running, this method is secure. + * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept + * any SEQ numbers. This allows an attacker to do replay attacks. But since + * the server has proven his identity via IKE, such an attack is only + * possible between server and AAA (if any). + */ +struct eap_aka_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the server implementation of the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + */ +eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the peer implementation of the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + */ +eap_aka_t *eap_aka_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_AKA_H_ @}*/ diff --git a/src/charon/plugins/eap_aka/eap_aka_plugin.c b/src/charon/plugins/eap_aka/eap_aka_plugin.c new file mode 100644 index 000000000..5c15b6d7e --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_aka_plugin.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "eap_aka_plugin.h" + +#include "eap_aka.h" + +#include <daemon.h> + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_aka_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_aka_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_aka_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_aka_plugin_t *this = malloc_thing(eap_aka_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_AKA, 0, EAP_SERVER, + (eap_constructor_t)eap_aka_create_server); + charon->eap->add_method(charon->eap, EAP_AKA, 0, EAP_PEER, + (eap_constructor_t)eap_aka_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_aka/eap_aka_plugin.h b/src/charon/plugins/eap_aka/eap_aka_plugin.h new file mode 100644 index 000000000..506d47f98 --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_aka_plugin.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_aka eap_aka + * @ingroup cplugins + * + * @defgroup eap_aka_plugin eap_aka_plugin + * @{ @ingroup eap_aka + */ + +#ifndef EAP_AKA_PLUGIN_H_ +#define EAP_AKA_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct eap_aka_plugin_t eap_aka_plugin_t; + +/** + * EAP-AKA plugin + */ +struct eap_aka_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_aka_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_AKA_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_identity/Makefile.am b/src/charon/plugins/eap_identity/Makefile.am new file mode 100644 index 000000000..dbf66e74b --- /dev/null +++ b/src/charon/plugins/eap_identity/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-eapidentity.la +libstrongswan_eapidentity_la_SOURCES = \ + eap_identity_plugin.h eap_identity_plugin.c eap_identity.h eap_identity.c +libstrongswan_eapidentity_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_identity/Makefile.in b/src/charon/plugins/eap_identity/Makefile.in new file mode 100644 index 000000000..37f3505f2 --- /dev/null +++ b/src/charon/plugins/eap_identity/Makefile.in @@ -0,0 +1,499 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/eap_identity +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_eapidentity_la_LIBADD = +am_libstrongswan_eapidentity_la_OBJECTS = eap_identity_plugin.lo \ + eap_identity.lo +libstrongswan_eapidentity_la_OBJECTS = \ + $(am_libstrongswan_eapidentity_la_OBJECTS) +libstrongswan_eapidentity_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_eapidentity_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_eapidentity_la_SOURCES) +DIST_SOURCES = $(libstrongswan_eapidentity_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-eapidentity.la +libstrongswan_eapidentity_la_SOURCES = \ + eap_identity_plugin.h eap_identity_plugin.c eap_identity.h eap_identity.c + +libstrongswan_eapidentity_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/eap_identity/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/eap_identity/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-eapidentity.la: $(libstrongswan_eapidentity_la_OBJECTS) $(libstrongswan_eapidentity_la_DEPENDENCIES) + $(libstrongswan_eapidentity_la_LINK) -rpath $(plugindir) $(libstrongswan_eapidentity_la_OBJECTS) $(libstrongswan_eapidentity_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_identity.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_identity_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/eap_identity/eap_identity.c b/src/charon/plugins/eap_identity/eap_identity.c new file mode 100644 index 000000000..0c90e8a04 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_identity.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "eap_identity.h" + +#include <daemon.h> +#include <library.h> + +typedef struct private_eap_identity_t private_eap_identity_t; + +/** + * Private data of an eap_identity_t object. + */ +struct private_eap_identity_t { + + /** + * Public authenticator_t interface. + */ + eap_identity_t public; + + /** + * ID of the peer + */ + identification_t *peer; +}; + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process(private_eap_identity_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t id, hdr; + + hdr = chunk_alloca(5); + id = this->peer->get_encoding(this->peer); + + *(hdr.ptr + 0) = EAP_RESPONSE; + *(hdr.ptr + 1) = in->get_identifier(in); + *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len); + *(hdr.ptr + 4) = EAP_IDENTITY; + + *out = eap_payload_create_data(chunk_cata("cc", hdr, id)); + return SUCCESS; + +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate(private_eap_identity_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_identity_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_IDENTITY; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_identity_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_identity_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_identity_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +eap_identity_t *eap_identity_create_peer(identification_t *server, + identification_t *peer) +{ + private_eap_identity_t *this = malloc_thing(private_eap_identity_t); + + /* public functions */ + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + + return &this->public; +} + diff --git a/src/charon/plugins/eap_identity/eap_identity.h b/src/charon/plugins/eap_identity/eap_identity.h new file mode 100644 index 000000000..9de89e6e3 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_identity.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_identity_i eap_identity + * @{ @ingroup eap_identity + */ + +#ifndef EAP_IDENTITY_H_ +#define EAP_IDENTITY_H_ + +typedef struct eap_identity_t eap_identity_t; + +#include <sa/authenticators/eap/eap_method.h> + +/** + * Implementation of the eap_method_t interface using EAP Identity. + */ +struct eap_identity_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP Identity, acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_identity_t object + */ +eap_identity_t *eap_identity_create_peer(identification_t *server, + identification_t *peer); + +#endif /* EAP_IDENTITY_H_ @}*/ diff --git a/src/charon/plugins/eap_identity/eap_identity_plugin.c b/src/charon/plugins/eap_identity/eap_identity_plugin.c new file mode 100644 index 000000000..38a19d784 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity_plugin.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_identity_plugin.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "eap_identity_plugin.h" + +#include "eap_identity.h" + +#include <daemon.h> + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_identity_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_identity_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_identity_plugin_t *this = malloc_thing(eap_identity_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_IDENTITY, 0, EAP_PEER, + (eap_constructor_t)eap_identity_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_identity/eap_identity_plugin.h b/src/charon/plugins/eap_identity/eap_identity_plugin.h new file mode 100644 index 000000000..d7fa525ce --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_identity_plugin.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_identity eap_identity + * @ingroup cplugins + * + * @defgroup eap_identity_plugin eap_identity_plugin + * @{ @ingroup eap_identity + */ + +#ifndef EAP_IDENTITY_PLUGIN_H_ +#define EAP_IDENTITY_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct eap_identity_plugin_t eap_identity_plugin_t; + +/** + * EAP-IDENTITY plugin. + */ +struct eap_identity_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_identity_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_IDENTITY_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_md5/Makefile.am b/src/charon/plugins/eap_md5/Makefile.am new file mode 100644 index 000000000..d7964fee9 --- /dev/null +++ b/src/charon/plugins/eap_md5/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-eapmd5.la + +libstrongswan_eapmd5_la_SOURCES = eap_md5_plugin.h eap_md5_plugin.c eap_md5.h eap_md5.c +libstrongswan_eapmd5_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_md5/Makefile.in b/src/charon/plugins/eap_md5/Makefile.in new file mode 100644 index 000000000..d48fb2c44 --- /dev/null +++ b/src/charon/plugins/eap_md5/Makefile.in @@ -0,0 +1,495 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/eap_md5 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_eapmd5_la_LIBADD = +am_libstrongswan_eapmd5_la_OBJECTS = eap_md5_plugin.lo eap_md5.lo +libstrongswan_eapmd5_la_OBJECTS = \ + $(am_libstrongswan_eapmd5_la_OBJECTS) +libstrongswan_eapmd5_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_eapmd5_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_eapmd5_la_SOURCES) +DIST_SOURCES = $(libstrongswan_eapmd5_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-eapmd5.la +libstrongswan_eapmd5_la_SOURCES = eap_md5_plugin.h eap_md5_plugin.c eap_md5.h eap_md5.c +libstrongswan_eapmd5_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/eap_md5/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/eap_md5/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-eapmd5.la: $(libstrongswan_eapmd5_la_OBJECTS) $(libstrongswan_eapmd5_la_DEPENDENCIES) + $(libstrongswan_eapmd5_la_LINK) -rpath $(plugindir) $(libstrongswan_eapmd5_la_OBJECTS) $(libstrongswan_eapmd5_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_md5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_md5_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/eap_md5/eap_md5.c b/src/charon/plugins/eap_md5/eap_md5.c new file mode 100644 index 000000000..990d64011 --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_md5.c 3806 2008-04-15 05:56:35Z martin $ + */ + +#include "eap_md5.h" + +#include <daemon.h> +#include <library.h> +#include <crypto/hashers/hasher.h> + +typedef struct private_eap_md5_t private_eap_md5_t; + +/** + * Private data of an eap_md5_t object. + */ +struct private_eap_md5_t { + + /** + * Public authenticator_t interface. + */ + eap_md5_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * challenge sent by the server + */ + chunk_t challenge; + + /** + * EAP message identififier + */ + u_int8_t identifier; +}; + +typedef struct eap_md5_header_t eap_md5_header_t; + +/** + * packed eap MD5 header struct + */ +struct eap_md5_header_t { + /** EAP code (REQUEST/RESPONSE) */ + u_int8_t code; + /** unique message identifier */ + u_int8_t identifier; + /** length of whole message */ + u_int16_t length; + /** EAP type */ + u_int8_t type; + /** length of value (challenge) */ + u_int8_t value_size; + /** actual value */ + u_int8_t value[]; +} __attribute__((__packed__)); + +#define CHALLENGE_LEN 16 +#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t)) + +/** + * Hash the challenge string, create response + */ +static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response) +{ + shared_key_t *shared; + chunk_t concat; + hasher_t *hasher; + + shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP, + this->server, this->peer); + if (shared == NULL) + { + DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", + this->server, this->peer); + return NOT_FOUND; + } + concat = chunk_cata("ccc", chunk_from_thing(this->identifier), + shared->get_key(shared), this->challenge); + shared->destroy(shared); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (hasher == NULL) + { + DBG1(DBG_IKE, "EAP-MD5 failed, MD5 not supported"); + return FAILED; + } + hasher->allocate_hash(hasher, concat, response); + hasher->destroy(hasher); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out) +{ + rng_t *rng; + eap_md5_header_t *req; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + return FAILED; + } + rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge); + rng->destroy(rng); + + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_REQUEST; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = this->challenge.len; + memcpy(req->value, this->challenge.ptr, this->challenge.len); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process_peer(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response; + chunk_t data; + eap_md5_header_t *req; + + this->identifier = in->get_identifier(in); + data = in->get_data(in); + this->challenge = chunk_clone(chunk_skip(data, 6)); + if (data.len < 6 || this->challenge.len < *(data.ptr + 5)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &response) != SUCCESS) + { + return FAILED; + } + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_RESPONSE; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = response.len; + memcpy(req->value, response.ptr, response.len); + chunk_free(&response); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t process_server(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response, expected; + chunk_t data; + + if (this->identifier != in->get_identifier(in)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &expected) != SUCCESS) + { + return FAILED; + } + data = in->get_data(in); + response = chunk_skip(data, 6); + + if (response.len < expected.len || + !memeq(response.ptr, expected.ptr, expected.len)) + { + chunk_free(&expected); + DBG1(DBG_IKE, "EAP-MD5 verification failed"); + return FAILED; + } + chunk_free(&expected); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_MD5; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_md5_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_md5_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_md5_t *this) +{ + chunk_free(&this->challenge); + free(this); +} + +/** + * Generic constructor + */ +static private_eap_md5_t *eap_md5_create_generic(identification_t *server, + identification_t *peer) +{ + private_eap_md5_t *this = malloc_thing(private_eap_md5_t); + + this->public.eap_method_interface.initiate = NULL; + this->public.eap_method_interface.process = NULL; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + this->server = server; + this->challenge = chunk_empty; + this->identifier = random(); + + return this; +} + +/* + * see header + */ +eap_md5_t *eap_md5_create_server(identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = eap_md5_create_generic(server, peer); + + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server; + + return &this->public; +} + +/* + * see header + */ +eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = eap_md5_create_generic(server, peer); + + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer; + + return &this->public; +} + diff --git a/src/charon/plugins/eap_md5/eap_md5.h b/src/charon/plugins/eap_md5/eap_md5.h new file mode 100644 index 000000000..421e1e602 --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_md5.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_md5_i eap_md5 + * @{ @ingroup eap_md5 + */ + +#ifndef EAP_MD5_H_ +#define EAP_MD5_H_ + +typedef struct eap_md5_t eap_md5_t; + +#include <sa/authenticators/eap/eap_method.h> + +/** + * Implementation of the eap_method_t interface using EAP-MD5 (CHAP). + */ +struct eap_md5_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP-MD5 acting as server. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + */ +eap_md5_t *eap_md5_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the EAP method EAP-MD5 acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + */ +eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_MD5_H_ @}*/ diff --git a/src/charon/plugins/eap_md5/eap_md5_plugin.c b/src/charon/plugins/eap_md5/eap_md5_plugin.c new file mode 100644 index 000000000..cb6a9bd7c --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_md5_plugin.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "eap_md5_plugin.h" + +#include "eap_md5.h" + +#include <daemon.h> + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_md5_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_md5_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_md5_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_md5_plugin_t *this = malloc_thing(eap_md5_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_MD5, 0, EAP_SERVER, + (eap_constructor_t)eap_md5_create_server); + charon->eap->add_method(charon->eap, EAP_MD5, 0, EAP_PEER, + (eap_constructor_t)eap_md5_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_md5/eap_md5_plugin.h b/src/charon/plugins/eap_md5/eap_md5_plugin.h new file mode 100644 index 000000000..d13794f2e --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_md5_plugin.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_md5 eap_md5 + * @ingroup cplugins + * + * @defgroup eap_md5_plugin eap_md5_plugin + * @{ @ingroup eap_md5 + */ + +#ifndef EAP_MD5_PLUGIN_H_ +#define EAP_MD5_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct eap_md5_plugin_t eap_md5_plugin_t; + +/** + * EAP-MD5 plugin + */ +struct eap_md5_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_md5_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_MD5_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_sim/Makefile.am b/src/charon/plugins/eap_sim/Makefile.am new file mode 100644 index 000000000..63267b9d3 --- /dev/null +++ b/src/charon/plugins/eap_sim/Makefile.am @@ -0,0 +1,13 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DSIM_READER_LIB=\"${simreader}\" + +plugin_LTLIBRARIES = libstrongswan-eapsim.la libeapsim-file.la + +libstrongswan_eapsim_la_SOURCES = eap_sim_plugin.h eap_sim_plugin.c eap_sim.h eap_sim.c +libstrongswan_eapsim_la_LDFLAGS = -module + +libeapsim_file_la_SOURCES = eap_sim_file.c +libeapsim_file_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_sim/Makefile.in b/src/charon/plugins/eap_sim/Makefile.in new file mode 100644 index 000000000..e70f8457c --- /dev/null +++ b/src/charon/plugins/eap_sim/Makefile.in @@ -0,0 +1,508 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/eap_sim +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libeapsim_file_la_LIBADD = +am_libeapsim_file_la_OBJECTS = eap_sim_file.lo +libeapsim_file_la_OBJECTS = $(am_libeapsim_file_la_OBJECTS) +libeapsim_file_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libeapsim_file_la_LDFLAGS) $(LDFLAGS) -o $@ +libstrongswan_eapsim_la_LIBADD = +am_libstrongswan_eapsim_la_OBJECTS = eap_sim_plugin.lo eap_sim.lo +libstrongswan_eapsim_la_OBJECTS = \ + $(am_libstrongswan_eapsim_la_OBJECTS) +libstrongswan_eapsim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_eapsim_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libeapsim_file_la_SOURCES) \ + $(libstrongswan_eapsim_la_SOURCES) +DIST_SOURCES = $(libeapsim_file_la_SOURCES) \ + $(libstrongswan_eapsim_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DSIM_READER_LIB=\"${simreader}\" +plugin_LTLIBRARIES = libstrongswan-eapsim.la libeapsim-file.la +libstrongswan_eapsim_la_SOURCES = eap_sim_plugin.h eap_sim_plugin.c eap_sim.h eap_sim.c +libstrongswan_eapsim_la_LDFLAGS = -module +libeapsim_file_la_SOURCES = eap_sim_file.c +libeapsim_file_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/eap_sim/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/eap_sim/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libeapsim-file.la: $(libeapsim_file_la_OBJECTS) $(libeapsim_file_la_DEPENDENCIES) + $(libeapsim_file_la_LINK) -rpath $(plugindir) $(libeapsim_file_la_OBJECTS) $(libeapsim_file_la_LIBADD) $(LIBS) +libstrongswan-eapsim.la: $(libstrongswan_eapsim_la_OBJECTS) $(libstrongswan_eapsim_la_DEPENDENCIES) + $(libstrongswan_eapsim_la_LINK) -rpath $(plugindir) $(libstrongswan_eapsim_la_OBJECTS) $(libstrongswan_eapsim_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim_file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/eap_sim/eap_sim.c b/src/charon/plugins/eap_sim/eap_sim.c new file mode 100644 index 000000000..b14076f34 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim.c @@ -0,0 +1,1149 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_sim.c 3806 2008-04-15 05:56:35Z martin $ + */ + +#include "eap_sim.h" + +#include <dlfcn.h> + +#include <daemon.h> +#include <library.h> + +#define MAX_TRIES 3 + +/* number of triplets for one authentication */ +#define TRIPLET_COUNT 3 + +typedef enum sim_subtype_t sim_subtype_t; + +/** + * Subtypes of SIM messages + */ +enum sim_subtype_t { + SIM_START = 10, + SIM_CHALLENGE = 11, + SIM_NOTIFICATION = 12, + SIM_CLIENT_ERROR = 14, +}; + +ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR, + "SIM_START", + "SIM_CHALLENGE", + "SIM_NOTIFICATION", + "SIM_13", + "SIM_CLIENT_ERROR", +); + +typedef enum sim_attribute_t sim_attribute_t; + +/** + * Attributes in SIM messages + */ +enum sim_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(sim_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_sim_t private_eap_sim_t; + +/** + * Private data of an eap_sim_t object. + */ +struct private_eap_sim_t { + + /** + * Public authenticator_t interface. + */ + eap_sim_t public; + + /** + * ID of ourself + */ + identification_t *peer; + + /** + * hashing function + */ + hasher_t *hasher; + + /** + * prf + */ + prf_t *prf; + + /** + * MAC function + */ + signer_t *signer; + + /** + * SIM cardreader function loaded from library + */ + sim_algo_t alg; + + /** + * libraries get_triplet() function returning a triplet + */ + sim_get_triplet_t get_triplet; + + /** + * handle of the loaded library + */ + void *handle; + + /** + * how many times we try to authenticate + */ + int tries; + + /** + * unique EAP identifier + */ + u_int8_t identifier; + + /** + * EAP message type this role sends + */ + u_int8_t type; + + /** + * version this implementation uses + */ + chunk_t version; + + /** + * version list received from server + */ + chunk_t version_list; + + /** + * Nonce value used in AT_NONCE_MT + */ + chunk_t nonce; + + /** + * concatenated SRES values + */ + chunk_t sreses; + + /** + * k_encr key derived from MK + */ + chunk_t k_encr; + + /** + * k_auth key derived from MK, used for AT_MAC verification + */ + chunk_t k_auth; + + /** + * MSK, used for EAP-SIM based IKEv2 authentication + */ + chunk_t msk; + + /** + * EMSK, extendes MSK for further uses + */ + chunk_t emsk; +}; + +/** length of the AT_NONCE_MT nonce value */ +#define NONCE_LEN 16 +/** length of the AT_MAC value */ +#define MAC_LEN 16 +/** length of the AT_RAND value */ +#define RAND_LEN 16 +/** length of Kc */ +#define KC_LEN 8 +/** length of SRES */ +#define SRES_LEN 4 +/** length of the k_encr key */ +#define KENCR_LEN 16 +/** length of the k_auth key */ +#define KAUTH_LEN 16 +/** length of the MSK */ +#define MSK_LEN 64 +/** length of the EMSK */ +#define EMSK_LEN 64 + +static char version[] = {0x00,0x01}; +/* client error codes used in AT_CLIENT_ERROR_CODE */ +char client_error_general_buf[] = {0x00, 0x01}; +char client_error_unsupported_buf[] = {0x00, 0x02}; +char client_error_insufficient_buf[] = {0x00, 0x03}; +char client_error_notfresh_buf[] = {0x00, 0x04}; +chunk_t client_error_general = chunk_from_buf(client_error_general_buf); +chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf); +chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf); +chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf); + +/** + * Read EAP and EAP-SIM header, return SIM type + */ +static sim_subtype_t read_header(chunk_t *message) +{ + sim_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data) +{ + sim_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", message); + + if (message->len < 2) + { + return AT_END; + } + attribute = *message->ptr++; + length = *message->ptr++ * 4 - 2; + message->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + sim_attribute_names, attribute, length); + + if (length > message->len) + { + return AT_END; + } + data->len = length; + data->ptr = message->ptr; + *message = chunk_skip(*message, length); + return attribute; +} + +/** + * Build an EAP-SIM payload using a variable length attribute list. + * The variable argument takes a sim_attribute_t followed by its data in a chunk. + */ +static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier, + sim_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + sim_attribute_t attr; + u_int8_t *mac_pos = NULL; + chunk_t mac_data = chunk_empty; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = this->type; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write SIM header with type and subtype, zero reserved bytes */ + *pos.ptr++ = EAP_SIM; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, sim_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_CLIENT_ERROR_CODE: + case AT_SELECTED_VERSION: + { + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_IDENTITY: + case AT_VERSION_LIST: + { + u_int16_t act_len = data.len; + /* align up to four byte */ + if (data.len % 4) + { + chunk_t tmp = chunk_alloca((data.len/4)*4 + 4); + memset(tmp.ptr, 0, tmp.len); + memcpy(tmp.ptr, data.ptr, data.len); + data = tmp; + } + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* actual length in bytes */ + *(u_int16_t*)pos.ptr = htons(act_len); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_NONCE_MT: + { + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memset(pos.ptr, 0, 2); + pos = chunk_skip(pos, 2); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + memset(mac_pos, 0, MAC_LEN); + pos = chunk_skip(pos, MAC_LEN); + mac_data = data; + break; + } + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + default: + DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped", + sim_attribute_names, attr); + break; + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included. Append supplied va_arg + * chunk mac_data to "to-sign" chunk */ + if (mac_pos) + { + this->signer->set_key(this->signer, this->k_auth); + mac_data = chunk_cata("cc", message, mac_data); + this->signer->get_signature(this->signer, mac_data, mac_pos); + DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b", + &mac_data, mac_pos, MAC_LEN); + } + + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * process an EAP-SIM/Request/Start message + */ +static status_t peer_process_start(private_eap_sim_t *this, eap_payload_t *in, + eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute, include_id = AT_END; + u_int8_t identifier; + + identifier = in->get_identifier(in); + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_VERSION_LIST: + { + /* check if server supports our implementation */ + bool found = FALSE; + if (data.len > 2) + { + /* read actual length first */ + data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2); + data = chunk_skip(data, 2); + chunk_free(&this->version_list); + this->version_list = chunk_clone(data); + while (data.len >= this->version.len) + { + if (memeq(data.ptr, this->version.ptr, this->version.len)) + { + found = TRUE; + break; + } + data = chunk_skip(data, this->version.len); + } + } + if (!found) + { + DBG1(DBG_IKE, "server does not support EAP_SIM " + "version number %#B", &this->version); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_unsupported, + AT_END); + return NEED_MORE; + } + break; + } + case AT_PERMANENT_ID_REQ: + case AT_FULLAUTH_ID_REQ: + case AT_ANY_ID_REQ: + /* only include AT_IDENTITY if requested */ + include_id = AT_IDENTITY; + break; + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + + /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */ + *out = build_payload(this, identifier, SIM_START, + AT_SELECTED_VERSION, this->version, + AT_NONCE_MT, this->nonce, + include_id, this->peer->get_encoding(this->peer), + AT_END); + return NEED_MORE; +} + +/** + * derive EAP keys from kc + */ +static void derive_keys(private_eap_sim_t *this, chunk_t kcs) +{ + chunk_t tmp, mk; + int i; + + /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ + tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs, + this->nonce, this->version_list, this->version); + mk = chunk_alloca(this->hasher->get_hash_size(this->hasher)); + this->hasher->get_hash(this->hasher, tmp, mk.ptr); + DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk); + + /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + this->prf->set_key(this->prf, mk); + tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 4); + for (i = 0; i < 4; i++) + { + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * i); + } + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth, + MSK_LEN, &this->msk, EMSK_LEN, &this->emsk); + DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B", + &this->k_encr, &this->k_auth, &this->msk, &this->emsk); +} + +/** + * process an EAP-SIM/Request/Challenge message + */ +static status_t peer_process_challenge(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data, tmp, kcs, kc, sreses, sres; + sim_attribute_t attribute; + u_int8_t identifier; + chunk_t mac = chunk_empty, rands = chunk_empty; + + if (this->tries-- <= 0) + { + /* give up without notification. This hack is required as some buggy + * server implementations won't respect our client-error. */ + return FAILED; + } + + identifier = in->get_identifier(in); + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_RAND: + { + rands = chunk_skip(data, 2); + break; + } + case AT_MAC: + { + /* backup MAC, zero it inline for later verification */ + data = chunk_skip(data, 2); + mac = chunk_clonea(data); + memset(data.ptr, 0, data.len); + break; + } + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + + /* excepting two or three RAND, each 16 bytes. We require two valid + * and different RANDs */ + if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) || + memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN)) + { + DBG1(DBG_IKE, "no valid AT_RAND received"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_insufficient, + AT_END); + return NEED_MORE; + } + if (mac.len != MAC_LEN) + { + DBG1(DBG_IKE, "no valid AT_MAC received"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + + /* get two or three KCs/SRESes from SIM using RANDs */ + kcs = kc = chunk_alloca(rands.len / 2); + sreses = sres = chunk_alloca(rands.len / 4); + while (rands.len > 0) + { + int kc_len = kc.len, sres_len = sres.len; + + if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len)) + { + DBG1(DBG_IKE, "unable to get EAP-SIM triplet"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b", + rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len); + kc = chunk_skip(kc, kc_len); + sres = chunk_skip(sres, sres_len); + rands = chunk_skip(rands, RAND_LEN); + } + + derive_keys(this, kcs); + + /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */ + this->signer->set_key(this->signer, this->k_auth); + tmp = chunk_cata("cc", in->get_data(in), this->nonce); + if (!this->signer->verify_signature(this->signer, tmp, mac)) + { + DBG1(DBG_IKE, "AT_MAC verification failed"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + + /* build response, AT_MAC is built over "EAP packet | n*SRES" */ + *out = build_payload(this, identifier, SIM_CHALLENGE, + AT_MAC, sreses, + AT_END); + return NEED_MORE; +} + +/** + * process an EAP-SIM/Response/Challenge message + */ +static status_t server_process_challenge(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + chunk_t mac = chunk_empty, tmp; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_MAC: + /* MAC has two reserved bytes */ + if (data.len == MAC_LEN + 2) + { /* clone and zero MAC for verification */ + mac = chunk_clonea(chunk_skip(data, 2)); + memset(data.ptr, 0, data.len); + } + break; + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + if (!mac.ptr) + { + DBG1(DBG_IKE, "no valid AT_MAC attribute received"); + return FAILED; + } + /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */ + this->signer->set_key(this->signer, this->k_auth); + tmp = chunk_cata("cc", in->get_data(in), this->sreses); + if (!this->signer->verify_signature(this->signer, tmp, mac)) + { + DBG1(DBG_IKE, "AT_MAC verification failed"); + return FAILED; + } + return SUCCESS; +} + +/** + * process an EAP-SIM/Response/Start message + */ +static status_t server_process_start(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + bool supported = FALSE; + chunk_t rands, rand, kcs, kc, sreses, sres; + char id[64]; + int len, i, rand_len, kc_len, sres_len; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_NONCE_MT: + if (data.len == NONCE_LEN + 2) + { + this->nonce = chunk_clone(chunk_skip(data, 2)); + } + break; + case AT_SELECTED_VERSION: + if (chunk_equals(data, this->version)) + { + supported = TRUE; + } + break; + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + if (!supported || !this->nonce.ptr) + { + DBG1(DBG_IKE, "received incomplete EAP-SIM/Response/Start"); + return FAILED; + } + len = snprintf(id, sizeof(id), "%D", this->peer); + if (len > sizeof(id) || len < 0) + { + return FAILED; + } + + /* read triplets from provider */ + rand = rands = chunk_alloca(RAND_LEN * TRIPLET_COUNT); + kc = kcs = chunk_alloca(KC_LEN * TRIPLET_COUNT); + sres = sreses = chunk_alloca(SRES_LEN * TRIPLET_COUNT); + rands.len = 0; + kcs.len = 0; + sreses.len = 0; + for (i = 0; i < TRIPLET_COUNT; i++) + { + rand_len = RAND_LEN; + kc_len = KC_LEN; + sres_len = SRES_LEN; + if (this->get_triplet(id, rand.ptr, &rand_len, sres.ptr, &sres_len, + kc.ptr, &kc_len)) + { + DBG1(DBG_IKE, "getting EAP-SIM triplet %d failed", i); + return FAILED; + } + rands.len += rand_len; + kcs.len += kc_len; + sreses.len += sres_len; + rand = chunk_skip(rand, rand_len); + kc = chunk_skip(kc, kc_len); + sres = chunk_skip(sres, sres_len); + } + derive_keys(this, kcs); + + /* build MAC over "EAP packet | NONCE_MT" */ + *out = build_payload(this, this->identifier++, SIM_CHALLENGE, AT_RAND, + rands, AT_MAC, this->nonce, AT_END); + this->sreses = chunk_clone(sreses); + return NEED_MORE; +} + +/** + * process an EAP-SIM/Request/Notification message + */ +static status_t peer_process_notification(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + /* reply with empty notification */ + *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END); + return NEED_MORE; +} + +/** + * Process a client error + */ +static status_t server_process_client_error(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + if (attribute == AT_CLIENT_ERROR_CODE) + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + } + else + { + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + } + } + return FAILED; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t peer_process(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + sim_subtype_t type; + chunk_t message; + + message = in->get_data(in); + type = read_header(&message); + + switch (type) + { + case SIM_START: + return peer_process_start(this, in, out); + case SIM_CHALLENGE: + return peer_process_challenge(this, in, out); + case SIM_NOTIFICATION: + return peer_process_notification(this, in, out); + default: + DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", + sim_subtype_names, type); + *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, AT_END); + return NEED_MORE; + } +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t server_process(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + sim_subtype_t type; + chunk_t message; + + message = in->get_data(in); + type = read_header(&message); + + switch (type) + { + case SIM_START: + return server_process_start(this, in, out); + case SIM_CHALLENGE: + return server_process_challenge(this, in, out); + case SIM_CLIENT_ERROR: + return server_process_client_error(this, in, out); + default: + DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", + sim_subtype_names, type); + return FAILED; + } +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t peer_initiate(private_eap_sim_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t server_initiate(private_eap_sim_t *this, eap_payload_t **out) +{ + /* version_list to derive MK, no padding */ + this->version_list = chunk_clone(this->version); + /* build_payloads adds padding itself */ + *out = build_payload(this, this->identifier++, SIM_START, + AT_VERSION_LIST, this->version, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_SIM; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_sim_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_sim_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_sim_t *this) +{ + dlclose(this->handle); + DESTROY_IF(this->hasher); + DESTROY_IF(this->prf); + DESTROY_IF(this->signer); + chunk_free(&this->nonce); + chunk_free(&this->sreses); + chunk_free(&this->version_list); + chunk_free(&this->k_auth); + chunk_free(&this->k_encr); + chunk_free(&this->msk); + chunk_free(&this->emsk); + free(this); +} + +/** + * Generic constructor for both roles + */ +eap_sim_t *eap_sim_create_generic(eap_role_t role, identification_t *server, + identification_t *peer) +{ + private_eap_sim_t *this; + rng_t *rng; + void *symbol; + char *name; + + this = malloc_thing(private_eap_sim_t); + this->alg = NULL; + this->get_triplet = NULL; + this->nonce = chunk_empty; + this->sreses = chunk_empty; + this->peer = peer; + this->tries = MAX_TRIES; + this->version.ptr = version; + this->version.len = sizeof(version); + this->version_list = chunk_empty; + this->k_auth = chunk_empty; + this->k_encr = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->identifier = random(); + + this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY); + if (this->handle == NULL) + { + DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB); + free(this); + return NULL; + } + switch (role) + { + case EAP_PEER: + name = SIM_READER_ALG; + break; + case EAP_SERVER: + name = SIM_READER_GET_TRIPLET; + break; + default: + free(this); + return NULL; + } + symbol = dlsym(this->handle, name); + if (symbol == NULL) + { + DBG1(DBG_IKE, "unable to open SIM function '%s' in '%s'", + name, SIM_READER_LIB); + dlclose(this->handle); + free(this); + return NULL; + } + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + this->get_triplet = symbol; + this->type = EAP_REQUEST; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + this->alg = symbol; + this->type = EAP_RESPONSE; + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM"); + free(this); + return NULL; + } + rng->allocate_bytes(rng, NONCE_LEN, &this->nonce); + rng->destroy(rng); + break; + default: + free(this); + return NULL; + } + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128); + if (!this->hasher || !this->prf || !this->signer) + { + DBG1(DBG_IKE, "initiating EAP-SIM failed, FIPS-PRF/SHA1 not supported"); + destroy(this); + return NULL; + } + return &this->public; +} + +/* + * Described in header. + */ +eap_sim_t *eap_sim_create_server(identification_t *server, + identification_t *peer) +{ + return eap_sim_create_generic(EAP_SERVER, server, peer); +} + +/* + * Described in header. + */ +eap_sim_t *eap_sim_create_peer(identification_t *server, + identification_t *peer) +{ + return eap_sim_create_generic(EAP_PEER, server, peer); +} + diff --git a/src/charon/plugins/eap_sim/eap_sim.h b/src/charon/plugins/eap_sim/eap_sim.h new file mode 100644 index 000000000..65020aa64 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_sim_i eap_sim + * @{ @ingroup eap_sim + */ + +#ifndef EAP_SIM_H_ +#define EAP_SIM_H_ + +typedef struct eap_sim_t eap_sim_t; + +#include <sa/authenticators/eap/eap_method.h> + +/** the library containing with the triplet functions */ +#ifndef SIM_READER_LIB +#error SIM_READER_LIB not specified, use --with-sim-reader option +#endif /* SIM_READER_LIB */ + +/** + * Cardreaders SIM function. + * + * @param rand RAND to run algo with + * @param rand_length length of value in rand + * @param sres buffer to get SRES + * @param sres_length size of buffer in sres, returns bytes written to SRES + * @param kc buffer to get Kc + * @param kc_length size of buffer in Kc, returns bytes written to Kc + * @return zero on success + */ +typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length); + +#ifndef SIM_READER_ALG +/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */ +#define SIM_READER_ALG "sim_run_alg" +#endif /* SIM_READER_ALG */ + +/** + * Function to get a SIM triplet. + * + * @param identity identity (imsi) to get a triplet for + * @param rand buffer to get RAND + * @param rand_length size of buffer in rand, returns bytes written to RAND + * @param sres buffer to get SRES + * @param sres_length size of buffer in sres, returns bytes written to SRES + * @param kc buffer to get Kc + * @param kc_length size of buffer in Kc, returns bytes written to Kc + * @return zero on success + */ +typedef int (*sim_get_triplet_t)(char *identity, + unsigned char *rand, int *rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length); + +#ifndef SIM_READER_GET_TRIPLET +/** the SIM_READER_LIB's get-triplet function, uses sim_get_triplet_t signature */ +#define SIM_READER_GET_TRIPLET "sim_get_triplet" +#endif /* SIM_READER_GET_TRIPLET */ + +/** + * Implementation of the eap_method_t interface using EAP-SIM. + * + * This EAP-SIM client implementation uses another pluggable library to + * access the SIM card/triplet provider. This module is specified using the + * SIM_READER_LIB definition. It has to privde a sim_run_alg() function to + * calculate a triplet (client), and/or a sim_get_triplet() function to get + * a triplet (server). These functions are named to the SIM_READER_ALG and + * the SIM_READER_GET_TRIPLET definitions. + */ +struct eap_sim_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP-SIM acting as server. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_sim_t object + */ +eap_sim_t *eap_sim_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the EAP method EAP-SIM acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_sim_t object + */ +eap_sim_t *eap_sim_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_SIM_H_ @}*/ diff --git a/src/charon/plugins/eap_sim/eap_sim_file.c b/src/charon/plugins/eap_sim/eap_sim_file.c new file mode 100644 index 000000000..fc4c1af26 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_file.c @@ -0,0 +1,283 @@ +/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details. + * + * $Id: eap_sim_file.c 3491 2008-02-22 14:04:00Z martin $ + */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <daemon.h>
+
+#define IMSI_LEN 64
+#define RAND_LEN 16
+#define SRES_LEN 4
+#define KC_LEN 8
+
+typedef struct triplet_t triplet_t;
+
+struct triplet_t {
+ unsigned char imsi[IMSI_LEN];
+ unsigned char rand[RAND_LEN];
+ unsigned char sres[SRES_LEN];
+ unsigned char kc[KC_LEN];
+};
+
+static triplet_t *triplets = NULL;
+static int triplet_count = 0;
+
+#define TRIPLET_FILE IPSEC_CONFDIR "/ipsec.d/triplets.dat"
+
+/**
+ * convert a single HEX char to its integer value
+ */
+static int hexchr(char chr)
+{
+ switch (chr)
+ {
+ case '0'...'9':
+ return chr - '0';
+ case 'A'...'F':
+ return 10 + chr - 'A';
+ case 'a'...'f':
+ return 10 + chr - 'a';
+ }
+ return 0;
+}
+
+/**
+ * convert a HEX string into a char array bin, limited by array length len
+ */
+static void hex2bin(char *hex, unsigned char *bin, size_t len)
+{
+ char *pos;
+ int i, even = 1;
+
+ pos = hex - 1;
+ /* find the end, as we convert bottom up */
+ while (TRUE)
+ {
+ switch (*(pos+1))
+ {
+ case '0'...'9':
+ case 'A'...'F':
+ case 'a'...'f':
+ pos++;
+ continue;
+ }
+ break;
+ }
+ /* convert two hex chars into a single bin byte */
+ for (i = 0; pos >= hex && i < len; pos--)
+ {
+ if (even)
+ {
+ bin[len - 1 - i] = hexchr(*pos);
+ }
+ else
+ {
+ bin[len - 1 - i] |= 16 * hexchr(*pos);
+ i++;
+ }
+ even = !even;
+ }
+}
+
+/**
+ * free up allocated triplets
+ */
+static void __attribute__ ((destructor)) free_triplets()
+{
+ free(triplets);
+}
+
+/**
+ * read the triplets from the file, using freeradius triplet file syntax:
+ * http://www.freeradius.org/radiusd/doc/rlm_sim_triplets
+ */
+static void __attribute__ ((constructor)) read_triplets()
+{
+ char line[512], *data[4], *pos;
+ FILE *file;
+ int i, nr = 0;
+ triplet_t *triplet;
+
+ file = fopen(TRIPLET_FILE, "r");
+ if (file == NULL)
+ {
+ DBG1(DBG_CFG, "opening triplet file %s failed: %s",
+ TRIPLET_FILE, strerror(errno));
+ return;
+ }
+
+ if (triplets)
+ {
+ free(triplets);
+ triplets = NULL;
+ triplet_count = 0;
+ }
+
+ /* read line by line */
+ while (fgets(line, sizeof(line), file))
+ {
+ nr++;
+ /* skip comments, empty lines */
+ switch (line[0])
+ {
+ case '\n':
+ case '\r':
+ case '#':
+ case '\0':
+ continue;
+ default:
+ break;
+ }
+ /* read comma separated values */
+ pos = line;
+ for (i = 0; i < 4; i++)
+ {
+ data[i] = pos;
+ pos = strchr(pos, ',');
+ if (pos)
+ {
+ *pos = '\0';
+ pos++;
+ }
+ else if (i != 3)
+ {
+ DBG1(DBG_CFG, "error in triplet file, line %d", nr);
+ fclose(file);
+ return;
+ }
+ }
+ /* allocate new triplet */
+ triplet_count++;
+ triplets = realloc(triplets, triplet_count * sizeof(triplet_t));
+ triplet = &triplets[triplet_count - 1];
+ memset(triplet, 0, sizeof(triplet_t));
+
+ /* convert/copy triplet data */
+ for (i = 0; i < IMSI_LEN - 1; i++)
+ {
+ switch (data[0][i])
+ {
+ case '\n':
+ case '\r':
+ case '\0':
+ break;
+ default:
+ triplet->imsi[i] = data[0][i];
+ continue;
+ }
+ break;
+ }
+ hex2bin(data[1], triplet->rand, RAND_LEN);
+ hex2bin(data[2], triplet->sres, SRES_LEN);
+ hex2bin(data[3], triplet->kc, KC_LEN);
+
+ DBG4(DBG_CFG, "triplet: imsi %b\nrand %b\nsres %b\nkc %b",
+ triplet->imsi, IMSI_LEN, triplet->rand, RAND_LEN,
+ triplet->sres, SRES_LEN, triplet->kc, KC_LEN);
+ }
+ fclose(file);
+ DBG2(DBG_CFG, "read %d triplets from %s", triplet_count, TRIPLET_FILE);
+}
+
+/**
+ * Run the sim algorithm, see eap_sim.h
+ */
+int sim_run_alg(const unsigned char *rand, int rand_length,
+ unsigned char *sres, int *sres_length,
+ unsigned char *kc, int *kc_length)
+{
+ int current;
+
+ if (rand_length != RAND_LEN ||
+ *sres_length < SRES_LEN ||
+ *kc_length < KC_LEN)
+ {
+ return 1;
+ }
+
+ for (current = 0; current < triplet_count; current++)
+ {
+ if (memcmp(triplets[current].rand, rand, RAND_LEN) == 0)
+ {
+ memcpy(sres, triplets[current].sres, SRES_LEN);
+ memcpy(kc, triplets[current].kc, KC_LEN);
+ *sres_length = SRES_LEN;
+ *kc_length = KC_LEN;
+ return 0;
+ }
+ }
+ return 2;
+}
+
+/**
+ * Get a single triplet, see_eap_sim.h
+ */
+int sim_get_triplet(char *imsi,
+ unsigned char *rand, int *rand_length,
+ unsigned char *sres, int *sres_length,
+ unsigned char *kc, int *kc_length)
+{
+ int current;
+ triplet_t *triplet;
+ static int skip = -1;
+
+ DBG2(DBG_CFG, "getting triplet for %s", imsi);
+
+ if (*rand_length < RAND_LEN ||
+ *sres_length < SRES_LEN ||
+ *kc_length < KC_LEN)
+ {
+ return 1;
+ }
+ if (triplet_count == 0)
+ {
+ return 2;
+ }
+ for (current = 0; current < triplet_count; current++)
+ {
+ triplet = &triplets[current];
+
+ if (streq(imsi, triplet->imsi))
+ {
+ /* skip triplet if already used */
+ if (skip >= current)
+ {
+ continue;
+ }
+ *rand_length = RAND_LEN;
+ *sres_length = SRES_LEN;
+ *kc_length = KC_LEN;
+ memcpy(rand, triplet->rand, RAND_LEN);
+ memcpy(sres, triplet->sres, SRES_LEN);
+ memcpy(kc, triplet->kc, KC_LEN);
+ /* remember used triplet */
+ skip = current;
+ return 0;
+ }
+ }
+ if (skip > -1)
+ {
+ /* no triplet left, reuse triplets */
+ skip = -1;
+ return sim_get_triplet(imsi, rand, rand_length,
+ sres, sres_length, kc, kc_length);
+ }
+ return 2;
+}
+
diff --git a/src/charon/plugins/eap_sim/eap_sim_plugin.c b/src/charon/plugins/eap_sim/eap_sim_plugin.c new file mode 100644 index 000000000..d937c57b4 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_sim_plugin.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "eap_sim_plugin.h" + +#include "eap_sim.h" + +#include <daemon.h> + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_sim_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_sim_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_sim_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_sim_plugin_t *this = malloc_thing(eap_sim_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_SIM, 0, EAP_SERVER, + (eap_constructor_t)eap_sim_create_server); + charon->eap->add_method(charon->eap, EAP_SIM, 0, EAP_PEER, + (eap_constructor_t)eap_sim_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_sim/eap_sim_plugin.h b/src/charon/plugins/eap_sim/eap_sim_plugin.h new file mode 100644 index 000000000..938807884 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: eap_sim_plugin.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup eap_sim eap_sim + * @ingroup cplugins + * + * @defgroup eap_sim_plugin eap_sim_plugin + * @{ @ingroup eap_sim + */ + +#ifndef EAP_SIM_PLUGIN_H_ +#define EAP_SIM_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct eap_sim_plugin_t eap_sim_plugin_t; + +/** + * EAP-sim plugin + */ +struct eap_sim_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_sim_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_SIM_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/medcli/Makefile.am b/src/charon/plugins/medcli/Makefile.am new file mode 100644 index 000000000..f15950af9 --- /dev/null +++ b/src/charon/plugins/medcli/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-medcli.la +libstrongswan_medcli_la_SOURCES = medcli_plugin.h medcli_plugin.c \ + medcli_creds.h medcli_creds.c \ + medcli_config.h medcli_config.c \ + medcli_listener.h medcli_listener.c +libstrongswan_medcli_la_LDFLAGS = -module + diff --git a/src/charon/plugins/medcli/Makefile.in b/src/charon/plugins/medcli/Makefile.in new file mode 100644 index 000000000..85be6bae7 --- /dev/null +++ b/src/charon/plugins/medcli/Makefile.in @@ -0,0 +1,502 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/medcli +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_medcli_la_LIBADD = +am_libstrongswan_medcli_la_OBJECTS = medcli_plugin.lo medcli_creds.lo \ + medcli_config.lo medcli_listener.lo +libstrongswan_medcli_la_OBJECTS = \ + $(am_libstrongswan_medcli_la_OBJECTS) +libstrongswan_medcli_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_medcli_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_medcli_la_SOURCES) +DIST_SOURCES = $(libstrongswan_medcli_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-medcli.la +libstrongswan_medcli_la_SOURCES = medcli_plugin.h medcli_plugin.c \ + medcli_creds.h medcli_creds.c \ + medcli_config.h medcli_config.c \ + medcli_listener.h medcli_listener.c + +libstrongswan_medcli_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/medcli/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/medcli/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-medcli.la: $(libstrongswan_medcli_la_OBJECTS) $(libstrongswan_medcli_la_DEPENDENCIES) + $(libstrongswan_medcli_la_LINK) -rpath $(plugindir) $(libstrongswan_medcli_la_OBJECTS) $(libstrongswan_medcli_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medcli_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medcli_creds.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medcli_listener.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medcli_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/medcli/medcli_config.c b/src/charon/plugins/medcli/medcli_config.c new file mode 100644 index 000000000..96dfa7c94 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_config.c @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include <string.h> + +#include "medcli_config.h" + +#include <daemon.h> +#include <processing/jobs/callback_job.h> + +typedef struct private_medcli_config_t private_medcli_config_t; + +/** + * Private data of an medcli_config_t object + */ +struct private_medcli_config_t { + + /** + * Public part + */ + medcli_config_t public; + + /** + * database connection + */ + database_t *db; + + /** + * rekey time + */ + int rekey; + + /** + * dpd delay + */ + int dpd; + + /** + * default ike config + */ + ike_cfg_t *ike; +}; + +/** + * create a traffic selector from a CIDR notation string + */ +static traffic_selector_t *ts_from_string(char *str) +{ + if (str) + { + int netbits = 32; + host_t *net; + char *pos; + + str = strdupa(str); + pos = strchr(str, '/'); + if (pos) + { + *pos++ = '\0'; + netbits = atoi(pos); + } + else + { + if (strchr(str, ':')) + { + netbits = 128; + } + } + net = host_create_from_string(str, 0); + if (net) + { + return traffic_selector_create_from_subnet(net, netbits, 0, 0); + } + } + return traffic_selector_create_dynamic(0, 0, 65535); +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_medcli_config_t *this, char *name) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg, *med_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + chunk_t me, other; + char *address, *local_net, *remote_net; + + /* query mediation server config: + * - build ike_cfg/peer_cfg for mediation connection on-the-fly + */ + e = this->db->query(this->db, + "SELECT Address, ClientConfig.KeyId, MediationServerConfig.KeyId " + "FROM MediationServerConfig JOIN ClientConfig", + DB_TEXT, DB_BLOB, DB_BLOB); + if (!e || !e->enumerate(e, &address, &me, &other)) + { + DESTROY_IF(e); + return NULL; + } + ike_cfg = ike_cfg_create(FALSE, FALSE, "0.0.0.0", address); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + med_cfg = peer_cfg_create( + "mediation", 2, ike_cfg, + identification_create_from_encoding(ID_KEY_ID, me), + identification_create_from_encoding(ID_KEY_ID, other), + CERT_NEVER_SEND, UNIQUE_REPLACE, CONF_AUTH_PUBKEY, + 0, 0, /* EAP method, vendor */ + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + TRUE, NULL, NULL); /* mediation, med by, peer id */ + e->destroy(e); + + /* query mediated config: + * - use any-any ike_cfg + * - build peer_cfg on-the-fly using med_cfg + * - add a child_cfg + */ + e = this->db->query(this->db, + "SELECT ClientConfig.KeyId, Connection.KeyId, " + "Connection.LocalSubnet, Connection.RemoteSubnet " + "FROM ClientConfig JOIN Connection " + "WHERE Active AND Alias = ?", DB_TEXT, name, + DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT); + if (!e || !e->enumerate(e, &me, &other, &local_net, &remote_net)) + { + DESTROY_IF(e); + return NULL; + } + peer_cfg = peer_cfg_create( + name, 2, this->ike->get_ref(this->ike), + identification_create_from_encoding(ID_KEY_ID, me), + identification_create_from_encoding(ID_KEY_ID, other), + CERT_NEVER_SEND, UNIQUE_REPLACE, CONF_AUTH_PUBKEY, + 0, 0, /* EAP method, vendor */ + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + FALSE, med_cfg, /* mediation, med by */ + identification_create_from_encoding(ID_KEY_ID, other)); + + child_cfg = child_cfg_create(name, this->rekey*60 + this->rekey, + this->rekey*60, this->rekey, NULL, TRUE, + MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + e->destroy(e); + return peer_cfg; +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_medcli_config_t *this, + host_t *me, host_t *other) +{ + return enumerator_create_single(this->ike, NULL); +} + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + peer_cfg_t *current; + /** ike cfg to use in peer cfg */ + ike_cfg_t *ike; + /** rekey time */ + int rekey; + /** dpd time */ + int dpd; +} peer_enumerator_t; + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +{ + char *name, *local_net, *remote_net; + chunk_t me, other; + child_cfg_t *child_cfg; + + DESTROY_IF(this->current); + if (!this->inner->enumerate(this->inner, &name, &me, &other, + &local_net, &remote_net)) + { + this->current = NULL; + return FALSE; + } + this->current = peer_cfg_create( + name, 2, this->ike->get_ref(this->ike), + identification_create_from_encoding(ID_KEY_ID, me), + identification_create_from_encoding(ID_KEY_ID, other), + CERT_NEVER_SEND, UNIQUE_REPLACE, AUTH_RSA, + 0, 0, /* EAP method, vendor */ + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + FALSE, NULL, NULL); /* mediation, med by, peer id */ + child_cfg = child_cfg_create( + name, this->rekey*60 + this->rekey, + this->rekey*60, this->rekey, NULL, TRUE, + MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); + this->current->add_child_cfg(this->current, child_cfg); + *cfg = this->current; + return TRUE; +} + +/** + * Implementation of peer_enumerator_t.public.destroy + */ +static void peer_enumerator_destroy(peer_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_medcli_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_enumerator_t *e = malloc_thing(peer_enumerator_t); + + e->current = NULL; + e->ike = this->ike; + e->rekey = this->rekey; + e->dpd = this->dpd; + e->public.enumerate = (void*)peer_enumerator_enumerate; + e->public.destroy = (void*)peer_enumerator_destroy; + + /* filter on IDs: NULL or ANY or matching KEY_ID */ + e->inner = this->db->query(this->db, + "SELECT Alias, ClientConfig.KeyId, Connection.KeyId, " + "Connection.LocalSubnet, Connection.RemoteSubnet " + "FROM ClientConfig JOIN Connection " + "WHERE Active AND " + "(? OR ClientConfig.KeyId = ?) AND (? OR Connection.KeyId = ?)", + DB_INT, me == NULL || me->get_type(me) == ID_ANY, + DB_BLOB, me && me->get_type(me) == ID_KEY_ID ? + me->get_encoding(me) : chunk_empty, + DB_INT, other == NULL || other->get_type(other) == ID_ANY, + DB_BLOB, other && other->get_type(other) == ID_KEY_ID ? + other->get_encoding(other) : chunk_empty, + DB_TEXT, DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * initiate a peer config + */ +static job_requeue_t initiate_config(peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg = NULL;; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + enumerator->enumerate(enumerator, &child_cfg); + if (child_cfg) + { + child_cfg->get_ref(child_cfg); + peer_cfg->get_ref(peer_cfg); + enumerator->destroy(enumerator); + charon->controller->initiate(charon->controller, + peer_cfg, child_cfg, NULL, NULL); + } + else + { + enumerator->destroy(enumerator); + } + return JOB_REQUEUE_NONE; +} + +/** + * schedule initation of all "active" connections + */ +static void schedule_autoinit(private_medcli_config_t *this) +{ + enumerator_t *e; + char *name; + + e = this->db->query(this->db, "SELECT Alias FROM Connection WHERE Active", + DB_TEXT); + if (e) + { + while (e->enumerate(e, &name)) + { + peer_cfg_t *peer_cfg; + + peer_cfg = get_peer_cfg_by_name(this, name); + if (peer_cfg) + { + /* schedule asynchronous initiation job */ + charon->processor->queue_job(charon->processor, + (job_t*)callback_job_create( + (callback_job_cb_t)initiate_config, + peer_cfg, (void*)peer_cfg->destroy, NULL)); + } + } + e->destroy(e); + } +} + +/** + * Implementation of medcli_config_t.destroy. + */ +static void destroy(private_medcli_config_t *this) +{ + this->ike->destroy(this->ike); + free(this); +} + +/** + * Described in header. + */ +medcli_config_t *medcli_config_create(database_t *db) +{ + private_medcli_config_t *this = malloc_thing(private_medcli_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(medcli_config_t*))destroy; + + this->db = db; + this->rekey = lib->settings->get_int(lib->settings, + "medclient.rekey", 20) * 60; + this->dpd = lib->settings->get_int(lib->settings, "medclient.dpd", 300); + this->ike = ike_cfg_create(FALSE, FALSE, "0.0.0.0", "0.0.0.0"); + this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); + + schedule_autoinit(this); + + return &this->public; +} + diff --git a/src/charon/plugins/medcli/medcli_config.h b/src/charon/plugins/medcli/medcli_config.h new file mode 100644 index 000000000..789a73243 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup medcli_config_i medcli_config + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_CONFIG_H_ +#define MEDCLI_CONFIG_H_ + +#include <config/backend.h> +#include <database/database.h> + +typedef struct medcli_config_t medcli_config_t; + +/** + * Mediation client configuration backend. + */ +struct medcli_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destroy the backend. + */ + void (*destroy)(medcli_config_t *this); +}; + +/** + * Create a medcli_config backend instance. + * + * @param db underlying database + * @return backend instance + */ +medcli_config_t *medcli_config_create(database_t *db); + +#endif /* MEDCLI_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/medcli/medcli_creds.c b/src/charon/plugins/medcli/medcli_creds.c new file mode 100644 index 000000000..685f34271 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_creds.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "medcli_creds.h" + +#include <daemon.h> +#include <library.h> +#include <utils/enumerator.h> + +typedef struct private_medcli_creds_t private_medcli_creds_t; + +/** + * Private data of an medcli_creds_t object + */ +struct private_medcli_creds_t { + + /** + * Public part + */ + medcli_creds_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * enumerator over private keys + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated private key */ + private_key_t *current; +} private_enumerator_t; + +/** + * Implementation of private_enumerator_t.public.enumerate + */ +static bool private_enumerator_enumerate(private_enumerator_t *this, + private_key_t **key) +{ + chunk_t chunk; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &chunk)) + { + this->current = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk_clone(chunk), + BUILD_END); + if (this->current) + { + *key = this->current; + return TRUE; + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of private_enumerator_t.public.destroy + */ +static void private_enumerator_destroy(private_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_private_enumerator. + */ +static enumerator_t* create_private_enumerator(private_medcli_creds_t *this, + key_type_t type, identification_t *id) +{ + private_enumerator_t *e; + + if ((type != KEY_RSA && type != KEY_ANY) || + id == NULL || id->get_type(id) != ID_KEY_ID) + { + DBG1(DBG_CFG, "%N - %D", key_type_names, type, id); + return NULL; + } + + e = malloc_thing(private_enumerator_t); + e->current = NULL; + e->public.enumerate = (void*)private_enumerator_enumerate; + e->public.destroy = (void*)private_enumerator_destroy; + e->inner = this->db->query(this->db, + "SELECT PrivateKey FROM ClientConfig WHERE KeyId = ?", + DB_BLOB, id->get_encoding(id), + DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated cert */ + certificate_t *current; + /** type of requested key */ + key_type_t type; +} cert_enumerator_t; + +/** + * Implementation of cert_enumerator_t.public.enumerate + */ +static bool cert_enumerator_enumerate(cert_enumerator_t *this, + certificate_t **cert) +{ + public_key_t *public; + chunk_t chunk; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &chunk)) + { + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_BLOB_ASN1_DER, chunk_clone(chunk), + BUILD_END); + if (public) + { + if (this->type == KEY_ANY || this->type == public->get_type(public)) + { + this->current = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, public, BUILD_END); + if (this->current) + { + *cert = this->current; + return TRUE; + } + continue; + } + public->destroy(public); + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of cert_enumerator_t.public.destroy + */ +static void cert_enumerator_destroy(cert_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_medcli_creds_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + cert_enumerator_t *e; + + if ((cert != CERT_TRUSTED_PUBKEY && cert != CERT_ANY) || + id == NULL || id->get_type(id) != ID_KEY_ID) + { + return NULL; + } + + e = malloc_thing(cert_enumerator_t); + e->current = NULL; + e->type = key; + e->public.enumerate = (void*)cert_enumerator_enumerate; + e->public.destroy = (void*)cert_enumerator_destroy; + e->inner = this->db->query(this->db, + "SELECT PublicKey FROM ClientConfig WHERE KeyId = ? UNION " + "SELECT PublicKey FROM MediationServerConfig WHERE KeyId = ? UNION " + "SELECT PublicKey FROM Connection WHERE KeyId = ?", + DB_BLOB, id->get_encoding(id), + DB_BLOB, id->get_encoding(id), + DB_BLOB, id->get_encoding(id), + DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_medcli_creds_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +medcli_creds_t *medcli_creds_create(database_t *db) +{ + private_medcli_creds_t *this = malloc_thing(private_medcli_creds_t); + + this->public.set.create_private_enumerator = (void*)create_private_enumerator; + this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->public.set.create_shared_enumerator = (void*)return_null; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.set.cache_cert = (void*)nop; + + this->public.destroy = (void (*)(medcli_creds_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/medcli/medcli_creds.h b/src/charon/plugins/medcli/medcli_creds.h new file mode 100644 index 000000000..5a81edaf2 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_creds.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup medcli_creds_i medcli_creds + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_CREDS_H_ +#define MEDCLI_CREDS_H_ + +#include <credentials/credential_set.h> +#include <database/database.h> + +typedef struct medcli_creds_t medcli_creds_t; + +/** + * Mediation client credentials database. + */ +struct medcli_creds_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(medcli_creds_t *this); +}; + +/** + * Create the medcli credential set. + * + * @param database underlying database + * @return credential set implementation on that database + */ +medcli_creds_t *medcli_creds_create(database_t *database); + +#endif /* MEDCLI_CREDS_H_ @}*/ diff --git a/src/charon/plugins/medcli/medcli_listener.c b/src/charon/plugins/medcli/medcli_listener.c new file mode 100644 index 000000000..cb370ba2a --- /dev/null +++ b/src/charon/plugins/medcli/medcli_listener.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "medcli_listener.h" + +#include <daemon.h> +#include <library.h> + +typedef struct private_medcli_listener_t private_medcli_listener_t; +typedef enum mediated_state_t mediated_state_t; + +/** + * state of a mediated connection + */ +enum mediated_state_t { + STATE_DOWN = 1, + STATE_CONNECTING = 2, + STATE_UP = 3, +}; + +/** + * Private data of an medcli_listener_t object + */ +struct private_medcli_listener_t { + + /** + * Public part + */ + medcli_listener_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * Implementation of bus_listener_t.signal. + */ +static bool signal_(private_medcli_listener_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) +{ + mediated_state_t state; + + if (!ike_sa) + { + return TRUE; + } + + switch (signal) + { + case IKE_UP_START: + state = STATE_CONNECTING; + break; + case IKE_UP_FAILED: + case IKE_DOWN_SUCCESS: + case IKE_DOWN_FAILED: + state = STATE_DOWN; + break; + case IKE_UP_SUCCESS: + state = STATE_UP; + break; + default: + return TRUE; + } + this->db->execute(this->db, NULL, + "UPDATE Connection SET Status = ? WHERE Alias = ?", + DB_UINT, state, DB_TEXT, ike_sa->get_name(ike_sa)); + return TRUE; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_medcli_listener_t *this) +{ + this->db->execute(this->db, NULL, "UPDATE Connection SET Status = ?", + DB_UINT, STATE_DOWN); + free(this); +} + +/** + * Described in header. + */ +medcli_listener_t *medcli_listener_create(database_t *db) +{ + private_medcli_listener_t *this = malloc_thing(private_medcli_listener_t); + + this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_; + this->public.destroy = (void (*)(medcli_listener_t*))destroy; + + this->db = db; + db->execute(db, NULL, "UPDATE Connection SET Status = ?", + DB_UINT, STATE_DOWN); + + return &this->public; +} + diff --git a/src/charon/plugins/medcli/medcli_listener.h b/src/charon/plugins/medcli/medcli_listener.h new file mode 100644 index 000000000..f07218d78 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_listener.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup medcli_listener_i medcli_listener + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_LISTENER_H_ +#define MEDCLI_LISTENER_H_ + +#include <bus/bus.h> +#include <database/database.h> + +typedef struct medcli_listener_t medcli_listener_t; + +/** + * Mediation client listener, writes connection status to database + */ +struct medcli_listener_t { + + /** + * Implements bus_listener_t interface + */ + bus_listener_t listener; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(medcli_listener_t *this); +}; + +/** + * Create the medcli credential set. + * + * @param database underlying database + * @return listener + */ +medcli_listener_t *medcli_listener_create(database_t *database); + +#endif /* MEDCLI_LISTENER_H_ @}*/ diff --git a/src/charon/plugins/medcli/medcli_plugin.c b/src/charon/plugins/medcli/medcli_plugin.c new file mode 100644 index 000000000..1642ed2fe --- /dev/null +++ b/src/charon/plugins/medcli/medcli_plugin.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "medcli_plugin.h" + +#include "medcli_creds.h" +#include "medcli_config.h" +#include "medcli_listener.h" + +#include <daemon.h> + +typedef struct private_medcli_plugin_t private_medcli_plugin_t; + +/** + * private data of medcli plugin + */ +struct private_medcli_plugin_t { + + /** + * implements plugin interface + */ + medcli_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * medcli credential set instance + */ + medcli_creds_t *creds; + + /** + * medcli config database + */ + medcli_config_t *config; + + /** + * Listener to update database connection state + */ + medcli_listener_t *listener; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_medcli_plugin_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener->listener); + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->credentials->remove_set(charon->credentials, &this->creds->set); + this->listener->destroy(this->listener); + this->config->destroy(this->config); + this->creds->destroy(this->creds); + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + char *uri; + private_medcli_plugin_t *this = malloc_thing(private_medcli_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + uri = lib->settings->get_str(lib->settings, + "medcli.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "mediation client database URI not defined, skipped"); + free(this); + return NULL; + } + + this->db = lib->db->create(lib->db, uri); + if (this->db == NULL) + { + DBG1(DBG_CFG, "opening mediation client database failed"); + free(this); + return NULL; + } + + this->creds = medcli_creds_create(this->db); + this->config = medcli_config_create(this->db); + this->listener = medcli_listener_create(this->db); + + charon->credentials->add_set(charon->credentials, &this->creds->set); + charon->backends->add_backend(charon->backends, &this->config->backend); + charon->bus->add_listener(charon->bus, &this->listener->listener); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/medcli/medcli_plugin.h b/src/charon/plugins/medcli/medcli_plugin.h new file mode 100644 index 000000000..1a8c5b5e7 --- /dev/null +++ b/src/charon/plugins/medcli/medcli_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup medcli medcli + * @ingroup cplugins + * + * @defgroup medcli_plugin medcli_plugin + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_PLUGIN_H_ +#define MEDCLI_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct medcli_plugin_t medcli_plugin_t; + +/** + * Mediation client database plugin. + */ +struct medcli_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a medcli_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MEDCLI_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/medsrv/Makefile.am b/src/charon/plugins/medsrv/Makefile.am new file mode 100644 index 000000000..476da1878 --- /dev/null +++ b/src/charon/plugins/medsrv/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-medsrv.la +libstrongswan_medsrv_la_SOURCES = medsrv_plugin.h medsrv_plugin.c \ + medsrv_creds.h medsrv_creds.c \ + medsrv_config.h medsrv_config.c +libstrongswan_medsrv_la_LDFLAGS = -module + diff --git a/src/charon/plugins/medsrv/Makefile.in b/src/charon/plugins/medsrv/Makefile.in new file mode 100644 index 000000000..b6561e15e --- /dev/null +++ b/src/charon/plugins/medsrv/Makefile.in @@ -0,0 +1,500 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/medsrv +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_medsrv_la_LIBADD = +am_libstrongswan_medsrv_la_OBJECTS = medsrv_plugin.lo medsrv_creds.lo \ + medsrv_config.lo +libstrongswan_medsrv_la_OBJECTS = \ + $(am_libstrongswan_medsrv_la_OBJECTS) +libstrongswan_medsrv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_medsrv_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_medsrv_la_SOURCES) +DIST_SOURCES = $(libstrongswan_medsrv_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-medsrv.la +libstrongswan_medsrv_la_SOURCES = medsrv_plugin.h medsrv_plugin.c \ + medsrv_creds.h medsrv_creds.c \ + medsrv_config.h medsrv_config.c + +libstrongswan_medsrv_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/medsrv/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/medsrv/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-medsrv.la: $(libstrongswan_medsrv_la_OBJECTS) $(libstrongswan_medsrv_la_DEPENDENCIES) + $(libstrongswan_medsrv_la_LINK) -rpath $(plugindir) $(libstrongswan_medsrv_la_OBJECTS) $(libstrongswan_medsrv_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medsrv_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medsrv_creds.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/medsrv_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/medsrv/medsrv_config.c b/src/charon/plugins/medsrv/medsrv_config.c new file mode 100644 index 000000000..1017b9de0 --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_config.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <string.h> + +#include "medsrv_config.h" + +#include <daemon.h> + +typedef struct private_medsrv_config_t private_medsrv_config_t; + +/** + * Private data of an medsrv_config_t object + */ +struct private_medsrv_config_t { + + /** + * Public part + */ + medsrv_config_t public; + + /** + * database connection + */ + database_t *db; + + /** + * rekey time + */ + int rekey; + + /** + * dpd delay + */ + int dpd; + + /** + * default ike config + */ + ike_cfg_t *ike; +}; + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_medsrv_config_t *this, char *name) +{ + return NULL; +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_medsrv_config_t *this, + host_t *me, host_t *other) +{ + return enumerator_create_single(this->ike, NULL); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_medsrv_config_t *this, + identification_t *me, + identification_t *other) +{ + enumerator_t *e; + + if (!me || !other || other->get_type(other) != ID_KEY_ID) + { + return NULL; + } + e = this->db->query(this->db, + "SELECT CONCAT(peer.alias, CONCAT('@', user.login)) FROM " + "peer JOIN user ON peer.user = user.id " + "WHERE peer.keyid = ?", DB_BLOB, other->get_encoding(other), + DB_TEXT); + if (e) + { + peer_cfg_t *peer_cfg; + char *name; + + if (e->enumerate(e, &name)) + { + peer_cfg = peer_cfg_create( + name, 2, this->ike->get_ref(this->ike), + me->clone(me), other->clone(other), + CERT_NEVER_SEND, UNIQUE_REPLACE, CONF_AUTH_PUBKEY, + 0, 0, /* EAP method, vendor */ + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + TRUE, NULL, NULL); /* mediation, med by, peer id */ + e->destroy(e); + return enumerator_create_single(peer_cfg, (void*)peer_cfg->destroy); + } + e->destroy(e); + } + return NULL; +} + +/** + * Implementation of medsrv_config_t.destroy. + */ +static void destroy(private_medsrv_config_t *this) +{ + this->ike->destroy(this->ike); + free(this); +} + +/** + * Described in header. + */ +medsrv_config_t *medsrv_config_create(database_t *db) +{ + private_medsrv_config_t *this = malloc_thing(private_medsrv_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(medsrv_config_t*))destroy; + + this->db = db; + this->rekey = lib->settings->get_int(lib->settings, + "medsrv.rekey", 20) * 60; + this->dpd = lib->settings->get_int(lib->settings, "medsrv.dpd", 300); + this->ike = ike_cfg_create(FALSE, FALSE, "0.0.0.0", "0.0.0.0"); + this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); + + return &this->public; +} + diff --git a/src/charon/plugins/medsrv/medsrv_config.h b/src/charon/plugins/medsrv/medsrv_config.h new file mode 100644 index 000000000..ebb62037e --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup medsrv_config_i medsrv_config + * @{ @ingroup medsrv + */ + +#ifndef MEDSRV_CONFIG_H_ +#define MEDSRV_CONFIG_H_ + +#include <config/backend.h> +#include <database/database.h> + +typedef struct medsrv_config_t medsrv_config_t; + +/** + * Mediation server configuration backend. + */ +struct medsrv_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destroy the backend. + */ + void (*destroy)(medsrv_config_t *this); +}; + +/** + * Create a medsrv_config backend instance. + * + * @param db underlying database + * @return backend instance + */ +medsrv_config_t *medsrv_config_create(database_t *db); + +#endif /* MEDSRV_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/medsrv/medsrv_creds.c b/src/charon/plugins/medsrv/medsrv_creds.c new file mode 100644 index 000000000..48e05c38e --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_creds.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: medsrv_creds.c 4061 2008-06-11 14:13:24Z martin $ + */ + +#include "medsrv_creds.h" + +#include <daemon.h> +#include <library.h> +#include <utils/enumerator.h> + +typedef struct private_medsrv_creds_t private_medsrv_creds_t; + +/** + * Private data of an medsrv_creds_t object + */ +struct private_medsrv_creds_t { + + /** + * Public part + */ + medsrv_creds_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated cert */ + certificate_t *current; + /** type of requested key */ + key_type_t type; +} cert_enumerator_t; + +/** + * Implementation of cert_enumerator_t.public.enumerate + */ +static bool cert_enumerator_enumerate(cert_enumerator_t *this, + certificate_t **cert) +{ + certificate_t *trusted; + public_key_t *public; + chunk_t chunk; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &chunk)) + { + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_BLOB_ASN1_DER, chunk_clone(chunk), + BUILD_END); + if (public) + { + if (this->type == KEY_ANY || this->type == public->get_type(public)) + { + trusted = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, public, BUILD_END); + if (trusted) + { + *cert = this->current = trusted; + return TRUE; + } + continue; + } + public->destroy(public); + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of cert_enumerator_t.public.destroy + */ +static void cert_enumerator_destroy(cert_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_medsrv_creds_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + cert_enumerator_t *e; + + if ((cert != CERT_TRUSTED_PUBKEY && cert != CERT_ANY) || + id == NULL || id->get_type(id) != ID_KEY_ID) + { + return NULL; + } + + e = malloc_thing(cert_enumerator_t); + e->current = NULL; + e->type = key; + e->public.enumerate = (void*)cert_enumerator_enumerate; + e->public.destroy = (void*)cert_enumerator_destroy; + e->inner = this->db->query(this->db, + "SELECT public_key FROM peer WHERE keyid = ?", + DB_BLOB, id->get_encoding(id), + DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_medsrv_creds_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +medsrv_creds_t *medsrv_creds_create(database_t *db) +{ + private_medsrv_creds_t *this = malloc_thing(private_medsrv_creds_t); + + this->public.set.create_private_enumerator = (void*)return_null; + this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->public.set.create_shared_enumerator = (void*)return_null; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.set.cache_cert = (void*)nop; + + this->public.destroy = (void (*)(medsrv_creds_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/medsrv/medsrv_creds.h b/src/charon/plugins/medsrv/medsrv_creds.h new file mode 100644 index 000000000..f65e98411 --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_creds.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: medsrv_creds.h 3915 2008-05-08 12:11:30Z martin $ + */ + +/** + * @defgroup medsrv_creds_i medsrv_creds + * @{ @ingroup medsrv + */ + +#ifndef MEDSRV_CREDS_H_ +#define MEDSRV_CREDS_H_ + +#include <credentials/credential_set.h> +#include <database/database.h> + +typedef struct medsrv_creds_t medsrv_creds_t; + +/** + * Mediation credentials database. + */ +struct medsrv_creds_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(medsrv_creds_t *this); +}; + +/** + * Create the medsrv credentials db. + * + * @param database underlying database + * @return credential set implementation on that database + */ +medsrv_creds_t *medsrv_creds_create(database_t *database); + +#endif /* MEDSRV_CREDS_H_ @}*/ diff --git a/src/charon/plugins/medsrv/medsrv_plugin.c b/src/charon/plugins/medsrv/medsrv_plugin.c new file mode 100644 index 000000000..f29120337 --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_plugin.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: medsrv_plugin.c 3915 2008-05-08 12:11:30Z martin $ + */ + +#include "medsrv_plugin.h" + +#include "medsrv_creds.h" +#include "medsrv_config.h" + +#include <daemon.h> + +typedef struct private_medsrv_plugin_t private_medsrv_plugin_t; + +/** + * private data of medsrv plugin + */ +struct private_medsrv_plugin_t { + + /** + * implements plugin interface + */ + medsrv_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * medsrv credential set instance + */ + medsrv_creds_t *creds; + + /** + * medsrv config database + */ + medsrv_config_t *config; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_medsrv_plugin_t *this) +{ + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->credentials->remove_set(charon->credentials, &this->creds->set); + this->config->destroy(this->config); + this->creds->destroy(this->creds); + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + char *uri; + private_medsrv_plugin_t *this = malloc_thing(private_medsrv_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + uri = lib->settings->get_str(lib->settings, + "medmanager.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "mediation database URI not defined, skipped"); + free(this); + return NULL; + } + + this->db = lib->db->create(lib->db, uri); + if (this->db == NULL) + { + DBG1(DBG_CFG, "opening mediation server database failed"); + free(this); + return NULL; + } + + this->creds = medsrv_creds_create(this->db); + this->config = medsrv_config_create(this->db); + + charon->credentials->add_set(charon->credentials, &this->creds->set); + charon->backends->add_backend(charon->backends, &this->config->backend); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/medsrv/medsrv_plugin.h b/src/charon/plugins/medsrv/medsrv_plugin.h new file mode 100644 index 000000000..8aa56d607 --- /dev/null +++ b/src/charon/plugins/medsrv/medsrv_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: medsrv_plugin.h 3915 2008-05-08 12:11:30Z martin $ + */ + +/** + * @defgroup medsrv medsrv + * @ingroup cplugins + * + * @defgroup medsrv_plugin medsrv_plugin + * @{ @ingroup medsrv + */ + +#ifndef MEDSRV_PLUGIN_H_ +#define MEDSRV_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct medsrv_plugin_t medsrv_plugin_t; + +/** + * Mediation server database plugin. + */ +struct medsrv_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a medsrv_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MEDSRV_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/smp/Makefile.am b/src/charon/plugins/smp/Makefile.am new file mode 100644 index 000000000..1679f1c68 --- /dev/null +++ b/src/charon/plugins/smp/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${xml_CFLAGS} + +AM_CFLAGS = -rdynamic -DIPSEC_PIDDIR=\"${piddir}\" + +plugin_LTLIBRARIES = libstrongswan-smp.la +libstrongswan_smp_la_SOURCES = smp.h smp.c +libstrongswan_smp_la_LDFLAGS = -module +libstrongswan_smp_la_LIBADD = ${xml_LIBS} + diff --git a/src/charon/plugins/smp/Makefile.in b/src/charon/plugins/smp/Makefile.in new file mode 100644 index 000000000..198526abb --- /dev/null +++ b/src/charon/plugins/smp/Makefile.in @@ -0,0 +1,495 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/smp +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libstrongswan_smp_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libstrongswan_smp_la_OBJECTS = smp.lo +libstrongswan_smp_la_OBJECTS = $(am_libstrongswan_smp_la_OBJECTS) +libstrongswan_smp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_smp_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_smp_la_SOURCES) +DIST_SOURCES = $(libstrongswan_smp_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${xml_CFLAGS} +AM_CFLAGS = -rdynamic -DIPSEC_PIDDIR=\"${piddir}\" +plugin_LTLIBRARIES = libstrongswan-smp.la +libstrongswan_smp_la_SOURCES = smp.h smp.c +libstrongswan_smp_la_LDFLAGS = -module +libstrongswan_smp_la_LIBADD = ${xml_LIBS} +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/smp/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/smp/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-smp.la: $(libstrongswan_smp_la_OBJECTS) $(libstrongswan_smp_la_DEPENDENCIES) + $(libstrongswan_smp_la_LINK) -rpath $(plugindir) $(libstrongswan_smp_la_OBJECTS) $(libstrongswan_smp_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smp.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/smp/smp.c b/src/charon/plugins/smp/smp.c new file mode 100644 index 000000000..3b7fa0070 --- /dev/null +++ b/src/charon/plugins/smp/smp.c @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: smp.c 4073 2008-06-20 07:14:35Z martin $ + */ + +#include <stdlib.h> + +#include "smp.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <libxml/xmlreader.h> +#include <libxml/xmlwriter.h> + +#include <library.h> +#include <daemon.h> +#include <processing/jobs/callback_job.h> + + +typedef struct private_smp_t private_smp_t; + +/** + * Private data of an smp_t object. + */ +struct private_smp_t { + + /** + * Public part of smp_t object. + */ + smp_t public; + + /** + * XML unix socket fd + */ + int socket; + + /** + * job accepting stroke messages + */ + callback_job_t *job; +}; + +ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING, + "created", + "connecting", + "established", + "rekeying", + "deleting", +); + +/** + * write a bool into element + */ +static void write_bool(xmlTextWriterPtr writer, char *element, bool val) +{ + xmlTextWriterWriteElement(writer, element, val ? "true" : "false"); +} + +/** + * write a identification_t into element + */ +static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id) +{ + xmlTextWriterStartElement(writer, element); + switch (id->get_type(id)) + { + { + char *type = ""; + while (TRUE) + { + case ID_ANY: + type = "any"; + break; + case ID_IPV4_ADDR: + type = "ipv4"; + break; + case ID_IPV6_ADDR: + type = "ipv6"; + break; + case ID_FQDN: + type = "fqdn"; + break; + case ID_RFC822_ADDR: + type = "email"; + break; + case ID_DER_ASN1_DN: + type = "asn1dn"; + break; + case ID_DER_ASN1_GN: + type = "asn1gn"; + break; + } + xmlTextWriterWriteAttribute(writer, "type", type); + xmlTextWriterWriteFormatString(writer, "%D", id); + break; + } + default: + /* TODO: base64 keyid */ + xmlTextWriterWriteAttribute(writer, "type", "keyid"); + break; + } + xmlTextWriterEndElement(writer); +} + +/** + * write a host_t address into an element + */ +static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) +{ + xmlTextWriterStartElement(writer, element); + xmlTextWriterWriteAttribute(writer, "type", + host->get_family(host) == AF_INET ? "ipv4" : "ipv6"); + if (host->is_anyaddr(host)) + { /* do not use %any for XML */ + xmlTextWriterWriteFormatString(writer, "%s", + host->get_family(host) == AF_INET ? "0.0.0.0" : "::"); + } + else + { + xmlTextWriterWriteFormatString(writer, "%H", host); + } + xmlTextWriterEndElement(writer); +} + +/** + * write networks element + */ +static void write_networks(xmlTextWriterPtr writer, char *element, + linked_list_t *list) +{ + enumerator_t *enumerator; + traffic_selector_t *ts; + + xmlTextWriterStartElement(writer, element); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, (void**)&ts)) + { + xmlTextWriterStartElement(writer, "network"); + xmlTextWriterWriteAttribute(writer, "type", + ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6"); + xmlTextWriterWriteFormatString(writer, "%R", ts); + xmlTextWriterEndElement(writer); + } + enumerator->destroy(enumerator); + xmlTextWriterEndElement(writer); +} + +/** + * write a childEnd + */ +static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +{ + linked_list_t *list; + + xmlTextWriterWriteFormatElement(writer, "spi", "%lx", + htonl(child->get_spi(child, local))); + list = child->get_traffic_selectors(child, local); + write_networks(writer, "networks", list); +} + +/** + * write a child_sa_t + */ +static void write_child(xmlTextWriterPtr writer, child_sa_t *child) +{ + mode_t mode; + encryption_algorithm_t encr; + integrity_algorithm_t int_algo; + size_t encr_len, int_len; + u_int32_t rekey, use_in, use_out, use_fwd; + child_cfg_t *config; + + config = child->get_config(child); + child->get_stats(child, &mode, &encr, &encr_len, &int_algo, &int_len, + &rekey, &use_in, &use_out, &use_fwd); + + xmlTextWriterStartElement(writer, "childsa"); + xmlTextWriterWriteFormatElement(writer, "reqid", "%d", child->get_reqid(child)); + xmlTextWriterWriteFormatElement(writer, "childconfig", "%s", + config->get_name(config)); + xmlTextWriterStartElement(writer, "local"); + write_childend(writer, child, TRUE); + xmlTextWriterEndElement(writer); + xmlTextWriterStartElement(writer, "remote"); + write_childend(writer, child, FALSE); + xmlTextWriterEndElement(writer); + xmlTextWriterEndElement(writer); +} + +/** + * process a ikesalist query request message + */ +static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + enumerator_t *enumerator; + ike_sa_t *ike_sa; + + /* <ikesalist> */ + xmlTextWriterStartElement(writer, "ikesalist"); + + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + ike_sa_id_t *id; + host_t *local, *remote; + iterator_t *children; + child_sa_t *child_sa; + + id = ike_sa->get_id(ike_sa); + + xmlTextWriterStartElement(writer, "ikesa"); + xmlTextWriterWriteFormatElement(writer, "id", "%d", + ike_sa->get_unique_id(ike_sa)); + xmlTextWriterWriteFormatElement(writer, "status", "%N", + ike_sa_state_lower_names, ike_sa->get_state(ike_sa)); + xmlTextWriterWriteElement(writer, "role", + id->is_initiator(id) ? "initiator" : "responder"); + xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa)); + + /* <local> */ + local = ike_sa->get_my_host(ike_sa); + xmlTextWriterStartElement(writer, "local"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_initiator_spi(id) + : id->get_responder_spi(id)); + write_id(writer, "identification", ike_sa->get_my_id(ike_sa)); + write_address(writer, "address", local); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + local->get_port(local)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) + { + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE)); + } + xmlTextWriterEndElement(writer); + /* </local> */ + + /* <remote> */ + remote = ike_sa->get_other_host(ike_sa); + xmlTextWriterStartElement(writer, "remote"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_responder_spi(id) + : id->get_initiator_spi(id)); + write_id(writer, "identification", ike_sa->get_other_id(ike_sa)); + write_address(writer, "address", remote); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + remote->get_port(remote)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) + { + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE)); + } + xmlTextWriterEndElement(writer); + /* </remote> */ + + /* <childsalist> */ + xmlTextWriterStartElement(writer, "childsalist"); + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + write_child(writer, child_sa); + } + children->destroy(children); + /* </childsalist> */ + xmlTextWriterEndElement(writer); + + /* </ikesa> */ + xmlTextWriterEndElement(writer); + } + enumerator->destroy(enumerator); + + /* </ikesalist> */ + xmlTextWriterEndElement(writer); +} + +/** + * process a configlist query request message + */ +static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + + /* <configlist> */ + xmlTextWriterStartElement(writer, "configlist"); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); + while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + { + enumerator_t *children; + child_cfg_t *child_cfg; + ike_cfg_t *ike_cfg; + linked_list_t *list; + + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { /* only IKEv2 connections yet */ + continue; + } + + /* <peerconfig> */ + xmlTextWriterStartElement(writer, "peerconfig"); + xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); + write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); + write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); + + /* <ikeconfig> */ + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + xmlTextWriterStartElement(writer, "ikeconfig"); + xmlTextWriterWriteElement(writer, "local", ike_cfg->get_my_addr(ike_cfg)); + xmlTextWriterWriteElement(writer, "remote", ike_cfg->get_other_addr(ike_cfg)); + xmlTextWriterEndElement(writer); + /* </ikeconfig> */ + + /* <childconfiglist> */ + xmlTextWriterStartElement(writer, "childconfiglist"); + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + /* <childconfig> */ + xmlTextWriterStartElement(writer, "childconfig"); + xmlTextWriterWriteElement(writer, "name", + child_cfg->get_name(child_cfg)); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + write_networks(writer, "local", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + write_networks(writer, "remote", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + xmlTextWriterEndElement(writer); + /* </childconfig> */ + } + children->destroy(children); + /* </childconfiglist> */ + xmlTextWriterEndElement(writer); + /* </peerconfig> */ + xmlTextWriterEndElement(writer); + } + enumerator->destroy(enumerator); + /* </configlist> */ + xmlTextWriterEndElement(writer); +} + +/** + * callback which logs to a XML writer + */ +static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level, + ike_sa_t* ike_sa, char* format, va_list args) +{ + if (level <= 1) + { + /* <item> */ + xmlTextWriterStartElement(writer, "item"); + xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); + xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal); + xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self()); + xmlTextWriterWriteVFormatString(writer, format, args); + xmlTextWriterEndElement(writer); + /* </item> */ + } + return TRUE; +} + +/** + * process a *terminate control request message + */ +static void request_control_terminate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + u_int32_t id; + status_t status; + + str = xmlTextReaderConstValue(reader); + if (str == NULL) + { + DBG1(DBG_CFG, "error parsing XML id string"); + return; + } + id = atoi(str); + if (!id) + { + enumerator_t *enumerator; + ike_sa_t *ike_sa; + + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + if (streq(str, ike_sa->get_name(ike_sa))) + { + ike = TRUE; + id = ike_sa->get_unique_id(ike_sa); + break; + } + } + enumerator->destroy(enumerator); + } + if (!id) + { + DBG1(DBG_CFG, "error parsing XML id string"); + return; + } + + DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + if (ike) + { + status = charon->controller->terminate_ike( + charon->controller, id, + (controller_cb_t)xml_callback, writer); + } + else + { + status = charon->controller->terminate_child( + charon->controller, id, + (controller_cb_t)xml_callback, writer); + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a *initiate control request message + */ +static void request_control_initiate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + status_t status = FAILED; + peer_cfg_t *peer; + child_cfg_t *child = NULL; + enumerator_t *enumerator; + + str = xmlTextReaderConstValue(reader); + if (str == NULL) + { + DBG1(DBG_CFG, "error parsing XML config name string"); + return; + } + DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str); + if (peer) + { + enumerator = peer->create_child_cfg_enumerator(peer); + if (ike) + { + if (!enumerator->enumerate(enumerator, &child)) + { + child = NULL; + } + child->get_ref(child); + } + else + { + while (enumerator->enumerate(enumerator, &child)) + { + if (streq(child->get_name(child), str)) + { + child->get_ref(child); + break; + } + child = NULL; + } + } + enumerator->destroy(enumerator); + if (child) + { + status = charon->controller->initiate(charon->controller, + peer, child, (controller_cb_t)xml_callback, + writer); + } + else + { + peer->destroy(peer); + } + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a query request + */ +static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* <query> */ + xmlTextWriterStartElement(writer, "query"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesalist")) + { + request_query_ikesa(reader, writer); + break; + } + if (streq(xmlTextReaderConstName(reader), "configlist")) + { + request_query_config(reader, writer); + break; + } + } + } + /* </query> */ + xmlTextWriterEndElement(writer); +} + +/** + * process a control request + */ +static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* <control> */ + xmlTextWriterStartElement(writer, "control"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesaterminate")) + { + request_control_terminate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsaterminate")) + { + request_control_terminate(reader, writer, FALSE); + break; + } + if (streq(xmlTextReaderConstName(reader), "ikesainitiate")) + { + request_control_initiate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsainitiate")) + { + request_control_initiate(reader, writer, FALSE); + break; + } + } + } + /* </control> */ + xmlTextWriterEndElement(writer); +} + +/** + * process a request message + */ +static void request(xmlTextReaderPtr reader, char *id, int fd) +{ + xmlTextWriterPtr writer; + + writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); + if (writer == NULL) + { + DBG1(DBG_CFG, "opening SMP XML writer failed"); + return; + } + + xmlTextWriterStartDocument(writer, NULL, NULL, NULL); + /* <message xmlns="http://www.strongswan.org/smp/1.0" + id="id" type="response"> */ + xmlTextWriterStartElement(writer, "message"); + xmlTextWriterWriteAttribute(writer, "xmlns", + "http://www.strongswan.org/smp/1.0"); + xmlTextWriterWriteAttribute(writer, "id", id); + xmlTextWriterWriteAttribute(writer, "type", "response"); + + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "query")) + { + request_query(reader, writer); + break; + } + if (streq(xmlTextReaderConstName(reader), "control")) + { + request_control(reader, writer); + break; + } + } + } + /* </message> and close document */ + xmlTextWriterEndDocument(writer); + xmlFreeTextWriter(writer); +} + +/** + * cleanup helper function for open file descriptors + */ +static void closefdp(int *fd) +{ + close(*fd); +} + +/** + * read from a opened connection and process it + */ +static job_requeue_t process(int *fdp) +{ + int oldstate, fd = *fdp; + char buffer[4096]; + size_t len; + xmlTextReaderPtr reader; + char *id = NULL, *type = NULL; + + pthread_cleanup_push((void*)closefdp, (void*)&fd); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + len = read(fd, buffer, sizeof(buffer)); + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); + if (len <= 0) + { + close(fd); + DBG2(DBG_CFG, "SMP XML connection closed"); + return JOB_REQUEUE_NONE; + } + DBG3(DBG_CFG, "got XML request: %b", buffer, len); + + reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); + if (reader == NULL) + { + DBG1(DBG_CFG, "opening SMP XML reader failed"); + return JOB_REQUEUE_FAIR;; + } + + /* read message type and id */ + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT && + streq(xmlTextReaderConstName(reader), "message")) + { + id = xmlTextReaderGetAttribute(reader, "id"); + type = xmlTextReaderGetAttribute(reader, "type"); + break; + } + } + + /* process message */ + if (id && type) + { + if (streq(type, "request")) + { + request(reader, id, fd); + } + else + { + /* response(reader, id) */ + } + } + xmlFreeTextReader(reader); + return JOB_REQUEUE_FAIR;; +} + +/** + * accept from XML socket and create jobs to process connections + */ +static job_requeue_t dispatch(private_smp_t *this) +{ + struct sockaddr_un strokeaddr; + int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr); + callback_job_t *job; + + /* wait for connections, but allow thread to terminate */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (fd < 0) + { + DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); + sleep(1); + return JOB_REQUEUE_FAIR;; + } + + fdp = malloc_thing(int); + *fdp = fd; + job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_DIRECT; +} + +/** + * Implementation of itnerface_t.destroy. + */ +static void destroy(private_smp_t *this) +{ + this->job->cancel(this->job); + close(this->socket); + free(this); +} + +/* + * Described in header file + */ +plugin_t *plugin_create() +{ + struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"}; + private_smp_t *this = malloc_thing(private_smp_t); + mode_t old; + + this->public.plugin.destroy = (void (*)(plugin_t*))destroy; + + /* set up unix socket */ + this->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "could not create XML socket"); + free(this); + return NULL; + } + + unlink(unix_addr.sun_path); + old = umask(~(S_IRWXU | S_IRWXG)); + if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) + { + DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + umask(old); + if (chown(unix_addr.sun_path, charon->uid, charon->gid) != 0) + { + DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno)); + } + + if (listen(this->socket, 5) < 0) + { + DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/smp/smp.h b/src/charon/plugins/smp/smp.h new file mode 100644 index 000000000..e65d5ea2c --- /dev/null +++ b/src/charon/plugins/smp/smp.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: smp.h 3689 2008-03-28 12:44:01Z martin $ + */ + +/** + * @defgroup smp smp + * @ingroup cplugins + * + * @defgroup smp_i smp + * @{ @ingroup smp + */ + +#ifndef SMP_H_ +#define SMP_H_ + +#include <plugins/plugin.h> + +typedef struct smp_t smp_t; + +/** + * SMP configuration and control interface. + * + * The SMP interface uses a socket and a to communicate. The syntax is strict + * XML, defined in the schema.xml specification. + */ +struct smp_t { + + /** + * implements the plugin interface. + */ + plugin_t plugin; +}; + +/** + * Create a smp plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* XML_H_ @}*/ diff --git a/src/charon/plugins/sql/Makefile.am b/src/charon/plugins/sql/Makefile.am new file mode 100644 index 000000000..ea39ce0d5 --- /dev/null +++ b/src/charon/plugins/sql/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic \ + -DSTRONGSWAN_CONF=\"${strongswan_conf}\" \ + -DIPSEC_PLUGINDIR=\"${plugindir}\" \ + -DPLUGINS=\""${libstrongswan_plugins}\"" + +plugin_LTLIBRARIES = libstrongswan-sql.la +libstrongswan_sql_la_SOURCES = sql_plugin.h sql_plugin.c \ + sql_config.h sql_config.c sql_cred.h sql_cred.c \ + sql_attribute.h sql_attribute.c sql_logger.h sql_logger.c +libstrongswan_sql_la_LDFLAGS = -module + +ipsec_PROGRAMS = pool +pool_SOURCES = pool.c +pool_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la diff --git a/src/charon/plugins/sql/Makefile.in b/src/charon/plugins/sql/Makefile.in new file mode 100644 index 000000000..babc11ecb --- /dev/null +++ b/src/charon/plugins/sql/Makefile.in @@ -0,0 +1,549 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +ipsec_PROGRAMS = pool$(EXEEXT) +subdir = src/charon/plugins/sql +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(ipsecdir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_sql_la_LIBADD = +am_libstrongswan_sql_la_OBJECTS = sql_plugin.lo sql_config.lo \ + sql_cred.lo sql_attribute.lo sql_logger.lo +libstrongswan_sql_la_OBJECTS = $(am_libstrongswan_sql_la_OBJECTS) +libstrongswan_sql_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_sql_la_LDFLAGS) $(LDFLAGS) -o $@ +ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(ipsec_PROGRAMS) +am_pool_OBJECTS = pool.$(OBJEXT) +pool_OBJECTS = $(am_pool_OBJECTS) +pool_DEPENDENCIES = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_sql_la_SOURCES) $(pool_SOURCES) +DIST_SOURCES = $(libstrongswan_sql_la_SOURCES) $(pool_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic \ + -DSTRONGSWAN_CONF=\"${strongswan_conf}\" \ + -DIPSEC_PLUGINDIR=\"${plugindir}\" \ + -DPLUGINS=\""${libstrongswan_plugins}\"" + +plugin_LTLIBRARIES = libstrongswan-sql.la +libstrongswan_sql_la_SOURCES = sql_plugin.h sql_plugin.c \ + sql_config.h sql_config.c sql_cred.h sql_cred.c \ + sql_attribute.h sql_attribute.c sql_logger.h sql_logger.c + +libstrongswan_sql_la_LDFLAGS = -module +pool_SOURCES = pool.c +pool_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/sql/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/sql/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-sql.la: $(libstrongswan_sql_la_OBJECTS) $(libstrongswan_sql_la_DEPENDENCIES) + $(libstrongswan_sql_la_LINK) -rpath $(plugindir) $(libstrongswan_sql_la_OBJECTS) $(libstrongswan_sql_la_LIBADD) $(LIBS) +install-ipsecPROGRAMS: $(ipsec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-ipsecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \ + done + +clean-ipsecPROGRAMS: + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +pool$(EXEEXT): $(pool_OBJECTS) $(pool_DEPENDENCIES) + @rm -f pool$(EXEEXT) + $(LINK) $(pool_OBJECTS) $(pool_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_attribute.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_cred.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_logger.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(ipsecdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ipsecPROGRAMS install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ipsecPROGRAMS uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-ipsecPROGRAMS clean-libtool clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-ipsecPROGRAMS install-man install-pdf \ + install-pdf-am install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-ipsecPROGRAMS \ + uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/sql/pool.c b/src/charon/plugins/sql/pool.c new file mode 100644 index 000000000..86ceddeee --- /dev/null +++ b/src/charon/plugins/sql/pool.c @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> +#include <time.h> + +#include <debug.h> +#include <library.h> +#include <utils/host.h> + +/** + * global database handle + */ +database_t *db; + +/** + * --start/--end addresses of various subcommands + */ +host_t *start = NULL, *end = NULL; + +/** + * create a host from a blob + */ +static host_t *host_create_from_blob(chunk_t blob) +{ + return host_create_from_chunk(blob.len == 4 ? AF_INET : AF_INET6, blob, 0); +} + +/** + * calculate the size of a pool using start and end address chunk + */ +static u_int get_pool_size(chunk_t start, chunk_t end) +{ + u_int *start_ptr, *end_ptr; + + if (start.len < sizeof(u_int) || end.len < sizeof(u_int)) + { + return 0; + } + start_ptr = (u_int*)(start.ptr + start.len - sizeof(u_int)); + end_ptr = (u_int*)(end.ptr + end.len - sizeof(u_int)); + return ntohl(*end_ptr) - ntohl(*start_ptr) + 1; +} + +/** + * print usage info + */ +static void usage(void) +{ + printf("\ +Usage:\n\ + ipsec pool --status|--add|--del|--resize|--purge [options]\n\ + \n\ + ipsec pool --status\n\ + Show a list of installed pools with statistics.\n\ + \n\ + ipsec pool --add <name> --start <start> --end <end> [--timeout <timeout>]\n\ + Add a new pool to the database.\n\ + name: Name of the pool, as used in ipsec.conf rightsourceip=%%name\n\ + start: Start address of the pool\n\ + end: End address of the pool\n\ + timeout: Lease time in hours, 0 for static leases\n\ + \n\ + ipsec pool --del <name>\n\ + Delete a pool from the database.\n\ + name: Name of the pool to delete\n\ + \n\ + ipsec pool --resize <name> --end <end>\n\ + Grow or shrink an existing pool.\n\ + name: Name of the pool to resize\n\ + end: New end address for the pool\n\ + \n\ + ipsec pool --leases <name> [--filter <filter>] [--utc]\n\ + Show lease information using filters:\n\ + name: Name of the pool to show leases from\n\ + filter: Filter string containing comma separated key=value filters,\n\ + e.g. id=alice@strongswan.org,addr=1.1.1.1\n\ + pool: name of the pool\n\ + id: assigned identity of the lease\n\ + addr: lease IP address\n\ + tstamp: UNIX timestamp when lease was valid, as integer\n\ + status: status of the lease: online|valid|expired\n\ + utc: Show times in UTC instead of local time\n\ + \n\ + ipsec pool --purge <name>\n\ + Delete expired leases of a pool:\n\ + name: Name of the pool to purge\n\ + \n"); + exit(0); +} + +/** + * ipsec pool --status - show pool overview + */ +static void status(void) +{ + enumerator_t *pool, *lease; + bool found = FALSE; + + pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools", + DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT); + if (pool) + { + char *name; + chunk_t start_chunk, end_chunk; + host_t *start, *end; + u_int id, timeout, online = 0, used = 0, size = 0; + + while (pool->enumerate(pool, &id, &name, + &start_chunk, &end_chunk, &timeout)) + { + if (!found) + { + printf("%8s %15s %15s %8s %6s %11s %11s\n", + "name", "start", "end", "timeout", "size", "online", "leases"); + found = TRUE; + } + + start = host_create_from_blob(start_chunk); + end = host_create_from_blob(end_chunk); + size = get_pool_size(start_chunk, end_chunk); + printf("%8s %15H %15H ", name, start, end); + if (timeout) + { + printf("%7dh ", timeout/3600); + } + else + { + printf("%8s ", "static"); + } + printf("%6d ", size); + /* get number of online hosts */ + lease = db->query(db, "SELECT COUNT(*) FROM leases " + "WHERE pool = ? AND released IS NULL", + DB_UINT, id, DB_INT); + if (lease) + { + lease->enumerate(lease, &online); + lease->destroy(lease); + } + printf("%5d (%2d%%) ", online, online*100/size); + /* get number of online or valid lieases */ + lease = db->query(db, "SELECT COUNT(*) FROM leases JOIN pools " + "ON leases.pool = pools.id " + "WHERE pools.id = ? " + "AND (released IS NULL OR released > ? - timeout) ", + DB_UINT, id, DB_UINT, time(NULL), DB_UINT); + if (lease) + { + lease->enumerate(lease, &used); + lease->destroy(lease); + } + printf("%5d (%2d%%) ", used, used*100/size); + + printf("\n"); + DESTROY_IF(start); + DESTROY_IF(end); + } + pool->destroy(pool); + } + if (!found) + { + printf("no pools found.\n"); + } + exit(0); +} + +/** + * ipsec pool --add - add a new pool + */ +static void add(char *name, host_t *start, host_t *end, int timeout) +{ + chunk_t start_addr, end_addr; + + start_addr = start->get_address(start); + end_addr = end->get_address(end); + + if (start_addr.len != end_addr.len || + memcmp(start_addr.ptr, end_addr.ptr, start_addr.len) > 0) + { + fprintf(stderr, "invalid start/end pair specified.\n"); + exit(-1); + } + if (db->execute(db, NULL, + "INSERT INTO pools (name, start, end, next, timeout) " + "VALUES (?, ?, ?, ?, ?)", + DB_TEXT, name, DB_BLOB, start_addr, + DB_BLOB, end_addr, DB_BLOB, start_addr, + DB_INT, timeout*3600) != 1) + { + fprintf(stderr, "creating pool failed.\n"); + exit(-1); + } + exit(0); +} + +/** + * ipsec pool --del - delete a pool + */ +static void del(char *name) +{ + enumerator_t *query; + u_int id; + bool found = FALSE; + + query = db->query(db, "SELECT id FROM pools WHERE name = ?", + DB_TEXT, name, DB_UINT); + if (!query) + { + fprintf(stderr, "deleting pool failed.\n"); + exit(-1); + } + while (query->enumerate(query, &id)) + { + found = TRUE; + if (db->execute(db, NULL, + "DELETE FROM pools WHERE id = ?", DB_UINT, id) != 1 || + db->execute(db, NULL, + "DELETE FROM leases WHERE pool = ?", DB_UINT, id) < 0) + { + fprintf(stderr, "deleting pool failed.\n"); + query->destroy(query); + exit(-1); + } + } + query->destroy(query); + if (!found) + { + fprintf(stderr, "pool '%s' not found.\n", name); + exit(-1); + } + exit(0); +} + +/** + * ipsec pool --resize - resize a pool + */ +static void resize(char *name, host_t *end) +{ + enumerator_t *query; + chunk_t next_addr, end_addr; + + end_addr = end->get_address(end); + + query = db->query(db, "SELECT next FROM pools WHERE name = ?", + DB_TEXT, name, DB_BLOB); + if (!query || !query->enumerate(query, &next_addr)) + { + DESTROY_IF(query); + fprintf(stderr, "resizing pool failed.\n"); + exit(-1); + } + if (next_addr.len != end_addr.len || + memcmp(end_addr.ptr, next_addr.ptr, end_addr.len) < 0) + { + end = host_create_from_blob(next_addr); + fprintf(stderr, "pool addresses up to %H in use, resizing failed.\n", end); + end->destroy(end); + query->destroy(query); + exit(-1); + } + query->destroy(query); + + if (db->execute(db, NULL, + "UPDATE pools SET end = ? WHERE name = ?", + DB_BLOB, end_addr, DB_TEXT, name) <= 0) + { + fprintf(stderr, "pool '%s' not found.\n", name); + exit(-1); + } + exit(0); +} + +/** + * create the lease query using the filter string + */ +static enumerator_t *create_lease_query(char *filter) +{ + enumerator_t *query; + identification_t *id = NULL; + host_t *addr = NULL; + u_int tstamp = 0; + bool online = FALSE, valid = FALSE, expired = FALSE; + char *value, *pos, *pool = NULL; + enum { + FIL_POOL = 0, + FIL_ID, + FIL_ADDR, + FIL_TSTAMP, + FIL_STATE, + }; + char *const token[] = { + [FIL_POOL] = "pool", + [FIL_ID] = "id", + [FIL_ADDR] = "addr", + [FIL_TSTAMP] = "tstamp", + [FIL_STATE] = "status", + NULL + }; + + /* if the filter string contains a distinguished name as a ID, we replace + * ", " by "/ " in order to not confuse the getsubopt parser */ + pos = filter; + while ((pos = strchr(pos, ','))) + { + if (pos[1] == ' ') + { + pos[0] = '/'; + } + pos++; + } + + while (filter && *filter != '\0') + { + switch (getsubopt(&filter, token, &value)) + { + case FIL_POOL: + if (value) + { + pool = value; + } + break; + case FIL_ID: + if (value) + { + id = identification_create_from_string(value); + } + if (!id) + { + fprintf(stderr, "invalid 'id' in filter string.\n"); + exit(-1); + } + break; + case FIL_ADDR: + if (value) + { + addr = host_create_from_string(value, 0); + } + if (!addr) + { + fprintf(stderr, "invalid 'addr' in filter string.\n"); + exit(-1); + } + break; + case FIL_TSTAMP: + if (value) + { + tstamp = atoi(value); + } + if (tstamp == 0) + { + online = TRUE; + } + break; + case FIL_STATE: + if (value) + { + if (streq(value, "online")) + { + online = TRUE; + } + else if (streq(value, "valid")) + { + valid = TRUE; + } + else if (streq(value, "expired")) + { + expired = TRUE; + } + else + { + fprintf(stderr, "invalid 'state' in filter string.\n"); + exit(-1); + } + } + break; + default: + fprintf(stderr, "invalid filter string.\n"); + exit(-1); + break; + } + } + query = db->query(db, + "SELECT name, address, identities.type, " + "identities.data, acquired, released, timeout " + "FROM leases JOIN pools ON leases.pool = pools.id " + "JOIN identities ON leases.identity = identities.id " + "WHERE (? OR name = ?) " + "AND (? OR (identities.type = ? AND identities.data = ?)) " + "AND (? OR address = ?) " + "AND (? OR (? >= acquired AND (? <= released OR released IS NULL))) " + "AND (? OR released IS NULL) " + "AND (? OR released > ? - timeout) " + "AND (? OR released < ? - timeout)", + DB_INT, pool == NULL, DB_TEXT, pool, + DB_INT, id == NULL, + DB_INT, id ? id->get_type(id) : 0, + DB_BLOB, id ? id->get_encoding(id) : chunk_empty, + DB_INT, addr == NULL, + DB_BLOB, addr ? addr->get_address(addr) : chunk_empty, + DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp, + DB_INT, !online, + DB_INT, !valid, DB_INT, time(NULL), + DB_INT, !expired, DB_INT, time(NULL), + DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT); + /* id and addr leak but we can't destroy them until query is destroyed. */ + return query; +} + +/** + * ipsec pool --leases - show lease information of a pool + */ +static void leases(char *filter, bool utc) +{ + enumerator_t *query; + chunk_t address_chunk, identity_chunk; + int identity_type; + char *name; + u_int acquired, released, timeout; + host_t *address; + identification_t *identity; + bool found = FALSE; + + query = create_lease_query(filter); + if (!query) + { + fprintf(stderr, "querying leases failed.\n"); + exit(-1); + } + while (query->enumerate(query, &name, &address_chunk, &identity_type, + &identity_chunk, &acquired, &released, &timeout)) + { + if (!found) + { + int len = utc ? 25 : 21; + + found = TRUE; + printf("%-8s %-15s %-7s %-*s %-*s %s\n", + "name", "address", "status", len, "start", len, "end", "identity"); + } + address = host_create_from_blob(address_chunk); + identity = identification_create_from_encoding(identity_type, identity_chunk); + + printf("%-8s %-15H ", name, address); + if (released == 0) + { + printf("%-7s ", "online"); + } + else if (timeout == 0) + { + printf("%-7s ", "static"); + } + else if (released >= time(NULL) - timeout) + { + printf("%-7s ", "valid"); + } + else + { + printf("%-7s ", "expired"); + } + + printf(" %#T ", &acquired, utc); + if (released) + { + printf("%#T ", &released, utc); + } + else + { + printf(" "); + if (utc) + { + printf(" "); + } + } + printf("%D\n", identity); + DESTROY_IF(address); + identity->destroy(identity); + } + query->destroy(query); + if (!found) + { + fprintf(stderr, "no matching leases found.\n"); + exit(-1); + } + exit(0); +} + +/** + * ipsec pool --purge - delete expired leases + */ +static void purge(char *name) +{ + enumerator_t *query; + u_int id, timeout, purged = 0; + + query = db->query(db, "SELECT id, timeout FROM pools WHERE name = ?", + DB_TEXT, name, DB_UINT, DB_UINT); + if (!query) + { + fprintf(stderr, "purging pool failed.\n"); + exit(-1); + } + /* we have to keep one lease if we purge. It wouldn't be reallocateable + * as we move on the "next" address for speedy allocation */ + if (query->enumerate(query, &id, &timeout)) + { + timeout = time(NULL) - timeout; + purged = db->execute(db, NULL, + "DELETE FROM leases WHERE pool = ? " + "AND released IS NOT NULL AND released < ? AND id NOT IN (" + " SELECT id FROM leases " + " WHERE released IS NOT NULL and released < ? " + " GROUP BY address)", + DB_UINT, id, DB_UINT, timeout, DB_UINT, timeout); + } + query->destroy(query); + fprintf(stderr, "purged %d leases in pool '%s'.\n", purged, name); + exit(0); +} + +/** + * atexit handler to close db on shutdown + */ +static void cleanup(void) +{ + db->destroy(db); + DESTROY_IF(start); + DESTROY_IF(end); +} + +/** + * Logging hook for library logs, using stderr output + */ +static void dbg_stderr(int level, char *fmt, ...) +{ + va_list args; + + if (level <= 1) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } +} + +int main(int argc, char *argv[]) +{ + char *uri, *name = "", *filter = ""; + int timeout = 0; + bool utc = FALSE; + enum { + OP_USAGE, + OP_STATUS, + OP_ADD, + OP_DEL, + OP_RESIZE, + OP_LEASES, + OP_PURGE, + } operation = OP_USAGE; + + dbg = dbg_stderr; + library_init(STRONGSWAN_CONF); + atexit(library_deinit); + lib->plugins->load(lib->plugins, IPSEC_PLUGINDIR, + lib->settings->get_str(lib->settings, "pool.load", PLUGINS)); + + uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL); + if (!uri) + { + fprintf(stderr, "database URI charon.plugins.sql.database not set.\n"); + exit(-1); + } + db = lib->db->create(lib->db, uri); + if (!db) + { + fprintf(stderr, "opening database failed.\n"); + exit(-1); + } + atexit(cleanup); + + while (TRUE) + { + int c; + + struct option long_opts[] = { + { "help", no_argument, NULL, 'h' }, + + { "utc", no_argument, NULL, 'u' }, + { "status", no_argument, NULL, 'w' }, + { "add", required_argument, NULL, 'a' }, + { "del", required_argument, NULL, 'd' }, + { "resize", required_argument, NULL, 'r' }, + { "leases", no_argument, NULL, 'l' }, + { "purge", required_argument, NULL, 'p' }, + + { "start", required_argument, NULL, 's' }, + { "end", required_argument, NULL, 'e' }, + { "timeout", required_argument, NULL, 't' }, + { "filter", required_argument, NULL, 'f' }, + { 0,0,0,0 } + }; + + c = getopt_long(argc, argv, "", long_opts, NULL); + switch (c) + { + case EOF: + break; + case 'h': + break; + case 'w': + operation = OP_STATUS; + break; + case 'u': + utc = TRUE; + continue; + case 'a': + operation = OP_ADD; + name = optarg; + continue; + case 'd': + operation = OP_DEL; + name = optarg; + continue; + case 'r': + operation = OP_RESIZE; + name = optarg; + continue; + case 'l': + operation = OP_LEASES; + continue; + case 'p': + operation = OP_PURGE; + name = optarg; + continue; + case 's': + start = host_create_from_string(optarg, 0); + if (start == NULL) + { + fprintf(stderr, "invalid start address: '%s'.\n", optarg); + operation = OP_USAGE; + break; + } + continue; + case 'e': + end = host_create_from_string(optarg, 0); + if (end == NULL) + { + fprintf(stderr, "invalid end address: '%s'.\n", optarg); + operation = OP_USAGE; + break; + } + continue; + case 't': + timeout = atoi(optarg); + if (timeout == 0 && strcmp(optarg, "0") != 0) + { + fprintf(stderr, "invalid timeout '%s'.\n", optarg); + operation = OP_USAGE; + break; + } + continue; + case 'f': + filter = optarg; + continue; + default: + operation = OP_USAGE; + break; + } + break; + } + + switch (operation) + { + case OP_USAGE: + usage(); + break; + case OP_STATUS: + status(); + break; + case OP_ADD: + if (start == NULL || end == NULL) + { + fprintf(stderr, "missing arguments.\n"); + usage(); + } + add(name, start, end, timeout); + break; + case OP_DEL: + del(name); + break; + case OP_RESIZE: + if (end == NULL) + { + fprintf(stderr, "missing arguments.\n"); + usage(); + } + resize(name, end); + break; + case OP_LEASES: + leases(filter, utc); + break; + case OP_PURGE: + purge(name); + break; + } + exit(0); +} + diff --git a/src/charon/plugins/sql/sql_attribute.c b/src/charon/plugins/sql/sql_attribute.c new file mode 100644 index 000000000..45c0750c7 --- /dev/null +++ b/src/charon/plugins/sql/sql_attribute.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "sql_attribute.h" + +#include <daemon.h> +#include <utils/mutex.h> + +typedef struct private_sql_attribute_t private_sql_attribute_t; + +/** + * private data of sql_attribute + */ +struct private_sql_attribute_t { + + /** + * public functions + */ + sql_attribute_t public; + + /** + * database connection + */ + database_t *db; + + /** + * mutex to simulate transactions + */ + mutex_t *mutex; +}; + +/** + * convert a address blob to an ip of the correct family + */ +static host_t *ip_from_chunk(chunk_t address) +{ + switch (address.len) + { + case 4: + return host_create_from_chunk(AF_INET, address, 0); + case 16: + return host_create_from_chunk(AF_INET6, address, 0); + default: + return NULL; + } +} + +/** + * increment a chunk, as it would reprensent a network order integer + */ +static void increment_chunk(chunk_t chunk) +{ + int i; + + for (i = chunk.len - 1; i >= 0; i++) + { + if (++chunk.ptr[i] != 0) + { + return; + } + } +} + +/** + * Lookup if we have an existing lease + */ +static host_t* get_lease(private_sql_attribute_t *this, + char *name, identification_t *id) +{ + enumerator_t *e; + chunk_t address; + host_t *ip = NULL; + int lease; + + /* transaction simulation, see create_lease() */ + this->mutex->lock(this->mutex); + + /* select a lease for "id" which still valid */ + e = this->db->query(this->db, + "SELECT l.id, l.address FROM leases AS l " + "JOIN pools AS p ON l.pool = p.id " + "JOIN identities AS i ON l.identity = i.id " + "WHERE p.name = ? AND i.type = ? AND i.data = ? " + "AND (l.released IS NULL OR p.timeout = 0 " + " OR (l.released >= (? - p.timeout))) " + "ORDER BY l.acquired LIMIT 1", DB_TEXT, name, + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), + DB_UINT, time(NULL), + DB_UINT, DB_BLOB); + if (e) + { + if (e->enumerate(e, &lease, &address)) + { + /* found one, set the lease to active */ + if (this->db->execute(this->db, NULL, + "UPDATE leases SET released = NULL WHERE id = ?", + DB_UINT, lease) > 0) + { + ip = ip_from_chunk(address); + DBG1(DBG_CFG, "reassigning address from valid lease " + "from pool '%s'", name); + } + } + e->destroy(e); + } + this->mutex->unlock(this->mutex); + return ip; +} + +/** + * Create a new lease entry for client + */ +static host_t* create_lease(private_sql_attribute_t *this, + char *name, identification_t *id) +{ + enumerator_t *e; + chunk_t address; + host_t *ip = NULL; + u_int pool, identity = 0, released, timeout; + bool new = FALSE; + + /* we currently do not use database transactions. While this would be + * the clean way, there is no real advantage, but some disadvantages: + * - we would require InnoDB for mysql, as MyISAM does not support trans. + * - the mysql plugin uses connection pooling, and we would need a + * mechanism to lock transactions to a single connection. + */ + this->mutex->lock(this->mutex); + + /* find an address which has outdated leases only. The HAVING clause filters + * out leases which are active (released = NULL) or not expired */ + e = this->db->query(this->db, + "SELECT pool, address, released, timeout FROM leases " + "JOIN pools ON leases.pool = pools.id " + "WHERE name = ? and timeout > 0 " + "GROUP BY address HAVING COUNT(released) = COUNT(*) " + "AND MAX(released) < (? - timeout) LIMIT 1", + DB_TEXT, name, DB_UINT, time(NULL), + DB_UINT, DB_BLOB, DB_UINT, DB_UINT); + + if (!e || !e->enumerate(e, &pool, &address, &released, &timeout)) + { + DESTROY_IF(e); + /* no outdated lease found, acquire new address */ + e = this->db->query(this->db, + "SELECT id, next FROM pools WHERE name = ? AND next <= end", + DB_TEXT, name, + DB_UINT, DB_BLOB); + if (!e || !e->enumerate(e, &pool, &address)) + { + /* pool seems full */ + DESTROY_IF(e); + this->mutex->unlock(this->mutex); + return NULL; + } + new = TRUE; + } + address = chunk_clonea(address); + e->destroy(e); + + /* look for peer identity in the identities table */ + e = this->db->query(this->db, + "SELECT id FROM identities WHERE type = ? AND data = ?", + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), + DB_UINT); + if (!e || !e->enumerate(e, &identity)) + { + DESTROY_IF(e); + /* not found, insert new one */ + this->db->execute(this->db, &identity, + "INSERT INTO identities (type, data) VALUES (?, ?)", + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)); + } + else + { + e->destroy(e); + } + /* if we have an identity, insert a new lease */ + if (identity) + { + if (this->db->execute(this->db, NULL, + "INSERT INTO leases (pool, address, identity, acquired) " + "VALUES (?, ?, ?, ?)", + DB_UINT, pool, DB_BLOB, address, DB_UINT, identity, + DB_UINT, time(NULL)) > 0) + { + ip = ip_from_chunk(address); + if (new) + { /* update next address, as we have consumed one */ + increment_chunk(address); + this->db->execute(this->db, NULL, + "UPDATE pools SET next = ? WHERE id = ?", + DB_BLOB, address, DB_UINT, pool); + DBG1(DBG_CFG, "assigning lease with new address " + "from pool '%s'", name); + } + else + { + DBG1(DBG_CFG, "reassigning address from expired lease " + "from pool '%s'", name); + } + } + } + this->mutex->unlock(this->mutex); + return ip; +} + +/** + * Implementation of attribute_provider_t.acquire_address + */ +static host_t* acquire_address(private_sql_attribute_t *this, + char *name, identification_t *id, + auth_info_t *auth, host_t *requested) +{ + host_t *ip; + + ip = get_lease(this, name, id); + if (!ip) + { + ip = create_lease(this, name, id); + } + return ip; +} + +/** + * Implementation of attribute_provider_t.release_address + */ +static bool release_address(private_sql_attribute_t *this, + char *name, host_t *address) +{ + if (this->db->execute(this->db, NULL, + "UPDATE leases SET released = ? WHERE " + "pool IN (SELECT id FROM pools WHERE name = ?) AND " + "address = ? AND released IS NULL", + DB_UINT, time(NULL), + DB_TEXT, name, DB_BLOB, address->get_address(address)) > 0) + { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of sql_attribute_t.destroy + */ +static void destroy(private_sql_attribute_t *this) +{ + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +sql_attribute_t *sql_attribute_create(database_t *db) +{ + private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t); + + this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address; + this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *))release_address; + this->public.destroy = (void(*)(sql_attribute_t*))destroy; + + this->db = db; + this->mutex = mutex_create(MUTEX_DEFAULT); + + /* close any "online" leases in the case we crashed */ + this->db->execute(this->db, NULL, + "UPDATE leases SET released = ? WHERE released IS NULL", + DB_UINT, time(NULL)); + + return &this->public; +} + diff --git a/src/charon/plugins/sql/sql_attribute.h b/src/charon/plugins/sql/sql_attribute.h new file mode 100644 index 000000000..211204ced --- /dev/null +++ b/src/charon/plugins/sql/sql_attribute.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup sql_attribute sql_attribute + * @{ @ingroup sql + */ + +#ifndef SQL_ATTRIBUTE_H_ +#define SQL_ATTRIBUTE_H_ + +#include <config/attributes/attribute_provider.h> + +typedef struct sql_attribute_t sql_attribute_t; + +/** + * SQL database based IKEv2 cfg attribute provider. + */ +struct sql_attribute_t { + + /** + * Implements attribute provider interface + */ + attribute_provider_t provider; + + /** + * Destroy a sql_attribute instance. + */ + void (*destroy)(sql_attribute_t *this); +}; + +/** + * Create a sql_attribute instance. + */ +sql_attribute_t *sql_attribute_create(database_t *db); + +#endif /* SQL_ATTRIBUTE_H_ @}*/ diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c new file mode 100644 index 000000000..3785839cf --- /dev/null +++ b/src/charon/plugins/sql/sql_config.c @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_config.c 4044 2008-06-06 15:05:54Z martin $ + */ + +#include <string.h> + +#include "sql_config.h" + +#include <daemon.h> + +typedef struct private_sql_config_t private_sql_config_t; + +/** + * Private data of an sql_config_t object + */ +struct private_sql_config_t { + + /** + * Public part + */ + sql_config_t public; + + /** + * database connection + */ + database_t *db; +}; + +/** + * forward declaration + */ +static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, + identification_t *me, identification_t *other); + +/** + * build a traffic selector from a SQL query + */ +static traffic_selector_t *build_traffic_selector(private_sql_config_t *this, + enumerator_t *e, bool *local) +{ + int type, protocol, start_port, end_port; + chunk_t start_addr, end_addr; + traffic_selector_t *ts; + enum { + TS_LOCAL = 0, + TS_REMOTE = 1, + TS_LOCAL_DYNAMIC = 2, + TS_REMOTE_DYNAMIC = 3, + } kind; + + while (e->enumerate(e, &kind, &type, &protocol, + &start_addr, &end_addr, &start_port, &end_port)) + { + *local = FALSE; + switch (kind) + { + case TS_LOCAL: + *local = TRUE; + /* FALL */ + case TS_REMOTE: + ts = traffic_selector_create_from_bytes(protocol, type, + start_addr, start_port, end_addr, end_port); + break; + case TS_LOCAL_DYNAMIC: + *local = TRUE; + /* FALL */ + case TS_REMOTE_DYNAMIC: + ts = traffic_selector_create_dynamic(protocol, + start_port, end_port); + break; + default: + continue; + } + if (ts) + { + return ts; + } + } + return NULL; +} + +/** + * Add traffic selectors to a child config + */ +static void add_traffic_selectors(private_sql_config_t *this, + child_cfg_t *child, int id) +{ + enumerator_t *e; + traffic_selector_t *ts; + bool local; + + e = this->db->query(this->db, + "SELECT kind, type, protocol, " + "start_addr, end_addr, start_port, end_port " + "FROM traffic_selectors JOIN child_config_traffic_selector " + "ON id = traffic_selector WHERE child_cfg = ?", + DB_INT, id, + DB_INT, DB_INT, DB_INT, + DB_BLOB, DB_BLOB, DB_INT, DB_INT); + if (e) + { + while ((ts = build_traffic_selector(this, e, &local))) + { + child->add_traffic_selector(child, local, ts); + } + e->destroy(e); + } +} + +/** + * build a Child configuration from a SQL query + */ +static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) +{ + int id, lifetime, rekeytime, jitter, hostaccess, mode, dpd, close, ipcomp; + char *name, *updown; + child_cfg_t *child_cfg; + + if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, + &updown, &hostaccess, &mode, &dpd, &close, &ipcomp)) + { + child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter, + updown, hostaccess, mode, dpd, close, ipcomp); + /* TODO: read proposal from db */ + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + add_traffic_selectors(this, child_cfg, id); + return child_cfg; + } + return NULL; +} + +/** + * Add child configs to peer config + */ +static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id) +{ + enumerator_t *e; + child_cfg_t *child_cfg; + + e = this->db->query(this->db, + "SELECT id, name, lifetime, rekeytime, jitter, " + "updown, hostaccess, mode, dpd_action, close_action, ipcomp " + "FROM child_configs JOIN peer_config_child_config ON id = child_cfg " + "WHERE peer_cfg = ?", + DB_INT, id, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, + DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while ((child_cfg = build_child_cfg(this, e))) + { + peer->add_child_cfg(peer, child_cfg); + } + e->destroy(e); + } +} + +/** + * build a ike configuration from a SQL query + */ +static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e, + host_t *my_host, host_t *other_host) +{ + int certreq, force_encap; + char *local, *remote; + + while (e->enumerate(e, &certreq, &force_encap, &local, &remote)) + { + ike_cfg_t *ike_cfg; + + ike_cfg = ike_cfg_create(certreq, force_encap, local, remote); + /* TODO: read proposal from db */ + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + return ike_cfg; + } + return NULL; +} + +/** + * Query a IKE config by its id + */ +static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id) +{ + enumerator_t *e; + ike_cfg_t *ike_cfg = NULL; + + e = this->db->query(this->db, + "SELECT certreq, force_encap, local, remote " + "FROM ike_configs WHERE id = ?", + DB_INT, id, + DB_INT, DB_INT, DB_TEXT, DB_TEXT); + if (e) + { + ike_cfg = build_ike_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return ike_cfg; +} + +/** + * Query a peer config by its id + */ +static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg = NULL; + + e = this->db->query(this->db, + "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, " + "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, " + "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, virtual, pool, " + "mediation, mediated_by, COALESCE(p.type, 0), p.data " + "FROM peer_configs AS c " + "JOIN identities AS l ON local_id = l.id " + "JOIN identities AS r ON remote_id = r.id " + "LEFT JOIN identities AS p ON peer_id = p.id " + "WHERE id = ?", + DB_INT, id, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_INT, DB_BLOB); + if (e) + { + peer_cfg = build_peer_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return peer_cfg; +} + +/** + * build a peer configuration from a SQL query + */ +static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, + identification_t *me, identification_t *other) +{ + int id, ike_cfg, l_type, r_type, + cert_policy, uniqueid, auth_method, eap_type, eap_vendor, keyingtries, + rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, + mediation, mediated_by, p_type; + chunk_t l_data, r_data, p_data; + char *name, *virtual, *pool; + + while (e->enumerate(e, + &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data, + &cert_policy, &uniqueid, &auth_method, &eap_type, &eap_vendor, + &keyingtries, &rekeytime, &reauthtime, &jitter, &overtime, &mobike, + &dpd_delay, &virtual, &pool, + &mediation, &mediated_by, &p_type, &p_data)) + { + identification_t *local_id, *remote_id, *peer_id = NULL; + peer_cfg_t *peer_cfg, *mediated_cfg; + ike_cfg_t *ike; + host_t *vip = NULL; + + local_id = identification_create_from_encoding(l_type, l_data); + remote_id = identification_create_from_encoding(r_type, r_data); + if ((me && !me->matches(me, local_id)) || + (other && !other->matches(other, remote_id))) + { + local_id->destroy(local_id); + remote_id->destroy(remote_id); + continue; + } + ike = get_ike_cfg_by_id(this, ike_cfg); + mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL; + if (p_type) + { + peer_id = identification_create_from_encoding(p_type, p_data); + } + if (virtual) + { + vip = host_create_from_string(virtual, 0); + } + if (ike) + { + peer_cfg = peer_cfg_create( + name, 2, ike, local_id, remote_id, cert_policy, uniqueid, + auth_method, eap_type, eap_vendor, keyingtries, + rekeytime, reauthtime, jitter, overtime, mobike, + dpd_delay, vip, pool, + mediation, mediated_cfg, peer_id); + add_child_cfgs(this, peer_cfg, id); + return peer_cfg; + } + DESTROY_IF(ike); + DESTROY_IF(mediated_cfg); + DESTROY_IF(peer_id); + DESTROY_IF(local_id); + DESTROY_IF(remote_id); + } + return NULL; +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg = NULL; + + e = this->db->query(this->db, + "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, " + "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, " + "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, virtual, pool, " + "mediation, mediated_by, COALESCE(p.type, 0), p.data " + "FROM peer_configs AS c " + "JOIN identities AS l ON local_id = l.id " + "JOIN identities AS r ON remote_id = r.id " + "LEFT JOIN identities AS p ON peer_id = p.id " + "WHERE ike_version = ? AND name = ?", + DB_INT, 2, DB_TEXT, name, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_INT, DB_BLOB); + if (e) + { + peer_cfg = build_peer_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return peer_cfg; +} + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** reference to context */ + private_sql_config_t *this; + /** filtering own host */ + host_t *me; + /** filtering remote host */ + host_t *other; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + ike_cfg_t *current; +} ike_enumerator_t; + +/** + * Implementation of ike_enumerator_t.public.enumerate + */ +static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg) +{ + DESTROY_IF(this->current); + this->current = build_ike_cfg(this->this, this->inner, this->me, this->other); + if (this->current) + { + *cfg = this->current; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of ike_enumerator_t.public.destroy + */ +static void ike_enumerator_destroy(ike_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this, + host_t *me, host_t *other) +{ + ike_enumerator_t *e = malloc_thing(ike_enumerator_t); + + e->this = this; + e->me = me; + e->other = other; + e->current = NULL; + e->public.enumerate = (void*)ike_enumerator_enumerate; + e->public.destroy = (void*)ike_enumerator_destroy; + + e->inner = this->db->query(this->db, + "SELECT certreq, force_encap, local, remote " + "FROM ike_configs", + DB_INT, DB_INT, DB_TEXT, DB_TEXT); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** reference to context */ + private_sql_config_t *this; + /** filtering own identity */ + identification_t *me; + /** filtering remote identity */ + identification_t *other; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + peer_cfg_t *current; +} peer_enumerator_t; + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +{ + DESTROY_IF(this->current); + this->current = build_peer_cfg(this->this, this->inner, this->me, this->other); + if (this->current) + { + *cfg = this->current; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of peer_enumerator_t.public.destroy + */ +static void peer_enumerator_destroy(peer_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_enumerator_t *e = malloc_thing(peer_enumerator_t); + + e->this = this; + e->me = me; + e->other = other; + e->current = NULL; + e->public.enumerate = (void*)peer_enumerator_enumerate; + e->public.destroy = (void*)peer_enumerator_destroy; + + /* TODO: only get configs whose IDs match exactly or contain wildcards */ + e->inner = this->db->query(this->db, + "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, " + "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, " + "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, virtual, pool, " + "mediation, mediated_by, COALESCE(p.type, 0), p.data " + "FROM peer_configs AS c " + "JOIN identities AS l ON local_id = l.id " + "JOIN identities AS r ON remote_id = r.id " + "LEFT JOIN identities AS p ON peer_id = p.id " + "WHERE ike_version = ?", + DB_INT, 2, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_INT, DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of sql_config_t.destroy. + */ +static void destroy(private_sql_config_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +sql_config_t *sql_config_create(database_t *db) +{ + private_sql_config_t *this = malloc_thing(private_sql_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(sql_config_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/sql/sql_config.h b/src/charon/plugins/sql/sql_config.h new file mode 100644 index 000000000..d34705c71 --- /dev/null +++ b/src/charon/plugins/sql/sql_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_config.h 3594 2008-03-13 14:53:57Z martin $ + */ + +/** + * @defgroup sql_config_i sql_config + * @{ @ingroup sql + */ + +#ifndef SQL_CONFIG_H_ +#define SQL_CONFIG_H_ + +#include <config/backend.h> +#include <database/database.h> + +typedef struct sql_config_t sql_config_t; + +/** + * SQL database configuration backend. + */ +struct sql_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destry the backend. + */ + void (*destroy)(sql_config_t *this); +}; + +/** + * Create a sql_config backend instance. + * + * @param db underlying database + * @return backend instance + */ +sql_config_t *sql_config_create(database_t *db); + +#endif /* SQL_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/sql/sql_cred.c b/src/charon/plugins/sql/sql_cred.c new file mode 100644 index 000000000..9d91973c2 --- /dev/null +++ b/src/charon/plugins/sql/sql_cred.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_cred.c 3589 2008-03-13 14:14:44Z martin $ + */ + +#include <string.h> + +#include "sql_cred.h" + +#include <daemon.h> + +typedef struct private_sql_cred_t private_sql_cred_t; + +/** + * Private data of an sql_cred_t object + */ +struct private_sql_cred_t { + + /** + * Public part + */ + sql_cred_t public; + + /** + * database connection + */ + database_t *db; +}; + +/** + * enumerator over private keys + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated private key */ + private_key_t *current; +} private_enumerator_t; + +/** + * Implementation of private_enumerator_t.public.enumerate + */ +static bool private_enumerator_enumerate(private_enumerator_t *this, + private_key_t **key) +{ + chunk_t blob; + int type; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &type, &blob)) + { + this->current = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_BLOB_ASN1_DER, chunk_clone(blob), + BUILD_END); + if (this->current) + { + *key = this->current; + return TRUE; + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of private_enumerator_t.public.destroy + */ +static void private_enumerator_destroy(private_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_private_enumerator. + */ +static enumerator_t* create_private_enumerator(private_sql_cred_t *this, + key_type_t type, + identification_t *id) +{ + private_enumerator_t *e; + + e = malloc_thing(private_enumerator_t); + e->current = NULL; + e->public.enumerate = (void*)private_enumerator_enumerate; + e->public.destroy = (void*)private_enumerator_destroy; + if (id && id->get_type(id) != ID_ANY) + { + e->inner = this->db->query(this->db, + "SELECT p.type, p.data FROM private_keys AS p " + "JOIN private_key_identity AS pi ON p.id = pi.private_key " + "JOIN identities AS i ON pi.identity = i.id " + "WHERE i.type = ? AND i.data = ? AND (? OR p.type = ?)", + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), + DB_INT, type == KEY_ANY, DB_INT, type, + DB_INT, DB_BLOB); + } + else + { + e->inner = this->db->query(this->db, + "SELECT type, data FROM private_keys WHERE (? OR type = ?)", + DB_INT, type == KEY_ANY, DB_INT, type, + DB_INT, DB_BLOB); + } + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated cert */ + certificate_t *current; +} cert_enumerator_t; + +/** + * Implementation of cert_enumerator_t.public.enumerate + */ +static bool cert_enumerator_enumerate(cert_enumerator_t *this, + certificate_t **cert) +{ + chunk_t blob; + int type; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &type, &blob)) + { + this->current = lib->creds->create(lib->creds, CRED_CERTIFICATE, type, + BUILD_BLOB_ASN1_DER, chunk_clone(blob), + BUILD_END); + if (this->current) + { + *cert = this->current; + return TRUE; + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of cert_enumerator_t.public.destroy + */ +static void cert_enumerator_destroy(cert_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_sql_cred_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + cert_enumerator_t *e; + + e = malloc_thing(cert_enumerator_t); + e->current = NULL; + e->public.enumerate = (void*)cert_enumerator_enumerate; + e->public.destroy = (void*)cert_enumerator_destroy; + if (id && id->get_type(id) != ID_ANY) + { + e->inner = this->db->query(this->db, + "SELECT c.type, c.data FROM certificates AS c " + "JOIN certificate_identity AS ci ON c.id = ci.certificate " + "JOIN identities AS i ON ci.identity = i.id " + "WHERE i.type = ? AND i.data = ? AND " + "(? OR c.type = ?) AND (? OR c.keytype = ?)", + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), + DB_INT, cert == CERT_ANY, DB_INT, cert, + DB_INT, key == KEY_ANY, DB_INT, key, + DB_INT, DB_BLOB); + } + else + { + e->inner = this->db->query(this->db, + "SELECT type, data FROM certificates WHERE " + "(? OR type = ?) AND (? OR keytype = ?)", + DB_INT, cert == CERT_ANY, DB_INT, cert, + DB_INT, key == KEY_ANY, DB_INT, key, + DB_INT, DB_BLOB); + } + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * enumerator over shared keys + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** own identity */ + identification_t *me; + /** remote identity */ + identification_t *other; + /** currently enumerated private key */ + shared_key_t *current; +} shared_enumerator_t; + +/** + * Implementation of shared_enumerator_t.public.enumerate + */ +static bool shared_enumerator_enumerate(shared_enumerator_t *this, + shared_key_t **shared, + id_match_t *me, id_match_t *other) +{ + chunk_t blob; + int type; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &type, &blob)) + { + this->current = shared_key_create(type, chunk_clone(blob)); + if (this->current) + { + *shared = this->current; + if (me) + { + *me = this->me ? ID_MATCH_PERFECT : ID_MATCH_ANY; + } + if (other) + { + *other = this->other ? ID_MATCH_PERFECT : ID_MATCH_ANY; + } + return TRUE; + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of shared_enumerator_t.public.destroy + */ +static void shared_enumerator_destroy(shared_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_shared_enumerator. + */ +static enumerator_t* create_shared_enumerator(private_sql_cred_t *this, + shared_key_type_t type, + identification_t *me, identification_t *other) +{ + shared_enumerator_t *e; + + e = malloc_thing(shared_enumerator_t); + e->me = me; + e->other = other; + e->current = NULL; + e->public.enumerate = (void*)shared_enumerator_enumerate; + e->public.destroy = (void*)shared_enumerator_destroy; + if (!me && !other) + { + e->inner = this->db->query(this->db, + "SELECT type, data FROM shared_secrets WHERE (? OR type = ?)", + DB_INT, type == SHARED_ANY, DB_INT, type, + DB_INT, DB_BLOB); + } + else if (me && other) + { + e->inner = this->db->query(this->db, + "SELECT s.type, s.data FROM shared_secrets AS s " + "JOIN shared_secret_identity AS sm ON s.id = sm.shared_secret " + "JOIN identities AS m ON sm.identity = m.id " + "JOIN shared_secret_identity AS so ON s.id = so.shared_secret " + "JOIN identities AS o ON so.identity = o.id " + "WHERE m.type = ? AND m.data = ? AND o.type = ? AND o.data = ? " + "AND (? OR s.type = ?)", + DB_INT, me->get_type(me), DB_BLOB, me->get_encoding(me), + DB_INT, other->get_type(other), DB_BLOB, other->get_encoding(other), + DB_INT, type == SHARED_ANY, DB_INT, type, + DB_INT, DB_BLOB); + } + else + { + identification_t *id = me ? me : other; + + e->inner = this->db->query(this->db, + "SELECT s.type, s.data FROM shared_secrets AS s " + "JOIN shared_secret_identity AS si ON s.id = si.shared_secret " + "JOIN identities AS i ON si.identity = i.id " + "WHERE i.type = ? AND i.data = ? AND (? OR s.type = ?)", + DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), + DB_INT, type == SHARED_ANY, DB_INT, type, + DB_INT, DB_BLOB); + } + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of credential_set_t.cache_cert. + */ +static void cache_cert(private_sql_cred_t *this, certificate_t *cert) +{ + /* TODO: implement CRL caching to database */ +} + +/** + * Implementation of sql_cred_t.destroy. + */ +static void destroy(private_sql_cred_t *this) +{ + free(this); +} +/** + * Described in header. + */ +sql_cred_t *sql_cred_create(database_t *db) +{ + private_sql_cred_t *this = malloc_thing(private_sql_cred_t); + + this->public.set.create_private_enumerator = (void*)create_private_enumerator; + this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->public.set.create_shared_enumerator = (void*)create_shared_enumerator; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.set.cache_cert = (void*)cache_cert; + this->public.destroy = (void(*)(sql_cred_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/sql/sql_cred.h b/src/charon/plugins/sql/sql_cred.h new file mode 100644 index 000000000..e251abe00 --- /dev/null +++ b/src/charon/plugins/sql/sql_cred.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_cred.h 3594 2008-03-13 14:53:57Z martin $ + */ + +/** + * @defgroup sql_cred_i sql_cred + * @{ @ingroup sql + */ + +#ifndef SQL_CRED_H_ +#define SQL_CRED_H_ + +#include <credentials/credential_set.h> +#include <database/database.h> + +typedef struct sql_cred_t sql_cred_t; + +/** + * SQL database credential set. + */ +struct sql_cred_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destry the backend. + */ + void (*destroy)(sql_cred_t *this); +}; + +/** + * Create a sql_cred backend instance. + * + * @param db underlying database + * @return credential set + */ +sql_cred_t *sql_cred_create(database_t *db); + +#endif /* SQL_CRED_H_ @}*/ diff --git a/src/charon/plugins/sql/sql_logger.c b/src/charon/plugins/sql/sql_logger.c new file mode 100644 index 000000000..2fb5844b3 --- /dev/null +++ b/src/charon/plugins/sql/sql_logger.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_logger.c 3589 2008-03-13 14:14:44Z martin $ + */ + +#include <string.h> + +#include "sql_logger.h" + +#include <daemon.h> + +typedef struct private_sql_logger_t private_sql_logger_t; + +/** + * Private data of an sql_logger_t object + */ +struct private_sql_logger_t { + + /** + * Public part + */ + sql_logger_t public; + + /** + * database connection + */ + database_t *db; + + /** + * logging level + */ + int level; + + /** + * avoid recursive logging + */ + bool recursive; +}; + + +/** + * Implementation of bus_listener_t.signal. + */ +static bool signal_(private_sql_logger_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) +{ + if (this->recursive) + { + return TRUE; + } + this->recursive = TRUE; + + if (ike_sa && level <= this->level) + { + char buffer[8192]; + chunk_t local_spi, remote_spi; + host_t *local_host, *remote_host; + identification_t *local_id, *remote_id; + u_int64_t ispi, rspi; + ike_sa_id_t *id; + + id = ike_sa->get_id(ike_sa); + ispi = id->get_initiator_spi(id); + rspi = id->get_responder_spi(id); + if (id->is_initiator(id)) + { + local_spi.ptr = (char*)&ispi; + remote_spi.ptr = (char*)&rspi; + } + else + { + local_spi.ptr = (char*)&rspi; + remote_spi.ptr = (char*)&ispi; + } + local_spi.len = remote_spi.len = sizeof(ispi); + local_id = ike_sa->get_my_id(ike_sa); + remote_id = ike_sa->get_other_id(ike_sa); + local_host = ike_sa->get_my_host(ike_sa); + remote_host = ike_sa->get_other_host(ike_sa); + + vsnprintf(buffer, sizeof(buffer), format, args); + + this->db->execute(this->db, NULL, "REPLACE INTO ike_sas (" + "local_spi, remote_spi, id, initiator, " + "local_id_type, local_id_data, " + "remote_id_type, remote_id_data, " + "host_family, local_host_data, remote_host_data) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + DB_BLOB, local_spi, DB_BLOB, remote_spi, + DB_INT, ike_sa->get_unique_id(ike_sa), + DB_INT, id->is_initiator(id), + DB_INT, local_id->get_type(local_id), + DB_BLOB, local_id->get_encoding(local_id), + DB_INT, remote_id->get_type(remote_id), + DB_BLOB, remote_id->get_encoding(remote_id), + DB_INT, local_host->get_family(local_host), + DB_BLOB, local_host->get_address(local_host), + DB_BLOB, remote_host->get_address(remote_host)); + this->db->execute(this->db, NULL, "INSERT INTO logs (" + "local_spi, signal, level, msg) VALUES (?, ?, ?, ?)", + DB_BLOB, local_spi, DB_INT, signal, DB_INT, level, + DB_TEXT, buffer); + } + this->recursive = FALSE; + /* always stay registered */ + return TRUE; +} + +/** + * Implementation of sql_logger_t.destroy. + */ +static void destroy(private_sql_logger_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +sql_logger_t *sql_logger_create(database_t *db) +{ + private_sql_logger_t *this = malloc_thing(private_sql_logger_t); + + this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_; + this->public.destroy = (void(*)(sql_logger_t*))destroy; + + this->db = db; + this->recursive = FALSE; + + this->level = lib->settings->get_int(lib->settings, + "charon.plugins.sql.loglevel", -1); + + return &this->public; +} + diff --git a/src/charon/plugins/sql/sql_logger.h b/src/charon/plugins/sql/sql_logger.h new file mode 100644 index 000000000..30507bcaf --- /dev/null +++ b/src/charon/plugins/sql/sql_logger.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_logger.h 3594 2008-03-13 14:53:57Z martin $ + */ + +/** + * @defgroup sql_logger_i sql_logger + * @{ @ingroup sql + */ + +#ifndef SQL_LOGGER_H_ +#define SQL_LOGGER_H_ + +#include <bus/bus.h> +#include <database/database.h> + +typedef struct sql_logger_t sql_logger_t; + +/** + * SQL database logger. + */ +struct sql_logger_t { + + /** + * Implements bus_listener_t interface + */ + bus_listener_t listener; + + /** + * Destry the backend. + */ + void (*destroy)(sql_logger_t *this); +}; + +/** + * Create a sql_logger instance. + * + * @param db underlying database + * @return logger instance + */ +sql_logger_t *sql_logger_create(database_t *db); + +#endif /* SQL_LOGGER_H_ @}*/ diff --git a/src/charon/plugins/sql/sql_plugin.c b/src/charon/plugins/sql/sql_plugin.c new file mode 100644 index 000000000..8c4f20f74 --- /dev/null +++ b/src/charon/plugins/sql/sql_plugin.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_plugin.c 3826 2008-04-17 15:08:48Z martin $ + */ + +#include "sql_plugin.h" + +#include <daemon.h> +#include "sql_config.h" +#include "sql_cred.h" +#include "sql_attribute.h" +#include "sql_logger.h" + +typedef struct private_sql_plugin_t private_sql_plugin_t; + +/** + * private data of sql plugin + */ +struct private_sql_plugin_t { + + /** + * implements plugin interface + */ + sql_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * configuration backend + */ + sql_config_t *config; + + /** + * credential set + */ + sql_cred_t *cred; + + /** + * CFG attributes + */ + sql_attribute_t *attribute; + + /** + * bus listener/logger + */ + sql_logger_t *logger; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_sql_plugin_t *this) +{ + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->credentials->remove_set(charon->credentials, &this->cred->set); + charon->bus->remove_listener(charon->bus, &this->logger->listener); + this->config->destroy(this->config); + this->cred->destroy(this->cred); + this->attribute->destroy(this->attribute); + this->logger->destroy(this->logger); + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + char *uri; + private_sql_plugin_t *this; + + uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "sql plugin: database URI not set"); + return NULL; + } + + this = malloc_thing(private_sql_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + this->db = lib->db->create(lib->db, uri); + if (!this->db) + { + DBG1(DBG_CFG, "sql plugin failed to connect to database"); + free(this); + return NULL; + } + this->config = sql_config_create(this->db); + this->cred = sql_cred_create(this->db); + this->attribute = sql_attribute_create(this->db); + this->logger = sql_logger_create(this->db); + + charon->backends->add_backend(charon->backends, &this->config->backend); + charon->credentials->add_set(charon->credentials, &this->cred->set); + charon->attributes->add_provider(charon->attributes, &this->attribute->provider); + charon->bus->add_listener(charon->bus, &this->logger->listener); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/sql/sql_plugin.h b/src/charon/plugins/sql/sql_plugin.h new file mode 100644 index 000000000..8a7ba3e85 --- /dev/null +++ b/src/charon/plugins/sql/sql_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: sql_plugin.h 3577 2008-03-12 14:38:35Z martin $ + */ + +/** + * @defgroup sql sql + * @ingroup cplugins + * + * @defgroup sql_plugin sql_plugin + * @{ @ingroup sql + */ + +#ifndef SQL_PLUGIN_H_ +#define SQL_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct sql_plugin_t sql_plugin_t; + +/** + * SQL database configuration plugin + */ +struct sql_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sql_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SQL_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/stroke/Makefile.am b/src/charon/plugins/stroke/Makefile.am new file mode 100644 index 000000000..7a341102b --- /dev/null +++ b/src/charon/plugins/stroke/Makefile.am @@ -0,0 +1,19 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke + +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" + +plugin_LTLIBRARIES = libstrongswan-stroke.la + +libstrongswan_stroke_la_SOURCES = stroke_plugin.h stroke_plugin.c \ + stroke_socket.h stroke_socket.c \ + stroke_config.h stroke_config.c \ + stroke_control.h stroke_control.c \ + stroke_cred.h stroke_cred.c \ + stroke_ca.h stroke_ca.c \ + stroke_attribute.h stroke_attribute.c \ + stroke_list.h stroke_list.c \ + stroke_shared_key.h stroke_shared_key.c + +libstrongswan_stroke_la_LDFLAGS = -module + diff --git a/src/charon/plugins/stroke/Makefile.in b/src/charon/plugins/stroke/Makefile.in new file mode 100644 index 000000000..a528377d0 --- /dev/null +++ b/src/charon/plugins/stroke/Makefile.in @@ -0,0 +1,513 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/stroke +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +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_shared_key.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 $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_stroke_la_SOURCES) +DIST_SOURCES = $(libstrongswan_stroke_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" +plugin_LTLIBRARIES = libstrongswan-stroke.la +libstrongswan_stroke_la_SOURCES = stroke_plugin.h stroke_plugin.c \ + stroke_socket.h stroke_socket.c \ + stroke_config.h stroke_config.c \ + stroke_control.h stroke_control.c \ + stroke_cred.h stroke_cred.c \ + stroke_ca.h stroke_ca.c \ + stroke_attribute.h stroke_attribute.c \ + stroke_list.h stroke_list.c \ + stroke_shared_key.h stroke_shared_key.c + +libstrongswan_stroke_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/stroke/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/stroke/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + 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) -rpath $(plugindir) $(libstrongswan_stroke_la_OBJECTS) $(libstrongswan_stroke_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_attribute.Plo@am__quote@ +@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_cred.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_shared_key.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@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/stroke/stroke_attribute.c b/src/charon/plugins/stroke/stroke_attribute.c new file mode 100644 index 000000000..71b56bc8a --- /dev/null +++ b/src/charon/plugins/stroke/stroke_attribute.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_attribute.h" + +#include <daemon.h> +#include <utils/linked_list.h> +#include <utils/mutex.h> + +#define POOL_LIMIT 16 + +typedef struct private_stroke_attribute_t private_stroke_attribute_t; + +/** + * private data of stroke_attribute + */ +struct private_stroke_attribute_t { + + /** + * public functions + */ + stroke_attribute_t public; + + /** + * list of pools, contains pool_t + */ + linked_list_t *pools; + + /** + * mutex to lock access to pools + */ + mutex_t *mutex; +}; + +typedef struct { + /** name of the pool */ + char *name; + /** base address of the pool */ + host_t *base; + /** number of entries in the pool */ + int count; + /** array of in-use flags, TODO: use bit fields */ + u_int8_t *in_use; +} pool_t; + +/** + * destroy a pool_t + */ +static void pool_destroy(pool_t *this) +{ + DESTROY_IF(this->base); + free(this->name); + free(this->in_use); + free(this); +} + +/** + * find a pool by name + */ +static pool_t *find_pool(private_stroke_attribute_t *this, char *name) +{ + enumerator_t *enumerator; + pool_t *current, *found = NULL; + + enumerator = this->pools->create_enumerator(this->pools); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(name, current->name)) + { + found = current; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * convert an pool offset to an address + */ +host_t* offset2host(pool_t *pool, int offset) +{ + chunk_t addr; + host_t *host; + u_int32_t *pos; + + if (offset > pool->count) + { + return NULL; + } + + addr = chunk_clone(pool->base->get_address(pool->base)); + if (pool->base->get_family(pool->base) == AF_INET6) + { + pos = (u_int32_t*)(addr.ptr + 12); + } + else + { + pos = (u_int32_t*)addr.ptr; + } + *pos = htonl(offset + ntohl(*pos)); + host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0); + free(addr.ptr); + return host; +} + +/** + * convert a host to a pool offset + */ +int host2offset(pool_t *pool, host_t *addr) +{ + chunk_t host, base; + u_int32_t hosti, basei; + + if (addr->get_family(addr) != pool->base->get_family(pool->base)) + { + return -1; + } + host = addr->get_address(addr); + base = pool->base->get_address(pool->base); + if (addr->get_family(addr) == AF_INET6) + { + /* only look at last /32 block */ + if (!memeq(host.ptr, base.ptr, 12)) + { + return -1; + } + host = chunk_skip(host, 12); + base = chunk_skip(base, 12); + } + hosti = ntohl(*(u_int32_t*)(host.ptr)); + basei = ntohl(*(u_int32_t*)(base.ptr)); + if (hosti > basei + pool->count) + { + return -1; + } + return hosti - basei; +} + +/** + * Implementation of attribute_provider_t.acquire_address + */ +static host_t* acquire_address(private_stroke_attribute_t *this, + char *name, identification_t *id, + auth_info_t *auth, host_t *requested) +{ + pool_t *pool; + host_t *host = NULL; + int i; + + this->mutex->lock(this->mutex); + pool = find_pool(this, name); + if (pool) + { + if (requested && !requested->is_anyaddr(requested)) + { + if (pool->count == 0) + { /* %config, give any */ + host = requested->clone(requested); + } + else + { + i = host2offset(pool, requested); + if (i >= 0 && !pool->in_use[i]) + { + pool->in_use[i] = TRUE; + host = requested->clone(requested); + } + } + } + if (!host) + { + for (i = 0; i < pool->count; i++) + { + if (!pool->in_use[i]) + { + pool->in_use[i] = TRUE; + host = offset2host(pool, i); + break; + } + } + } + } + this->mutex->unlock(this->mutex); + return host; +} + +/** + * Implementation of attribute_provider_t.release_address + */ +static bool release_address(private_stroke_attribute_t *this, + char *name, host_t *address) +{ + pool_t *pool; + bool found = FALSE; + int i; + + this->mutex->lock(this->mutex); + pool = find_pool(this, name); + if (pool) + { + if (pool->count != 0) + { + i = host2offset(pool, address); + if (i >= 0 && pool->in_use[i]) + { + pool->in_use[i] = FALSE; + found = TRUE; + } + } + } + this->mutex->unlock(this->mutex); + return found; +} + +/** + * Implementation of stroke_attribute_t.add_pool. + */ +static void add_pool(private_stroke_attribute_t *this, stroke_msg_t *msg) +{ + if (msg->add_conn.other.sourceip_size) + { + pool_t *pool; + + if (msg->add_conn.other.sourceip) + { + u_int32_t bits; + int family; + + 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_size); + + pool = malloc_thing(pool_t); + pool->base = host_create_from_string(msg->add_conn.other.sourceip, 0); + if (!pool->base) + { + free(pool); + DBG1(DBG_CFG, "virtual IP address invalid, discarded"); + return; + } + pool->name = strdup(msg->add_conn.name); + family = pool->base->get_family(pool->base); + bits = (family == AF_INET ? 32 : 128) - msg->add_conn.other.sourceip_size; + if (bits > POOL_LIMIT) + { + bits = POOL_LIMIT; + DBG1(DBG_CFG, "virtual IP pool to large, limiting to %s/%d", + msg->add_conn.other.sourceip, + (family == AF_INET ? 32 : 128) - bits); + } + pool->count = 1 << (bits); + pool->in_use = calloc(pool->count, sizeof(u_int8_t)); + + if (pool->count > 2) + { /* do not use first and last addresses of a block */ + pool->in_use[0] = TRUE; + pool->in_use[pool->count-1] = TRUE; + } + } + else + { /* %config, add an empty pool */ + pool = malloc_thing(pool_t); + pool->name = strdup(msg->add_conn.name); + pool->base = NULL; + pool->count = 0; + pool->in_use = NULL; + } + this->mutex->lock(this->mutex); + this->pools->insert_last(this->pools, pool); + this->mutex->unlock(this->mutex); + } +} + +/** + * Implementation of stroke_attribute_t.del_pool. + */ +static void del_pool(private_stroke_attribute_t *this, stroke_msg_t *msg) +{ + enumerator_t *enumerator; + pool_t *pool; + + this->mutex->lock(this->mutex); + enumerator = this->pools->create_enumerator(this->pools); + while (enumerator->enumerate(enumerator, &pool)) + { + if (streq(msg->del_conn.name, pool->name)) + { + this->pools->remove_at(this->pools, enumerator); + pool_destroy(pool); + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of stroke_attribute_t.destroy + */ +static void destroy(private_stroke_attribute_t *this) +{ + this->mutex->destroy(this->mutex); + this->pools->destroy_function(this->pools, (void*)pool_destroy); + free(this); +} + +/* + * see header file + */ +stroke_attribute_t *stroke_attribute_create() +{ + private_stroke_attribute_t *this = malloc_thing(private_stroke_attribute_t); + + this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address; + this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *))release_address; + this->public.add_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))add_pool; + this->public.del_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))del_pool; + this->public.destroy = (void(*)(stroke_attribute_t*))destroy; + + this->pools = linked_list_create(); + this->mutex = mutex_create(MUTEX_DEFAULT); + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_attribute.h b/src/charon/plugins/stroke/stroke_attribute.h new file mode 100644 index 000000000..f871d5a13 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_attribute.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_attribute stroke_attribute + * @{ @ingroup stroke + */ + +#ifndef STROKE_ATTRIBUTE_H_ +#define STROKE_ATTRIBUTE_H_ + +#include <stroke_msg.h> +#include <config/attributes/attribute_provider.h> + +typedef struct stroke_attribute_t stroke_attribute_t; + +/** + * Stroke IKEv2 cfg attribute provider + */ +struct stroke_attribute_t { + + /** + * Implements attribute provider interface + */ + attribute_provider_t provider; + + /** + * Add a virtual IP address. + * + * @param msg stroke message + * @param end end of stroke message that contains virtual IP. + */ + void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg); + + /** + * Remove a virtual IP address. + * + * @param msg stroke message + */ + void (*del_pool)(stroke_attribute_t *this, stroke_msg_t *msg); + + /** + * Destroy a stroke_attribute instance. + */ + void (*destroy)(stroke_attribute_t *this); +}; + +/** + * Create a stroke_attribute instance. + */ +stroke_attribute_t *stroke_attribute_create(); + +#endif /* STROKE_ATTRIBUTE_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_ca.c b/src/charon/plugins/stroke/stroke_ca.c new file mode 100644 index 000000000..897365eb0 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_ca.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_ca.h" +#include "stroke_cred.h" + +#include <utils/mutex.h> +#include <utils/linked_list.h> +#include <crypto/hashers/hasher.h> + +#include <daemon.h> + +typedef struct private_stroke_ca_t private_stroke_ca_t; + +/** + * private data of stroke_ca + */ +struct private_stroke_ca_t { + + /** + * public functions + */ + stroke_ca_t public; + + /** + * mutex to lock access to list + */ + mutex_t *mutex; + + /** + * list of starters CA sections and its certificates (ca_section_t) + */ + linked_list_t *sections; + + /** + * stroke credentials, stores our CA certificates + */ + stroke_cred_t *cred; +}; + +typedef struct ca_section_t ca_section_t; + +/** + * loaded ipsec.conf CA sections + */ +struct ca_section_t { + + /** + * name of the CA section + */ + char *name; + + /** + * reference to cert in trusted_credential_t + */ + certificate_t *cert; + + /** + * CRL URIs + */ + linked_list_t *crl; + + /** + * OCSP URIs + */ + linked_list_t *ocsp; + + /** + * Hashes of certificates issued by this CA + */ + linked_list_t *hashes; + + /** + * Base URI used for certificates from this CA + */ + char *certuribase; +}; + +/** + * create a new CA section + */ +static ca_section_t *ca_section_create(char *name, certificate_t *cert) +{ + ca_section_t *ca = malloc_thing(ca_section_t); + + ca->name = strdup(name); + ca->crl = linked_list_create(); + ca->ocsp = linked_list_create(); + ca->cert = cert; + ca->hashes = linked_list_create(); + ca->certuribase = NULL; + return ca; +} + +/** + * destroy a ca section entry + */ +static void ca_section_destroy(ca_section_t *this) +{ + this->crl->destroy_function(this->crl, free); + this->ocsp->destroy_function(this->ocsp, free); + this->hashes->destroy_offset(this->hashes, offsetof(identification_t, destroy)); + free(this->certuribase); + free(this->name); + free(this); +} + +/** + * data to pass to create_inner_cdp + */ +typedef struct { + private_stroke_ca_t *this; + certificate_type_t type; + identification_t *id; +} cdp_data_t; + +/** + * destroy cdp enumerator data and unlock list + */ +static void cdp_data_destroy(cdp_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * inner enumerator constructor for CDP URIs + */ +static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data) +{ + public_key_t *public; + identification_t *keyid; + enumerator_t *enumerator = NULL; + linked_list_t *list; + + if (data->type == CERT_X509_OCSP_RESPONSE) + { + list = section->ocsp; + } + else + { + list = section->crl; + } + + public = section->cert->get_public_key(section->cert); + if (public) + { + if (!data->id) + { + enumerator = list->create_enumerator(list); + } + else + { + keyid = public->get_id(public, data->id->get_type(data->id)); + if (keyid && keyid->matches(keyid, data->id)) + { + enumerator = list->create_enumerator(list); + } + } + public->destroy(public); + } + return enumerator; +} + +/** + * inner enumerator constructor for "Hash and URL" + */ +static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data) +{ + enumerator_t *enumerator = NULL, *hash_enum; + identification_t *current; + + if (!data->id || !section->certuribase) + { + return NULL; + } + + hash_enum = section->hashes->create_enumerator(section->hashes); + while (hash_enum->enumerate(hash_enum, ¤t)) + { + if (current->matches(current, data->id)) + { + char *url, *hash; + + url = malloc(strlen(section->certuribase) + 40 + 1); + strcpy(url, section->certuribase); + hash = chunk_to_hex(current->get_encoding(current), NULL, FALSE).ptr; + strncat(url, hash, 40); + free(hash); + + enumerator = enumerator_create_single(url, free); + break; + } + } + hash_enum->destroy(hash_enum); + return enumerator; +} + +/** + * Implementation of credential_set_t.create_cdp_enumerator. + */ +static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this, + certificate_type_t type, identification_t *id) +{ + cdp_data_t *data; + + switch (type) + { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */ + case CERT_X509: + case CERT_X509_CRL: + case CERT_X509_OCSP_RESPONSE: + case CERT_ANY: + break; + default: + return NULL; + } + data = malloc_thing(cdp_data_t); + data->this = this; + data->type = type; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sections->create_enumerator(this->sections), + (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp, + data, (void*)cdp_data_destroy); +} +/** + * Implementation of stroke_ca_t.add. + */ +static void add(private_stroke_ca_t *this, stroke_msg_t *msg) +{ + certificate_t *cert; + ca_section_t *ca; + + if (msg->add_ca.cacert == NULL) + { + DBG1(DBG_CFG, "missing cacert parameter"); + return; + } + cert = this->cred->load_ca(this->cred, msg->add_ca.cacert); + if (cert) + { + ca = ca_section_create(msg->add_ca.name, cert); + if (msg->add_ca.crluri) + { + ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri)); + } + if (msg->add_ca.crluri2) + { + ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2)); + } + if (msg->add_ca.ocspuri) + { + ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri)); + } + if (msg->add_ca.ocspuri2) + { + ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2)); + } + if (msg->add_ca.certuribase) + { + ca->certuribase = strdup(msg->add_ca.certuribase); + } + this->mutex->lock(this->mutex); + this->sections->insert_last(this->sections, ca); + this->mutex->unlock(this->mutex); + DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name); + } +} + +/** + * Implementation of stroke_ca_t.del. + */ +static void del(private_stroke_ca_t *this, stroke_msg_t *msg) +{ + enumerator_t *enumerator; + ca_section_t *ca = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->sections->create_enumerator(this->sections); + while (enumerator->enumerate(enumerator, &ca)) + { + if (streq(ca->name, msg->del_ca.name)) + { + this->sections->remove_at(this->sections, enumerator); + break; + } + ca = NULL; + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + if (ca == NULL) + { + DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name); + return; + } + ca_section_destroy(ca); + /* TODO: flush cached certs */ +} + +/** + * list crl or ocsp URIs + */ +static void list_uris(linked_list_t *list, char *label, FILE *out) +{ + bool first = TRUE; + char *uri; + enumerator_t *enumerator; + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, (void**)&uri)) + { + if (first) + { + fprintf(out, label); + first = FALSE; + } + else + { + fprintf(out, " "); + } + fprintf(out, "'%s'\n", uri); + } + enumerator->destroy(enumerator); +} + +/** + * Implementation of stroke_ca_t.check_for_hash_and_url. + */ +static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cert) +{ + ca_section_t *section; + enumerator_t *enumerator; + + hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); + return; + } + + this->mutex->lock(this->mutex); + enumerator = this->sections->create_enumerator(this->sections); + while (enumerator->enumerate(enumerator, (void**)§ion)) + { + if (section->certuribase && cert->issued_by(cert, section->cert)) + { + chunk_t hash, encoded = cert->get_encoding(cert); + hasher->allocate_hash(hasher, encoded, &hash); + section->hashes->insert_last(section->hashes, + identification_create_from_encoding(ID_CERT_DER_SHA1, hash)); + chunk_free(&hash); + chunk_free(&encoded); + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + hasher->destroy(hasher); +} + +/** + * Implementation of stroke_ca_t.list. + */ +static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out) +{ + bool first = TRUE; + ca_section_t *section; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->sections->create_enumerator(this->sections); + while (enumerator->enumerate(enumerator, (void**)§ion)) + { + certificate_t *cert = section->cert; + public_key_t *public = cert->get_public_key(cert); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of CA Information Sections:\n"); + first = FALSE; + } + fprintf(out, "\n"); + fprintf(out, " authname: \"%D\"\n", cert->get_subject(cert)); + + /* list authkey and keyid */ + if (public) + { + fprintf(out, " authkey: %D\n", + public->get_id(public, ID_PUBKEY_SHA1)); + fprintf(out, " keyid: %D\n", + public->get_id(public, ID_PUBKEY_INFO_SHA1)); + public->destroy(public); + } + list_uris(section->crl, " crluris: ", out); + list_uris(section->ocsp, " ocspuris: ", out); + if (section->certuribase) + { + fprintf(out, " certuribase: '%s'\n", section->certuribase); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of stroke_ca_t.destroy + */ +static void destroy(private_stroke_ca_t *this) +{ + this->sections->destroy_function(this->sections, (void*)ca_section_destroy); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +stroke_ca_t *stroke_ca_create(stroke_cred_t *cred) +{ + private_stroke_ca_t *this = malloc_thing(private_stroke_ca_t); + + this->public.set.create_private_enumerator = (void*)return_null; + this->public.set.create_cert_enumerator = (void*)return_null; + this->public.set.create_shared_enumerator = (void*)return_null; + this->public.set.create_cdp_enumerator = (void*)create_cdp_enumerator; + this->public.set.cache_cert = (void*)nop; + this->public.add = (void(*)(stroke_ca_t*, stroke_msg_t *msg))add; + this->public.del = (void(*)(stroke_ca_t*, stroke_msg_t *msg))del; + this->public.list = (void(*)(stroke_ca_t*, stroke_msg_t *msg, FILE *out))list; + this->public.check_for_hash_and_url = (void(*)(stroke_ca_t*, certificate_t*))check_for_hash_and_url; + this->public.destroy = (void(*)(stroke_ca_t*))destroy; + + this->sections = linked_list_create(); + this->mutex = mutex_create(MUTEX_RECURSIVE); + this->cred = cred; + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_ca.h b/src/charon/plugins/stroke/stroke_ca.h new file mode 100644 index 000000000..882446afe --- /dev/null +++ b/src/charon/plugins/stroke/stroke_ca.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_ca stroke_ca + * @{ @ingroup stroke + */ + +#ifndef STROKE_CA_H_ +#define STROKE_CA_H_ + +#include <stroke_msg.h> + +#include "stroke_cred.h" + +typedef struct stroke_ca_t stroke_ca_t; + +/** + * ipsec.conf ca section handling. + */ +struct stroke_ca_t { + + /** + * Implements credential_set_t + */ + credential_set_t set; + + /** + * Add a CA to the set using a stroke_msg_t. + * + * @param msg stroke message containing CA info + */ + void (*add)(stroke_ca_t *this, stroke_msg_t *msg); + + /** + * Remove a CA from the set using a stroke_msg_t. + * + * @param msg stroke message containing CA info + */ + void (*del)(stroke_ca_t *this, stroke_msg_t *msg); + + /** + * List CA sections to stroke console. + * + * @param msg stroke message + */ + void (*list)(stroke_ca_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Check if a certificate can be made available through hash and URL. + * + * @param cert peer certificate + */ + void (*check_for_hash_and_url)(stroke_ca_t *this, certificate_t* cert); + + /** + * Destroy a stroke_ca instance. + */ + void (*destroy)(stroke_ca_t *this); +}; + +/** + * Create a stroke_ca instance. + */ +stroke_ca_t *stroke_ca_create(stroke_cred_t *cred); + +#endif /* STROKE_CA_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c new file mode 100644 index 000000000..0069191b5 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_config.c @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_config.h" + +#include <daemon.h> +#include <utils/mutex.h> + +typedef struct private_stroke_config_t private_stroke_config_t; + +/** + * private data of stroke_config + */ +struct private_stroke_config_t { + + /** + * public functions + */ + stroke_config_t public; + + /** + * list of peer_cfg_t + */ + linked_list_t *list; + + /** + * mutex to lock config list + */ + mutex_t *mutex; + + /** + * ca sections + */ + stroke_ca_t *ca; + + /** + * credentials + */ + stroke_cred_t *cred; +}; + +/** + * data to pass peer_filter + */ +typedef struct { + private_stroke_config_t *this; + identification_t *me; + identification_t *other; +} peer_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void peer_data_destroy(peer_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for peer configs + */ +static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out) +{ + bool match_me = FALSE, match_other = FALSE; + identification_t *me, *other; + + me = (*in)->get_my_id(*in); + other = (*in)->get_other_id(*in); + + /* own ID may have wildcards in data (no IDr payload) or in config */ + match_me = (!data->me || data->me->matches(data->me, me) || + me->matches(me, data->me)); + /* others ID has wildcards in config only */ + match_other = (!data->other || data->other->matches(data->other, other)); + + if (match_me && match_other) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_stroke_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_data_t *data; + + data = malloc_thing(peer_data_t); + data->this = this; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)peer_filter, data, + (void*)peer_data_destroy); +} + +/** + * data to pass ike_filter + */ +typedef struct { + private_stroke_config_t *this; + host_t *me; + host_t *other; +} ike_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void ike_data_destroy(ike_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for ike configs + */ +static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out) +{ + *out = (*in)->get_ike_cfg(*in); + return TRUE; +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this, + host_t *me, host_t *other) +{ + ike_data_t *data; + + data = malloc_thing(ike_data_t); + data->this = this; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)ike_filter, data, + (void*)ike_data_destroy); +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *name) +{ + enumerator_t *e1, *e2; + peer_cfg_t *current, *found = NULL; + child_cfg_t *child; + + this->mutex->lock(this->mutex); + e1 = this->list->create_enumerator(this->list); + while (e1->enumerate(e1, ¤t)) + { + /* compare peer_cfgs name first */ + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + /* compare all child_cfg names otherwise */ + e2 = current->create_child_cfg_enumerator(current); + while (e2->enumerate(e2, &child)) + { + if (streq(child->get_name(child), name)) + { + found = current; + found->get_ref(found); + break; + } + } + e2->destroy(e2); + if (found) + { + break; + } + } + e1->destroy(e1); + this->mutex->unlock(this->mutex); + return found; +} + +/** + * check if a certificate has an ID + */ +static identification_t *update_peerid(certificate_t *cert, identification_t *id) +{ + if (!cert->has_subject(cert, id)) + { + DBG1(DBG_CFG, " peerid %D not confirmed by certificate, " + "defaulting to subject DN", id); + id->destroy(id); + id = cert->get_subject(cert); + return id->clone(id); + } + return id; +} + +/** + * parse a proposal string, either into ike_cfg or child_cfg + */ +static void add_proposals(private_stroke_config_t *this, char *string, + ike_cfg_t *ike_cfg, child_cfg_t *child_cfg) +{ + if (string) + { + char *single; + char *strict; + proposal_t *proposal; + protocol_id_t proto = PROTO_ESP; + + if (ike_cfg) + { + proto = PROTO_IKE; + } + strict = string + strlen(string) - 1; + if (*strict == '!') + { + *strict = '\0'; + } + else + { + strict = NULL; + } + while ((single = strsep(&string, ","))) + { + proposal = proposal_create_from_string(proto, single); + if (proposal) + { + if (ike_cfg) + { + ike_cfg->add_proposal(ike_cfg, proposal); + } + else + { + child_cfg->add_proposal(child_cfg, proposal); + } + continue; + } + DBG1(DBG_CFG, "skipped invalid proposal string: %s", single); + } + if (strict) + { + return; + } + /* add default porposal to the end if not strict */ + } + if (ike_cfg) + { + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + } + else + { + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + } +} + +/** + * Build an IKE config from a stroke message + */ +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; + + host = host_create_from_dns(msg->add_conn.other.address, 0, 0); + if (host) + { + interface = charon->kernel_interface->get_interface( + charon->kernel_interface, host); + host->destroy(host); + if (interface) + { + 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); + } + else + { + host = host_create_from_dns(msg->add_conn.me.address, 0, 0); + if (host) + { + interface = charon->kernel_interface->get_interface( + charon->kernel_interface, host); + host->destroy(host); + if (!interface) + { + DBG1(DBG_CFG, "left nor right host is our side, " + "assuming left=local"); + } + else + { + free(interface); + } + + } + } + } + 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.other.address); + add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); + return ike_cfg; +} +/** + * build a peer_cfg from a stroke msg + */ +static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, + stroke_msg_t *msg, ike_cfg_t *ike_cfg) +{ + identification_t *me, *other, *peer_id = NULL; + peer_cfg_t *mediated_by = NULL; + host_t *vip = NULL; + certificate_t *cert; + unique_policy_t unique; + u_int32_t rekey = 0, reauth = 0, over, jitter; + + me = identification_create_from_string(msg->add_conn.me.id ? + msg->add_conn.me.id : msg->add_conn.me.address); + if (!me) + { + DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id); + return NULL; + } + other = identification_create_from_string(msg->add_conn.other.id ? + msg->add_conn.other.id : msg->add_conn.other.address); + if (!other) + { + DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id); + me->destroy(me); + return NULL; + } + + +#ifdef ME + if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by) + { + DBG1(DBG_CFG, "a mediation connection cannot be a" + " mediated connection at the same time, aborting"); + me->destroy(me); + other->destroy(other); + return NULL; + } + + if (msg->add_conn.ikeme.mediated_by) + { + mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->add_conn.ikeme.mediated_by); + if (!mediated_by) + { + DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", + msg->add_conn.ikeme.mediated_by); + me->destroy(me); + other->destroy(other); + return NULL; + } + + if (!mediated_by->is_mediation(mediated_by)) + { + DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is" + "no mediation connection, aborting", + msg->add_conn.ikeme.mediated_by, msg->add_conn.name); + mediated_by->destroy(mediated_by); + me->destroy(me); + other->destroy(other); + return NULL; + } + } + + if (msg->add_conn.ikeme.peerid) + { + peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid); + if (!peer_id) + { + DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid); + mediated_by->destroy(mediated_by); + me->destroy(me); + other->destroy(other); + return NULL; + } + } + else + { + /* no peer ID supplied, assume right ID */ + peer_id = other->clone(other); + } +#endif /* ME */ + + if (msg->add_conn.me.cert) + { + cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert); + if (cert) + { + this->ca->check_for_hash_and_url(this->ca, cert); + me = update_peerid(cert, me); + cert->destroy(cert); + } + } + if (msg->add_conn.other.cert) + { + cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert); + if (cert) + { + other = update_peerid(cert, other); + cert->destroy(cert); + } + } + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + over = msg->add_conn.rekey.margin; + if (msg->add_conn.rekey.reauth) + { + reauth = msg->add_conn.rekey.ike_lifetime - over; + } + else + { + rekey = msg->add_conn.rekey.ike_lifetime - over; + } + if (msg->add_conn.me.sourceip_size) + { + 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 */ + case 2: /* replace */ + unique = UNIQUE_REPLACE; + break; + case 3: /* keep */ + unique = UNIQUE_KEEP; + break; + default: /* no */ + unique = UNIQUE_NO; + break; + } + if (msg->add_conn.dpd.action == 0) + { /* dpdaction=none disables DPD */ + msg->add_conn.dpd.delay = 0; + } + + /* 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. */ + return peer_cfg_create(msg->add_conn.name, + msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other, + msg->add_conn.me.sendcert, unique, msg->add_conn.auth_method, + msg->add_conn.eap_type, msg->add_conn.eap_vendor, + msg->add_conn.rekey.tries, rekey, reauth, jitter, over, + msg->add_conn.mobike, msg->add_conn.dpd.delay, + vip, msg->add_conn.other.sourceip_size ? + msg->add_conn.name : msg->add_conn.other.sourceip, + msg->add_conn.ikeme.mediation, mediated_by, peer_id); +} + +/** + * fill in auth_info from stroke message + */ +static void build_auth_info(private_stroke_config_t *this, + stroke_msg_t *msg, auth_info_t *auth) +{ + identification_t *my_ca = NULL, *other_ca = NULL; + bool my_ca_same = FALSE; + bool other_ca_same = FALSE; + cert_validation_t valid; + + if (msg->add_conn.other.groups) + { + /* TODO: AC groups */ + } + + switch (msg->add_conn.crl_policy) + { + case CRL_STRICT_YES: + valid = VALIDATION_GOOD; + auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + break; + case CRL_STRICT_IFURI: + valid = VALIDATION_SKIPPED; + auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + break; + default: + break; + } + + if (msg->add_conn.me.ca) + { + if (streq(msg->add_conn.me.ca, "%same")) + { + my_ca_same = TRUE; + } + else + { + my_ca = identification_create_from_string(msg->add_conn.me.ca); + } + } + if (msg->add_conn.other.ca) + { + if (streq(msg->add_conn.other.ca, "%same")) + { + other_ca_same = TRUE; + } + else + { + other_ca = identification_create_from_string(msg->add_conn.other.ca); + } + } + if (other_ca_same && my_ca) + { + other_ca = my_ca->clone(my_ca); + } + else if (my_ca_same && other_ca) + { + my_ca = other_ca->clone(other_ca); + } + + if (other_ca) + { + DBG2(DBG_CFG, " other ca: %D", other_ca); + certificate_t *cert = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, other_ca, TRUE); + if (cert) + { + auth->add_item(auth, AUTHZ_CA_CERT, cert); + cert->destroy(cert); + } + else + { + auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca); + } + other_ca->destroy(other_ca); + } + if (my_ca) + { + DBG2(DBG_CFG, " my ca: %D", my_ca); + certificate_t *cert = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, my_ca, TRUE); + if (cert) + { + auth->add_item(auth, AUTHN_CA_CERT, cert); + cert->destroy(cert); + } + else + { + auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca); + } + my_ca->destroy(my_ca); + } +} + +/** + * build a traffic selector from a stroke_end + */ +static void add_ts(private_stroke_config_t *this, + stroke_end_t *end, child_cfg_t *child_cfg, bool local) +{ + traffic_selector_t *ts; + + if (end->tohost) + { + ts = traffic_selector_create_dynamic(end->protocol, + end->port ? end->port : 0, end->port ? end->port : 65535); + child_cfg->add_traffic_selector(child_cfg, local, ts); + } + else + { + host_t *net; + + if (!end->subnets) + { + net = host_create_from_string(end->address, IKEV2_UDP_PORT); + if (net) + { + ts = traffic_selector_create_from_subnet(net, 0, end->protocol, + end->port); + child_cfg->add_traffic_selector(child_cfg, local, ts); + } + } + else + { + char *del, *start, *bits; + + start = end->subnets; + do + { + int intbits = 0; + + del = strchr(start, ','); + if (del) + { + *del = '\0'; + } + bits = strchr(start, '/'); + if (bits) + { + *bits = '\0'; + intbits = atoi(bits + 1); + } + + net = host_create_from_string(start, IKEV2_UDP_PORT); + if (net) + { + 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); + } + start = del + 1; + } + while (del); + } + } +} + +/** + * build a child config from the stroke message + */ +static child_cfg_t *build_child_cfg(private_stroke_config_t *this, + stroke_msg_t *msg) +{ + child_cfg_t *child_cfg; + action_t dpd; + + switch (msg->add_conn.dpd.action) + { /* map startes magic values to our action type */ + case 2: /* =hold */ + dpd = ACTION_ROUTE; + break; + case 3: /* =restart */ + dpd = ACTION_RESTART; + break; + default: + dpd = ACTION_NONE; + break; + } + child_cfg = child_cfg_create( + msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime, + msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, + msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, + msg->add_conn.me.updown, msg->add_conn.me.hostaccess, + msg->add_conn.mode, dpd, ACTION_NONE, msg->add_conn.ipcomp); + + add_ts(this, &msg->add_conn.me, child_cfg, TRUE); + add_ts(this, &msg->add_conn.other, child_cfg, FALSE); + + add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg); + + return child_cfg; +} + +/** + * Implementation of stroke_config_t.add. + */ +static void add(private_stroke_config_t *this, stroke_msg_t *msg) +{ + ike_cfg_t *ike_cfg, *existing_ike; + peer_cfg_t *peer_cfg, *existing; + child_cfg_t *child_cfg; + enumerator_t *enumerator; + bool use_existing = FALSE; + + ike_cfg = build_ike_cfg(this, msg); + if (!ike_cfg) + { + return; + } + peer_cfg = build_peer_cfg(this, msg, ike_cfg); + if (!peer_cfg) + { + ike_cfg->destroy(ike_cfg); + return; + } + + build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg)); + enumerator = create_peer_cfg_enumerator(this, NULL, NULL); + while (enumerator->enumerate(enumerator, &existing)) + { + existing_ike = existing->get_ike_cfg(existing); + if (existing->equals(existing, peer_cfg) && + existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg))) + { + use_existing = TRUE; + peer_cfg->destroy(peer_cfg); + peer_cfg = existing; + peer_cfg->get_ref(peer_cfg); + DBG1(DBG_CFG, "added child to existing configuration '%s'", + peer_cfg->get_name(peer_cfg)); + break; + } + } + enumerator->destroy(enumerator); + + child_cfg = build_child_cfg(this, msg); + if (!child_cfg) + { + peer_cfg->destroy(peer_cfg); + return; + } + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + + if (use_existing) + { + peer_cfg->destroy(peer_cfg); + } + else + { + /* add config to backend */ + DBG1(DBG_CFG, "added configuration '%s': %s[%D]...%s[%D]", msg->add_conn.name, + ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg), + ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg)); + this->mutex->lock(this->mutex); + this->list->insert_last(this->list, peer_cfg); + this->mutex->unlock(this->mutex); + } +} + +/** + * Implementation of stroke_config_t.del. + */ +static void del(private_stroke_config_t *this, stroke_msg_t *msg) +{ + enumerator_t *enumerator, *children; + peer_cfg_t *peer; + child_cfg_t *child; + + this->mutex->lock(this->mutex); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + /* remove peer config with such a name */ + if (streq(peer->get_name(peer), msg->del_conn.name)) + { + this->list->remove_at(this->list, enumerator); + peer->destroy(peer); + continue; + } + /* remove any child with such a name */ + children = peer->create_child_cfg_enumerator(peer); + while (children->enumerate(children, &child)) + { + if (streq(child->get_name(child), msg->del_conn.name)) + { + peer->remove_child_cfg(peer, enumerator); + child->destroy(child); + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name); +} + +/** + * Implementation of stroke_config_t.destroy + */ +static void destroy(private_stroke_config_t *this) +{ + this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy)); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) +{ + private_stroke_config_t *this = malloc_thing(private_stroke_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add; + this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del; + this->public.destroy = (void(*)(stroke_config_t*))destroy; + + this->list = linked_list_create(); + this->mutex = mutex_create(MUTEX_RECURSIVE); + this->ca = ca; + this->cred = cred; + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_config.h b/src/charon/plugins/stroke/stroke_config.h new file mode 100644 index 000000000..22b493cd2 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_config.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_config stroke_config + * @{ @ingroup stroke + */ + +#ifndef STROKE_CONFIG_H_ +#define STROKE_CONFIG_H_ + +#include <config/backend.h> +#include <stroke_msg.h> +#include "stroke_ca.h" +#include "stroke_cred.h" + +typedef struct stroke_config_t stroke_config_t; + +/** + * Stroke in-memory configuration backend + */ +struct stroke_config_t { + + /** + * Implements the backend_t interface + */ + backend_t backend; + + /** + * Add a configuration to the backend. + * + * @param msg received stroke message containing config + */ + void (*add)(stroke_config_t *this, stroke_msg_t *msg); + + /** + * Remove a configuration from the backend. + * + * @param msg received stroke message containing config name + */ + void (*del)(stroke_config_t *this, stroke_msg_t *msg); + + /** + * Destroy a stroke_config instance. + */ + void (*destroy)(stroke_config_t *this); +}; + +/** + * Create a stroke_config instance. + */ +stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred); + +#endif /* STROKE_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_control.c b/src/charon/plugins/stroke/stroke_control.c new file mode 100644 index 000000000..2956b1576 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_control.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_control.h" + +#include <daemon.h> + +typedef struct private_stroke_control_t private_stroke_control_t; + +/** + * private data of stroke_control + */ +struct private_stroke_control_t { + + /** + * public functions + */ + stroke_control_t public; +}; + + +typedef struct stroke_log_info_t stroke_log_info_t; + +/** + * helper struct to say what and where to log when using controller callback + */ +struct stroke_log_info_t { + + /** + * level to log up to + */ + level_t level; + + /** + * where to write log + */ + FILE* out; +}; + +/** + * logging to the stroke interface + */ +static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level, + ike_sa_t *ike_sa, char *format, va_list args) +{ + if (level <= info->level) + { + if (vfprintf(info->out, format, args) < 0 || + fprintf(info->out, "\n") < 0 || + fflush(info->out) != 0) + { + return FALSE; + } + } + return TRUE; +} + +/** + * get the child_cfg with the same name as the peer cfg + */ +static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) +{ + child_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Implementation of stroke_control_t.initiate. + */ +static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + stroke_log_info_t info; + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->initiate.name); + if (peer_cfg == NULL) + { + DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name); + return; + } + 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) + { + DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name); + peer_cfg->destroy(peer_cfg); + return; + } + + if (msg->output_verbosity < 0) + { + charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + NULL, NULL); + } + else + { + info.out = out; + info.level = msg->output_verbosity; + charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + (controller_cb_t)stroke_log, &info); + } +} + +/** + * Implementation of stroke_control_t.terminate. + */ +static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) +{ + char *string, *pos = NULL, *name = NULL; + u_int32_t id = 0; + bool child; + int len; + ike_sa_t *ike_sa; + enumerator_t *enumerator; + stroke_log_info_t info; + + string = msg->terminate.name; + + len = strlen(string); + if (len < 1) + { + DBG1(DBG_CFG, "error parsing string"); + return; + } + switch (string[len-1]) + { + case '}': + child = TRUE; + pos = strchr(string, '{'); + break; + case ']': + child = FALSE; + pos = strchr(string, '['); + break; + default: + name = string; + child = FALSE; + break; + } + + if (name) + { + /* is a single name */ + } + else if (pos == string + len - 2) + { /* is name[] or name{} */ + string[len-2] = '\0'; + name = string; + } + else + { /* is name[123] or name{23} */ + string[len-1] = '\0'; + id = atoi(pos + 1); + if (id == 0) + { + DBG1(DBG_CFG, "error parsing string"); + return; + } + } + + info.out = out; + info.level = msg->output_verbosity; + + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + + if (child) + { + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if ((name && streq(name, child_sa->get_name(child_sa))) || + (id && id == child_sa->get_reqid(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + enumerator->destroy(enumerator); + + charon->controller->terminate_child(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + } + children->destroy(children); + } + else if ((name && streq(name, ike_sa->get_name(ike_sa))) || + (id && id == ike_sa->get_unique_id(ike_sa))) + { + id = ike_sa->get_unique_id(ike_sa); + /* unlock manager first */ + enumerator->destroy(enumerator); + + charon->controller->terminate_ike(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + + } + enumerator->destroy(enumerator); + DBG1(DBG_CFG, "no such SA found"); +} + +/** + * Implementation of stroke_control_t.route. + */ +static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + stroke_log_info_t info; + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->route.name); + if (peer_cfg == NULL) + { + fprintf(out, "no config named '%s'\n", msg->route.name); + return; + } + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { + peer_cfg->destroy(peer_cfg); + return; + } + + child_cfg = get_child_from_peer(peer_cfg, msg->route.name); + if (child_cfg == NULL) + { + fprintf(out, "no child config named '%s'\n", msg->route.name); + peer_cfg->destroy(peer_cfg); + return; + } + + info.out = out; + info.level = msg->output_verbosity; + charon->controller->route(charon->controller, peer_cfg, child_cfg, + (controller_cb_t)stroke_log, &info); + peer_cfg->destroy(peer_cfg); + child_cfg->destroy(child_cfg); +} + +/** + * Implementation of stroke_control_t.unroute. + */ +static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) +{ + char *name; + ike_sa_t *ike_sa; + enumerator_t *enumerator; + stroke_log_info_t info; + + name = msg->terminate.name; + + info.out = out; + info.level = msg->output_verbosity; + + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + u_int32_t id; + + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if (child_sa->get_state(child_sa) == CHILD_ROUTED && + streq(name, child_sa->get_name(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + enumerator->destroy(enumerator); + charon->controller->unroute(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + DBG1(DBG_CFG, "no such SA found"); +} + +/** + * Implementation of stroke_control_t.destroy + */ +static void destroy(private_stroke_control_t *this) +{ + free(this); +} + +/* + * see header file + */ +stroke_control_t *stroke_control_create() +{ + private_stroke_control_t *this = malloc_thing(private_stroke_control_t); + + this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate; + this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate; + this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route; + this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute; + this->public.destroy = (void(*)(stroke_control_t*))destroy; + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_control.h b/src/charon/plugins/stroke/stroke_control.h new file mode 100644 index 000000000..917679209 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_control.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_control stroke_control + * @{ @ingroup stroke + */ + +#ifndef STROKE_CONTROL_H_ +#define STROKE_CONTROL_H_ + +#include <stroke_msg.h> +#include <library.h> +#include <stdio.h> + +typedef struct stroke_control_t stroke_control_t; + +/** + * Process stroke control messages + */ +struct stroke_control_t { + + /** + * Initiate a connection. + * + * @param msg stroke message + */ + void (*initiate)(stroke_control_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Terminate a connection. + * + * @param msg stroke message + */ + void (*terminate)(stroke_control_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Route a connection. + * + * @param msg stroke message + */ + void (*route)(stroke_control_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Unroute a connection. + * + * @param msg stroke message + */ + void (*unroute)(stroke_control_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Destroy a stroke_control instance. + */ + void (*destroy)(stroke_control_t *this); +}; + +/** + * Create a stroke_control instance. + */ +stroke_control_t *stroke_control_create(); + +#endif /* STROKE_CONTROL_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_cred.c b/src/charon/plugins/stroke/stroke_cred.c new file mode 100644 index 000000000..223500488 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_cred.c @@ -0,0 +1,977 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_cred.h" +#include "stroke_shared_key.h" + +#include <sys/stat.h> +#include <limits.h> + +#include <credentials/certificates/x509.h> +#include <credentials/certificates/crl.h> +#include <credentials/certificates/ac.h> +#include <utils/linked_list.h> +#include <utils/mutex.h> +#include <utils/lexparser.h> +#include <asn1/pem.h> +#include <daemon.h> + +/* configuration directories and files */ +#define CONFIG_DIR IPSEC_CONFDIR +#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d" +#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private" +#define CERTIFICATE_DIR IPSEC_D_DIR "/certs" +#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts" +#define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts" +#define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts" +#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts" +#define CRL_DIR IPSEC_D_DIR "/crls" +#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets" + +typedef struct private_stroke_cred_t private_stroke_cred_t; + +/** + * private data of stroke_cred + */ +struct private_stroke_cred_t { + + /** + * public functions + */ + stroke_cred_t public; + + /** + * list of trusted peer/signer/CA certificates (certificate_t) + */ + linked_list_t *certs; + + /** + * list of shared secrets (private_shared_key_t) + */ + linked_list_t *shared; + + /** + * list of private keys (private_key_t) + */ + linked_list_t *private; + + /** + * mutex to lock lists above + */ + mutex_t *mutex; + + /** + * cache CRLs to disk? + */ + bool cachecrl; +}; + +/** + * data to pass to various filters + */ +typedef struct { + private_stroke_cred_t *this; + identification_t *id; +} id_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void id_data_destroy(id_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for private key enumerator + */ +static bool private_filter(id_data_t *data, + private_key_t **in, private_key_t **out) +{ + identification_t *candidate; + id_type_t type; + + if (data->id == NULL) + { + *out = *in; + return TRUE; + } + type = data->id->get_type(data->id); + if (type == ID_KEY_ID) + { /* handle ID_KEY_ID as a ID_PUBKEY_SHA1 */ + type = ID_PUBKEY_SHA1; + } + candidate = (*in)->get_id(*in, type); + if (candidate && + chunk_equals(candidate->get_encoding(candidate), + data->id->get_encoding(data->id))) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implements credential_set_t.create_private_enumerator + */ +static enumerator_t* create_private_enumerator(private_stroke_cred_t *this, + key_type_t type, identification_t *id) +{ + id_data_t *data; + + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->private->create_enumerator(this->private), + (void*)private_filter, data, + (void*)id_data_destroy); +} + +/** + * filter function for certs enumerator + */ +static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **out) +{ + public_key_t *public; + identification_t *candidate; + certificate_t *cert = *in; + certificate_type_t type = cert->get_type(cert); + + if (type == CERT_X509_CRL || type == CERT_X509_AC) + { + return FALSE; + } + + if (data->id == NULL || cert->has_subject(cert, data->id)) + { + *out = *in; + return TRUE; + } + + public = (cert)->get_public_key(cert); + if (public) + { + candidate = public->get_id(public, data->id->get_type(data->id)); + if (candidate && data->id->equals(data->id, candidate)) + { + public->destroy(public); + *out = *in; + return TRUE; + } + public->destroy(public); + } + return FALSE; +} + +/** + * filter function for crl enumerator + */ +static bool crl_filter(id_data_t *data, certificate_t **in, certificate_t **out) +{ + certificate_t *cert = *in; + + if (cert->get_type(cert) != CERT_X509_CRL) + { + return FALSE; + } + + if (data->id == NULL || cert->has_issuer(cert, data->id)) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * filter function for attribute certificate enumerator + */ +static bool ac_filter(id_data_t *data, certificate_t **in, certificate_t **out) +{ + certificate_t *cert = *in; + + if (cert->get_type(cert) != CERT_X509_AC) + { + return FALSE; + } + + if (data->id == NULL || cert->has_subject(cert, data->id)) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implements credential_set_t.create_cert_enumerator + */ +static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + id_data_t *data; + + if (cert == CERT_X509_CRL || cert == CERT_X509_AC) + { + if (trusted) + { + return NULL; + } + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->certs->create_enumerator(this->certs), + (cert == CERT_X509_CRL)? (void*)crl_filter : (void*)ac_filter, + data, (void*)id_data_destroy); + } + if (cert != CERT_X509 && cert != CERT_ANY) + { /* we only have X509 certificates. TODO: ACs? */ + return NULL; + } + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->certs->create_enumerator(this->certs), + (void*)certs_filter, data, + (void*)id_data_destroy); +} + +typedef struct { + private_stroke_cred_t *this; + identification_t *me; + identification_t *other; + shared_key_type_t type; +} shared_data_t; + +/** + * free shared key enumerator data and unlock list + */ +static void shared_data_destroy(shared_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for certs enumerator + */ +static bool shared_filter(shared_data_t *data, + stroke_shared_key_t **in, shared_key_t **out, + void **unused1, id_match_t *me, + void **unused2, id_match_t *other) +{ + id_match_t my_match, other_match; + stroke_shared_key_t *stroke = *in; + shared_key_t *shared = &stroke->shared; + + if (data->type != SHARED_ANY && shared->get_type(shared) != data->type) + { + return FALSE; + } + + my_match = stroke->has_owner(stroke, data->me); + other_match = stroke->has_owner(stroke, data->other); + if (!my_match && !other_match) + { + return FALSE; + } + *out = shared; + if (me) + { + *me = my_match; + } + if (other) + { + *other = other_match; + } + return TRUE; +} + +/** + * Implements credential_set_t.create_shared_enumerator + */ +static enumerator_t* create_shared_enumerator(private_stroke_cred_t *this, + shared_key_type_t type, identification_t *me, + identification_t *other) +{ + shared_data_t *data = malloc_thing(shared_data_t); + + data->this = this; + data->me = me; + data->other = other; + data->type = type; + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->shared->create_enumerator(this->shared), + (void*)shared_filter, data, + (void*)shared_data_destroy); +} + +/** + * Add a certificate to chain + */ +static certificate_t* add_cert(private_stroke_cred_t *this, certificate_t *cert) +{ + certificate_t *current; + enumerator_t *enumerator; + bool new = TRUE; + + this->mutex->lock(this->mutex); + enumerator = this->certs->create_enumerator(this->certs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->equals(current, cert)) + { + /* cert already in queue */ + cert->destroy(cert); + cert = current; + new = FALSE; + break; + } + } + enumerator->destroy(enumerator); + + if (new) + { + this->certs->insert_last(this->certs, cert); + } + this->mutex->unlock(this->mutex); + return cert; +} + +/** + * Implementation of stroke_cred_t.load_ca. + */ +static certificate_t* load_ca(private_stroke_cred_t *this, char *filename) +{ + certificate_t *cert; + char path[PATH_MAX]; + + if (*filename == '/') + { + snprintf(path, sizeof(path), "%s", filename); + } + else + { + snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename); + } + + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, path, + BUILD_X509_FLAG, X509_CA, + BUILD_END); + if (cert) + { + return (certificate_t*)add_cert(this, cert); + } + return NULL; +} + +/** + * Add X.509 CRL to chain + */ +static bool add_crl(private_stroke_cred_t *this, crl_t* crl) +{ + certificate_t *current, *cert = &crl->certificate; + enumerator_t *enumerator; + bool new = TRUE, found = FALSE; + + this->mutex->lock(this->mutex); + enumerator = this->certs->create_enumerator(this->certs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->get_type(current) == CERT_X509_CRL) + { + crl_t *crl_c = (crl_t*)current; + identification_t *authkey = crl->get_authKeyIdentifier(crl); + identification_t *authkey_c = crl_c->get_authKeyIdentifier(crl_c); + + /* if compare authorityKeyIdentifiers if available */ + if (authkey != NULL && authkey_c != NULL && + authkey->equals(authkey, authkey_c)) + { + found = TRUE; + } + else + { + identification_t *issuer = cert->get_issuer(cert); + identification_t *issuer_c = current->get_issuer(current); + + /* otherwise compare issuer distinguished names */ + if (issuer->equals(issuer, issuer_c)) + { + found = TRUE; + } + } + if (found) + { + new = cert->is_newer(cert, current); + if (new) + { + this->certs->remove_at(this->certs, enumerator); + } + else + { + cert->destroy(cert); + } + break; + } + } + } + enumerator->destroy(enumerator); + + if (new) + { + this->certs->insert_last(this->certs, cert); + } + this->mutex->unlock(this->mutex); + return new; +} + +/** + * Add X.509 attribute certificate to chain + */ +static bool add_ac(private_stroke_cred_t *this, ac_t* ac) +{ + certificate_t *cert = &ac->certificate; + + this->mutex->lock(this->mutex); + this->certs->insert_last(this->certs, cert); + this->mutex->unlock(this->mutex); + return TRUE; +} + +/** + * Implementation of stroke_cred_t.load_peer. + */ +static certificate_t* load_peer(private_stroke_cred_t *this, char *filename) +{ + certificate_t *cert; + char path[PATH_MAX]; + + 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_X509, + BUILD_FROM_FILE, path, + BUILD_X509_FLAG, 0, + BUILD_END); + if (cert) + { + cert = add_cert(this, cert); + return cert->get_ref(cert); + } + return NULL; +} + +/** + * load trusted certificates from a directory + */ +static void load_certdir(private_stroke_cred_t *this, char *path, + certificate_type_t type, x509_flag_t flag) +{ + struct stat st; + char *file; + + enumerator_t *enumerator = enumerator_create_directory(path); + + if (!enumerator) + { + DBG1(DBG_CFG, " reading directory failed"); + return; + } + + while (enumerator->enumerate(enumerator, NULL, &file, &st)) + { + certificate_t *cert; + + if (!S_ISREG(st.st_mode)) + { + /* skip special file */ + continue; + } + switch (type) + { + case CERT_X509: + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, file, + BUILD_X509_FLAG, flag, + BUILD_END); + if (cert) + { + add_cert(this, cert); + } + break; + case CERT_X509_CRL: + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_CRL, + BUILD_FROM_FILE, file, + BUILD_END); + if (cert) + { + add_crl(this, (crl_t*)cert); + } + break; + case CERT_X509_AC: + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_AC, + BUILD_FROM_FILE, file, + BUILD_END); + if (cert) + { + add_ac(this, (ac_t*)cert); + } + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Implementation of credential_set_t.cache_cert. + */ +static void cache_cert(private_stroke_cred_t *this, certificate_t *cert) +{ + if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl) + { + /* CRLs get written to /etc/ipsec.d/crls/authkeyId.crl */ + crl_t *crl = (crl_t*)cert; + + cert->get_ref(cert); + if (add_crl(this, crl)) + { + char buf[256]; + chunk_t chunk, hex; + identification_t *id; + + id = crl->get_authKeyIdentifier(crl); + chunk = id->get_encoding(id); + hex = chunk_to_hex(chunk, NULL, FALSE); + snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex); + free(hex.ptr); + + chunk = cert->get_encoding(cert); + if (chunk_write(chunk, buf, 022, TRUE)) + { + DBG1(DBG_CFG, " written crl to '%s'", buf); + } + else + { + DBG1(DBG_CFG, " writing crl to '%s' failed", buf); + } + free(chunk.ptr); + } + } +} + +/** + * Implementation of stroke_cred_t.cachecrl. + */ +static void cachecrl(private_stroke_cred_t *this, bool enabled) +{ + DBG1(DBG_CFG, "crl caching to %s %s", + CRL_DIR, enabled ? "enabled" : "disabled"); + this->cachecrl = enabled; +} + + +/** + * Convert a string of characters into a binary secret + * A string between single or double quotes is treated as ASCII characters + * A string prepended by 0x is treated as HEX and prepended by 0s as Base64 + */ +static err_t extract_secret(chunk_t *secret, chunk_t *line) +{ + chunk_t raw_secret; + char delimiter = ' '; + bool quotes = FALSE; + + if (!eat_whitespace(line)) + { + return "missing secret"; + } + + if (*line->ptr == '\'' || *line->ptr == '"') + { + quotes = TRUE; + delimiter = *line->ptr; + line->ptr++; line->len--; + } + + if (!extract_token(&raw_secret, delimiter, line)) + { + if (delimiter == ' ') + { + raw_secret = *line; + } + else + { + return "missing second delimiter"; + } + } + + if (quotes) + { + /* treat as an ASCII string */ + *secret = chunk_clone(raw_secret); + return NULL; + } + /* treat 0x as hex, 0s as base64 */ + if (raw_secret.len > 2) + { + if (strncasecmp("0x", raw_secret.ptr, 2) == 0) + { + *secret = chunk_from_hex(chunk_skip(raw_secret, 2), NULL); + return NULL; + } + if (strncasecmp("0s", raw_secret.ptr, 2) == 0) + { + *secret = chunk_from_base64(chunk_skip(raw_secret, 2), NULL); + return NULL; + } + } + *secret = chunk_clone(raw_secret); + return NULL; +} + +/** + * reload ipsec.secrets + */ +static void load_secrets(private_stroke_cred_t *this) +{ + size_t bytes; + int line_nr = 0; + chunk_t chunk, src, line; + FILE *fd; + private_key_t *private; + shared_key_t *shared; + + DBG1(DBG_CFG, "loading secrets from '%s'", SECRETS_FILE); + + fd = fopen(SECRETS_FILE, "r"); + if (fd == NULL) + { + DBG1(DBG_CFG, "opening secrets file '%s' failed"); + return; + } + + /* TODO: do error checks */ + fseek(fd, 0, SEEK_END); + chunk.len = ftell(fd); + rewind(fd); + chunk.ptr = malloc(chunk.len); + bytes = fread(chunk.ptr, 1, chunk.len, fd); + fclose(fd); + src = chunk; + + this->mutex->lock(this->mutex); + while (this->shared->remove_last(this->shared, + (void**)&shared) == SUCCESS) + { + shared->destroy(shared); + } + while (this->private->remove_last(this->private, + (void**)&private) == SUCCESS) + { + private->destroy(private); + } + + while (fetchline(&src, &line)) + { + chunk_t ids, token; + shared_key_type_t type; + + line_nr++; + + if (!eat_whitespace(&line)) + { + continue; + } + if (!extract_last_token(&ids, ':', &line)) + { + DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr); + goto error; + } + /* NULL terminate the ids string by replacing the : separator */ + *(ids.ptr + ids.len) = '\0'; + + if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) + { + DBG1(DBG_CFG, "line %d: missing token", line_nr); + goto error; + } + if (match("RSA", &token) || match("ECDSA", &token)) + { + char path[PATH_MAX]; + chunk_t filename; + chunk_t secret = chunk_empty; + private_key_t *key; + bool pgp = FALSE; + chunk_t chunk = chunk_empty; + key_type_t key_type = match("RSA", &token) ? KEY_RSA : KEY_ECDSA; + + err_t ugh = extract_value(&filename, &line); + + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + goto error; + } + if (filename.len == 0) + { + DBG1(DBG_CFG, "line %d: empty filename", line_nr); + goto error; + } + if (*filename.ptr == '/') + { + /* absolute path name */ + snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); + } + else + { + /* relative path name */ + snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, + filename.len, filename.ptr); + } + + /* check for optional passphrase */ + if (eat_whitespace(&line)) + { + ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh); + goto error; + } + } + + if (pem_asn1_load_file(path, &secret, &chunk, &pgp)) + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (key) + { + DBG1(DBG_CFG, " loaded private key file '%s'", path); + this->private->insert_last(this->private, key); + } + } + chunk_clear(&secret); + } + else if ((match("PSK", &token) && (type = SHARED_IKE)) || + (match("EAP", &token) && (type = SHARED_EAP)) || + (match("XAUTH", &token) && (type = SHARED_EAP)) || + (match("PIN", &token) && (type = SHARED_PIN))) + { + stroke_shared_key_t *shared_key; + chunk_t secret = chunk_empty; + bool any = TRUE; + + err_t ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh); + goto error; + } + shared_key = stroke_shared_key_create(type, secret); + DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type, + ids.len > 0 ? (char*)ids.ptr : "%any"); + DBG4(DBG_CFG, " secret: %#B", &secret); + + this->shared->insert_last(this->shared, shared_key); + while (ids.len > 0) + { + chunk_t id; + identification_t *peer_id; + + ugh = extract_value(&id, &ids); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + goto error; + } + if (id.len == 0) + { + continue; + } + + /* NULL terminate the ID string */ + *(id.ptr + id.len) = '\0'; + + peer_id = identification_create_from_string(id.ptr); + if (peer_id == NULL) + { + DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr); + goto error; + } + if (peer_id->get_type(peer_id) == ID_ANY) + { + peer_id->destroy(peer_id); + continue; + } + + shared_key->add_owner(shared_key, peer_id); + any = FALSE; + } + if (any) + { + shared_key->add_owner(shared_key, + identification_create_from_encoding(ID_ANY, chunk_empty)); + } + } + else + { + DBG1(DBG_CFG, "line %d: token must be either " + "RSA, EC, PSK, EAP, or PIN", line_nr); + goto error; + } + } +error: + this->mutex->unlock(this->mutex); + chunk_clear(&chunk); +} + +/** + * load all certificates from ipsec.d + */ +static void load_certs(private_stroke_cred_t *this) +{ + DBG1(DBG_CFG, "loading ca certificates from '%s'", + CA_CERTIFICATE_DIR); + load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA); + + DBG1(DBG_CFG, "loading aa certificates from '%s'", + AA_CERTIFICATE_DIR); + load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA); + + DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'", + OCSP_CERTIFICATE_DIR); + load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER); + + DBG1(DBG_CFG, "loading attribute certificates from '%s'", + ATTR_CERTIFICATE_DIR); + load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0); + + DBG1(DBG_CFG, "loading crls from '%s'", + CRL_DIR); + load_certdir(this, CRL_DIR, CERT_X509_CRL, 0); +} + +/** + * Implementation of stroke_cred_t.reread. + */ +static void reread(private_stroke_cred_t *this, stroke_msg_t *msg) +{ + if (msg->reread.flags & REREAD_SECRETS) + { + DBG1(DBG_CFG, "rereading secrets"); + load_secrets(this); + } + if (msg->reread.flags & REREAD_CACERTS) + { + DBG1(DBG_CFG, "rereading ca certificates from '%s'", + CA_CERTIFICATE_DIR); + load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA); + } + if (msg->reread.flags & REREAD_OCSPCERTS) + { + DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'", + OCSP_CERTIFICATE_DIR); + load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, + X509_OCSP_SIGNER); + } + if (msg->reread.flags & REREAD_AACERTS) + { + DBG1(DBG_CFG, "rereading aa certificates from '%s'", + AA_CERTIFICATE_DIR); + load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA); + } + if (msg->reread.flags & REREAD_ACERTS) + { + DBG1(DBG_CFG, "rereading attribute certificates from '%s'", + ATTR_CERTIFICATE_DIR); + load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0); + } + if (msg->reread.flags & REREAD_CRLS) + { + DBG1(DBG_CFG, "rereading crls from '%s'", + CRL_DIR); + load_certdir(this, CRL_DIR, CERT_X509_CRL, 0); + } +} + +/** + * Implementation of stroke_cred_t.destroy + */ +static void destroy(private_stroke_cred_t *this) +{ + this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy)); + this->shared->destroy_offset(this->shared, offsetof(shared_key_t, destroy)); + this->private->destroy_offset(this->private, offsetof(private_key_t, destroy)); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +stroke_cred_t *stroke_cred_create() +{ + private_stroke_cred_t *this = malloc_thing(private_stroke_cred_t); + + this->public.set.create_private_enumerator = (void*)create_private_enumerator; + this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->public.set.create_shared_enumerator = (void*)create_shared_enumerator; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.set.cache_cert = (void*)cache_cert; + this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg))reread; + this->public.load_ca = (certificate_t*(*)(stroke_cred_t*, char *filename))load_ca; + this->public.load_peer = (certificate_t*(*)(stroke_cred_t*, char *filename))load_peer; + this->public.cachecrl = (void(*)(stroke_cred_t*, bool enabled))cachecrl; + this->public.destroy = (void(*)(stroke_cred_t*))destroy; + + this->certs = linked_list_create(); + this->shared = linked_list_create(); + this->private = linked_list_create(); + this->mutex = mutex_create(MUTEX_RECURSIVE); + + load_certs(this); + load_secrets(this); + + this->cachecrl = FALSE; + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_cred.h b/src/charon/plugins/stroke/stroke_cred.h new file mode 100644 index 000000000..1b9ef986e --- /dev/null +++ b/src/charon/plugins/stroke/stroke_cred.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_cred stroke_cred + * @{ @ingroup stroke + */ + +#ifndef STROKE_CRED_H_ +#define STROKE_CRED_H_ + +#include <stroke_msg.h> +#include <credentials/credential_set.h> +#include <credentials/certificates/certificate.h> + +typedef struct stroke_cred_t stroke_cred_t; + +/** + * Stroke in-memory credential storage. + */ +struct stroke_cred_t { + + /** + * Implements credential_set_t + */ + credential_set_t set; + + /** + * Reread secrets from config files. + * + * @param msg stroke message + */ + void (*reread)(stroke_cred_t *this, stroke_msg_t *msg); + + /** + * Load a CA certificate, and serve it through the credential_set. + * + * @param filename file to load CA cert from + * @return reference to loaded certificate, or NULL + */ + certificate_t* (*load_ca)(stroke_cred_t *this, char *filename); + + /** + * Load a peer certificate and serve it rhrough the credential_set. + * + * @param filename file to load peer cert from + * @return reference to loaded certificate, or NULL + */ + certificate_t* (*load_peer)(stroke_cred_t *this, char *filename); + + /** + * Enable/Disable CRL caching to disk. + * + * @param enabled TRUE to enable, FALSE to disable + */ + void (*cachecrl)(stroke_cred_t *this, bool enabled); + + /** + * Destroy a stroke_cred instance. + */ + void (*destroy)(stroke_cred_t *this); +}; + +/** + * Create a stroke_cred instance. + */ +stroke_cred_t *stroke_cred_create(); + +#endif /* STROKE_CRED_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_list.c b/src/charon/plugins/stroke/stroke_list.c new file mode 100644 index 000000000..44699ba0a --- /dev/null +++ b/src/charon/plugins/stroke/stroke_list.c @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_list.h" + +#include <daemon.h> +#include <utils/linked_list.h> +#include <credentials/certificates/x509.h> +#include <credentials/certificates/ac.h> +#include <credentials/certificates/crl.h> + +/* warning intervals for list functions */ +#define CERT_WARNING_INTERVAL 30 /* days */ +#define CRL_WARNING_INTERVAL 7 /* days */ +#define AC_WARNING_INTERVAL 1 /* day */ + +typedef struct private_stroke_list_t private_stroke_list_t; + +/** + * private data of stroke_list + */ +struct private_stroke_list_t { + + /** + * public functions + */ + stroke_list_t public; + + /** + * timestamp of daemon start + */ + time_t uptime; +}; + +/** + * log an IKE_SA to out + */ +static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) +{ + ike_sa_id_t *id = ike_sa->get_id(ike_sa); + + fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_sa_state_names, ike_sa->get_state(ike_sa), + ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa), + ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa)); + + if (all) + { + char *ike_proposal = ike_sa->get_proposal(ike_sa); + + fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", + id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); + + + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) + { + u_int32_t rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); + u_int32_t reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); + + if (rekey) + { + fprintf(out, ", rekeying in %V", &rekey); + } + if (reauth) + { + fprintf(out, ", reauthentication in %V", &reauth); + } + if (!rekey && !reauth) + { + fprintf(out, ", rekeying disabled"); + } + } + fprintf(out, "\n"); + + if (ike_proposal) + { + fprintf(out, "%12s[%d]: IKE proposal: %s\n", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_proposal); + } + } +} + +/** + * log an CHILD_SA to out + */ +static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) +{ + u_int32_t rekey, now = time(NULL); + u_int32_t use_in, use_out, use_fwd; + encryption_algorithm_t encr_alg; + integrity_algorithm_t int_alg; + size_t encr_len, int_len; + mode_t mode; + + child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len, + &int_alg, &int_len, &rekey, &use_in, &use_out, + &use_fwd); + + fprintf(out, "%12s{%d}: %N, %N", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + child_sa_state_names, child_sa->get_state(child_sa), + mode_names, mode); + + if (child_sa->get_state(child_sa) == CHILD_INSTALLED) + { + fprintf(out, ", %N SPIs: %.8x_i %.8x_o", + protocol_id_names, child_sa->get_protocol(child_sa), + htonl(child_sa->get_spi(child_sa, TRUE)), + htonl(child_sa->get_spi(child_sa, FALSE))); + + if (all) + { + fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa), + child_sa->get_reqid(child_sa)); + + + if (child_sa->get_protocol(child_sa) == PROTO_ESP) + { + fprintf(out, "%N", encryption_algorithm_names, encr_alg); + + if (encr_len) + { + fprintf(out, "-%d", encr_len); + } + if (int_alg != AUTH_UNDEFINED) + { + fprintf(out, "/"); + } + } + + if (int_alg != AUTH_UNDEFINED) + { + fprintf(out, "%N", integrity_algorithm_names, int_alg); + if (int_len) + { + fprintf(out, "-%d", int_len); + } + } + fprintf(out, ", rekeying "); + + if (rekey) + { + fprintf(out, "in %#V", &now, &rekey); + } + else + { + fprintf(out, "disabled"); + } + + fprintf(out, ", last use: "); + use_in = max(use_in, use_fwd); + if (use_in) + { + fprintf(out, "%ds_i ", now - use_in); + } + else + { + fprintf(out, "no_i "); + } + if (use_out) + { + fprintf(out, "%ds_o ", now - use_out); + } + else + { + fprintf(out, "no_o "); + } + } + } + + 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)); +} + +/** + * Implementation of stroke_list_t.status. + */ +static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all) +{ + enumerator_t *enumerator, *children; + iterator_t *iterator; + host_t *host; + peer_cfg_t *peer_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + ike_sa_t *ike_sa; + char *name = NULL, *plugin; + bool found = FALSE; + time_t uptime; + + name = msg->status.name; + + if (all) + { + uptime = time(NULL) - this->uptime; + fprintf(out, "Performance:\n"); + fprintf(out, " uptime: %V, since %#T\n", &uptime, &this->uptime, FALSE); + fprintf(out, " worker threads: %d idle of %d,", + charon->processor->get_idle_threads(charon->processor), + charon->processor->get_total_threads(charon->processor)); + fprintf(out, " job queue load: %d,", + charon->processor->get_job_load(charon->processor)); + fprintf(out, " scheduled events: %d\n", + charon->scheduler->get_job_load(charon->scheduler)); + fprintf(out, " loaded plugins: "); + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (enumerator->enumerate(enumerator, &plugin)) + { + fprintf(out, "%s ", plugin); + } + enumerator->destroy(enumerator); + fprintf(out, "\n"); + + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + fprintf(out, "Listening IP addresses:\n"); + while (iterator->iterate(iterator, (void**)&host)) + { + fprintf(out, " %H\n", host); + } + iterator->destroy(iterator); + + fprintf(out, "Connections:\n"); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); + while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + { + if (peer_cfg->get_ike_version(peer_cfg) != 2 || + (name && !streq(name, peer_cfg->get_name(peer_cfg)))) + { + continue; + } + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + fprintf(out, "%12s: %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg), + ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg), + ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg)); + /* TODO: list CAs and groups */ + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + linked_list_t *my_ts, *other_ts; + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg), + my_ts, other_ts); + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + } + children->destroy(children); + } + enumerator->destroy(enumerator); + } + + fprintf(out, "Security Associations:\n"); + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + bool ike_printed = FALSE; + child_sa_t *child_sa; + iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa); + + if (name == NULL || streq(name, ike_sa->get_name(ike_sa))) + { + log_ike_sa(out, ike_sa, all); + found = TRUE; + ike_printed = TRUE; + } + + while (children->iterate(children, (void**)&child_sa)) + { + if (name == NULL || streq(name, child_sa->get_name(child_sa))) + { + if (!ike_printed) + { + log_ike_sa(out, ike_sa, all); + found = TRUE; + ike_printed = TRUE; + } + log_child_sa(out, child_sa, all); + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + + if (!found) + { + if (name) + { + fprintf(out, " no match\n"); + } + else + { + fprintf(out, " none\n"); + } + } +} + +/** + * create a unique certificate list without duplicates + * certicates having the same issuer are grouped together. + */ +static linked_list_t* create_unique_cert_list(certificate_type_t type) +{ + linked_list_t *list = linked_list_create(); + enumerator_t *enumerator = charon->credentials->create_cert_enumerator( + charon->credentials, type, KEY_ANY, + NULL, FALSE); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + iterator_t *iterator = list->create_iterator(list, TRUE); + identification_t *issuer = cert->get_issuer(cert); + bool previous_same, same = FALSE, last = TRUE; + certificate_t *list_cert; + + while (iterator->iterate(iterator, (void**)&list_cert)) + { + /* exit if we have a duplicate? */ + if (list_cert->equals(list_cert, cert)) + { + last = FALSE; + break; + } + /* group certificates with same issuer */ + previous_same = same; + same = list_cert->has_issuer(list_cert, issuer); + if (previous_same && !same) + { + iterator->insert_before(iterator, (void *)cert->get_ref(cert)); + last = FALSE; + break; + } + } + iterator->destroy(iterator); + + if (last) + { + list->insert_last(list, (void *)cert->get_ref(cert)); + } + } + enumerator->destroy(enumerator); + return list; +} + +/** + * list all X.509 certificates matching the flags + */ +static void stroke_list_certs(linked_list_t *list, char *label, + x509_flag_t flags, bool utc, FILE *out) +{ + bool first = TRUE; + time_t now = time(NULL); + enumerator_t *enumerator = list->create_enumerator(list); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + x509_t *x509 = (x509_t*)cert; + x509_flag_t x509_flags = x509->get_flags(x509); + + /* list only if flag is set, or flags == 0 (ignoring self-signed) */ + if ((x509_flags & flags) || (flags == (x509_flags & ~X509_SELF_SIGNED))) + { + enumerator_t *enumerator; + identification_t *altName; + bool first_altName = TRUE; + chunk_t serial = x509->get_serial(x509); + identification_t *authkey = x509->get_authKeyIdentifier(x509); + time_t notBefore, notAfter; + public_key_t *public = cert->get_public_key(cert); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of %s:\n", label); + first = FALSE; + } + fprintf(out, "\n"); + + /* list subjectAltNames */ + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, (void**)&altName)) + { + if (first_altName) + { + fprintf(out, " altNames: "); + first_altName = FALSE; + } + else + { + fprintf(out, ", "); + } + fprintf(out, "%D", altName); + } + if (!first_altName) + { + fprintf(out, "\n"); + } + enumerator->destroy(enumerator); + + fprintf(out, " subject: \"%D\"\n", cert->get_subject(cert)); + fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert)); + fprintf(out, " serial: %#B\n", &serial); + + /* list validity */ + cert->get_validity(cert, &now, ¬Before, ¬After); + fprintf(out, " validity: not before %#T, ", ¬Before, utc); + if (now < notBefore) + { + fprintf(out, "not valid yet (valid in %#V)\n", &now, ¬Before); + } + else + { + fprintf(out, "ok\n"); + } + fprintf(out, " not after %#T, ", ¬After, utc); + if (now > notAfter) + { + fprintf(out, "expired (%#V ago)\n", &now, ¬After); + } + else + { + fprintf(out, "ok"); + if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %#V)", &now, ¬After); + } + fprintf(out, " \n"); + } + + /* list public key information */ + if (public) + { + private_key_t *private = NULL; + identification_t *id, *keyid; + + id = public->get_id(public, ID_PUBKEY_SHA1); + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + + private = charon->credentials->get_private( + charon->credentials, + public->get_type(public), keyid, NULL); + fprintf(out, " pubkey: %N %d bits%s\n", + key_type_names, public->get_type(public), + public->get_keysize(public) * 8, + private ? ", has private key" : ""); + fprintf(out, " keyid: %D\n", keyid); + fprintf(out, " subjkey: %D\n", id); + DESTROY_IF(private); + public->destroy(public); + } + + /* list optional authorityKeyIdentifier */ + if (authkey) + { + fprintf(out, " authkey: %D\n", authkey); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * list all X.509 attribute certificates + */ +static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out) +{ + bool first = TRUE; + time_t thisUpdate, nextUpdate, now = time(NULL); + enumerator_t *enumerator = list->create_enumerator(list); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + ac_t *ac = (ac_t*)cert; + chunk_t serial = ac->get_serial(ac); + chunk_t holderSerial = ac->get_holderSerial(ac); + identification_t *holderIssuer = ac->get_holderIssuer(ac); + identification_t *authkey = ac->get_authKeyIdentifier(ac); + identification_t *entityName = cert->get_subject(cert); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of X.509 Attribute Certificates:\n"); + first = FALSE; + } + fprintf(out, "\n"); + + if (entityName) + { + fprintf(out, " holder: \"%D\"\n", entityName); + } + if (holderIssuer) + { + fprintf(out, " hissuer: \"%D\"\n", holderIssuer); + } + if (holderSerial.ptr) + { + fprintf(out, " hserial: %#B\n", &holderSerial); + } + fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert)); + fprintf(out, " serial: %#B\n", &serial); + + /* list validity */ + cert->get_validity(cert, &now, &thisUpdate, &nextUpdate); + fprintf(out, " updates: this %#T\n", &thisUpdate, utc); + fprintf(out, " next %#T, ", &nextUpdate, utc); + if (now > nextUpdate) + { + fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); + } + else + { + fprintf(out, "ok"); + if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %#V)", &now, &nextUpdate); + } + fprintf(out, " \n"); + } + + /* list optional authorityKeyIdentifier */ + if (authkey) + { + fprintf(out, " authkey: %D\n", authkey); + } + } + enumerator->destroy(enumerator); +} + +/** + * list all X.509 CRLs + */ +static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out) +{ + bool first = TRUE; + time_t thisUpdate, nextUpdate, now = time(NULL); + enumerator_t *enumerator = list->create_enumerator(list); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + crl_t *crl = (crl_t*)cert; + chunk_t serial = crl->get_serial(crl); + identification_t *authkey = crl->get_authKeyIdentifier(crl); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of X.509 CRLs:\n"); + first = FALSE; + } + fprintf(out, "\n"); + + fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert)); + + /* list optional crlNumber */ + if (serial.ptr) + { + fprintf(out, " serial: %#B\n", &serial); + } + + /* count the number of revoked certificates */ + { + int count = 0; + enumerator_t *enumerator = crl->create_enumerator(crl); + + while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) + { + count++; + } + fprintf(out, " revoked: %d certificate%s\n", count, + (count == 1)? "" : "s"); + enumerator->destroy(enumerator); + } + + /* list validity */ + cert->get_validity(cert, &now, &thisUpdate, &nextUpdate); + fprintf(out, " updates: this %#T\n", &thisUpdate, utc); + fprintf(out, " next %#T, ", &nextUpdate, utc); + if (now > nextUpdate) + { + fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); + } + else + { + fprintf(out, "ok"); + if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %#V)", &now, &nextUpdate); + } + fprintf(out, " \n"); + } + + /* list optional authorityKeyIdentifier */ + if (authkey) + { + fprintf(out, " authkey: %D\n", authkey); + } + } + enumerator->destroy(enumerator); +} + +/** + * list all OCSP responses + */ +static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out) +{ + bool first = TRUE; + enumerator_t *enumerator = list->create_enumerator(list); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of OCSP responses:\n"); + fprintf(out, "\n"); + first = FALSE; + } + + fprintf(out, " signer: \"%D\"\n", cert->get_issuer(cert)); + } + enumerator->destroy(enumerator); +} + +/** + * Implementation of stroke_list_t.list. + */ +static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out) +{ + linked_list_t *cert_list = NULL; + + if (msg->list.flags & (LIST_CERTS | LIST_CACERTS | LIST_OCSPCERTS | LIST_AACERTS)) + { + cert_list = create_unique_cert_list(CERT_X509); + } + if (msg->list.flags & LIST_CERTS) + { + stroke_list_certs(cert_list, "X.509 End Entity Certificates", + 0, msg->list.utc, out); + } + if (msg->list.flags & LIST_CACERTS) + { + stroke_list_certs(cert_list, "X.509 CA Certificates", + X509_CA, msg->list.utc, out); + } + if (msg->list.flags & LIST_OCSPCERTS) + { + stroke_list_certs(cert_list, "X.509 OCSP Signer Certificates", + X509_OCSP_SIGNER, msg->list.utc, out); + } + if (msg->list.flags & LIST_AACERTS) + { + stroke_list_certs(cert_list, "X.509 AA Certificates", + X509_AA, msg->list.utc, out); + } + if (msg->list.flags & LIST_ACERTS) + { + linked_list_t *ac_list = create_unique_cert_list(CERT_X509_AC); + + stroke_list_acerts(ac_list, msg->list.utc, out); + ac_list->destroy_offset(ac_list, offsetof(certificate_t, destroy)); + } + if (msg->list.flags & LIST_CRLS) + { + linked_list_t *crl_list = create_unique_cert_list(CERT_X509_CRL); + + stroke_list_crls(crl_list, msg->list.utc, out); + crl_list->destroy_offset(crl_list, offsetof(certificate_t, destroy)); + } + if (msg->list.flags & LIST_OCSP) + { + linked_list_t *ocsp_list = create_unique_cert_list(CERT_X509_OCSP_RESPONSE); + + stroke_list_ocsp(ocsp_list, msg->list.utc, out); + ocsp_list->destroy_offset(ocsp_list, offsetof(certificate_t, destroy)); + } + DESTROY_OFFSET_IF(cert_list, offsetof(certificate_t, destroy)); +} + +/** + * Implementation of stroke_list_t.destroy + */ +static void destroy(private_stroke_list_t *this) +{ + free(this); +} + +/* + * see header file + */ +stroke_list_t *stroke_list_create() +{ + private_stroke_list_t *this = malloc_thing(private_stroke_list_t); + + this->public.list = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out))list; + this->public.status = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out,bool))status; + this->public.destroy = (void(*)(stroke_list_t*))destroy; + + this->uptime = time(NULL); + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_list.h b/src/charon/plugins/stroke/stroke_list.h new file mode 100644 index 000000000..dabdbff39 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_list.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_list stroke_list + * @{ @ingroup stroke + */ + +#ifndef STROKE_LIST_H_ +#define STROKE_LIST_H_ + +#include <stroke_msg.h> +#include <library.h> + +typedef struct stroke_list_t stroke_list_t; + +/** + * Log status information to stroke console + */ +struct stroke_list_t { + + /** + * List certificate information to stroke console. + * + * @param msg stroke message + * @param out stroke console stream + */ + void (*list)(stroke_list_t *this, stroke_msg_t *msg, FILE *out); + + /** + * Log status information to stroke console. + * + * @param msg stroke message + * @param out stroke console stream + * @param all TRUE for "statusall" + */ + void (*status)(stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all); + + /** + * Destroy a stroke_list instance. + */ + void (*destroy)(stroke_list_t *this); +}; + +/** + * Create a stroke_list instance. + */ +stroke_list_t *stroke_list_create(); + +#endif /* STROKE_LIST_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_plugin.c b/src/charon/plugins/stroke/stroke_plugin.c new file mode 100644 index 000000000..6933fc074 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_plugin.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_plugin.h" + +#include <library.h> +#include "stroke_socket.h" + +typedef struct private_stroke_plugin_t private_stroke_plugin_t; + +/** + * private data of stroke_plugin + */ +struct private_stroke_plugin_t { + + /** + * public functions + */ + stroke_plugin_t public; + + /** + * stroke socket, receives strokes + */ + stroke_socket_t *socket; +}; + +/** + * Implementation of stroke_plugin_t.destroy + */ +static void destroy(private_stroke_plugin_t *this) +{ + this->socket->destroy(this->socket); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_stroke_plugin_t *this = malloc_thing(private_stroke_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + this->socket = stroke_socket_create(); + if (this->socket == NULL) + { + free(this); + return NULL; + } + return &this->public.plugin; +} + diff --git a/src/charon/plugins/stroke/stroke_plugin.h b/src/charon/plugins/stroke/stroke_plugin.h new file mode 100644 index 000000000..7ea18b8af --- /dev/null +++ b/src/charon/plugins/stroke/stroke_plugin.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: stroke.h 3589 2008-03-13 14:14:44Z martin $ + */ + +/** + * @defgroup stroke stroke + * @ingroup cplugins + * + * @defgroup stroke_plugin stroke_plugin + * @{ @ingroup stroke + */ + +#ifndef STROKE_PLUGIN_H_ +#define STROKE_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct stroke_plugin_t stroke_plugin_t; + +/** + * strongSwan 2.x style configuration and control interface. + * + * Stroke is a home-brewed communication interface inspired by whack. It + * uses a unix socket (/var/run/charon.ctl). + */ +struct stroke_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Instanciate stroke plugin. + */ +plugin_t *plugin_create(); + +#endif /* STROKE_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_shared_key.c b/src/charon/plugins/stroke/stroke_shared_key.c new file mode 100644 index 000000000..9c21eb830 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_shared_key.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_shared_key.h" + +#include <utils/linked_list.h> + +typedef struct private_stroke_shared_key_t private_stroke_shared_key_t; + +/** + * private data of shared_key + */ +struct private_stroke_shared_key_t { + + /** + * implements shared_key_t + */ + stroke_shared_key_t public; + + /** + * type of this key + */ + shared_key_type_t type; + + /** + * data of the key + */ + chunk_t key; + + /** + * list of key owners, as identification_t + */ + linked_list_t *owners; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * Implementation of shared_key_t.get_type. + */ +static shared_key_type_t get_type(private_stroke_shared_key_t *this) +{ + return this->type; +} + +/** + * Implementation of shared_key_t.get_ref. + */ +static private_stroke_shared_key_t* get_ref(private_stroke_shared_key_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of shared_key_t.get_key. + */ +static chunk_t get_key(private_stroke_shared_key_t *this) +{ + return this->key; +} + +/** + * Implementation of stroke_shared_key_t.has_owner. + */ +static id_match_t has_owner(private_stroke_shared_key_t *this, identification_t *owner) +{ + enumerator_t *enumerator; + id_match_t match, best = ID_MATCH_NONE; + identification_t *current; + + enumerator = this->owners->create_enumerator(this->owners); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = owner->matches(owner, current); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} +/** + * Implementation of stroke_shared_key_t.add_owner. + */ +static void add_owner(private_stroke_shared_key_t *this, identification_t *owner) +{ + this->owners->insert_last(this->owners, owner); +} + +/** + * Implementation of stroke_shared_key_t.destroy + */ +static void destroy(private_stroke_shared_key_t *this) +{ + if (ref_put(&this->ref)) + { + this->owners->destroy_offset(this->owners, offsetof(identification_t, destroy)); + chunk_free(&this->key); + free(this); + } +} + +/** + * create a shared key + */ +stroke_shared_key_t *stroke_shared_key_create(shared_key_type_t type, chunk_t key) +{ + private_stroke_shared_key_t *this = malloc_thing(private_stroke_shared_key_t); + + this->public.shared.get_type = (shared_key_type_t(*)(shared_key_t*))get_type; + this->public.shared.get_key = (chunk_t(*)(shared_key_t*))get_key; + this->public.shared.get_ref = (shared_key_t*(*)(shared_key_t*))get_ref; + this->public.shared.destroy = (void(*)(shared_key_t*))destroy; + this->public.add_owner = (void(*)(stroke_shared_key_t*, identification_t *owner))add_owner; + this->public.has_owner = (id_match_t(*)(stroke_shared_key_t*, identification_t *owner))has_owner; + + this->owners = linked_list_create(); + this->type = type; + this->key = key; + this->ref = 1; + + return &this->public; +} diff --git a/src/charon/plugins/stroke/stroke_shared_key.h b/src/charon/plugins/stroke/stroke_shared_key.h new file mode 100644 index 000000000..e93d8cee2 --- /dev/null +++ b/src/charon/plugins/stroke/stroke_shared_key.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_shared_key stroke_shared_key + * @{ @ingroup stroke + */ + +#ifndef STROKE_SHARED_KEY_H_ +#define STROKE_SHARED_KEY_H_ + +#include <utils/identification.h> +#include <credentials/keys/shared_key.h> + +typedef struct stroke_shared_key_t stroke_shared_key_t; + +/** + * Shared key implementation for keys read from ipsec.secrets + */ +struct stroke_shared_key_t { + + /** + * Implements the shared_key_t interface. + */ + shared_key_t shared; + + /** + * Add an owner to the key. + * + * @param owner owner to add + */ + void (*add_owner)(stroke_shared_key_t *this, identification_t *owner); + + /** + * Check if a key has a specific owner. + * + * @param owner owner to check + * @return best match found + */ + id_match_t (*has_owner)(stroke_shared_key_t *this, identification_t *owner); +}; + +/** + * Create a stroke_shared_key instance. + */ +stroke_shared_key_t *stroke_shared_key_create(shared_key_type_t type, chunk_t key); + +#endif /* STROKE_SHARED_KEY_H_ @}*/ diff --git a/src/charon/plugins/stroke/stroke_socket.c b/src/charon/plugins/stroke/stroke_socket.c new file mode 100644 index 000000000..92e295a0c --- /dev/null +++ b/src/charon/plugins/stroke/stroke_socket.c @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "stroke_socket.h" + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include <processing/jobs/callback_job.h> +#include <daemon.h> + +#include "stroke_config.h" +#include "stroke_control.h" +#include "stroke_cred.h" +#include "stroke_ca.h" +#include "stroke_attribute.h" +#include "stroke_list.h" + +typedef struct stroke_job_context_t stroke_job_context_t; +typedef struct private_stroke_socket_t private_stroke_socket_t; + +/** + * private data of stroke_socket + */ +struct private_stroke_socket_t { + + /** + * public functions + */ + stroke_socket_t public; + + /** + * Unix socket to listen for strokes + */ + int socket; + + /** + * job accepting stroke messages + */ + callback_job_t *job; + + /** + * configuration backend + */ + stroke_config_t *config; + + /** + * attribute provider + */ + stroke_attribute_t *attribute; + + /** + * controller to control daemon + */ + stroke_control_t *control; + + /** + * credential set + */ + stroke_cred_t *cred; + + /** + * CA sections + */ + stroke_ca_t *ca; + + /** + * Status information logging + */ + stroke_list_t *list; +}; + +/** + * job context to pass to processing thread + */ +struct stroke_job_context_t { + + /** + * file descriptor to read from + */ + int fd; + + /** + * global stroke interface + */ + private_stroke_socket_t *this; +}; + +/** + * Helper function which corrects the string pointers + * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" + * contains RELATIVE addresses (relative to the beginning of the + * stroke_msg). They must be corrected if they reach our address + * space... + */ +static void pop_string(stroke_msg_t *msg, char **string) +{ + if (*string == NULL) + { + return; + } + + /* check for sanity of string pointer and string */ + if (string < (char**)msg || + string > (char**)msg + sizeof(stroke_msg_t) || + (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) || + (unsigned long)*string > msg->length) + { + *string = "(invalid pointer in stroke msg)"; + } + else + { + *string = (char*)msg + (unsigned long)*string; + } +} + +/** + * Pop the strings of a stroke_end_t struct and log them for debugging purposes + */ +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->id); + pop_string(msg, &end->cert); + pop_string(msg, &end->ca); + pop_string(msg, &end->groups); + 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, " %sid=%s", label, end->id); + DBG2(DBG_CFG, " %scert=%s", label, end->cert); + DBG2(DBG_CFG, " %sca=%s", label, end->ca); + DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); + DBG2(DBG_CFG, " %supdown=%s", label, end->updown); +} + +/** + * Add a connection to the configuration list + */ +static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) +{ + pop_string(msg, &msg->add_conn.name); + DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); + + DBG2(DBG_CFG, "conn %s", msg->add_conn.name); + pop_end(msg, "left", &msg->add_conn.me); + pop_end(msg, "right", &msg->add_conn.other); + 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, " ike=%s", msg->add_conn.algorithms.ike); + DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); + 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); + + this->config->add(this->config, msg); + this->attribute->add_pool(this->attribute, msg); +} + +/** + * Delete a connection from the list + */ +static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg) +{ + pop_string(msg, &msg->del_conn.name); + 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); +} + +/** + * initiate a connection by name + */ +static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->initiate.name); + DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name); + + this->control->initiate(this->control, msg, out); +} + +/** + * terminate a connection by name + */ +static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->terminate.name); + DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name); + + this->control->terminate(this->control, msg, out); +} + +/** + * route a policy (install SPD entries) + */ +static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->route.name); + DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); + + this->control->route(this->control, msg, out); +} + +/** + * unroute a policy + */ +static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->terminate.name); + DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name); + + this->control->unroute(this->control, msg, out); +} + +/** + * Add a ca information record to the cainfo list + */ +static void stroke_add_ca(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->add_ca.name); + DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name); + + pop_string(msg, &msg->add_ca.cacert); + pop_string(msg, &msg->add_ca.crluri); + pop_string(msg, &msg->add_ca.crluri2); + pop_string(msg, &msg->add_ca.ocspuri); + pop_string(msg, &msg->add_ca.ocspuri2); + pop_string(msg, &msg->add_ca.certuribase); + DBG2(DBG_CFG, "ca %s", msg->add_ca.name); + DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert); + DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri); + DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2); + DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri); + DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2); + DBG2(DBG_CFG, " certuribase=%s", msg->add_ca.certuribase); + + this->ca->add(this->ca, msg); +} + +/** + * Delete a ca information record from the cainfo list + */ +static void stroke_del_ca(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->del_ca.name); + DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name); + + this->ca->del(this->ca, msg); +} + + +/** + * show status of daemon + */ +static void stroke_status(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out, bool all) +{ + pop_string(msg, &(msg->status.name)); + + this->list->status(this->list, msg, out, all); +} + +/** + * list various information + */ +static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + if (msg->list.flags & LIST_CAINFOS) + { + this->ca->list(this->ca, msg, out); + } + this->list->list(this->list, msg, out); +} + +/** + * reread various information + */ +static void stroke_reread(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + this->cred->reread(this->cred, msg); +} + +/** + * purge various information + */ +static void stroke_purge(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + charon->credentials->flush_cache(charon->credentials, + CERT_X509_OCSP_RESPONSE); +} + +signal_t get_signal_from_logtype(char *type) +{ + if (strcasecmp(type, "any") == 0) return SIG_ANY; + else if (strcasecmp(type, "mgr") == 0) return DBG_MGR; + else if (strcasecmp(type, "ike") == 0) return DBG_IKE; + else if (strcasecmp(type, "chd") == 0) return DBG_CHD; + else if (strcasecmp(type, "job") == 0) return DBG_JOB; + else if (strcasecmp(type, "cfg") == 0) return DBG_CFG; + else if (strcasecmp(type, "knl") == 0) return DBG_KNL; + else if (strcasecmp(type, "net") == 0) return DBG_NET; + else if (strcasecmp(type, "enc") == 0) return DBG_ENC; + else if (strcasecmp(type, "lib") == 0) return DBG_LIB; + else return -1; +} + +/** + * set the verbosity debug output + */ +static void stroke_loglevel(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + signal_t signal; + + pop_string(msg, &(msg->loglevel.type)); + DBG1(DBG_CFG, "received stroke: loglevel %d for %s", + msg->loglevel.level, msg->loglevel.type); + + signal = get_signal_from_logtype(msg->loglevel.type); + if (signal < 0) + { + fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); + return; + } + + charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level); + charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level); +} + +/** + * set various config options + */ +static void stroke_config(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) +{ + this->cred->cachecrl(this->cred, msg->config.cachecrl); +} + +/** + * destroy a job context + */ +static void stroke_job_context_destroy(stroke_job_context_t *this) +{ + if (this->fd) + { + close(this->fd); + } + free(this); +} + +/** + * process a stroke request from the socket pointed by "fd" + */ +static job_requeue_t process(stroke_job_context_t *ctx) +{ + stroke_msg_t *msg; + u_int16_t msg_length; + ssize_t bytes_read; + 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)) + { + DBG1(DBG_CFG, "reading length of stroke message failed: %s", + strerror(errno)); + return JOB_REQUEUE_NONE; + } + + /* read message */ + msg = alloca(msg_length); + bytes_read = recv(strokefd, msg, msg_length, 0); + if (bytes_read != msg_length) + { + DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); + return JOB_REQUEUE_NONE; + } + + out = fdopen(strokefd, "w"); + if (out == NULL) + { + DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); + return JOB_REQUEUE_NONE; + } + + DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); + + switch (msg->type) + { + case STR_INITIATE: + stroke_initiate(this, msg, out); + break; + case STR_ROUTE: + stroke_route(this, msg, out); + break; + case STR_UNROUTE: + stroke_unroute(this, msg, out); + break; + case STR_TERMINATE: + stroke_terminate(this, msg, out); + break; + case STR_STATUS: + stroke_status(this, msg, out, FALSE); + break; + case STR_STATUS_ALL: + stroke_status(this, msg, out, TRUE); + break; + case STR_ADD_CONN: + stroke_add_conn(this, msg); + break; + case STR_DEL_CONN: + stroke_del_conn(this, msg); + break; + case STR_ADD_CA: + stroke_add_ca(this, msg, out); + break; + case STR_DEL_CA: + stroke_del_ca(this, msg, out); + break; + case STR_LOGLEVEL: + stroke_loglevel(this, msg, out); + break; + case STR_CONFIG: + stroke_config(this, msg, out); + break; + case STR_LIST: + stroke_list(this, msg, out); + break; + case STR_REREAD: + stroke_reread(this, msg, out); + break; + case STR_PURGE: + stroke_purge(this, msg, out); + break; + default: + DBG1(DBG_CFG, "received unknown stroke"); + break; + } + fclose(out); + /* fclose() closes underlying FD */ + ctx->fd = 0; + return JOB_REQUEUE_NONE; +} + +/** + * Implementation of private_stroke_socket_t.stroke_receive. + */ +static job_requeue_t receive(private_stroke_socket_t *this) +{ + struct sockaddr_un strokeaddr; + int strokeaddrlen = sizeof(strokeaddr); + int strokefd; + int oldstate; + callback_job_t *job; + stroke_job_context_t *ctx; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (strokefd < 0) + { + DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno)); + return JOB_REQUEUE_FAIR; + } + + ctx = malloc_thing(stroke_job_context_t); + ctx->fd = strokefd; + ctx->this = this; + job = callback_job_create((callback_job_cb_t)process, + ctx, (void*)stroke_job_context_destroy, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_FAIR; +} + + +/** + * initialize and open stroke socket + */ +static bool open_socket(private_stroke_socket_t *this) +{ + struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET}; + mode_t old; + + /* 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, 0) < 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; +} + +/** + * Implementation of stroke_socket_t.destroy + */ +static void destroy(private_stroke_socket_t *this) +{ + this->job->cancel(this->job); + charon->credentials->remove_set(charon->credentials, &this->ca->set); + charon->credentials->remove_set(charon->credentials, &this->cred->set); + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->attributes->remove_provider(charon->attributes, &this->attribute->provider); + this->cred->destroy(this->cred); + this->ca->destroy(this->ca); + this->config->destroy(this->config); + this->attribute->destroy(this->attribute); + this->control->destroy(this->control); + this->list->destroy(this->list); + free(this); +} + +/* + * see header file + */ +stroke_socket_t *stroke_socket_create() +{ + private_stroke_socket_t *this = malloc_thing(private_stroke_socket_t); + + this->public.destroy = (void(*)(stroke_socket_t*))destroy; + + if (!open_socket(this)) + { + free(this); + return NULL; + } + + this->cred = stroke_cred_create(); + this->attribute = stroke_attribute_create(); + this->ca = stroke_ca_create(this->cred); + this->config = stroke_config_create(this->ca, this->cred); + this->control = stroke_control_create(); + this->list = stroke_list_create(); + + charon->credentials->add_set(charon->credentials, &this->ca->set); + charon->credentials->add_set(charon->credentials, &this->cred->set); + charon->backends->add_backend(charon->backends, &this->config->backend); + charon->attributes->add_provider(charon->attributes, &this->attribute->provider); + + this->job = callback_job_create((callback_job_cb_t)receive, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public; +} + diff --git a/src/charon/plugins/stroke/stroke_socket.h b/src/charon/plugins/stroke/stroke_socket.h new file mode 100644 index 000000000..7bc96686f --- /dev/null +++ b/src/charon/plugins/stroke/stroke_socket.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup stroke_socket stroke_socket + * @{ @ingroup stroke + */ + +#ifndef STROKE_SOCKET_H_ +#define STROKE_SOCKET_H_ + +typedef struct stroke_socket_t stroke_socket_t; + +/** + * Stroke socket, opens UNIX communication socket, reads and dispatches. + */ +struct stroke_socket_t { + + /** + * Destroy a stroke_socket instance. + */ + void (*destroy)(stroke_socket_t *this); +}; + +/** + * Create a stroke_socket instance. + */ +stroke_socket_t *stroke_socket_create(); + +#endif /* STROKE_SOCKET_H_ @}*/ diff --git a/src/charon/plugins/uci/Makefile.am b/src/charon/plugins/uci/Makefile.am new file mode 100644 index 000000000..47a55ae17 --- /dev/null +++ b/src/charon/plugins/uci/Makefile.am @@ -0,0 +1,13 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-uci.la +libstrongswan_uci_la_SOURCES = \ + uci_plugin.h uci_plugin.c uci_parser.h uci_parser.c \ + uci_config.h uci_config.c uci_creds.h uci_creds.c +libstrongswan_uci_la_LDFLAGS = -module +libstrongswan_uci_la_LIBADD = -luci + + diff --git a/src/charon/plugins/uci/Makefile.in b/src/charon/plugins/uci/Makefile.in new file mode 100644 index 000000000..297f25768 --- /dev/null +++ b/src/charon/plugins/uci/Makefile.in @@ -0,0 +1,501 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/uci +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_uci_la_DEPENDENCIES = +am_libstrongswan_uci_la_OBJECTS = uci_plugin.lo uci_parser.lo \ + uci_config.lo uci_creds.lo +libstrongswan_uci_la_OBJECTS = $(am_libstrongswan_uci_la_OBJECTS) +libstrongswan_uci_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_uci_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_uci_la_SOURCES) +DIST_SOURCES = $(libstrongswan_uci_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-uci.la +libstrongswan_uci_la_SOURCES = \ + uci_plugin.h uci_plugin.c uci_parser.h uci_parser.c \ + uci_config.h uci_config.c uci_creds.h uci_creds.c + +libstrongswan_uci_la_LDFLAGS = -module +libstrongswan_uci_la_LIBADD = -luci +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/uci/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/uci/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-uci.la: $(libstrongswan_uci_la_OBJECTS) $(libstrongswan_uci_la_DEPENDENCIES) + $(libstrongswan_uci_la_LINK) -rpath $(plugindir) $(libstrongswan_uci_la_OBJECTS) $(libstrongswan_uci_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci_creds.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci_parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/uci/uci_config.c b/src/charon/plugins/uci/uci_config.c new file mode 100644 index 000000000..cc44eaa9b --- /dev/null +++ b/src/charon/plugins/uci/uci_config.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2008 Thomas Kallenberg + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include <string.h> + +#include "uci_config.h" +#include "uci_parser.h" + +#include <daemon.h> + +typedef struct private_uci_config_t private_uci_config_t; + +/** + * Private data of an uci_config_t object + */ +struct private_uci_config_t { + + /** + * Public part + */ + uci_config_t public; + + /** + * UCI parser context + */ + uci_parser_t *parser; +}; + +/** + * enumerator implementation for create_peer_cfg_enumerator + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** currently enumerated peer config */ + peer_cfg_t *peer_cfg; + /** inner uci_parser section enumerator */ + enumerator_t *inner; +} peer_enumerator_t; + +/** + * create a proposal from a string, with fallback to default + */ +static proposal_t *create_proposal(char *string, protocol_id_t proto) +{ + proposal_t *proposal = NULL; + + if (string) + { + proposal = proposal_create_from_string(proto, string); + } + if (!proposal) + { /* UCI default is aes/sha1 only */ + if (proto == PROTO_IKE) + { + proposal = proposal_create_from_string(proto, + "aes128-aes192-aes256-sha1-modp1536-modp2048"); + } + else + { + proposal = proposal_create_from_string(proto, + "aes128-aes192-aes256-sha1"); + } + } + return proposal; +} + +/** + * create an identity, with fallback to %any + */ +static identification_t *create_id(char *string) +{ + identification_t *id = NULL; + + if (string) + { + id = identification_create_from_string(string); + } + if (!id) + { + id = identification_create_from_encoding(ID_ANY, chunk_empty); + } + return id; +} + +/** + * create an traffic selector, fallback to dynamic + */ +static traffic_selector_t *create_ts(char *string) +{ + if (string) + { + int netbits = 32; + host_t *net; + char *pos; + + string = strdupa(string); + pos = strchr(string, '/'); + if (pos) + { + *pos++ = '\0'; + netbits = atoi(pos); + } + else + { + if (strchr(string, ':')) + { + netbits = 128; + } + } + net = host_create_from_string(string, 0); + if (net) + { + return traffic_selector_create_from_subnet(net, netbits, 0, 0); + } + } + return traffic_selector_create_dynamic(0, 0, 65535); +} + +/** + * create a rekey time from a string with hours, with fallback + */ +static u_int create_rekey(char *string) +{ + u_int rekey = 0; + + if (string) + { + rekey = atoi(string); + if (rekey) + { + return rekey * 3600; + } + } + /* every 12 hours */ + return 12 * 3600; +} + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +{ + char *name, *ike_proposal, *esp_proposal, *ike_rekey, *esp_rekey; + char *local_id, *local_addr, *local_net; + char *remote_id, *remote_addr, *remote_net; + child_cfg_t *child_cfg; + ike_cfg_t *ike_cfg; + + /* defaults */ + name = "unnamed"; + local_id = NULL; + remote_id = NULL; + local_addr = "0.0.0.0"; + remote_addr = "0.0.0.0"; + local_net = NULL; + remote_net = NULL; + ike_proposal = NULL; + esp_proposal = NULL; + ike_rekey = NULL; + esp_rekey = NULL; + + if (this->inner->enumerate(this->inner, &name, &local_id, &remote_id, + &local_addr, &remote_addr, &local_net, &remote_net, + &ike_proposal, &esp_proposal, &ike_rekey, &esp_rekey)) + { + DESTROY_IF(this->peer_cfg); + ike_cfg = ike_cfg_create(FALSE, FALSE, local_addr, remote_addr); + ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); + this->peer_cfg = peer_cfg_create( + name, 2, ike_cfg, create_id(local_id), create_id(remote_id), + CERT_SEND_IF_ASKED, UNIQUE_NO, CONF_AUTH_PSK, + 0, 0, /* EAP method, vendor */ + 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ + 1800, 900, /* jitter, overtime */ + TRUE, 60, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + FALSE, NULL, NULL); /* mediation, med by, peer id */ + child_cfg = child_cfg_create(name, + create_rekey(esp_rekey) + 300, create_rekey(ike_rekey), 300, + NULL, TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE); + child_cfg->add_proposal(child_cfg, create_proposal(esp_proposal, PROTO_ESP)); + child_cfg->add_traffic_selector(child_cfg, TRUE, create_ts(local_net)); + child_cfg->add_traffic_selector(child_cfg, FALSE, create_ts(remote_net)); + this->peer_cfg->add_child_cfg(this->peer_cfg, child_cfg); + *cfg = this->peer_cfg; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of peer_enumerator_t.public.destroy + */ +static void peer_enumerator_destroy(peer_enumerator_t *this) +{ + DESTROY_IF(this->peer_cfg); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_uci_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_enumerator_t *e = malloc_thing(peer_enumerator_t); + + e->public.enumerate = (void*)peer_enumerator_enumerate; + e->public.destroy = (void*)peer_enumerator_destroy; + e->peer_cfg = NULL; + e->inner = this->parser->create_section_enumerator(this->parser, + "local_id", "remote_id", "local_addr", "remote_addr", + "local_net", "remote_net", "ike_proposal", "esp_proposal", + "ike_rekey", "esp_rekey", NULL); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * enumerator implementation for create_ike_cfg_enumerator + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** currently enumerated ike config */ + ike_cfg_t *ike_cfg; + /** inner uci_parser section enumerator */ + enumerator_t *inner; +} ike_enumerator_t; + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg) +{ + char *local_addr, *remote_addr, *ike_proposal; + + /* defaults */ + local_addr = "0.0.0.0"; + remote_addr = "0.0.0.0"; + ike_proposal = NULL; + + if (this->inner->enumerate(this->inner, NULL, + &local_addr, &remote_addr, &ike_proposal)) + { + DESTROY_IF(this->ike_cfg); + this->ike_cfg = ike_cfg_create(FALSE, FALSE, local_addr, remote_addr); + this->ike_cfg->add_proposal(this->ike_cfg, + create_proposal(ike_proposal, PROTO_IKE)); + + *cfg = this->ike_cfg; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of ike_enumerator_t.public.destroy + */ +static void ike_enumerator_destroy(ike_enumerator_t *this) +{ + DESTROY_IF(this->ike_cfg); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_uci_config_t *this, + host_t *me, host_t *other) +{ + ike_enumerator_t *e = malloc_thing(ike_enumerator_t); + + e->public.enumerate = (void*)ike_enumerator_enumerate; + e->public.destroy = (void*)ike_enumerator_destroy; + e->ike_cfg = NULL; + e->inner = this->parser->create_section_enumerator(this->parser, + "local_addr", "remote_addr", "ike_proposal", NULL); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_uci_config_t *this, char *name) +{ + enumerator_t *enumerator; + peer_cfg_t *current, *found = NULL; + + enumerator = create_peer_cfg_enumerator(this, NULL, NULL); + if (enumerator) + { + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(name, current->get_name(current))) + { + found = current->get_ref(current); + break; + } + } + enumerator->destroy(enumerator); + } + return found; +} + +/** + * Implementation of uci_config_t.destroy. + */ +static void destroy(private_uci_config_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +uci_config_t *uci_config_create(uci_parser_t *parser) +{ + private_uci_config_t *this = malloc_thing(private_uci_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(uci_config_t*))destroy; + + this->parser = parser; + + return &this->public; +} + diff --git a/src/charon/plugins/uci/uci_config.h b/src/charon/plugins/uci/uci_config.h new file mode 100644 index 000000000..4d8b286c6 --- /dev/null +++ b/src/charon/plugins/uci/uci_config.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Thomas Kallenberg + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup uci_config_t uci_config + * @{ @ingroup uci + */ + +#ifndef UCI_CONFIG_H_ +#define UCI_CONFIG_H_ + +#include "uci_parser.h" + +#include <config/backend.h> + +typedef struct uci_config_t uci_config_t; + +/** + * OpenWRT UCI configuration backend. + */ +struct uci_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destroy the backend. + */ + void (*destroy)(uci_config_t *this); +}; + +/** + * Create a UCI based configuration backend. + * + * @param parser UCI parser to use + * @return configuration backend + */ +uci_config_t *uci_config_create(uci_parser_t *parser); + +#endif /* UCI_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/uci/uci_creds.c b/src/charon/plugins/uci/uci_creds.c new file mode 100644 index 000000000..60f6fc934 --- /dev/null +++ b/src/charon/plugins/uci/uci_creds.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008 Thomas Kallenberg + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "uci_creds.h" + +#include <daemon.h> +#include <credentials/keys/shared_key.h> +#include <utils/identification.h> + +typedef struct private_uci_creds_t private_uci_creds_t; + +/** + * Private data of an uci_creds_t object + */ +struct private_uci_creds_t { + /** + * Public part + */ + uci_creds_t public; + + /** + * UCI parser context + */ + uci_parser_t *parser; +}; + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inneer UCI enumerator */ + enumerator_t *inner; + /** currently enumerated shared shared */ + shared_key_t *current; + /** local ID to match */ + identification_t *me; + /** remote ID to match */ + identification_t *other; +} shared_enumerator_t; + +/** + * Implementation of shared_enumerator_t.public.enumerate + */ +static bool shared_enumerator_enumerate(shared_enumerator_t *this, + shared_key_t **key, id_match_t *me, id_match_t *other) +{ + char *local_id, *remote_id, *psk; + identification_t *local, *remote; + + while (TRUE) + { + /* defaults */ + local_id = "%any"; + remote_id = "%any"; + psk = NULL; + + if (!this->inner->enumerate(this->inner, NULL, + &local_id, &remote_id, &psk)) + { + return FALSE; + } + if (psk == NULL) + { + continue; + } + if (me) + { + local = identification_create_from_string(local_id); + if (!local) + { + continue; + } + *me = this->me ? this->me->matches(this->me, local) + : ID_MATCH_ANY; + local->destroy(local); + if (!*me) + { + continue; + } + } + if (other) + { + remote = identification_create_from_string(remote_id); + if (!remote) + { + continue; + } + *other = this->other ? this->other->matches(this->other, remote) + : ID_MATCH_ANY; + remote->destroy(remote); + if (!*other) + { + continue; + } + } + break; + } + DESTROY_IF(this->current); + this->current = shared_key_create(SHARED_IKE, + chunk_clone(chunk_create(psk, strlen(psk)))); + *key = this->current; + return TRUE; +} + +/** + * Implementation of shared_enumerator_t.public.destroy + */ +static void shared_enumerator_destroy(shared_enumerator_t *this) +{ + this->inner->destroy(this->inner); + DESTROY_IF(this->current); + free(this); +} + +/** + * Implementation of backend_t.create_shared_cfg_enumerator. + */ +static enumerator_t* create_shared_enumerator(private_uci_creds_t *this, + shared_key_type_t type, + identification_t *me, + identification_t *other) +{ + shared_enumerator_t *e; + + if (type != SHARED_IKE) + { + return NULL; + } + + e = malloc_thing(shared_enumerator_t); + e->current = NULL; + e->public.enumerate = (void*)shared_enumerator_enumerate; + e->public.destroy = (void*)shared_enumerator_destroy; + e->me = me; + e->other = other; + e->inner = this->parser->create_section_enumerator(this->parser, + "local_id", "remote_id", "psk", NULL); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of uci_creds_t.destroy + */ +static void destroy(private_uci_creds_t *this) +{ + free(this); +} + +uci_creds_t *uci_creds_create(uci_parser_t *parser) +{ + private_uci_creds_t *this = malloc_thing(private_uci_creds_t); + + this->public.credential_set.create_shared_enumerator = (enumerator_t*(*)(credential_set_t*, shared_key_type_t, identification_t*, identification_t*))create_shared_enumerator; + this->public.credential_set.create_private_enumerator = (enumerator_t*(*) (credential_set_t*, key_type_t, identification_t*))return_null; + this->public.credential_set.create_cert_enumerator = (enumerator_t*(*) (credential_set_t*, certificate_type_t, key_type_t,identification_t *, bool))return_null; + this->public.credential_set.create_cdp_enumerator = (enumerator_t*(*) (credential_set_t *,certificate_type_t, identification_t *))return_null; + this->public.credential_set.cache_cert = (void (*)(credential_set_t *, certificate_t *))nop; + this->public.destroy = (void(*) (uci_creds_t*))destroy; + + this->parser = parser; + + return &this->public; +} + diff --git a/src/charon/plugins/uci/uci_creds.h b/src/charon/plugins/uci/uci_creds.h new file mode 100644 index 000000000..cf82f1c07 --- /dev/null +++ b/src/charon/plugins/uci/uci_creds.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Thomas Kallenberg + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup uci_creds_t uci_creds + * @{ @ingroup uci + */ + +#ifndef UCI_CREDS_H_ +#define UCI_CREDS_H_ + +#include "uci_parser.h" + +#include <credentials/credential_set.h> + +typedef struct uci_creds_t uci_creds_t; + +/** + * OpenWRT UCI credential set implementation. + */ +struct uci_creds_t { + + /** + * Implements credential set interface. + */ + credential_set_t credential_set; + + /** + * Destroy the backend. + */ + void (*destroy)(uci_creds_t *this); +}; + +/** + * Create a UCI based credential set. + * + * @param parser UCI parser to use + * @return credential set + */ +uci_creds_t *uci_creds_create(uci_parser_t *parser); + +#endif /* UCI_CREDS_H_ @}*/ diff --git a/src/charon/plugins/uci/uci_parser.c b/src/charon/plugins/uci/uci_parser.c new file mode 100644 index 000000000..796d2993a --- /dev/null +++ b/src/charon/plugins/uci/uci_parser.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Thomas Kallenberg + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "uci_parser.h" + +#include <stdarg.h> + +#include <library.h> +#include <uci.h> + +typedef struct private_uci_parser_t private_uci_parser_t; + +/** + * Private data of an uci_parser_t object + */ +struct private_uci_parser_t { + + /** + * Public part + */ + uci_parser_t public; + + /** + * UCI package name this parser reads + */ + char *package; +}; + +/** + * enumerator implementation create_section_enumerator + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** currently enumerated uci section */ + struct uci_element *current; + /** all uci ipsec config sections */ + struct uci_list *list; + /** uci conntext */ + struct uci_context *ctx; + /** ipsec uci package */ + struct uci_package *package; + /** NULL terminated list of keywords */ + char *keywords[]; +} section_enumerator_t; + +/** + * Implementation of section_enumerator_t.enumerate + */ +static bool section_enumerator_enumerate(section_enumerator_t *this, ...) +{ + struct uci_element *element; + char **value; + va_list args; + int i; + + if (&this->current->list == this->list) + { + return FALSE; + } + + va_start(args, this); + + /* name is first parameter */ + value = va_arg(args, char**); + if (value) + { + *value = uci_to_section(this->current)->type; + } + + /* followed by keyword parameters */ + for (i = 0; this->keywords[i]; i++) + { + value = va_arg(args, char**); + if (value && uci_lookup(this->ctx, &element, this->package, + this->current->name, this->keywords[i]) == UCI_OK) + { + *value = uci_to_option(element)->value; + } + } + va_end(args); + + this->current = list_to_element(this->current->list.next); + return TRUE; +} + +/** + * Implementation of section_enumerator_t.public.destroy + */ +static void section_enumerator_destroy(section_enumerator_t *this) +{ + uci_free_context(this->ctx); + free(this); +} + +/** + * Implementation of backend_t.create_section_enumerator. + */ +static enumerator_t* create_section_enumerator(private_uci_parser_t *this, ...) +{ + section_enumerator_t *e; + va_list args; + int i; + + /* allocate enumerator large enought to hold keyword pointers */ + i = 1; + va_start(args, this); + while (va_arg(args, char*)) + { + i++; + } + va_end(args); + e = malloc(sizeof(section_enumerator_t) + sizeof(char*) * i); + i = 0; + va_start(args, this); + do + { + e->keywords[i] = va_arg(args, char*); + } + while (e->keywords[i++]); + va_end(args); + + e->public.enumerate = (void*)section_enumerator_enumerate; + e->public.destroy = (void*)section_enumerator_destroy; + + /* load uci context */ + e->ctx = uci_alloc_context(); + if (uci_load(e->ctx, this->package, &e->package) != UCI_OK) + { + section_enumerator_destroy(e); + return NULL; + } + e->list = &e->package->sections; + e->current = list_to_element(e->list->next); + if (e->current->type != UCI_TYPE_SECTION) + { + section_enumerator_destroy(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of uci_parser_t.destroy. + */ +static void destroy(private_uci_parser_t *this) +{ + free(this->package); + free(this); +} + +/** + * Described in header. + */ +uci_parser_t *uci_parser_create(char *package) +{ + private_uci_parser_t *this = malloc_thing(private_uci_parser_t); + + this->public.create_section_enumerator = (enumerator_t*(*)(uci_parser_t*, ...))create_section_enumerator; + this->public.destroy = (void(*)(uci_parser_t*))destroy; + + this->package = strdup(package); + + return &this->public; +} + diff --git a/src/charon/plugins/uci/uci_parser.h b/src/charon/plugins/uci/uci_parser.h new file mode 100644 index 000000000..a8633ca2e --- /dev/null +++ b/src/charon/plugins/uci/uci_parser.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Thomas Kallenberg + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup uci_parser_t uci_parser + * @{ @ingroup uci + */ + +#ifndef UCI_PARSER_H_ +#define UCI_PARSER_H_ + +#include <utils/enumerator.h> + +typedef struct uci_parser_t uci_parser_t; + +/** + * Wrapper to parse UCI sections with an enumerator. + */ +struct uci_parser_t { + + /** + * Create an enumerator over a section. + * + * The enumerator returns a section name followed by values for the keywords + * specified in the variable argument list of this function. + * + * @param ... variable argument list with keywords, NULL terminated + * @return enumerator over sections + */ + enumerator_t* (*create_section_enumerator)(uci_parser_t *this, ...); + + /** + * Destroy the parser. + */ + void (*destroy)(uci_parser_t *this); +}; + +/** + * Create a UCI parser. + * + * @param package UCI package this parser should read + * @return parser context + */ +uci_parser_t *uci_parser_create(char *package); + +#endif /* UCI_PARSER_H_ @}*/ + diff --git a/src/charon/plugins/uci/uci_plugin.c b/src/charon/plugins/uci/uci_plugin.c new file mode 100644 index 000000000..918523826 --- /dev/null +++ b/src/charon/plugins/uci/uci_plugin.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 Thomas Kallenberg + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "uci_plugin.h" +#include "uci_config.h" +#include "uci_creds.h" + +#include <daemon.h> + +/** + * UCI package name to use for lookups + */ +#define UCI_PACKAGE "strongswan" + +typedef struct private_uci_plugin_t private_uci_plugin_t; + +/** + * private data of uci plugin + */ +struct private_uci_plugin_t { + + /** + * implements plugin interface + */ + uci_plugin_t public; + + /** + * UCI configuration backend + */ + uci_config_t *config; + + /** + * UCI credential set implementation + */ + uci_creds_t *creds; + + /** + * UCI parser wrapper + */ + uci_parser_t *parser; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_uci_plugin_t *this) +{ + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->credentials->remove_set(charon->credentials, &this->creds->credential_set); + this->config->destroy(this->config); + this->creds->destroy(this->creds); + this->parser->destroy(this->parser); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_uci_plugin_t *this = malloc_thing(private_uci_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + this->parser = uci_parser_create(UCI_PACKAGE); + this->config = uci_config_create(this->parser); + this->creds = uci_creds_create(this->parser); + charon->backends->add_backend(charon->backends, &this->config->backend); + charon->credentials->add_set(charon->credentials, &this->creds->credential_set); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/uci/uci_plugin.h b/src/charon/plugins/uci/uci_plugin.h new file mode 100644 index 000000000..cac95dc13 --- /dev/null +++ b/src/charon/plugins/uci/uci_plugin.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Thomas Kallenberg + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup uci uci + * @ingroup cplugins + * + * @defgroup uci_plugin uci_plugin + * @{ @ingroup uci + */ + +#ifndef UCI_PLUGIN_H_ +#define UCI_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct uci_plugin_t uci_plugin_t; + +/** + * OpenWRT UCI (Unified Configuration Interface) configuration plugin. + */ +struct uci_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a uci_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* UCI_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/unit_tester/Makefile.am b/src/charon/plugins/unit_tester/Makefile.am new file mode 100644 index 000000000..2487cf207 --- /dev/null +++ b/src/charon/plugins/unit_tester/Makefile.am @@ -0,0 +1,21 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-unit-tester.la + +libstrongswan_unit_tester_la_SOURCES = unit_tester.c unit_tester.h \ + tests/test_enumerator.c \ + tests/test_auth_info.c \ + tests/test_fips_prf.c \ + tests/test_curl.c \ + tests/test_mysql.c \ + tests/test_sqlite.c \ + tests/test_mutex.c \ + tests/test_rsa_gen.c \ + tests/test_med_db.c \ + tests/test_aes.c \ + tests/test_chunk.c +libstrongswan_unit_tester_la_LDFLAGS = -module + diff --git a/src/charon/plugins/unit_tester/Makefile.in b/src/charon/plugins/unit_tester/Makefile.in new file mode 100644 index 000000000..fe5dfa6cf --- /dev/null +++ b/src/charon/plugins/unit_tester/Makefile.in @@ -0,0 +1,598 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon/plugins/unit_tester +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +libstrongswan_unit_tester_la_LIBADD = +am_libstrongswan_unit_tester_la_OBJECTS = unit_tester.lo \ + test_enumerator.lo test_auth_info.lo test_fips_prf.lo \ + test_curl.lo test_mysql.lo test_sqlite.lo test_mutex.lo \ + test_rsa_gen.lo test_med_db.lo test_aes.lo test_chunk.lo +libstrongswan_unit_tester_la_OBJECTS = \ + $(am_libstrongswan_unit_tester_la_OBJECTS) +libstrongswan_unit_tester_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_unit_tester_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_unit_tester_la_SOURCES) +DIST_SOURCES = $(libstrongswan_unit_tester_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +resolv_conf = @resolv_conf@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +simreader = @simreader@ +srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic +plugin_LTLIBRARIES = libstrongswan-unit-tester.la +libstrongswan_unit_tester_la_SOURCES = unit_tester.c unit_tester.h \ + tests/test_enumerator.c \ + tests/test_auth_info.c \ + tests/test_fips_prf.c \ + tests/test_curl.c \ + tests/test_mysql.c \ + tests/test_sqlite.c \ + tests/test_mutex.c \ + tests/test_rsa_gen.c \ + tests/test_med_db.c \ + tests/test_aes.c \ + tests/test_chunk.c + +libstrongswan_unit_tester_la_LDFLAGS = -module +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/plugins/unit_tester/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon/plugins/unit_tester/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-unit-tester.la: $(libstrongswan_unit_tester_la_OBJECTS) $(libstrongswan_unit_tester_la_DEPENDENCIES) + $(libstrongswan_unit_tester_la_LINK) -rpath $(plugindir) $(libstrongswan_unit_tester_la_OBJECTS) $(libstrongswan_unit_tester_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_auth_info.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chunk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_curl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_enumerator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fips_prf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_med_db.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mysql.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_rsa_gen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_sqlite.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit_tester.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +test_enumerator.lo: tests/test_enumerator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_enumerator.lo -MD -MP -MF $(DEPDIR)/test_enumerator.Tpo -c -o test_enumerator.lo `test -f 'tests/test_enumerator.c' || echo '$(srcdir)/'`tests/test_enumerator.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_enumerator.Tpo $(DEPDIR)/test_enumerator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_enumerator.c' object='test_enumerator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_enumerator.lo `test -f 'tests/test_enumerator.c' || echo '$(srcdir)/'`tests/test_enumerator.c + +test_auth_info.lo: tests/test_auth_info.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_auth_info.lo -MD -MP -MF $(DEPDIR)/test_auth_info.Tpo -c -o test_auth_info.lo `test -f 'tests/test_auth_info.c' || echo '$(srcdir)/'`tests/test_auth_info.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_auth_info.Tpo $(DEPDIR)/test_auth_info.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_auth_info.c' object='test_auth_info.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_auth_info.lo `test -f 'tests/test_auth_info.c' || echo '$(srcdir)/'`tests/test_auth_info.c + +test_fips_prf.lo: tests/test_fips_prf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_fips_prf.lo -MD -MP -MF $(DEPDIR)/test_fips_prf.Tpo -c -o test_fips_prf.lo `test -f 'tests/test_fips_prf.c' || echo '$(srcdir)/'`tests/test_fips_prf.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_fips_prf.Tpo $(DEPDIR)/test_fips_prf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_fips_prf.c' object='test_fips_prf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_fips_prf.lo `test -f 'tests/test_fips_prf.c' || echo '$(srcdir)/'`tests/test_fips_prf.c + +test_curl.lo: tests/test_curl.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_curl.lo -MD -MP -MF $(DEPDIR)/test_curl.Tpo -c -o test_curl.lo `test -f 'tests/test_curl.c' || echo '$(srcdir)/'`tests/test_curl.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_curl.Tpo $(DEPDIR)/test_curl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_curl.c' object='test_curl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_curl.lo `test -f 'tests/test_curl.c' || echo '$(srcdir)/'`tests/test_curl.c + +test_mysql.lo: tests/test_mysql.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_mysql.lo -MD -MP -MF $(DEPDIR)/test_mysql.Tpo -c -o test_mysql.lo `test -f 'tests/test_mysql.c' || echo '$(srcdir)/'`tests/test_mysql.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_mysql.Tpo $(DEPDIR)/test_mysql.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_mysql.c' object='test_mysql.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_mysql.lo `test -f 'tests/test_mysql.c' || echo '$(srcdir)/'`tests/test_mysql.c + +test_sqlite.lo: tests/test_sqlite.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_sqlite.lo -MD -MP -MF $(DEPDIR)/test_sqlite.Tpo -c -o test_sqlite.lo `test -f 'tests/test_sqlite.c' || echo '$(srcdir)/'`tests/test_sqlite.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_sqlite.Tpo $(DEPDIR)/test_sqlite.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_sqlite.c' object='test_sqlite.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_sqlite.lo `test -f 'tests/test_sqlite.c' || echo '$(srcdir)/'`tests/test_sqlite.c + +test_mutex.lo: tests/test_mutex.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_mutex.lo -MD -MP -MF $(DEPDIR)/test_mutex.Tpo -c -o test_mutex.lo `test -f 'tests/test_mutex.c' || echo '$(srcdir)/'`tests/test_mutex.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_mutex.Tpo $(DEPDIR)/test_mutex.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_mutex.c' object='test_mutex.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_mutex.lo `test -f 'tests/test_mutex.c' || echo '$(srcdir)/'`tests/test_mutex.c + +test_rsa_gen.lo: tests/test_rsa_gen.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_rsa_gen.lo -MD -MP -MF $(DEPDIR)/test_rsa_gen.Tpo -c -o test_rsa_gen.lo `test -f 'tests/test_rsa_gen.c' || echo '$(srcdir)/'`tests/test_rsa_gen.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_rsa_gen.Tpo $(DEPDIR)/test_rsa_gen.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_rsa_gen.c' object='test_rsa_gen.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_rsa_gen.lo `test -f 'tests/test_rsa_gen.c' || echo '$(srcdir)/'`tests/test_rsa_gen.c + +test_med_db.lo: tests/test_med_db.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_med_db.lo -MD -MP -MF $(DEPDIR)/test_med_db.Tpo -c -o test_med_db.lo `test -f 'tests/test_med_db.c' || echo '$(srcdir)/'`tests/test_med_db.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_med_db.Tpo $(DEPDIR)/test_med_db.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_med_db.c' object='test_med_db.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_med_db.lo `test -f 'tests/test_med_db.c' || echo '$(srcdir)/'`tests/test_med_db.c + +test_aes.lo: tests/test_aes.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_aes.lo -MD -MP -MF $(DEPDIR)/test_aes.Tpo -c -o test_aes.lo `test -f 'tests/test_aes.c' || echo '$(srcdir)/'`tests/test_aes.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_aes.Tpo $(DEPDIR)/test_aes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_aes.c' object='test_aes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_aes.lo `test -f 'tests/test_aes.c' || echo '$(srcdir)/'`tests/test_aes.c + +test_chunk.lo: tests/test_chunk.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_chunk.lo -MD -MP -MF $(DEPDIR)/test_chunk.Tpo -c -o test_chunk.lo `test -f 'tests/test_chunk.c' || echo '$(srcdir)/'`tests/test_chunk.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/test_chunk.Tpo $(DEPDIR)/test_chunk.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_chunk.c' object='test_chunk.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_chunk.lo `test -f 'tests/test_chunk.c' || echo '$(srcdir)/'`tests/test_chunk.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-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 +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon/plugins/unit_tester/tests/test_aes.c b/src/charon/plugins/unit_tester/tests/test_aes.c new file mode 100644 index 000000000..06e891d83 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_aes.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <daemon.h> +#include <library.h> +#include <utils/mutex.h> + +#include <unistd.h> +#include <sched.h> +#include <pthread.h> + +/** + * run a test using given values + */ +static bool do_aes_test(u_char *key, int keysize, u_char *iv, + u_char *plain, u_char *cipher, int len) +{ + crypter_t *crypter; + chunk_t enc, dec; + bool good = TRUE; + + crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, keysize); + if (!crypter) + { + return FALSE; + } + crypter->set_key(crypter, chunk_create(key, keysize)); + crypter->encrypt(crypter, + chunk_create(plain, len), chunk_create(iv, 16), &enc); + if (!memeq(enc.ptr, cipher, len)) + { + good = FALSE; + } + crypter->decrypt(crypter, enc, chunk_create(iv, 16), &dec); + if (!memeq(dec.ptr, plain, len)) + { + good = FALSE; + } + free(enc.ptr); + free(dec.ptr); + crypter->destroy(crypter); + return good; +} + +/******************************************************************************* + * AES-128 test + ******************************************************************************/ +bool test_aes128() +{ + /* + * Test 1 of RFC3602 + * Key : 0x06a9214036b8a15b512e03d534120006 + * IV : 0x3dafba429d9eb430b422da802c9fac41 + * Plaintext : "Single block msg" + * Ciphertext: 0xe353779c1079aeb82708942dbe77181a + */ + u_char key1[] = { + 0x06,0xa9,0x21,0x40,0x36,0xb8,0xa1,0x5b, + 0x51,0x2e,0x03,0xd5,0x34,0x12,0x00,0x06 + }; + u_char iv1[] = { + 0x3d,0xaf,0xba,0x42,0x9d,0x9e,0xb4,0x30, + 0xb4,0x22,0xda,0x80,0x2c,0x9f,0xac,0x41 + }; + u_char plain1[] = { + 'S','i','n','g','l','e',' ','b','l','o','c','k',' ','m','s','g' + }; + u_char cipher1[] = { + 0xe3,0x53,0x77,0x9c,0x10,0x79,0xae,0xb8, + 0x27,0x08,0x94,0x2d,0xbe,0x77,0x18,0x1a + }; + if (!do_aes_test(key1, 16, iv1, plain1, cipher1, sizeof(plain1))) + { + return FALSE; + } + + /* + * Test 2 of RFC3602 + * Key : 0xc286696d887c9aa0611bbb3e2025a45a + * IV : 0x562e17996d093d28ddb3ba695a2e6f58 + * Plaintext : 0x000102030405060708090a0b0c0d0e0f + * 101112131415161718191a1b1c1d1e1f + * Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a + * 7586602d253cfff91b8266bea6d61ab1 + */ + u_char key2[] = { + 0xc2,0x86,0x69,0x6d,0x88,0x7c,0x9a,0xa0, + 0x61,0x1b,0xbb,0x3e,0x20,0x25,0xa4,0x5a + }; + u_char iv2[] = { + 0x56,0x2e,0x17,0x99,0x6d,0x09,0x3d,0x28, + 0xdd,0xb3,0xba,0x69,0x5a,0x2e,0x6f,0x58 + }; + u_char plain2[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + u_char cipher2[] = { + 0xd2,0x96,0xcd,0x94,0xc2,0xcc,0xcf,0x8a, + 0x3a,0x86,0x30,0x28,0xb5,0xe1,0xdc,0x0a, + 0x75,0x86,0x60,0x2d,0x25,0x3c,0xff,0xf9, + 0x1b,0x82,0x66,0xbe,0xa6,0xd6,0x1a,0xb1 + }; + if (!do_aes_test(key2, 16, iv2, plain2, cipher2, sizeof(plain2))) + { + return FALSE; + } + + /* + * Test 3 of RFC3603 + * Key : 0x56e47a38c5598974bc46903dba290349 + * IV : 0x8ce82eefbea0da3c44699ed7db51b7d9 + * Plaintext : 0xa0a1a2a3a4a5a6a7a8a9aaabacadaeaf + * b0b1b2b3b4b5b6b7b8b9babbbcbdbebf + * c0c1c2c3c4c5c6c7c8c9cacbcccdcecf + * d0d1d2d3d4d5d6d7d8d9dadbdcdddedf + * Ciphertext: 0xc30e32ffedc0774e6aff6af0869f71aa + * 0f3af07a9a31a9c684db207eb0ef8e4e + * 35907aa632c3ffdf868bb7b29d3d46ad + * 83ce9f9a102ee99d49a53e87f4c3da55 + */ + u_char key3[] = { + 0x56,0xe4,0x7a,0x38,0xc5,0x59,0x89,0x74, + 0xbc,0x46,0x90,0x3d,0xba,0x29,0x03,0x49 + }; + u_char iv3[] = { + 0x8c,0xe8,0x2e,0xef,0xbe,0xa0,0xda,0x3c, + 0x44,0x69,0x9e,0xd7,0xdb,0x51,0xb7,0xd9 + }; + u_char plain3[] = { + 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, + 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7, + 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, + 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7, + 0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf + }; + u_char cipher3[] = { + 0xc3,0x0e,0x32,0xff,0xed,0xc0,0x77,0x4e, + 0x6a,0xff,0x6a,0xf0,0x86,0x9f,0x71,0xaa, + 0x0f,0x3a,0xf0,0x7a,0x9a,0x31,0xa9,0xc6, + 0x84,0xdb,0x20,0x7e,0xb0,0xef,0x8e,0x4e, + 0x35,0x90,0x7a,0xa6,0x32,0xc3,0xff,0xdf, + 0x86,0x8b,0xb7,0xb2,0x9d,0x3d,0x46,0xad, + 0x83,0xce,0x9f,0x9a,0x10,0x2e,0xe9,0x9d, + 0x49,0xa5,0x3e,0x87,0xf4,0xc3,0xda,0x55 + }; + if (!do_aes_test(key3, 16, iv3, plain3, cipher3, sizeof(plain3))) + { + return FALSE; + } + return TRUE; +} + +/** + * run a single xcbc test for prf and signer + */ +static bool do_xcbc_test(u_int8_t *key, size_t keylen, u_int8_t *mac, + u_int8_t *plain, size_t len) +{ + signer_t *signer; + prf_t *prf; + u_int8_t res[16]; + + prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_XCBC); + if (!prf) + { + return FALSE; + } + prf->set_key(prf, chunk_create(key, keylen)); + prf->get_bytes(prf, chunk_create(plain, len), res); + if (!memeq(res, mac, 16)) + { + DBG1(DBG_CFG, "expected %b\ngot %b", mac, 16, res, 16); + prf->destroy(prf); + return FALSE; + } + prf->destroy(prf); + + signer = lib->crypto->create_signer(lib->crypto, AUTH_AES_XCBC_96); + if (!signer) + { + return FALSE; + } + signer->set_key(signer, chunk_create(key, keylen)); + if (!signer->verify_signature(signer, chunk_create(plain, len), + chunk_create(mac, 12))) + { + return FALSE; + } + signer->destroy(signer); + return TRUE; +} + + +/******************************************************************************* + * AES_XCBC mac test + ******************************************************************************/ +bool test_aes_xcbc() +{ + /* Vectors from RFC 3566 */ + + /* Test Case #1 : AES-XCBC-MAC-96 with 0-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : <empty string> + * AES-XCBC-MAC : 75f0251d528ac01c4573dfd584d79f29 + * AES-XCBC-MAC-96: 75f0251d528ac01c4573dfd5 + */ + u_char key1[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain1[] = { + }; + u_char mac1[] = { + 0x75,0xf0,0x25,0x1d,0x52,0x8a,0xc0,0x1c, + 0x45,0x73,0xdf,0xd5,0x84,0xd7,0x9f,0x29 + }; + if (!do_xcbc_test(key1, 16, mac1, plain1, sizeof(plain1))) + { + return FALSE; + } + + /* + * Test Case #2 : AES-XCBC-MAC-96 with 3-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102 + * AES-XCBC-MAC : 5b376580ae2f19afe7219ceef172756f + * AES-XCBC-MAC-96: 5b376580ae2f19afe7219cee + */ + u_char key2[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain2[] = { + 0x00,0x01,0x02 + }; + u_char mac2[] = { + 0x5b,0x37,0x65,0x80,0xae,0x2f,0x19,0xaf, + 0xe7,0x21,0x9c,0xee,0xf1,0x72,0x75,0x6f + }; + if (!do_xcbc_test(key2, 16, mac2, plain2, sizeof(plain2))) + { + return FALSE; + } + + /* Test Case #3 : AES-XCBC-MAC-96 with 16-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102030405060708090a0b0c0d0e0f + * AES-XCBC-MAC : d2a246fa349b68a79998a4394ff7a263 + * AES-XCBC-MAC-96: d2a246fa349b68a79998a439 + */ + u_char key3[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain3[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char mac3[] = { + 0xd2,0xa2,0x46,0xfa,0x34,0x9b,0x68,0xa7, + 0x99,0x98,0xa4,0x39,0x4f,0xf7,0xa2,0x63 + }; + if (!do_xcbc_test(key3, 16, mac3, plain3, sizeof(plain3))) + { + return FALSE; + } + + /* Test Case #4 : AES-XCBC-MAC-96 with 20-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102030405060708090a0b0c0d0e0f10111213 + * AES-XCBC-MAC : 47f51b4564966215b8985c63055ed308 + * AES-XCBC-MAC-96: 47f51b4564966215b8985c63 + */ + u_char key4[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain4[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13 + }; + u_char mac4[] = { + 0x47,0xf5,0x1b,0x45,0x64,0x96,0x62,0x15, + 0xb8,0x98,0x5c,0x63,0x05,0x5e,0xd3,0x08 + }; + if (!do_xcbc_test(key4, 16, mac4, plain4, sizeof(plain4))) + { + return FALSE; + } + + /* Test Case #5 : AES-XCBC-MAC-96 with 32-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102030405060708090a0b0c0d0e0f10111213141516171819 + * 1a1b1c1d1e1f + * AES-XCBC-MAC : f54f0ec8d2b9f3d36807734bd5283fd4 + * AES-XCBC-MAC-96: f54f0ec8d2b9f3d36807734b + */ + u_char key5[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain5[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + u_char mac5[] = { + 0xf5,0x4f,0x0e,0xc8,0xd2,0xb9,0xf3,0xd3, + 0x68,0x07,0x73,0x4b,0xd5,0x28,0x3f,0xd4 + }; + if (!do_xcbc_test(key5, 16, mac5, plain5, sizeof(plain5))) + { + return FALSE; + } + + /* Test Case #7 : AES-XCBC-MAC-96 with 1000-byte input + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 00000000000000000000 ... 00000000000000000000 + * [1000 bytes] + * AES-XCBC-MAC : f0dafee895db30253761103b5d84528f + * AES-XCBC-MAC-96: f0dafee895db30253761103b + */ + u_char key7[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain7[1000]; + memset(plain7, 0, 1000); + u_char mac7[] = { + 0xf0,0xda,0xfe,0xe8,0x95,0xdb,0x30,0x25, + 0x37,0x61,0x10,0x3b,0x5d,0x84,0x52,0x8f + }; + if (!do_xcbc_test(key7, 16, mac7, plain7, sizeof(plain7))) + { + return FALSE; + } + + /* variable key test, RFC4434 */ + + /* Test Case AES-XCBC-PRF-128 with 20-byte input + * Key : 00010203040506070809 + * Message : 000102030405060708090a0b0c0d0e0f10111213 + * PRF Output : 0fa087af7d866e7653434e602fdde835 + */ + u_char key8[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09, + }; + u_char plain8[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13 + }; + u_char mac8[] = { + 0x0f,0xa0,0x87,0xaf,0x7d,0x86,0x6e,0x76, + 0x53,0x43,0x4e,0x60,0x2f,0xdd,0xe8,0x35 + }; + if (!do_xcbc_test(key8, 10, mac8, plain8, sizeof(plain8))) + { + return FALSE; + } + + /* Test Case AES-XCBC-PRF-128 with 20-byte input + * Key : 000102030405060708090a0b0c0d0e0fedcb + * Message : 000102030405060708090a0b0c0d0e0f10111213 + * PRF Output : 8cd3c93ae598a9803006ffb67c40e9e4 + */ + u_char key9[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0xed,0xcb + }; + u_char plain9[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13 + }; + u_char mac9[] = { + 0x8c,0xd3,0xc9,0x3a,0xe5,0x98,0xa9,0x80, + 0x30,0x06,0xff,0xb6,0x7c,0x40,0xe9,0xe4 + }; + if (!do_xcbc_test(key9, 18, mac9, plain9, sizeof(plain9))) + { + return FALSE; + } + + + /* Test Case #10 : AES-XCBC-MAC-96 with 32-byte input using append mode + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102030405060708090a0b0c0d0e0f10111213141516171819 + * 1a1b1c1d1e1f + * AES-XCBC-MAC : f54f0ec8d2b9f3d36807734bd5283fd4 + * AES-XCBC-MAC-96: f54f0ec8d2b9f3d36807734b + */ + u_char key10[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain10[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + u_char mac10[] = { + 0xf5,0x4f,0x0e,0xc8,0xd2,0xb9,0xf3,0xd3, + 0x68,0x07,0x73,0x4b,0xd5,0x28,0x3f,0xd4 + }; + int i; + prf_t *prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_XCBC); + u_char res[16]; + if (!prf) + { + return FALSE; + } + prf->set_key(prf, chunk_create(key10, sizeof(key10))); + for (i = 0; i < 4; i++) + { /* bytes 0 - 3, 1 byte at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 1), NULL); + } + for (i = 4; i < 5; i+=8) + { /* bytes 4 - 11, at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 8), NULL); + } + for (i = 12; i < 24; i+=4) + { /* bytes 12 - 23, in blocks of 4 */ + prf->get_bytes(prf, chunk_create(plain10 + i, 4), NULL); + } + for (i = 0; i < 4; i++) + { /* 4 zero blobs */ + prf->get_bytes(prf, chunk_create(NULL, 0), NULL); + } + for (i = 24; i < 25; i+=8) + { /* bytes 24 - 32, at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 8), res); + } + if (!memeq(res, mac10, 16)) + { + DBG1(DBG_CFG, "expected %b\ngot %b", mac10, 16, res, 16); + prf->destroy(prf); + return FALSE; + } + prf->destroy(prf); + + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_auth_info.c b/src/charon/plugins/unit_tester/tests/test_auth_info.c new file mode 100644 index 000000000..2640c951c --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_auth_info.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <daemon.h> +#include <library.h> +#include <credentials/auth_info.h> + + +char buf[] = {0x01,0x02,0x03,0x04}; +chunk_t chunk = chunk_from_buf(buf); +char certbuf[] = { + 0x30,0x82,0x02,0xfa,0x30,0x82,0x01,0xe2,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x5a, + 0xf2,0x65,0xae,0x78,0xff,0x23,0xde,0xf7,0xa6,0xa3,0x94,0x8c,0x3f,0xa0,0xc1,0x30, + 0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x39, + 0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x19,0x30, + 0x17,0x06,0x03,0x55,0x04,0x0a,0x13,0x10,0x4c,0x69,0x6e,0x75,0x78,0x20,0x73,0x74, + 0x72,0x6f,0x6e,0x67,0x53,0x77,0x61,0x6e,0x31,0x0f,0x30,0x0d,0x06,0x03,0x55,0x04, + 0x03,0x13,0x06,0x6d,0x61,0x72,0x74,0x69,0x6e,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30, + 0x34,0x32,0x37,0x30,0x37,0x31,0x34,0x32,0x36,0x5a,0x17,0x0d,0x31,0x32,0x30,0x34, + 0x32,0x35,0x30,0x37,0x31,0x34,0x32,0x36,0x5a,0x30,0x39,0x31,0x0b,0x30,0x09,0x06, + 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, + 0x0a,0x13,0x10,0x4c,0x69,0x6e,0x75,0x78,0x20,0x73,0x74,0x72,0x6f,0x6e,0x67,0x53, + 0x77,0x61,0x6e,0x31,0x0f,0x30,0x0d,0x06,0x03,0x55,0x04,0x03,0x13,0x06,0x6d,0x61, + 0x72,0x74,0x69,0x6e,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, + 0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a, + 0x02,0x82,0x01,0x01,0x00,0xd7,0xb9,0xba,0x4d,0xe2,0x3b,0x3d,0x35,0x7a,0x3f,0x88, + 0x67,0x95,0xe7,0xfd,0x9f,0xe9,0x0a,0x0d,0x79,0x3a,0x9e,0x21,0x8f,0xcb,0xe4,0x67, + 0x24,0xae,0x0c,0xda,0xb3,0xcc,0xec,0x36,0xb4,0xa8,0x4d,0xf1,0x3d,0xad,0xe4,0x8c, + 0x63,0x92,0x54,0xb7,0xb2,0x02,0xa2,0x00,0x62,0x8b,0x04,0xac,0xa0,0x17,0xad,0x17, + 0x9a,0x05,0x0d,0xd7,0xb3,0x08,0x02,0xc5,0x26,0xcf,0xdd,0x05,0x42,0xfc,0x13,0x6d, + 0x9f,0xb1,0xf3,0x4f,0x82,0x1d,0xef,0x01,0xc9,0x91,0xea,0x37,0x1b,0x79,0x28,0xfa, + 0xbf,0x9f,0xb3,0xeb,0x82,0x4f,0x10,0xc6,0x4b,0xa4,0x08,0xf7,0x8e,0xf2,0x00,0xea, + 0x04,0x97,0x80,0x9f,0x65,0x86,0xde,0x6b,0xc7,0xda,0x83,0xfc,0xad,0x4a,0xaf,0x52, + 0x8b,0x4d,0x33,0xee,0x49,0x87,0x2f,0x3b,0x60,0x45,0x66,0x8f,0xe6,0x89,0xcc,0xb1, + 0x92,0x02,0x17,0x2b,0x7b,0x8e,0x90,0x47,0x84,0x84,0x59,0x95,0x81,0xd8,0xe0,0xf3, + 0x87,0xe0,0x04,0x09,0xfd,0xcc,0x3a,0x21,0x34,0xfa,0xec,0xbe,0xf5,0x9c,0xcf,0x55, + 0x80,0x7b,0xe3,0x75,0x9d,0x36,0x68,0xab,0x83,0xe3,0xad,0x01,0x53,0x0d,0x8a,0x9a, + 0xa6,0xb0,0x15,0xc9,0xc5,0xf8,0x9b,0x51,0x32,0xcf,0x97,0x6c,0xfe,0x4a,0x56,0x3c, + 0xc8,0x8f,0x4a,0x70,0x23,0x4f,0xf6,0xf7,0xe6,0x9f,0x09,0xcd,0x8f,0xea,0x20,0x7d, + 0x34,0xc0,0xc5,0xc0,0x34,0x06,0x6f,0x8b,0xeb,0x04,0x54,0x3f,0x0e,0xcd,0xe2,0x85, + 0xab,0x94,0x3e,0x91,0x6c,0x18,0x6f,0x96,0x5d,0xf2,0x8b,0x10,0xe9,0x90,0x43,0xb0, + 0x61,0x52,0xac,0xcf,0x75,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86, + 0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x09,0x63, + 0x42,0xad,0xe5,0xa3,0xf6,0xc9,0x5d,0x08,0xf2,0x78,0x7b,0xeb,0x8a,0xef,0x50,0x00, + 0xc8,0xeb,0xe9,0x26,0x94,0xcb,0x84,0x10,0x7e,0x42,0x6b,0x86,0x38,0x57,0xa6,0x02, + 0x98,0x5a,0x2c,0x8f,0x44,0x32,0x1b,0x97,0x8c,0x7e,0x4b,0xd8,0xe8,0xe8,0x0f,0x4a, + 0xb9,0x31,0x9f,0xf6,0x9f,0x0e,0x67,0x26,0x05,0x2a,0x99,0x14,0x35,0x41,0x47,0x9a, + 0xfa,0x12,0x94,0x0b,0xe9,0x27,0x7c,0x71,0x20,0xd7,0x8d,0x3b,0x97,0x19,0x2d,0x15, + 0xff,0xa4,0xf3,0x89,0x8d,0x29,0x5f,0xf6,0x3f,0x93,0xaf,0x78,0x61,0xe4,0xe1,0x2e, + 0x75,0xc1,0x2c,0xc4,0x76,0x95,0x19,0xf8,0x37,0xdc,0xd8,0x00,0x7a,0x3c,0x0f,0x49, + 0x2e,0x88,0x09,0x16,0xb3,0x92,0x33,0xdf,0x77,0x83,0x4f,0xb5,0x9e,0x30,0x8c,0x48, + 0x1d,0xd8,0x84,0xfb,0xf1,0xb9,0xa0,0xbe,0x25,0xff,0x4c,0xeb,0xef,0x2b,0xcd,0xfa, + 0x0b,0x94,0x66,0x3b,0x28,0x08,0x3f,0x3a,0xda,0x41,0xd0,0x6b,0xab,0x5e,0xbb,0x8a, + 0x9f,0xdc,0x98,0x3e,0x59,0x37,0x48,0xbe,0x69,0xde,0x85,0x82,0xf2,0x53,0x8b,0xe4, + 0x44,0xe4,0x71,0x91,0x14,0x85,0x0e,0x1e,0x79,0xdd,0x62,0xf5,0xdc,0x25,0x89,0xab, + 0x50,0x5b,0xaa,0xae,0xe3,0x64,0x6a,0x23,0x34,0xd7,0x30,0xe2,0x2a,0xc8,0x81,0x0c, + 0xec,0xd2,0x31,0xc6,0x1e,0xb6,0xc0,0x57,0xd9,0xe1,0x14,0x06,0x9b,0xf8,0x51,0x69, + 0x47,0xf0,0x9c,0xcd,0x69,0xef,0x8e,0x5f,0x62,0xda,0x10,0xf7,0x3c,0x6d,0x0f,0x33, + 0xec,0x6f,0xfd,0x94,0x07,0x16,0x41,0x32,0x06,0xa4,0xe1,0x08,0x31,0x87, +}; +chunk_t certchunk = chunk_from_buf(certbuf); + +/******************************************************************************* + * auth info test + ******************************************************************************/ +bool test_auth_info() +{ + auth_info_t *auth = auth_info_create(), *auth2; + certificate_t *c1, *c2; + enumerator_t *enumerator; + int round = 0; + void *value; + auth_item_t type; + + c1 = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk_clone(certchunk), + BUILD_END); + if (!c1) + { + return FALSE; + } + + auth->add_item(auth, AUTHN_SUBJECT_CERT, c1); + if (!auth->get_item(auth, AUTHN_SUBJECT_CERT, (void**)&c2)) + { + return FALSE; + } + if (!c1->equals(c1, c2)) + { + return FALSE; + } + + enumerator = auth->create_item_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + round++; + if (round == 1 && type == AUTHN_SUBJECT_CERT && value == c1) + { + continue; + } + return FALSE; + } + enumerator->destroy(enumerator); + + auth2 = auth_info_create(); + auth2->add_item(auth2, AUTHN_CA_CERT, c1); + auth2->merge(auth2, auth); + + round = 0; + enumerator = auth2->create_item_enumerator(auth2); + while (enumerator->enumerate(enumerator, &type, &value)) + { + round++; + if (round == 1 && type == AUTHN_CA_CERT && value == c1) + { + continue; + } + if (round == 2 && type == AUTHN_SUBJECT_CERT && value == c1) + { + continue; + } + return FALSE; + } + enumerator->destroy(enumerator); + auth->destroy(auth); + auth2->destroy(auth2); + c1->destroy(c1); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_chunk.c b/src/charon/plugins/unit_tester/tests/test_chunk.c new file mode 100644 index 000000000..e7a8586c9 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_chunk.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <daemon.h> + +#define countof(array) (sizeof(array)/sizeof(typeof(array[0]))) + +/******************************************************************************* + * Base64 encoding/decoding test + ******************************************************************************/ +bool test_chunk_base64() +{ + /* test vectors from RFC4648: + * + * BASE64("") = "" + * BASE64("f") = "Zg==" + * BASE64("fo") = "Zm8=" + * BASE64("foo") = "Zm9v" + * BASE64("foob") = "Zm9vYg==" + * BASE64("fooba") = "Zm9vYmE=" + * BASE64("foobar") = "Zm9vYmFy" + */ + + typedef struct { + char *in; + char *out; + } testdata_t; + + testdata_t test[] = { + {"", ""}, + {"f", "Zg=="}, + {"fo", "Zm8="}, + {"foo", "Zm9v"}, + {"foob", "Zm9vYg=="}, + {"fooba", "Zm9vYmE="}, + {"foobar", "Zm9vYmFy"}, + }; + int i; + + for (i = 0; i < countof(test); i++) + { + chunk_t out; + + out = chunk_to_base64(chunk_create(test[i].in, strlen(test[i].in)), NULL); + + if (!streq(out.ptr, test[i].out)) + { + DBG1(DBG_CFG, "base64 conversion error - should %s, is %s", + test[i].out, out.ptr); + return FALSE; + } + free(out.ptr); + } + + for (i = 0; i < countof(test); i++) + { + chunk_t out; + + out = chunk_from_base64(chunk_create(test[i].out, strlen(test[i].out)), NULL); + + if (!strneq(out.ptr, test[i].in, out.len)) + { + DBG1(DBG_CFG, "base64 conversion error - should %s, is %#B", + test[i].in, &out); + return FALSE; + } + free(out.ptr); + } + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_curl.c b/src/charon/plugins/unit_tester/tests/test_curl.c new file mode 100644 index 000000000..c011617a7 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_curl.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <daemon.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +/******************************************************************************* + * curl get test + ******************************************************************************/ + +bool test_curl_get() +{ + chunk_t chunk; + + if (lib->fetcher->fetch(lib->fetcher, "http://www.strongswan.org", + &chunk, FETCH_END) != SUCCESS) + { + return FALSE; + } + free(chunk.ptr); + + if (lib->fetcher->fetch(lib->fetcher, "http://www.google.com", + &chunk, FETCH_END) != SUCCESS) + { + return FALSE; + } + free(chunk.ptr); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_enumerator.c b/src/charon/plugins/unit_tester/tests/test_enumerator.c new file mode 100644 index 000000000..d17d62bef --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_enumerator.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <utils/linked_list.h> + + +/******************************************************************************* + * linked list remove test + ******************************************************************************/ +bool test_list_remove() +{ + void *a = (void*)1, *b = (void*)2; + linked_list_t *list; + + list = linked_list_create(); + list->insert_last(list, a); + if (list->remove(list, a, NULL) != 1) + { + return FALSE; + } + list->insert_last(list, a); + list->insert_first(list, a); + list->insert_last(list, a); + list->insert_last(list, b); + if (list->remove(list, a, NULL) != 3) + { + return FALSE; + } + if (list->remove(list, a, NULL) != 0) + { + return FALSE; + } + if (list->get_count(list) != 1) + { + return FALSE; + } + if (list->remove(list, b, NULL) != 1) + { + return FALSE; + } + if (list->remove(list, b, NULL) != 0) + { + return FALSE; + } + list->destroy(list); + return TRUE; +} + +/******************************************************************************* + * Simple insert first/last and enumerate test + ******************************************************************************/ +bool test_enumerate() +{ + int round, x; + void *a = (void*)4, *b = (void*)3, *c = (void*)2, *d = (void*)5, *e = (void*)1; + linked_list_t *list; + enumerator_t *enumerator; + + list = linked_list_create(); + + list->insert_last(list, a); + list->insert_first(list, b); + list->insert_first(list, c); + list->insert_last(list, d); + list->insert_first(list, e); + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + if (round != x) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + return TRUE; +} + +/******************************************************************************* + * nested enumerator test + ******************************************************************************/ + +static bool bad_data; + +static enumerator_t* create_inner(linked_list_t *outer, void *data) +{ + if (data != (void*)101) + { + bad_data = TRUE; + } + return outer->create_enumerator(outer); +} + + +static void destroy_data(void *data) +{ + if (data != (void*)101) + { + bad_data = TRUE; + } +} + +bool test_enumerate_nested() +{ + int round, x; + void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; + linked_list_t *list, *l1, *l2, *l3; + enumerator_t *enumerator; + + bad_data = FALSE; + list = linked_list_create(); + l1 = linked_list_create(); + l2 = linked_list_create(); + l3 = linked_list_create(); + list->insert_last(list, l1); + list->insert_last(list, l2); + list->insert_last(list, l3); + + l1->insert_last(l1, a); + l1->insert_last(l1, b); + l3->insert_last(l3, c); + l3->insert_last(l3, d); + l3->insert_last(l3, e); + + round = 1; + enumerator = enumerator_create_nested(list->create_enumerator(list), + (void*)create_inner, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &x)) + { + if (round != x) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + l1->destroy(l1); + l2->destroy(l2); + l3->destroy(l3); + return !bad_data; +} + + +/******************************************************************************* + * filtered enumerator test + ******************************************************************************/ +static bool filter(void *data, int *v, int *vo, int *w, int *wo, + int *x, int *xo, int *y, int *yo, int *z, int *zo) +{ + int val = *v; + + *vo = val++; + *wo = val++; + *xo = val++; + *yo = val++; + *zo = val++; + if (data != (void*)101) + { + return FALSE; + } + return TRUE; +} + +bool test_enumerate_filtered() +{ + int round, v, w, x, y, z; + void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; + linked_list_t *list; + enumerator_t *enumerator; + + bad_data = FALSE; + list = linked_list_create(); + + list->insert_last(list, a); + list->insert_last(list, b); + list->insert_last(list, c); + list->insert_last(list, d); + list->insert_last(list, e); + + round = 1; + enumerator = enumerator_create_filter(list->create_enumerator(list), + (void*)filter, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z)) + { + if (v != round || w != round + 1 || x != round + 2 || + y != round + 3 || z != round + 4) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + return !bad_data; +} diff --git a/src/charon/plugins/unit_tester/tests/test_fips_prf.c b/src/charon/plugins/unit_tester/tests/test_fips_prf.c new file mode 100644 index 000000000..29612143e --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_fips_prf.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <utils/linked_list.h> +#include <daemon.h> + +/******************************************************************************* + * fips prf known value test + ******************************************************************************/ +bool fips_prf_test() +{ + prf_t *prf; + u_int8_t key_buf[] = { + 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + 0xeb, 0x5a, 0x38, 0xb6 + }; + u_int8_t seed_buf[] = { + 0x00 + }; + u_int8_t result_buf[] = { + 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + }; + chunk_t key = chunk_from_buf(key_buf); + chunk_t seed = chunk_from_buf(seed_buf); + chunk_t expected = chunk_from_buf(result_buf); + chunk_t result; + + prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + if (prf == NULL) + { + DBG1(DBG_CFG, "FIPS PRF implementation not found"); + return FALSE; + } + prf->set_key(prf, key); + prf->allocate_bytes(prf, seed, &result); + prf->destroy(prf); + if (!chunk_equals(result, expected)) + { + DBG1(DBG_CFG, "FIPS PRF result invalid:\nexpected: %Bresult: %B", + &expected, &result); + chunk_free(&result); + return FALSE; + } + chunk_free(&result); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_med_db.c b/src/charon/plugins/unit_tester/tests/test_med_db.c new file mode 100644 index 000000000..d65eb0cc4 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_med_db.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <daemon.h> +#include <utils/enumerator.h> + +#include <unistd.h> + +/******************************************************************************* + * fetch public key from mediation database + ******************************************************************************/ + +bool test_med_db() +{ + char keyid_buf[] = { + 0xed,0x90,0xe6,0x4f,0xec,0xa2,0x1f,0x4b, + 0x68,0x97,0x99,0x24,0x22,0xe0,0xde,0x21, + 0xb9,0xd6,0x26,0x29 + }; + chunk_t keyid = chunk_from_buf(keyid_buf); + identification_t *id, *found; + enumerator_t *enumerator; + auth_info_t *auth; + public_key_t *public; + bool good = FALSE; + + id = identification_create_from_encoding(ID_KEY_ID, keyid); + enumerator = charon->credentials->create_public_enumerator( + charon->credentials, KEY_ANY, id, NULL); + while (enumerator->enumerate(enumerator, &public, &auth)) + { + found = public->get_id(public, ID_PUBKEY_SHA1); + good = chunk_equals(id->get_encoding(id), found->get_encoding(found)); + } + enumerator->destroy(enumerator); + id->destroy(id); + return good; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_mutex.c b/src/charon/plugins/unit_tester/tests/test_mutex.c new file mode 100644 index 000000000..a305d5082 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_mutex.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <utils/mutex.h> + +#include <unistd.h> +#include <sched.h> +#include <pthread.h> + + +static mutex_t *mutex; + +static int locked = 0; + +static bool failed = FALSE; + +static pthread_barrier_t barrier; + +static void* run(void* null) +{ + int i; + + /* wait for all threads before getting in action */ + pthread_barrier_wait(&barrier); + + for (i = 0; i < 100; i++) + { + mutex->lock(mutex); + mutex->lock(mutex); + mutex->lock(mutex); + locked++; + sched_yield(); + if (locked > 1) + { + failed = TRUE; + } + locked--; + mutex->unlock(mutex); + mutex->unlock(mutex); + mutex->unlock(mutex); + } + return NULL; +} + +#define THREADS 20 + +/******************************************************************************* + * mutex test + ******************************************************************************/ +bool test_mutex() +{ + int i; + pthread_t threads[THREADS]; + + mutex = mutex_create(MUTEX_RECURSIVE); + + for (i = 0; i < 10; i++) + { + mutex->lock(mutex); + mutex->unlock(mutex); + } + for (i = 0; i < 10; i++) + { + mutex->lock(mutex); + } + for (i = 0; i < 10; i++) + { + mutex->unlock(mutex); + } + + pthread_barrier_init(&barrier, NULL, THREADS); + + for (i = 0; i < THREADS; i++) + { + pthread_create(&threads[i], NULL, run, NULL); + } + for (i = 0; i < THREADS; i++) + { + pthread_join(threads[i], NULL); + } + pthread_barrier_destroy(&barrier); + + mutex->destroy(mutex); + + return !failed; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_mysql.c b/src/charon/plugins/unit_tester/tests/test_mysql.c new file mode 100644 index 000000000..ff3d38ad8 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_mysql.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <daemon.h> +#include <utils/enumerator.h> + +/******************************************************************************* + * mysql simple test + ******************************************************************************/ +bool test_mysql() +{ + database_t *db; + char *txt = "I'm a superduper test"; + char buf[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; + chunk_t data = chunk_from_buf(buf); + int row; + chunk_t qdata; + char *qtxt; + bool good = FALSE; + enumerator_t *enumerator; + + db = lib->db->create(lib->db, "mysql://testuser:testpass@localhost/test"); + if (!db) + { + return FALSE; + } + if (db->execute(db, NULL, "CREATE TABLE test (" + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, " + "txt TEXT, data BLOB)") < 0) + { + return FALSE; + } + if (db->execute(db, &row, "INSERT INTO test (txt, data) VALUES (?,?)", + DB_TEXT, txt, DB_BLOB, data) < 0) + { + return FALSE; + } + if (row != 1) + { + return FALSE; + } + enumerator = db->query(db, "SELECT txt, data FROM test WHERE id = ?", + DB_INT, row, + DB_TEXT, DB_BLOB); + if (!enumerator) + { + return FALSE; + } + while (enumerator->enumerate(enumerator, &qtxt, &qdata)) + { + if (good) + { /* only one row */ + good = FALSE; + break; + } + if (streq(qtxt, txt) && chunk_equals(data, qdata)) + { + good = TRUE; + } + } + enumerator->destroy(enumerator); + if (!good) + { + return FALSE; + } + if (db->execute(db, NULL, "DELETE FROM test WHERE id = ?", DB_INT, row) != 1) + { + return FALSE; + } + if (db->execute(db, NULL, "DROP TABLE test") < 0) + { + return FALSE; + } + db->destroy(db); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_rsa_gen.c b/src/charon/plugins/unit_tester/tests/test_rsa_gen.c new file mode 100644 index 000000000..783a4c913 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_rsa_gen.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <daemon.h> + +/******************************************************************************* + * RSA key generation and signature + ******************************************************************************/ +bool test_rsa_gen() +{ + char buf[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; + chunk_t data = chunk_from_buf(buf), sig; + private_key_t *private; + public_key_t *public; + u_int key_size; + + for (key_size = 512; key_size <= 2048; key_size *= 2) + { + private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_KEY_SIZE, key_size, BUILD_END); + if (!private) + { + DBG1(DBG_CFG, "generating %d bit RSA key failed"); + return FALSE; + } + public = private->get_public_key(private); + if (!public) + { + DBG1(DBG_CFG, "generating public from private key failed"); + return FALSE; + } + if (!private->sign(private, SIGN_RSA_EMSA_PKCS1_SHA1, data, &sig)) + { + DBG1(DBG_CFG, "creating RSA signature failed"); + return FALSE; + } + if (!public->verify(public, SIGN_RSA_EMSA_PKCS1_SHA1, data, sig)) + { + DBG1(DBG_CFG, "verifying RSA signature failed"); + return FALSE; + } + sig.ptr[sig.len-1]++; + if (public->verify(public, SIGN_RSA_EMSA_PKCS1_SHA1, data, sig)) + { + DBG1(DBG_CFG, "verifying faked RSA signature succeeded!"); + return FALSE; + } + free(sig.ptr); + public->destroy(public); + private->destroy(private); + } + return TRUE; +} + + +/******************************************************************************* + * Load a subjectPubkeyInfo wrapped key (RSA in this case) + ******************************************************************************/ +static char public_any[] = { + 0x30,0x82,0x01,0x20,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, + 0x01,0x05,0x00,0x03,0x82,0x01,0x0d,0x00,0x30,0x82,0x01,0x08,0x02,0x82,0x01,0x01, + 0x00,0xc6,0x68,0x99,0x1d,0xc8,0x06,0xdb,0xcf,0x1c,0x66,0xbb,0x91,0xc3,0xd4,0x10, + 0xb2,0x08,0xa9,0xc5,0x71,0x39,0x1c,0xbe,0x5b,0x1d,0xce,0xfd,0x1b,0xfa,0xec,0x04, + 0x89,0x9f,0x79,0xc8,0x46,0x00,0xd2,0x71,0xfb,0x22,0x16,0x52,0x2f,0xda,0xbf,0x0f, + 0xe7,0x16,0xb1,0xd7,0x6a,0xa5,0xa5,0xfc,0xee,0xff,0x84,0x4c,0x81,0x3f,0xab,0x84, + 0x0e,0xed,0x4a,0x26,0x59,0xd0,0x9b,0xb5,0xe1,0xec,0x61,0xc4,0xd3,0x15,0x4c,0x29, + 0x51,0xa0,0xde,0x33,0x07,0x58,0x6c,0x36,0x1b,0x18,0x61,0xd9,0x56,0x18,0x39,0x54, + 0x8b,0xd2,0xea,0x4e,0x87,0x28,0x58,0xb9,0x88,0x3d,0x30,0xbc,0xfc,0x6d,0xad,0xab, + 0x43,0x26,0x09,0x48,0x4e,0x6e,0x8a,0x8b,0x88,0xb3,0xf0,0x29,0x25,0x79,0xb6,0xb6, + 0x71,0x3c,0x93,0x59,0xd2,0x36,0x94,0xd5,0xfc,0xf3,0x62,0x2b,0x69,0xa3,0x7a,0x47, + 0x4e,0x53,0xa2,0x35,0x1b,0x26,0x89,0xaa,0x09,0xfd,0x56,0xd7,0x75,0x2a,0xd4,0x91, + 0xc0,0xf2,0x78,0xd7,0x05,0xca,0x12,0x1d,0xd9,0xd4,0x81,0x23,0xb2,0x3c,0x38,0xd9, + 0xb4,0xdc,0x21,0xe0,0xe5,0x2d,0xd4,0xbe,0x61,0x39,0x8a,0x46,0x90,0x46,0x73,0x31, + 0xba,0x48,0xbb,0x51,0xbb,0x91,0xd5,0x62,0xad,0xd1,0x53,0x5b,0x85,0xc9,0x1d,0xa7, + 0xf6,0xa0,0xe1,0x0e,0x6c,0x22,0x5d,0x29,0x9a,0xe7,0x0f,0xe8,0x0a,0x50,0xa7,0x19, + 0x11,0xc2,0x8b,0xe0,0x8a,0xfd,0x2b,0x94,0x31,0x7a,0x78,0x9c,0x9b,0x75,0x63,0x49, + 0xa9,0xe5,0x58,0xe6,0x3a,0x99,0xcb,0x2b,0xdd,0x0e,0xdc,0x7d,0x1b,0x98,0x80,0xc3, + 0x9f,0x02,0x01,0x23, +}; + +bool test_rsa_load_any() +{ + chunk_t chunk = chunk_from_buf(public_any); + public_key_t *public; + + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_BLOB_ASN1_DER, chunk_clone(chunk), + BUILD_END); + if (!public || public->get_keysize(public) != 256) + { + return FALSE; + } + public->destroy(public); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_sqlite.c b/src/charon/plugins/unit_tester/tests/test_sqlite.c new file mode 100644 index 000000000..d152fc594 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_sqlite.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> +#include <daemon.h> +#include <utils/enumerator.h> + +#include <unistd.h> + + +#define DBFILE "/tmp/strongswan-test.db" + +/******************************************************************************* + * sqlite simple test + ******************************************************************************/ +bool test_sqlite() +{ + database_t *db; + char *txt = "I'm a superduper test"; + char buf[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; + chunk_t data = chunk_from_buf(buf); + int row; + chunk_t qdata; + char *qtxt; + bool good = FALSE; + enumerator_t *enumerator; + + db = lib->db->create(lib->db, "sqlite://" DBFILE); + if (!db) + { + return FALSE; + } + if (db->execute(db, NULL, "CREATE TABLE test (txt TEXT, data BLOB)") < 0) + { + return FALSE; + } + if (db->execute(db, &row, "INSERT INTO test (txt, data) VALUES (?,?)", + DB_TEXT, txt, DB_BLOB, data) < 0) + { + return FALSE; + } + if (row != 1) + { + return FALSE; + } + enumerator = db->query(db, "SELECT txt, data FROM test WHERE oid = ?", + DB_INT, row, + DB_TEXT, DB_BLOB); + if (!enumerator) + { + return FALSE; + } + while (enumerator->enumerate(enumerator, &qtxt, &qdata)) + { + if (good) + { /* only one row */ + good = FALSE; + break; + } + if (streq(qtxt, txt) && chunk_equals(data, qdata)) + { + good = TRUE; + } + } + enumerator->destroy(enumerator); + if (!good) + { + return FALSE; + } + if (db->execute(db, NULL, "DELETE FROM test WHERE oid = ?", DB_INT, row) != 1) + { + return FALSE; + } + if (db->execute(db, NULL, "DROP TABLE test") < 0) + { + return FALSE; + } + db->destroy(db); + unlink(DBFILE); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/unit_tester.c b/src/charon/plugins/unit_tester/unit_tester.c new file mode 100644 index 000000000..28c6b4c11 --- /dev/null +++ b/src/charon/plugins/unit_tester/unit_tester.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: unit_tester.c 3491 2008-02-22 14:04:00Z martin $ + */ + +#include "unit_tester.h" + +#include <daemon.h> + +typedef struct private_unit_tester_t private_unit_tester_t; +typedef struct unit_test_t unit_test_t; +typedef enum test_status_t test_status_t; + +/** + * private data of unit_tester + */ +struct private_unit_tester_t { + + /** + * public functions + */ + unit_tester_t public; +}; + +struct unit_test_t { + + /** + * name of the test + */ + char *name; + + /** + * test function + */ + bool (*test)(void); + + /** + * run the test? + */ + bool enabled; +}; + +#undef DEFINE_TEST +#define DEFINE_TEST(name, function, enabled) bool function(); +#include <plugins/unit_tester/tests.h> +#undef DEFINE_TEST +#define DEFINE_TEST(name, function, enabled) {name, function, enabled}, +static unit_test_t tests[] = { +#include <plugins/unit_tester/tests.h> +}; + +static void run_tests(private_unit_tester_t *this) +{ + int i, run = 0, failed = 0, success = 0, skipped = 0; + + DBG1(DBG_CFG, "running unit tests, %d tests registered", + sizeof(tests)/sizeof(unit_test_t)); + + for (i = 0; i < sizeof(tests)/sizeof(unit_test_t); i++) + { + if (tests[i].enabled) + { + run++; + if (tests[i].test()) + { + DBG1(DBG_CFG, "test '%s' successful", tests[i].name); + success++; + } + else + { + DBG1(DBG_CFG, "test '%s' failed", tests[i].name); + failed++; + } + } + else + { + DBG1(DBG_CFG, "test '%s' disabled", tests[i].name); + skipped++; + } + } + DBG1(DBG_CFG, "%d/%d tests successful (%d failed, %d disabled)", + success, run, failed, skipped); +} + +/** + * Implementation of 2007_t.destroy + */ +static void destroy(private_unit_tester_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_unit_tester_t *this = malloc_thing(private_unit_tester_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + run_tests(this); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/unit_tester/unit_tester.h b/src/charon/plugins/unit_tester/unit_tester.h new file mode 100644 index 000000000..af946c2e0 --- /dev/null +++ b/src/charon/plugins/unit_tester/unit_tester.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: unit_tester.h 3491 2008-02-22 14:04:00Z martin $ + */ + +/** + * @defgroup unit_tester unit_tester + * @{ @ingroup cplugins + */ + +#ifndef UNIT_TESTER_H_ +#define UNIT_TESTER_H_ + +#include <plugins/plugin.h> + +typedef struct unit_tester_t unit_tester_t; + +/** + * Unit testing plugin. + * + * The unit testing plugin runs tests on plugin initialization. Tests are + * defined in tests.h using the DEFINE_TEST macro. Implementation of the + * tests is done in the tests folder. Each test has uses a function which + * returns TRUE for success or FALSE for failure. + */ +struct unit_tester_t { + + /** + * Implements the plugin interface. + */ + plugin_t plugin; +}; + +/** + * Create a unit_tester plugin. + */ +plugin_t *plugin_create(); + +#endif /* UNIT_TESTER_H_ @}*/ |