diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-04-12 20:30:08 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-04-12 20:30:08 +0000 |
commit | b0d8ed94fe9e74afb49fdf5f11e4add29879c65c (patch) | |
tree | b20167235628771046e940a82a906a6d0991ee4a /src/starter | |
parent | ea939d07c84d2a8e51215458063fc05e9c399290 (diff) | |
download | vyos-strongswan-b0d8ed94fe9e74afb49fdf5f11e4add29879c65c.tar.gz vyos-strongswan-b0d8ed94fe9e74afb49fdf5f11e4add29879c65c.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.1.1)
Diffstat (limited to 'src/starter')
36 files changed, 11563 insertions, 0 deletions
diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am new file mode 100644 index 000000000..7d5a4b69a --- /dev/null +++ b/src/starter/Makefile.am @@ -0,0 +1,37 @@ +ipsec_PROGRAMS = starter +starter_SOURCES = y.tab.c netkey.c y.tab.h parser.h args.h netkey.h \ +starterwhack.c starterwhack.h starterstroke.c invokepluto.c confread.c \ +starterstroke.h interfaces.c invokepluto.h confread.h interfaces.h args.c \ +keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \ +exec.h invokecharon.h lex.yy.c + +INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke +AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG +starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a +EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf +dist_man_MANS = ipsec.conf.5 +MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c + +PLUTODIR=$(top_srcdir)/src/pluto +OPENACDIR=$(top_srcdir)/src/openac + +lex.yy.c: y.tab.c parser.l parser.y parser.h + $(LEX) parser.l + +y.tab.c: parser.l parser.y parser.h + $(YACC) -v -d parser.y + +y.tab.h: parser.l parser.y parser.h + $(YACC) -v -d parser.y + +keywords.c: keywords.txt keywords.h + $(GPERF) -C -G -t < keywords.txt > keywords.c + +loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h + $(COMPILE) -c -o $@ $< + +defs.o: $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h + $(COMPILE) -c -o $@ $< + +install-exec-local : + test -e "$(sysconfdir)/ipsec.conf" || $(INSTALL) ipsec.conf $(sysconfdir)/ipsec.conf diff --git a/src/starter/Makefile.in b/src/starter/Makefile.in new file mode 100644 index 000000000..80410a205 --- /dev/null +++ b/src/starter/Makefile.in @@ -0,0 +1,581 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 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@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +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 = starter$(EXEEXT) +subdir = src/starter +DIST_COMMON = README $(dist_man_MANS) $(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__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" +ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(ipsec_PROGRAMS) +am_starter_OBJECTS = y.tab.$(OBJEXT) netkey.$(OBJEXT) \ + starterwhack.$(OBJEXT) starterstroke.$(OBJEXT) \ + invokepluto.$(OBJEXT) confread.$(OBJEXT) interfaces.$(OBJEXT) \ + args.$(OBJEXT) keywords.$(OBJEXT) cmp.$(OBJEXT) \ + starter.$(OBJEXT) exec.$(OBJEXT) invokecharon.$(OBJEXT) \ + lex.yy.$(OBJEXT) +starter_OBJECTS = $(am_starter_OBJECTS) +starter_DEPENDENCIES = loglite.o defs.o \ + $(top_srcdir)/src/libfreeswan/libfreeswan.a +DEFAULT_INCLUDES = -I. -I$(srcdir) +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 --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(starter_SOURCES) +DIST_SOURCES = $(starter_SOURCES) +man5dir = $(mandir)/man5 +NROFF = nroff +MANS = $(dist_man_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@ +BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@ +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@ +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_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +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@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@ +USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@ +USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@ +USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@ +USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@ +USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@ +USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@ +USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@ +USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@ +USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@ +USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@ +USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@ +USE_VENDORID_FALSE = @USE_VENDORID_FALSE@ +USE_VENDORID_TRUE = @USE_VENDORID_TRUE@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +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@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +eapdir = @eapdir@ +exec_prefix = @exec_prefix@ +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@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +starter_SOURCES = y.tab.c netkey.c y.tab.h parser.h args.h netkey.h \ +starterwhack.c starterwhack.h starterstroke.c invokepluto.c confread.c \ +starterstroke.h interfaces.c invokepluto.h confread.h interfaces.h args.c \ +keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \ +exec.h invokecharon.h lex.yy.c + +INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke +AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG +starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a +EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf +dist_man_MANS = ipsec.conf.5 +MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c +PLUTODIR = $(top_srcdir)/src/pluto +OPENACDIR = $(top_srcdir)/src/openac +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/starter/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/starter/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-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) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --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 +starter$(EXEEXT): $(starter_OBJECTS) $(starter_DEPENDENCIES) + @rm -f starter$(EXEEXT) + $(LINK) $(starter_LDFLAGS) $(starter_OBJECTS) $(starter_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/args.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/confread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exec.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interfaces.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invokecharon.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invokepluto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keywords.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.yy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netkey.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starterstroke.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starterwhack.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/y.tab.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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 + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-man5: $(man5_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)" + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ + done +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ + done + +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; } \ + END { 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; } \ + END { 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=; \ + 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; } \ + END { 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)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + 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 $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)"; 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." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ipsecPROGRAMS install-man + +install-exec-am: install-exec-local + +install-info: install-info-am + +install-man: install-man5 + +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-info-am uninstall-ipsecPROGRAMS uninstall-man + +uninstall-man: uninstall-man5 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-ipsecPROGRAMS clean-libtool 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-exec \ + install-exec-am install-exec-local install-info \ + install-info-am install-ipsecPROGRAMS install-man install-man5 \ + 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-info-am uninstall-ipsecPROGRAMS uninstall-man \ + uninstall-man5 + + +lex.yy.c: y.tab.c parser.l parser.y parser.h + $(LEX) parser.l + +y.tab.c: parser.l parser.y parser.h + $(YACC) -v -d parser.y + +y.tab.h: parser.l parser.y parser.h + $(YACC) -v -d parser.y + +keywords.c: keywords.txt keywords.h + $(GPERF) -C -G -t < keywords.txt > keywords.c + +loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h + $(COMPILE) -c -o $@ $< + +defs.o: $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h + $(COMPILE) -c -o $@ $< + +install-exec-local : + test -e "$(sysconfdir)/ipsec.conf" || $(INSTALL) ipsec.conf $(sysconfdir)/ipsec.conf +# 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/starter/README b/src/starter/README new file mode 100644 index 000000000..12a60a11d --- /dev/null +++ b/src/starter/README @@ -0,0 +1,104 @@ + +IPsec Starter -- Version 0.2 [Contributed by Arkoon Network Security] +============================ [ http://www.arkoon.net/] + +IPsec Starter is aimed to replace all the scripts which are used to +start and stop strongSwan and to do that in a quicker and a smarter way. + +IPsec Starter can also reload the configuration file (kill --HUP or periodicaly) +and apply the changes. + +Usage: + starter [--debug] [--auto_update <x seconds>] + --debug: enable debugging output + --no_fork: all msg (including pluto) are sent to the console + --auto_update: reload the config file (like kill -HUP) every x seconds + and determine any configuration changes + +FEATURES +-------- + +o Load and unload KLIPS (ipsec.o kernel module) + +o Load modules of the native Linux 2.6 IPsec stack + +o Launch and monitor pluto + +o Add, initiate, route and del connections + +o Attach and detach interfaces according to config file + +o kill -HUP can be used to reload the config file. New connections will be + added, old ones will be removed and modified ones will be reloaded. + Interfaces/Klips/Pluto will be reloaded if necessary. + +o Full support of the %defaultroute wildcard parameter. + +o save own pid in /var/run/starter + +o Upon reloading, dynamic DNS addr will be resolved and reloaded. Use + --auto_update to periodicaly check dynamic DNS changes. + +o kill -USR1 can be used to reload all connections (delete then add and + route/initiate) + +o /var/run/dynip/xxxx can be used to use a virtual interface name in + ipsec.conf. By example, when adsl can be ppp0, ppp1, ... : + ipsec.conf: interfaces="ipsec0=adsl" + And use /etc/ppp/ip-up to create /var/run/dynip/adsl + /var/run/dynip/adsl: IP_PHYS=ppp0 + +o %auto can be used to automaticaly name the connections + +o kill -TERM can be used to stop FS. pluto will be stopped and KLIPS unloaded + (if it has been loaded). + +o Can be used to start strongSwan and load lots of connections in a few + seconds. + +TODO +---- + +o handle wildcards in include lines -- use glob() fct + ex: include /etc/ipsec.*.conf + +o handle duplicates keywords and sections + +o 'also' keyword not supported + +o manually keyed connections + +o IPv6 + +o Documentation + + +CHANGES +------- + +o Version 0.1 -- 2002.01.14 -- First public release + +o Version 0.2 -- 2002.09.04 -- Various enhancements + FreeS/WAN 1.98b, x509 0.9.14, algo 0.8.0 + +o Version 0.2d -- 2004.01.13 -- Adaptions for Openswan 1.0.0 + by Stephan Scholz <sscholz@astaro.com> + +o Version 0.2e -- 2004.10.14 -- Added support for change of interface address + by Stephan Scholz <sscholz@astaro.com> + +o Version 0.2s -- 2005-12-02 -- Ported to strongSwan + by Stephan Scholz <sscholz@astaro.com> + +o Version 0.2x -- 2006-01-02 -- Added missing strongSwan keywords + Full support of the native Linux 2.6 IPsec stack + Full support of %defaultroute + Improved parsing of keywords using perfect hash + function generated by gperf. + by Andreas Steffen <andreas.steffen@hsr.ch> + +THANKS +------ + +o Nathan Angelacos - include fix + diff --git a/src/starter/args.c b/src/starter/args.c new file mode 100644 index 000000000..82e957f59 --- /dev/null +++ b/src/starter/args.c @@ -0,0 +1,632 @@ +/* automatic handling of confread struct arguments + * Copyright (C) 2006 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id: args.c,v 1.9 2006/04/17 10:32:36 as Exp $ + */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "keywords.h" +#include "parser.h" +#include "confread.h" +#include "args.h" + +/* argument types */ + +typedef enum { + ARG_NONE, + ARG_ENUM, + ARG_UINT, + ARG_TIME, + ARG_ULNG, + ARG_PCNT, + ARG_STR, + ARG_LST, + ARG_MISC +} arg_t; + +/* various keyword lists */ + +static const char *LST_bool[] = { + "no", + "yes", + NULL +}; + +static const char *LST_sendcert[] = { + "always", + "ifasked", + "never", + "yes", + "no", + NULL +}; + +static const char *LST_dpd_action[] = { + "none", + "clear", + "hold", + "restart", + NULL +}; + +static const char *LST_startup[] = { + "ignore", + "add", + "route", + "start", + NULL +}; + +static const char *LST_packetdefault[] = { + "drop", + "reject", + "pass", + NULL +}; + +static const char *LST_keyexchange[] = { + "ike", + "ikev1", + "ikev2", + NULL +}; + +static const char *LST_pfsgroup[] = { + "modp1024", + "modp1536", + "modp2048", + "modp3072", + "modp4096", + "modp6144", + "modp8192", + NULL +}; + +static const char *LST_plutodebug[] = { + "none", + "all", + "raw", + "crypt", + "parsing", + "emitting", + "control", + "lifecycle", + "klips", + "dns", + "natt", + "oppo", + "controlmore", + "private", + NULL +}; + +static const char *LST_klipsdebug[] = { + "tunnel", + "tunnel-xmit", + "pfkey", + "xform", + "eroute", + "spi", + "radij", + "esp", + "ah", + "ipcomp", + "verbose", + "all", + "none", + NULL +}; + +typedef struct { + arg_t type; + size_t offset; + const char **list; +} token_info_t; + +static const token_info_t token_info[] = +{ + /* config setup keywords */ + { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL }, + { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool }, + { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool }, + + /* pluto/charon keywords */ + { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug }, + { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL }, + { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_bool }, + { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL }, + { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL }, + { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool }, + { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_bool }, + { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool }, + { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool }, + { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL }, + { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool }, + { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool }, + + /* KLIPS keywords */ + { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug }, + { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool }, + { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault }, + { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool }, + + /* conn section keywords */ + { ARG_STR, offsetof(starter_conn_t, name), NULL }, + { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup }, + { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange }, + { ARG_MISC, 0, NULL /* KW_TYPE */ }, + { ARG_MISC, 0, NULL /* KW_PFS */ }, + { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, + { ARG_MISC, 0, NULL /* KW_AUTH */ }, + { ARG_MISC, 0, NULL /* KW_AUTHBY */ }, + { ARG_MISC, 0, NULL /* KW_EAP */ }, + { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL }, + { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL }, + { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL }, + { ARG_ULNG, offsetof(starter_conn_t, sa_keying_tries), NULL }, + { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL }, + { ARG_MISC, 0, NULL /* KW_REKEY */ }, + { ARG_MISC, 0, NULL /* KW_REAUTH */ }, + { ARG_STR, offsetof(starter_conn_t, ike), NULL }, + { ARG_STR, offsetof(starter_conn_t, esp), NULL }, + { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup }, + { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL }, + { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL }, + { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action }, + { ARG_MISC, 0, NULL /* KW_MODECONFIG */ }, + { ARG_MISC, 0, NULL /* KW_XAUTH */ }, + + /* ca section keywords */ + { ARG_STR, offsetof(starter_ca_t, name), NULL }, + { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup }, + { ARG_STR, offsetof(starter_ca_t, cacert), NULL }, + { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL }, + { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL }, + { ARG_STR, offsetof(starter_ca_t, crluri), NULL }, + { ARG_STR, offsetof(starter_ca_t, crluri2), NULL }, + { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL }, + { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL }, + + /* end keywords */ + { ARG_MISC, 0, NULL /* KW_HOST */ }, + { ARG_MISC, 0, NULL /* KW_NEXTHOP */ }, + { ARG_MISC, 0, NULL /* KW_SUBNET */ }, + { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ }, + { ARG_MISC, 0, NULL /* KW_PROTOPORT */ }, + { ARG_MISC, 0, NULL /* KW_SOURCEIP */ }, + { ARG_MISC, 0, NULL /* KW_NATIP */ }, + { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool }, + { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool }, + { ARG_STR, offsetof(starter_end_t, updown), NULL }, + { ARG_STR, offsetof(starter_end_t, id), NULL }, + { ARG_STR, offsetof(starter_end_t, rsakey), NULL }, + { ARG_STR, offsetof(starter_end_t, cert), NULL }, + { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert }, + { ARG_STR, offsetof(starter_end_t, ca), NULL }, + { ARG_STR, offsetof(starter_end_t, groups), NULL }, + { ARG_STR, offsetof(starter_end_t, iface), NULL } +}; + +static void +free_list(char **list) +{ + char **s; + + for (s = list; *s; s++) + pfree(*s); + pfree(list); +} + +char ** +new_list(char *value) +{ + char *val, *b, *e, *end, **ret; + int count; + + val = value ? clone_str(value, "list value") : NULL; + if (!val) + return NULL; + end = val + strlen(val); + for (b = val, count = 0; b < end;) + { + for (e = b; ((*e != ' ') && (*e != '\0')); e++); + *e = '\0'; + if (e != b) + count++; + b = e + 1; + } + if (count == 0) + { + pfree(val); + return NULL; + } + ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list"); + + for (b = val, count = 0; b < end; ) + { + for (e = b; (*e != '\0'); e++); + if (e != b) + ret[count++] = clone_str(b, "list value"); + b = e + 1; + } + ret[count] = NULL; + pfree(val); + return ret; +} + + +/* + * assigns an argument value to a struct field + */ +bool +assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base + , bool *assigned) +{ + char *p = base + token_info[token].offset; + const char **list = token_info[token].list; + + int index = -1; /* used for enumeration arguments */ + + lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */ + lset_t f = LELEM(token - first); /* compute flag position of argument */ + + *assigned = FALSE; + + DBG(DBG_CONTROLMORE, + DBG_log(" %s=%s", kw->entry->name, kw->value) + ) + + if (*seen & f) + { + plog("# duplicate '%s' option", kw->entry->name); + return FALSE; + } + + /* set flag that this argument has been seen */ + *seen |= f; + + /* is there a keyword list? */ + if (list != NULL && token_info[token].type != ARG_LST) + { + bool match = FALSE; + + while (*list != NULL && !match) + { + index++; + match = streq(kw->value, *list++); + } + if (!match) + { + plog("# bad value: %s=%s", kw->entry->name, kw->value); + return FALSE; + } + } + + switch (token_info[token].type) + { + case ARG_NONE: + plog("# option '%s' not supported yet", kw->entry->name); + return FALSE; + case ARG_ENUM: + { + int *i = (int *)p; + + if (index < 0) + { + plog("# bad enumeration value: %s=%s (%d)" + , kw->entry->name, kw->value, index); + return FALSE; + } + *i = index; + } + break; + + case ARG_UINT: + { + char *endptr; + u_int *u = (u_int *)p; + + *u = strtoul(kw->value, &endptr, 10); + + if (*endptr != '\0') + { + plog("# bad integer value: %s=%s", kw->entry->name, kw->value); + return FALSE; + } + } + break; + case ARG_ULNG: + case ARG_PCNT: + { + char *endptr; + unsigned long *l = (unsigned long *)p; + + *l = strtoul(kw->value, &endptr, 10); + + if (token_info[token].type == ARG_ULNG) + { + if (*endptr != '\0') + { + plog("# bad integer value: %s=%s", kw->entry->name, kw->value); + return FALSE; + } + } + else + { + if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value) + { + plog("# bad percent value: %s=%s", kw->entry->name, kw->value); + return FALSE; + } + } + + } + break; + case ARG_TIME: + { + char *endptr; + time_t *t = (time_t *)p; + + *t = strtoul(kw->value, &endptr, 10); + + /* time in seconds? */ + if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0')) + break; + + if (endptr[1] == '\0') + { + if (*endptr == 'm') /* time in minutes? */ + { + *t *= 60; + break; + } + if (*endptr == 'h') /* time in hours? */ + { + *t *= 3600; + break; + } + if (*endptr == 'd') /* time in days? */ + { + *t *= 3600*24; + break; + } + } + plog("# bad duration value: %s=%s", kw->entry->name, kw->value); + return FALSE; + } + case ARG_STR: + { + char **cp = (char **)p; + + /* free any existing string */ + pfreeany(*cp); + + /* assign the new string */ + *cp = clone_str(kw->value, "str_value"); + } + break; + case ARG_LST: + { + char ***listp = (char ***)p; + + /* free any existing list */ + if (*listp != NULL) + free_list(*listp); + + /* create a new list and assign values */ + *listp = new_list(kw->value); + + /* is there a keyword list? */ + if (list != NULL) + { + char ** lst; + + for (lst = *listp; lst && *lst; lst++) + { + bool match = FALSE; + + list = token_info[token].list; + + while (*list != NULL && !match) + { + match = streq(*lst, *list++); + } + if (!match) + { + plog("# bad value: %s=%s", kw->entry->name, *lst); + return FALSE; + } + } + } + } + default: + return TRUE; + } + + *assigned = TRUE; + return TRUE; +} + +/* + * frees all dynamically allocated arguments in a struct + */ +void +free_args(kw_token_t first, kw_token_t last, char *base) +{ + kw_token_t token; + + for (token = first; token <= last; token++) + { + char *p = base + token_info[token].offset; + + switch (token_info[token].type) + { + case ARG_STR: + { + char **cp = (char **)p; + + pfreeany(*cp); + *cp = NULL; + } + break; + case ARG_LST: + { + char ***listp = (char ***)p; + + if (*listp != NULL) + { + free_list(*listp); + *listp = NULL; + } + } + break; + default: + break; + } + } +} + +/* + * clone all dynamically allocated arguments in a struct + */ +void +clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2) +{ + kw_token_t token; + + for (token = first; token <= last; token++) + { + if (token_info[token].type == ARG_STR) + { + char **cp1 = (char **)(base1 + token_info[token].offset); + char **cp2 = (char **)(base2 + token_info[token].offset); + + *cp1 = clone_str(*cp2, "cloned str"); + } + } +} + +static bool +cmp_list(char **list1, char **list2) +{ + if ((list1 == NULL) && (list2 == NULL)) + return TRUE; + if ((list1 == NULL) || (list2 == NULL)) + return FALSE; + + for ( ; *list1 && *list2; list1++, list2++) + { + if (strcmp(*list1,*list2) != 0) + return FALSE; + } + + if ((*list1 != NULL) || (*list2 != NULL)) + return FALSE; + + return TRUE; +} + +/* + * compare all arguments in a struct + */ +bool +cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2) +{ + kw_token_t token; + + for (token = first; token <= last; token++) + { + char *p1 = base1 + token_info[token].offset; + char *p2 = base2 + token_info[token].offset; + + switch (token_info[token].type) + { + case ARG_ENUM: + { + int *i1 = (int *)p1; + int *i2 = (int *)p2; + + if (*i1 != *i2) + return FALSE; + } + break; + case ARG_UINT: + { + u_int *u1 = (u_int *)p1; + u_int *u2 = (u_int *)p2; + + if (*u1 != *u2) + return FALSE; + } + break; + case ARG_ULNG: + case ARG_PCNT: + { + unsigned long *l1 = (unsigned long *)p1; + unsigned long *l2 = (unsigned long *)p2; + + if (*l1 != *l2) + return FALSE; + } + break; + case ARG_TIME: + { + time_t *t1 = (time_t *)p1; + time_t *t2 = (time_t *)p2; + + if (*t1 != *t2) + return FALSE; + } + break; + case ARG_STR: + { + char **cp1 = (char **)p1; + char **cp2 = (char **)p2; + + if (*cp1 == NULL && *cp2 == NULL) + break; + if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0) + return FALSE; + } + break; + case ARG_LST: + { + char ***listp1 = (char ***)p1; + char ***listp2 = (char ***)p2; + + if (!cmp_list(*listp1, *listp2)) + return FALSE; + } + break; + default: + break; + } + } + return TRUE; +} diff --git a/src/starter/args.h b/src/starter/args.h new file mode 100644 index 000000000..302e9bb7b --- /dev/null +++ b/src/starter/args.h @@ -0,0 +1,34 @@ +/* automatic handling of confread struct arguments + * Copyright (C) 2006 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id: args.h,v 1.3 2006/01/13 18:02:02 as Exp $ + */ + +#ifndef _ARGS_H_ +#define _ARGS_H_ + +#include "keywords.h" +#include "parser.h" + +extern char **new_list(char *value); +extern bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw + , char *base, bool *assigned); +extern void free_args(kw_token_t first, kw_token_t last, char *base); +extern void clone_args(kw_token_t first, kw_token_t last, char *base1 + , char *base2); +extern bool cmp_args(kw_token_t first, kw_token_t last, char *base1 + , char *base2); + +#endif /* _ARGS_H_ */ + diff --git a/src/starter/cmp.c b/src/starter/cmp.c new file mode 100644 index 000000000..9222bf58f --- /dev/null +++ b/src/starter/cmp.c @@ -0,0 +1,105 @@ +/* strongSwan IPsec starter comparison functions + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: cmp.c,v 1.12 2006/01/13 18:03:25 as Exp $ + */ + +#include <string.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" + +#include "confread.h" +#include "args.h" +#include "interfaces.h" +#include "cmp.h" + +#define VARCMP(obj) if (c1->obj != c2->obj) return FALSE +#define ADDCMP(obj) if (!sameaddr(&c1->obj,&c2->obj)) return FALSE +#define SUBCMP(obj) if (!samesubnet(&c1->obj,&c2->obj)) return FALSE + +static bool +starter_cmp_end(starter_end_t *c1, starter_end_t *c2) +{ + if ((c1 == NULL) || (c2 == NULL)) + return FALSE; + + ADDCMP(addr); + ADDCMP(nexthop); + ADDCMP(srcip); + SUBCMP(subnet); + VARCMP(has_client); + VARCMP(has_client_wildcard); + VARCMP(has_port_wildcard); + VARCMP(has_srcip); + VARCMP(modecfg); + VARCMP(port); + VARCMP(protocol); + + return cmp_args(KW_END_FIRST, KW_END_LAST, (char *)c1, (char *)c2); + } + +bool +starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2) +{ + if ((c1 == NULL) || (c2 == NULL)) + return FALSE; + + VARCMP(policy); + VARCMP(addr_family); + VARCMP(tunnel_addr_family); + + if (!starter_cmp_end(&c1->left, &c2->left)) + return FALSE; + if (!starter_cmp_end(&c1->right, &c2->right)) + return FALSE; + + return cmp_args(KW_CONN_NAME, KW_CONN_LAST, (char *)c1, (char *)c2); +} + +bool +starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2) +{ + if (c1 == NULL || c2 == NULL) + return FALSE; + + return cmp_args(KW_CA_NAME, KW_CA_LAST, (char *)c1, (char *)c2); +} + +bool +starter_cmp_klips(starter_config_t *c1, starter_config_t *c2) +{ + if ((c1 == NULL) || (c2 == NULL)) + return FALSE; + + return cmp_args(KW_KLIPS_FIRST, KW_KLIPS_LAST, (char *)c1, (char *)c2); +} + +bool +starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2) +{ + if ((c1 == NULL) || (c2 == NULL)) + return FALSE; + + return cmp_args(KW_PLUTO_FIRST, KW_PLUTO_LAST, (char *)c1, (char *)c2); +} + +bool +starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2) +{ + if ((d1 == NULL) || (d2 == NULL)) + return FALSE; + return memcmp(d1, d2, sizeof(defaultroute_t)) == 0; +} diff --git a/src/starter/cmp.h b/src/starter/cmp.h new file mode 100644 index 000000000..ca355e9eb --- /dev/null +++ b/src/starter/cmp.h @@ -0,0 +1,29 @@ +/* strongSwan IPsec starter comparison functions + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: cmp.h,v 1.4 2006/01/06 20:24:41 as Exp $ + */ + +#ifndef _STARTER_CMP_H_ +#define _STARTER_CMP_H_ + +#include "interfaces.h" + +extern bool starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2); +extern bool starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2); +extern bool starter_cmp_klips(starter_config_t *c1, starter_config_t *c2); +extern bool starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2); +extern bool starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2); + +#endif + diff --git a/src/starter/confread.c b/src/starter/confread.c new file mode 100644 index 000000000..e7a4789a9 --- /dev/null +++ b/src/starter/confread.c @@ -0,0 +1,936 @@ +/* strongSwan IPsec config file parser + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: confread.c,v 1.37 2006/04/17 19:35:07 as Exp $ + */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "keywords.h" +#include "parser.h" +#include "confread.h" +#include "args.h" +#include "interfaces.h" + +/* strings containing a colon are interpreted as an IPv6 address */ +#define ip_version(string) (strchr(string, ':') != NULL)? AF_INET6 : AF_INET; + +static const char ike_defaults[] = "aes128-sha-modp2048"; +static const char esp_defaults[] = "aes128-sha1, 3des-md5"; + +static const char firewall_defaults[] = "ipsec _updown iptables"; + +static void default_values(starter_config_t *cfg) +{ + if (cfg == NULL) + return; + + memset(cfg, 0, sizeof(struct starter_config)); + + /* is there enough space for all seen flags? */ + assert(KW_SETUP_LAST - KW_SETUP_FIRST < + sizeof(cfg->setup.seen) * BITS_PER_BYTE); + assert(KW_CONN_LAST - KW_CONN_FIRST < + sizeof(cfg->conn_default.seen) * BITS_PER_BYTE); + assert(KW_END_LAST - KW_END_FIRST < + sizeof(cfg->conn_default.right.seen) * BITS_PER_BYTE); + assert(KW_CA_LAST - KW_CA_FIRST < + sizeof(cfg->ca_default.seen) * BITS_PER_BYTE); + + cfg->setup.seen = LEMPTY; + cfg->setup.fragicmp = TRUE; + cfg->setup.hidetos = TRUE; + cfg->setup.uniqueids = TRUE; + cfg->setup.interfaces = new_list("%defaultroute"); + cfg->setup.charonstart = TRUE; + cfg->setup.plutostart = TRUE; + + cfg->conn_default.seen = LEMPTY; + cfg->conn_default.startup = STARTUP_NO; + cfg->conn_default.state = STATE_IGNORE; + cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG | POLICY_PFS ; + + cfg->conn_default.ike = clone_str(ike_defaults, "ike_defaults"); + cfg->conn_default.esp = clone_str(esp_defaults, "esp_defaults"); + cfg->conn_default.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; + cfg->conn_default.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT; + cfg->conn_default.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT; + cfg->conn_default.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT; + cfg->conn_default.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT; + cfg->conn_default.addr_family = AF_INET; + cfg->conn_default.tunnel_addr_family = AF_INET; + + cfg->conn_default.left.seen = LEMPTY; + cfg->conn_default.right.seen = LEMPTY; + + cfg->conn_default.left.sendcert = CERT_SEND_IF_ASKED; + cfg->conn_default.right.sendcert = CERT_SEND_IF_ASKED; + + anyaddr(AF_INET, &cfg->conn_default.left.addr); + anyaddr(AF_INET, &cfg->conn_default.left.nexthop); + anyaddr(AF_INET, &cfg->conn_default.left.srcip); + anyaddr(AF_INET, &cfg->conn_default.right.addr); + anyaddr(AF_INET, &cfg->conn_default.right.nexthop); + anyaddr(AF_INET, &cfg->conn_default.right.srcip); + + cfg->ca_default.seen = LEMPTY; +} + +#define KW_POLICY_FLAG(sy, sn, fl) \ + if (streq(kw->value, sy)) { conn->policy |= fl; } \ + else if (streq(kw->value, sn)) { conn->policy &= ~fl; } \ + else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); cfg->err++; } + +static void +load_setup(starter_config_t *cfg, config_parsed_t *cfgp) +{ + kw_list_t *kw; + + DBG(DBG_CONTROL, + DBG_log("Loading config setup") + ) + + for (kw = cfgp->config_setup; kw; kw = kw->next) + { + bool assigned = FALSE; + + kw_token_t token = kw->entry->token; + + if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST) + { + plog("# unsupported keyword '%s' in config setup", kw->entry->name); + cfg->err++; + continue; + } + + if (!assign_arg(token, KW_SETUP_FIRST, kw, (char *)cfg, &assigned)) + { + plog(" bad argument value in config setup"); + cfg->err++; + continue; + } + } +} + +static void +kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token + , kw_list_t *kw, char *conn_name, starter_config_t *cfg) +{ + err_t ugh = NULL; + bool assigned = FALSE; + int has_port_wildcard; /* set if port is %any */ + + char *name = kw->entry->name; + char *value = kw->value; + + if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned)) + goto err; + + if (token == KW_SENDCERT) + { + if (end->sendcert == CERT_YES_SEND) + end->sendcert = CERT_ALWAYS_SEND; + else if (end->sendcert == CERT_NO_SEND) + end->sendcert = CERT_NEVER_SEND; + } + + if (assigned) + return; + + switch (token) + { + case KW_HOST: + if (streq(value, "%defaultroute")) + { + if (cfg->defaultroute.defined) + { + end->addr = cfg->defaultroute.addr; + end->nexthop = cfg->defaultroute.nexthop; + } + else + { + plog("# default route not known: %s=%s", name, value); + goto err; + } + } + else if (streq(value, "%any")) + { + anyaddr(conn->addr_family, &end->addr); + } + else if (streq(value, "%any6")) + { + conn->addr_family = AF_INET6; + anyaddr(conn->addr_family, &end->addr); + } + else + { + conn->addr_family = ip_version(value); + ugh = ttoaddr(value, 0, conn->addr_family, &end->addr); + if (ugh != NULL) + { + plog("# bad addr: %s=%s [%s]", name, value, ugh); + goto err; + } + } + break; + case KW_NEXTHOP: + if (streq(value, "%defaultroute")) + { + if (cfg->defaultroute.defined) + end->nexthop = cfg->defaultroute.nexthop; + else + { + plog("# default route not known: %s=%s", name, value); + goto err; + } + } + else if (streq(value, "%direct")) + { + ugh = anyaddr(conn->addr_family, &end->nexthop); + } + else + { + conn->addr_family = ip_version(value); + ugh = ttoaddr(value, 0, conn->addr_family, &end->nexthop); + } + if (ugh != NULL) + { + plog("# bad addr: %s=%s [%s]", name, value, ugh); + goto err; + } + break; + case KW_SUBNET: + if ((strlen(value) >= 6 && strncmp(value,"vhost:",6) == 0) + || (strlen(value) >= 5 && strncmp(value,"vnet:",5) == 0)) + { + end->virt = clone_str(value, "virt"); + } + else + { + end->has_client = TRUE; + conn->tunnel_addr_family = ip_version(value); + ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet); + if (ugh != NULL) + { + plog("# bad subnet: %s=%s [%s]", name, value, ugh); + goto err; + } + } + break; + case KW_SUBNETWITHIN: + end->has_client = TRUE; + end->has_client_wildcard = TRUE; + conn->tunnel_addr_family = ip_version(value); + ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet); + break; + case KW_PROTOPORT: + ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &has_port_wildcard); + end->has_port_wildcard = has_port_wildcard; + break; + case KW_SOURCEIP: + if (end->has_natip) + { + plog("# natip and sourceip cannot be defined at the same time"); + goto err; + } + if (streq(value, "%modeconfig") || streq(value, "%modecfg") || + streq(value, "%config") || streq(value, "%cfg")) + { + end->modecfg = TRUE; + } + else + { + conn->tunnel_addr_family = ip_version(value); + ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &end->srcip); + if (ugh != NULL) + { + plog("# bad addr: %s=%s [%s]", name, value, ugh); + goto err; + } + end->has_srcip = TRUE; + } + conn->policy |= POLICY_TUNNEL; + break; + case KW_NATIP: + if (end->has_srcip) + { + plog("# natip and sourceip cannot be defined at the same time"); + goto err; + } + if (streq(value, "%defaultroute")) + { + if (cfg->defaultroute.defined) + { + end->srcip = cfg->defaultroute.addr; + } + else + { + plog("# default route not known: %s=%s", name, value); + goto err; + } + } + else + { + conn->tunnel_addr_family = ip_version(value); + ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &end->srcip); + if (ugh != NULL) + { + plog("# bad addr: %s=%s [%s]", name, value, ugh); + goto err; + } + } + end->has_natip = TRUE; + conn->policy |= POLICY_TUNNEL; + break; + default: + break; + } + return; + +err: + plog(" bad argument value in conn '%s'", conn_name); + cfg->err++; +} + +/* + * handles left|rightfirewall and left|rightupdown parameters + */ +static void +handle_firewall( const char *label, starter_end_t *end, starter_config_t *cfg) +{ + if (end->firewall && (end->seen & LELEM(KW_FIREWALL - KW_END_FIRST))) + { + if (end->updown != NULL) + { + plog("# cannot have both %sfirewall and %supdown", label, label); + cfg->err++; + } + else + { + end->updown = clone_str(firewall_defaults, "firewall_defaults"); + end->firewall = FALSE; + } + } +} + +/* + * parse a conn section + */ +static void +load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) +{ + char *conn_name = (conn->name == NULL)? "%default":conn->name; + + for ( ; kw; kw = kw->next) + { + bool assigned = FALSE; + + kw_token_t token = kw->entry->token; + + if (token >= KW_LEFT_FIRST && token <= KW_LEFT_LAST) + { + kw_end(conn, &conn->left, token - KW_LEFT_FIRST + KW_END_FIRST + , kw, conn_name, cfg); + continue; + } + else if (token >= KW_RIGHT_FIRST && token <= KW_RIGHT_LAST) + { + kw_end(conn, &conn->right, token - KW_RIGHT_FIRST + KW_END_FIRST + , kw, conn_name, cfg); + continue; + } + + if (token == KW_AUTO) + { + token = KW_CONN_SETUP; + } + else if (token == KW_ALSO) + { + if (cfg->parse_also) + { + also_t *also = alloc_thing(also_t, "also_t"); + + also->name = clone_str(kw->value, "also"); + also->next = conn->also; + conn->also = also; + + DBG(DBG_CONTROL, + DBG_log(" also=%s", kw->value) + ) + } + continue; + } + + if (token < KW_CONN_FIRST || token > KW_CONN_LAST) + { + plog("# unsupported keyword '%s' in conn '%s'" + , kw->entry->name, conn_name); + cfg->err++; + continue; + } + + if (!assign_arg(token, KW_CONN_FIRST, kw, (char *)conn, &assigned)) + { + plog(" bad argument value in conn '%s'", conn_name); + cfg->err++; + continue; + } + + if (assigned) + continue; + + switch (token) + { + case KW_TYPE: + conn->policy &= ~(POLICY_TUNNEL | POLICY_SHUNT_MASK); + if (streq(kw->value, "tunnel")) + conn->policy |= POLICY_TUNNEL; + else if (streq(kw->value, "beet")) + conn->policy |= POLICY_BEET; + else if (streq(kw->value, "passthrough") || streq(kw->value, "pass")) + conn->policy |= POLICY_SHUNT_PASS; + else if (streq(kw->value, "drop")) + conn->policy |= POLICY_SHUNT_DROP; + else if (streq(kw->value, "reject")) + conn->policy |= POLICY_SHUNT_REJECT; + else if (strcmp(kw->value, "transport") != 0) + { + plog("# bad policy value: %s=%s", kw->entry->name, kw->value); + cfg->err++; + } + break; + case KW_PFS: + KW_POLICY_FLAG("yes", "no", POLICY_PFS) + break; + case KW_COMPRESS: + KW_POLICY_FLAG("yes", "no", POLICY_COMPRESS) + break; + case KW_AUTH: + KW_POLICY_FLAG("ah", "esp", POLICY_AUTHENTICATE) + break; + case KW_AUTHBY: + conn->policy &= ~(POLICY_ID_AUTH_MASK | POLICY_ENCRYPT); + + if (!(streq(kw->value, "never") || streq(kw->value, "eap"))) + { + char *value = kw->value; + char *second = strchr(kw->value, '|'); + + if (second != NULL) + *second = '\0'; + + /* also handles the cases secret|rsasig and rsasig|secret */ + for (;;) + { + if (streq(value, "rsasig")) + conn->policy |= POLICY_RSASIG | POLICY_ENCRYPT; + else if (streq(value, "secret") || streq(value, "psk")) + conn->policy |= POLICY_PSK | POLICY_ENCRYPT; + else if (streq(value, "xauthrsasig")) + conn->policy |= POLICY_XAUTH_RSASIG | POLICY_ENCRYPT; + else if (streq(value, "xauthpsk")) + conn->policy |= POLICY_XAUTH_PSK | POLICY_ENCRYPT; + else + { + plog("# bad policy value: %s=%s", kw->entry->name, kw->value); + cfg->err++; + break; + } + if (second == NULL) + break; + value = second; + second = NULL; /* traverse the loop no more than twice */ + } + } + break; + case KW_EAP: + /* TODO: a gperf function for all EAP types */ + if (streq(kw->value, "aka")) + conn->eap = 23; + else if (streq(kw->value, "sim")) + { + conn->eap = 18; + + } + else + { + conn->eap = atoi(kw->value); + if (conn->eap == 0) + { + plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value); + cfg->err++; + } + } + break; + case KW_REKEY: + KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY) + break; + case KW_REAUTH: + KW_POLICY_FLAG("no", "yes", POLICY_DONT_REAUTH) + break; + case KW_MODECONFIG: + KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH) + break; + case KW_XAUTH: + KW_POLICY_FLAG("server", "client", POLICY_XAUTH_SERVER) + break; + default: + break; + } + } + handle_firewall("left", &conn->left, cfg); + handle_firewall("right", &conn->right, cfg); +} + +/* + * initialize a conn object with the default conn + */ +static void +conn_default(char *name, starter_conn_t *conn, starter_conn_t *def) +{ + memcpy(conn, def, sizeof(starter_conn_t)); + conn->name = clone_str(name, "conn name"); + + clone_args(KW_CONN_FIRST, KW_CONN_LAST, (char *)conn, (char *)def); + clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left, (char *)&def->left); + clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right, (char *)&def->right); +} + +/* + * parse a ca section + */ +static void +load_ca(starter_ca_t *ca, kw_list_t *kw, starter_config_t *cfg) +{ + char *ca_name = (ca->name == NULL)? "%default":ca->name; + + for ( ; kw; kw = kw->next) + { + bool assigned = FALSE; + + kw_token_t token = kw->entry->token; + + if (token == KW_AUTO) + { + token = KW_CA_SETUP; + } + else if (token == KW_ALSO) + { + if (cfg->parse_also) + { + also_t *also = alloc_thing(also_t, "also_t"); + + also->name = clone_str(kw->value, "also"); + also->next = ca->also; + ca->also = also; + + DBG(DBG_CONTROL, + DBG_log(" also=%s", kw->value) + ) + } + continue; + } + + if (token < KW_CA_FIRST || token > KW_CA_LAST) + { + plog("# unsupported keyword '%s' in ca '%s'", kw->entry->name, ca_name); + cfg->err++; + continue; + } + + if (!assign_arg(token, KW_CA_FIRST, kw, (char *)ca, &assigned)) + { + plog(" bad argument value in ca '%s'", ca_name); + cfg->err++; + } + } + + /* treat 'route' and 'start' as 'add' */ + if (ca->startup != STARTUP_NO) + ca->startup = STARTUP_ADD; +} + +/* + * initialize a ca object with the default ca + */ +static void +ca_default(char *name, starter_ca_t *ca, starter_ca_t *def) +{ + memcpy(ca, def, sizeof(starter_ca_t)); + ca->name = clone_str(name, "ca name"); + + clone_args(KW_CA_FIRST, KW_CA_LAST, (char *)ca, (char *)def); +} + +static kw_list_t* +find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg); + +static void +load_also_conns(starter_conn_t *conn, also_t *also, starter_config_t *cfg) +{ + while (also != NULL) + { + kw_list_t *kw = find_also_conn(also->name, conn, cfg); + + if (kw == NULL) + { + plog(" conn '%s' cannot include '%s'", conn->name, also->name); + } + else + { + DBG(DBG_CONTROL, + DBG_log("conn '%s' includes '%s'", conn->name, also->name) + ) + /* only load if no error occurred in the first round */ + if (cfg->err == 0) + load_conn(conn, kw, cfg); + } + also = also->next; + } +} + +/* + * find a conn included by also + */ +static kw_list_t* +find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg) +{ + starter_conn_t *c = cfg->conn_first; + + while (c != NULL) + { + if (streq(name, c->name)) + { + if (conn->visit == c->visit) + { + plog("# detected also loop"); + cfg->err++; + return NULL; + } + c->visit = conn->visit; + load_also_conns(conn, c->also, cfg); + return c->kw; + } + c = c->next; + } + + plog("# also '%s' not found", name); + cfg->err++; + return NULL; +} + +static kw_list_t* +find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg); + +static void +load_also_cas(starter_ca_t *ca, also_t *also, starter_config_t *cfg) +{ + while (also != NULL) + { + kw_list_t *kw = find_also_ca(also->name, ca, cfg); + + if (kw == NULL) + { + plog(" ca '%s' cannot include '%s'", ca->name, also->name); + } + else + { + DBG(DBG_CONTROL, + DBG_log("ca '%s' includes '%s'", ca->name, also->name) + ) + /* only load if no error occurred in the first round */ + if (cfg->err == 0) + load_ca(ca, kw, cfg); + } + also = also->next; + } +} + +/* + * find a ca included by also + */ +static kw_list_t* +find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg) +{ + starter_ca_t *c = cfg->ca_first; + + while (c != NULL) + { + if (streq(name, c->name)) + { + if (ca->visit == c->visit) + { + plog("# detected also loop"); + cfg->err++; + return NULL; + } + c->visit = ca->visit; + load_also_cas(ca, c->also, cfg); + return c->kw; + } + c = c->next; + } + + plog("# also '%s' not found", name); + cfg->err++; + return NULL; +} + + + +/* + * load and parse an IPsec configuration file + */ +starter_config_t * +confread_load(const char *file) +{ + starter_config_t *cfg = NULL; + config_parsed_t *cfgp; + section_list_t *sconn, *sca; + starter_conn_t *conn; + starter_ca_t *ca; + + u_int visit = 0; + + /* load IPSec configuration file */ + cfgp = parser_load_conf(file); + if (!cfgp) + return NULL; + + cfg = (starter_config_t *)alloc_thing(starter_config_t, "starter_config_t"); + + /* set default values */ + default_values(cfg); + + /* determine default route */ + get_defaultroute(&cfg->defaultroute); + + /* load config setup section */ + load_setup(cfg, cfgp); + + /* in the first round parse also statements */ + cfg->parse_also = TRUE; + + /* find %default ca section */ + for (sca = cfgp->ca_first; sca; sca = sca->next) + { + if (streq(sca->name, "%default")) + { + DBG(DBG_CONTROL, + DBG_log("Loading ca %%default") + ) + load_ca(&cfg->ca_default, sca->kw, cfg); + } + } + + /* parameters defined in ca %default sections can be overloads */ + cfg->ca_default.seen = LEMPTY; + + /* load other ca sections */ + for (sca = cfgp->ca_first; sca; sca = sca->next) + { + /* skip %default ca section */ + if (streq(sca->name, "%default")) + continue; + + DBG(DBG_CONTROL, + DBG_log("Loading ca '%s'", sca->name) + ) + ca = (starter_ca_t *)alloc_thing(starter_ca_t, "starter_ca_t"); + + ca_default(sca->name, ca, &cfg->ca_default); + ca->kw = sca->kw; + ca->next = NULL; + + if (cfg->ca_last) + cfg->ca_last->next = ca; + cfg->ca_last = ca; + if (!cfg->ca_first) + cfg->ca_first = ca; + + load_ca(ca, ca->kw, cfg); + } + + for (ca = cfg->ca_first; ca; ca = ca->next) + { + also_t *also = ca->also; + + while (also != NULL) + { + kw_list_t *kw = find_also_ca(also->name, cfg->ca_first, cfg); + + load_ca(ca, kw, cfg); + also = also->next; + } + + if (ca->startup != STARTUP_NO) + ca->state = STATE_TO_ADD; + } + + /* find %default conn sections */ + for (sconn = cfgp->conn_first; sconn; sconn = sconn->next) + { + if (streq(sconn->name, "%default")) + { + DBG(DBG_CONTROL, + DBG_log("Loading conn %%default") + ) + load_conn(&cfg->conn_default, sconn->kw, cfg); + } + } + + /* parameter defined in conn %default sections can be overloaded */ + cfg->conn_default.seen = LEMPTY; + cfg->conn_default.right.seen = LEMPTY; + cfg->conn_default.left.seen = LEMPTY; + + /* load other conn sections */ + for (sconn = cfgp->conn_first; sconn; sconn = sconn->next) + { + /* skip %default conn section */ + if (streq(sconn->name, "%default")) + continue; + + DBG(DBG_CONTROL, + DBG_log("Loading conn '%s'", sconn->name) + ) + conn = (starter_conn_t *)alloc_thing(starter_conn_t, "starter_conn_t"); + + conn_default(sconn->name, conn, &cfg->conn_default); + conn->kw = sconn->kw; + conn->next = NULL; + + if (cfg->conn_last) + cfg->conn_last->next = conn; + cfg->conn_last = conn; + if (!cfg->conn_first) + cfg->conn_first = conn; + + load_conn(conn, conn->kw, cfg); + } + + /* in the second round do not parse also statements */ + cfg->parse_also = FALSE; + + for (ca = cfg->ca_first; ca; ca = ca->next) + { + ca->visit = ++visit; + load_also_cas(ca, ca->also, cfg); + + if (ca->startup != STARTUP_NO) + ca->state = STATE_TO_ADD; + } + + for (conn = cfg->conn_first; conn; conn = conn->next) + { + conn->visit = ++visit; + load_also_conns(conn, conn->also, cfg); + + if (conn->startup != STARTUP_NO) + conn->state = STATE_TO_ADD; + } + + parser_free_conf(cfgp); + + if (cfg->err) + { + plog("### %d parsing error%s ###", cfg->err, (cfg->err > 1)?"s":""); + confread_free(cfg); + cfg = NULL; + } + + return cfg; +} + +/* + * free the memory used by also_t objects + */ +static void +free_also(also_t *head) +{ + while (head != NULL) + { + also_t *also = head; + + head = also->next; + pfree(also->name); + pfree(also); + } +} + +/* + * free the memory used by a starter_conn_t object + */ +static void +confread_free_conn(starter_conn_t *conn) +{ + free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left); + free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right); + free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn); + free_also(conn->also); +} + +/* + * free the memory used by a starter_ca_t object + */ +static void +confread_free_ca(starter_ca_t *ca) +{ + free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca); + free_also(ca->also); +} + +/* + * free the memory used by a starter_config_t object + */ +void +confread_free(starter_config_t *cfg) +{ + starter_conn_t *conn = cfg->conn_first; + starter_ca_t *ca = cfg->ca_first; + + free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg); + + confread_free_conn(&cfg->conn_default); + + while (conn != NULL) + { + starter_conn_t *conn_aux = conn; + + conn = conn->next; + confread_free_conn(conn_aux); + pfree(conn_aux); + } + + confread_free_ca(&cfg->ca_default); + + while (ca != NULL) + { + starter_ca_t *ca_aux = ca; + + ca = ca->next; + confread_free_ca(ca_aux); + pfree(ca_aux); + } + + pfree(cfg); +} diff --git a/src/starter/confread.h b/src/starter/confread.h new file mode 100644 index 000000000..e0de68376 --- /dev/null +++ b/src/starter/confread.h @@ -0,0 +1,210 @@ +/* strongSwan IPsec config file parser + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: confread.h,v 1.23 2006/04/17 10:32:36 as Exp $ + */ + +#ifndef _IPSEC_CONFREAD_H_ +#define _IPSEC_CONFREAD_H_ + +#ifndef _FREESWAN_H +#include <freeswan.h> +#include "../pluto/constants.h" +#endif + +#include "parser.h" +#include "interfaces.h" + +typedef enum { + STARTUP_NO, + STARTUP_ADD, + STARTUP_ROUTE, + STARTUP_START +} startup_t; + +typedef enum { + STATE_IGNORE, + STATE_TO_ADD, + STATE_ADDED, + STATE_REPLACED, + STATE_INVALID +} starter_state_t; + +typedef enum { + KEY_EXCHANGE_IKE, + KEY_EXCHANGE_IKEV1, + KEY_EXCHANGE_IKEV2 +} keyexchange_t; + +typedef struct starter_end starter_end_t; + +struct starter_end { + lset_t seen; + char *id; + char *rsakey; + char *cert; + char *ca; + char *groups; + char *iface; + ip_address addr; + ip_address nexthop; + ip_address srcip; + ip_subnet subnet; + bool has_client; + bool has_client_wildcard; + bool has_port_wildcard; + bool has_srcip; + bool has_natip; + bool modecfg; + certpolicy_t sendcert; + bool firewall; + bool hostaccess; + char *updown; + u_int16_t port; + u_int8_t protocol; + char *virt; +}; + +typedef struct also also_t; + +struct also { + char *name; + bool included; + also_t *next; +}; + +typedef struct starter_conn starter_conn_t; + +struct starter_conn { + lset_t seen; + char *name; + also_t *also; + kw_list_t *kw; + u_int visit; + startup_t startup; + starter_state_t state; + + keyexchange_t keyexchange; + int eap; + lset_t policy; + time_t sa_ike_life_seconds; + time_t sa_ipsec_life_seconds; + time_t sa_rekey_margin; + unsigned long sa_keying_tries; + unsigned long sa_rekey_fuzz; + sa_family_t addr_family; + sa_family_t tunnel_addr_family; + + starter_end_t left, right; + + unsigned long id; + + char *esp; + char *ike; + char *pfsgroup; + + time_t dpd_delay; + time_t dpd_timeout; + dpd_action_t dpd_action; + int dpd_count; + + starter_conn_t *next; +}; + +typedef struct starter_ca starter_ca_t; + +struct starter_ca { + lset_t seen; + char *name; + also_t *also; + kw_list_t *kw; + u_int visit; + startup_t startup; + starter_state_t state; + + char *cacert; + char *ldaphost; + char *ldapbase; + char *crluri; + char *crluri2; + char *ocspuri; + char *ocspuri2; + + bool strict; + + starter_ca_t *next; +}; + +typedef struct starter_config starter_config_t; + +struct starter_config { + struct { + lset_t seen; + char **interfaces; + char *dumpdir; + bool charonstart; + bool plutostart; + + /* pluto/charon keywords */ + char **plutodebug; + char *charondebug; + char *prepluto; + char *postpluto; + bool uniqueids; + u_int overridemtu; + u_int crlcheckinterval; + bool cachecrls; + bool strictcrlpolicy; + bool nocrsend; + bool nat_traversal; + u_int keep_alive; + char *virtual_private; + char *eapdir; + char *pkcs11module; + bool pkcs11keepstate; + bool pkcs11proxy; + + /* KLIPS keywords */ + char **klipsdebug; + bool fragicmp; + char *packetdefault; + bool hidetos; + } setup; + + /* information about the default route */ + defaultroute_t defaultroute; + + /* number of encountered parsing errors */ + u_int err; + + /* do we parse also statements */ + bool parse_also; + + /* ca %default */ + starter_ca_t ca_default; + + /* connections list (without %default) */ + starter_ca_t *ca_first, *ca_last; + + /* conn %default */ + starter_conn_t conn_default; + + /* connections list (without %default) */ + starter_conn_t *conn_first, *conn_last; +}; + +extern starter_config_t *confread_load(const char *file); +extern void confread_free(starter_config_t *cfg); + +#endif /* _IPSEC_CONFREAD_H_ */ + diff --git a/src/starter/exec.c b/src/starter/exec.c new file mode 100644 index 000000000..98541db75 --- /dev/null +++ b/src/starter/exec.c @@ -0,0 +1,54 @@ +/* strongSwan IPsec exec helper function + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: exec.c,v 1.4 2006/01/04 23:30:24 as Exp $ + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "exec.h" + +#define BUF_SIZE 2048 + +/** + * TODO: + * o log stdout with LOG_LEVEL_INFO and stderr with LOG_LEVEL_ERR + */ + +int +starter_exec(const char *fmt, ...) +{ + va_list args; + static char buf[BUF_SIZE]; + int r; + + va_start (args, fmt); + vsnprintf(buf, BUF_SIZE-1, fmt, args); + buf[BUF_SIZE - 1] = '\0'; + va_end(args); + r = system(buf); + DBG(DBG_CONTROL, + DBG_log("starter_exec(%s) = %d", buf, r) + ) + return r; +} + diff --git a/src/starter/exec.h b/src/starter/exec.h new file mode 100644 index 000000000..d4be931dd --- /dev/null +++ b/src/starter/exec.h @@ -0,0 +1,23 @@ +/* strongSwan IPsec starter exec helper function + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: exec.h,v 1.2 2005/12/28 10:20:32 as Exp $ + */ + +#ifndef _STARTER_EXEC_H_ +#define _STARTER_EXEC_H_ + +extern int starter_exec (const char *fmt, ...); + +#endif /* _STARTER_EXEC_H_ */ + diff --git a/src/starter/files.h b/src/starter/files.h new file mode 100644 index 000000000..88b670d94 --- /dev/null +++ b/src/starter/files.h @@ -0,0 +1,40 @@ +/* strongSwan file locations + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: files.h,v 1.5 2006/02/04 18:52:58 as Exp $ + */ + +#ifndef _STARTER_FILES_H_ +#define _STARTER_FILES_H_ + +#define STARTER_PID_FILE IPSEC_PIDDIR "/starter.pid" + +#define PROC_NETKEY "/proc/net/pfkey" +#define PROC_MODULES "/proc/modules" + +#define CONFIG_FILE IPSEC_CONFDIR "/ipsec.conf" +#define SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets" + +#define PLUTO_CMD IPSEC_DIR "/pluto" +#define PLUTO_CTL_FILE IPSEC_PIDDIR "/pluto.ctl" +#define PLUTO_PID_FILE IPSEC_PIDDIR "/pluto.pid" + +#define CHARON_CMD IPSEC_DIR "/charon" +#define CHARON_CTL_FILE IPSEC_PIDDIR "/charon.ctl" +#define CHARON_PID_FILE IPSEC_PIDDIR "/charon.pid" + +#define DYNIP_DIR IPSEC_PIDDIR "/dynip" +#define INFO_FILE IPSEC_PIDDIR "/ipsec.info" + +#endif /* _STARTER_FILES_H_ */ + diff --git a/src/starter/interfaces.c b/src/starter/interfaces.c new file mode 100644 index 000000000..a7c8efd44 --- /dev/null +++ b/src/starter/interfaces.c @@ -0,0 +1,595 @@ +/* strongSwan IPsec interfaces management + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: interfaces.c,v 1.15 2006/02/05 10:51:55 as Exp $ + */ + +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <linux/if.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include <freeswan.h> +#include <ipsec_tunnel.h> + +#include <constants.h> +#include <defs.h> +#include <log.h> + +#include "interfaces.h" +#include "exec.h" +#include "files.h" + +#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) + +#define N_IPSEC_IF 4 + +struct st_ipsec_if { + char name[IFNAMSIZ]; + char phys[IFNAMSIZ]; + int up; +}; + +static struct st_ipsec_if _ipsec_if[N_IPSEC_IF]; + +static char * +_find_physical_iface(int sock, char *iface) +{ + static char _if[IFNAMSIZ]; + char *b; + struct ifreq req; + FILE *fd; + char line[BUF_LEN]; + + strncpy(req.ifr_name, iface, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req)==0) + { + if (req.ifr_flags & IFF_UP) + { + strncpy(_if, iface, IFNAMSIZ); + return _if; + } + } + else + { + /* If there is a file named /var/run/dynip/<iface>, look if we + * can get interface name from there (IP_PHYS) + */ + b = (char *)alloc_bytes(strlen(DYNIP_DIR) + strlen(iface) + 10, "iface"); + if (b) + { + sprintf(b, "%s/%s", DYNIP_DIR, iface); + fd = fopen(b, "r"); + pfree(b); + if (fd) + { + memset(_if, 0, sizeof(_if)); + memset(line, 0, sizeof(line)); + while (fgets(line, sizeof(line), fd) != 0) + { + if ((strncmp(line,"IP_PHYS=\"", 9) == 0) + && (line[strlen(line) - 2] == '"') + && (line[strlen(line) - 1] == '\n')) + { + strncpy(_if, line + 9, MIN(strlen(line) - 11, IFNAMSIZ)); + break; + } + else if ((strncmp(line,"IP_PHYS=", 8) == 0) + && (line[8] != '"') + && (line[strlen(line) - 1] == '\n')) + { + strncpy(_if, line + 8, MIN(strlen(line) - 9, IFNAMSIZ)); + break; + } + } + fclose(fd); + + if (*_if) + { + strncpy(req.ifr_name, _if, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req) == 0) + { + if (req.ifr_flags & IFF_UP) + return _if; + } + } + } + } + } + return NULL; +} + +int +starter_iface_find(char *iface, int af, ip_address *dst, ip_address *nh) +{ + char *phys; + struct ifreq req; + struct sockaddr_in *sa = (struct sockaddr_in *)(&req.ifr_addr); + int sock; + + if (!iface) + return -1; + + sock = socket(af, SOCK_DGRAM, 0); + if (sock < 0) + return -1; + + phys = _find_physical_iface(sock, iface); + if (!phys) + goto failed; + + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) + goto failed; + if (!(req.ifr_flags & IFF_UP)) + goto failed; + + if ((req.ifr_flags & IFF_POINTOPOINT) + && nh + && ioctl(sock, SIOCGIFDSTADDR, &req) == 0) + { + if (sa->sin_family == af) + initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, nh); + } + if ((dst) && (ioctl(sock, SIOCGIFADDR, &req) == 0)) + { + if (sa->sin_family == af) + initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, dst); + } + close(sock); + return 0; + +failed: + close(sock); + return -1; +} + +static int +valid_str(char *str, unsigned int *pn, char **pphys +, defaultroute_t *defaultroute) +{ + if (streq(str, "%defaultroute")) + { + if (!defaultroute->defined) + { + return 0; + } + *pn = 0; + *pphys = defaultroute->iface; + } + else + { + if (strlen(str) < 8 + || str[0] != 'i' || str[1] != 'p' || str[2] !='s' || str[3] != 'e' + || str[4] != 'c' || str[5] < '0' || str[5] > '9' || str[6] != '=') + { + return 0; + } + *pn = str[5] - '0'; + *pphys = &(str[7]); + } + return 1; +} + +static int +_iface_up (int sock, struct st_ipsec_if *iface, char *phys +, unsigned int mtu, bool nat_t) +{ + struct ifreq req; + struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&req.ifr_data; + short phys_flags; + int ret = 0; + /* sscholz@astaro.com: for network mask 32 bit + struct sockaddr_in *inp; + */ + + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req) !=0 ) + return ret; + phys_flags = req.ifr_flags; + + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req) != 0) + return ret; + + if ((!(req.ifr_flags & IFF_UP)) || (!iface->up)) + { + DBG(DBG_CONTROL, + DBG_log("attaching interface %s to %s", iface->name, phys) + ) + ret = 1; + } + + if ((*iface->phys) && (strcmp(iface->phys, phys) != 0 )) + { + /* tncfg --detach if phys has changed */ + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + ioctl(sock, IPSEC_DEL_DEV, &req); + ret = 1; + } + + /* tncfg --attach */ + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + strncpy(shc->cf_name, phys, sizeof(shc->cf_name)); + ioctl(sock, IPSEC_SET_DEV, &req); + + /* set ipsec addr = phys addr */ + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFADDR, &req) == 0) + { + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + ioctl(sock, SIOCSIFADDR, &req); + } + + /* set ipsec mask = phys mask */ + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFNETMASK, &req) == 0) + { + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + /* sscholz@astaro.com: changed netmask to 32 bit + * in order to prevent network routes from being created + + inp = (struct sockaddr_in *)&req.ifr_addr; + inp->sin_addr.s_addr = 0xFFFFFFFFL; + + */ + ioctl(sock, SIOCSIFNETMASK, &req); + } + + /* set other flags & addr */ + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req)==0) + { +/* removed by sscholz@astaro.com (caused trouble with DSL/ppp0) */ +/* if (phys_flags & IFF_POINTOPOINT) + { + req.ifr_flags |= IFF_POINTOPOINT; + req.ifr_flags &= ~IFF_BROADCAST; + ioctl(sock, SIOCSIFFLAGS, &req); + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0) + { + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + ioctl(sock, SIOCSIFDSTADDR, &req); + } + } + else + */ + if (phys_flags & IFF_BROADCAST) + { + req.ifr_flags &= ~IFF_POINTOPOINT; + req.ifr_flags |= IFF_BROADCAST; + ioctl(sock, SIOCSIFFLAGS, &req); + strncpy(req.ifr_name, phys, IFNAMSIZ); + if (ioctl(sock, SIOCGIFBRDADDR, &req) == 0) + { + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + ioctl(sock, SIOCSIFBRDADDR, &req); + } + } + else + { + req.ifr_flags &= ~IFF_POINTOPOINT; + req.ifr_flags &= ~IFF_BROADCAST; + ioctl(sock, SIOCSIFFLAGS, &req); + } + } + + /* + * guess MTU = phys interface MTU - ESP Overhead + * + * ESP overhead : 10+16+7+2+12=57 -> 60 by security + * NAT-T overhead : 20 + */ + if (mtu == 0) + { + strncpy(req.ifr_name, phys, IFNAMSIZ); + ioctl(sock, SIOCGIFMTU, &req); + mtu = req.ifr_mtu - 60; + if (nat_t) + mtu -= 20; + } + /* set MTU */ + if (mtu) + { + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + req.ifr_mtu = mtu; + ioctl(sock, SIOCSIFMTU, &req); + } + + /* ipsec interface UP */ + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req) == 0) + { + req.ifr_flags |= IFF_UP; + ioctl(sock, SIOCSIFFLAGS, &req); + } + + iface->up = 1; + strncpy(iface->phys, phys, IFNAMSIZ); + return ret; +} + +static int +_iface_down(int sock, struct st_ipsec_if *iface) +{ + struct ifreq req; + int ret = 0; + + iface->up = 0; + + strncpy(req.ifr_name, iface->name, IFNAMSIZ); + if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) + return ret; + + if (req.ifr_flags & IFF_UP) + { + DBG(DBG_CONTROL, + DBG_log("shutting down interface %s/%s", iface->name, iface->phys) + ) + req.ifr_flags &= ~IFF_UP; + ioctl(sock, SIOCSIFFLAGS, &req); + ret = 1; + } + + /* unset addr */ + memset(&req.ifr_addr, 0, sizeof(req.ifr_addr)); + req.ifr_addr.sa_family = AF_INET; + ioctl(sock, SIOCSIFADDR, &req); + + /* tncfg --detach */ + ioctl(sock, IPSEC_DEL_DEV, &req); + + memset(iface->phys, 0, sizeof(iface->phys)); + + return ret; +} + +void +starter_ifaces_init(void) +{ + int i; + + memset(_ipsec_if, 0, sizeof(_ipsec_if)); + for (i = 0; i < N_IPSEC_IF; i++) + snprintf(_ipsec_if[i].name, IFNAMSIZ, "ipsec%d", i); +} + +void +starter_ifaces_clear (void) +{ + int sock; + unsigned int i; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + return; + + for (i = 0; i < N_IPSEC_IF; i++) + _iface_down (sock, &(_ipsec_if[i])); +} + +int +starter_ifaces_load(char **ifaces, unsigned int omtu, bool nat_t +, defaultroute_t *defaultroute) +{ + char *tmp_phys, *phys; + int n; + char **i; + int sock; + int j, found; + int ret = 0; + struct ifreq physreq, ipsecreq; // re-attach interface + struct sockaddr_in *inp1, *inp2; // re-attach interface + + DBG(DBG_CONTROL, + DBG_log("starter_ifaces_load()") + ) + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + return -1; + + for (j = 0; j < N_IPSEC_IF; j++) + { + found = 0; + + for (i = ifaces; i && *i; i++) + { + if (valid_str(*i, &n, &tmp_phys, defaultroute) + && tmp_phys + && n >= 0 + && n < N_IPSEC_IF) + { + if (n==j) + { + if (found) + { + plog( "ignoring duplicate entry for interface ipsec%d", j); + } + else + { + found++; + phys = _find_physical_iface(sock, tmp_phys); + + /* Re-attach ipsec interface if IP address changes + * sscholz@astaro.com + */ + if (phys) + { + memset ((void*)&physreq, 0, sizeof(physreq)); + memset ((void*)&ipsecreq, 0, sizeof(ipsecreq)); + strncpy(physreq.ifr_name, phys, IFNAMSIZ); + sprintf(ipsecreq.ifr_name, "ipsec%d", j); + ioctl(sock, SIOCGIFADDR, &physreq); + ioctl(sock, SIOCGIFADDR, &ipsecreq); + inp1 = (struct sockaddr_in *)&physreq.ifr_addr; + inp2 = (struct sockaddr_in *)&ipsecreq.ifr_addr; + if (inp1->sin_addr.s_addr != inp2->sin_addr.s_addr) + { + plog("IP address of physical interface changed " + "-> reinit of ipsec interface"); + _iface_down (sock, &(_ipsec_if[n])); + } + ret += _iface_up (sock, &(_ipsec_if[n]), phys, omtu, nat_t); + } + else + { + ret += _iface_down (sock, &(_ipsec_if[n])); + } + } + } + } + else if (j == 0) + { + /* Only log in the first loop */ + plog("ignoring invalid interface '%s'", *i); + } + } + if (!found) + ret += _iface_down (sock, &(_ipsec_if[j])); + } + + close(sock); + return ret; /* = number of changes - 'whack --listen' if > 0 */ +} + +/* + * initialize a defaultroute_t struct + */ +static void +init_defaultroute(defaultroute_t *defaultroute) +{ + memset(defaultroute, 0, sizeof(defaultroute_t)); +} + +/* + * discover the default route via /proc/net/route + */ +void +get_defaultroute(defaultroute_t *defaultroute) +{ + FILE *fd; + char line[BUF_LEN]; + bool first = TRUE; + + init_defaultroute(defaultroute); + + fd = fopen("/proc/net/route", "r"); + + if (!fd) + { + plog("could not open 'proc/net/route'"); + return; + } + + while (fgets(line, sizeof(line), fd) != 0) + { + char iface[11]; + char destination[9]; + char gateway[11]; + char flags[5]; + char mask[9]; + + int refcnt; + int use; + int metric; + int items; + + /* proc/net/route returns IP addresses in host order */ + strcpy(gateway, "0h"); + + /* skip the header line */ + if (first) + { + first = FALSE; + continue; + } + + /* parsing a single line of proc/net/route */ + items = sscanf(line, "%10s\t%8s\t%8s\t%5s\t%d\t%d\t%d\t%8s\t" + , iface, destination, gateway+2, flags, &refcnt, &use, &metric, mask); + if (items < 8) + { + plog("parsing error while scanning /proc/net/route"); + continue; + } + + /* check for defaultroute (destination 0.0.0.0 and mask 0.0.0.0) */ + if (streq(destination, "00000000") && streq(mask, "00000000")) + { + if (defaultroute->defined) + { + plog("multiple default routes - cannot cope with %%defaultroute!!!"); + defaultroute->defined = FALSE; + fclose(fd); + return; + } + ttoaddr(gateway, strlen(gateway), AF_INET, &defaultroute->nexthop); + strncpy(defaultroute->iface, iface, IFNAMSIZ); + defaultroute->defined = TRUE; + } + } + fclose(fd); + + if (!defaultroute->defined) + { + plog("no default route - cannot cope with %%defaultroute!!!"); + } + else + { + char addr_buf[20], nexthop_buf[20]; + struct ifreq physreq; + + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + /* determine IP address of iface */ + if (sock < 0) + { + plog("could not open SOCK_DGRAM socket"); + defaultroute->defined = FALSE; + return; + } + memset ((void*)&physreq, 0, sizeof(physreq)); + strncpy(physreq.ifr_name, defaultroute->iface, IFNAMSIZ); + ioctl(sock, SIOCGIFADDR, &physreq); + close(sock); + defaultroute->addr.u.v4 = *((struct sockaddr_in *)&physreq.ifr_addr); + + addrtot(&defaultroute->addr, 0, addr_buf, sizeof(addr_buf)); + addrtot(&defaultroute->nexthop, 0, nexthop_buf, sizeof(nexthop_buf)); + + DBG(DBG_CONTROL, + DBG_log("Default route found: iface=%s, addr=%s, nexthop=%s" + , defaultroute->iface, addr_buf, nexthop_buf) + ) + + /* for backwards-compatibility with the awk shell scripts + * store the defaultroute in /var/run/ipsec.info + */ + fd = fopen(INFO_FILE, "w"); + + if (fd) + { + fprintf(fd, "defaultroutephys=%s\n", defaultroute->iface ); + fprintf(fd, "defaultroutevirt=ipsec0\n"); + fprintf(fd, "defaultrouteaddr=%s\n", addr_buf); + fprintf(fd, "defaultroutenexthop=%s\n", nexthop_buf); + fclose(fd); + } + } + return; +} diff --git a/src/starter/interfaces.h b/src/starter/interfaces.h new file mode 100644 index 000000000..9898c0516 --- /dev/null +++ b/src/starter/interfaces.h @@ -0,0 +1,41 @@ +/* strongSwan IPsec interfaces management + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: interfaces.h,v 1.6 2006/01/06 20:24:07 as Exp $ + */ + +#ifndef _STARTER_INTERFACES_H_ +#define _STARTER_INTERFACES_H_ + +#include <linux/if.h> + +#include "../pluto/constants.h" + +typedef struct { + bool defined; + char iface[IFNAMSIZ]; + ip_address addr; + ip_address nexthop; +} defaultroute_t; + +extern void starter_ifaces_init (void); +extern int starter_iface_find(char *iface, int af, ip_address *dst + , ip_address *nh); +extern int starter_ifaces_load (char **ifaces, unsigned int omtu, bool nat_t + , defaultroute_t *defaultroute); +extern void starter_ifaces_clear (void); +extern void get_defaultroute(defaultroute_t *defaultroute); + + +#endif /* _STARTER_INTERFACES_H_ */ + diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c new file mode 100644 index 000000000..e97c8388b --- /dev/null +++ b/src/starter/invokecharon.c @@ -0,0 +1,251 @@ +/* strongSwan charon launcher + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil + * + * Ported from invokepluto.c to fit charons needs. + * + * 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. + * + * RCSID $Id: invokecharon.c $ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "confread.h" +#include "invokecharon.h" +#include "files.h" + +static int _charon_pid = 0; +static int _stop_requested; + +pid_t +starter_charon_pid(void) +{ + return _charon_pid; +} + +void +starter_charon_sigchild(pid_t pid) +{ + if (pid == _charon_pid) + { + _charon_pid = 0; + if (!_stop_requested) + { + plog("charon has died -- restart scheduled (%dsec)" + , CHARON_RESTART_DELAY); + alarm(CHARON_RESTART_DELAY); // restart in 5 sec + } + unlink(CHARON_PID_FILE); + } +} + +int +starter_stop_charon (void) +{ + pid_t pid; + int i; + + pid = _charon_pid; + if (pid) + { + _stop_requested = 1; + + /* be more and more aggressive */ + for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++) + { + if (i == 0) + kill(pid, SIGINT); + else if (i < 10) + kill(pid, SIGTERM); + else + kill(pid, SIGKILL); + usleep(20000); + } + if (_charon_pid == 0) + return 0; + plog("starter_stop_charon(): can't stop charon !!!"); + return -1; + } + else + { + plog("stater_stop_charon(): charon is not started..."); + } + return -1; +} + + +int +starter_start_charon (starter_config_t *cfg, bool debug) +{ + int pid, i; + struct stat stb; + int argc = 1; + char *arg[] = { + CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + + if (!debug) + { + arg[argc++] = "--use-syslog"; + } + if (cfg->setup.strictcrlpolicy) + { + arg[argc++] = "--strictcrlpolicy"; + } + if (cfg->setup.cachecrls) + { + arg[argc++] = "--cachecrls"; + } + if (cfg->setup.crlcheckinterval > 0) + { + char buffer[BUF_LEN]; + + snprintf(buffer, BUF_LEN, "%u", cfg->setup.crlcheckinterval); + arg[argc++] = "--crlcheckinterval"; + arg[argc++] = buffer; + } + if (cfg->setup.eapdir) + { + arg[argc++] = "--eapdir"; + arg[argc++] = cfg->setup.eapdir; + } + + { /* parse debug string */ + char *pos, *level, *buf_pos, type[4], buffer[BUF_LEN]; + pos = cfg->setup.charondebug; + buf_pos = buffer; + while (pos && sscanf(pos, "%4s %d,", type, &level) == 2) + { + snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type); + arg[argc++] = buf_pos; + buf_pos += strlen(buf_pos) + 1; + if (buf_pos >= buffer + sizeof(buffer)) + { + break; + } + snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level); + arg[argc++] = buf_pos; + buf_pos += strlen(buf_pos) + 1; + if (buf_pos >= buffer + sizeof(buffer)) + { + break; + } + + /* get next */ + pos = strchr(pos, ','); + if (pos) + { + pos++; + } + } + } + + if (_charon_pid) + { + plog("starter_start_charon(): charon already started..."); + return -1; + } + else + { + unlink(CHARON_CTL_FILE); + _stop_requested = 0; + + /* if ipsec.secrets file is missing then generate RSA default key pair */ + if (stat(SECRETS_FILE, &stb) != 0) + { + mode_t oldmask; + FILE *f; + + plog("no %s file, generating RSA key", SECRETS_FILE); + system("ipsec scepclient --out pkcs1 --out cert-self --quiet"); + + /* ipsec.secrets is root readable only */ + oldmask = umask(0066); + + f = fopen(SECRETS_FILE, "w"); + if (f) + { + fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n"); + fprintf(f, "\n"); + fprintf(f, ": RSA myKey.der\n"); + fclose(f); + } + umask(oldmask); + } + + pid = fork(); + switch (pid) + { + case -1: + plog("can't fork(): %s", strerror(errno)); + return -1; + case 0: + /* child */ + setsid(); + sigprocmask(SIG_SETMASK, 0, NULL); + execv(arg[0], arg); + plog("can't execv(%s,...): %s", arg[0], strerror(errno)); + exit(1); + default: + /* father */ + _charon_pid = pid; + for (i = 0; i < 50 && _charon_pid; i++) + { + /* wait for charon */ + usleep(20000); + if (stat(CHARON_PID_FILE, &stb) == 0) + { + DBG(DBG_CONTROL, + DBG_log("charon (%d) started", _charon_pid) + ) + return 0; + } + } + if (_charon_pid) + { + /* If charon is started but with no ctl file, stop it */ + plog("charon too long to start... - kill kill"); + for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++) + { + if (i == 0) + kill(pid, SIGINT); + else if (i < 10) + kill(pid, SIGTERM); + else + kill(pid, SIGKILL); + usleep(20000); + } + } + else + { + plog("charon refused to be started"); + } + return -1; + } + } + return -1; +} diff --git a/src/starter/invokecharon.h b/src/starter/invokecharon.h new file mode 100644 index 000000000..b18dba362 --- /dev/null +++ b/src/starter/invokecharon.h @@ -0,0 +1,31 @@ +/* strongSwan charon launcher + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil + * + * Ported from invokepluto.h to fit charons needs. + * + * 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. + * + * RCSID $Id: invokecharon.h $ + */ + +#ifndef _STARTER_CHARON_H_ +#define _STARTER_CHARON_H_ + +#define CHARON_RESTART_DELAY 5 + +extern void starter_charon_sigchild (pid_t pid); +extern pid_t starter_charon_pid (void); +extern int starter_stop_charon (void); +extern int starter_start_charon(struct starter_config *cfg, bool debug); + +#endif /* _STARTER_CHARON_H_ */ + diff --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c new file mode 100644 index 000000000..1b11b4a10 --- /dev/null +++ b/src/starter/invokepluto.c @@ -0,0 +1,286 @@ +/* strongSwan Pluto launcher + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: invokepluto.c,v 1.12 2006/02/17 21:41:50 as Exp $ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "confread.h" +#include "invokepluto.h" +#include "files.h" +#include "starterwhack.h" +# +static int _pluto_pid = 0; +static int _stop_requested; + +pid_t +starter_pluto_pid(void) +{ + return _pluto_pid; +} + +void +starter_pluto_sigchild(pid_t pid) +{ + if (pid == _pluto_pid) + { + _pluto_pid = 0; + if (!_stop_requested) + { + plog("pluto has died -- restart scheduled (%dsec)" + , PLUTO_RESTART_DELAY); + alarm(PLUTO_RESTART_DELAY); // restart in 5 sec + } + unlink(PLUTO_PID_FILE); + } +} + +int +starter_stop_pluto (void) +{ + pid_t pid; + int i; + + pid = _pluto_pid; + if (pid) + { + _stop_requested = 1; + if (starter_whack_shutdown() == 0) + { + for (i = 0; i < 20; i++) + { + usleep(20000); + if (_pluto_pid == 0) + return 0; + } + } + /* be more and more aggressive */ + for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++) + { + if (i < 10) + kill(pid, SIGTERM); + else + kill(pid, SIGKILL); + usleep(20000); + } + if (_pluto_pid == 0) + return 0; + plog("starter_stop_pluto(): can't stop pluto !!!"); + return -1; + } + else + { + plog("stater_stop_pluto(): pluto is not started..."); + } + return -1; +} + +#define ADD_DEBUG(v) { \ + for (l = cfg->setup.plutodebug; l && *l; l++) if (streq(*l, v)) \ + arg[argc++] = "--debug-" v; \ + } + +int +starter_start_pluto (starter_config_t *cfg, bool debug) +{ + int i; + struct stat stb; + pid_t pid; + char **l; + int argc = 2; + char *arg[] = { + PLUTO_CMD, "--nofork" + , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + + printf ("starter_start_pluto entered\n"); + + if (debug) + { + arg[argc++] = "--stderrlog"; + } + if (cfg->setup.uniqueids) + { + arg[argc++] = "--uniqueids"; + } + ADD_DEBUG("none") + ADD_DEBUG("all") + ADD_DEBUG("raw") + ADD_DEBUG("crypt") + ADD_DEBUG("parsing") + ADD_DEBUG("emitting") + ADD_DEBUG("control") + ADD_DEBUG("lifecycle") + ADD_DEBUG("klips") + ADD_DEBUG("dns") + ADD_DEBUG("natt") + ADD_DEBUG("oppo") + ADD_DEBUG("controlmore") + ADD_DEBUG("private") + if (cfg->setup.crlcheckinterval > 0) + { + static char buf1[15]; + + arg[argc++] = "--crlcheckinterval"; + snprintf(buf1, sizeof(buf1), "%u", cfg->setup.crlcheckinterval); + arg[argc++] = buf1; + } + if (cfg->setup.cachecrls) + { + arg[argc++] = "--cachecrls"; + } + if (cfg->setup.strictcrlpolicy) + { + arg[argc++] = "--strictcrlpolicy"; + } + if (cfg->setup.nocrsend) + { + arg[argc++] = "--nocrsend"; + } + if (cfg->setup.nat_traversal) + { + arg[argc++] = "--nat_traversal"; + } + if (cfg->setup.keep_alive) + { + static char buf2[15]; + + arg[argc++] = "--keep_alive"; + snprintf(buf2, sizeof(buf2), "%u", cfg->setup.keep_alive); + arg[argc++] = buf2; + } +#ifdef VIRTUAL_IP + if (cfg->setup.virtual_private) + { + arg[argc++] = "--virtual_private"; + arg[argc++] = cfg->setup.virtual_private; + } +#endif + if (cfg->setup.pkcs11module) + { + arg[argc++] = "--pkcs11module"; + arg[argc++] = cfg->setup.pkcs11module; + } + if (cfg->setup.pkcs11keepstate) + { + arg[argc++] = "--pkcs11keepstate"; + } + if (cfg->setup.pkcs11proxy) + { + arg[argc++] = "--pkcs11proxy"; + } + + if (_pluto_pid) + { + plog("starter_start_pluto(): pluto already started..."); + return -1; + } + else + { + unlink(PLUTO_CTL_FILE); + _stop_requested = 0; + + if (cfg->setup.prepluto) + system(cfg->setup.prepluto); + + /* if ipsec.secrets file is missing then generate RSA default key pair */ + if (stat(SECRETS_FILE, &stb) != 0) + { + mode_t oldmask; + FILE *f; + + plog("no %s file, generating RSA key", SECRETS_FILE); + system("ipsec scepclient --out pkcs1 --out cert-self --quiet"); + + /* ipsec.secrets is root readable only */ + oldmask = umask(0066); + + f = fopen(SECRETS_FILE, "w"); + if (f) + { + fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n"); + fprintf(f, "\n"); + fprintf(f, ": RSA myKey.der\n"); + fclose(f); + } + umask(oldmask); + } + + pid = fork(); + switch (pid) + { + case -1: + plog("can't fork(): %s", strerror(errno)); + return -1; + case 0: + /* child */ + setsid(); + sigprocmask(SIG_SETMASK, 0, NULL); + execv(arg[0], arg); + plog("can't execv(%s,...): %s", arg[0], strerror(errno)); + exit(1); + default: + /* father */ + _pluto_pid = pid; + for (i = 0; i < 50 && _pluto_pid; i++) + { + /* wait for pluto */ + usleep(20000); + if (stat(PLUTO_CTL_FILE, &stb) == 0) + { + DBG(DBG_CONTROL, + DBG_log("pluto (%d) started", _pluto_pid) + ) + if (cfg->setup.postpluto) + system(cfg->setup.postpluto); + return 0; + } + } + if (_pluto_pid) + { + /* If pluto is started but with no ctl file, stop it */ + plog("pluto too long to start... - kill kill"); + for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++) + { + if (i < 10) + kill(pid, SIGTERM); + else + kill(pid, SIGKILL); + usleep(20000); + } + } + else + { + plog("pluto refused to be started"); + } + return -1; + } + } + return -1; +} diff --git a/src/starter/invokepluto.h b/src/starter/invokepluto.h new file mode 100644 index 000000000..26858f9b2 --- /dev/null +++ b/src/starter/invokepluto.h @@ -0,0 +1,28 @@ +/* strongSwan pluto launcher + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: invokepluto.h,v 1.3 2006/01/04 23:30:24 as Exp $ + */ + +#ifndef _STARTER_PLUTO_H_ +#define _STARTER_PLUTO_H_ + +#define PLUTO_RESTART_DELAY 5 + +extern void starter_pluto_sigchild (pid_t pid); +extern pid_t starter_pluto_pid (void); +extern int starter_stop_pluto (void); +extern int starter_start_pluto (struct starter_config *cfg, bool debug); + +#endif /* _STARTER_PLUTO_H_ */ + diff --git a/src/starter/ipsec.conf b/src/starter/ipsec.conf new file mode 100644 index 000000000..76b85b23a --- /dev/null +++ b/src/starter/ipsec.conf @@ -0,0 +1,42 @@ +# ipsec.conf - strongSwan IPsec configuration file + +# Manual: man 5 ipsec.conf +# Help: http://www.strongswan.org/docs/readme.htm + +version 2.0 # conforms to second version of ipsec.conf specification + +# basic configuration + +config setup + # Debug-logging controls: "none" for (almost) none, "all" for lots. + # plutodebug=all + # crlcheckinterval=600 + # strictcrlpolicy=yes + # cachecrls=yes + # nat_traversal=yes + # charonstart=no + # plutostart=no + +# Add connections here. + +# Sample VPN connections + +#conn sample-self-signed +# left=%defaultroute +# leftsubnet=10.1.0.0/16 +# leftcert=selfCert.der +# leftsendcert=never +# right=192.168.0.2 +# rightsubnet=10.2.0.0/16 +# rightcert=peerCert.der +# auto=start + +#conn sample-with-ca-cert +# left=%defaultroute +# leftsubnet=10.1.0.0/16 +# leftcert=myCert.pem +# right=192.168.0.2 +# rightsubnet=10.2.0.0/16 +# rightid="C=CH, O=Linux strongSwan CN=peer name" +# keyexchange=ikev2 +# auto=start diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5 new file mode 100644 index 000000000..3e59190e3 --- /dev/null +++ b/src/starter/ipsec.conf.5 @@ -0,0 +1,1062 @@ +.TH IPSEC.CONF 5 "20 Jan 2006" +.\" RCSID $Id: ipsec.conf.5,v 1.2 2006/01/22 15:33:46 as Exp $ +.SH NAME +ipsec.conf \- IPsec configuration and connections +.SH DESCRIPTION +The optional +.I ipsec.conf +file +specifies most configuration and control information for the +strongSwan IPsec subsystem. +(The major exception is secrets for authentication; +see +.IR ipsec.secrets (5).) +Its contents are not security-sensitive. +.PP +The file is a text file, consisting of one or more +.IR sections . +White space followed by +.B # +followed by anything to the end of the line +is a comment and is ignored, +as are empty lines which are not within a section. +.PP +A line which contains +.B include +and a file name, separated by white space, +is replaced by the contents of that file, +preceded and followed by empty lines. +If the file name is not a full pathname, +it is considered to be relative to the directory containing the +including file. +Such inclusions can be nested. +Only a single filename may be supplied, and it may not contain white space, +but it may include shell wildcards (see +.IR sh (1)); +for example: +.PP +.B include +.B "ipsec.*.conf" +.PP +The intention of the include facility is mostly to permit keeping +information on connections, or sets of connections, +separate from the main configuration file. +This permits such connection descriptions to be changed, +copied to the other security gateways involved, etc., +without having to constantly extract them from the configuration +file and then insert them back into it. +Note also the +.B also +parameter (described below) which permits splitting a single logical +section (e.g. a connection description) into several actual sections. +.PP +A section +begins with a line of the form: +.PP +.I type +.I name +.PP +where +.I type +indicates what type of section follows, and +.I name +is an arbitrary name which distinguishes the section from others +of the same type. +(Names must start with a letter and may contain only +letters, digits, periods, underscores, and hyphens.) +All subsequent non-empty lines +which begin with white space are part of the section; +comments within a section must begin with white space too. +There may be only one section of a given type with a given name. +.PP +Lines within the section are generally of the form +.PP +\ \ \ \ \ \fIparameter\fB=\fIvalue\fR +.PP +(note the mandatory preceding white space). +There can be white space on either side of the +.BR = . +Parameter names follow the same syntax as section names, +and are specific to a section type. +Unless otherwise explicitly specified, +no parameter name may appear more than once in a section. +.PP +An empty +.I value +stands for the system default value (if any) of the parameter, +i.e. it is roughly equivalent to omitting the parameter line entirely. +A +.I value +may contain white space only if the entire +.I value +is enclosed in double quotes (\fB"\fR); +a +.I value +cannot itself contain a double quote, +nor may it be continued across more than one line. +.PP +Numeric values are specified to be either an ``integer'' +(a sequence of digits) or a ``decimal number'' +(sequence of digits optionally followed by `.' and another sequence of digits). +.PP +There is currently one parameter which is available in any type of +section: +.TP +.B also +the value is a section name; +the parameters of that section are appended to this section, +as if they had been written as part of it. +The specified section must exist, must follow the current one, +and must have the same section type. +(Nesting is permitted, +and there may be more than one +.B also +in a single section, +although it is forbidden to append the same section more than once.) +.PP +A section with name +.B %default +specifies defaults for sections of the same type. +For each parameter in it, +any section of that type which does not have a parameter of the same name +gets a copy of the one from the +.B %default +section. +There may be multiple +.B %default +sections of a given type, +but only one default may be supplied for any specific parameter name, +and all +.B %default +sections of a given type must precede all non-\c +.B %default +sections of that type. +.B %default +sections may not contain the +.B also +parameter. +.PP +Currently there are three types of sections: +a +.B config +section specifies general configuration information for IPsec, a +.B conn +section specifies an IPsec connection, while a +.B ca +section specifies special properties a certification authority. +.SH "CONN SECTIONS" +A +.B conn +section contains a +.IR "connection specification" , +defining a network connection to be made using IPsec. +The name given is arbitrary, and is used to identify the connection. +Here's a simple example: +.PP +.ne 10 +.nf +.ft B +.ta 1c +conn snt + left=10.11.11.1 + leftsubnet=10.0.1.0/24 + leftnexthop=172.16.55.66 + right=192.168.22.1 + rightsubnet=10.0.2.0/24 + rightnexthop=172.16.88.99 + keyingtries=%forever +.ft +.fi +.PP +A note on terminology: There are two kinds of communications going on: +transmission of user IP packets, and gateway-to-gateway negotiations for +keying, rekeying, and general control. +The path to control the connection is called 'ISAKMP SA' in IKEv1 and +'IKE SA' in the IKEv2 protocol. That what is beeing negotiated, the kernel +level data path, is called 'IPsec SA'. +strongSwan currently uses two separate keying daemons. Pluto handles +all IKEv1 connections, Charon is the new daemon supporting the IKEv2 protocol. +Charon does not support all keywords yet. +.PP +To avoid trivial editing of the configuration file to suit it to each system +involved in a connection, +connection specifications are written in terms of +.I left +and +.I right +participants, +rather than in terms of local and remote. +Which participant is considered +.I left +or +.I right +is arbitrary; +IPsec figures out which one it is being run on based on internal information. +This permits using identical connection specifications on both ends. +There are cases where there is no symmetry; a good convention is to +use +.I left +for the local side and +.I right +for the remote side (the first letters are a good mnemonic). +.PP +Many of the parameters relate to one participant or the other; +only the ones for +.I left +are listed here, but every parameter whose name begins with +.B left +has a +.B right +counterpart, +whose description is the same but with +.B left +and +.B right +reversed. +.PP +Parameters are optional unless marked '(required)'. +.SS "CONN PARAMETERS" +Unless otherwise noted, for a connection to work, +in general it is necessary for the two ends to agree exactly +on the values of these parameters. +.TP 14 +.B type +the type of the connection; currently the accepted values +are +.B tunnel +(the default) +signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel; +.BR transport , +signifying host-to-host transport mode; +.BR passthrough , +signifying that no IPsec processing should be done at all; +.BR drop , +signifying that packets should be discarded; and +.BR reject , +signifying that packets should be discarded and a diagnostic ICMP returned. +Charon currently supports only +.BR tunnel +and +.BR transport +connection types. +.TP +.B left +(required) +the IP address of the left participant's public-network interface, +in any form accepted by +.IR ipsec_ttoaddr (3) +or one of several magic values. +If it is +.BR %defaultroute , +and +the +.B config +.B setup +section's, +.B interfaces +specification contains +.BR %defaultroute, +.B left +will be filled in automatically with the local address +of the default-route interface (as determined at IPsec startup time); +this also overrides any value supplied for +.BR leftnexthop . +(Either +.B left +or +.B right +may be +.BR %defaultroute , +but not both.) +The value +.B %any +signifies an address to be filled in (by automatic keying) during +negotiation. +.TP +.B leftsubnet +private subnet behind the left participant, expressed as +\fInetwork\fB/\fInetmask\fR +(actually, any form acceptable to +.IR ipsec_ttosubnet (3)); +if omitted, essentially assumed to be \fIleft\fB/32\fR, +signifying that the left end of the connection goes to the left participant +only. When using IKEv2, the configured subnet of the peers may differ, the +protocol narrows it to the greates common subnet. +.TP +.B leftnexthop +next-hop gateway IP address for the left participant's connection +to the public network; +defaults to +.B %direct +(meaning +.IR right ). +If the value is to be overridden by the +.B left=%defaultroute +method (see above), +an explicit value must +.I not +be given. +If that method is not being used, +but +.B leftnexthop +is +.BR %defaultroute , +and +.B interfaces=%defaultroute +is used in the +.B config +.B setup +section, +the next-hop gateway address of the default-route interface +will be used. +The magic value +.B %direct +signifies a value to be filled in (by automatic keying) +with the peer's address. +Relevant only locally, other end need not agree on it. Currently not supported +in IKEv2. +.TP +.B leftupdown +what ``updown'' script to run to adjust routing and/or firewalling +when the status of the connection +changes (default +.BR "ipsec _updown" ). +May include positional parameters separated by white space +(although this requires enclosing the whole string in quotes); +including shell metacharacters is unwise. +See +.IR ipsec_pluto (8) +for details. +Relevant only locally, other end need not agree on it. IKEv2 uses the updown +script to insert firewall rules only. Routing is not support and will be +implemented directly into Charon. +.TP +.B leftfirewall +whether the left participant is doing forwarding-firewalling +(including masquerading) for traffic from \fIleftsubnet\fR, +which should be turned off (for traffic to the other subnet) +once the connection is established; +acceptable values are +.B yes +and (the default) +.BR no . +May not be used in the same connection description with +.BR leftupdown . +Implemented as a parameter to the default +.I updown +script. +See notes below. +Relevant only locally, other end need not agree on it. + +If one or both security gateways are doing forwarding firewalling +(possibly including masquerading), +and this is specified using the firewall parameters, +tunnels established with IPsec are exempted from it +so that packets can flow unchanged through the tunnels. +(This means that all subnets connected in this manner must have +distinct, non-overlapping subnet address blocks.) +This is done by the default +.I updown +script (see +.IR ipsec_pluto (8)). + +In situations calling for more control, +it may be preferable for the user to supply his own +.I updown +script, +which makes the appropriate adjustments for his system. +.TP +.B auto +what operation, if any, should be done automatically at IPsec startup; +currently-accepted values are +.B add +, +.B route +, +.B start +and +.B ignore +. +.B add +loads a connection without starting it. +.B route +loads a connection and installs kernel traps. If traffic is detected between +.B leftsubnet +and +.B rightsubnet +, a connection is established. +.B start +loads a connection and brings it up immediatly. +.B ignore +ignores the connection. This is equal to delete a connection from the config +file. +Relevant only locally, other end need not agree on it +(but in general, for an intended-to-be-permanent connection, +both ends should use +.B auto=start +to ensure that any reboot causes immediate renegotiation). +.TP +.B auth +whether authentication should be done as part of +ESP encryption, or separately using the AH protocol; +acceptable values are +.B esp +(the default) and +.BR ah . +The IKEv2 daemon currently supports only ESP. +.TP +.B authby +how the two security gateways should authenticate each other; +acceptable values are +.B secret +for shared secrets, +.B rsasig +for RSA digital signatures (the default), +.B secret|rsasig +for either, and +.B never +if negotiation is never to be attempted or accepted (useful for shunt-only conns). +Digital signatures are superior in every way to shared secrets. In IKEv2, the +two ends must not agree on this parameter, it is relevant for the own +authentication method only. IKEv2 additionally supports the value +.B eap, +which indicates an initiator to request EAP authentication. The EAP method to +use is selected by the server (see +.B eap). +.TP +.B compress +whether IPComp compression of content is proposed on the connection +(link-level compression does not work on encrypted data, +so to be effective, compression must be done \fIbefore\fR encryption); +acceptable values are +.B yes +and +.B no +(the default). A value of +.B yes +causes IPsec to propose both compressed and uncompressed, +and prefer compressed. +A value of +.B no +prevents IPsec from proposing compression; +a proposal to compress will still be accepted. +IKEv2 does not support IP compression yet. +.TP +.B dpdaction +controls the use of the Dead Peer Detection protocol (DPD, RFC 3706) where +R_U_THERE notification messages (IKEv1) or empty INFORMATIONAL messages (IKEv2) +are periodically sent in order to check the +liveliness of the IPsec peer. The values +.B clear +and +.B hold +both activate DPD. If no activity is detected, all connections with a dead peer +are stopped and unrouted ( +.B clear +) or put in the hold state ( +.B hold +). For +.B IKEv1 +, the default is +.B none +which disables the active sending of R_U_THERE notifications. +Nevertheless pluto will always send the DPD Vendor ID during connection set up +in order to signal the readiness to act passively as a responder if the peer +wants to use DPD. For +.B IKEv2, none +does't make sense, as all messages are used to detect dead peers. If specified, +it has the same meaning as the default ( +.B clear +). +.TP +.B dpddelay +defines the period time interval with which R_U_THERE messages/INFORMATIONAL +exchanges are sent to the peer. These are only sent if no other traffic is +received. In IKEv2, a value of 0 sends no additional INFORMATIONAL +messages and uses only standard messages (such as those to rekey) to detect +dead peers. +.TP +.B dpdtimeout +defines the timeout interval, after which all connections to a peer are deleted +in case of inactivity. This only applies to IKEv1, in IKEv2 the default +retransmission timeout applies, as every exchange is used to detect dead peers. +.TP +.B failureshunt +what to do with packets when negotiation fails. +The default is +.BR none : +no shunt; +.BR passthrough , +.BR drop , +and +.B reject +have the obvious meanings. Has no effect in IKEv2 yet. +.TP +.B ikelifetime +how long the keying channel of a connection ('ISAKMP/IKE SA') +should last before being renegotiated. +.TP +.B keyexchange +method of key exchange; +which protocol should be used to initialize the connection. Connections marked with +.B ikev1 +are initiated with pluto, those marked with +.B ikev2 +with charon. An incoming request from the remote peer is handled by the correct +daemon, unaffected from the +.B keyexchange +setting. The default value +.B ike +currently behaves exactly as +.B ikev1. +.TP +.B keyingtries +how many attempts (a whole number or \fB%forever\fP) should be made to +negotiate a connection, or a replacement for one, before giving up +(default +.BR %forever ). +The value \fB%forever\fP +means 'never give up'. +Relevant only locally, other end need not agree on it. +.TP +.B keylife +how long a particular instance of a connection +(a set of encryption/authentication keys for user packets) should last, +from successful negotiation to expiry; +acceptable values are an integer optionally followed by +.BR s +(a time in seconds) +or a decimal number followed by +.BR m , +.BR h , +or +.B d +(a time +in minutes, hours, or days respectively) +(default +.BR 1h , +maximum +.BR 24h ). +Normally, the connection is renegotiated (via the keying channel) +before it expires. +The two ends need not exactly agree on +.BR keylife , +although if they do not, +there will be some clutter of superseded connections on the end +which thinks the lifetime is longer. +.TP +.B leftca +the distinguished name of a certificate authority which is required to +lie in the trust path going from the left participant's certificate up +to the root certification authority. +.TP +.B leftcert +the path to the left participant's X.509 certificate. The file can be coded either in +PEM or DER format. OpenPGP certificates are supported as well. +Both absolute paths or paths relative to +.B /etc/ipsec.d/certs +are accepted. By default +.B leftcert +sets +.B leftid +to the distinguished name of the certificate's subject and +.B leftca +to the distinguished name of the certificate's issuer. +The left participant's ID can be overriden by specifying a +.B leftid +value which must be certified by the certificate, though. +.TP +.B leftgroups +a comma separated list of group names. If the +.B leftgroups +parameter is present then the peer must be a member of at least one +of the groups defined by the parameter. Group membership must be certified +by a valid attribute certificate stored in \fI/etc/ipsec.d/acerts\fP thas has been +issued to the peer by a trusted Authorization Authority stored in +\fI/etc/ipsec.d/aacerts\fP. Attribute certificates are not supported in IKEv2 yet. +.TP +.B leftid +how +the left participant +should be identified for authentication; +defaults to +.BR left . +Can be an IP address (in any +.IR ipsec_ttoaddr (3) +syntax) +or a fully-qualified domain name preceded by +.B @ +(which is used as a literal string and not resolved). +The magic value +.B %myid +stands for the current setting of \fImyid\fP. +This is set in \fBconfig setup\fP or by \fIipsec_whack\fP(8)), or, if not set, +it is the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise +it is the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined. +.TP +.B leftsourceip +The internal source IP to use in a tunnel, also known as virtual IP. If the +value is +.B %modeconfig +or +.B %config, +an address is requested from the peer. +.TP +.B leftsubnetwithin +Not relevant for IKEv2, as subnets are narrowed. +.TP +.B pfs +whether Perfect Forward Secrecy of keys is desired on the connection's +keying channel +(with PFS, penetration of the key-exchange protocol +does not compromise keys negotiated earlier); +acceptable values are +.B yes +(the default) +and +.BR no +. IKEv2 always uses PFS for IKE_SA rekeying. PFS for rekeying IPsec SAs is +currently not supported. +.TP +.B rekey +whether a connection should be renegotiated when it is about to expire; +acceptable values are +.B yes +(the default) +and +.BR no . +The two ends need not agree, +but while a value of +.B no +prevents Pluto/Charon from requesting renegotiation, +it does not prevent responding to renegotiation requested from the other end, +so +.B no +will be largely ineffective unless both ends agree on it. +.TP +.B reauth +whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1, +reauthentication is always done. In IKEv2, a value of +.B no +rekeys without uninstalling the IPsec SAs, a value of +.B yes +(the default) creates a new IKE_SA from scratch and tries to recreate +all IPsec SAs. +.TP +.B rekeyfuzz +maximum percentage by which +.B rekeymargin +should be randomly increased to randomize rekeying intervals +(important for hosts with many connections); +acceptable values are an integer, +which may exceed 100, +followed by a `%' +(default set by +.IR ipsec_pluto (8), +currently +.BR 100% ). +The value of +.BR rekeymargin , +after this random increase, +must not exceed +.BR keylife . +The value +.B 0% +will suppress time randomization. +Relevant only locally, other end need not agree on it. +.TP +.B rekeymargin +how long before connection expiry or keying-channel expiry +should attempts to +negotiate a replacement +begin; acceptable values as for +.B keylife +(default +.BR 9m ). +Relevant only locally, other end need not agree on it. +.TP +.B ike +IKE/ISAKMP SA encryption/authentication algorithm to be used, e.g. +.B aes128-sha1-modp2048 +(encryption-integrity-dhgroup). +.TP +.B esp +ESP encryption/authentication algorithm to be used +for the connection, e.g. +.B 3des-md5 +(encryption-integrity). +.TP +.B ah +AH authentication algorithm to be used +for the connection, e.g. +.B hmac-md5. +.SH "CA SECTIONS" +This are optional sections that can be used to assign special +parameters to a Certification Authority (CA). These parameters are not +supported in IKEv2 yet. +.TP 10 +.B auto +currently can have either the value +.B ignore +or +.B add +. +.TP +.B cacert +defines a path to the CA certificate either relative to +\fI/etc/ipsec.d/cacerts\fP or as an absolute path. +.TP +.B crluri +defines a CRL distribution point (ldap, http, or file URI) +.TP +.B crluri2 +defines an alternative CRL distribution point (ldap, http, or file URI) +.TP +.B ldaphost +defines an ldap host. +.TP +.B ocspuri +defines an OCSP URI. +.SH "CONFIG SECTIONS" +At present, the only +.B config +section known to the IPsec software is the one named +.BR setup , +which contains information used when the software is being started +(see +.IR ipsec_setup (8)). +Here's an example: +.PP +.ne 8 +.nf +.ft B +.ta 1c +config setup + interfaces="ipsec0=eth1 ipsec1=ppp0" + klipsdebug=none + plutodebug=all + manualstart= +.ft +.fi +.PP +Parameters are optional unless marked ``(required)''. +The currently-accepted +.I parameter +names in a +.B config +.B setup +section are: +.TP 14 +.B myid +the identity to be used for +.BR %myid . +.B %myid +is used in the implicit policy group conns and can be used as +an identity in explicit conns. +If unspecified, +.B %myid +is set to the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise +the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined. +An explicit value generally starts with ``\fB@\fP''. +.TP +.B interfaces +virtual and physical interfaces for IPsec to use: +a single +\fIvirtual\fB=\fIphysical\fR pair, a (quoted!) list of pairs separated +by white space, or +.BR %none . +One of the pairs may be written as +.BR %defaultroute , +which means: find the interface \fId\fR that the default route points to, +and then act as if the value was ``\fBipsec0=\fId\fR''. +.B %defaultroute +is the default; +.B %none +must be used to denote no interfaces. +If +.B %defaultroute +is used (implicitly or explicitly) +information about the default route and its interface is noted for +use by +.IR ipsec_manual (8) +and +.IR ipsec_auto (8).) +.TP +.B forwardcontrol +whether +.I setup +should turn IP forwarding on +(if it's not already on) as IPsec is started, +and turn it off again (if it was off) as IPsec is stopped; +acceptable values are +.B yes +and (the default) +.BR no . +For this to have full effect, forwarding must be +disabled before the hardware interfaces are brought +up (e.g., +.B "net.ipv4.ip_forward\ =\ 0" +in Red Hat 6.x +.IR /etc/sysctl.conf ), +because IPsec doesn't get control early enough to do that. +.TP +.B rp_filter +whether and how +.I setup +should adjust the reverse path filtering mechanism for the +physical devices to be used. +Values are \fB%unchanged\fP (to leave it alone) +or \fB0\fP, \fB1\fP, \fB2\fP (values to set it to). +\fI/proc/sys/net/ipv4/conf/PHYS/rp_filter\fP +is badly documented; it must be \fB0\fP in many cases +for ipsec to function. +The default value for the parameter is \fB0\fP. +.TP +.B syslog +the +.IR syslog (2) +``facility'' name and priority to use for +startup/shutdown log messages, +default +.BR daemon.error . +.TP +.B plutodebug +how much Pluto debugging output should be logged. +An empty value, +or the magic value +.BR none , +means no debugging output (the default). +The magic value +.B all +means full output. +Otherwise only the specified types of output +(a quoted list, names without the +.B \-\-debug\- +prefix, +separated by white space) are enabled; +for details on available debugging types, see +.IR ipsec_pluto (8). +.TP +.B charondebug +how much Charon debugging output should be logged. +A comma separated list containing type level/pairs may +be specified, e.g: +.B dmn 3, ike 1, net -1. +Acceptable values for types are +.B dmn, mgr, ike, chd, job, cfg, knl, net, enc, lib +and the level is one of +.B -1, 0, 1, 2, 3, 4 +(for silent, audit, control, controlmore, raw, private) +.TP +.B plutoopts +additional options to pass to pluto upon startup. See +.IR ipsec_pluto (8). +.TP +.B plutostderrlog +do not use syslog, but rather log to stderr, and direct stderr to the +argument file. +.TP +.B dumpdir +in what directory should things started by +.I setup +(notably the Pluto daemon) be allowed to +dump core? +The empty value (the default) means they are not +allowed to. +.TP +.B pluto +whether to start Pluto or not; +Values are +.B yes +(the default) +or +.B no +(useful only in special circumstances). +.TP +.B plutowait +should Pluto wait for each +negotiation attempt that is part of startup to +finish before proceeding with the next? +Values are +.B yes +or +.BR no +(the default). +.TP +.B prepluto +shell command to run before starting Pluto +(e.g., to decrypt an encrypted copy of the +.I ipsec.secrets +file). +It's run in a very simple way; +complexities like I/O redirection are best hidden within a script. +Any output is redirected for logging, +so running interactive commands is difficult unless they use +.I /dev/tty +or equivalent for their interaction. +Default is none. +.TP +.B postpluto +shell command to run after starting Pluto +(e.g., to remove a decrypted copy of the +.I ipsec.secrets +file). +It's run in a very simple way; +complexities like I/O redirection are best hidden within a script. +Any output is redirected for logging, +so running interactive commands is difficult unless they use +.I /dev/tty +or equivalent for their interaction. +Default is none. +.TP +.B fragicmp +whether a tunnel's need to fragment a packet should be reported +back with an ICMP message, +in an attempt to make the sender lower his PMTU estimate; +acceptable values are +.B yes +(the default) +and +.BR no . +.TP +.B hidetos +whether a tunnel packet's TOS field should be set to +.B 0 +rather than copied from the user packet inside; +acceptable values are +.B yes +(the default) +and +.BR no . +.TP +.B uniqueids +whether a particular participant ID should be kept unique, +with any new (automatically keyed) +connection using an ID from a different IP address +deemed to replace all old ones using that ID; +acceptable values are +.B yes +(the default) +and +.BR no . +Participant IDs normally \fIare\fR unique, +so a new (automatically-keyed) connection using the same ID is +almost invariably intended to replace an old one. +.TP +.B overridemtu +value that the MTU of the ipsec\fIn\fR interface(s) should be set to, +overriding IPsec's (large) default. +This parameter is needed only in special situations. +.TP +.B nat_traversal +.TP +.B crlcheckinterval +.TP +.B strictcrlpolicy +.TP +.B pkcs11module +.TP +.B pkcs11keepstate + +.SH CHOOSING A CONNECTION +.PP +When choosing a connection to apply to an outbound packet caught with a +.BR %trap, +the system prefers the one with the most specific eroute that +includes the packet's source and destination IP addresses. +Source subnets are examined before destination subnets. +For initiating, only routed connections are considered. For responding, +unrouted but added connections are considered. +.PP +When choosing a connection to use to respond to a negotiation which +doesn't match an ordinary conn, an opportunistic connection +may be instantiated. Eventually, its instance will be /32 -> /32, but +for earlier stages of the negotiation, there will not be enough +information about the client subnets to complete the instantiation. +.SH FILES +.nf +/etc/ipsec.conf +/etc/ipsec.d/cacerts +/etc/ipsec.d/certs +/etc/ipsec.d/crls +/etc/ipsec.d/aacerts +/etc/ipsec.d/acerts + +.SH SEE ALSO +ipsec(8), ipsec_ttoaddr(8), ipsec_auto(8), ipsec_manual(8), ipsec_rsasigkey(8) +.SH HISTORY +Written for the FreeS/WAN project +<http://www.freeswan.org> +by Henry Spencer. Extended for the strongSwan project +<http://www.strongswan.org> +by Andreas Steffen. Updated to respect IKEv2 specific configuration +by Martin Willi. +.SH BUGS +.PP +When +.B type +or +.B failureshunt +is set to +.B drop +or +.BR reject, +strongSwan blocks outbound packets using eroutes, but assumes inbound +blocking is handled by the firewall. strongSwan offers firewall hooks +via an ``updown'' script. However, the default +.B ipsec _updown +provides no help in controlling a modern firewall. +.PP +Including attributes of the keying channel +(authentication methods, +.BR ikelifetime , +etc.) +as an attribute of a connection, +rather than of a participant pair, is dubious and incurs limitations. +.PP +.IR Ipsec_manual +is not nearly as generous about the syntax of subnets, +addresses, etc. as the usual strongSwan user interfaces. +Four-component dotted-decimal must be used for all addresses. +It +.I is +smart enough to translate bit-count netmasks to dotted-decimal form. +.PP +It would be good to have a line-continuation syntax, +especially for the very long lines involved in +RSA signature keys. +.PP +The ability to specify different identities, +.BR authby , +and public keys for different automatic-keyed connections +between the same participants is misleading; +this doesn't work dependably because the identity of the participants +is not known early enough. +This is especially awkward for the ``Road Warrior'' case, +where the remote IP address is specified as +.BR 0.0.0.0 , +and that is considered to be the ``participant'' for such connections. +.PP +In principle it might be necessary to control MTU on an +interface-by-interface basis, +rather than with the single global override that +.B overridemtu +provides. +.PP +A number of features which \fIcould\fR be implemented in +both manual and automatic keying +actually are not yet implemented for manual keying. +This is unlikely to be fixed any time soon. +.PP +If conns are to be added before DNS is available, +\fBleft=\fP\fIFQDN\fP, +\fBleftnextop=\fP\fIFQDN\fP, +and +.B leftrsasigkey=%dnsonload +will fail. +.IR ipsec_pluto (8) +does not actually use the public key for our side of a conn but it +isn't generally known at a add-time which side is ours (Road Warrior +and Opportunistic conns are currently exceptions). +.PP +The \fBmyid\fP option does not affect explicit \fB ipsec auto \-\-add\fP or \fBipsec auto \-\-replace\fP commands for implicit conns. diff --git a/src/starter/keywords.c b/src/starter/keywords.c new file mode 100644 index 000000000..215b95ad6 --- /dev/null +++ b/src/starter/keywords.c @@ -0,0 +1,261 @@ +/* C code produced by gperf version 3.0.1 */ +/* Command-line: /usr/bin/gperf -C -G -t */ +/* Computed positions: -k'1-2,$' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." +#endif + + +/* strongSwan keywords + * Copyright (C) 2005 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $ + */ + +#include <string.h> + +#include "keywords.h" + +struct kw_entry { + char *name; + kw_token_t token; +}; + +#define TOTAL_KEYWORDS 90 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 17 +#define MIN_HASH_VALUE 15 +#define MAX_HASH_VALUE 188 +/* maximum key range = 174, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 40, + 10, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 80, 189, 20, + 75, 5, 95, 0, 30, 0, 189, 55, 0, 45, + 0, 35, 20, 189, 15, 70, 40, 15, 20, 189, + 0, 25, 0, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189 + }; + return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]]; +} + +static const struct kw_entry wordlist[] = + { + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, + {"leftupdown", KW_LEFTUPDOWN}, + {""}, + {"leftfirewall", KW_LEFTFIREWALL}, + {""}, {""}, {""}, + {"leftsubnetwithin", KW_LEFTSUBNETWITHIN}, + {""}, {""}, {""}, {""}, + {"rightupdown", KW_RIGHTUPDOWN}, + {""}, + {"rightfirewall", KW_RIGHTFIREWALL}, + {"rekeyfuzz", KW_REKEYFUZZ}, + {"plutodebug", KW_PLUTODEBUG}, + {"rekeymargin", KW_REKEYMARGIN}, + {"rightsubnetwithin", KW_RIGHTSUBNETWITHIN}, + {""}, + {"leftnatip", KW_LEFTNATIP}, + {""}, + {"leftnexthop", KW_LEFTNEXTHOP}, + {"leftsourceip", KW_LEFTSOURCEIP}, + {""}, {""}, + {"virtual_private", KW_VIRTUAL_PRIVATE}, + {"crluri", KW_CRLURI}, + {""}, + {"leftrsasigkey", KW_LEFTRSASIGKEY}, + {""}, + {"rightnatip", KW_RIGHTNATIP}, + {""}, + {"rightnexthop", KW_RIGHTNEXTHOP}, + {"rightsourceip", KW_RIGHTSOURCEIP}, + {"left", KW_LEFT}, + {"rekey", KW_REKEY}, + {"crlcheckinterval", KW_CRLCHECKINTERVAL}, + {"crluri2", KW_CRLURI2}, + {"leftcert", KW_LEFTCERT,}, + {"rightrsasigkey", KW_RIGHTRSASIGKEY}, + {"leftsubnet", KW_LEFTSUBNET}, + {"reauth", KW_REAUTH}, + {"leftsendcert", KW_LEFTSENDCERT}, + {"leftprotoport", KW_LEFTPROTOPORT}, + {""}, + {"right", KW_RIGHT}, + {"charondebug", KW_CHARONDEBUG}, + {"ocspuri", KW_OCSPURI}, + {"ike", KW_IKE}, + {"rightcert", KW_RIGHTCERT}, + {"klipsdebug", KW_KLIPSDEBUG}, + {"rightsubnet", KW_RIGHTSUBNET}, + {""}, + {"rightsendcert", KW_RIGHTSENDCERT}, + {"rightprotoport", KW_RIGHTPROTOPORT}, + {"plutostart", KW_PLUTOSTART}, + {"ikelifetime", KW_IKELIFETIME}, + {"keylife", KW_KEYLIFE}, + {"ocspuri2", KW_OCSPURI2}, + {"type", KW_TYPE}, + {"keep_alive", KW_KEEP_ALIVE}, + {"keyexchange", KW_KEYEXCHANGE}, + {""}, + {"prepluto", KW_PREPLUTO}, + {""}, + {"interfaces", KW_INTERFACES}, + {"overridemtu", KW_OVERRIDEMTU}, + {"crluri1", KW_CRLURI}, + {""}, {""}, + {"leftgroups", KW_LEFTGROUPS}, + {"leftid", KW_LEFTID}, + {""}, + {"ldapbase", KW_LDAPBASE}, + {"lefthostaccess", KW_LEFTHOSTACCESS}, + {"modeconfig", KW_MODECONFIG}, + {"leftca", KW_LEFTCA}, + {"pkcs11module", KW_PKCS11MODULE}, + {"nat_traversal", KW_NAT_TRAVERSAL}, + {"uniqueids", KW_UNIQUEIDS}, + {"pkcs11keepstate", KW_PKCS11KEEPSTATE}, + {"rightgroups", KW_RIGHTGROUPS}, + {"rightid", KW_RIGHTID}, + {"esp", KW_ESP}, + {"postpluto", KW_POSTPLUTO}, + {"righthostaccess", KW_RIGHTHOSTACCESS}, + {"charonstart", KW_CHARONSTART}, + {"rightca", KW_RIGHTCA}, + {"ocspuri1", KW_OCSPURI}, + {"dpdaction", KW_DPDACTION}, + {""}, + {"eapdir", KW_EAPDIR}, + {"hidetos", KW_HIDETOS}, + {"eap", KW_EAP}, + {""}, {""}, + {"pkcs11proxy", KW_PKCS11PROXY}, + {"dumpdir", KW_DUMPDIR}, + {""}, {""}, + {"xauth", KW_XAUTH}, + {""}, {""}, + {"nocrsend", KW_NOCRSEND}, + {"also", KW_ALSO}, + {""}, {""}, {""}, + {"ldaphost", KW_LDAPHOST}, + {""}, {""}, + {"authby", KW_AUTHBY}, + {""}, + {"dpddelay", KW_DPDDELAY}, + {"auth", KW_AUTH}, + {""}, {""}, {""}, + {"compress", KW_COMPRESS}, + {"auto", KW_AUTO}, + {""}, {""}, {""}, + {"fragicmp", KW_FRAGICMP}, + {""}, {""}, + {"keyingtries", KW_KEYINGTRIES}, + {""}, + {"pfsgroup", KW_PFSGROUP}, + {""}, + {"dpdtimeout", KW_DPDTIMEOUT}, + {"cacert", KW_CACERT}, + {""}, {""}, {""}, + {"strictcrlpolicy", KW_STRICTCRLPOLICY}, + {""}, {""}, + {"packetdefault", KW_PACKETDEFAULT}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {"cachecrls", KW_CACHECRLS}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {"pfs", KW_PFS} + }; + +#ifdef __GNUC__ +__inline +#endif +const struct kw_entry * +in_word_set (str, len) + register const char *str; + register unsigned int len; +{ + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register const char *s = wordlist[key].name; + + if (*str == *s && !strcmp (str + 1, s + 1)) + return &wordlist[key]; + } + } + return 0; +} diff --git a/src/starter/keywords.h b/src/starter/keywords.h new file mode 100644 index 000000000..08d50fea0 --- /dev/null +++ b/src/starter/keywords.h @@ -0,0 +1,176 @@ +/* strongSwan keywords + * Copyright (C) 2005 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id: keywords.h,v 1.8 2006/04/17 10:30:27 as Exp $ + */ + +#ifndef _KEYWORDS_H_ +#define _KEYWORDS_H_ + +typedef enum { + /* config setup keywords */ + KW_INTERFACES, + KW_DUMPDIR, + KW_CHARONSTART, + KW_PLUTOSTART, + + /* pluto/charon keywords */ + KW_PLUTODEBUG, + KW_CHARONDEBUG, + KW_PREPLUTO, + KW_POSTPLUTO, + KW_UNIQUEIDS, + KW_OVERRIDEMTU, + KW_CRLCHECKINTERVAL, + KW_CACHECRLS, + KW_STRICTCRLPOLICY, + KW_NOCRSEND, + KW_NAT_TRAVERSAL, + KW_KEEP_ALIVE, + KW_VIRTUAL_PRIVATE, + KW_EAPDIR, + KW_PKCS11MODULE, + KW_PKCS11KEEPSTATE, + KW_PKCS11PROXY, + +#define KW_PLUTO_FIRST KW_PLUTODEBUG +#define KW_PLUTO_LAST KW_PKCS11PROXY + + /* KLIPS keywords */ + KW_KLIPSDEBUG, + KW_FRAGICMP, + KW_PACKETDEFAULT, + KW_HIDETOS, + +#define KW_KLIPS_FIRST KW_KLIPSDEBUG +#define KW_KLIPS_LAST KW_HIDETOS + +#define KW_SETUP_FIRST KW_INTERFACES +#define KW_SETUP_LAST KW_HIDETOS + + /* conn section keywords */ + KW_CONN_NAME, + KW_CONN_SETUP, + KW_KEYEXCHANGE, + KW_TYPE, + KW_PFS, + KW_COMPRESS, + KW_AUTH, + KW_AUTHBY, + KW_EAP, + KW_IKELIFETIME, + KW_KEYLIFE, + KW_REKEYMARGIN, + KW_KEYINGTRIES, + KW_REKEYFUZZ, + KW_REKEY, + KW_REAUTH, + KW_IKE, + KW_ESP, + KW_PFSGROUP, + KW_DPDDELAY, + KW_DPDTIMEOUT, + KW_DPDACTION, + KW_MODECONFIG, + KW_XAUTH, + +#define KW_CONN_FIRST KW_CONN_SETUP +#define KW_CONN_LAST KW_XAUTH + + /* ca section keywords */ + KW_CA_NAME, + KW_CA_SETUP, + KW_CACERT, + KW_LDAPHOST, + KW_LDAPBASE, + KW_CRLURI, + KW_CRLURI2, + KW_OCSPURI, + KW_OCSPURI2, + +#define KW_CA_FIRST KW_CA_SETUP +#define KW_CA_LAST KW_OCSPURI2 + + /* end keywords */ + KW_HOST, + KW_NEXTHOP, + KW_SUBNET, + KW_SUBNETWITHIN, + KW_PROTOPORT, + KW_SOURCEIP, + KW_NATIP, + KW_FIREWALL, + KW_HOSTACCESS, + KW_UPDOWN, + KW_ID, + KW_RSASIGKEY, + KW_CERT, + KW_SENDCERT, + KW_CA, + KW_GROUPS, + KW_IFACE, + +#define KW_END_FIRST KW_HOST +#define KW_END_LAST KW_IFACE + + /* left end keywords */ + KW_LEFT, + KW_LEFTNEXTHOP, + KW_LEFTSUBNET, + KW_LEFTSUBNETWITHIN, + KW_LEFTPROTOPORT, + KW_LEFTSOURCEIP, + KW_LEFTNATIP, + KW_LEFTFIREWALL, + KW_LEFTHOSTACCESS, + KW_LEFTUPDOWN, + KW_LEFTID, + KW_LEFTRSASIGKEY, + KW_LEFTCERT, + KW_LEFTSENDCERT, + KW_LEFTCA, + KW_LEFTGROUPS, + +#define KW_LEFT_FIRST KW_LEFT +#define KW_LEFT_LAST KW_LEFTGROUPS + + /* right end keywords */ + KW_RIGHT, + KW_RIGHTNEXTHOP, + KW_RIGHTSUBNET, + KW_RIGHTSUBNETWITHIN, + KW_RIGHTPROTOPORT, + KW_RIGHTSOURCEIP, + KW_RIGHTNATIP, + KW_RIGHTFIREWALL, + KW_RIGHTHOSTACCESS, + KW_RIGHTUPDOWN, + KW_RIGHTID, + KW_RIGHTRSASIGKEY, + KW_RIGHTCERT, + KW_RIGHTSENDCERT, + KW_RIGHTCA, + KW_RIGHTGROUPS, + +#define KW_RIGHT_FIRST KW_RIGHT +#define KW_RIGHT_LAST KW_RIGHTGROUPS + + /* general section keywords */ + KW_ALSO, + KW_AUTO + +} kw_token_t; + +#endif /* _KEYWORDS_H_ */ + diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt new file mode 100644 index 000000000..0f943fc3c --- /dev/null +++ b/src/starter/keywords.txt @@ -0,0 +1,118 @@ +%{ +/* strongSwan keywords + * Copyright (C) 2005 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $ + */ + +#include <string.h> + +#include "keywords.h" + +%} +struct kw_entry { + char *name; + kw_token_t token; +}; +%% +interfaces, KW_INTERFACES +dumpdir, KW_DUMPDIR +charonstart, KW_CHARONSTART +plutostart, KW_PLUTOSTART +klipsdebug, KW_KLIPSDEBUG +plutodebug, KW_PLUTODEBUG +charondebug, KW_CHARONDEBUG +prepluto, KW_PREPLUTO +postpluto, KW_POSTPLUTO +fragicmp, KW_FRAGICMP +packetdefault, KW_PACKETDEFAULT +hidetos, KW_HIDETOS +uniqueids, KW_UNIQUEIDS +overridemtu, KW_OVERRIDEMTU +crlcheckinterval, KW_CRLCHECKINTERVAL +cachecrls, KW_CACHECRLS +strictcrlpolicy, KW_STRICTCRLPOLICY +nocrsend, KW_NOCRSEND +nat_traversal, KW_NAT_TRAVERSAL +keep_alive, KW_KEEP_ALIVE +virtual_private, KW_VIRTUAL_PRIVATE +eap, KW_EAP +eapdir, KW_EAPDIR +pkcs11module, KW_PKCS11MODULE +pkcs11keepstate, KW_PKCS11KEEPSTATE +pkcs11proxy, KW_PKCS11PROXY +keyexchange, KW_KEYEXCHANGE +type, KW_TYPE +pfs, KW_PFS +compress, KW_COMPRESS +auth, KW_AUTH +authby, KW_AUTHBY +keylife, KW_KEYLIFE +rekeymargin, KW_REKEYMARGIN +ikelifetime, KW_IKELIFETIME +keyingtries, KW_KEYINGTRIES +rekeyfuzz, KW_REKEYFUZZ +rekey, KW_REKEY +reauth, KW_REAUTH +esp, KW_ESP +ike, KW_IKE +pfsgroup, KW_PFSGROUP +dpddelay, KW_DPDDELAY +dpdtimeout, KW_DPDTIMEOUT +dpdaction, KW_DPDACTION +modeconfig, KW_MODECONFIG +xauth, KW_XAUTH +cacert, KW_CACERT +ldaphost, KW_LDAPHOST +ldapbase, KW_LDAPBASE +crluri, KW_CRLURI +crluri1, KW_CRLURI +crluri2, KW_CRLURI2 +ocspuri, KW_OCSPURI +ocspuri1, KW_OCSPURI +ocspuri2, KW_OCSPURI2 +left, KW_LEFT +leftnexthop, KW_LEFTNEXTHOP +leftsubnet, KW_LEFTSUBNET +leftsubnetwithin, KW_LEFTSUBNETWITHIN +leftprotoport, KW_LEFTPROTOPORT +leftsourceip, KW_LEFTSOURCEIP +leftnatip, KW_LEFTNATIP +leftfirewall, KW_LEFTFIREWALL +lefthostaccess, KW_LEFTHOSTACCESS +leftupdown, KW_LEFTUPDOWN +leftid, KW_LEFTID +leftrsasigkey, KW_LEFTRSASIGKEY +leftcert, KW_LEFTCERT, +leftsendcert, KW_LEFTSENDCERT +leftca, KW_LEFTCA +leftgroups, KW_LEFTGROUPS +right, KW_RIGHT +rightnexthop, KW_RIGHTNEXTHOP +rightsubnet, KW_RIGHTSUBNET +rightsubnetwithin, KW_RIGHTSUBNETWITHIN +rightprotoport, KW_RIGHTPROTOPORT +rightsourceip, KW_RIGHTSOURCEIP +rightnatip, KW_RIGHTNATIP +rightfirewall, KW_RIGHTFIREWALL +righthostaccess, KW_RIGHTHOSTACCESS +rightupdown, KW_RIGHTUPDOWN +rightid, KW_RIGHTID +rightrsasigkey, KW_RIGHTRSASIGKEY +rightcert, KW_RIGHTCERT +rightsendcert, KW_RIGHTSENDCERT +rightca, KW_RIGHTCA +rightgroups, KW_RIGHTGROUPS +also, KW_ALSO +auto, KW_AUTO diff --git a/src/starter/lex.yy.c b/src/starter/lex.yy.c new file mode 100644 index 000000000..f8e6569f1 --- /dev/null +++ b/src/starter/lex.yy.c @@ -0,0 +1,1966 @@ + +#line 3 "lex.yy.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 33 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 14 +#define YY_END_OF_BUFFER 15 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[47] = + { 0, + 0, 0, 15, 11, 2, 4, 13, 11, 3, 11, + 11, 11, 11, 1, 11, 2, 0, 12, 11, 0, + 4, 8, 11, 11, 11, 11, 1, 11, 11, 11, + 11, 11, 7, 11, 11, 11, 11, 11, 6, 11, + 5, 11, 11, 9, 10, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, 8, 9, + + 10, 11, 12, 1, 13, 1, 1, 14, 1, 15, + 16, 17, 1, 18, 19, 20, 21, 22, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[23] = + { 0, + 1, 2, 3, 2, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1 + } ; + +static yyconst flex_int16_t yy_base[51] = + { 0, + 0, 69, 70, 0, 67, 72, 64, 21, 72, 19, + 52, 56, 55, 62, 0, 61, 58, 72, 34, 58, + 72, 0, 45, 51, 38, 39, 54, 17, 41, 33, + 34, 39, 0, 30, 33, 36, 27, 25, 0, 17, + 0, 21, 15, 0, 0, 72, 28, 40, 42, 45 + } ; + +static yyconst flex_int16_t yy_def[51] = + { 0, + 46, 1, 46, 47, 46, 46, 48, 49, 46, 47, + 47, 47, 47, 46, 47, 46, 48, 46, 49, 50, + 46, 47, 47, 47, 47, 47, 46, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 0, 46, 46, 46, 46 + } ; + +static yyconst flex_int16_t yy_nxt[95] = + { 0, + 4, 5, 6, 7, 8, 9, 4, 10, 4, 4, + 4, 4, 11, 4, 4, 4, 4, 4, 12, 4, + 4, 13, 20, 21, 20, 22, 20, 32, 15, 45, + 44, 33, 43, 42, 23, 20, 21, 20, 41, 20, + 17, 17, 19, 19, 19, 20, 20, 20, 40, 39, + 38, 37, 36, 35, 34, 27, 31, 30, 29, 28, + 21, 18, 16, 27, 26, 25, 24, 18, 16, 46, + 14, 3, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46 + + } ; + +static yyconst flex_int16_t yy_chk[95] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8, 8, 8, 10, 8, 28, 47, 43, + 42, 28, 40, 38, 10, 19, 19, 19, 37, 19, + 48, 48, 49, 49, 49, 50, 50, 50, 36, 35, + 34, 32, 31, 30, 29, 27, 26, 25, 24, 23, + 20, 17, 16, 14, 13, 12, 11, 7, 5, 3, + 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46 + + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "parser.l" +#line 2 "parser.l" +/* FreeS/WAN config file parser (parser.l) + * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: parser.l,v 1.5 2006/03/28 22:32:33 as Exp $ + */ + +#include <string.h> +#include <stdlib.h> +#include <glob.h> + +#include "y.tab.h" + +#define MAX_INCLUDE_DEPTH 20 + +#define YY_NO_UNPUT +extern void yyerror(const char *); +extern int yylex (void); + +static struct { + int stack_ptr; + YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH]; + FILE *file[MAX_INCLUDE_DEPTH]; + unsigned int line[MAX_INCLUDE_DEPTH]; + char *filename[MAX_INCLUDE_DEPTH]; +} __parser_y_private; + +void _parser_y_error(char *b, int size, const char *s); +void _parser_y_init (const char *f); +void _parser_y_fini (void); +int _parser_y_include (const char *filename); + +void _parser_y_error(char *b, int size, const char *s) +{ + extern char *yytext; // was: char yytext[]; + + snprintf(b, size, "%s:%d: %s [%s]", + __parser_y_private.filename[__parser_y_private.stack_ptr], + __parser_y_private.line[__parser_y_private.stack_ptr], + s, yytext); +} + +void _parser_y_init (const char *f) +{ + memset(&__parser_y_private, 0, sizeof(__parser_y_private)); + __parser_y_private.line[0] = 1; + __parser_y_private.filename[0] = strdup(f); +} + +void _parser_y_fini (void) +{ + unsigned int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) + { + if (__parser_y_private.filename[i]) + free(__parser_y_private.filename[i]); + if (__parser_y_private.file[i]) + fclose(__parser_y_private.file[i]); + } + memset(&__parser_y_private, 0, sizeof(__parser_y_private)); +} + +int _parser_y_include (const char *filename) +{ + glob_t files; + int i, ret; + + ret = glob(filename, GLOB_ERR, NULL, &files); + if (ret) + { + const char *err; + + switch (ret) + { + case GLOB_NOSPACE: + err = "include files ran out of memory"; + break; + case GLOB_ABORTED: + err = "include files aborted due to read error"; + break; + case GLOB_NOMATCH: + err = "include files found no matches"; + break; + default: + err = "unknown include files error"; + } + yyerror(err); + return 1; + } + + for (i = 0; i < files.gl_pathc; i++) + { + FILE *f; + unsigned int p = __parser_y_private.stack_ptr + 1; + + if (p >= MAX_INCLUDE_DEPTH) + { + yyerror("max inclusion depth reached"); + return 1; + } + + f = fopen(files.gl_pathv[i], "r"); + if (!f) + { + yyerror("can't open include filename"); + continue; + } + + __parser_y_private.stack_ptr++; + __parser_y_private.file[p] = f; + __parser_y_private.stack[p] = YY_CURRENT_BUFFER; + __parser_y_private.line[p] = 1; + __parser_y_private.filename[p] = strdup(files.gl_pathv[i]); + + yy_switch_to_buffer(yy_create_buffer(f,YY_BUF_SIZE)); + } + globfree(&files); + return 0; +} + +#line 618 "lex.yy.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 134 "parser.l" + + +#line 777 "lex.yy.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 47 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 72 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case YY_STATE_EOF(INITIAL): +#line 136 "parser.l" +{ + if (__parser_y_private.filename[__parser_y_private.stack_ptr]) { + free(__parser_y_private.filename[__parser_y_private.stack_ptr]); + __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL; + } + if (__parser_y_private.file[__parser_y_private.stack_ptr]) { + fclose(__parser_y_private.file[__parser_y_private.stack_ptr]); + __parser_y_private.file[__parser_y_private.stack_ptr] = NULL; + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer + (__parser_y_private.stack[__parser_y_private.stack_ptr]); + } + if (--__parser_y_private.stack_ptr < 0) { + yyterminate(); + } +} + YY_BREAK +case 1: +YY_RULE_SETUP +#line 153 "parser.l" +return FIRST_SPACES; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 155 "parser.l" +/* ignore spaces in line */ ; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 157 "parser.l" +return EQUAL; + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 159 "parser.l" +{ + __parser_y_private.line[__parser_y_private.stack_ptr]++; + return EOL; + } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 164 "parser.l" +return CONFIG; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 165 "parser.l" +return SETUP; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 166 "parser.l" +return CONN; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 167 "parser.l" +return CA; + YY_BREAK +case 9: +YY_RULE_SETUP +#line 168 "parser.l" +return INCLUDE; + YY_BREAK +case 10: +YY_RULE_SETUP +#line 169 "parser.l" +return FILE_VERSION; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 171 "parser.l" +{ + yylval.s = strdup(yytext); + return STRING; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 176 "parser.l" +{ + yylval.s = strdup(yytext+1); + if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0'; + return STRING; + } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 182 "parser.l" +yyerror(yytext); + YY_BREAK +case 14: +YY_RULE_SETUP +#line 184 "parser.l" +ECHO; + YY_BREAK +#line 961 "lex.yy.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 47 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 47 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 46); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */ +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __THROW /* this is a gnuism */ +extern int isatty (int ) __THROW; +#else +extern int isatty (int ); +#endif +#ifdef __cplusplus +} +#endif +#endif + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param str a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 184 "parser.l" + + + +int yywrap(void) +{ + return 1; +} + + diff --git a/src/starter/netkey.c b/src/starter/netkey.c new file mode 100644 index 000000000..d0b8e0a2c --- /dev/null +++ b/src/starter/netkey.c @@ -0,0 +1,85 @@ +/* strongSwan netkey starter + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: netkey.c,v 1.4 2006/02/15 18:33:57 as Exp $ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "files.h" + +bool +starter_netkey_init(void) +{ + struct stat stb; + + if (stat(PROC_NETKEY, &stb) != 0) + { + /* af_key module makes the netkey proc interface visible */ + if (stat(PROC_MODULES, &stb) == 0) + { + system("modprobe -qv af_key"); + } + + /* now test again */ + if (stat(PROC_NETKEY, &stb) != 0) + { + DBG(DBG_CONTROL, + DBG_log("kernel appears to lack the native netkey IPsec stack") + ) + return FALSE; + } + } + + /* make sure that all required IPsec modules are loaded */ + if (stat(PROC_MODULES, &stb) == 0) + { + system("modprobe -qv ah4"); + system("modprobe -qv esp4"); + system("modprobe -qv ipcomp"); + system("modprobe -qv xfrm4_tunnel"); + system("modprobe -qv xfrm_user"); + } + + DBG(DBG_CONTROL, + DBG_log("Found netkey IPsec stack") + ) + return TRUE; +} + +void +starter_netkey_cleanup(void) +{ + if (system("ip xfrm state > /dev/null 2>&1") == 0) + { + system("ip xfrm state flush"); + system("ip xfrm policy flush"); + } + else if (system("type setkey > /dev/null 2>&1") == 0) + { + system("setkey -F"); + system("setkey -FP"); + } + else + { + plog("WARNING: cannot flush IPsec state/policy database"); + } +} diff --git a/src/starter/netkey.h b/src/starter/netkey.h new file mode 100644 index 000000000..ff8989d34 --- /dev/null +++ b/src/starter/netkey.h @@ -0,0 +1,24 @@ +/* strongSwan netkey initialization and cleanup + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: netkey.h,v 1.1 2005/12/30 19:03:15 as Exp $ + */ + +#ifndef _STARTER_NETKEY_H_ +#define _STARTER_NETKEY_H_ + +extern bool starter_netkey_init (void); +extern void starter_netkey_cleanup (void); + +#endif /* _STARTER_NETKEY_H_ */ + diff --git a/src/starter/parser.h b/src/starter/parser.h new file mode 100644 index 000000000..61bdea974 --- /dev/null +++ b/src/starter/parser.h @@ -0,0 +1,57 @@ +/* strongSwan config file parser + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: parser.h,v 1.5 2006/01/17 23:43:36 as Exp $ + */ + +#ifndef _IPSEC_PARSER_H_ +#define _IPSEC_PARSER_H_ + +#include "keywords.h" + +typedef struct kw_entry kw_entry_t; + +struct kw_entry { + char *name; + kw_token_t token; +}; + +typedef struct kw_list kw_list_t; + +struct kw_list { + kw_entry_t *entry; + char *value; + kw_list_t *next; +}; + +typedef struct section_list section_list_t; + +struct section_list { + char *name; + kw_list_t *kw; + section_list_t *next; +}; + +typedef struct config_parsed config_parsed_t; + +struct config_parsed { + kw_list_t *config_setup; + section_list_t *conn_first, *conn_last; + section_list_t *ca_first, *ca_last; +}; + +config_parsed_t *parser_load_conf (const char *file); +void parser_free_conf (config_parsed_t *cfg); + +#endif /* _IPSEC_PARSER_H_ */ + diff --git a/src/starter/parser.l b/src/starter/parser.l new file mode 100644 index 000000000..1469f94bc --- /dev/null +++ b/src/starter/parser.l @@ -0,0 +1,190 @@ +%{ +/* FreeS/WAN config file parser (parser.l) + * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: parser.l,v 1.5 2006/03/28 22:32:33 as Exp $ + */ + +#include <string.h> +#include <stdlib.h> +#include <glob.h> + +#include "y.tab.h" + +#define MAX_INCLUDE_DEPTH 20 + +#define YY_NO_UNPUT +extern void yyerror(const char *); +extern int yylex (void); + +static struct { + int stack_ptr; + YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH]; + FILE *file[MAX_INCLUDE_DEPTH]; + unsigned int line[MAX_INCLUDE_DEPTH]; + char *filename[MAX_INCLUDE_DEPTH]; +} __parser_y_private; + +void _parser_y_error(char *b, int size, const char *s); +void _parser_y_init (const char *f); +void _parser_y_fini (void); +int _parser_y_include (const char *filename); + +void _parser_y_error(char *b, int size, const char *s) +{ + extern char *yytext; // was: char yytext[]; + + snprintf(b, size, "%s:%d: %s [%s]", + __parser_y_private.filename[__parser_y_private.stack_ptr], + __parser_y_private.line[__parser_y_private.stack_ptr], + s, yytext); +} + +void _parser_y_init (const char *f) +{ + memset(&__parser_y_private, 0, sizeof(__parser_y_private)); + __parser_y_private.line[0] = 1; + __parser_y_private.filename[0] = strdup(f); +} + +void _parser_y_fini (void) +{ + unsigned int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) + { + if (__parser_y_private.filename[i]) + free(__parser_y_private.filename[i]); + if (__parser_y_private.file[i]) + fclose(__parser_y_private.file[i]); + } + memset(&__parser_y_private, 0, sizeof(__parser_y_private)); +} + +int _parser_y_include (const char *filename) +{ + glob_t files; + int i, ret; + + ret = glob(filename, GLOB_ERR, NULL, &files); + if (ret) + { + const char *err; + + switch (ret) + { + case GLOB_NOSPACE: + err = "include files ran out of memory"; + break; + case GLOB_ABORTED: + err = "include files aborted due to read error"; + break; + case GLOB_NOMATCH: + err = "include files found no matches"; + break; + default: + err = "unknown include files error"; + } + yyerror(err); + return 1; + } + + for (i = 0; i < files.gl_pathc; i++) + { + FILE *f; + unsigned int p = __parser_y_private.stack_ptr + 1; + + if (p >= MAX_INCLUDE_DEPTH) + { + yyerror("max inclusion depth reached"); + return 1; + } + + f = fopen(files.gl_pathv[i], "r"); + if (!f) + { + yyerror("can't open include filename"); + continue; + } + + __parser_y_private.stack_ptr++; + __parser_y_private.file[p] = f; + __parser_y_private.stack[p] = YY_CURRENT_BUFFER; + __parser_y_private.line[p] = 1; + __parser_y_private.filename[p] = strdup(files.gl_pathv[i]); + + yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); + } + globfree(&files); + return 0; +} + +%} + +%% + +<<EOF>> { + if (__parser_y_private.filename[__parser_y_private.stack_ptr]) { + free(__parser_y_private.filename[__parser_y_private.stack_ptr]); + __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL; + } + if (__parser_y_private.file[__parser_y_private.stack_ptr]) { + fclose(__parser_y_private.file[__parser_y_private.stack_ptr]); + __parser_y_private.file[__parser_y_private.stack_ptr] = NULL; + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer + (__parser_y_private.stack[__parser_y_private.stack_ptr]); + } + if (--__parser_y_private.stack_ptr < 0) { + yyterminate(); + } +} + +^[\t ]+ return FIRST_SPACES; + +[\t ]+ /* ignore spaces in line */ ; + += return EQUAL; + +\n|#.*\n { + __parser_y_private.line[__parser_y_private.stack_ptr]++; + return EOL; + } + +config return CONFIG; +setup return SETUP; +conn return CONN; +ca return CA; +include return INCLUDE; +version return FILE_VERSION; + +[^\"= \t\n]+ { + yylval.s = strdup(yytext); + return STRING; + } + +\"[^\"\n]*\" { + yylval.s = strdup(yytext+1); + if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0'; + return STRING; + } + +. yyerror(yytext); + +%% + +int yywrap(void) +{ + return 1; +} + diff --git a/src/starter/parser.y b/src/starter/parser.y new file mode 100644 index 000000000..db984fae3 --- /dev/null +++ b/src/starter/parser.y @@ -0,0 +1,283 @@ +%{ +/* strongSwan config file parser (parser.y) + * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: parser.y,v 1.6 2006/01/17 23:43:36 as Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" +#include "parser.h" + +#define YYERROR_VERBOSE +#define ERRSTRING_LEN 256 + +/** + * Bison + */ +static char parser_errstring[ERRSTRING_LEN+1]; + +extern void yyerror(const char *s); +extern int yylex (void); +extern void _parser_y_error(char *b, int size, const char *s); + +/** + * Static Globals + */ +static int _save_errors_; +static config_parsed_t *_parser_cfg; +static kw_list_t **_parser_kw, *_parser_kw_last; +static char errbuf[ERRSTRING_LEN+1]; + +/** + * Gperf + */ +extern kw_entry_t *in_word_set (char *str, unsigned int len); + +%} + +%union { char *s; }; +%token EQUAL FIRST_SPACES EOL CONFIG SETUP CONN CA INCLUDE FILE_VERSION +%token <s> STRING + +%% + +/* + * Config file + */ + +config_file: + config_file section_or_include + | /* NULL */ + ; + +section_or_include: + FILE_VERSION STRING EOL + { + free($2); + } + | CONFIG SETUP EOL + { + _parser_kw = &(_parser_cfg->config_setup); + _parser_kw_last = NULL; + } kw_section + | CONN STRING EOL + { + section_list_t *section = (section_list_t *)alloc_thing(section_list_t + , "section_list_t"); + + section->name = clone_str($2, "conn section name"); + section->kw = NULL; + section->next = NULL; + _parser_kw = &(section->kw); + if (!_parser_cfg->conn_first) + _parser_cfg->conn_first = section; + if (_parser_cfg->conn_last) + _parser_cfg->conn_last->next = section; + _parser_cfg->conn_last = section; + _parser_kw_last = NULL; + free($2); + } kw_section + | CA STRING EOL + { + section_list_t *section = (section_list_t *)alloc_thing(section_list_t + , "section_list_t"); + section->name = clone_str($2, "ca section name"); + section->kw = NULL; + section->next = NULL; + _parser_kw = &(section->kw); + if (!_parser_cfg->ca_first) + _parser_cfg->ca_first = section; + if (_parser_cfg->ca_last) + _parser_cfg->ca_last->next = section; + _parser_cfg->ca_last = section; + _parser_kw_last = NULL; + free($2); + } kw_section + | INCLUDE STRING + { + extern void _parser_y_include (const char *f); + _parser_y_include($2); + free($2); + } EOL + | EOL + ; + +kw_section: + FIRST_SPACES statement_kw EOL kw_section + | + ; + +statement_kw: + STRING EQUAL STRING + { + kw_list_t *new; + kw_entry_t *entry = in_word_set($1, strlen($1)); + + if (entry == NULL) + { + snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", $1); + yyerror(errbuf); + } + else if (_parser_kw) + { + new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t"); + new->entry = entry; + new->value = clone_str($3, "kw_list value"); + new->next = NULL; + if (_parser_kw_last) + _parser_kw_last->next = new; + _parser_kw_last = new; + if (!*_parser_kw) + *_parser_kw = new; + } + free($1); + free($3); + } + | STRING EQUAL + { + free($1); + } + | + ; + +%% + +void +yyerror(const char *s) +{ + if (_save_errors_) + _parser_y_error(parser_errstring, ERRSTRING_LEN, s); +} + +config_parsed_t * +parser_load_conf(const char *file) +{ + config_parsed_t *cfg = NULL; + int err = 0; + FILE *f; + + extern void _parser_y_init (const char *f); + extern FILE *yyin; + + memset(parser_errstring, 0, ERRSTRING_LEN+1); + + cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t"); + if (cfg) + { + memset(cfg, 0, sizeof(config_parsed_t)); + f = fopen(file, "r"); + if (f) + { + yyin = f; + _parser_y_init(file); + _save_errors_ = 1; + _parser_cfg = cfg; + + if (yyparse() !=0 ) + { + if (parser_errstring[0] == '\0') + { + snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error..."); + } + _save_errors_ = 0; + while (yyparse() != 0); + err++; + } + else if (parser_errstring[0] != '\0') + { + err++; + } + else + { + /** + * Config valid + */ + } + + fclose(f); + } + else + { + snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file); + err++; + } + } + else + { + snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory"); + err++; + } + + if (err) + { + plog("%s", parser_errstring); + + if (cfg) + parser_free_conf(cfg); + cfg = NULL; + } + + return cfg; +} + +static void +parser_free_kwlist(kw_list_t *list) +{ + kw_list_t *elt; + + while (list) + { + elt = list; + list = list->next; + if (elt->value) + pfree(elt->value); + pfree(elt); + } +} + +void +parser_free_conf(config_parsed_t *cfg) +{ + section_list_t *sec; + if (cfg) + { + parser_free_kwlist(cfg->config_setup); + while (cfg->conn_first) + { + sec = cfg->conn_first; + cfg->conn_first = cfg->conn_first->next; + if (sec->name) + pfree(sec->name); + parser_free_kwlist(sec->kw); + pfree(sec); + } + while (cfg->ca_first) + { + sec = cfg->ca_first; + cfg->ca_first = cfg->ca_first->next; + if (sec->name) + pfree(sec->name); + parser_free_kwlist(sec->kw); + pfree(sec); + } + pfree(cfg); + } +} diff --git a/src/starter/starter.c b/src/starter/starter.c new file mode 100644 index 000000000..0bf1d7a71 --- /dev/null +++ b/src/starter/starter.c @@ -0,0 +1,643 @@ +/* strongSwan IPsec starter + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: starter.c,v 1.23 2006/02/15 18:37:46 as Exp $ + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" + +#include "confread.h" +#include "files.h" +#include "starterwhack.h" +#include "starterstroke.h" +#include "invokepluto.h" +#include "invokecharon.h" +#include "netkey.h" +#include "cmp.h" +#include "interfaces.h" + +#define FLAG_ACTION_START_PLUTO 0x01 +#define FLAG_ACTION_UPDATE 0x02 +#define FLAG_ACTION_RELOAD 0x04 +#define FLAG_ACTION_QUIT 0x08 +#define FLAG_ACTION_LISTEN 0x10 +#define FLAG_ACTION_START_CHARON 0x20 + +static unsigned int _action_ = 0; + +static void +fsig(int signal) +{ + switch (signal) + { + case SIGCHLD: + { + int status; + pid_t pid; + char *name = NULL; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + { + if (pid == starter_pluto_pid()) + name = " (Pluto)"; + if (pid == starter_charon_pid()) + name = " (Charon)"; + if (WIFSIGNALED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been killed by sig %d\n", + pid, name?name:"", WTERMSIG(status)) + ) + else if (WIFSTOPPED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been stopped by sig %d\n", + pid, name?name:"", WSTOPSIG(status)) + ) + else if (WIFEXITED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit (exit code %d)\n", + pid, name?name:"", WEXITSTATUS(status)) + ) + else + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit", pid, name?name:"") + ) + if (pid == starter_pluto_pid()) + starter_pluto_sigchild(pid); + if (pid == starter_charon_pid()) + starter_charon_sigchild(pid); + } + } + break; + + case SIGPIPE: + /** ignore **/ + break; + + case SIGALRM: + _action_ |= FLAG_ACTION_START_PLUTO; + _action_ |= FLAG_ACTION_START_CHARON; + break; + + case SIGHUP: + _action_ |= FLAG_ACTION_UPDATE; + break; + + case SIGTERM: + case SIGQUIT: + case SIGINT: + _action_ |= FLAG_ACTION_QUIT; + break; + + case SIGUSR1: + _action_ |= FLAG_ACTION_RELOAD; + _action_ |= FLAG_ACTION_UPDATE; + break; + + default: + plog("fsig(): unknown signal %d -- investigate", signal); + break; + } +} + +static void +usage(char *name) +{ + fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " + "[--debug|--debug-more|--debug-all]\n"); + exit(1); +} + +int main (int argc, char **argv) +{ + starter_config_t *cfg = NULL; + starter_config_t *new_cfg; + starter_conn_t *conn, *conn2; + starter_ca_t *ca, *ca2; + + struct stat stb; + + char *err = NULL; + int i; + int id = 1; + struct timeval tv; + unsigned long auto_update = 0; + time_t last_reload; + bool no_fork = FALSE; + + /* global variables defined in log.h */ + log_to_stderr = TRUE; + base_debugging = DBG_NONE; + + /* parse command line */ + for (i = 1; i < argc; i++) + { + if (streq(argv[i], "--debug")) + { + base_debugging |= DBG_CONTROL; + } + else if (streq(argv[i], "--debug-more")) + { + base_debugging |= DBG_CONTROLMORE; + } + else if (streq(argv[i], "--debug-all")) + { + base_debugging |= DBG_ALL; + } + else if (streq(argv[i], "--nofork")) + { + no_fork = TRUE; + } + else if (streq(argv[i], "--auto-update") && i+1 < argc) + { + auto_update = atoi(argv[++i]); + if (!auto_update) + usage(argv[0]); + } + else + { + usage(argv[0]); + } + } + + /* Init */ + init_log("ipsec_starter"); + cur_debugging = base_debugging; + + signal(SIGHUP, fsig); + signal(SIGCHLD, fsig); + signal(SIGPIPE, fsig); + signal(SIGINT, fsig); + signal(SIGTERM, fsig); + signal(SIGQUIT, fsig); + signal(SIGALRM, fsig); + signal(SIGUSR1, fsig); + + plog("Starting strongSwan %s IPsec [starter]...", ipsec_version_code()); + + /* verify that we can start */ + if (getuid() != 0) + { + plog("permission denied (must be superuser)"); + exit(1); + } + + if (stat(PLUTO_PID_FILE, &stb) == 0) + { + plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE); + } + else + { + _action_ |= FLAG_ACTION_START_PLUTO; + } + if (stat(CHARON_PID_FILE, &stb) == 0) + { + plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); + } + else + { + _action_ |= FLAG_ACTION_START_CHARON; + } + if (stat(DEV_RANDOM, &stb) != 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); + exit(1); + } + + if (stat(DEV_URANDOM, &stb)!= 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); + exit(1); + } + + cfg = confread_load(CONFIG_FILE); + if (!cfg) + { + plog("unable to start strongSwan -- errors in config"); + exit(1); + } + + /* determine if we have a native netkey IPsec stack */ + if (!starter_netkey_init()) + { + plog("no netkey IPSec stack detected"); + exit(1); + } + + last_reload = time(NULL); + + if (stat(STARTER_PID_FILE, &stb) == 0) + { + plog("starter is already running (%s exists) -- no fork done", STARTER_PID_FILE); + exit(0); + } + + /* fork if we're not debugging stuff */ + if (!no_fork) + { + log_to_stderr = FALSE; + + switch (fork()) + { + case 0: + { + int fnull = open("/dev/null", O_RDWR); + + if (fnull >= 0) + { + dup2(fnull, STDIN_FILENO); + dup2(fnull, STDOUT_FILENO); + dup2(fnull, STDERR_FILENO); + close(fnull); + } + } + break; + case -1: + plog("can't fork: %s", strerror(errno)); + break; + default: + exit(0); + } + } + + /* save pid file in /var/run/starter.pid */ + { + FILE *fd = fopen(STARTER_PID_FILE, "w"); + + if (fd) + { + fprintf(fd, "%u\n", getpid()); + fclose(fd); + } + } + + for (;;) + { + /* + * Stop pluto/charon (if started) and exit + */ + if (_action_ & FLAG_ACTION_QUIT) + { + if (starter_pluto_pid()) + starter_stop_pluto(); + if (starter_charon_pid()) + starter_stop_charon(); + starter_netkey_cleanup(); + confread_free(cfg); + unlink(STARTER_PID_FILE); + unlink(INFO_FILE); +#ifdef LEAK_DETECTIVE + report_leaks(); +#endif /* LEAK_DETECTIVE */ + close_log(); + plog("ipsec starter stopped"); + exit(0); + } + + /* + * Delete all connections. Will be added below + */ + if (_action_ & FLAG_ACTION_RELOAD) + { + if (starter_pluto_pid() || starter_charon_pid()) + { + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { + if (starter_charon_pid()) + { + starter_stroke_del_conn(conn); + } + if (starter_pluto_pid()) + { + starter_whack_del_conn(conn); + } + conn->state = STATE_TO_ADD; + } + } + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + if (starter_charon_pid()) + { + starter_stroke_del_ca(ca); + } + if (starter_pluto_pid()) + { + starter_whack_del_ca(ca); + } + ca->state = STATE_TO_ADD; + } + } + } + _action_ &= ~FLAG_ACTION_RELOAD; + } + + /* + * Update configuration + */ + if (_action_ & FLAG_ACTION_UPDATE) + { + err = NULL; + DBG(DBG_CONTROL, + DBG_log("Reloading config...") + ); + new_cfg = confread_load(CONFIG_FILE); + + if (new_cfg) + { + /* Switch to new config. New conn will be loaded below */ + if (!starter_cmp_defaultroute(&new_cfg->defaultroute + , &cfg->defaultroute)) + { + _action_ |= FLAG_ACTION_LISTEN; + } + + if (!starter_cmp_pluto(cfg, new_cfg)) + { + plog("Pluto has changed"); + if (starter_pluto_pid()) + starter_stop_pluto(); + _action_ &= ~FLAG_ACTION_LISTEN; + _action_ |= FLAG_ACTION_START_PLUTO; + } + else + { + /* Only reload conn and ca sections if pluto is not killed */ + + /* Look for new connections that are already loaded */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { + for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) + { + if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2)) + { + conn->state = STATE_REPLACED; + conn2->state = STATE_ADDED; + conn2->id = conn->id; + break; + } + } + } + } + + /* Remove conn sections that have become unused */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { + if (starter_charon_pid()) + { + starter_stroke_del_conn(conn); + } + if (starter_pluto_pid()) + { + starter_whack_del_conn(conn); + } + } + } + + /* Look for new ca sections that are already loaded */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) + { + if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2)) + { + ca->state = STATE_REPLACED; + ca2->state = STATE_ADDED; + break; + } + } + } + } + + /* Remove ca sections that have become unused */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + if (starter_charon_pid()) + { + starter_stroke_del_ca(ca); + } + if (starter_pluto_pid()) + { + starter_whack_del_ca(ca); + } + } + } + } + confread_free(cfg); + cfg = new_cfg; + } + else + { + plog("can't reload config file: %s -- keeping old one"); + } + _action_ &= ~FLAG_ACTION_UPDATE; + last_reload = time(NULL); + } + + /* + * Start pluto + */ + if (_action_ & FLAG_ACTION_START_PLUTO) + { + if (cfg->setup.plutostart && !starter_pluto_pid()) + { + DBG(DBG_CONTROL, + DBG_log("Attempting to start pluto...") + ); + + if (starter_start_pluto(cfg, no_fork) == 0) + { + starter_whack_listen(); + } + else + { + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); + } + } + _action_ &= ~FLAG_ACTION_START_PLUTO; + + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + ca->state = STATE_TO_ADD; + } + + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + conn->state = STATE_TO_ADD; + } + } + + /* + * Start charon + */ + if (_action_ & FLAG_ACTION_START_CHARON) + { + if (cfg->setup.charonstart && !starter_charon_pid()) + { + DBG(DBG_CONTROL, + DBG_log("Attempting to start charon...") + ); + if (starter_start_charon(cfg, no_fork)) + { + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); + } + } + _action_ &= ~FLAG_ACTION_START_CHARON; + } + + /* + * Tell pluto to reread its interfaces + */ + if (_action_ & FLAG_ACTION_LISTEN) + { + if (starter_pluto_pid()) + { + starter_whack_listen(); + _action_ &= ~FLAG_ACTION_LISTEN; + } + } + + /* + * Add stale conn and ca sections + */ + if (starter_pluto_pid() || starter_charon_pid()) + { + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_TO_ADD) + { + if (starter_charon_pid()) + { + starter_stroke_add_ca(ca); + } + if (starter_pluto_pid()) + { + starter_whack_add_ca(ca); + } + ca->state = STATE_ADDED; + } + } + + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_TO_ADD) + { + if (conn->id == 0) + { + /* affect new unique id */ + conn->id = id++; + } + if (starter_charon_pid()) + { + starter_stroke_add_conn(conn); + } + if (starter_pluto_pid()) + { + starter_whack_add_conn(conn); + } + conn->state = STATE_ADDED; + + if (conn->startup == STARTUP_START) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + if (starter_charon_pid()) + { + starter_stroke_initiate_conn(conn); + } + } + else + { + if (starter_pluto_pid()) + { + starter_whack_initiate_conn(conn); + } + } + } + else if (conn->startup == STARTUP_ROUTE) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + if (starter_charon_pid()) + { + starter_stroke_route_conn(conn); + } + } + else + { + if (starter_pluto_pid()) + { + starter_whack_route_conn(conn); + } + } + } + } + } + } + + /* + * If auto_update activated, when to stop select + */ + if (auto_update) + { + time_t now = time(NULL); + + tv.tv_sec = (now < last_reload + auto_update) + ? (last_reload + auto_update-now) : 0; + tv.tv_usec = 0; + } + + /* + * Wait for something to happen + */ + if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) + { + /* timeout -> auto_update */ + _action_ |= FLAG_ACTION_UPDATE; + } + } + + return 0; +} + diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c new file mode 100644 index 000000000..fb8e74b8c --- /dev/null +++ b/src/starter/starterstroke.c @@ -0,0 +1,295 @@ +/* Stroke for charon is the counterpart to whack from pluto + * 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. + * + * RCSID $Id: starterstroke.c $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stddef.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <freeswan.h> + +#include <constants.h> +#include <defs.h> +#include <log.h> + +#include <stroke.h> + +#include "starterstroke.h" +#include "confread.h" +#include "files.h" + +/** + * Authentication mehtods, must be the same values as in charon + */ +enum auth_method_t { + AUTH_RSA = 1, + AUTH_PSK = 2, + AUTH_DSS = 3, + AUTH_EAP = 201, +}; + +static char* push_string(stroke_msg_t *msg, char *string) +{ + unsigned long string_start = msg->length; + + if (string == NULL || msg->length + strlen(string) >= sizeof(stroke_msg_t)) + { + return NULL; + } + else + { + msg->length += strlen(string) + 1; + strcpy((char*)msg + string_start, string); + return (char*)string_start; + } +} + +static int send_stroke_msg (stroke_msg_t *msg) +{ + struct sockaddr_un ctl_addr = { AF_UNIX, CHARON_CTL_FILE }; + int byte_count; + char buffer[64]; + + /* starter is not called from commandline, and therefore absolutely silent */ + msg->output_verbosity = -1; + + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + + if (sock < 0) + { + plog("socket() failed: %s", strerror(errno)); + return -1; + } + if (connect(sock, (struct sockaddr *)&ctl_addr, offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) + { + plog("connect(charon_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + + /* send message */ + if (write(sock, msg, msg->length) != msg->length) + { + plog("write(charon_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0) + { + buffer[byte_count] = '\0'; + plog("%s", buffer); + } + if (byte_count < 0) + { + plog("read() failed: %s", strerror(errno)); + } + + close(sock); + return 0; +} + +static char* connection_name(starter_conn_t *conn) +{ + /* if connection name is '%auto', create a new name like conn_xxxxx */ + static char buf[32]; + + if (streq(conn->name, "%auto")) + { + sprintf(buf, "conn_%ld", conn->id); + return buf; + } + return conn->name; +} + +static void ip_address2string(ip_address *addr, char *buffer, size_t len) +{ + switch (((struct sockaddr*)addr)->sa_family) + { + case AF_INET: + { + struct sockaddr_in* sin = (struct sockaddr_in*)addr; + if (inet_ntop(AF_INET, &sin->sin_addr, buffer, len)) + { + return; + } + break; + } + case AF_INET6: + { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; + if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer, len)) + { + return; + } + break; + } + default: + break; + } + /* failed */ + snprintf(buffer, len, "0.0.0.0"); +} + + +static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, starter_end_t *conn_end) +{ + char buffer[INET6_ADDRSTRLEN]; + + msg_end->id = push_string(msg, conn_end->id); + msg_end->cert = push_string(msg, conn_end->cert); + msg_end->ca = push_string(msg, conn_end->ca); + msg_end->updown = push_string(msg, conn_end->updown); + ip_address2string(&conn_end->addr, buffer, sizeof(buffer)); + msg_end->address = push_string(msg, buffer); + ip_address2string(&conn_end->subnet.addr, buffer, sizeof(buffer)); + msg_end->subnet = push_string(msg, buffer); + msg_end->subnet_mask = conn_end->subnet.maskbits; + msg_end->sendcert = conn_end->sendcert; + msg_end->hostaccess = conn_end->hostaccess; + msg_end->tohost = !conn_end->has_client; + msg_end->protocol = conn_end->protocol; + msg_end->port = conn_end->port; + msg_end->virtual_ip = conn_end->modecfg; + ip_address2string(&conn_end->srcip, buffer, sizeof(buffer)); + msg_end->sourceip = push_string(msg, buffer); +} + +int starter_stroke_add_conn(starter_conn_t *conn) +{ + stroke_msg_t msg; + + msg.type = STR_ADD_CONN; + msg.length = offsetof(stroke_msg_t, buffer); + msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2; + msg.add_conn.name = push_string(&msg, connection_name(conn)); + + /* RSA is preferred before PSK and EAP */ + if (conn->policy & POLICY_RSASIG) + { + msg.add_conn.auth_method = AUTH_RSA; + } + else if (conn->policy & POLICY_PSK) + { + msg.add_conn.auth_method = AUTH_PSK; + } + else + { + msg.add_conn.auth_method = AUTH_EAP; + } + msg.add_conn.eap_type = conn->eap; + + if (conn->policy & POLICY_TUNNEL) + { + msg.add_conn.mode = 1; /* XFRM_MODE_TRANSPORT */ + } + else if (conn->policy & POLICY_BEET) + { + msg.add_conn.mode = 4; /* XFRM_MODE_BEET */ + } + else + { + msg.add_conn.mode = 0; /* XFRM_MODE_TUNNEL */ + } + + if (conn->policy & POLICY_DONT_REKEY) + { + msg.add_conn.rekey.ipsec_lifetime = 0; + msg.add_conn.rekey.ike_lifetime = 0; + msg.add_conn.rekey.margin = 0; + msg.add_conn.rekey.tries = 0; + msg.add_conn.rekey.fuzz = 0; + } + else + { + msg.add_conn.rekey.reauth = (conn->policy & POLICY_DONT_REAUTH) == LEMPTY; + msg.add_conn.rekey.ipsec_lifetime = conn->sa_ipsec_life_seconds; + msg.add_conn.rekey.ike_lifetime = conn->sa_ike_life_seconds; + msg.add_conn.rekey.margin = conn->sa_rekey_margin; + msg.add_conn.rekey.tries = conn->sa_keying_tries; + msg.add_conn.rekey.fuzz = conn->sa_rekey_fuzz; + } + msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); + msg.add_conn.algorithms.esp = push_string(&msg, conn->esp); + msg.add_conn.dpd.delay = conn->dpd_delay; + msg.add_conn.dpd.action = conn->dpd_action; + + starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->left); + starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->right); + + return send_stroke_msg(&msg); +} + +int starter_stroke_del_conn(starter_conn_t *conn) +{ + stroke_msg_t msg; + + msg.type = STR_DEL_CONN; + msg.length = offsetof(stroke_msg_t, buffer); + msg.del_conn.name = push_string(&msg, connection_name(conn)); + return send_stroke_msg(&msg); +} + +int starter_stroke_route_conn(starter_conn_t *conn) +{ + stroke_msg_t msg; + + msg.type = STR_ROUTE; + msg.length = offsetof(stroke_msg_t, buffer); + msg.route.name = push_string(&msg, connection_name(conn)); + return send_stroke_msg(&msg); +} + +int starter_stroke_initiate_conn(starter_conn_t *conn) +{ + stroke_msg_t msg; + + msg.type = STR_INITIATE; + msg.length = offsetof(stroke_msg_t, buffer); + msg.initiate.name = push_string(&msg, connection_name(conn)); + return send_stroke_msg(&msg); +} + +int starter_stroke_add_ca(starter_ca_t *ca) +{ + stroke_msg_t msg; + + msg.type = STR_ADD_CA; + msg.length = offsetof(stroke_msg_t, buffer); + msg.add_ca.name = push_string(&msg, ca->name); + msg.add_ca.cacert = push_string(&msg, ca->cacert); + msg.add_ca.crluri = push_string(&msg, ca->crluri); + msg.add_ca.crluri2 = push_string(&msg, ca->crluri2); + msg.add_ca.ocspuri = push_string(&msg, ca->ocspuri); + msg.add_ca.ocspuri2 = push_string(&msg, ca->ocspuri2); + return send_stroke_msg(&msg); +} + +int starter_stroke_del_ca(starter_ca_t *ca) +{ + stroke_msg_t msg; + + msg.type = STR_DEL_CA; + msg.length = offsetof(stroke_msg_t, buffer); + msg.del_ca.name = push_string(&msg, ca->name); + return send_stroke_msg(&msg); +} + + diff --git a/src/starter/starterstroke.h b/src/starter/starterstroke.h new file mode 100644 index 000000000..95c37094e --- /dev/null +++ b/src/starter/starterstroke.h @@ -0,0 +1,29 @@ +/* Stroke for charon is the counterpart to whack from pluto + * 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. + * + * RCSID $Id: starterstroke.h $ + */ + +#ifndef _STARTER_STROKE_H_ +#define _STARTER_STROKE_H_ + +#include "confread.h" + +extern int starter_stroke_add_conn(starter_conn_t *conn); +extern int starter_stroke_del_conn(starter_conn_t *conn); +extern int starter_stroke_route_conn(starter_conn_t *conn); +extern int starter_stroke_initiate_conn(starter_conn_t *conn); +extern int starter_stroke_add_ca(starter_ca_t *ca); +extern int starter_stroke_del_ca(starter_ca_t *ca); + +#endif /* _STARTER_STROKE_H_ */ diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c new file mode 100644 index 000000000..42328849a --- /dev/null +++ b/src/starter/starterwhack.c @@ -0,0 +1,369 @@ +/* strongSwan whack functions to communicate with pluto (whack.c) + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: starterwhack.c,v 1.17 2006/04/17 10:32:36 as Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stddef.h> +#include <unistd.h> +#include <errno.h> + +#include <freeswan.h> + +#include <constants.h> +#include <defs.h> +#include <log.h> +#include <whack.h> + +#include "starterwhack.h" +#include "confread.h" +#include "files.h" + +static int +pack_str (char **p, char **next, char **roof) +{ + const char *s = (*p==NULL) ? "" : *p; /* note: NULL becomes ""! */ + size_t len = strlen(s) + 1; + + if ((*roof - *next) < len) + { + return 0; /* not enough space */ + } + else + { + strcpy(*next, s); + *next += len; + *p = NULL; /* don't send pointers on the wire! */ + return 1; + } +} + +static int +send_whack_msg (whack_message_t *msg) +{ + struct sockaddr_un ctl_addr = { AF_UNIX, PLUTO_CTL_FILE }; + int sock; + ssize_t len; + char *str_next, *str_roof; + + /* pack strings */ + str_next = (char *)msg->string; + str_roof = (char *)&msg->string[sizeof(msg->string)]; + + if (!pack_str(&msg->name, &str_next, &str_roof) + || !pack_str(&msg->left.id, &str_next, &str_roof) + || !pack_str(&msg->left.cert, &str_next, &str_roof) + || !pack_str(&msg->left.ca, &str_next, &str_roof) + || !pack_str(&msg->left.groups, &str_next, &str_roof) + || !pack_str(&msg->left.updown, &str_next, &str_roof) + || !pack_str(&msg->left.virt, &str_next, &str_roof) + || !pack_str(&msg->right.id, &str_next, &str_roof) + || !pack_str(&msg->right.cert, &str_next, &str_roof) + || !pack_str(&msg->right.ca, &str_next, &str_roof) + || !pack_str(&msg->right.groups, &str_next, &str_roof) + || !pack_str(&msg->right.updown, &str_next, &str_roof) + || !pack_str(&msg->right.virt, &str_next, &str_roof) + || !pack_str(&msg->keyid, &str_next, &str_roof) + || !pack_str(&msg->myid, &str_next, &str_roof) + || !pack_str(&msg->cacert, &str_next, &str_roof) + || !pack_str(&msg->ldaphost, &str_next, &str_roof) + || !pack_str(&msg->ldapbase, &str_next, &str_roof) + || !pack_str(&msg->crluri, &str_next, &str_roof) + || !pack_str(&msg->crluri2, &str_next, &str_roof) + || !pack_str(&msg->ocspuri, &str_next, &str_roof) + || !pack_str(&msg->ike, &str_next, &str_roof) + || !pack_str(&msg->esp, &str_next, &str_roof) + || !pack_str(&msg->sc_data, &str_next, &str_roof) + || (str_roof - str_next < msg->keyval.len)) + { + plog("send_wack_msg(): can't pack strings"); + return -1; + } + if (msg->keyval.ptr) + memcpy(str_next, msg->keyval.ptr, msg->keyval.len); + msg->keyval.ptr = NULL; + str_next += msg->keyval.len; + len = str_next - (char *)msg; + + /* connect to pluto ctl */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + plog("socket() failed: %s", strerror(errno)); + return -1; + } + if (connect(sock, (struct sockaddr *)&ctl_addr, + offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) + { + plog("connect(pluto_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + + /* send message */ + if (write(sock, msg, len) != len) + { + plog("write(pluto_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + + /* TODO: read reply */ + close(sock); + return 0; +} + +static void +init_whack_msg(whack_message_t *msg) +{ + memset(msg, 0, sizeof(whack_message_t)); + msg->magic = WHACK_MAGIC; +} + +static char * +connection_name(starter_conn_t *conn) +{ + /* if connection name is '%auto', create a new name like conn_xxxxx */ + static char buf[32]; + + if (streq(conn->name, "%auto")) + { + sprintf(buf, "conn_%ld", conn->id); + return buf; + } + return conn->name; +} + +static void +set_whack_end(whack_end_t *w, starter_end_t *end) +{ + w->id = end->id; + w->cert = end->cert; + w->ca = end->ca; + w->groups = end->groups; + w->host_addr = end->addr; + w->host_nexthop = end->nexthop; + w->host_srcip = end->srcip; + w->has_client = end->has_client; + + if (w->has_client) + w->client = end->subnet; + else + w->client.addr.u.v4.sin_family = addrtypeof(&w->host_addr); + + w->has_client_wildcard = end->has_client_wildcard; + w->has_port_wildcard = end->has_port_wildcard; + w->has_srcip = end->has_srcip; + w->has_natip = end->has_natip; + w->modecfg = end->modecfg; + w->hostaccess = end->hostaccess; + w->sendcert = end->sendcert; + w->updown = end->updown; + w->host_port = IKE_UDP_PORT; + w->port = end->port; + w->protocol = end->protocol; + w->virt = end->virt; + + if (w->port != 0) + { + int port = htons(w->port); + + setportof(port, &w->host_addr); + setportof(port, &w->client.addr); + } +} + +static int +starter_whack_add_pubkey (starter_conn_t *conn, starter_end_t *end +, const char *lr) +{ + const char *err; + static char keyspace[1024 + 4]; + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_key = TRUE; + msg.pubkey_alg = PUBKEY_ALG_RSA; + if (end->id && end->rsakey) + { + /* special values to ignore */ + if (streq(end->rsakey, "") + || streq(end->rsakey, "%none") + || streq(end->rsakey, "%cert") + || streq(end->rsakey, "0x00")) + { + return 0; + } + msg.keyid = end->id; + err = atobytes(end->rsakey, 0, keyspace, sizeof(keyspace), &msg.keyval.len); + if (err) + { + plog("conn %s/%s: rsakey malformed [%s]", connection_name(conn), lr, err); + return 1; + } + else + { + msg.keyval.ptr = keyspace; + return send_whack_msg(&msg); + } + } + return 0; +} + +int +starter_whack_add_conn(starter_conn_t *conn) +{ + whack_message_t msg; + int r; + + init_whack_msg(&msg); + + msg.whack_connection = TRUE; + msg.name = connection_name(conn); + + msg.ikev1 = conn->keyexchange != KEY_EXCHANGE_IKEV2; + msg.addr_family = conn->addr_family; + msg.tunnel_addr_family = conn->tunnel_addr_family; + msg.sa_ike_life_seconds = conn->sa_ike_life_seconds; + msg.sa_ipsec_life_seconds = conn->sa_ipsec_life_seconds; + msg.sa_rekey_margin = conn->sa_rekey_margin; + msg.sa_rekey_fuzz = conn->sa_rekey_fuzz; + msg.sa_keying_tries = conn->sa_keying_tries; + msg.policy = conn->policy; + + set_whack_end(&msg.left, &conn->left); + set_whack_end(&msg.right, &conn->right); + + msg.esp = conn->esp; + msg.ike = conn->ike; + msg.pfsgroup = conn->pfsgroup; + + /* taken from pluto/whack.c */ + if (msg.pfsgroup) + { + char esp_buf[256]; + + snprintf(esp_buf, sizeof (esp_buf), "%s;%s" + , msg.esp ? msg.esp : "" + , msg.pfsgroup ? msg.pfsgroup : ""); + msg.esp = esp_buf; + + DBG(DBG_CONTROL, + DBG_log("Setting --esp=%s", msg.esp) + ) + } + msg.dpd_delay = conn->dpd_delay; + msg.dpd_timeout = conn->dpd_timeout; + msg.dpd_action = conn->dpd_action; +/* msg.dpd_count = conn->dpd_count; not supported yet by strongSwan */ + + r = send_whack_msg(&msg); + + if (r == 0 && (conn->policy & POLICY_RSASIG)) + { + r += starter_whack_add_pubkey (conn, &conn->left, "left"); + r += starter_whack_add_pubkey (conn, &conn->right, "right"); + } + + return r; +} + +int +starter_whack_del_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_delete = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_route_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_route = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_initiate_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_initiate = TRUE; + msg.whack_async = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_listen(void) +{ + whack_message_t msg; + init_whack_msg(&msg); + msg.whack_listen = TRUE; + return send_whack_msg(&msg); +} + +int starter_whack_shutdown(void) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_shutdown = TRUE; + return send_whack_msg(&msg); +} + +int +starter_whack_add_ca(starter_ca_t *ca) +{ + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_ca = TRUE; + msg.name = ca->name; + msg.cacert = ca->cacert; + msg.ldaphost = ca->ldaphost; + msg.ldapbase = ca->ldapbase; + msg.crluri = ca->crluri; + msg.crluri2 = ca->crluri2; + msg.ocspuri = ca->ocspuri; + msg.whack_strict = ca->strict; + + return send_whack_msg(&msg); +} + +int +starter_whack_del_ca(starter_ca_t *ca) +{ + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_delete = TRUE; + msg.whack_ca = TRUE; + msg.name = ca->name; + + return send_whack_msg(&msg); +} diff --git a/src/starter/starterwhack.h b/src/starter/starterwhack.h new file mode 100644 index 000000000..2e79c0715 --- /dev/null +++ b/src/starter/starterwhack.h @@ -0,0 +1,32 @@ +/* FreeS/WAN whack functions to communicate with pluto (whack.h) + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: starterwhack.h,v 1.6 2006/01/03 18:37:03 as Exp $ + */ + +#ifndef _STARTER_WHACK_H_ +#define _STARTER_WHACK_H_ + +#include "confread.h" + +extern int starter_whack_add_conn(starter_conn_t *conn); +extern int starter_whack_del_conn(starter_conn_t *conn); +extern int starter_whack_route_conn(starter_conn_t *conn); +extern int starter_whack_initiate_conn(starter_conn_t *conn); +extern int starter_whack_listen(void); +extern int starter_whack_shutdown(void); +extern int starter_whack_add_ca(starter_ca_t *ca); +extern int starter_whack_del_ca(starter_ca_t *ca); + +#endif /* _STARTER_WHACK_H_ */ + diff --git a/src/starter/y.tab.c b/src/starter/y.tab.c new file mode 100644 index 000000000..11a0373e9 --- /dev/null +++ b/src/starter/y.tab.c @@ -0,0 +1,1832 @@ +/* A Bison parser, made by GNU Bison 2.2. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + EQUAL = 258, + FIRST_SPACES = 259, + EOL = 260, + CONFIG = 261, + SETUP = 262, + CONN = 263, + CA = 264, + INCLUDE = 265, + FILE_VERSION = 266, + STRING = 267 + }; +#endif +/* Tokens. */ +#define EQUAL 258 +#define FIRST_SPACES 259 +#define EOL 260 +#define CONFIG 261 +#define SETUP 262 +#define CONN 263 +#define CA 264 +#define INCLUDE 265 +#define FILE_VERSION 266 +#define STRING 267 + + + + +/* Copy the first part of user declarations. */ +#line 1 "parser.y" + +/* strongSwan config file parser (parser.y) + * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security + * + * 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. + * + * RCSID $Id: parser.y,v 1.6 2006/01/17 23:43:36 as Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <freeswan.h> + +#include "../pluto/constants.h" +#include "../pluto/defs.h" +#include "../pluto/log.h" +#include "parser.h" + +#define YYERROR_VERBOSE +#define ERRSTRING_LEN 256 + +/** + * Bison + */ +static char parser_errstring[ERRSTRING_LEN+1]; + +extern void yyerror(const char *s); +extern int yylex (void); +extern void _parser_y_error(char *b, int size, const char *s); + +/** + * Static Globals + */ +static int _save_errors_; +static config_parsed_t *_parser_cfg; +static kw_list_t **_parser_kw, *_parser_kw_last; +static char errbuf[ERRSTRING_LEN+1]; + +/** + * Gperf + */ +extern kw_entry_t *in_word_set (char *str, unsigned int len); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 56 "parser.y" +{ char *s; } +/* Line 193 of yacc.c. */ +#line 177 "y.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 190 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 27 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 13 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 9 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 18 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 34 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 267 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 6, 7, 11, 12, 18, 19, 25, + 26, 32, 33, 38, 40, 45, 46, 50, 53 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 14, 0, -1, 14, 15, -1, -1, 11, 12, 5, + -1, -1, 6, 7, 5, 16, 20, -1, -1, 8, + 12, 5, 17, 20, -1, -1, 9, 12, 5, 18, + 20, -1, -1, 10, 12, 19, 5, -1, 5, -1, + 4, 21, 5, 20, -1, -1, 12, 3, 12, -1, + 12, 3, -1, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 67, 67, 68, 72, 77, 76, 82, 81, 99, + 98, 115, 114, 120, 124, 125, 129, 154, 158 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "EQUAL", "FIRST_SPACES", "EOL", "CONFIG", + "SETUP", "CONN", "CA", "INCLUDE", "FILE_VERSION", "STRING", "$accept", + "config_file", "section_or_include", "@1", "@2", "@3", "@4", + "kw_section", "statement_kw", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 13, 14, 14, 15, 16, 15, 17, 15, 18, + 15, 19, 15, 15, 20, 20, 21, 21, 21 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 0, 3, 0, 5, 0, 5, 0, + 5, 0, 4, 1, 4, 0, 3, 2, 0 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 3, 0, 1, 13, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 11, 0, 5, 7, 9, 0, 4, + 15, 15, 15, 12, 18, 6, 8, 10, 0, 0, + 17, 15, 16, 14 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 1, 9, 20, 21, 22, 18, 25, 29 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -20 +static const yytype_int8 yypact[] = +{ + -20, 0, -20, -20, -6, -8, -5, 1, 2, -20, + 10, 11, 12, -20, 13, -20, -20, -20, 14, -20, + 16, 16, 16, -20, 9, -20, -20, -20, 19, 18, + 15, 16, -20, -20 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -20, -20, -20, -20, -20, -20, -20, -19, -20 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 2, 10, 26, 27, 11, 3, 4, 12, 5, 6, + 7, 8, 33, 13, 14, 15, 16, 17, 19, 23, + 24, 28, 30, 31, 0, 0, 0, 32 +}; + +static const yytype_int8 yycheck[] = +{ + 0, 7, 21, 22, 12, 5, 6, 12, 8, 9, + 10, 11, 31, 12, 12, 5, 5, 5, 5, 5, + 4, 12, 3, 5, -1, -1, -1, 12 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 14, 0, 5, 6, 8, 9, 10, 11, 15, + 7, 12, 12, 12, 12, 5, 5, 5, 19, 5, + 16, 17, 18, 5, 4, 20, 20, 20, 12, 21, + 3, 5, 12, 20 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + const YYSTYPE * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + const YYSTYPE * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, + int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule + ) + YYSTYPE *yyvsp; + + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: +#line 73 "parser.y" + { + free((yyvsp[(2) - (3)].s)); + } + break; + + case 5: +#line 77 "parser.y" + { + _parser_kw = &(_parser_cfg->config_setup); + _parser_kw_last = NULL; + } + break; + + case 7: +#line 82 "parser.y" + { + section_list_t *section = (section_list_t *)alloc_thing(section_list_t + , "section_list_t"); + + section->name = clone_str((yyvsp[(2) - (3)].s), "conn section name"); + section->kw = NULL; + section->next = NULL; + _parser_kw = &(section->kw); + if (!_parser_cfg->conn_first) + _parser_cfg->conn_first = section; + if (_parser_cfg->conn_last) + _parser_cfg->conn_last->next = section; + _parser_cfg->conn_last = section; + _parser_kw_last = NULL; + free((yyvsp[(2) - (3)].s)); + } + break; + + case 9: +#line 99 "parser.y" + { + section_list_t *section = (section_list_t *)alloc_thing(section_list_t + , "section_list_t"); + section->name = clone_str((yyvsp[(2) - (3)].s), "ca section name"); + section->kw = NULL; + section->next = NULL; + _parser_kw = &(section->kw); + if (!_parser_cfg->ca_first) + _parser_cfg->ca_first = section; + if (_parser_cfg->ca_last) + _parser_cfg->ca_last->next = section; + _parser_cfg->ca_last = section; + _parser_kw_last = NULL; + free((yyvsp[(2) - (3)].s)); + } + break; + + case 11: +#line 115 "parser.y" + { + extern void _parser_y_include (const char *f); + _parser_y_include((yyvsp[(2) - (2)].s)); + free((yyvsp[(2) - (2)].s)); + } + break; + + case 16: +#line 130 "parser.y" + { + kw_list_t *new; + kw_entry_t *entry = in_word_set((yyvsp[(1) - (3)].s), strlen((yyvsp[(1) - (3)].s))); + + if (entry == NULL) + { + snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", (yyvsp[(1) - (3)].s)); + yyerror(errbuf); + } + else if (_parser_kw) + { + new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t"); + new->entry = entry; + new->value = clone_str((yyvsp[(3) - (3)].s), "kw_list value"); + new->next = NULL; + if (_parser_kw_last) + _parser_kw_last->next = new; + _parser_kw_last = new; + if (!*_parser_kw) + *_parser_kw = new; + } + free((yyvsp[(1) - (3)].s)); + free((yyvsp[(3) - (3)].s)); + } + break; + + case 17: +#line 155 "parser.y" + { + free((yyvsp[(1) - (2)].s)); + } + break; + + +/* Line 1267 of yacc.c. */ +#line 1496 "y.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} + + +#line 161 "parser.y" + + +void +yyerror(const char *s) +{ + if (_save_errors_) + _parser_y_error(parser_errstring, ERRSTRING_LEN, s); +} + +config_parsed_t * +parser_load_conf(const char *file) +{ + config_parsed_t *cfg = NULL; + int err = 0; + FILE *f; + + extern void _parser_y_init (const char *f); + extern FILE *yyin; + + memset(parser_errstring, 0, ERRSTRING_LEN+1); + + cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t"); + if (cfg) + { + memset(cfg, 0, sizeof(config_parsed_t)); + f = fopen(file, "r"); + if (f) + { + yyin = f; + _parser_y_init(file); + _save_errors_ = 1; + _parser_cfg = cfg; + + if (yyparse() !=0 ) + { + if (parser_errstring[0] == '\0') + { + snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error..."); + } + _save_errors_ = 0; + while (yyparse() != 0); + err++; + } + else if (parser_errstring[0] != '\0') + { + err++; + } + else + { + /** + * Config valid + */ + } + + fclose(f); + } + else + { + snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file); + err++; + } + } + else + { + snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory"); + err++; + } + + if (err) + { + plog("%s", parser_errstring); + + if (cfg) + parser_free_conf(cfg); + cfg = NULL; + } + + return cfg; +} + +static void +parser_free_kwlist(kw_list_t *list) +{ + kw_list_t *elt; + + while (list) + { + elt = list; + list = list->next; + if (elt->value) + pfree(elt->value); + pfree(elt); + } +} + +void +parser_free_conf(config_parsed_t *cfg) +{ + section_list_t *sec; + if (cfg) + { + parser_free_kwlist(cfg->config_setup); + while (cfg->conn_first) + { + sec = cfg->conn_first; + cfg->conn_first = cfg->conn_first->next; + if (sec->name) + pfree(sec->name); + parser_free_kwlist(sec->kw); + pfree(sec); + } + while (cfg->ca_first) + { + sec = cfg->ca_first; + cfg->ca_first = cfg->ca_first->next; + if (sec->name) + pfree(sec->name); + parser_free_kwlist(sec->kw); + pfree(sec); + } + pfree(cfg); + } +} + diff --git a/src/starter/y.tab.h b/src/starter/y.tab.h new file mode 100644 index 000000000..4b55cb005 --- /dev/null +++ b/src/starter/y.tab.h @@ -0,0 +1,82 @@ +/* A Bison parser, made by GNU Bison 2.2. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + EQUAL = 258, + FIRST_SPACES = 259, + EOL = 260, + CONFIG = 261, + SETUP = 262, + CONN = 263, + CA = 264, + INCLUDE = 265, + FILE_VERSION = 266, + STRING = 267 + }; +#endif +/* Tokens. */ +#define EQUAL 258 +#define FIRST_SPACES 259 +#define EOL 260 +#define CONFIG 261 +#define SETUP 262 +#define CONN 263 +#define CA 264 +#define INCLUDE 265 +#define FILE_VERSION 266 +#define STRING 267 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 56 "parser.y" +{ char *s; } +/* Line 1528 of yacc.c. */ +#line 75 "y.tab.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + |